Sunday, March 30, 2008

Writing my first linux driver - Part 1

I've always wanted to write a driver for a piece of hardware, but hadn't the slightest clue how to go about it. It seems like such a complex process...interfacing with the system at the kernel level, dealing with the necessary subsystems (ex: USB), reverse engineering the device's communication protocol. Where does a driver writing noob even begin?

Getting my inspiration

Luckily, I found a very insightful and well written series of articles by Greg Kroah-Hartman, who is the official maintainer of (among other things) the linux USB subsystem code. In his series, he covers all kinds of topics dealing with driver writing. Theres a lot of content, and it's not exactly laid out in step-by-step tutorial form. Still, it is by far the best resource out there that I've seen so far.

A list of the articles is located here. Lots of those articles are useful, but the most enlightening for someone getting started were the articles on writng usb drivers, writing your first kernel space driver, then rewriting the driver as a user space driver. In addition, the article on snooping the usb stream was helpful in figuring out how to reverse engineer a devices protocol from the working Windows driver that almost every usb device has.


Choosing a device for my first driver

So now that the series of articles had inspired me, I needed a piece of hardware to serve as my first driver. I quickly figured out a way to kill 2 birds with one stone.

I've been having some success getting my LCD working, but I've been having some trouble with the IR part of it. It seems that when the IR sensor receives certain signals, it locks up and stops responding. However, it works fine under Windows, so theres some issue in the current linux driver for this device.

The device seemed to be simple enough. I didn't envision a lot of back and forth communication. I envision a one way stream of incoming data for the IR sensor, and another of outgoing data to write to the LCD. The hardware didn't appear to have a lot of conditional states built into it. That meant there probably woulnd't be a lot of tricky reverse engineering such as "this command does X if the device is doing A, but Y if it's doing C, or Z if it's doing C or D" etc. Nope...it appeared it would (hopefully) be fairly straight forward.


Reverse engineering the protocol

If I needed to, I could always try to strip some protocol information out of the existing partially working driver. However, I figured it would be best to start out from scratch (that would be the most rewarding experience for my learning process).

I downloaded a copy the Snoopy program for Windows, hooked the LCD up to my Windows system, installed the drivers, and started monitoring the stream with Snoopy. Snoopy has it's pluses and minuses. It's very simple to use, but it doesn't let you monitor the stream in real time. It records it all to a log file, which you can later look through. The entries are all timestamped (relative to the start of the log), so you can tell what happened and when.

So first thing I did way was start up the log and watch the event counter grow. After a couple seconds, the counter stopped. I waited 10 second and the count remained steady. Great...that means I can look at that bunch and treat it as the initialization code. I then pressed a single button, waited for the event counter to stabilize, and then waited another 10. Then I started doing the same with other things (turn the volume knob, hit the menu key, switch the driver into graphic eq mode, etc).

At the same time I was doing this, I was writing down on paper a list of what actions I took at each step, and what type of feedback I got for each action (text on the LCD changed, an icon blinked, etc). After doing this for about a dozen different actions, I stopped and saved the log file.

Now, all I had to do was go through the list and start picking out some common things. I saw that every event had one pair of command codes in common. Looking at my notes, the one thing that every event had in common was that it blinked a particular icon. I now figured out the first code was to turn the icon on, and the other to turn it off.

Comparing them, they were very similar codes. Almost all zeros, except for the last byte (which was identical), and one of the other bytes had a single bit set in one of the codes but not the other. I quickly figured out that the last byte indicated that we were toggling the icons, and which bits were set in the other bytes indicated which icons to turn on.

I then looked at my written list. One of the other action had toggled a different icon. I suspected that If I looked in the corresponding series of events, I'd find an event where the command code had the same last byte, but a different set of bits turned on in the other bytes. Indeed, there was. I had now figured out how to toggle the icons. All that was left was to determine which bits handle which icons...a trivial task.


Comming Attractions!

Before I got much further in the debugging, I decided I needed to test my theory about the icon command. It was time to start writing a very basic driver. In my next post, I'll cover writing the first bits of driver code and putting my theories about the protocol to the test.

