一篇dbus移植的點點滴滴

3個月了,終於把這個問題搞定了,前後學習加動手可能花了1個半月在這個系統搭建上面。我懷着複雜的心情寫這篇文章,對很多懂這方面的專家我無話可說,對自己我更不知道該愛還是該恨。 
  
6月中的時候我來到新的公司,接到的第一個任務就是交叉編譯dbus,並在目標機上跑起來。我工作快3年了,一直搞的嵌入式開發,說實話在FSK很失敗,以前開發環境都是搭好了,我們只是做一些應用程序的開發而已,我自認爲最有成就的就是寫了LCD和LED驅動。新公司真的有很多牛人,軟硬件都懂,自己開始有點自卑。對第一個任務我甚至不知道怎麼搭建嵌入式交叉編譯環境,指定一個交叉編譯工具鏈都花了我半天的時間,更不要說交叉編譯dbus這麼複雜的東西了,依賴的庫太多,遇到的編譯錯誤也讓我摸不着頭腦。幸好,這些東西做過就會了,在師傅的帶領下我花了10天的時間把dbus交叉編譯搞定。編譯過程如下: 
http://blog.chinaunix.net/u3/99283/showart.php?id=1971652 其中有一個隱患在裏面。 
  
好了,該運行測試程序,運行的時候發現一些錯誤一個個解決掉,發現通信有問題。(其實就是交叉編譯裏面的一個隱患造成的) 
http://blog.chinaunix.net/u3/99283/showart.php?id=1976658 
  
接下來的1個月被師傅叫去接別的任務,說這個問題可以先緩一下以後解決。1個月後又開始接着搞,這次的任務是要把input subsystem、udev、hal、dbus全部搭建起來,預期的的效果是,當觸摸屏有按鍵事件的時候能通過input驅動-> hal(addon)->dbus並被應用程序接收到。這個架構我花了3天的事件看,並找了一些資料,感覺給我的2個禮拜應該足夠了,可是接下來並沒有想象的那麼順利。 
  
重新運行dbus-daemon後臺進程,感覺OK, 但是我這裏有個測試程序收發消息確不能向網上所說的那麼順暢: 
/********************************************************************************/ 
/*
* Example low-level D-Bus code.
* Written by Matthew Johnson <[email protected]>
*
* This code has been released into the Public Domain.
* You may do whatever you like with it.
*/
#include <dbus/dbus.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> 
/**
* Connect to the DBUS bus and send a broadcast signal
*/
void sendsignal(char* sigvalue)
{
   DBusMessage* msg;
   DBusMessageIter args;
   DBusConnection* conn;
   DBusError err;
   int ret;
   dbus_uint32_t serial = 0; 
   printf("Sending signal with value %s\n", sigvalue); 
   // initialise the error value
   dbus_error_init(&err); 
   // connect to the DBUS system bus, and check for errors
   conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Connection Error (%s)\n", err.message); 
      dbus_error_free(&err); 
   }
   if (NULL == conn) { 
      exit(1); 
   } 
   // register our name on the bus, and check for errors
   ret = dbus_bus_request_name(conn, "test.signal.source", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Name Error (%s)\n", err.message); 
      dbus_error_free(&err); 
   }
   if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { 
      exit(1);
   } 
   // create a signal & check for errors 
   msg = dbus_message_new_signal("/test/signal/Object", // object name of the signal
                                 "test.signal.Type",    // interface name of the signal
                                 "Test");               // name of the signal
   if (NULL == msg) 
   { 
      fprintf(stderr, "Message Null\n"); 
      exit(1); 
   } 
   // append arguments onto signal
   dbus_message_iter_init_append(msg, &args);
   if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &sigvalue)) {
      fprintf(stderr, "Out Of Memory!\n"); 
      exit(1);
   } 
   // send the message and flush the connection
   if (!dbus_connection_send(conn, msg, &serial)) {
      fprintf(stderr, "Out Of Memory!\n"); 
      exit(1);
   }
   dbus_connection_flush(conn);
   
   printf("Signal Sent\n");
   
   // free the message 
   dbus_message_unref(msg);

/**
* Call a method on a remote object
*/
void query(char* param) 
{
   DBusMessage* msg;
   DBusMessageIter args;
   DBusConnection* conn;
   DBusError err;
   DBusPendingCall* pending;
   int ret;
   bool stat;
   dbus_uint32_t level; 
   printf("Calling remote method with %s\n", param); 
   // initialiset the errors
   dbus_error_init(&err); 
   // connect to the system bus and check for errors
   conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Connection Error (%s)\n", err.message); 
      dbus_error_free(&err);
   }
   if (NULL == conn) { 
      exit(1); 
   } 
   // request our name on the bus
   ret = dbus_bus_request_name(conn, "test.method.caller", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Name Error (%s)\n", err.message); 
      dbus_error_free(&err);
   }
   if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { 
      exit(1);
   } 
   // create a new method call and check for errors
   msg = dbus_message_new_method_call("test.method.server",// target for the method call
                                      "/test/method/Object", // object to call on
                                      "test.method.Type",    // interface to call on
                                      "Method");             // method name
   if (NULL == msg) { 
      fprintf(stderr, "Message Null\n");
      exit(1);
   } 
   // append arguments
   dbus_message_iter_init_append(msg, &args);
   if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &param)) {
      fprintf(stderr, "Out Of Memory!\n"); 
      exit(1);
   }
   
   // send message and get a handle for a reply
   if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) { // -1 is default timeout
      fprintf(stderr, "Out Of Memory!\n"); 
      exit(1);
   }
   if (NULL == pending) { 
      fprintf(stderr, "Pending Call Null\n"); 
      exit(1); 
   }
   dbus_connection_flush(conn);
   
   printf("Request Sent\n");
   
   // free message
   dbus_message_unref(msg);
   
   // block until we recieve a reply
   dbus_pending_call_block(pending); 
   // get the reply message
   msg = dbus_pending_call_steal_reply(pending);
   if (NULL == msg) {
      fprintf(stderr, "Reply Null\n"); 
      exit(1); 
   }
   // free the pending message handle
   dbus_pending_call_unref(pending); 
   // read the parameters
   if (!dbus_message_iter_init(msg, &args))
      fprintf(stderr, "Message has no arguments!\n"); 
   else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args)) 
      fprintf(stderr, "Argument is not boolean!\n"); 
   else
      dbus_message_iter_get_basic(&args, &stat); 
   if (!dbus_message_iter_next(&args))
      fprintf(stderr, "Message has too few arguments!\n"); 
   else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args)) 
      fprintf(stderr, "Argument is not int!\n"); 
   else
      dbus_message_iter_get_basic(&args, &level); 
   printf("Got Reply: %d, %d\n", stat, level);
   
   // free reply 
   dbus_message_unref(msg);   



void reply_to_method_call(DBusMessage* msg, DBusConnection* conn)
{
   DBusMessage* reply;
   DBusMessageIter args;
   bool stat = true;
   dbus_uint32_t level = 21614;
   dbus_uint32_t serial = 0;
   char* param = ""; 
   // read the arguments
   if (!dbus_message_iter_init(msg, &args))
      fprintf(stderr, "Message has no arguments!\n"); 
   else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) 
      fprintf(stderr, "Argument is not string!\n"); 
   else 
      dbus_message_iter_get_basic(&args, &param); 
   printf("Method called with %s\n", param); 
   // create a reply from the message
   reply = dbus_message_new_method_return(msg); 
   // add the arguments to the reply
   dbus_message_iter_init_append(reply, &args);
   if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &stat)) { 
      fprintf(stderr, "Out Of Memory!\n"); 
      exit(1);
   }
   if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &level)) { 
      fprintf(stderr, "Out Of Memory!\n"); 
      exit(1);
   } 
   // send the reply && flush the connection
   if (!dbus_connection_send(conn, reply, &serial)) {
      fprintf(stderr, "Out Of Memory!\n"); 
      exit(1);
   }
   dbus_connection_flush(conn); 
   // free the reply
   dbus_message_unref(reply);

  
