The Zalman HD160XT is equipped with a remote control receiver, a set of buttons and a turning knob on the front, and a control interface which is able to set the speed of the internal fans and measure the temperature on two internal strips. All of this is accessed through an USB-to-Serial interface of the FTDI-type. It is an OEM-version of a variant of the M-Play Blast from VL-System in Korea.

Note, that the buttons underneat the LCD display is directly coubled to the display and the PC has no access to them.

Temperature/Fan control

The temperature control interface has been investigated here and here. I have for some unknown reason been unable to get this hack to work, but as the Zalman Windows software (Zini) cannot find the remote control/temperature unit either, I suppose it is broken on the temperature side. As I do not need it (allthough it could be fun to experiment with), I did not consider it worth the trouble to send the cabinet back for repair/replacement on that account. Anyone interested could themself install the driver under Windows and then sniff the communication using e.g. Free Serial Port Monitor.

Note, that one user has found that the operation of the fan control influences the IR receiver sensibility, so setting the fan speed directly (rather than leaving it on automatic) reduces the receiver sensibility. This has not been confirmed elsewhere.

The Remote Control Receiver

The temperature sensors and control are multiplexed on the same USB-based serial link as the remote control. The remote control is again buildt together with the case buttons, whereas the volume turn knob is signalled using the modem control lines on the virtual UART. The Remote Control Receiver is based on an FT232RL from FTDI rs232-to-USB chip and sends the data on a 'virtual' serial link. The kernel module ftdi_sio will detect it and install it as /dev/USBttyX. In the following it is assumed that the device is on /dev/USBtty0 - if you have it otherwise, please correct as necessary.

The lines in /var/log/dmesg identifying this is something like:
usbcore: registered new interface driver usbserial
drivers/usb/serial/usb-serial.c: USB Serial support registered for generic
usbcore: registered new interface driver usbserial_generic
drivers/usb/serial/usb-serial.c: USB Serial Driver core
drivers/usb/serial/usb-serial.c: USB Serial support registered for FTDI USB Serial Device
ftdi_sio 3-2:1.0: FTDI USB Serial Device converter detected
drivers/usb/serial/ftdi_sio.c: Detected FT232RL
usb 3-2: FTDI USB Serial Device converter now attached to ttyUSB0
usbcore: registered new interface driver ftdi_sio
drivers/usb/serial/ftdi_sio.c: v1.4.3:USB FTDI Serial Converters Driver
Note, that if the interface as above is detected as an FT232RL rather than just FT232, you should read the paragraph Newer kernel below.

When the serial UART is initialized using 38400 baud 8n1, the module will report single-byte codes for each button on the remote and also for the hotkeys on the enclosure itself - in fact, they share the codes with the corresponding buttons on the remote. There are however two exceptions:
1) The turning knob can be pressed and reports 'mute', but the turning up and down signals the CTS and DCD virtual modem control signals in a grey-code like manner, which is incompatible with lirc.
2) The power button on the enclosure will always work as a normal ATX power button (and can thus be captured by ASPI). The remote control power button however will do the same if the virtual serial port is not open. If the serial port has been opened, it will just signal a code and NOT activate the ATX power button to the motherboard.
The latter case means, that if the FTDI UART is not explicitly closed before suspend, it will remember its state (as there is power on the module through the ATX standby voltage), and continue to just send USB messages in stead of resuming the system!

For some reason, my motherboard (an Asus P5KPL with an Intel G31, and it has been seen on others) will not boot unless the USB port corresponding to the remote control interface is set to have 5VSB, i.e. 5V enabled when the system is shut down. This could maybe cause the module to fail to detect the system suspend.


The common way to get a remote control to function under Linux and X is using lirc. This is a very versatile package with various tools for executing programs and simulating keypresses and mouse clicks, and many multimedia apps comes with build-in lirc support. This includes mplayer, vlc, xine, and mythtv.

I have unfortunately been unable to find a lirc driver, which can initialize and use an USB-based UART with direct single-byte output, as well as it would not be able to receive the turning knob.

Update: I have later found some drivers aiming at the Zalman HD135 enclosure including a VFD and no turning knob. But the remote control function as well as the other buttons on the case should function with this driver. It has the advantage of being a native lirc device.
And an irserver-based approach is described here.

