USB在接入系統的時候,以0的設備ID和主機通信,然后由主機為其分配新的ID。
在主機端,D+和D-都是下拉接地的。而設備端的D-接上拉時,表明此設備為高速設備:12M/s。 D+接上拉時則是全速設備:480M/S。
PC的USB口中的D+D-有15K的下拉電阻,未接USB設備時,皆為低電平。
而設備中的D+D-則是1.5K的上拉電阻。一旦接入PC中,電腦就會知道有設備接入。
USB是主從結構。所有的傳輸都是由主機發起的,即USB設備沒有主動通知USB主機的能力。
USB的傳輸類型:
控制傳輸。 可靠,時間有保證。 例如:USB設備的識別。
批量傳輸。 可靠,但時間沒有保證。 例如:U盤。
中斷傳輸。 可靠,實時傳輸。 例如:USB鼠標。
實時傳輸。 不可靠。實時傳輸。 例如:USB攝像頭。
USB傳輸的對象為端點。比如讀U盤和寫U盤,可以形容為從端點1讀數據,從端點2寫數據。
除了端點0以外,每個端點只支持一個方向的數據傳輸。
端點0用於控制傳輸,既能輸出也能輸入。
每一個端點都有傳輸類型和方向。
程序和術語中說的輸入輸出 都是基於USB主機的立場說的。
比如鼠標是數據從鼠標傳輸到PC機的,鼠標對應的端點稱為輸入端點。
USB總線驅動程序的作用: 1.識別設備 2. 查找並安裝對應的設備驅動程序 3.提供USB讀寫函數。
USB驅動程序框架:
app:
--------------------------------------------------------------------
USB設備驅動程序 (拿到數據處理,驅動開發人員編寫)
--------------------------------------------------------------------
USB總線驅動程序 //1.識別 2.找到匹配的設備驅動 3.提供讀寫函數(不知數據含義)
--------------------------------------------------------------------
主機控制器
UHCI OHCI EHCI
--------------------------------------------------------------------
USB設備
UHCI intel 適用於低速和全速
OHCI Microsoft 適用於低速和全速
EHCI 高速
1.識別設備
1.1分配地址,並告訴USB設備(set address)。
1.2 發出命令獲取描述符
2. 查找並安裝對應的設備驅動程序
3.提供USB讀寫函數。
把USB設備接到開發板上,看輸出信息:
usb 1-1: new full speed USB device using s3c2410-ohci and address 2
usb 1-1: configuration #1 chosen from 1 choice
scsi0 : SCSI emulation for USB Mass Storage devices
scsi 0:0:0:0: Direct-Access Kingston DataTraveler 3.0 PMAP PQ: 0 ANSI: 6
sd 0:0:0:0: [sda] 30277632 512-byte hardware sectors (15502 MB)
sd 0:0:0:0: [sda] Write Protect is off
sd 0:0:0:0: [sda] Assuming drive cache: write through
sd 0:0:0:0: [sda] 30277632 512-byte hardware sectors (15502 MB)
sd 0:0:0:0: [sda] Write Protect is off
sd 0:0:0:0: [sda] Assuming drive cache: write through
sda: sda1
sd 0:0:0:0: [sda] Attached SCSI removable disk
斷開USB設備
usb 1-1: USB disconnect, address 2
再接上:
usb 1-1: new full speed USB device using s3c2410-ohci and address 3 usb 1-1: configuration #1 chosen from 1 choice scsi1 : SCSI emulation for USB Mass Storage devices scsi 1:0:0:0: Direct-Access Kingston DataTraveler 3.0 PMAP PQ: 0 ANSI: 6 sd 1:0:0:0: [sda] 30277632 512-byte hardware sectors (15502 MB) sd 1:0:0:0: [sda] Write Protect is off sd 1:0:0:0: [sda] Assuming drive cache: write through sd 1:0:0:0: [sda] 30277632 512-byte hardware sectors (15502 MB) sd 1:0:0:0: [sda] Write Protect is off sd 1:0:0:0: [sda] Assuming drive cache: write through sda: sda1 sd 1:0:0:0: [sda] Attached SCSI removable disk
然后在內核中搜索USB device using這個字符。最后發現在 drivers/usb/core/hub.c(+2186)中的hub_port_init 函數中。
逆推則發現如下調用關系:
hub_irq()
-->> kick_khubd()
-->> hub_thread()
-->> hub_events()
-->> hub_port_connect_change()
-->>choose_address() //分配新的USB地址
-->> hub_port_init()
-->> hub_set_address() //把地址告訴USB設備
-->> usb_get_device_descriptor() //獲取USB設備描述符
-->> usb_get_device_descriptor() //再獲取一次USB設備描述符
-->> usb_new_device()
-->> usb_get_configuration() //讀取所有的設備描述符並解析
-->> device_add() //把設備放入總線的dev鏈表,從總線的driver鏈表中取出driver一一比較。
//usb_interface和usb_driver的id_table比較。
//如果匹配上了,則調用對應driver的probe函數。
-->> 進入USB總線驅動
usb驅動測試程序:
/************************************************************************* > File Name: usb_mouse_as_key.c > Author: > Mail: > Created Time: 2016年11月04日 星期五 22時55分15秒 ************************************************************************/ #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> struct input_dev *input_dev; signed char *usb_buff; static dma_addr_t usb_buf_phys; struct urb *uk_urb; int len; static void usbmouse_as_key_irq(struct urb *urb) { int i; static int cnt = 0;
#if 0
static int pr_lb,pr_rb,pr_mb;
// printk("data cnt %d:",++cnt);
// for( i=0;i<len;i++ )
// {
// printk("%2.2x ",usb_buff[i]);
// }
// printk("\n");
// printk("lb:%01x rb:%01x mb:%01x\n",(usb_buff[1])&0x01,(usb_buff[1]>>1)&0x01,(usb_buff[1]>>2)&0x01);
// printk("move x:%04d y:%04d\n",(usb_buff[2]),(usb_buff[3]>>4));
if( (usb_buff[1]&0x01) != pr_lb )
{
input_event(input_dev,EV_KEY,KEY_L,!pr_lb); /* 有事件產生時上報事件 */
input_sync(input_dev);
}
if( ((usb_buff[1]>>1)&0x01) != pr_rb )
{
input_event(input_dev,EV_KEY,KEY_S,!pr_rb); /* 有事件產生時上報事件 */
input_sync(input_dev);
}
if( ((usb_buff[1]>>2)&0x01) != pr_mb )
{
input_event(input_dev,EV_KEY,KEY_ENTER,!pr_mb); /* 有事件產生時上報事件 */
input_sync(input_dev);
}
pr_lb = usb_buff[1]&0x01;
pr_rb = (usb_buff[1]>>1)&0x01;
pr_mb = (usb_buff[1]>>2)&0x01;
#else printk("data cnt %d:",++cnt); for( i=0;i<len;i++ ) { printk("%02x",usb_buff[i]); } printk("\n");
#endif usb_submit_urb(uk_urb,GFP_KERNEL); } static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; int pipe; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; printk("found usbmouse_as_key\n"); printk("bcdUSB = %x\n",dev->descriptor.bcdUSB); printk("VID = 0X%x\n",dev->descriptor.idVendor); printk("PID = 0X%x\n",dev->descriptor.idProduct); /* 分配一個input_dev結構體 */ input_dev = input_allocate_device(); /* 設置 */ /* 能產生哪類事件 */ set_bit(EV_KEY,input_dev->evbit); set_bit(EV_REP,input_dev->evbit); //重復類事件 /* 能產生哪些事件 */ set_bit(KEY_L,input_dev->keybit); set_bit(KEY_S,input_dev->keybit); set_bit(KEY_ENTER,input_dev->keybit); /* 注冊 */ input_register_device(input_dev); /* 硬件相關操作 */ /* 數據傳輸3要素: 源、目的、長度 */ /* 源: USB設備的某個節點 */ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); /* 長度 */ len = endpoint->wMaxPacketSize; /* 目的: */ usb_buff = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &usb_buf_phys); /* 使用3要素 */ /* USB request block */ uk_urb = usb_alloc_urb(0, GFP_KERNEL); /* 設置URB */ usb_fill_int_urb(uk_urb, dev, pipe, usb_buff, len, usbmouse_as_key_irq, NULL, endpoint->bInterval); //bInterval 查詢頻率 uk_urb->transfer_dma = usb_buf_phys; uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* 使用urb */ usb_submit_urb(uk_urb,GFP_KERNEL); return 0; } static void usbmouse_as_key_disconnect(struct usb_interface *intf) { struct usb_device *dev = interface_to_usbdev(intf); printk("disconnect usbmouse_as_key\n"); usb_kill_urb(uk_urb); usb_free_urb(uk_urb); usb_buffer_free(dev, len, usb_buff,usb_buf_phys); input_unregister_device(input_dev); input_free_device(input_dev); } static struct usb_device_id usbmouse_as_key_id_table[] = { { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE) }, { }/* Terminating entry */ }; /* 分配 設置 */ static struct usb_driver usbmouse_as_key_driver = { .name= "usbmouse", .probe= usbmouse_as_key_probe, .disconnect= usbmouse_as_key_disconnect, .id_table= usbmouse_as_key_id_table, }; static int mouse_init(void) { /* 注冊 */ usb_register(&usbmouse_as_key_driver); return 0; } static void mouse_exit(void) { usb_deregister(&usbmouse_as_key_driver); } module_init(mouse_init); module_exit(mouse_exit); MODULE_LICENSE("GPL");
卸載掉內核中的鼠標usb驅動程序。
安裝我們的驅動程序,接入鼠標。
按下鼠標按鍵,將會在控制台看到相應的信息。
將打印信息的地方改成上報信息,即可
sd