平台:mini2440
核心:linux 2.6.32.2
USB裝置插入時,核心會讀取裝置資訊,接着就把id_table裡的資訊與讀取到的資訊做比較,看是否比對,如果比對,就調用probe函數。USB裝置拔出時會調用disconnect函數。URB在USB裝置驅動程式中用來描述與USB裝置通信時用到的基本載體和核心資料結構。
URB(usb request block)處理流程:
①USB裝置驅動程式建立并初始化一個通路特定USB裝置特定端點的urb并送出給USB core。
②USB core把這個urb送出到USB主要制器驅動程式。
③USB主要制器驅動程式根據該urb描述的資訊來通路usb裝置。
④當裝置通路結束後,USB主要制器驅動程式通知USB裝置驅動程式。
USB滑鼠資料格式:
①bit0 ->左鍵,1->按下,0->松開
②bit1 ->右鍵,1->按下,0->松開
③bit2 ->中鍵,1->按下,0->松開
驅動代碼清單:
usb_mouse_input_test.c:
#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 struct urb *uk_urb;
static char *usb_buf;
static int len;
static struct input_dev *uk_dev;
static dma_addr_t usb_buf_phys;
static struct usb_device_id usb_mouse_input_test_id_table [] =
{
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE)
}
};
static void usb_mouse_input_test_irq(struct urb *urb)
{
static unsigned char pre_val;//USB滑鼠将它的資料寫到驅動緩沖區usb_buf
if ((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))
{
//狀态變化
printk("left !\n");
}
if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))
{
//狀态變化
printk("right !\n");
}
if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))
{
//狀态變化
printk("middle !\n");
}
pre_val = usb_buf[0];
usb_submit_urb(uk_urb, GFP_KERNEL);
}
static int usb_mouse_input_test_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);//擷取usb接口結構體中的usb裝置結構體
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
int pipe;
interface = intf->cur_altsetting; //擷取usb接口結構體中的usb host接口結構體
endpoint = &interface->endpoint[0].desc;//擷取usb host接口結構體中的端點描述結構體
uk_dev = input_allocate_device();
set_bit(EV_KEY, uk_dev->evbit);//設定
set_bit(EV_REP, uk_dev->evbit);
set_bit(KEY_L, uk_dev->keybit);
set_bit(KEY_S, uk_dev->keybit);
set_bit(KEY_ENTER, uk_dev->keybit);
input_register_device(uk_dev);//注冊
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
len = endpoint->wMaxPacketSize;
usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);
uk_urb = usb_alloc_urb(0, GFP_KERNEL);//配置設定usb request block
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usb_mouse_input_test_irq, NULL, endpoint->bInterval);
uk_urb->transfer_dma = usb_buf_phys; //源,目的,長度,設定URB
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb(uk_urb, GFP_KERNEL);//把URB送出到USB主要制器驅動
return 0;
}
static void usb_mouse_input_test_disconnect(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf);
printk("disconnect mouse!\n");
usb_kill_urb(uk_urb);
usb_free_urb(uk_urb);
usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
input_unregister_device(uk_dev);
input_free_device(uk_dev);
}
static struct usb_driver usb_mouse_input_test_driver = {
.name = "usb_mouse_input_test_",
.probe = usb_mouse_input_test_probe,
.disconnect = usb_mouse_input_test_disconnect,
.id_table = usb_mouse_input_test_id_table,
};
static int usb_mouse_input_test_init(void)
{
usb_register(&usb_mouse_input_test_driver);
return 0;
}
static void usb_mouse_input_test_exit(void)
{
usb_deregister(&usb_mouse_input_test_driver);
}
MODULE_LICENSE("GPL");
module_init(usb_mouse_input_test_init);
module_exit(usb_mouse_input_test_exit);
Makefile:
obj-m += usb_mouse_input_test.o
KERN_DIR = /home/***/linux-2.6.32.2
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
測試前去掉linux核心中滑鼠功能:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN0LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX90zZOBTT61UNBRUT5V1MkZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39zM1QjN0cTN2EjNxYDM0EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
insmod usb_mouse_input_test.ko
插入USB滑鼠
點選滑鼠三個按鍵
終端可見列印資訊:
left !
right !
middle !