转载USB总线驱动分析
内核里USB总线驱动程序:
- 识别USB设备(分配地址、USB设备(set address)、获取描述符);
- 查找并安装对应的设备驱动程序;
- 提供USB读写函数(不知道数据含义)。
USB设备驱动程序:
- 由我们完成,知道数据含义,
USB设备驱动程序实现
- 分配/设置usb_driver结构体
.id_table
.probe
.disconnect - 注册
转载相关函数的详解
转载USB设备接口描述符详解
通过鼠标按键实现L、S、回车。
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
static char *usb_buf;
static u32 usb_buf_phys;
static u32 usb_buf_len;
static struct urb* usbmouse_urb;
static struct input_dev *usbmouse_dev;
/*接口描述符*/
static struct usb_device_id usbmouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },//指定接口描述符
//{USB_DEVICE(vend, prod)}可指定驱动程序只支持特定设备(vid,pid)
{ } /* Terminating entry */
};
static void usbmouse_irq(struct urb*urb)
{
/*打印鼠标原始数据
u32 i;
static u32 cnt=0;
printk("data:%d",++cnt);
for (i = 0; i < usb_buf_len; i++)
{
printk("%02x \n", usb_buf[i]);
}
printk("\n");
/*usb数据含义
*buf[0]:bit0-左键01;bit1右键02;bit2中键 04 1表示按下*/
input_report_key(usbmouse_dev, KEY_L, usb_buf[0] & 0x01);
input_report_key(usbmouse_dev, KEY_S, usb_buf[0] & 0x02);
input_report_key(usbmouse_dev, KEY_ENTER, usb_buf[0] & 0x04);
input_sync(usbmouse_dev);
usb_submit_urb(usbmouse_urb,GFP_KERNEL);
}
static int usbmouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);//由接口获取usb_device
struct usb_host_interface *interface; //当前接口设置
struct usb_endpoint_descriptor *endpoint;//端点描述符
int pipe;
interface = intf->cur_altsetting; //获取当前接口设置
endpoint = &interface->endpoint[0].desc;//获取当前端点描述符,除端点0的第一个端点
/*分配一个结构体*/
usbmouse_dev=input_allocate_device();
/*设置*/
/*能产生那类事件*/
set_bit(EV_KEY,usbmouse_dev->evbit);
set_bit(EV_REP,usbmouse_dev->evbit);//相对位移类
/*能产生哪些事件*/
set_bit(KEY_L,usbmouse_dev->keybit);
set_bit(KEY_S,usbmouse_dev->keybit);
set_bit(KEY_ENTER,usbmouse_dev->keybit);
/*注册*/
input_register_device(usbmouse_dev);
/*硬件相关操作*/
/*数据传输三要素:*/
/*源:usb的某个端点 建立中断输入端点 端点地址*/
pipe = usb_rcvintpipe(usb_dev, endpoint->bEndpointAddress);
/*长度 端点所支持最大数据包的长度*/
usb_buf_len=endpoint->wMaxPacketSize;
/*目的(返回虚拟地址 分配 物理地址)*/
usb_buf = usb_buffer_alloc(usb_dev, usb_buf_len, GFP_ATOMIC, &usb_buf_phys);
/*使用三要素*/
/*分配urb,usb请求块*/
usbmouse_urb=usb_alloc_urb(0,GFP_KERNEL);
/*设置urb 查询完成函数 查询方式的端点数据传输的查询频率*/
usb_fill_int_urb(usbmouse_urb, usb_dev, pipe,usb_buf,usb_buf_len,usbmouse_irq, NULL, endpoint->bInterval);
usbmouse_urb->transfer_dma =usb_buf_phys;
usbmouse_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/*使用urb 提交*/
usb_submit_urb(usbmouse_urb, GFP_KERNEL);
return 0;
}
static void usbmouse_disconnect(struct usb_interface *intf)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
usb_kill_urb(usbmouse_urb);
input_unregister_device(usbmouse_dev);
input_free_device(usbmouse_dev);
usb_free_urb(usbmouse_urb);
usb_buffer_free(usb_dev, usb_buf_len, usb_buf, usb_buf_phys);
}
static struct usb_driver usb_mouse_driver = {
.name = "usbmouse",
.probe = usbmouse_probe,
.disconnect = usbmouse_disconnect,
.id_table = usbmouse_id_table,
};
static int usbmouse_init(void)
{
usb_register(&usb_mouse_driver);
return 0;
}
static void usbmouse_exit(void)
{
usb_deregister(&usb_mouse_driver);
}
module_init(usbmouse_init);//入口函数
module_exit(usbmouse_exit);//出口函数
MODULE_LICENSE("GPL");