Saturday, November 3, 2012

Multimedia keys and osd volume bars on Linux with Alsa and bare-metal X-Window


Update: on recent distros, some dunce obviously decided we didn't need /dev/dsp etc any more but failed to realize that would break several packages, including but not limited to aumix, so on a recent Ubuntu the volume bars WILL NOT WORK. Sad to say, the mute command is also affected. Temporary fix is described in this post. Stand by for a more permanent fix, but I won't apologize for the inconvenience. If you want an apology, find said dunce and make him say sorry.

Up until recently, the multimedia keys on my big, (once) shiny, expensive Logitech G15 keyboard were mostly laying waste - I simply never saw any need to get them working. Usually I do those things only when something breaks, but alas, I had a whim. So here's the story of what I did.

If you read my previous posts, you know already that I like to get down to the bare metal with my designs. That holds true not only in my tinkering but also in my coding and in my sysadmining. The reason's quite simple: The deeper down I clamp my works onto the things I want to affect, the less other stuff I depend on, and the less stuff I depend on the less sources of failure I have to worry about. Of course there's more: the less layers I have in between my designs and the stuff I actually try to control/affect/do, the less things I have to pay attention to to get stuff "just right", and the less places I have to worry about to have their own ideas about what I might want to do. That's probably why my minimalistic, bare-metal X-Window setup works so well for me. Call me fickle, but that's how I like it, and it works well for me.

What I didn't want to do is bring one of the Great Big Frameworks into things - you know my views on those. But, as I wrote elsewhere, the tools used in the good old times are still around, they just lay dormant under thick layers of framework-glaciers, waiting their time to reemerge and take the world back from them. OK, enough quoting Pratchett and poetry, back to the subject at hand, which is, all you have to do is look for them and unearth them.

First order of business: get the Multimedia keys to work in principle. 


