Linux Input 子系統

Linux Input 子系統Event Interface詳解 : 得到Input Device信息

(2013-06-06 15:24:27)

在之前的工作中,常遇到對Input 子系統中Event Device操作和設置的需求。但一直沒有總結過。這次藉機總結一下。


Linux Input子系統中,每個輸入設備可以建立一個Device。例如:當插入USB Mouse,USB Keyboard,或者採用UInput建立Input Device時。在系統/dev/input/ 目錄下就會生成對應的Device。 如:/dev/input/event0, /dev/input/mouse0, /dev/input/misc等。


可以通過讀取這些Device獲取輸入設備輸入的信息。同時,也可以通過一系列ioctl()得到和設置(主要是得到)這些Device 的信息。 這裏,我們主要分析此Event Interface 的ioctl().


0. 基礎信息:
0.1:關鍵結構體input_event信息:
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};

type: 設備類型。可以設置爲:
#define EV_SYN          0x00    表示設備支持所有的事件
#define EV_KEY          0x01    鍵盤或者按鍵,表示一個鍵碼  
#define EV_REL          0x02    鼠標設備,表示一個相對的光標位置結果
#define EV_ABS          0x03    手寫板產生的值,其是一個絕對整數值 
#define EV_MSC          0x04    其他類型 
#define EV_LED          0x11    LED燈設備
#define EV_SND          0x12    蜂鳴器,輸入聲音 
#define EV_REP          0x14    允許重複按鍵類型 
#define EV_PWR          0x16    電源管理事件 
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)

code: 根據Type的不同而含義不同。
例如:
Type爲EV_KEY時,code表示鍵盤code或者鼠標Button值。
取值範圍:
#define EV_SYN 0x00
到:
#define KEY_MIN_INTERESTING KEY_MUTE
#define KEY_MAX 0x2ff
#define KEY_CNT (KEY_MAX+1)


Type爲EV_REL時,code表示操作的是哪個座標軸,如:REL_X,REL_Y。(因爲鼠標有x,y兩個軸向,所以一次鼠標移動,會產生兩個input_event)
取值範圍:
#define REL_X 0x00
#define REL_Y 0x01
#define REL_Z 0x02
#define REL_RX 0x03
#define REL_RY 0x04
#define REL_RZ 0x05
#define REL_HWHEEL 0x06
#define REL_DIAL 0x07
#define REL_WHEEL 0x08
#define REL_MISC 0x09
#define REL_MAX 0x0f
#define REL_CNT (REL_MAX+1)
Type爲EV_ABS時,code表示絕對座標軸向。


value:根據Type的不同而含義不同。
例如:
Type爲EV_KEY時,value: 0表示按鍵擡起。1表示按鍵按下。(4表示持續按下等?)。
Type爲EV_REL時,value: 表明移動的值和方向(正負值)。
Type爲EV_ABS時,code表示絕對位置。


0.2: Device ID 結構體信息:
struct input_id {
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
};

bustype: 一些枚舉類型。如 USB PCI等。
取值範圍:
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
#define BUS_VIRTUAL 0x06

#define BUS_ISA 0x10
#define BUS_I8042 0x11
#define BUS_XTKBD 0x12
#define BUS_RS232 0x13
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
#define BUS_SPI 0x1C

vendor,product,version: 廠商號,產品號,版本號。



1. 各類ioctl:
1.1:得到Driver Version:
#define EVIOCGVERSION _IOR('E', 0x01, int)
int 暗示了ioctl()參數三能夠得到int值。

例:
vesion = 0;
ioctl(fd, EVIOCGVERSION, &vesion);
printf("\nDriver Version:[0x%x]\n", vesion);


1.2:得到Device ID:
#define EVIOCGID _IOR('E', 0x02, struct input_id)
從struct input_id暗示,ioctl參數三可以得到此結構體內容。
// 2. Device ID.
memset(&Device_ID, 0, sizeof(struct input_id));
ioctl(fd, EVIOCGID, &Device_ID);
printf("\nbustype:[%d]. vendor:[%d]. product:[%d]. version:[%d]\n", Device_ID.bustype, Device_ID.vendor, Device_ID.product, Device_ID.version);


1.3: 得到和設置Repeat速度:
#define EVIOCGREP _IOR('E', 0x03, unsigned int[2])
#define EVIOCSREP _IOW('E', 0x03, unsigned int[2])
從unsigned int[2] 暗示,ioctl的第三個參數是個數組。

int rep[2];
ioctl(fd, EVIOCGREP, rep);
printf("[0]= %d, [1] = %d\n", rep[0], rep[1]);

注意,其中一些Device不支持Get Set Repeat。此時,Ioctl會報錯。
另:參數說明: rep[0]表示在按鍵重複出現之前 delay的時間; rep[1]表示按鍵重複出現的時間間隔。


