USB裝置驅動之滑鼠

來源:互聯網
上載者:User

USB裝置驅動之滑鼠

1.  概述

     USB滑鼠驅動程式大致分為兩大部分:USB裝置驅動部分和輸入裝置驅動部分,USB裝置驅動只起了掛接匯流排和傳輸資料的作用,而具體的裝置類型的驅動仍然是工作的主體。

     USB裝置驅動部分:負責註冊USB裝置驅動,實現probe和disconnect函數,初始化驅動支援的USB滑鼠裝置類型表(id_table);初始化和提交URB;根據HID規範,滑鼠只有一個端點(不包括端點0),且屬於中斷傳輸類型。

     輸入裝置驅動部分:負責註冊輸入裝置和該裝置所支援的事件類型;向輸入核心層上報滑鼠事件。

     這裡有一個概念需要注意,這裡的中斷傳輸與硬體中斷那個中斷是不一樣的,這個中斷傳輸實際是靠USB hostcontrol輪詢usb device來實現的,而USBhost control對於CPU則是基於中斷的機制。拿USB滑鼠為例,USB host control對USB滑鼠不斷請求,這個請求的間隔是很短的,端點描述符中的bInterval域中指定的,當滑鼠發生過了事件之後,滑鼠會發送資料回host,這時USB
host control中斷通知CPU,於是usb_mouse_irq被調用,在usb_mouse_irq裡,就可以讀取滑鼠發回來的資料,當讀完之後,驅動再次調用usb_submit_urb發出請求,就這麼一直重複下去,一個usb滑鼠的驅動也就完成了。

     我們在進行硬體訪問的時候,只需調用URB相關的介面,而不需要關心底層USB主機控制器的具體細節,因此,USB裝置也變得與平台無關,同樣的驅動可應用於不同的SOC。

2.程式碼分析