/**
* Server that exposes a method call and waits for it to be called
*/
void listen() 
{
   DBusMessage* msg;
   DBusMessage* reply;
   DBusMessageIter args;
   DBusConnection* conn;
   DBusError err;
   int ret;
   char* param; 
   printf("Listening for method calls\n"); 
   // initialise the error
   dbus_error_init(&err);
   
   // connect to the bus and check for errors
   conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Connection Error (%s)\n", err.message); 
      dbus_error_free(&err); 
   }
   if (NULL == conn) {
      fprintf(stderr, "Connection Null\n"); 
      exit(1); 
   }
   
   // request our name on the bus and check for errors
   ret = dbus_bus_request_name(conn, "test.method.server", 
                               DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Name Error (%s)\n", err.message); 
      dbus_error_free(&err);
   }
   if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { 
      fprintf(stderr, "Not Primary Owner (%d)\n", ret);
      exit(1); 
   } 
   // loop, testing for new messages
   while (true) {
      // non blocking read of the next available message
      dbus_connection_read_write(conn, 0);
      msg = dbus_connection_pop_message(conn); 
      // loop again if we haven't got a message
      if (NULL == msg) { 
         sleep(1); 
         continue; 
      }
      
      // check this is a method call for the right interface & method
      if (dbus_message_is_method_call(msg, "test.method.Type", "Method")) 
         reply_to_method_call(msg, conn); 
      // free the message
      dbus_message_unref(msg);
   }

  
/**
* Listens for signals on the bus
*/
void receive()
{
   DBusMessage* msg;
   DBusMessageIter args;
   DBusConnection* conn;
   DBusError err;
   int ret;
   char* sigvalue; 
   printf("Listening for signals\n"); 
   // initialise the errors
   dbus_error_init(&err);
   
   // connect to the bus and check for errors
   conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Connection Error (%s)\n", err.message);
      dbus_error_free(&err); 
   }
   if (NULL == conn) { 
      exit(1);
   }
   
   // request our name on the bus and check for errors
   ret = dbus_bus_request_name(conn, "test.signal.sink", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Name Error (%s)\n", err.message);
      dbus_error_free(&err); 
   }
   if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
      exit(1);
   } 
   // add a rule for which messages we want to see
   dbus_bus_add_match(conn, "type='signal',interface='test.signal.Type'", &err); // see signals from the given interface
   dbus_connection_flush(conn);
   if (dbus_error_is_set(&err)) { 
      fprintf(stderr, "Match Error (%s)\n", err.message);
      exit(1); 
   }
   printf("Match rule sent\n"); 
   // loop listening for signals being emmitted
   while (true) { 
      // non blocking read of the next available message
      dbus_connection_read_write(conn, 0);
      msg = dbus_connection_pop_message(conn); 
      // loop again if we haven't read a message
      if (NULL == msg) { 
         sleep(1);
         continue;
      } 
      // check if the message is a signal from the correct interface and with the correct name
      if (dbus_message_is_signal(msg, "test.signal.Type", "Test")) {
         
         // read the parameters
         if (!dbus_message_iter_init(msg, &args))
            fprintf(stderr, "Message Has No Parameters\n");
         else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) 
            fprintf(stderr, "Argument is not string!\n"); 
         else
            dbus_message_iter_get_basic(&args, &sigvalue);
         
         printf("Got Signal with value %s\n", sigvalue);
      } 
      // free the message
      dbus_message_unref(msg);
   }

  