1.4:得到ScanKey和KeyMap。
這個功能Sam沒有測試過。所以不具體討論。
#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2])
#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2])


1.5:得到DeviceName:
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len)
此處暗示ioctl參數二:EVIOCGNAME(len)

char name[256]= "Unknown";
ioctl(fd, EVIOCGNAME(sizeof(name)), name);
printf("\nDevice Name:[%s]. \n", name);


1.6:得到設備物理位置:
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) //get physical location
此處暗示參數二爲:EVIOCGPHYS(len)
儘管設備身份信息和名字信息通常很有用,但是它也許並沒有提供足夠的信息告訴你當前在使用哪個設備。例如,你當前有兩個完全相同的遙控杆,你需要確定每個使用哪個端口。這通常屬於拓撲信息( topology information),可以使用 EVIOCGPHYS ioctl獲取:

char physic[256]= "Unknown";
if(ioctl(fd, EVIOCGPHYS(sizeof(physic)), physic) < 0) 
{
perror("EVIOCGPHYS ioctl");
}
else
printf("Phys location is %s\n", physic);
結果通常爲:
Phys location is: usb-hiusb-ehci-2.1/input1
Phys location is: usb-hiusb-ehci-2.1/input2
涵義: Usb部分意味着這使用 usb系統的一個物理拓撲。 2.1表示了從 root hub device的路徑,這裏表示上行 hub接在 root hub的第 2個端口上,設備接在上行 hub的第 1個端口上。 Input0表示這是設備的第 1event device 節點。


1.7: 得到唯一的ID:
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) //get unique identifier 
此處暗示ioctl()參數二:EVIOCGUNIQ(len)

char uniq[256]= "Unknown";
if(ioctl(fd, EVIOCGUNIQ(sizeof(uniq)), uniq) < 0) 
{
perror("EVIOCGUNIQ ioctl");
}
else
printf("UID is %s\n", uniq);
絕大多數設備沒有這樣的唯一號,所以你使用該 ioctl將返回一個空字符串


1.8:得到全局key/button狀態,看其是否被按下或釋放:
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len)
此處暗示 ioctl()參數二是:EVIOCGKEY(len)
通過這個ioctl, 參數三中得到信息。它在 bit array裏設置了每個 key/button是否被釋放。


1.9: 得到LED狀態:
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len)

LED排列如下:
#define LED_NUML 0x00
#define LED_CAPSL 0x01
#define LED_SCROLLL 0x02
#define LED_COMPOSE 0x03
#define LED_KANA 0x04
#define LED_SLEEP 0x05
#define LED_SUSPEND 0x06
#define LED_MUTE 0x07
#define LED_MISC 0x08
#define LED_MAIL 0x09
#define LED_CHARGING 0x0a
#define LED_MAX 0x0f
#define LED_CNT (LED_MAX+1)



1.10:得到Device能力集:

使用 EVIOCGBIT ioctl可以獲取設備的能力和特性。它告知你設備是否有 key或者 button

EVIOCGBIT ioctl處理 4個參數 ( ioctl(fd, EVIOCGBIT(ev_type, max_bytes), bitfield)) ev_type是返回的 type feature 0是個特殊 case,表示返回設備支持的所有的type features)。 max_bytes表示返回的最大字節數。 bitfield域是指向保存結果的內存指針。 return value表示保存結果的實際字節數,如果調用失敗,則返回負值。


//找到addr中的對應bit.看其是否爲1。

 

static int test_bit(int nr, const volatile unsigned long *addr)

{

return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));

}



 

memset(pEvtype, 0, sizeof(pEvtype));

if (ioctl(fd, EVIOCGBIT(0, EV_MAX), pEvtype) < 0) 

{

//printf();

}

for (yalv = 0; yalv < EV_MAX; yalv++) 

{

if (test_bit(yalv, pEvtype)) 

{

 

printf(" Event type 0xx ", yalv);

switch ( yalv)

{

case EV_SYN :

printf(" (Synch Events)\n");

break;

case EV_KEY :

printf(" (Keys or Buttons)\n");

break;

case EV_REL :

printf(" (Relative Axes)\n");

break;

case EV_ABS :

printf(" (Absolute Axes)\n");

break;

case EV_MSC :

printf(" (Miscellaneous)\n");

break;

case EV_LED :

printf(" (LEDs)\n");

break;

case EV_SND :

printf(" (Sounds)\n");

break;

case EV_REP :

printf(" (Repeat)\n");

break;

case EV_FF :

case EV_FF_STATUS:

printf(" (Force Feedback)\n");

break;

case EV_PWR:

printf(" (Power Management)\n");

break;

default:

printf(" (Unknown: 0xhx)\n",yalv);

}

}

}

 



通過這個辦法,就可以的到能力集。例如:
Event type 0x00  (Synch Events)
 Event type 0x01  (Keys or Buttons)
 Event type 0x02  (Relative Axes)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章