urb传输的代码分析【转】
轉(zhuǎn)自:http://blog.csdn.net/zkami/article/details/2503829
urb傳輸?shù)拇a分析
如需引用,請注明出處blog.csdn.net/zkami 作者ZhengKui
分配一個urb,并初始化之。返回這個urb的指針
usb_alloc_urb(int iso_packets, gfp_t mem_flags) (core/message.c)
->urb = kmalloc(...); 分配一個urb
->usb_init_urb(urb); 初始化這個urb:初始化個字段為0,增加引用計(jì)數(shù)
根據(jù)傳輸類型,填寫urb的一些字段(usb.h)
static inline void usb_fill_control_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
static inline void usb_fill_int_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context,
int interval)
static inline void usb_fill_bulk_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
相 同:對于ctl/int/bulk這三種傳輸類型,在fill urb時都需要填充dev,pipe,transfer_buffer,transfer_buffer_length,complete, context 字段。其中pipe代表當(dāng)前urb傳輸?shù)墓艿溃瑃ransfer_buffer
代表當(dāng)前urb傳輸?shù)臄?shù)據(jù)的起始地址,transfer_buffer_length是當(dāng)前urb傳輸?shù)臄?shù)據(jù)長度,complete是當(dāng)前urb處理完后調(diào)用的回調(diào)函數(shù)。
不同:fill control urb時需要fill setup_packet字段,它指向一個setup包的起始地址
fill int urb時要根據(jù)傳輸速度來fill interval字段
提交urb。發(fā)出一個異步的傳輸請求,完成后將調(diào)用回調(diào)函數(shù)。在調(diào)用usb_submit_urb函數(shù)前必須正確的初始化urb, 最后urb的控制將返回給發(fā)出申請的dev driver。
usb_submit_urb(struct urb *urb, gfp_t mem_flags) (core/urb.c)
->ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)[usb_pipeendpoint(urb->pipe)];
根據(jù)pipe得到urb要連接到哪個ep的list中
->xfertype = usb_endpoint_type(&ep->desc);
得到端點(diǎn)類型,并根據(jù)不同的類型進(jìn)行設(shè)置,如填充urb的transfer_flags字段。
如果是ISO傳輸,根據(jù)iso packet的數(shù)量(urb->number_of_packets),初始化每一個packet。 (urb->iso_frame_desc[n])
如果是iso/int傳輸,根據(jù)端點(diǎn)速度類型設(shè)置urb->interval
->usb_hcd_submit_urb(urb, mem_flags) (core/hcd.c)
將提交的urb指派給合適的host controller driver,這里的HC遵守OHCI規(guī)范
->rh_urb_enqueue(hcd, urb); 如果是Root Hub,調(diào)用該函數(shù)
->rh_queue_status (hcd, urb); 如果是中斷傳輸
->usb_hcd_link_urb_to_ep(hcd, urb); 把urb掛到ep上
->mod_timer(); 修改rh_timer polling的時間
->rh_call_control (hcd, urb); 如果是控制傳輸
->usb_hcd_link_urb_to_ep(hcd, urb); 把urb掛到ep上
然后根據(jù)不同的standard request(ch9.h) Setup Packet的request域來確定len
->ohci_hub_control(hcd, typeReq, wValue, wIndex,tbuf, wLength)
通過操作根Hub寄存器來完成上層對根Hub發(fā)送的命令
->usb_hcd_unlink_urb_from_ep(hcd, urb); 出錯的話把urb從ep上脫鏈
->usb_hcd_giveback_urb(hcd, urb, status); urb處理完后調(diào)用回調(diào)函數(shù)
->ohci_urb_enqueue(hcd, urb, mem_flags) 如果不是Root Hub,調(diào)用該函數(shù)
-> ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) ohci-q.c
如果ep上掛有ed,直接返回。如果沒有,則用參數(shù)pipe、interval以及ep.desc加工一個ed,將其掛在ep上并返回
-> ed_alloc (ohci, GFP_ATOMIC); (ohci-mem.c)分配一個struct ed
-> td_alloc (ohci, GFP_ATOMIC); (ohci-mem.c)分配一個struct td
-> ed_free(ohci, ed); 釋放struct ed
-> usb_calc_bus_time() 計(jì)算傳輸一個擁有最大字節(jié)數(shù)的數(shù)據(jù)包所需要的時間(ms)
然后:設(shè)定info的各個域,(info其實(shí)就是OHCI Spec中定義的Endpoint Descriptor的Dword 0
詳見P16 OHCI spec figure4-1)再將info賦給ed->hwInfo
然后: 根據(jù)端點(diǎn)的類型確定size(size決定該端點(diǎn)上掛載的td的數(shù)目,除實(shí)時端點(diǎn)上的td外,
其它端點(diǎn)上的td能夠裝載4K的數(shù)據(jù))
接著: 給urb_priv_t分配空間,并為其上所掛載的td指針數(shù)組分配空間
-> td_alloc (ohci, mem_flags); (ohci-mem.c) 分配ed中的每一個td
-> usb_hcd_link_urb_to_ep(hcd, urb); urb掛到ep的urb_list上
-> ed_schedule (ohci, ed);
根據(jù)ed的類型將ed插入到HC相應(yīng)隊(duì)列中,并讀/寫HC的寄存器
-> balance (ohci, ed->interval, ed->load);
-> periodic_link(ohci, ed);
-> usb_hcd_unlink_urb_from_ep(hcd, urb);
-> td_submit_urb (ohci, urb); 將urb需要發(fā)送的數(shù)據(jù)安排到相應(yīng)ed下的td隊(duì)列中
-> td_fill(ohci, info, data, 4096, urb, cnt);
message.c
usb_interrupt_msg(...) 事實(shí)上調(diào)用的是usb_bulk_msg()
->usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout)
-> usb_alloc_urb(0, GFP_KERNEL) 分配一個urb
-> usb_fill_int_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL,
ep->desc.bInterval); 如果是int msg
-> usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL); 如果是bulk msg
-> usb_start_wait_urb(urb, timeout, actual_length);
提交urb并等待完成或超時。將urb提交給usb core后就停在wait_for_completion_timeout()等待
當(dāng)這個urb完成后,會調(diào)用usb_api_blocking_completion()進(jìn)而調(diào)用complete來通知不用再等了。
->usb_submit_urb(urb, GFP_NOIO) 提交urb
->wait_for_completion_timeout(&ctx.done, expire)) 等待。其中expire是等待的時間限
&ctx.done是等到了的話,調(diào)用的回調(diào)函數(shù)
->usb_kill_urb(urb) 如果超時就kill這個urb
usb_control_msg(...)
->struct usb_ctrlrequest *dr = kmalloc(...)
首先創(chuàng)建一個usb_ctrlrequest的數(shù)據(jù)結(jié)構(gòu)(詳見usb2.0 spec ch9),并初始化bRequestType,bRequest,wValue
wIndex,wLength字段
->usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
->usb_alloc_urb(0, GFP_NOIO); 分配一個urb
->usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
填充這個ctl urb, usb_api_blocking_completion是回調(diào)函數(shù)
->usb_start_wait_urb(urb, timeout, &length);
提交urb并等待完成或超時。將urb提交給usb core后就停在wait_for_completion_timeout()等待
當(dāng)這個urb完成后,會調(diào)用usb_api_blocking_completion()進(jìn)而調(diào)用complete來通知不用再等了。
->usb_submit_urb(urb, GFP_NOIO) 提交urb
->wait_for_completion_timeout(&ctx.done, expire)) 等待。其中expire是等待的時間限
&ctx.done是等到了的話,調(diào)用的回調(diào)函數(shù)
->usb_kill_urb(urb) 如果超時就kill這個urb
如需引用,請注明出處blog.csdn.net/zkami 作者ZhengKui
總結(jié)
以上是生活随笔為你收集整理的urb传输的代码分析【转】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文件夹管理器
- 下一篇: 转:HTTPS 协议