(基於 Linux 3.4.2 內核) 可分為以下幾個步驟來完成這個驅動: ~~~~ 1. 分配設置一個 usb_driver 結構體 2. 註冊這個 usb_driver (如果設備的 id_table 與驅動匹配的話會調用驅動程式的 probe 函數) 3. 在 probe 函數中分配 urb ...
(基於 Linux 3.4.2 內核)
可分為以下幾個步驟來完成這個驅動:
1. 分配設置一個 usb_driver 結構體
2. 註冊這個 usb_driver
(如果設備的 id_table 與驅動匹配的話會調用驅動程式的 probe 函數)
3. 在 probe 函數中分配 urb
4. 配置 urb
5. 調用 usb_submit_urb 啟用 urb
6. 在 urb 中斷函數內處理狀態
7. 重新提交 urb
usb_driver 的配置與註冊
/* 驅動的 id_table */
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ }
};
/* 分配設置 usb_driver */
static struct usb_driver mouse_monitor = {
.name = "MouseMonitor",
.probe = mouse_monitor_probe,
.disconnect = mouse_monitor_disconnect,
.id_table = usb_mouse_id_table,
};
/* 註冊 usb_driver */
static int mouse_monitor_init(void)
{
usb_register(&mouse_monitor);
return 0;
}
probe 函數
static int mouse_monitor_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
static struct usb_device *dev;
dma_addr_t usb_buf_phy;
int pipe;
int buffer_length;
/* 得到 usb_device */
dev = interface_to_usbdev(intf);
/* 得到當前的介面描述符與端點描述符 */
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
/* 獲取到設備數據長度 */
buffer_length = __le16_to_cpu(endpoint->wMaxPacketSize);
len = buffer_length;
/* 獲取到通信的管道 */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/* 分配一段連貫的記憶體 */
usb_buf = usb_alloc_coherent(dev, buffer_length, GFP_ATOMIC, &usb_buf_phy);
/* 分配 urb */
MouseUrb = usb_alloc_urb(0, GFP_KERNEL);
/* 配置 urb */
usb_fill_int_urb(MouseUrb, dev, pipe, usb_buf, (buffer_length > 8 ? 8 : buffer_length), usb_complete, NULL, endpoint->bInterval);
MouseUrb->transfer_dma = usb_buf_phy;
MouseUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* 提交調用 urb */
usb_submit_urb(MouseUrb, GFP_KERNEL);
return 0;
}
urb 傳輸完成函數
static void usb_complete(struct urb *urb)
{
static unsigned char presta;
#if 0
int i;
for (i = 0; i < len; i++)
printk("%02x ", usb_buf[i]);
printk("\n");
#endif
if(presta != (usb_buf[1] & 0x01)){
if(presta)
printk("BTN_LEFT is released. \n");
else
printk("BTN_LEFT is pressed. \n");
}
/* 保存狀態 */
presta = usb_buf[1] & 0x01;
/* 重新提交 urb */
usb_submit_urb(MouseUrb, GFP_KERNEL);
}
usb_complete 函數中註釋掉的程式為測試使用,通過輸出的數據找到滑鼠左鍵對應的 usb_buf 與 bit 位。
測試驅動
make menuconfig 去掉原來的 USB 滑鼠驅動
-> Device Drivers
-> HID Devices
<> USB Human Interface Device (full HID) support
編譯當前驅動,傳入開發板並安裝。
按下鬆開滑鼠左鍵,現象如下: