It was interesting to me what is inside DS207 box, how it works and controlled. Because root access is allowed it was not very hard to do my investigation. Hardware itself is based on standard 8245 PPC CPU with 64Mb of memory. It starts booting from internal flash (/dev/mtdX) using PPCBoot 2.0.0. boot loader. After loading kernel from flash its trying to run OS from system partition and if it is not possible – waiting for commands from synology tools. If DSM is already installed then it will boot OS from the hard drive and will start the web interface and other services. Network and sata controllers are standard hardware with corresponding device drivers in kernel. They are working in a standard way, as on any other hardware. Non-standard parts in the NAS hardware are: Buttons, FAN control/sensors, and temperature sensor. We will talk how to manage them in this article.
About synobios module
To make an abstraction layer for the Synology kernel module synobios was implemented. It is not under GPL but sources are available inside synology GPL packages. This driver is different for every NAS family but providing same API for the user-land applications. Also has information about device capabilities. Driver using ioctl() to speak with userland application. Internally there is a closed-source library in DSM with all related functions implemented. I decided to re-implement them myself based on module source.
Controlling FAN(s) and getting system temperature.
I decided to start with system temperature. I found that kernel sources are missing synobios.h – header with all ioctl related structures. I found it on another directory with uclib. ioctl providing many commands, i found that only small part of them are implemented by driver.
Below is a full command list with mine short description for some commands
SYNOIO_RTC_CONTROL_READ commands to manage RTC, it is not available as normal linux /dev/rtc
SYNOIO_SET_DISK_LED sets LED disks status, actively used by scemd
SYNOIO_GET_FAN_STATUS getting fan(s) speed and status
SYNOIO_SET_FAN_STATUS setting fan(s) speed and status
SYNOIO_GET_DS_MODEL device identification, used by synobios driver
SYNOIO_GET_TEMPERATURE system temperature command
SYNOIO_GET_CPLD_REG internal registries of Complex programmable logic device. Different for every model.
SYNOIO_GET_AUTO_POWERON get/set power on after AC failure?
SYNOIO_GET_MEM_BYTE direct memory operations, don`t think that is in use
SYNOIO_GET_HW_CAPABILITY getting device capabilities, actively used by DSM
SYNOIO_GET_CPU_TEMPERATURE CPU temp., supported only by few devices
SYNOIO_SET_HDD_LED actively used by DSM (scemd)
DISK_BADSECTOR_ON - seems to be not implemented at all.
Our IOCTL is SYNOIO_GET_TEMPERATURE. It should return correct temperature. To find if it works i created small C code. I will post only part of the source, full source is available in archive.
syno_fd = open("/dev/synobios", O_RDONLY,0);
ret = ioctl(syno_fd, SYNOIO_GET_TEMPERATURE, &i);
printf("SYNOIO_GET_TEMPERATURE= %dF, %dC\n",i, (i - 32) * 5 / 9);
After running this code i got system temperature (in F), so driver works! Good start, lets look what else could be done. I personally tested get capabilities command, RTC and CPLD registers. BTW, only using CPLD registers you will get FAN speed (high/low, no RPM on this device) because this information is not exported in other structures. Also you may set HDD leds mode using it. We will talk about this in the next section.
LEDs and buttons
My device has a lot of controllable LEDs: Status, LAN, HDD1, HDD2, USB Copy, Power and 2 buttons – Power and Reset. Most of the leds are controlled by DSM, only LAN led is controlled directly by Ethernet chip. HDD leds are controlled with IOCTL call to /dev/synobios with SYNOIO_SET_DISK_LED. It is possible to switch this leds between OFF/GREEN/GREEN_BLINK/ORANGE/ORANGE_BLINK modes. In the solid green mode it also blinks on SATA activity. It is possible to change the mode, but scemd from DSM will set it back in a couple of seconds. See demo in the source code if you want to play with this. But what about other leds and buttons? They are controlled by special controller installed on /dev/ttyS1. To change LED mode or beep with speaker you need to send 1 byte to the /dev/ttyS1. It is also possible to read this device, and button events are passed to the serial port as 1 byte commands. DSM scemd is always reading this port to capture key presses. This controller is also used to implement some special functionality, e.g. to control WoL on supported boards. I was able to find full list of the available commands in the source tarball in the libsynosdk/gpl/synosdk/external.h file (it was not easy!). Below i provided list of the commands with my comments:
UART2_CMD_BUTTON_POWER 0x30 Power button event, delayed, handled by scemd
UART2_CMD_SHUTDOWN 0x31 Hard power off, use with care!!!
UART2_CMD_BUZZER_SHORT 0x32 Short beep
UART2_CMD_BUZZER_LONG 0x33 Long beep
UART2_CMD_LED_POWER_ON 0x34 Power led on
Power led blink
Power led off
UART2_CMD_LED_HD_OFF 0x37 Status led off
Status led green
Status led green blinking
Status led orange
Status led orange
UART2_CMD_LED_USB_ON 0x40 USB led on
USB led blinking
USB led off
UART2_CMD_TOGGLE_FAN_RPS_REPORT 0x55 /* 'U' */
UART2_CMD_SET_PWM_DUTY 0x56 /* 'V' */
UART2_CMD_SET_PWM_FREQ 0x57 /* 'W' */
UART2_CMD_BUTTON_USB 0x60 Fired if USB button pressed, handled by scemd
UART2_CMD_FAN_FAILURE 0x66 /* 'f' */
UART2_CMD_CPUFAN_FAILURE 0x67 /* 'g' */
UART2_CMD_WOL_ENABLE "l" Does not working on DS207
UART2_CMD_GET_UNIQUE_CMD 0x52 /* 'R' */ Only for x86/x64 devices
The easiest way to send command to the serial port is to use printf with redirect. Below is an example:
"printf "\\x35" > /dev/ttyS1" - this should make your power lad blinking, as on normal DSM boot. To read from port you will need to write some code (on C, Perl or anything else) which reading one byte from the port. Before doing this you will need to stop scemd to avoid conflicts. You can find example of this in the source code.
It is relatively easy to work with all hardware on Synology NAS device. Currently all operations are managed by “scemd” closed-source daemon, so to work directly with hardware we will need to re-implement it functionality (or fake it somehow, e.g. with LD_PRELOAD or virtual ttyS1). I am not yet sure that I am going to do this (it works fine) but it always good to know that it is possible. It also could be very useful for alternative OS, like NetBSD or just normal Debian. Source code is available as is, without any warranty.
Sample source code: synosrc_0.0.1.tar.gz