页面加载中,请稍候
来源:嵌入式Linux系统开发发布时间:2023-06-232639浏览
询问 AI参考:
韦东山老师驱动大全
Linux 内核源码:include\linux\usb.h
Linux 内核源码:drivers\hid\usbhid\usbmouse.c

使用鼠标模拟按键:左键相当于"L"、右键相当于"S"、"中键"相当于 "回车"。

对于 GPIO 按键,是直接构造、注册一个 input_dev 结构体,在 GPIO 中断函数里获得数据。
现在数据来源发生了变化,数据来自 USB 设备,需要做的事情是:
仿照 usbmouse.c 如下代码构造一个 usb_driver 结构体:

核心是:
id_table 是一个 usb_device_id 数组,示例如下:

usb_device_id 结构体定义如下:
structusb_device_id{2.2.2 probe 函数
/*whichfieldstomatchagainst?*/
__u16match_flags;
/*Usedforproductspecificmatches;rangeisinclusive*/
__u16idVendor;
__u16idProduct;
__u16bcdDevice_lo;
__u16bcdDevice_hi;
/*Usedfordeviceclassmatches*/
__u8bDeviceClass;
__u8bDeviceSubClass;
__u8bDeviceProtocol;
/*Usedforinterfaceclassmatches*/
__u8bInterfaceClass;
__u8bInterfaceSubClass;
__u8bInterfaceProtocol;
/*Usedforvendor-specificinterfacematches*/
__u8bInterfaceNumber;
/*notmatchedagainst*/
kernel_ulong_tdriver_info
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
probe 函数原型如下:
int(*probe)(structusb_interface*intf,
conststructusb_device_id*id);
第 1 个参数是"struct usb_interface *"类型,表示匹配到的"USB 逻辑设备"。
第 2 个参数是"struct usb_device_id *"类型,它是 usb_driver 的 id_table 中的某项,表示第 1 个参数就是跟这个 usb_device_id 匹配的。有必要的话,probe 函数里可以从 id->driver_info 得到驱动相关的一些信息。
在 probe 函数,一般要记录 intf 信息,以后发起 USB 传输时会用到 intf 信息。
核心是:分配、设置、注册一个 input_device 结构体。
分配、填充、提交 URB,在 URB 的回调函数里上报"input_event"。
需要重新配置内核,去掉内核自带的驱动程序。在内核目录下执行"make menuconfig":
DeviceDrivers--->
HIDsupport--->
USBHIDsupport--->
<>USBHIDtransportlayer//不要选中
然后重新编译内核、给开发板替换内核。
韦老师的 USB 鼠标驱动,只实现了检测鼠标左键、右键、中键的【按下弹起】功能,没有实现复杂功能,可以做 demo 学习参考。使用完整 USB 鼠标功能请使用 Linux 内核自带的 driver,如文章开头目录。
/*参考:drivers\hid\usbhid\usbmouse.c*/
#include<linux/kernel.h>
#include<linux/slab.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/usb.h>
#include<linux/input.h>
#include<linux/hid.h>
structusb_mouse_as_key_desc{
structusb_device*dev;
structusb_interface*intf;
conststructusb_device_id*id;
intpipe,maxp;
intbInterval;
void*data_buffer;
dma_addr_tdata_dma;
structurb*urb;
};
/*1.构造 usb_driver
*1.1id_table:能支持哪些设备
*1.2probe:记录某些信息,分配/设置/注册 input_dev,也许"分配/填充/提交 URB"
*/
staticstructusb_device_idusb_mouse_as_key_id_table[]={
{USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID,USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE),.driver_info=(kernel_ulong_t)"itisamouse",},
{}/*Terminatingentry*/
};
staticvoidusb_mouse_as_key_irq(structurb*urb)
{
structinput_dev*dev=urb->context;
structusb_mouse_as_key_desc*desc=input_get_drvdata(dev);
signedchar*data=desc->data_buffer;
intstatus;
//printk("%s%s%d,urb->status=%d\n",__FILE__,__FUNCTION__,__LINE__,urb->status);
switch(urb->status){
case0:/*success*/
break;
case-ECONNRESET:/*unlink*/
case-ENOENT:
case-ESHUTDOWN:
return;
/*-EPIPE:shouldclearthehalt*/
default:/*error*/
gotoresubmit;
}
//printk("data[1]=0x%x\n",data[1]);
input_report_key(dev,KEY_L,data[1]0x01);
input_report_key(dev,KEY_S,data[1]0x02);
input_report_key(dev,KEY_ENTER,data[1]0x04);
input_sync(dev);
resubmit:
status=usb_submit_urb(urb,GFP_ATOMIC);
//printk("%s%s%d,status=%d\n",__FILE__,__FUNCTION__,__LINE__,status);
}
staticintusb_mouse_as_key_open(structinput_dev*dev)
{
structurb*urb;
structusb_mouse_as_key_desc*desc=input_get_drvdata(dev);
interr;
printk("%s%s%d\n",__FILE__,__FUNCTION__,__LINE__);
/*分配/填充/提交URB*/
urb=usb_alloc_urb(0,GFP_KERNEL);
desc->urb=urb;
usb_fill_int_urb(urb,
desc->dev,
desc->pipe,
desc->data_buffer,
(desc->maxp>8?8:desc->maxp),
usb_mouse_as_key_irq,
dev,
desc->bInterval);
urb->transfer_dma=desc->data_dma;
urb->transfer_flags|=URB_NO_TRANSFER_DMA_MAP;
err=usb_submit_urb(urb,GFP_ATOMIC);
printk("%s%s%d,err=%d\n",__FILE__,__FUNCTION__,__LINE__,err);
returnerr;
}
staticvoidusb_mouse_as_key_close(structinput_dev*dev)
{
structusb_mouse_as_key_desc*desc=input_get_drvdata(dev);
/*取消/释放URB*/
usb_kill_urb(desc->urb);
usb_free_urb(desc->urb);
}
staticintusb_mouse_as_key_probe(structusb_interface*intf,conststructusb_device_id*id)
{
structusb_device*dev=interface_to_usbdev(intf);
structinput_dev*input_dev;
structusb_mouse_as_key_desc*desc;
interror;
structusb_host_interface*interface;
structusb_endpoint_descriptor*endpoint;
intpipe,maxp;
printk("%s%s%d\n",__FILE__,__FUNCTION__,__LINE__);
/*1.记录设备信息:intf*/
interface=intf->cur_altsetting;
if(interface->desc.bNumEndpoints!=1)
return-ENODEV;
endpoint=interface->endpoint[0].desc;
if(!usb_endpoint_is_int_in(endpoint))
return-ENODEV;
pipe=usb_rcvintpipe(dev,endpoint->bEndpointAddress);
maxp=usb_maxpacket(dev,pipe,usb_pipeout(pipe));
desc=kmalloc(sizeof(structusb_mouse_as_key_desc),GFP_KERNEL);
desc->dev=dev;
desc->intf=intf;
desc->id=id;
desc->pipe=pipe;
desc->maxp=maxp;
desc->bInterval=endpoint->bInterval;
desc->data_buffer=usb_alloc_coherent(dev,maxp,GFP_ATOMIC,desc->data_dma);
printk("%s%s%d,desc->data_buffer=0x%x\n",__FILE__,__FUNCTION__,__LINE__,desc->data_buffer);
/*2.分配/设置/注册input_dev
*2.1能产生哪类事件
*2.2能产生这类事件里哪些些事件:L/S/ENTER
*2.3设置函数,比如open
*2.4在open函数里:分配/填充/提交URB
*2.5URB的回调函数:解析数据,上报input_event
*/
input_dev=devm_input_allocate_device(intf->dev);
input_set_drvdata(input_dev,desc);
/*set1:whichtypeevent?*/
__set_bit(EV_KEY,input_dev->evbit);
/*set2:whichevent?*/
__set_bit(KEY_L,input_dev->keybit);
__set_bit(KEY_S,input_dev->keybit);
__set_bit(KEY_ENTER,input_dev->keybit);
/*set3:open*/
input_dev->open=usb_mouse_as_key_open;
input_dev->close=usb_mouse_as_key_close;
error=input_register_device(input_dev);
usb_set_intfdata(intf,input_dev);
return0;
}
staticvoidusb_mouse_as_key_disconnect(structusb_interface*intf)
{
structinput_dev*input_dev=usb_get_intfdata(intf);
structusb_mouse_as_key_desc*desc=input_get_drvdata(input_dev);
usb_free_coherent(desc->dev,desc->maxp,desc->data_buffer,desc->data_dma);
kfree(desc);
input_unregister_device(input_dev);
usb_set_intfdata(intf,NULL);
}
staticstructusb_driverusb_mouse_as_key_driver={
.name="usbmouse_as_key",
.probe=usb_mouse_as_key_probe,
.disconnect=usb_mouse_as_key_disconnect,
.id_table=usb_mouse_as_key_id_table,
};
/*入口函数/出口函数*/
//module_usb_driver(usb_mouse_as_key_driver);
staticint__initusb_mouse_as_key__init(void)
{
printk("%s%s%d\n",__FILE__,__FUNCTION__,__LINE__);
returnusb_register(usb_mouse_as_key_driver);
}
staticvoid__exitusb_mouse_as_key__init_exit(void)
{
usb_deregister(usb_mouse_as_key_driver);
}
module_init(usb_mouse_as_key__init);
module_exit(usb_mouse_as_key__init_exit);
MODULE_LICENSE("GPL");
测试:
#把USB鼠标查到开发板上
#先看看原来有哪些设备节点
ls/dev/input/event*
#安装驱动程序
insmodusbmouse_as_key.ko
#再看看新得到了哪个设备节点
ls/dev/input/event*
#执行命令,假设event4是新节点
hexdump/dev/input/event4
#点击鼠标按键即可观察输出信息
#第2种测试方法:执行以下命令,按鼠标左键、右键,再按中键就有输出"ls"
cat/dev/tty0
#第3种测试方法:执行以下命令(注意"<"号前后没有空格),就可以使用鼠标按键在控制台输入字符
exec0</dev/tty0
新闻来源:嵌入式Linux系统开发,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。
暂无评论哦,快来评论一下吧!

2026-06-10

2026-07-08