lørdag den 29. maj 2010

Getting your multimedia keys/remote control to work under X11 - by hacking your kernel

Right, so I have a media center (who doesn`t these days), and ofcourse a remote control for it.
My problem is, that I`ve got a Logitech ultraX media remote.
It is a nice remote, but only some of of the keys on the remote works out of the box
Heres the story of how I got all of my keys working.


The underlying problem
The underlying problem to all of this is that X11 does not support more then 255 different keys.
This is fine for most purposes, but not many media keys are included in these 255 keys.
Meny (if not all) common keys are mapped with a low keycode (range 0 to 200 (like letters and numbers), but many specialized meida keys are mapped much higher.

Testing to see if your keys really are dead in X
The first thing I did when trying to get the keys working, was running xev, which tells me if X recieves the input (key press in my case), and what that input is mapped to.
The problem was, that xev didn`t recieve any input from the buttons that did not work.
If your key press is detected in xev, this guide is NOT for you!
This guide is for getting your keys to register in X (xev)!

Solutions/Remedies for the problem?
After googling a bit I quickly found a MultimediaKeys guide on the gentoo-wiki.com site, which suggested running "showkey" from a real console (to open a real console hit alt-ctrl-f1).
When doing so, it registered my input, and showed a corrosponding keycode, but no scancode.
Output from showkey, when pressing some of the non-working keys in X (subtitle, language, dvd, music and repeat keys on the remote were pressed here):
showkey
kb mode was UNICODE
[ if you are trying this under X, it might not work
since the X server is also reading /dev/console ]

press any key (program terminates 10s after last keypress)...
keycode 28 release
keycode 370 press
keycode 370 release
keycode 368 press
keycode 368 release
keycode 389 press
keycode 389 release
keycode 391 press
keycode 391 release
keycode 129 press
keycode 129 release
The first line above (keycode 28 release) is the enter key being released (after executing the command).

I didn`t note it at the time, but the buttons that worked had keycodes lower then 255, and those that did not had keycodes higher then 255.
TAKE NOTE OF THIS, IT IS IMPORTANT!

So, first I thought it was because the input did not generate any scancodes (showkey -s shows generated scancodes, and showkey -k shows generated keycodes) - (but none of the keys do, and some of them work), so that wasn`t it.
So I hacked around a bit to generate some fake scancodes, but this was/is a dead end, and is not needed.

Using keytouch
The gentoo wiki guide suggested using a application called "keytouch" to get the keys working.
The keytouch application is used as a system service, and translates keycodes higher then 255 to lower keycodes, or it can map key presses directly to program commands.
I`ve tried keytouch; When starting the service (you can only do this after you`ve selected a keyboard/remote or created your own), I get this output (which means it does not work):
* Service keytouch starting
keytouch-init: Failed to set keycode:
keycode 148 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 149 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 202 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 203 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 227 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 141 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 225 to scancode 786 (0x312)
keytouch-init: Failed to set keycode:
keycode 224 to scancode 786 (0x312)
keytouch-init: Failed to set keycode:
keycode 231 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 124 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 235 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 219 to scancode 786 (0x312)
keytouch-init: Failed to set keycode:
keycode 147 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 129 to scancode -57260 (0xffff2054)
* Service keytouch started
So, no luck there :-(

Alternate solution - hacking the kernel
I figured the easiest way would then be to just change the mapping of the non-working keys to a lower keycode, this way I also don`t need yet another system service running, and I really want as few of those as possible (both to reduce system boot time, and to conserve system ressources).
The next step requires compiling your own kernel.
If you don`t know how, read the documentation for your distro (it's not covered here).
I`m running gentoo linux on all of my systems, so I`m quite comfortable compiling my own kernel, so heres what you need to do, once you know how (and has otherwise configured your kernel correctly for your own system).

Determine what keycodes needs to be remapped
Run showkey from a real console (as described above), and write down all the keycodes for the keys that does not work.
Note: showkey shows the keycodes in decimal form, and later you`ll need them in hex, so you may want to convert the numbers as you write them down.
For instance, take the Subtitle key from the showkey output above, it has a keycode of 370 in decimal, and thus becomes 0x172 in hex.

Remap the keys
Now edit /usr/src/linux/include/linux/input.h
In this file you will find all the defines for the keycodes that the linux kernel can generate.
Now, search for the keycodes you`ve noted down (remember to search for the converted hex numbers).
Once you have found a #define match, change the value to something lower then 248 (Range 248 - 255 is reserved for special needs of AT keyboard driver acording to a comment in input.h) - (you don`t have to write the value down in hex, you can write it in decimal if you want).
You`ll be remapping your keys to a keycode that most likely is already used, and the system won`t know the difference between these, so think about how you remap!

For the subtitle example, here the relevant part of input.h (lines 472 to 477):
#define KEY_LANGUAGE 0x170
#define KEY_TITLE 0x171
#define KEY_SUBTITLE 0x172
#define KEY_ANGLE 0x173
#define KEY_ZOOM 0x174
#define KEY_MODE 0x175
I`v changed the value of KEY_SUBTITLE to 183.
This means that the susbtitle button will ack like the F13 key (because it has a keycode value of 183) - (which I don`t have on my keyboard, and don`t use - since I have never heard of it).
You can also remap them directly to something else, like the arrow keys, if you know how you are going to use them.
For instance if you are going to use them in mythtv, or some other application where you`ll need s, m or any other key, this might be simpler, however it does not give you as much control over your keys as they will always ack like and s or a m.

I`ve remapped every key on the remote having a higher keycode then 255, to something else f14,f15...f24 and others.

Save, recompile and reboot
Once done, save input.h, and recompile your kernel (do a make clean first, to ensure the new values are used).
Now install your new kernel and reboot.

Testing if it works
Once rebooted, start X, fire up xev, and viola, all your keys now work (as whatever you remapped them to).


Why the 255 limit?
Q: So why does X only allow for 255 keys?
A: I don`t know!
The X11 protocol was released in 1985, and they properly didn`t think it was an issue.
The problem shound be fixed in X12, but no-one really knows when this is comming out.

Are there any drawbacks?
Yep, sure:
  • One drawback to this is that you can`t use one key to create keycombo`s.
  • Every time you update to a new kernel, you`ll have to patch it with your own remapped values.

Any suggestions?
I suggest remapping to the f13...f24 keys, and then let mythtv, xbmc or xmodmap remap the keys from there, as it gives you more control, and the abillity to make key combinations (keycombo`s).

References

tirsdag den 25. maj 2010

HTC Internet sharing and linux (gentoo)

As previous mentioned, I have a HTC Tattoo, and now that I've gotten familiar to it, I really like it.

Now, on topic:
The HTC Tattoo offers a "Internet sharing" option when it is connected to a computer via USB.
The driver installation on Windows sucks (at least on Danish windows installs - as it fails without installing the drivers), however, under linux, all you need is a couple a modules, and you're ready to go.

Here's the dmesg output when I connect the phone:
[101272.454938] hub 1-6:1.0: state 7 ports 4 chg 0000 evt 0002
[101272.455227] hub 1-6:1.0: port 1, status 0101, change 0001, 12 Mb/s
[101272.559111] hub 1-6:1.0: debounce: port 1: total 100ms stable 100ms status 0x101
[101272.570240] hub 1-6:1.0: port 1 not reset yet, waiting 10ms
[101272.632287] usb 1-6.1: new high speed USB device using ehci_hcd and address 18
[101272.644235] hub 1-6:1.0: port 1 not reset yet, waiting 10ms
[101272.725235] usb 1-6.1: default language 0x0409
[101272.731235] usb 1-6.1: udev 18, busnum 1, minor = 17
[101272.731241] usb 1-6.1: New USB device found, idVendor=0bb4, idProduct=0c01
[101272.731246] usb 1-6.1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[101272.731252] usb 1-6.1: Product: Android Phone
[101272.731257] usb 1-6.1: Manufacturer: HTC
[101272.731261] usb 1-6.1: SerialNumber: SH9CVLG00376
[101272.731390] usb 1-6.1: uevent
[101272.731423] usb 1-6.1: usb_probe_device
[101272.731430] usb 1-6.1: configuration #1 chosen from 1 choice
[101272.733488] usb 1-6.1: adding 1-6.1:1.0 (config #1, interface 0)
[101272.735621] usb 1-6.1:1.0: uevent
[101272.735661] usb-storage 1-6.1:1.0: usb_probe_interface
[101272.735672] usb-storage 1-6.1:1.0: usb_probe_interface - got id
[101272.735760] scsi9 : SCSI emulation for USB Mass Storage devices
[101272.735924] drivers/usb/core/inode.c: creating file '018'
[101272.735963] usb-storage: device found at 18
[101272.735966] usb-storage: waiting for device to settle before scanning
[101272.759587] usb 1-6.1: uevent
[101275.271385] hub 1-6:1.0: state 7 ports 4 chg 0000 evt 0002
[101275.271598] hub 1-6:1.0: port 1, status 0101, change 0001, 12 Mb/s
[101275.271605] usb 1-6.1: USB disconnect, address 18
[101275.271610] usb 1-6.1: unregistering device
[101275.271615] usb 1-6.1: usb_disable_device nuking all URBs
[101275.271624] usb 1-6.1: unregistering interface 1-6.1:1.0
[101275.274280] usb 1-6.1:1.0: uevent
[101275.274530] usb 1-6.1: uevent
[101275.379244] hub 1-6:1.0: debounce: port 1: total 100ms stable 100ms status 0x101
[101275.390236] hub 1-6:1.0: port 1 not reset yet, waiting 10ms
[101275.452284] usb 1-6.1: new high speed USB device using ehci_hcd and address 19
[101275.464233] hub 1-6:1.0: port 1 not reset yet, waiting 10ms
[101275.543241] usb 1-6.1: skipped 4 descriptors after interface
[101275.545238] usb 1-6.1: default language 0x0409
[101275.551238] usb 1-6.1: udev 19, busnum 1, minor = 18
[101275.551243] usb 1-6.1: New USB device found, idVendor=0bb4, idProduct=0ffe
[101275.551249] usb 1-6.1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[101275.551255] usb 1-6.1: Product: Android Phone
[101275.551259] usb 1-6.1: Manufacturer: HTC
[101275.551263] usb 1-6.1: SerialNumber: SH9CVLG00376
[101275.551383] usb 1-6.1: uevent
[101275.551418] usb 1-6.1: usb_probe_device
[101275.551425] usb 1-6.1: configuration #1 chosen from 1 choice
[101275.553481] usb 1-6.1: adding 1-6.1:1.0 (config #1, interface 0)
[101275.553898] usb 1-6.1: uevent
[101275.555614] usb 1-6.1:1.0: uevent
[101275.555660] usbserial_generic 1-6.1:1.0: usb_probe_interface
[101275.555666] usbserial_generic 1-6.1:1.0: usb_probe_interface - got id
[101275.555687] rndis_host 1-6.1:1.0: usb_probe_interface
[101275.555692] rndis_host 1-6.1:1.0: usb_probe_interface - got id
[101275.569291] usb0: register 'rndis_host' at usb-0000:00:1d.7-6.1, RNDIS device, fa:6a:94:9d:b9:49
[101275.569324] usb 1-6.1: adding 1-6.1:1.1 (config #1, interface 1)
[101275.570622] usb 1-6.1:1.1: uevent
[101275.570691] drivers/usb/core/inode.c: creating file '019'
[101276.342616] usb 1-6.1: link qh32-0001/f6435900 start 11 [2/0 us]
and lsusb has this to say:
Bus 001 Device 019: ID 0bb4:0ffe High Tech Computer Corp.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x0bb4 High Tech Computer Corp.
idProduct 0x0ffe
bcdDevice 1.00
iManufacturer 3 HTC
iProduct 2 Android Phone
iSerial 1 SH9CVLG00376
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 67
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 256mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 255 Vendor Specific (MSFT RNDIS?)
iInterface 6 HTC Ethernet Sharing
CDC Header:
bcdCDC 1.10
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
CDC ACM:
bmCapabilities 0x00
CDC Union:
bMasterInterface 0
bSlaveInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 9
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0
iInterface 6 HTC Ethernet Sharing
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x84 EP 4 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Device Qualifier (for other device speed):
bLength 10
bDescriptorType 6
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
bNumConfigurations 1
Device Status: 0x0000
(Bus Powered)
For this to work, I have enabled the following modules in my kernel:
rndis_host
cdc_ether (with rndis support)
usbnet

These are found under:

  • Device Drivers --->
    • Network device support --->
      • USB Network Adapters --->
        • Multi-purpose USB Networking Framework
        • Host for RNDIS and ActiveSync devices (EXPERIMENTAL)
    • USB support --->
      • USB Gadget Support --->
        • Ethernet Gadget (with CDC Ethernet support)
        • [*] RNDIS support

Next, you'll just need to create a symlink from net.lo to net.usb0 in /etc/init.d/
cd /etc/init.d/
ln -s net.lo net.usb0
This will get the device working under gentoo at least.

lørdag den 30. januar 2010

Installing linux (gentoo) on a usb pen...

I've just received my newest toy; a Zotac ITX-F board (Atom N330 and nVidia ION).
I'm going to use it as my media center because (oddly enough) it is the only Pc in my house that can play 1080p files (because of the vpdau support in mplayer).

The real issuse here was to install gentoo on it. First I wanted to do a NFS (diskless) install on it, but since my server is only running 32bit gentoo, I could not chroot into the new installation dir.
Instead I decided to use a 8gig usb pen drive, and just use that as primary storage.

The installation went just fine, but once rebooted the kernel would panic and complain about not being able to mount root:
Root-NFS: No NFS server available, giving up.
VFS: Unable to mount root fs via NFS, trying floppy.
VFS: Cannot open root device "sda2" or unknown-block(2,0)
Please append a correct "root=" boot option; here are the available partitions:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)

I found out you have to append rootdelay option to your kernel, this should give the usb storage time to settle and thus be scanned and become available to the system.

My kernel boot line is now:
kernel /boot/kernel-2.6.31-r7 root=/dev/sda2 video=uvesafb:1280x1024-32@60,ywrap,mtrr:3 rootdelay=5

And it works :-)


And just a note on my previous post.
I found two program that might do the trick:
  • GO Contact sync (http://www.webgear.co.nz/Products/GOContactSync.aspx)
  • Sync2 for Microsoft® Outlook® (http://www.sync2.com/)
GO Contact sync is open source, and thus free, but I could not get the program to work (Match not found).
The other program is not free, but you can download it as a fully functioning trial, and so I did.
It works, and syncs like it should, with just one exception: It does not sync contact images (luckily the HTC Tattoo can match people with their facebook profiles, so I'll just just the profile pictures from facebook).

torsdag den 28. januar 2010

I got myself a new phone: Meet HTC Tattoo

For the amount this phone costs, it is atually quite nice.

Theres just one thing I wanted to share with you for now.
If you configure more then one calendar on the thing, you can't select which one is the default.

I found out that the phone just uses the first one you set up.

So, after having configured my Exchange calendar (for work) and google calendar(for private) use, I had to delete my Exchange, and create it again.

Otherwise it would select the Exchange as default, and I dont want to accidentially add my personal stuff to my work calendar.

Now, the next challenge is to add my contacts (with pictures) to it.
I know I can import contacts to google via CSV file(s), but this does not contain the picture (also there are some teouble using this method, since my outlook is in danish, and the csv file's header is in danish, so they don't match what google's import expect's).