手邊有一閑置的linux開發(fā)板iMX6ULL一直在吃灰,不用來搞點事情,總覺得對不住它。業(yè)余打發(fā)時間就玩起來吧,總比刷某音強。從某多多上買來一個usb接口的游戲手柄,讓開發(fā)板支持以下它,后續(xù)就可以接著在上面玩童年經典游戲啦。
?我使用的是正點原子的I.MX6U-ALPHA 開發(fā)板,板子資源很豐富。計劃搞一個系列在上面玩各種有意思的事情。包含linux驅動開發(fā)和應用開發(fā),最終學以致用,在玩中學,興趣是最好的老師。
?展示下我買的FC游戲手柄長這樣,普普通通,但便宜啊,還是經典的味道。
驅動移植過程
確定設備類型
要讓板子支持這一USB接口的FC游戲手柄,首先得知道這個手柄是使用的什么接口協(xié)議。插到win10電腦上看了下,是一個USB協(xié)議接口的HID類型的設備。USB-HID是Universal Serial Bus-Human Interface Device的縮寫,由其名稱可以了解HID設備是直接與人交互的設備,例如鍵盤、鼠標與游戲桿等。
USB的硬件端口是統(tǒng)一的,但是USB設備卻是多種多樣的,USB主機根據USB設備的描述符來區(qū)分不同的USB設備。每一個USB設備都有自己的描述符,當插入USB設備之后,主機會向從機發(fā)送命令,從機收到命令之后,會返回特定的描述符信息。主機通過解析收到的描述符,來識別從機設備的相關信息,這個過程,就是設備枚舉(enumeration)過程。
獲取USB的VID和PID信息
我的這個FC手柄插到電腦上后識別出了usb-hid設備。查看到它的vid和pid信息,直接在電腦的設備管理器里能夠查看到,這個信息很有用,后面驅動移植需要用到。
已啟動設備 HID\VID_0810&PID_0001\6&1eff4ed2&0&0000。
驅動程序名稱: input.inf
查找linux內核源碼,鎖定相關驅動
在linux內核源碼的linux/drivers/hid/路徑下,有跟HID相關的驅動源碼。打開hid-core.c文件(HID support for Linux),查看下該源文件中是否包含該usb設備的VID和PID信息。如果沒有,則在hid_have_special_driver添加上VID和PID信息。這個里面的一些宏定義在文件hid-ids.h中可以查看。
torvalds大神linux源碼的github地址:
GitHub - torvalds/linux: Linux kernel source tree文章來源:http://www.zghlxwxcb.cn/news/detail-630609.html
/*
* A list of devices for which there is a specialized driver on HID bus.
*
* Please note that for multitouch devices (driven by hid-multitouch driver),
* there is a proper autodetection and autoloading in place (based on presence
* of HID_DG_CONTACTID), so those devices don't need to be added to this list,
* as we are doing the right thing in hid_scan_usage().
*
* Autodetection for (USB) HID sensor hubs exists too. If a collection of type
* physical is found inside a usage page of type sensor, hid-sensor-hub will be
* used as a driver. See hid_scan_report().
*/
static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) },
//......
}
查找近似hid的游戲手柄驅動
通過make menuconfig打開內核配置選項查看。
?找到有個DragonRise Inc, game controller。雖然不確定它跟我的這款FC手柄完美匹配,但至少從名字上看,這就是個游戲手柄的hid設備。
?如果有默認的內核配置選項文件,也可以直接添加選項開關:
CONFIG_HID_DRAGONRISE=y
跟這個相關的驅動源文件是linux/drivers/hid/hid-dr.c。打開這個文件,添加上我的usb設備的VID和PID信息。
static const struct hid_device_id dr_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006), },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011), },
{ HID_USB_DEVICE(0x0810, 0x0001), },
{ }
};
編譯內核驅動
#使用Yocto SDK里的GCC 5.3.0交叉編譯器編譯出廠Linux源碼,可不用指定ARCH等,直接執(zhí)行Make
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
#編譯前先清除
make distclean
#配置defconfig文件
make imx_v7_defconfig -j 16
#開始編譯zImage
make zImage -j 16
這之后,更新板子上的內核并重啟設備。把該USB游戲手柄插上去,輸入dmesg查看內核日志信息,看是否識別到該設備節(jié)點。
dmesg
查看輸入設備、獲取輸入事件信息
/dev/input/目錄
/dev/input/目錄下的事件都是在驅動中調用input_register_device(struct input_dev *dev)產生的。我的/dev/input/目錄中的文件如下:
$ ls /dev/input/
by-id by-path event0 event1 event2 event3
每個event代表一個事件。那么如何知道每個事件分別與哪個設備對應?可以借助于/proc/bus查看。
/proc/bus/input/devices
/proc/bus/input/devices存放了與event對應的相關設備信息。我的板子上查看到的內容如下:
$ cat /proc/bus/input/devices
可以看到,每一項的“H:”一行后邊的內容中就是對應的event。?
直接讀取/dev/input/eventx
使用cat查看輸入事件的內容,操作相應輸入設備,事件會上報內容。以字符串方式解讀會呈現(xiàn)亂碼。所以可以使用hexdump讀取十六進制的數(shù)據。
測試讀取demo
linux內核使用 input_event結構體描述所有的輸入事件。
/*
* The event structure itself
*/
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
為了驗證該usb的游戲手柄是否工作,以及獲取它對應的鍵值,寫一個小的demo測試讀取下。
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#define _EV_KEY 0x01 /* button pressed/released */
#define _EV_ABS 0x03
#define _EV_MSC 0x04
int main() {
printf("hello,usb hid joystick key test\n");
int fd = open("/dev/input/event3", O_RDONLY);
struct input_event e;
while(1) {
read(fd, &e, sizeof(e));
switch(e.type) {
case _EV_KEY:
printf("type: %d, code: %d,value: %d, time: %d\n", e.type, e.code,e.value, e.time);
break;
case _EV_ABS:
printf("type: %d, code: %d,value: %d, time: %d\n", e.type, e.code,e.value, e.time);
break;
case _EV_MSC:
printf("type: %d, code: %d,value: %d, time: %d\n", e.type, e.code,e.value, e.time);
break;
default:
if(e.type != 0){
printf("type:%d, code: %d,value: %d, time: %d\n",e.type, e.code,e.value, e.time);
}
}
}
close(fd);
return 0;
}
evtest測試工具
在開發(fā)input子系統(tǒng)驅動時,常常會使用evtest工具進行測試。evtest是打印evdev內核事件的工具,它直接從內核設備讀取并打印設備描述的帶有值和符號名的事件,可以用來調試鼠標、鍵盤、觸摸板等輸入設備。通常用于調試輸入設備的問題。
輸出數(shù)據中,“type”是input類型,可以是“EV KEY”、“EV SW”、“EV SND”、“EV LED”或數(shù)值;“value”可以是十進制也可以是十六進制,或者是查詢的kev/開關/聲音/LED的常量名。
evtest工具下載安裝
下載地址:Index of /debian/pool/main/e/evtest/ | 南陽理工學院開源鏡像站 | Nanyang Institute of Technology Open Source Mirror
交叉編譯安裝
#解壓縮
$ tar -xjvf evtest_1.33.orig.tar.bz2
$ cd evtest-1.33/
#加載環(huán)境
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
#生成makefile,指定交叉編譯
.confiqure --host=arm-linux
#編譯
make
evtest工具使用
?運行示例
time
:事件產生的時間。
type:事件類型,常見的有:EV_KEY(鍵盤)、EV_REL(相對坐標)、EV_ABS(絕對坐標)、,定義在[input-event-codes.h] (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h#LC35) 或 input.h 中。
code
:事件的代碼,對事件進一步的描述,如:鍵盤事件的鍵值(KEY_NUMLOCK、KEY_ESC、KEY_1、KEY_A
)。
value
:事件的值,對事件更具體地描述,如:按鍵的按下/抬起。
以下是使用devtest工具,(各按一次上,下,左,右,選擇,開始等按鍵),?抓取的各個按鍵的反饋信息:
手柄上的鍵值確定
FC手柄上一般包含以下鍵。左,右,上,下,start,select,A,B,X,Y。
? ? /**
? ? ?* FC手柄 bit 鍵位對應關系 真實手柄中有一個定時器,處理 連A? 連B
? ? ?* 0? 1? ?2? ? ? ?3? ? ? ?4? ? 5? ? ? 6? ? ?7
? ? ?* A? B? ?Select? Start? Up? ?Down? ?Left? Right
? ? ?*/
如果你買的usb接口的FC游戲手柄是DragonRise Inc. game這家的,估計就不用以上這么的測試鍵值了,直接啟用就能用。但是我隨便買的這款需要測試下對應起來才能用。
?經過以上測試,最終確定鍵值的對應關系如下:
游戲手柄按鍵 | 讀出的鍵值 |
---|---|
左側方向鍵上 | type: 3, code:1,value: 0 type: 3, code:1,value: 127 |
左側方向鍵下 | type: 3, code:1,value: 255 type: 3, code:1,value: 127 |
左側方向鍵左 | type: 3, code:0,value: 0 type: 3, code:0,value: 127 |
左側方向鍵右 | type: 3, code:0,value: 255 type: 3, code:0,value: 127 |
SELECT鍵 | type: 1, code:296,value: 1 type: 1, code:296,value: 0 |
START鍵 | type: 1, code:297,value: 1 type: 1, code:297,value: 0 |
右邊數(shù)字鍵1 | type: 1, code:288,value: 1 type: 1, code:288,value: 0 |
右邊數(shù)字鍵2 | type: 1, code:289,value: 1 type: 1, code:289,value: 0 |
右邊數(shù)字鍵3 | type: 1, code:290,value: 1 type: 1, code:290,value: 0 |
右邊數(shù)字鍵4 | type: 1, code:291,value: 1 type: 1, code:291,value: 0 |
最后試了下控制完全沒問題,還很流暢呢!可以愉快的玩耍啦,帶上個充電寶,這個就是我的移動游戲機,支持無限多個好玩的經典游戲!關于Nes模擬器的移植后面逐一揭曉,歡迎關注收藏。?
其他資源
USB HID_Soc點燈大師的博客-CSDN博客
為了V3S不吃灰,移植NES游戲 / 全志 SOC / WhyCan Forum(哇酷開發(fā)者社區(qū))
V3S移植nes游戲模擬器(附帶游戲合集)_v3s編譯游戲模擬器_qq_46604211的博客-CSDN博客
Linux下查看輸入設備、獲取輸入事件的詳細方法_evtest命令_藍天居士的博客-CSDN博客
linux驅動開發(fā)學習筆記九:menuconfig過程詳解
開發(fā)者搜索-Beta-讓技術搜索更簡單高效
Linux系統(tǒng)struct input_event結構體分類型(鼠標、鍵盤、觸屏)詳解與例子_wkd_007的博客-CSDN博客開發(fā)者搜索-Beta-讓技術搜索更簡單高效
?
USB_HID基礎_usbhid_jansert的博客-CSDN博客
玩轉USB HID系列:Linux下使用C語言和libusb開發(fā)USB HID_whstudio123的博客-CSDN博客
i.MX6ULL驅動開發(fā) | 20 - Linux input 子系統(tǒng)_imx6ull input驅動框架_Mculover666的博客-CSDN博客
GitHub - torvalds/linux: Linux kernel source tree
嵌入式Linux:V3s移植NES游戲,聲音,游戲手柄_全志v3s 移植nes_liefyuan的博客-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-630609.html
到了這里,關于iMX6ULL驅動開發(fā) | 讓imx6ull開發(fā)板支持usb接口FC游戲手柄的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!