每當說起 Linux Kernel Driver 入門,就不免提到如何寫個 Hello World 級的 Module,這樣的第一支程式,除了可供 Linux Kernel 動態載入和卸載,似乎是一點用處也沒有。與一般應用程式不同,開發 Linux Driver 最大的門檻不在於如何撰寫出 Module,而是如何設計系統架構與硬體兩者間的橋樑。其中懂得如何控制和結合 Kernel 內各種機制更是重點,最複雜的莫過於此。
這邊有個 Mouse Kernel Driver,會在 Kernel 上新增一個虛擬滑鼠裝置,然後使用者可從 sysfs 控制該虛擬滑鼠(virmouse.c):
/*
* A Virtual Mouse Driver to send fake events from userspace.
*
* Written by Fred Chien <fred@ullab.org>
*
*/
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/platform_device.h>
struct input_dev *virmouse_input_dev;
static struct platform_device *virmouse_dev; /* Device structure */
/* Sysfs method to input simulated coordinates */
static ssize_t write_virmouse(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
int x, y, key;
/* parsing input data */
sscanf(buffer, "%d%d%d", &x, &y, &key);
/* Report relative coordinates */
input_report_rel(virmouse_input_dev, REL_X, x);
input_report_rel(virmouse_input_dev, REL_Y, y);
printk ("virmouse_event: X:%d Y:%d %d\n", x, y, key);
/* Report key event */
if (key>0) {
if (key==1)
input_report_key(virmouse_input_dev, BTN_LEFT, 1);
else if (key==2)
input_report_key(virmouse_input_dev, BTN_MIDDLE, 1);
else
input_report_key(virmouse_input_dev, BTN_RIGHT, 1);
}
input_sync(virmouse_input_dev);
return count;
}
/* Attach the sysfs write method */
DEVICE_ATTR(vmevent, 0644, NULL, write_virmouse);
/* Attribute Descriptor */
static struct attribute *virmouse_attrs[] = {
&dev_attr_vmevent.attr,
NULL
};
/* Attribute group */
static struct attribute_group virmouse_attr_group = {
.attrs = virmouse_attrs,
};
/* Driver Initializing */
int __init virmouse_init(void)
{
/* Register a platform device */
virmouse_dev = platform_device_register_simple("virmouse", -1, NULL, 0);
if (IS_ERR(virmouse_dev)){
printk ("virmouse_init: error\n");
return PTR_ERR(virmouse_dev);
}
/* Create a sysfs node to read simulated coordinates */
sysfs_create_group(&virmouse_dev->dev.kobj, &virmouse_attr_group);
/* Allocate an input device data structure */
virmouse_input_dev = input_allocate_device();
if (!virmouse_input_dev) {
printk("Bad input_allocate_device()\n");
return -ENOMEM;
}
/* Announce that the virtual mouse will generate relative coordinates */
set_bit(EV_REL, virmouse_input_dev->evbit);
set_bit(REL_X, virmouse_input_dev->relbit);
set_bit(REL_Y, virmouse_input_dev->relbit);
set_bit(REL_WHEEL, virmouse_input_dev->relbit);
/* Announce key event */
set_bit(EV_KEY, virmouse_input_dev->evbit);
set_bit(BTN_LEFT, virmouse_input_dev->keybit);
set_bit(BTN_MIDDLE, virmouse_input_dev->keybit);
set_bit(BTN_RIGHT, virmouse_input_dev->keybit);
/* Register with the input subsystem */
input_register_device(virmouse_input_dev);
/* print messages in the dmesg */
printk("Virtual Mouse Driver Initialized.\n");
return 0;
}
/* Driver Uninitializing */
void virmouse_uninit(void)
{
/* Unregister from the input subsystem */
input_unregister_device(virmouse_input_dev);
/* Remove sysfs node */
sysfs_remove_group(&virmouse_dev->dev.kobj, &virmouse_attr_group);
/* Unregister driver */
platform_device_unregister(virmouse_dev);
return;
}
module_init(virmouse_init);
module_exit(virmouse_uninit);
MODULE_AUTHOR("Fred Chien <fred@ullab.org>");
MODULE_DESCRIPTION("Virtual Mouse Driver");
MODULE_LICENSE("GPL");然後建立 Makefile:
obj-m += virmouse.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
@rm -fr *.ko *.o編譯(需要安裝 Kernel header):
$ make
載入:
$ sudo insmod virmouse.ko
測試:
# 先切換成 root $ sudo su - # 滑鼠 X軸移動 168,Y軸移動 68,0 代表純移動不點擊 $ echo "168 68 0" > /sys/devices/platform/virmouse/vmevent
此 Driver 會先註冊成 evdev input 的滑鼠裝置,然後在 sysfs 並建立 group 和 vmevent 檔,Userspace 下的應用程式可以發送命令到 vmevent 使滑鼠移動或點擊左右中鍵。
後記:
此程式極為簡單,因此省略程式碼的說明,讀者直接看 source code 應該就能明瞭。

請問一下
回覆刪除他的點擊是跟目前的螢幕上的滑鼠分開囉?
我下了一些命令但似乎
螢幕上的滑鼠沒有反應
[403064.769199] virmouse_event: X:168 Y:68 0
[403077.313221] virmouse_event: X:168 Y:68 0
[403137.784216] virmouse_event: X:0 Y:0 1
[403209.072702] virmouse_event: X:0 Y:0 2
[403213.264967] virmouse_event: X:0 Y:0 1
[403228.372760] virmouse_event: X:0 Y:0 1
[403230.220670] virmouse_event: X:0 Y:0 1
[403234.157705] virmouse_event: X:0 Y:0 0
好像懂了
回覆刪除cat /dev/input/mouse2
就可以看到他的行為
如果你有動作的話
很實用的範例!
不好意思喔~想問一下
回覆刪除我echo " 10 10 3" 不是應該按右鍵嗎?
但是他好像沒有反應?
另外, 我好像開不了 dev/input/mouse2 ??
應該是要先 ls /dev/input 看看新增的是那個mouse!然後再使用 cat /dev/input/mouse1(or 2.......)
回覆刪除我是的 /dev/input/mouse1
does it work with Kernel 2.6?
回覆刪除FC
Yes. Of course :-)
刪除可以請問您是用ubuntu哪一個版本嗎@@?
回覆刪除因為我的input.h檔案裡面找不到"input_report_rel(virmouse_input_dev, REL_X, x);"這個函式
你可能忘了裝 linux kernel header 相關套件吧 :-)
回覆刪除可以麻煩前輩告訴我妳裝了哪些套件嗎><?
回覆刪除