#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>/* for apple IDs */#ifdef CONFIG_USB_HID_MODULE#include "../hid-ids.h"#endif/* * Version Information */#define DRIVER_VERSION "v1.6"#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"#define DRIVER_DESC "USB HID Boot Protocol mouse driver"#define DRIVER_LICENSE "GPL"MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE(DRIVER_LICENSE);/*  */struct usb_mouse {char name[128];char phys[64];struct usb_device *usbdev;struct input_dev *dev;struct urb *irq;signed char *data;dma_addr_t data_dma;};static void usb_mouse_irq(struct urb *urb){struct usb_mouse *mouse = urb->context; /* context 指向USB驅動 程式分 配 的 資料 塊*/signed char *data = mouse->data;struct input_dev *dev = mouse->dev;int status;/* 判斷傳輸是否成功 */switch (urb->status) {case 0:/* success */break;case -ECONNRESET:/* unlink */case -ENOENT:case -ESHUTDOWN:return;/* -EPIPE:  should clear the halt */default:/* error */goto resubmit;}/* 上報事件 */input_report_key(dev, BTN_LEFT,   data[0] & 0x01);input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);input_report_key(dev, BTN_SIDE,   data[0] & 0x08);input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);input_report_rel(dev, REL_X,     data[1]);input_report_rel(dev, REL_Y,     data[2]);input_report_rel(dev, REL_WHEEL, data[3]);input_sync(dev);/* 提交下次傳輸 */resubmit:status = usb_submit_urb (urb, GFP_ATOMIC);if (status)err ("can't resubmit intr, %s-%s/input0, status %d",mouse->usbdev->bus->bus_name,mouse->usbdev->devpath, status);}static int usb_mouse_open(struct input_dev *dev){struct usb_mouse *mouse = input_get_drvdata(dev);mouse->irq->dev = mouse->usbdev;/* 向USB核心層提交URB */if (usb_submit_urb(mouse->irq, GFP_KERNEL))return -EIO;return 0;}static void usb_mouse_close(struct input_dev *dev){struct usb_mouse *mouse = input_get_drvdata(dev);usb_kill_urb(mouse->irq);}/* USB裝置與驅動匹配上時調用 */static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id){/* 裝置描述 usb_device *//* 介面描述 usb_interface */struct usb_device *dev = interface_to_usbdev(intf); /* 介面設定描述 */struct usb_host_interface *interface;/* 端點描述符 */struct usb_endpoint_descriptor *endpoint;struct usb_mouse *mouse;struct input_dev *input_dev;int pipe, maxp;int error = -ENOMEM;/* 擷取當前介面設定 */interface = intf->cur_altsetting;  /* 根據HID規範,滑鼠只有一個端點(不包含0號控制端點)*/if (interface->desc.bNumEndpoints != 1)return -ENODEV;/* 擷取端點0描述符 */endpoint = &interface->endpoint[0].desc;/* 根據HID規範,滑鼠唯一的端點應為中斷端點 */if (!usb_endpoint_is_int_in(endpoint))return -ENODEV;/* 產生中斷管道 */pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);/* 返回該端點能夠傳輸的最大的包長度,滑鼠的返回的最大資料包為4個位元組。*/  maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));/* 建立input裝置 */mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);input_dev = input_allocate_device();if (!mouse || !input_dev)goto fail1;   /* 申請記憶體空間用於資料轉送,data 為指向該空間的地址*/mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);if (!mouse->data)goto fail1;/* 分配URB */mouse->irq = usb_alloc_urb(0, GFP_KERNEL);if (!mouse->irq)goto fail2;mouse->usbdev = dev;mouse->dev = input_dev;if (dev->manufacturer)strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));if (dev->product) {if (dev->manufacturer)strlcat(mouse->name, " ", sizeof(mouse->name));strlcat(mouse->name, dev->product, sizeof(mouse->name));}if (!strlen(mouse->name))snprintf(mouse->name, sizeof(mouse->name), "USB HIDBP Mouse %04x:%04x", le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct));usb_make_path(dev, mouse->phys, sizeof(mouse->phys));strlcat(mouse->phys, "/input0", sizeof(mouse->phys));/* 設定輸入裝置的相關屬性 */input_dev->name = mouse->name;input_dev->phys = mouse->phys;usb_to_input_id(dev, &input_dev->id);input_dev->dev.parent = &intf->dev;/* 設定輸入裝置支援的事件和事件代碼 */input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |BIT_MASK(BTN_EXTRA);input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);input_set_drvdata(input_dev, mouse);input_dev->open = usb_mouse_open;input_dev->close = usb_mouse_close;/* 初始化中斷URB */usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, (maxp > 8 ? 8 : maxp), usb_mouse_irq, mouse, endpoint->bInterval);mouse->irq->transfer_dma = mouse->data_dma;mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;/* 向輸入核心層註冊輸入裝置 */error = input_register_device(mouse->dev);if (error)goto fail3;usb_set_intfdata(intf, mouse);return 0;fail3:usb_free_urb(mouse->irq);fail2:usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);fail1:input_free_device(input_dev);kfree(mouse);return error;}/* USB裝置移除時調用 */static void usb_mouse_disconnect(struct usb_interface *intf){struct usb_mouse *mouse = usb_get_intfdata (intf);usb_set_intfdata(intf, NULL);if (mouse) {usb_kill_urb(mouse->irq);input_unregister_device(mouse->dev);usb_free_urb(mouse->irq);usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);kfree(mouse);}}/* USB驅動支援的滑鼠類型表 */static struct usb_device_id usb_mouse_id_table [] = {{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE) },{ }/* Terminating entry */};MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);static struct usb_driver usb_mouse_driver = {.name= "usbmouse",   /* 驅動名 */.probe= usb_mouse_probe, /* 捕獲函數 */.disconnect= usb_mouse_disconnect, /* 卸載函數 */.id_table= usb_mouse_id_table, /* 裝置列表 */};static int __init usb_mouse_init(void){/* 註冊滑鼠驅動程式 */int retval = usb_register(&usb_mouse_driver);if (retval == 0)printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"DRIVER_DESC "\n");return retval;}static void __exit usb_mouse_exit(void){usb_deregister(&usb_mouse_driver);}module_init(usb_mouse_init);module_exit(usb_mouse_exit);


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.