Some googling scared up this article on xbindkeys (which isn't that old after all): http://www.debian-administration.org/articles/52. xbindkeys is a very nice tool that can bind totally arbitrary key combinations to equally arbitrary commands. In other words: it will do what you tell it to and leave the thinking to you, just the way I like it. Also it comes with an equally nice graphical configuration tool named xbindkeys-config, which allows you to configure key combos...

Hold it, grasshopper, not so fast, ... Oh well. He'll be back.

Where was I? Oh yes: lets you define function keys without the hassle of hand-editing the config file. Now I don't have a problem with that, but I know a lot of you guys like your point-and-click interface. By the way, did I mention that you can also bind mouse button clicks and key-click-combos? Very versatile that tool. That thing is SO going into my work notebook where I use nautilus, because on a notebook evilwm is a bitch to use. Nautilus is a really nice WM once you get to know it, and it can do a lot more than you usually see of it in the Gnome environment. Note to self: write an article about using nautilus bare-metal.

Back so soon, grasshopper? No, xbindkeys-config isn't broken, YOU caused that segfault. Now will you read the rest of the article? VERY good of you, grasshopper.

OK, let's go hands-on, before somebody else gets his fingers where (s)he shouldn't, shall we?
First order of business with xbindkeys is to init the configuration: Run

xbindkeys --defaults >>~/.xbindkeysrc

to create the .xbindkeysrc file, without which xbindkeys-config will indeed segfault. No, that's not a bad bug, because it TELLS you you have to init .xbindkeysrc before conking out. Never read your console output, did you grasshopper? Serves you right.

Then, and ONLY then does it make sense to run xbindkeys-config. Mind you, from there on out it is pretty much smooth sailing downhill all the way. Does TOO make sense, there is such a thing as land-sailing, where you CAN sail downhill. Here's a nice screenshot for you:

The first three items are examples I left in since they don't bother me. You should have them too, so have a look at them and enjoy. The other three are what I have so far.

Here's the work flow: Click "new" below the list, click "Get Key", type in the desired key combination (special keys like media keys, etc work fine) and specify the action, i.e. the command you would like to have run upon that key press.
One noteworthy limitation there: you can run one command and one command only. bash-style command lists do NOT work. Note how I have scripts in there? More about that later, but that's the reason.
Last but not least, either click "Save Apply & Exit" or just click apply and try it out. It may or may not work, if it doesn't re-start xbindkeys and it will, apparently there is some glitch in the re-loading of .xbindkeysrc or the triggering thereof.

Second order of business: Do something with the keys configured. 

Mute was easy as you can see in the screenshot above. Alsa brings a nice little tool named - nomen est omen - mute that will either mute or unmute sound with every call of it. That being taken care of, I had to find a way to actually change the settings of the volume without resorting to graphical tools and stuff. I never did that before, never had to. Again, google is your friend. I found this here page: http://thehacklist.blogspot.de/2010/08/ubuntualsa-controlling-volume-from.html which started me off into the right direction, which is amixer. Simple tool from the alsa suite that lets you get and set stuff in the alsa framework from the command line. There are more, more about another one below. But one thing at a time, OK?

amixer is an amazing tool full of possibilities that can do stuff you probably never dreamt of if you never used anything but those simple-minded graphical mixers. I'll probably write a whole article on alsa and amixer and it's friends some day, but for the scope of this article, it is completely sufficient to go into what I did indeed use here, if you're Linux savvy you can probably hack your way from there.

So here's the command I had in the command field initially (now coming to you from the volup.sh script):

amixer sset Master,0 3%+

Let me break that down for you a bit.

sset means "set simple control" which implies correctly that there are non-simple controls too, which would be set with "set". Equally, simple controls are gotten with "sget" whereas non-simple controls are gotten with "get" and so on. As usual, have a peek at the man page.

Master,0 is the control I'm planning to affect, the master volume.

3%+ means "up by three percent". The voldown.sh script uses the exact same command except it's 3%- there - you're smart, you get the pattern. amixer is smart too, it can do absolute and relative percent values, relative dB values and absolute and relative values relating to the limits of the control(which you can find out with a "sget" call):

user@machine:~$ amixer sget Master,0
Simple mixer control 'Master',0
   Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
   Playback channels: Mono
   Limits: Playback 0 - 64
   Mono: Playback 37 [58%] [-27.00dB] [on]

Last but not least: make it comfy, make it pretty

Now with that, I could control my volume just fine. But you know me: I wanted more. I always want more. I never settle for "good enough". I always... Oh, let's just quote George Bernhard Shaw:

"Many people strife for the extraordinary and never get past the ordinary. I prefer to strife for perfection and never get past the extraordinary"

There you have it. Never could have said it as well as old George. Then he probably couldn't program his way out of a wet cardboard box. To each his own.

Again, enough poetry, back to the hard facts.  What I wanted was a visual feedback of the volume setting. I've often fiddled with xosd, e.g. since I don't use a panel (evilwm isn't panel-aware) I use osd_clock instead. Bare metal again, right there. Now xosd does those pretty percentage bars. Why not use one of them? Sure thing, let's do it!

Now, as a little excursion, this is where the scripts came in, since, as I wrote above, xbindkeys does not do more than one command per key entry. That serves me fine, I like keeping my stuff in little packets, makes it easier to modify. There's your basic modular concept. That's why I always keep a .scripts folder in my home directory where I throw all the little scripts and snippets I code to be Santa's little helpers and do the background work for me. Let's look at one of those, shall we? Here's the listing of volup.sh for you:

 #!/bin/bash
amixer sset Master,0 3%+
killall -q osd_cat
osd_cat -i20 -o5 -b percentage -P$(aumix -q|grep vol|cut -d' ' -f3) \
-T "Master Left" &
osd_cat -i20 -o35 -b percentage -P$(aumix -q|grep vol|cut -d' ' -f2|cut \
-d',' -f1) -T "Master Right"

Here's a nice little snapshot of that script in action:
OK, let's break it down. The first two lines I'll just skip here. The third line I'll explain, but a little later.

The main work is done by the two osd_cat calls. I won't go into the details of osd_cat here, it's all in the man page, just a few quick hints:
-i and -o set the position
-P takes the percentage of the bar requested with -b.
 Note also that the first of the osd_cat calls is sent to background, else they would show one after the other.

The interesting stuff happens inside the parentheses. Now why use aumix here instead of amixer? Simple: aumix, while being a much simpler tool than amixer, gives me separate values for left and right channel with a simple call, whereas I would have to go deep into the channels with amixer.

user@machine:~$ aumix -q
vol 59, 59
line 0, 0
mic 0, 0
cd 90, 90
pcm2 100, 100
igain 100, 100
dig1 100, 100, P

Right tool for the right job, remember? You CAN loosen a bolt with a pair of pliers, but a wrench will work much better.

The rest of the command is just to cut out the two numbers.

That leaves that peculiar killall osd_cat to be explained. Look at this page(German) I found some time later: https://wiki.archlinux.de/title/Lautst%C3%A4rkebalken_mit_xosd
Just to tell you right now: what they're doing there won't work for xbindkeys for a simple reason: You can't update a percentage bar created by xosd. Each time that script is called, it creates a new instance of osd_cat - which overlap. So if you press that key five times in a row, you get a garbled percentage bar. Allow me to demonstrate:

If I run this:
osd_cat -i20 -o20 -bpercentage -P60&  osd_cat -i20 -o20 -bpercentage -P50 --colour=Green& \
osd_cat -i20 -o40 -bpercentage -P60&  osd_cat -i20 -o40 -bpercentage -P50

I get this view on screen:
I did it twice, to show you the effect better. Above I used a different color for the later-created bar to make the effect clearer, below is how it would look in the real world if you bound that script from the archlinux wiki to a volume key and pressed that twice.

That's where that killall command comes in. What it does is, it clears all previously existing percentage bars from the screen, allowing those created right after to replace them instead of overlapping them. To tell the truth, that killall command could probably be written a little more specific so it won't kill all osd_cat instances but only those associated with the script. I'll probably re-do that, latest when I find another use for osd_cat which clashes with what I have now.

Guess that about sums it up for today. Now that I've taught you  how to make key combinations execute commands and what key commands to use to control alsa, and as a little bonus how to work those nice percentage bars of xosd's, go out there and knock em dead!

Saturday, October 20, 2012

Grub conks out, Lilo to the rescue

It would seem that I say goodbye to an ever-increasing number of established wisdoms and state-of-the-arts of the Linux world these days. After getting rid of both KDE and Gnome some time back, now it's Grub, the GRand Unified Bootloader, that has drawn my displeasure. Here's the story why.

Actually I never paid a lot of attention to boot loaders until two weeks ago or so. To me, they simply were "that magic that makes Linux boot" - Well, there's a time for everything, which is usually when something stops working. When I found out that grub would conk out with a cryptic error message the minute I stuck my shiny new RAID-Controller into it's assigned slot, I decided that now was the time to get into boot loaders.

After searching the web for that particular error didn't yield any result whatsoever, I did what I always do in such cases: logged on to IRC and asked the guys who develop the gizmo itself if they knew what the trouble was.
Tinkerer's Tips No. 6:
If you're in trouble, the Web is your friend. However, your best friends are mailing lists, forums and IRC, because there you will get something you won't find on the net: custom-fabricated answers.
As a matter of fact, they did know what that error meant: It meant that some thingamabob named int12 conked out, likely because of some weird memory-mapping issue. Their solution was: use Grub 2.00.

It turns out however, that no major distro offers 2.00 except in their most bleeding-edge distros, which I sure as hell didn't want to install over my smooth-running Linux.
Tinkerer's Tips No. 7:
Never ever try to solve a problem in an otherwise stable system by using experimental stuff. It just might solve the original problem, but it sure as hell will create a truckload of new ones - and often enough there's no way of telling beforehand if you can safely revert back to the original configuration
Not that I didn't try to shoe-horn in grub-pc from Debian Sid, but after having a cursory glance at the dependency tree, I discarded that solution rather quickly. Not that I didn't try to compile Grub 2.00 from source (nobody shall say I shy back from a little compiling) but that broke off with a few cryptic, very likely library-version-related errors, see above.
Well, what was to be done? Actually I had exactly three options: sell my shiny new RAID controller, shelve it until Debian shipped the 2.00 Grub (which likely wouldn't be until the next version after Wheezy) or try another boot loader.

Since Options 1 and 2 would leave me without the data security I craved (See New toys: LSI MegaRAID 9240-8i for why) at least for the foreseeable future, and since I didn't even know if Grub 2.00 would fix the problem - I couldn't find any live distro shipping with it either - it was pretty much a foregone conclusion. Writing this, I must say that now I see why several professional distros still use LiLo and not the vaunted grub, VMware's ESXi for instance, which I'm using at the office, and which doesn't have a problem with the very same controller card.

 Just to be fair: Others report that they have that specific card - the LSI MegaRAID 9240-8i to be exact - running fine with Grub, so there's probably another factor involved. Likely it has something to do with the chipset, which, watercooling junkie that I am, I can't change any easier than I can my bootloader, and certainly not as cheaply.

So I got into Lilo. If I'm telling you that I'm writing this on a computer containing said RAID controller, will it tell you how I fared?
So: How about we go hands on and I tell you how I did it?

OK, here's my lilo.conf for starters: (don't worry, I'll go over it line by line later.)

boot=/dev/sda
map=/boot/map
install=/boot/boot.b
prompt
timeout=100
compact
lba32
vga=795
default=Linux
image=/boot/vmlinuz-2.6.32-5-amd64
        label=Linux
        initrd=/boot/initrd.img-2.6.32-5-amd64
        root=/dev/mapper/system-root
        read-only
other=/dev/sdb
        label="Chainload Grub"
Looks simple compared to a grub.cfg, doesn't it? Well, you know my views: KISS, and it does the job, or I wouldn't be here. So here's the promised line-by-line breakdown:

boot=/dev/sda
This is the device where lilo will install the bootloader. Just like always: you can install either into a mbr or into a partition. If you install into a partition, you're going to need another bootloader in an mbr somewhere chainloading into lilo. More about that later. Note that in many howtos on the net, there's still a hda or something there, because many tutorials on Lilo haven't been updated since grub sucked it's thumb. Rule of same: what you see if you run

ls -1 /dev/ |egrep '.d[a-z][0-9]+$
will fit there fine, as will all symlinks in /dev/disk . Basically, this can be any device you can imagine, including but not limited to multi-devices like Linux software-raids and lvms. How much use it is to install into some logical volume that the bios never sees is another question, but Lilo definitely can be installed into traditional Linux multi-devices. There are a few specific configuration options for that, but that's beyond the scope of this post.

map=/boot/map
install=/boot/boot.b
Internal stuff for Lilo, specifically files it creates during install. If you have more than one installation of Lilo sharing the same /boot, you're going to have to modify those, otherwise you can just leave them alone.
prompt
timeout=100
Orders Lilo to display a prompt or OS chooser the way grub does. The timeout value is in tenths of seconds, so in this case the timeout is ten seconds.

compact
lba32
Informs lilo that it's going to be installed inside a large device and orders it to chunk several read operations into one if possible to improve performance. Doesn't do a lot these days, but is still standard, in case somebody wants to install in a disk from the mid nineties.

vga=795
Passes the video mode to the kernel on boot, in my case 1280x1024@24bit.  If you're not sure what to use, stick with vga=normal and put up with those ugly, two-feet-high characters. If you don't want to, look up the video settings for your monitor and graphics card on the interwebz. Hint: it's the exact same for grub, so don't bother looking for anything special for lilo.

default=Linux
Sets the default entry to boot after the timeout runs out. Use the same value you use for label(see below).


image=/boot/vmlinuz-2.6.32-5-amd64
        label=Linux
        initrd=/boot/initrd.img-2.6.32-5-amd64
        root=/dev/mapper/system-root
        read-only
Every entry in the lilo.conf starts with an image entry, giving the local path to the linuz-image to use. Don't worry about what lilo does with that, you'll only give yourself worry lines. It has to be there, it has to be correct and it starts a new entry in lilo.conf.

label=Linux
Next comes the label. That's important for two reasons: because it identifies the entry in the Lilo boot menu (so you can find it) and because it goes into the default entry mentioned above.

initrd=/boot/initrd.img-2.6.32-5-amd64
The initrd option is pretty much self-explaining too, there usually is one for every kernel image you have, except on very exotic systems. When you don't have one each, or don't use one at all, you'll probably not get a lot new info out of this howto anyhow, and those cases are beyond the scope of this article (and me, for that matter) anyways.

root=/dev/mapper/system-root
The root option specifies what you want to have mounted as your rootfs. Again, use whatever you can find in your /dev/disk, /dev/mapper or any other block device. Choose wisely though, because if your root filesystem isn't what it is supposed to be, you're lucky if you have a good initrd that can present you with an emergency shell to find out where the problem lies.

read-only
This option specifies that the root filesystem should be mounted read-only on boot, because the boot process will automatically re-mount it read-write after fsck-ing it.

other=/dev/sdb
        label="Chainload Grub"
Ok, I admit it: I was lie-to-childrening when I said every entry begins with an image option - here's one noteable exception. Blocks beginning with the other option are chainloading entries, as an option they take the device where the other (sic!) boot loader is located.

Well, that's all for today. Hope what I wrote helps somebody who faces the same problem I did to switch over to Lilo without all the research and hassle I had to endure to scrape together all the info I did need.

Have fun!

New Toys: LSI MegaRAID 9240-8i

Lately, I had a bit of a scare: One of my HDDs started acting funny - guess what, it was the one I added unmirrored, because I couldn't get a second one. It was the time of the great flood in Thailand and hard disks were both devilishly expensive and in short supply.

Well, it turns out It was just a loose connector, but it still yanked me out of my comfy, trusty world once more, even more so since that specific drive is packed to bursting with my digital negatives. I know I haven't written anything about my new digital camera yet (shame on me), but I promise I will - any day now...

Well, bottom line, I decided I'd never be that scared again. To that end I took some serious money in hand (almost 300€) and bought myself some top-of-the-line hardware: An LSI MegaRAID 9240-8i card, said by LSI to
"allow small to medium business owners and gaming enthusiasts to enjoy the latest RAID technology at affordable price"
Though I'm neither, I guess it applies to hardware enthusiasts and fanatic hobby photographers as well.

As of writing this, I've finally got it working. You may be wanting to read about part of my oddyssey here:  Grub conks out, Lilo to the rescue 

By now I've found out that:
  • Grub from Debian Squeeze/Wheezy won't work with it on a Gigabyte GA-870A-USB3 board
  • Lilo from said distros however does work with that board-controller combination
  • RAID5 will produce a kernel panic both with the 2.6 kernel from Squeeze and the 3.2 kernel from Wheezy on above board
  • RAID5 can work with that controller/board config, as is proven by Arconis DiskImager which I used to rescue my data from the array after the RAID5 experiment blew up in my face. Alas, I have yet to figure out how they do it.
As of writing this, what remains to be done (besides getting RAID5 to work) is getting the Megaraid Storage-Manager (short MSM) to work with Debian. In case you face the same problem: Don't bother with the hints in the LSI Knowledge Base, they don't work. Check back in three weeks (after my vacation) for an article on wether or not I eventually got it working.
Also check back here for how I finally scraped together the courage to include the controller in my liquid cooling system, but that won't happen so soon...