Hidd
Intro
This is a research page on hidd -- how to examine what it does, how it works, etc.
Files
Hidd is started from upstart (/etc/event.d/hidd) with a -f option to load a given configuration file. On the emulator, this is /etc/hidd/HidPluginsVbox.xml. On a pre, this is /etc/hidd/HidPlugins.xml. There's also something called casper there, not sure what that is as of yet
Architecture
Hidd seems to use a modular plugin-style architecture where each plugin is a shared library.
Default files are:
libhid.so libhidavrcp.so libhidlight.so libhidqemukeypad.so libhidtouchpanel.so libhidaccelerometer.so libhidkeypad.so libhidproximity.so libhidqemutouchpanel.so
Plugin definition in config file
<source lang=xml>
<plugin> <name>HidKeypad</name> <eventsDeferIdle>true</eventsDeferIdle> <eventSocketAddress>/var/tmp/hidd/KeypadEventSocket</eventSocketAddress> <cmdSocketAddress>/var/tmp/hidd/KeypadCmdSocket</cmdSocketAddress> <path>/usr/lib/libhidkeypad.so</path> </plugin>
</source>
Starting the daemon
A lot of debug information can be obtained by starting the daemon like so (on a pre, on an emulator add Vbox before .xml)
/usr/bin/hidd -vvv -f /etc/hidd/HidPlugins.xml
Example trace
/usr/bin/hidd -vvv -f /etc/hidd/HidPlugins-keypadonly.xml
Verbosity level set to 7
root@castle:/etc/hidd# hidd -vvvv -f /etc/hidd/HidPlugins-test.xml
Verbosity level set to 7
Plugin: 0
Name: HidKeypad Path: /usr/lib/libhidkeypad.so Event Socket Address: /var/tmp/hidd/KeypadEventSocket Cmd Socket Address: /var/tmp/hidd/KeypadCmdSocket
_SetupPluginTransport:
Socket created successfully
_SetupPluginTransport:
--> Event socket address: /var/tmp/hidd/KeypadEventSocket
_SetupPluginTransport:
--> Command socket address: /var/tmp/hidd/KeypadCmdSocket
Init:
HidKeypad: init function called!
HidKeypadIpc.c:104 : GetSwitchStates: Bad file descriptor ReportEvent:
kInputEvent received 1 events, fd: 7
_ReportStandardEvent:
Event: 0.0, type=EV_SYN, code=8, value=0
HidPluginStartReaderThread:
HidKeypad: starting reader thread
main:
Setting up power management...
ReportEvent:
kInputEvent received 2 events, fd: 7
_ReportStandardEvent:
Event: 85906.791100, type=EV_KEY, code=19, value=1
_ReportStandardEvent:
Event: 85906.791130, type=EV_SYN, code=0, value=0
ReportEvent:
kInputEvent received 2 events, fd: 7
_ReportStandardEvent:
Event: 85906.999809, type=EV_KEY, code=19, value=0
_ReportStandardEvent:
Event: 85906.999840, type=EV_SYN, code=0, value=0
Listening to Hidd event
The libSDL patch provided by Palm provides good examples of listening to events via hidd. Based upon this I created a simple example program to listen to the HidKeypad events and print them to stdout. Listening directly to HidKeypad events we can observe all the keys including power button, volume keys and center gesture-area button. I built using WIDK. WARNING: After running this program, I cannot get the screen to come back on after sleeping via a key press. It only turns back on after reconnecting USB cable
hidTest.c
#include <stdio.h> #include <linux/input.h> #include "HidLib.h" //#include "hid/IncsPublic/HidLib.h" #define XML_FILE "/etc/hidd/HidPlugins.xml" static HidPluginSettings_t* pSettings = NULL; static int numPlugins = 0; int HidEventInit(void) { PmErr retVal = kPmErrorUnknown; if (pSettings == NULL) { retVal = HidAllocPluginSettings(XML_FILE, &pSettings, &numPlugins); if (kPmErrorNone != retVal) { pSettings = NULL; return -1; } } return 0; } void HidEventDeInit(void) { if (NULL != pSettings) { HidFreePluginSettings(&pSettings, numPlugins); pSettings = NULL; } } void *HidEventOpen(int Device) { PmErr retVal = kPmErrorUnknown; HidHandle_t* pHandle = NULL; if (pSettings == NULL) { // Ensure plugin settings are initialized. if (HidEventInit() != 0) { return NULL; } } static const char* PluginName[] = { HID_KEYPAD, HID_ACCELEROMETER, HID_TOUCHPANEL }; retVal = HidInitPluginTransport(PluginName[Device], pSettings, numPlugins, &pHandle); if (kPmErrorNone != retVal) { HidFreePluginSettings(&pSettings, numPlugins); pSettings = NULL; return NULL; } return pHandle; } void HidEventClose(void *Handle) { if (NULL != Handle) { HidDestroyPluginTransport((HidHandle_t**)&Handle); } } int HidEventGetFd(void *Handle) { return HidHandleGetFd((HidHandle_t*)Handle); } int HidEventRead(void *Handle, struct input_event* Events, int MaxEvents) { return HidHandleReadInputEvent((HidHandle_t*)Handle, (InputEvent_t*)Events, MaxEvents); } int main() { void *pHandle; struct input_event myevent; int ret = 0; pHandle = HidEventOpen(0); while (1) { ret = HidEventRead(pHandle, &myevent, 1); printf("return %d, type %d, code %d, value %d\n", ret, myevent.type, myevent.code, myevent.value); // q for quit if (myevent.code == 16) { HidEventDeInit(); HidEventClose(pHandle); break; } } return 0; }
HidLib.h
typedef int HidPluginSettings_t; typedef int HidHandle_t; typedef int PmErr; typedef struct input_event InputEvent_t; #define kPmErrorNone 0 #define kPmErrorUnknown -1 #define HID_KEYPAD "HidKeypad" #define HID_ACCELEROMETER "HidAccelerometer" #define HID_TOUCHPANEL "HidTouchpanel"
Makefile
CC = arm-none-linux-gnueabi-gcc CFLAGS = -g -O2 -I/usr/local/include LIBS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lhid DEMOS = hidTest $(DEMOS): $(CC) -o $@ $@.c $(CFLAGS) $(LIBS) clean: rm -f $(DEMOS)
Silly hidd plugin
#include <stdio.h> typedef struct PluginTable_t { int (*GetEventCallBack)() ; int (*Init)() ; int (*Exit)() ; int (*Suspend)() ; int (*Resume)() ; int (*Poll)() ; } PluginTable_t; extern PluginTable_t PluginTable; void *gPluginPrvInfo[21]; int GetEventCallBack(void *a1) { printf( "Silly GetEventCallBack()\n" ) ; gPluginPrvInfo[0] = a1; return 0; } int Init(a1) { printf( "Silly Init\n" ) ; return HidPluginGenericInit(a1, gPluginPrvInfo); } int Exit() { printf( "Silly Exit\n" ) ; return HidPluginGenericExit(gPluginPrvInfo); } int Suspend() { printf( "Silly Suspend\n" ) ; return HidPluginGenericSuspend(gPluginPrvInfo); } int Resume() { printf( "Silly Resume\n" ) ; return HidPluginGenericResume(gPluginPrvInfo); } int Poll() { printf( "Silly Poll\n" ) ; return HidPluginGenericGetEvents(gPluginPrvInfo); } PluginTable_t PluginTable = { *GetEventCallBack, *Init, *Exit, *Suspend, *Resume, *Poll } ;
You'll see its socket get registered and then some printf's when getcallback and init get called. Next steps will be to fix to figure out gPluginPrvInfo since we probably need to put more things in it, and then to actually communicate with hidd. :)
Private Info
Some information from the privinfo internals that are used with the Generic function calls:
#include <linux/input.h> #include <pthread.h> #include <stdint.h> typedef int (*ReportFunction_t)(input_event *events, int num_events, int is_custom_event, uint32_t unk2); typedef int (*ReaderFunction_t)(int event_device_fd); struct PrivateInfo { ReportFunc_t report_function; // +00 char *event_device; // +04 can be symlink char *real_event_device; // +08 realpath(3) of event_device int *event_device_fds; // +0c file descriptors for IO (read/select/et al) char *plugin_name; // +10 name of this plugin uint32_t unk_param; // +14 passed as final unk2 to report function uint32_t unk_0; // +18 unknown uint32_t unk_1; // +1c unknown uint32_t unk_2; // +20 unknown uint32_t unk_3; // +24 unknown ReaderFunction_t reader_function; // +28 reader thread function void *event_source; // +2c pointer to an EventSource void (*init_callback)(); // +30 this is called part way through init (optional) pthread_t reader_thread; // +34 reader thread char is_running; // +38 is 1 if the reader thread is running char padding[3]; pthread_mutex_t reader_mutex; // +3c mutex for reader // maybe more here? } __attribute__((packed));