int main(int argc, char** argv)
{
 char* param = "no param"; 
 printf("#Kluter T1:argc=%d\n", argc);
 if (2 > argc) 
 {
      printf ("Syntax: dbus-example [send|receive|listen|query] [<param>]\n");
      return 1;
   } 
   
 if (3 >= argc && NULL != argv[2]) 
  param = argv[2]; 
 if (0 == strcmp(argv[1], "send"))
  sendsignal(param);
 else if (0 == strcmp(argv[1], "receive"))
  receive();
 else if (0 == strcmp(argv[1], "listen"))
  listen();
 else if (0 == strcmp(argv[1], "query"))
  query(param);
 else 
 {
  printf ("Syntax: dbus-example [send|receive|listen|query] [<param>]\n");
  return 1;
 }
 return 0;

/****************************************************************************/ 
  
PS:這是一個Dbus典型的測試程序, 交叉編譯和makefile的部分我在以前的文章已經講了,對高手來說應該不是問題了吧。 
最初這個程序的dbus_bus_get()這個函數的第一個參數都是用的DBUS_BUS_SESSION這個參數,我也糊里糊塗的,也沒有覺得用這個參數有什麼不妥。但是我這樣在開發板上運行(可執行文件爲eg2): 
#eg2 receive & 
#eg2 send abcdefg 
  
始終不能在接收端收到消息,鬱悶ing~    無意之中看到一篇文章說要起一個dbus-launch, 這個launch其實就是去launch了一個dbus-daemon, 當然這個launch起來的daemon是以session bus跑起來的。看到這個可能很多人應該明白了是什麼原因了吧, 可當時的我還是糊里糊塗的。可是這樣還是不行的,還要看dbus-launch官方介紹的文章: http://dbus.freedesktop.org/doc/dbus-launch.1.html 
裏面提到了一點: 
## test for an existing bus daemon, just to be safe
  if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then
      ## if not found, launch a new one
      eval `dbus-launch --sh-syntax --exit-with-session`
      echo "D-Bus per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
  fi


莫名其妙的我打了一個eval `dbus-launch --sh-syntax --exit-with-session` 哈哈終於可以收發消息了!!高興了1個小時,以爲成功了。殊不知這個只是session bus通過了測試,後來發現問題之後又仔細閱讀dbus-launch那篇文章,比對每一個參數等等過程不在描述了。總之一句話,沒有方向,沒有頭腦,無限鬱悶…… 
我在別人的提示下才知道用dbus_bus_get()這個函數的時候第一個param要用DBUS_BUS_SYSTEM纔是合理的,應爲整個事件的core是在system bus上面跑的(後來看hald源代碼的時候才知道),只有應用程序之間纔可以用session來通信,否則就會存在安全隱患,這個是我們金融相關行業最忌諱的東西! 
接下來兩三天痛苦的摸索着,終於在週末的時候把問題解決了,可是先申明問題不是我解決的,是我同事幫我解決的,他從配置文件和安全性方面入手從頭到尾檢查我的編譯流程,發現在我編譯dbus-1.0.2的時候make出錯的一個問題我解決得有問題且剛好是和socket的安全問題相關。dbus-sysdeps-unix.c 這個文件中找不到struct ucred, 鬱悶後來他告訴我新內核的這個結構體被改掉了,所以加入新kernel結構體
      struct ucred {
        pid_t   pid;     /* 發送進程的進程標識 */
        uid_t   uid;     /* 發送進程的用戶標識 */
        gid_t   gid;     /* 發送進程的組標識 */   
    }; 
把這個該死的問題解決了,還得我和他被拿來和老大比較,當然被批評的那個人大家都應該清楚。。。。。。 
  
dbus編譯的問題解決了之後當然趕快試一下hald是否能掛起來,幸運的是果然成功了,應爲在hald.c中調用hald_dbus_init_preprobe() 是去init DBUS_BUS_SYSTEM。又去跑文章開頭那個測試程序,會報錯: 
Name Error (Connection ":1.3" is not allowed to own the service "test.signal.sink" due to security policies in the configuration file) 
這次很明確了,肯定是配置文件的問題。這裏我想說一下,做過這個系統的人應該很清楚這個問題,但是爲什麼網上沒有人清楚的說明一下呢?那些做過的人做完了就算了,也不願意共享一下資源,願意共享的也只是把這個問題一帶而過,害的我們又要花費半天時間,其實解決了真的覺得很簡單一個問題,開始很討厭OpenSource,很厭煩中國人的孽根性。話說回來,配置文件是在/etc/dbus-1/system.d下面,自己新建一個*.conf文件,我的配置文件內容供大家參考: 
<!DOCTYPE busconfig PUBLIC
 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
        <policy user="root">
                <allow own="test.signal.sink"/> 
                <allow send_destination="test.signal.sink"/>
                <allow send_interface="test.signal.sink"/>
                
                <allow own="test.signal.source"/> 
                <allow send_destination="test.signal.source"/>
                <allow send_interface="test.signal.source"/>
                
                <allow own="test.method.server"/> 
                <allow send_destination="test.method.server"/>
                <allow send_interface="test.method.server"/>
        </policy>
        <policy at_console="true">
                <allow send_destination="test.signal.sink"/>
                <allow send_interface="test.signal.sink"/>
                <allow send_destination="test.signal.source"/>
                <allow send_interface="test.signal.source"/>
                <allow send_destination="test.method.server"/>
                <allow send_interface="test.method.server"/>
        </policy>
        <policy context="default">
                <deny own="test.signal.sink"/>
                <deny send_destination="test.signal.sink"/>
                <deny send_interface="test.signal.sink"/>
                <deny own="test.signal.source"/>
                <deny send_destination="test.signal.source"/>
                <deny send_interface="test.signal.source"/>
                <deny own="test.method.server"/>
                <deny send_destination="test.method.server"/>
                <deny send_interface="test.method.server"/>
        </policy>
        <limit name="max_replies_per_connection">512</limit>
</busconfig>
不要問我爲什麼,I don't know. Just do it。 老外的東西就是這樣要求的。 
  
system bus通信正常之後,就試着使input設備能往上dbus報事件了。大家能感覺得到我說的有多籠統嗎?不錯當時我只知道這樣肯定行得通,但是具體怎麼做又是另一回事了…… 
  
首先在做這個事情之前,我先花了5天的時間去研究input subsystem,input device driver,本想寫一個s3c2440上的按鍵驅動的,kconfig makefile都改好了,確怎麼都沒辦法驅動起來,師傅說可能要在內核裏面先去註冊,因此轉而用2440開發板自帶的觸摸屏驅動,它就是用input subsystem實現的,內核驅動的部分見:http://blog.chinaunix.net/u3/99283/showart.php?id=2024189 我已經將trace代碼的註解加進去了。當然開發板fs中自帶的qtopia已經加載了tslib,據說是一個觸摸屏校準程序(沒有深究),也就是說qt幫我們open了/dev/input/event0。(PS:但是這樣就違背了我們設計這個系統的初衷,應爲大部分公司的大部分產品都是同步偵聽這些驅動事件的,但我們系統是異步的。) 
  
根據下面2點,我確定了input設備是由hald偵聽的: 
1. 參考“理解和使用Linux的硬件抽象層HAL.mht”,很多人轉載了這篇文章。其中講述到“由於不同的硬件,有着很不同的行爲,HAL還會通過一些特定的Addon來監聽設備的狀態變更情況。例如針對input類設備,hald會啓動一個 hald-addon-input 的Addon,它的其中一個功能就是監聽鍵盤事件,如果其中有sw類的事件(如sw_lid 因該是表示筆記本蓋的開合,好像電源管理會模擬這個事件)則會去修改設備對象對應的狀態屬性。” 
2. 在pc機上#ps -A(省略無關部分) 
 PID TTY          TIME CMD 
。。。
    6 ?        00:00:00 events/0
    7 ?        00:00:00 events/1
 1177 ?        00:00:00 udevd
 2697 ?        00:00:00 dbus-daemon
 2705 ?        00:00:00 hald
 2706 ?        00:00:00 hald-runner
 2712 ?        00:00:00 hald-addon-acpi
 2717 ?        00:00:00 hald-addon-keyb
 2730 ?        00:00:00 hald-addon-stor
 3042 ?        00:00:00 dbus-launch
 3043 ?        00:00:00 dbus-daemon
。。。 
  
但是在我的開發板上只有dbus-daemon和hald hald-runner跑起來了,說明我的系統裏面根本就沒有去偵聽input設備。一時又沒有了方向。沒辦法只有去跟蹤hald源代碼。hald.c的main()函數中有這樣一段: 
case 0:
       /* child */ 
       dev_null_fd = open ("/dev/null", O_RDWR);
       /* ignore if we can't open /dev/null */
       if (dev_null_fd >= 0) {
        /* attach /dev/null to stdout, stdin, stderr */
        dup2 (dev_null_fd, 0);
        dup2 (dev_null_fd, 1);
        dup2 (dev_null_fd, 2);
        close (dev_null_fd);
       } 
       umask (022);
       break; 
  
我們必須拿掉那3行dup2才能在console下打印出hald的啓動過程。 
  
胡亂看了2遍,隨便試了及格hal的執行文件,發現lshal的時候 HAL database裏面只記錄了1個設備和pc機上列出的72個設備相差甚遠(實際上開發板上遠沒有那麼多),又搜了幾篇相關文章(搜索能力只有靠自己了哈),我懷疑和udev daemon相關,雖然我很確定input和udev無關,但是事後證明我的猜測是對的。 
然後我在啓動hald之前又加上了udevd --daemon 和 udevstart兩條命令。果然lshal的時候列出了34個設備,其中包括input 觸摸屏的: 
  


udi = '/org/freedesktop/Hal/devices/computer_logicaldev_input' 
  info.capabilities = {'input', 'input.touchpad'} (string list) 
  info.category = 'input'  (string) 
  info.parent = '/org/freedesktop/Hal/devices/computer'  (string) 
  info.product = 's3c2410 TouchScreen'  (string) 
  info.udi = '/org/freedesktop/Hal/devices/computer_logicaldev_input'  (string) 
  input.device = '/dev/input/event0'  (string) 
  input.product = 's3c2410 TouchScreen'  (string) 
  linux.device_file = '/dev/input/event0'  (string) 
  linux.hotplug_type = 2  (0x2)  (int) 
  linux.subsystem = 'input'  (string) 
  linux.sysfs_path = '/sys/devices/virtual/input/input0/event0'  (string) 
  
既然input設備已經加載到了hal database,那麼是不是hald開始偵聽它了呢?結果ps的時候也沒有出現類似pc上的“2717 ?   00:00:00 hald-addon-keyb”這個進程,又鬱悶了…… 
感覺離勝利很近了卻偏偏不知道問題出在哪裏,開源的東西真的很煩。不過至少讓我確定了啓動hald-input-addon這個daemon的方向是正確的。 
  
做事一定要執着,要永不放棄,繼續閱讀hal spec,到網上找文章,終於讓我發現要寫一個*.fdi的文件的文章,竊喜,因爲很可能是這個原因。修改了/usr/share/hal/fdi/policy/10osvendor中的10-input-policy.fdi文件: 




  
<?xml version="1.0" encoding="UTF-8"?> 
<deviceinfo version="0.2"> 
  <device> 
    <match key="info.capabilities" contains="input"> 
      <match key="info.capabilities" contains="touchpad"> 
        <append key="info.addons.singleton" type="strlist">hald-addon-input</append>        
      </match>        
      <match key="info.capabilities" contains="input.touchpad"> 
        <append key="info.addons.singleton" type="strlist">hald-addon-input</append>               
          <match key="info.capabilities" contains_not="button">    
            <append key="info.capabilities" type="strlist">touchpad</append>               
          </match> 
      </match>    
   </match>  
  </device> 
</deviceinfo> 
  
Yeah! ps之後終於在addon-input終於在後臺通過hald-runner跑起來了! 
  
後來的事情就會輕鬆很多,到dbus上收input事件的消息只要跟蹤一下addon-input.c這些代碼就知道是怎麼回事了,這裏不再解釋了。 
  
總之,我寫這篇文章的目的不是說我有多懂,我在這個月沒有少捱過批評教育,沒有少煎熬過,甚至一度想通過離職來解脫,我也在網上1000圓徵求具體解決方案,可是逃避又能怎樣呢?除非我這輩子都不搞技術了。我只是希望做過開源或者一些通用平臺搭建的朋友能把你們的心得和遇到的問題都無私的奉獻出來,中國的開源項目才步入起步階段,大公司裏面憑藉雄厚的實力已經非常穩定了,可是小公司和在校的朋友可能根本就沒有機會接觸。雖然說只有靠自己解決問題纔是生存之道,但是憑心而論,有幾個高人是一開始就懂這麼多呢?還不是從借鑑開始的。 

在解決這些問題的過程中我就走了很多彎路,甚至某段時間導致問題是發散的,其實解決的方法就在那些英文文檔和英文論壇裏面,只有概念性的東西我們中國人才喜歡寫,其實那些東西都沒有多大意義,不外乎告訴別人你懂很多,真正困擾我們的是做的時候遇到的難題,希望一些通性的東西大家共享,opensource纔會有更多高人加入進來!



來自:http://www.diybl.com/course/6_system/linux/Linuxjs/20090905/173963.html

發佈了22 篇原創文章 · 獲贊 21 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章