ZalmanRemote driver

So in stead I have written a small driver program, which simply opens and reads the input on the FTDI device. The events are then output through a pseudo device in an event-format suitable for the lirc dev/event driver. To use it, grap my ZalmanRemote driver here and compile it (a precompiled version is included). Try to run it. You should now be able to receive remote control commands as well as to register enclosure button presses and the turns of the knob - at least on the screen ;-) Note, that if your device is not connected at /dev/USBtty0, you have to give the ZalmanRemote the correct device as an argument, e.g. ZalmanRemote /dev/USBtty0

For kernels 2.6.19 - 2.6.23

This works fine in kernel 2.6.18 for me, and probably also a long time before this. But for kernel 2.6.21 and 2.6.22 the above might result in an IOCTL error message and telling there is a problem with the ftdi_sio driver.

Under kernel 2.6.21, the ftdi_sio has been updated to differentiate between several FT232-chips - notably the FT232RL and the FT232BN - and only enable the ioctl() interface for the latter :-(
The solution is to patch the kernel and build the module again - using the ftdi_sio.c found here - or to patch the file yourself: go through the file and include a check for FT232RL where ever a check for FT232BN is found. Or grab the 2.6.18 version of the file. Copy the file over the existing file in e.g. /usr/src/linux-source-2.6.21/drivers/usb/serial - and then recompile and install the kernel modules :-(

For later kernels (at least 2.6.24), this is fixed in the sense that the ioctl() has enabled also for the FT232RL, where it still works - at least for our use.

Setting up lirc

When ZalmanRemote is running, you need to install and setup the lirc package. Assuming it is installed, your /etc/lirc/hardware.conf should be like: DRIVER="dev/input"
# If DEVICE is set to /dev/lirc and devfs is in use /dev/lirc/0 will be
# automatically used instead DEVICE="/dev/remotecontrol"
# Default configuration files for your hardware if any
The /etc/lirc/lircd.conf must contain the definitions of the single-byte button codes (note: lirc sees them as 32 bit in the event-format) in lirc format. This thus also defines the protocol of the remote control FTDI interface too. Note however that the codes fro Knob_up (0x02) and Knob_dn (0x04) are generated by the ZalmanRemote and thus does not appear directly from the FTDI interface. Note also, that the codes Up, Left, Right, Down, OK, Mute and Back can also come from the buttons on the enclosure.

You can now start lirc and should be able to se the button presses using the irw utility from the lirc package. Then you need to tie them to actions. This is done in the ~/.lircrc file. You may use my files for inspiration or a template. They are divided into a main ~/.lircrc and application-specific included files residing in ~/.lirc.

To start programs, I use irexec from the lirc package. It is started when X starts by calling a small script. Try it from a non-root xterm. If it works, insert it in the list of programs for X to start on start-up. I also run another irexec to suspend and to eject the DVD - but this is done as root (it requires some more work to suspend as an ordinary user!). It is started by the lirc startup-script in /etc/init.d/lirc and uses a global configuration file.

When the system is suspended, it should be possible to wake it up using the remote control. But this requires the ZalmanRemote driver to close down the serial connection, as the FTDI IR receiver will otherwise just send the "power" IR code to the USB driver rather than toggle the ATX power switch. This may be done by executing /bin/stty -F /dev/ttyUSB0 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 but this will kill the ZalmanRemote driver connection. Therefore the lirc system must be shut down too before suspend and started again after. I do this by the mysuspend script, se also here.

The irexec program started with X will get into trouble if lirc is shut down. It is therefore also stopped. And all the programs I use remote control for will only work if started after the currently running irexec. If lirc is shut down, these programs are therefore also automatically killed. While they are not started when lirc comes up after resume, the irexec is, but as the lirc start script is started as root, we have to su to the mythtv user before. Therefore the irexec startup script is started via a helper script. In my configuration, these two resides in /home/mythtv. Remeber, they must be made executable by the mythtv user. The latter may be omitted if the command was inserted directly in /etc/init.d/lirc but I have made it of historical reasons and to ease testing.

All this is then combined in a modified /etc/init.d/lirc. Note, that if your device is not connected at /dev/USBtty0, you have to give the ZalmanRemote the correct device as an argument after the "--".

More help on setting up lirc can be found here.