『壹』 求助,usb hid滑鼠上位機程序的編寫問題
USBHID是HumanInterfaceDevice的縮寫,由其名稱可以了解HID設備是直接與人交互的設備,例如鍵盤、滑鼠與游戲桿等。不過HID設備並不一定要有人機介面,只要符合HID類別規范的設備都是HID設備。下列是HID類別設備的主要能力:1、交換的數據存儲在稱為報表(report)的結構內,設備的固件必須支持HID報表的格式。主機在控制與中斷傳輸中傳送與要求報表,來傳送與接收數據。報表的格式非常有彈性,可以處理任何類別的數據。2、每一筆事務可以攜帶小量或中量的數據。低速設備每一筆事務最大是8個位元組,全速設備每一筆事務最大是64個位元組,高速設備每一筆事務最大是1024個位元組。一個報表可以使用多筆事務。3、設備可以在未預期的時間傳送信息給主機,例如鍵盤的按鍵或是滑鼠的移動。所以主機會定時輪詢設備,來取得最新的數據。下列是HID類別設備的主要限制:1、最大的傳輸速度有限,特別是低速與全速的時候。主機可以保證低速的中斷端點,每10ms內不會有超過1筆事務,每一秒最多800個位元組。主機可以保證全速端點,每1ms1筆事務,每一秒最多是6400個位元組。主機可以保證高速端點,每125us3筆事務,每一秒最多24.576MB。2、沒有保證的傳輸速率。如果設備是設置在10ms的時距,事務之間的時間可能等於或小於10ms。除非設備是設置在全速時在每個幀傳輸數據,或是在高速時在每個微幀傳輸數據。這是最快的輪詢速率,所以斷點可以保證有正確的帶寬可供使用。3、Windows98Gold系統不支持中斷輸出傳輸,所有主機與設備的數據都必須使用控制傳輸。HID設備除了傳送數據給主機外,它也會從主機接收數據。只要能夠符合HID類別規范的設備都可以是HID設備,在規范內提到了條型碼筆、溫度計以及電壓計等例子。這些設備雖然沒有傳統的人機介面,但是它們都可以傳送數據給主機,也可以從主機接收配置的要求。設備除了HID介面之外,它可能同時還包含有其他的USB介面。例如影像顯示設備可能使用HID介面來做亮度,對比,與更新率的軟體控制,而使用傳統的影像介面來傳送要顯示的數據。USB擴音器可以使用實時傳輸來播放語音,同時使用HID介面來控制音量,震盪,與低音等。HID介面通常比傳統的控制介面來得便宜。HID類別設備的規范是。另外還有一份文件HIDUsabeTables,用來定義讓主機了解以及使用HID數據的數值。這兩份文件是由USBDeviceWorkingGroup所制定,Group的成員都是USB實施者論壇的會員。您可以在USB實施者論壇網站上下載這兩份文件。地址:http://www.usb.org
『貳』 淺析usbhid驅動如何源源不斷的獲取usb滑鼠
淺析usbhid驅動如何源源不斷的獲取usb滑鼠數據
hid_probe
==>usb_hid_configure
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize, // 首先申請interrupt urb內存,並填充下面的有效數據
// 後面的hid_start_in()函數會usb_submit_urb提交該urb,到
// usb host控制器,進而發送interrupt in事物到hid設備[滑鼠或鍵盤]
hid_irq_in, hid, interval); // hid_irq_in為interrupt中斷管道數據處理回調函數
// urb->complete = hid_irq_in;
// interval為usbhid driver需要每隔interval毫秒
// 產生一次in讀取動作,這只是一個理論上的東西[luther.gliethttp]
// 實際上該interval數值,僅僅用來usb host管理interrupt類型匯流排帶寬
// 時,作為調整系數之一而已,[luther.gliethttp]
// 真正通信是這樣的,對該urb執行一次usb_submit_urb()操作,
// 那麼usb host將等待interrupt數據返回,如果hid物理設備沒有
// 向它的interrupt端點填入指定大小的數據,那麼
// usb host將一直等待,直到hid物理設備將指定個數的數據填入
// 它的interrupt端點為止,於是usb host將觸發中斷,
// 通知usb_submit_urb提交的interrupt類型的urb有數據回來了,
// 同時該urb生命終結,如果不再執行usb_submit_urb提交動作,再次等待
// 下一次interrupt數據到來的話,那麼usbhid.ko將只得到
// 一次數據,[luther.gliethttp]
// 於是hid_irq_in函數將被執行,幸運的是,
// hid_irq_in函數中確實又調用了usb_submit_urb,再次將
// 該urb添加usb host事件中,等待下一次hid設備產生數據上傳,然後再次調用到這里hid_irq_in處理數據,
// 如果強行將hid_irq_in函數中的usb_submit_urb屏蔽掉,
// 我們可以通過kernel klog看到,滑鼠數據只會產生一個[luther.gliethttp]
static void hid_irq_in(struct urb *urb)
{
struct hid_device *hid = urb->context;
struct usbhid_device *usbhid = hid->driver_data;
int status;
switch (urb->status) {
case 0: /* success */
usbhid->retry_delay = 0;
hid_input_report(urb->context, HID_INPUT_REPORT, // 提交到更高一級的驅動層處理urb->transfer_buffer數據
urb->transfer_buffer, // 下面是截獲的urb->transfer_buffer數據內容,對於我的mouse,每次都是4個位元組:
urb->actual_length, 1); // [13602.612302] 00 fe 00 00
break; // [13602.868282] 01 00 00 00
case -EPIPE: /* stall */ // [13602.964277] 00 00 00 00
clear_bit(HID_IN_RUNNING, &usbhid->iofl); // [13603.860290] 04 00 00 00
set_bit(HID_CLEAR_HALT, &usbhid->iofl); // [13604.052288] 00 00 00 00
schele_work(&usbhid->reset_work); // [13605.332295] 02 00 00 00
return; // [13605.460297] 00 00 00 00
case -ECONNRESET: /* unlink */ // [13605.812292] 00 f9 01 00
case -ENOENT: // [13605.876280] 00 ff 00 00
case -ESHUTDOWN: /* unplug */
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
return;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
case -ETIME: /* protocol error or unplug */
case -ETIMEDOUT: /* Should never happen, but... */
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
hid_io_error(hid);
return;
default: /* error */
warn("input irq status %d received", urb->status);
}
status = usb_submit_urb(urb, GFP_ATOMIC); // 再次將該urb提交到usb host上,
if (status) { // 這樣才能繼續讀取下一次滑鼠數據[luther.gliethttp]
clear_bit(HID_IN_RUNNING, &usbhid->iofl); // 如果將status = usb_submit_urb(urb, GFP_ATOMIC);注釋掉
if (status != -EPERM) { // 那麼表示urb生命就真的終結在這次了,不會再讀到mouse數據了.
err_hid("can't resubmit intr, %s-%s/input%d, status %d", // 因為沒有任何urb讓usb host做讀取mouse的interrupt管道[luther.gliethttp].
hid_to_usb_dev(hid)->bus->bus_name,
hid_to_usb_dev(hid)->devpath,
usbhid->ifnum, status);
hid_io_error(hid);
}
}
}
那hid_irq_in什麼時候被調用呢,來看看,對hid_irq_in的調用直接來自物理irq中斷[luther.gliethttp]
drivers/usb/host/ohci-s3c2410.c|455| .urb_enqueue = ohci_urb_enqueue,
drivers/usb/host/ohci-ep93xx.c|132| .urb_enqueue = ohci_urb_enqueue
drivers/usb/host/ohci-at91.c|250| .urb_enqueue = ohci_urb_enqueue,
static const struct hc_driver ohci_at91_hc_driver = {
.description = hcd_name,
.proct_desc = "AT91 OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
* generic hardware linkage
*/
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
*/
.start = ohci_at91_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
/*
* scheling support
*/
.get_frame_number = ohci_get_frame,
/*
* root hub support
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
.start_port_reset = ohci_start_port_reset,
};
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_hcd_at91_drv_suspend,
.resume = ohci_hcd_at91_drv_resume,
.driver = {
.name = "at91_ohci",
.owner = THIS_MODULE,
},
};
ohci_hcd_at91_drv_probe
==> usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
==*> usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED); // pdev->resource[1].start等於irqnum中斷號[luther.gliethttp]
==**> request_irq(irqnum, &usb_hcd_irq, irqflags, hcd->irq_descr, hcd) // 注冊物理中斷處理函數usb_hcd_irq
所以當usb host有數據或者異常時就會產生物理irq中斷,隨後kernel調用到usb_hcd_irq中斷處理函數
usb_hcd_irq
==> hcd->driver->irq (hcd);即ohci_irq
==> ohci_irq
==*> dl_done_list (ohci);
==**> takeback_td(ohci, td);
==***> finish_urb(ohci, urb, status); // 如果ed->td_list.next鏈表上沒有任何控制管道,bulk等數據發送時,調用該函數[luther.gliethtt]
==****> usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
==*****> urb->complete (urb);即hid_irq_in // 調用回調函數, hid_irq_in會調用usb_submit_urb(urb, GFP_ATOMIC);
// 再次讓usb host等待hid硬體設備的interrupt數據到來.[luther.gliethttp]
『叄』 usbhid 端點0如何發送數據
usbhid端點0發送數據是分兩次發送的。檢查一個端點的發送是否結束有二種方法:
1、當發送結束(設備收到ACK)時,有一個發送結束中斷,這個中斷由USB庫處理,並通過EP1_IN_Callback這個回調函數交由用戶程序確認。
2、查詢這個端點的狀態,如果端點狀態處於EP_TX_VALID,說明發送未結束,如果端點狀態處於EP_TX_NAK,說明發送結束。使用下述調用可以得到端點1的發送狀態:GetEPTxStatus(ENDP1)。
usbhid是Human Interface Device的縮寫,由其名稱可以了解HID設備是直接與人交互的設備,例如鍵盤、滑鼠與游戲桿等。不過HID設備並不一定要有人機介面,只要符合HID類別規范的設備都是HID設備。
交換的數據存儲在稱為報表(report)的結構內,設備的固件必須支持HID報表的格式。主機在控制與中斷傳輸中傳送與要求報表,來傳送與接收數據。報表的格式非常有彈性,可以處理任何類別的數據。
設備除了HID介面之外,它可能同時還包含有其他的USB介面。例如影像顯示設備可能使用HID介面來做亮度,對比,與更新率的軟體控制,而使用傳統的影 像介面來傳送要顯示的數據。USB擴音器可以使用實時傳輸來播放語音,同時使用HID介面來控制音量,震盪,與低音等。HID介面通常比傳統的控制介面來得便宜。