...click here to read more!

Wednesday, March 26, 2008

Got my Thermaltake DH-101 case with iMon LCD

I'm currently in the process of building a dedicated frontend box for my living room. Choosing most of the hardware was easy, since I'm modeling this after my other myth boxes. However, for the case, I wanted something that would blend into the entertainment center a bit better.

After looking for options for several weeks, trying to decide which HTPC case I like, I finally settled on the Thermaltake DH-101 case. It arrived yesterday, and I quickly began putting it together. Once it was up and running, my first task was to figure out how to get the new hardware features (the LCD and front panel control buttons) working. It's been tough, but I'm making progress.


iMon hardware is not linux friendly

Not that it was any surprise, but Soundgraph (makers of the iMon hardware) have been less than helpful with using the iMon hardware on linux. They refuse to release a linux driver for the hardware, and that's really not such a big deal. There are plenty of people willing to write the drivers for them (as is usually the case for hardware under linux). However, they also refuse to release the protocol for the hardware. Thats not such a big deal either. Again, plenty of hardware hackers out there enjoy reverse engineering this stuff.

The thing that is most annoying is that, after people went through the processes of reverse engineering the protocol and writing the driver for it, Soundgraph decided to suddenly change the hardware's protocol, thus breaking a lot of the work that had been done. Luckily (as can be expected) people have already gotten underway figuring things out again.

The forums over at codeka.com have been filled with discussion about the iMon hardware, with lots of helpful advice on getting the hardware working. There's even info and patches that explain how to get the new iMon hardware (denoted by the hardware ID 15c2:0038). I wasn't having any luck at first, but I'm starting to make some progress here. I'll post more details in the coming days as I come up with a more concrete description of just what it takes.


Initial impressions on the case

The case is very nicely constructed, and looks even better in person that what I had thought from the photos. Assembly was nice and easy, organization of the case was very good. However, I do have a few complaint. First, the stock fans are quite loud. I'm going to have to replace them with something else if this is to go in the living room. Second I'm a bit disappointed with the LCD. Besides the fact that I ended up with the new "redesigned, for more difficult linux compatibility" model, I'm also disappoint by which LCD color they used.

The photos on the Thermaltake website all show the system used with the Soundgraph negative white LCD. However, the one I got is using the negative blue. Negative white has a dark, unlit background, so all you really see is the lit up elements (text and symbols). The negative blue, however, has the whole display backlight with a dimmer blue light. That has 2 downsides. First, it gives off more light. When you are in a datk room watching a movie, the fewer sources of bright light, the better. But more so than that, having the whole background lit up means less contrast for the characters being displayed.

...click here to read more!

Tuesday, March 25, 2008

Enabling Quality of Service for the HDHomeRun

A few times recently, I've had problems where I was generating a large amount of bandwidth at the same time mythtv was recording a few HD programs from my HDHomeRun. The HDHomeRun transmits its data over the network via UDP instead of TCP, so when it ends up on the losing end of an oversaturated network, it's packets just get dropped and the data is never retransmitted. The end result is a lot of packet loss, and the recording will be full of skips and other corruption. Having damaged recordings is an unacceptable situation, and was something that I needed to resolve. Simply scheduling any heavy network activity around the recording schedule was not acceptable, either. I needed a better solution.


Upgrading the network

As it just so happens, I also had another problem at the same time. My home network had grown considerably, and I was now out of ports on my router and switch. I needed to add another switch to the network. In looking around, I found the D-Link DGS-2208 and it seemed to be both inexpensive and had very good reviews. It also had something else I found interesting...support for 802.1p Quality of Service delivery.


QoS on the HDHomeRun

When I saw 802.1p support in the feature list, something clicked in my mind. I remember reading once that the HDHomeRun could enable Quality of Service flagging on its packets. I figured that would be a great feature to enable, to ensure that the HDHomeRun got priority over other devices when the network starts getting saturated.

