举一个嵌入式linux内核驱动的例程,关于usb子系统驱动鼠标,要有详细说明与代码注释
时间: 2024-03-20 16:44:07 浏览: 15
好的,下面是一个关于 USB 子系统驱动鼠标的嵌入式 Linux 内核驱动例程,包括详细说明与代码注释:
```c
#include <linux/module.h>
#include <linux/usb.h>
// 定义 USB 设备的 vendor ID 和 product ID
#define USB_VENDOR_ID 0x046d
#define USB_PRODUCT_ID 0xc52b
// 定义 USB 鼠标设备结构体
struct usb_mouse {
struct usb_device *dev; // USB 设备指针
struct urb *urb; // USB 请求块指针
struct input_dev *idev; // 输入设备指针
char *data; // 数据缓冲区指针
dma_addr_t data_dma; // 数据缓冲区 DMA 地址
};
// USB 设备 ID 结构体
static struct usb_device_id usb_mouse_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID, USB_PRODUCT_ID) },
{ } // 必须以空结构体结束
};
MODULE_DEVICE_TABLE(usb, usb_mouse_id_table);
// USB 设备连接回调函数
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_mouse *mouse;
struct input_dev *idev;
struct usb_device *dev = interface_to_usbdev(intf);
int error = -ENOMEM;
// 分配 USB 鼠标设备结构体
mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
if (!mouse) {
dev_err(&intf->dev, "no memory for device\n");
goto error;
}
// 分配输入设备结构体
idev = input_allocate_device();
if (!idev) {
dev_err(&intf->dev, "no memory for input device\n");
goto error_free_mouse;
}
// 设置输入设备参数
idev->name = "USB Mouse";
idev->phys = "usb-mouse/input0";
idev->id.bustype = BUS_USB;
idev->id.vendor = USB_VENDOR_ID;
idev->id.product = USB_PRODUCT_ID;
idev->id.version = 0x0100;
// 注册输入设备
input_register_device(idev);
// 绑定 USB 鼠标设备和输入设备
mouse->dev = dev;
mouse->idev = idev;
// 分配 USB 请求块
mouse->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!mouse->urb) {
dev_err(&intf->dev, "no memory for urb\n");
goto error_free_input;
}
// 分配数据缓冲区
mouse->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &mouse->data_dma);
if (!mouse->data) {
dev_err(&intf->dev, "no memory for data\n");
goto error_free_urb;
}
// 初始化 USB 请求块
usb_fill_int_urb(mouse->urb, dev, usb_rcvintpipe(dev, 1), mouse->data, 8,
usb_mouse_irq, mouse, 1);
// 提交 USB 请求块
error = usb_submit_urb(mouse->urb, GFP_KERNEL);
if (error) {
dev_err(&intf->dev, "submit urb failed: %d\n", error);
goto error_free_data;
}
// 保存私有数据指针
usb_set_intfdata(intf, mouse);
return 0;
error_free_data:
usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
error_free_urb:
usb_free_urb(mouse->urb);
error_free_input:
input_free_device(idev);
error_free_mouse:
kfree(mouse);
error:
return error;
}
// USB 设备断开回调函数
static void usb_mouse_disconnect(struct usb_interface *intf)
{
struct usb_mouse *mouse = usb_get_intfdata(intf);
// 取消 USB 请求块
usb_kill_urb(mouse->urb);
// 释放数据缓冲区
usb_free_coherent(mouse->dev, 8, mouse->data, mouse->data_dma);
// 释放 USB 请求块
usb_free_urb(mouse->urb);
// 注销输入设备
input_unregister_device(mouse->idev);
// 释放 USB 鼠标设备结构体
kfree(mouse);
}
// USB 鼠标中断处理函数
static void usb_mouse_irq(struct urb *urb)
{
struct usb_mouse *mouse = urb->context;
struct input_dev *idev = mouse->idev;
char *data = mouse->data;
int error;
// 处理 USB 鼠标数据
input_report_key(idev, BTN_LEFT, data[0] & 0x01);
input_report_key(idev, BTN_RIGHT, data[0] & 0x02);
input_report_key(idev, BTN_MIDDLE, data[0] & 0x04);
input_report_rel(idev, REL_X, data[1]);
input_report_rel(idev, REL_Y, data[2]);
// 提交输入报告
error = input_sync(idev);
if (error) {
dev_err(&mouse->dev->dev, "sync failed: %d\n", error);
}
// 重新提交 USB 请求块
error = usb_submit_urb(urb, GFP_KERNEL);
if (error) {
dev_err(&mouse->dev->dev, "resubmit urb failed: %d\n", error);
}
}
// 定义 USB 驱动程序结构体
static struct usb_driver usb_mouse_driver = {
.name = "usb_mouse",
.id_table = usb_mouse_id_table,
.probe = usb_mouse_probe,
.disconnect = usb_mouse_disconnect,
};
// 模块初始化函数
static int __init usb_mouse_init(void)
{
int error;
// 注册 USB 驱动程序
error = usb_register_driver(&usb_mouse_driver);
if (error) {
pr_err("usb_register_driver failed: %d\n", error);
}
return error;
}
// 模块退出函数
static void __exit usb_mouse_exit(void)
{
// 注销 USB 驱动程序
usb_deregister_driver(&usb_mouse_driver);
}
module_init(usb_mouse_init);
module_exit(usb_mouse_exit);
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("USB Mouse Driver");
MODULE_LICENSE("GPL");
```
以上代码实现了一个简单的 USB 鼠标驱动程序,包括 USB 设备连接和断开回调函数、USB 鼠标中断处理函数等。具体来说,该驱动程序通过 USB 鼠标中断传输方式接收鼠标数据,并将数据转换为输入报告,最终通过输入子系统向用户空间发送数据。开发人员可以根据实际需要修改和扩展该驱动程序,实现更加复杂的 USB 设备驱动。