Difference between revisions of "Hidd"

From WebOS Internals
Jump to navigation Jump to search
 
(2 intermediate revisions by the same user not shown)
Line 298: Line 298:
 
You'll see its socket get registered and then some printf's when getcallback and init get called.
 
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. :)
 
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:
 +
<pre>
 +
#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));
 +
</pre>

Latest revision as of 17:06, 8 September 2011

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));