I figured it would be as simple as changing a setting in the HDHomeRun, and all data would be streamed with a QoS flag. Do that once, and it would be transparent to everything else. I promptly opened up a support ticket with Silicon Dust to find out how to do it. I got a prompt response back indicating how it could be done.

As I expected, the solution was quite simple. Simply pass an extra flag to hdhomerun_config when you tell it where to stream the data to. Instead of

hdhomerun_config FFFFFFFF set /tuner0/target "udp://192.168.0.10:5555"

it would be

hdhomerun_config FFFFFFFF set /tuner0/target "udp://192.168.0.10:5555 qos"

(note...the quotes in the parameter list are important so that the qos string doesn't get treated as a separate parmaeter).

I gave it a try and it worked. That was a very easy solution. However, there was a slight problem here. The way this was enabled meant that a patch would need to be applied to mythtv to enable this to happen each time it opened up the stream.


Patching MythTV

The patch to make this happen wasn't very difficult. There were only a few tiny changes that needed to take place. A single line of code could be used to accomplish this, except for the fact that 802.1p tagging is applied as part of the 802.1q standard for virtual LANs. This meant in order to QoS tag the packet, the packet had to be destined for a VLAN (the HDHomeRun uses VLAN 0).

By default, linux will ignore packets that are received for a VLAN unless it has been explicitly configured to do otherwise. This means that a quick and dirty patch to mythtv would break HDHomeRun functionality for anyone who doesn't have VLANs configured, as the packets from the HDHomeRun would never be handled. Obviously, this needed to be a feature that could be toggled on/off in the capture card setup of mythtv-setup. This made the patch just a tiny bit more complex, because it requires a schema change to the database so you have somewhere to store this flag. Regardless, I was quickly able to code up the patch. I'll release it soon, but I first need to run a few things by the mythtv-dev mailing list.


Enabling VLAN support under Debian

As I mentioned, linux ignores packets destined for VLANs unless explicitly configured to do otherwise. It turns out that configuring Debian to handle a VLAN wasn't all that difficult.

The first step was to install the vlan package ( apt-get install vlan ). Once that was done, you needed load the 8021q module ( modprobe 8021q ). Finally, you just needed to tell linux to accept packets for VLAN 0 on your adapter ( vconfig add eth0 0 ). Your network is now accepting VLAN 0 packets. This created an entry for eth0.0 under /proc/net/vlan/. If you view its contents ( cat /proc/net/vlan/eth0.0 ), it will give you network usage statistics for that VLAN.

That last thing you need to do is make sure your VLAN configuration survives a reboot. Simply create a script called /etc/init.d/vlan that runs your modprobe and vconfig commands. This script can then be run automatically when your eth0 interface comes up by adding the line "up /etc/init.d/vlan" to your /etc/network/interfaces file in the section for "iface eth0".

...click here to read more!

Thursday, March 20, 2008

Patch to configure mythmusic exit action

I released a tiny new patch today. This patch is for the mythmusic plugin. It allows you to configure the action you want mythtv to take when exiting the mythmusic plugin while music is playing back.

Currently, when you are use the mythmusic pluging and are playing some music, if you try to exit the plugin (perhaps to do other things in myth), you get prompted whether you want to stop playback or contiue playback. For myself, if I didn't want the music to keep playing, I'd hit the stop key first, so getting prompted every time gets a bit annoying. In addition, if I hit a jumppoint key (perhaps to jump into the photo gallery), music playback stops instantly with no option to exit.

This patch gives you the option to configure the action to take when exiting. By default, it maintains the current behavior. However, you can also set it to always stop playing or to always continue playing. In either case, you can exit myth without being prompted. In addition, if you set it to always continue playing, it will do so even if you exit the plugin by using a jumppoint.

This patch will work with either myth 0.21-fixes or trunk.

You can download the patch file from Ticket #5008.

...click here to read more!

Wednesday, March 19, 2008

My USB-UIRT failed on me

Just when my wife was REALLY starting to take a liking to mythtv (she's been rejecting the mythbox for years, all the while desperately holding onto the TiVo), I suffered a tiny setback to my progress. I had to experience a hardware failure...my USB-UIRT died on me. Luckily my wife is pretty understanding of stuff like that, and I was able to get things back up and running quickly enough, so she really hardly noticed:

My previous IR experience

For several years, I had been using a IRA-3 serial port IR receiver from http://www.home-electro.com. I was very pleased with the device, and it served me quite well. However, when I decided to rebuild my entire mythtv system late last year, I decided I had a few additional needs. One, I wanted something that could transmit as well as receive. Second, I wanted a USB device that I could use to wake the machine up from suspend-to-ram when I pressed the power button on the remote. After searching around, the USB-UIRT seemed to be the device that best suited my needs and had some happy users.

Unhappy with the USB-UIRT

My experiences with the device, however, had been less than satisfactory. First, there had been some code reverted in the latest kernels, and the device no longer functioned without patching and rebuilding a kernel driver. After spending a lot of time figuring that out, and then finally successfully getting it all working, the next release of the kernel seemed to fix the problem, so all of my work accomplished little. However, being that linux isn't an officially supported platform for the USB-UIRT, I could hardly blame the manufacturer (well...I guess I COULD blame them for not caring to support linux).

Once the device was up and running, my next task was to program the device. I immediately had trouble, as irrecord kept telling me there was an error reading the signal. After much trial and error, I was able to brute force my way through the errors and get it to record my lircd.conf file. By contrast, my IRA-3 worked perfectly every time in this regard.

Once that was working, the next thing I noticed was that the device was VERY finicky about the remote being pointed directly at it. If I pointed it just a tad too high, low, or to the side, it would only pick up the IR signal intermittently. A little more that that and it wouldn't see it at all. By contrast, with my IRA-3, I could point the remote at the ceiling, the opposite wall, or even stand in an adjacent room and it would still pick up the remote.

Next came the task of getting the device to wake the machine from suspend. I was able to program it with my remote's power button signal and get it to wake the machine successfully. However, I then ran into the discovery that, as soon lirc tried to use the USB-UIRT, the device's state would somehow get corrupted and it would no longer wake the machine up. I would have to physically unplug the device before it would wake the system again. Thus I had my choice of using it for lirc, or using it to wake the machine, but not both.

The final straw came this weekend. The USB-UIRT was working perfectly. I left the room, came back 30 minutes later, and the red light was stuck on. The device was no longer responding to IR signals, and nothing could get it to work again (rebooting or unplugging it didn't help). There were other posting of the same problem in the support forum, but no response was ever posted by the manufacturer. Now it looks like I'll need to send it back.

Final outcome

Overall, I was quite disappointed in the device. It's performance was inferior to the IRA-3 in almost every respect. The one aspect where the USB-UIRT actually didn't disappoint me was with the IR emitter. I was able to get the IR emitter working successfully with little effort. However, I never got a chance to actually implement that aspect of it on my system, so I never got to put it through its paces.

For now, luckily my IRA-3 was still sitting around, unused and functional. I was able reconfigure my myth frontend (drivers, config files, and scripts) and get it working in relatively short order. My wife barely noticed downtime.

The only downside to the IRA-3...I've only got one serial port, and now I'm using it. I was just about set to start controlling my TV via the RS-232 serial port, but now I have to put that plan on hold. I've ordered a PCI serial port card and am waiting for it to arrive before I can continue. I've also still got to find a solution for waking the machine from suspend, and I may need to come up with another device to do the IR transmit functionality.
...click here to read more!

Blog spam is a PITA

I'm a few days later than expected in getting this blog started. It seems that google suspected my blog was blog spam (for reasons unknown) and locked it, so I had to wait for them to fix it. So, now it's time to get started...


Don't bother to click this link ...click here to read more!

Sunday, March 16, 2008

First Post

I thought it would be useful to have a place where I can put some of my daily thought on using and developing mythtv. Somewhere to talk about features I'm working on, patches I release, problems I run into, things I discover, etc.


Don't bother to click this link ...click here to read more!