f_sourcesink.c裏面在執行set_alt方法後就調用source_sink_start_ep(),這裏面就有usb_ep_queue()可以認爲開始進行數據交互。後期我要改一下這個過程,通過一個簡單的misc驅動去分開調用接受發送
我們現在看
static int source_sink_start_ep(struct f_sourcesink *ss,boolis_in)
{
structusb_ep *ep;
structusb_request *req;
int status;
ep = is_in ? ss->in_ep :ss->out_ep;
//是in還是out,
req = alloc_ep_req(ep);
if(!req)
return-ENOMEM;
req->complete =source_sink_complete;//下面來說
if(is_in)// 這裏要說的就是in是對於主機來說
reinit_write_data(ep, req);//把數據寫到req的buf中
else
memset(req->buf, 0x55,req->length);//初始化req->buf
status = usb_ep_queue(ep, req,GFP_ATOMIC);//提交req到硬件fifo
if(status) {
structusb_composite_dev *cdev;
cdev =ss->function.config->cdev;
free_ep_req(ep, req);
}
/*
這裏總結一下數據交互過程
1. 動態申請空間。
2. 設置完成函數。
3. 是in就或取數據(操作硬件的話,可能用到別的驅動),是out就初始化req->buf。
4. 提交req到硬件fifo。
萬變不離其宗,大概就這樣。
*/
returnstatus;
}
看完成函數
static void source_sink_complete(struct usb_ep *ep,structusb_request *req)
{
structf_sourcesink *ss = ep->driver_data;
structusb_composite_dev *cdev = ss->function.config->cdev;
int status = req->status;
switch(status) {
case0: /*normal completion? */
/*
正常,繼續操作req。
*/
if(ep == ss->out_ep) {
check_read_data(ss,req);//f_sourcesink提供,MOD63或0
memset(req->buf,0x55, req->length);
} else
reinit_write_data(ep,req);
break;
/*this endpoint is normally active while we're configured */
case-ECONNABORTED: /* hardware forced ep reset */
case-ECONNRESET: /*request dequeued */
case-ESHUTDOWN: /*disconnect from host *///這幾個說明傳輸停止
if(ep == ss->out_ep)
check_read_data(ss,req);
free_ep_req(ep, req);
return;
case-EOVERFLOW: /*buffer overrun on read means that
* we didn't provide a big enough
* buffer.
*/
default:
case-EREMOTEIO: /*short read *///一些錯誤,沒有操作buf,相當於重發
break;
}
status = usb_ep_queue(ep, req,GFP_ATOMIC);
//繼續提交,幾乎所有的complete都要做的,正常就要繼續
}
/*
總結一下complete
1.是否有一些錯誤,根據錯誤判斷是停止還是重發。
2.正常就要繼續提交req。
*/
最後是setup
這個要從udc說起
看s3c2410,假設ep0中斷,且是置位了setup_end位
會調用
dev->driver->setup(&dev->gadget,crq);
就是它,事實這就是和usb枚舉相關
static int
composite_setup(struct usb_gadget *gadget,conststructusb_ctrlrequest *ctrl)//ctrl是硬件獲得的
{
u8 intf = w_index & 0xFF;
structusb_function *f = NULL;
//省掉了一大堆
switch(ctrl->bRequest) {
//對於各請求,composite_setup寫成了一個統一的,我們只要實現接口就可以了
caseUSB_REQ_GET_DESCRIPTOR:
/* any number of configs can work */
caseUSB_REQ_SET_CONFIGURATION:
caseUSB_REQ_GET_CONFIGURATION:
caseUSB_REQ_SET_INTERFACE:
caseUSB_REQ_GET_INTERFACE:
caseUSB_REQ_GET_STATUS:
caseUSB_REQ_CLEAR_FEATURE:
caseUSB_REQ_SET_FEATURE:
break;
default:
switch(ctrl->bRequestType & USB_RECIP_MASK) {//接受對象
caseUSB_RECIP_INTERFACE://intf = w_index & 0xFF,對應的接口號
if (!cdev->config || intf >=MAX_CONFIG_INTERFACES)
break;
f =cdev->config->interface[intf];
break;
caseUSB_RECIP_ENDPOINT:
endp = ((w_index &0x80) >> 3) | (w_index & 0x0f);
/*
這個操作過後,endp的第4位是方向,0~3是地址,對應set_config()中的
addr =((ep->bEndpointAddress & 0x80) >> 3)
| (ep->bEndpointAddress & 0x0f);
set_bit(addr,f->endpoints);
*/
list_for_each_entry(f,&cdev->config->functions, list) {
if (test_bit(endp, f->endpoints))
break;
}
if (&f->list == &cdev->config->functions)
f = NULL;
break;
}//上面就是找對應的struct usb_function
if(f && f->setup)// structusb_function中的setup優先使用,f_sourcesink沒實現
value = f->setup(f,ctrl);
else{
struct usb_configuration *c;
c = cdev->config;
if (c && c->setup)
value =c->setup(c, ctrl); //對我們來說就是sourcesink_setup()
}
gotodone;
}
}
static int sourcesink_setup(struct usb_configuration *c,
conststruct usb_ctrlrequest *ctrl)
{
structusb_request *req = c->cdev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);//小端轉換要注意一下
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
req->length = USB_BUFSIZ;
//我們知道請求分標準和非標準,這下面兩個就是非標準,
//控制端口允許多包請求,爲了測試
switch(ctrl->bRequest) {
case0x5b: //控制寫。 填充buffer
if(ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
goto unknown;
if(w_value || w_index)
break;
if(w_length > req->length)//大於USB_BUFSIZ,就用USB_BUFSIZ
break;
value = w_length;//請求的數據長度
break;
case0x5c: //控制讀。 返回buffer
if(ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
goto unknown;
if(w_value || w_index)
break;
if(w_length > req->length)
break;
value = w_length;
break;
default:
unknown:
}
if(value >= 0) {
req->zero = 0;
req->length = value;
value =usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);//看到是從控制端口輸出的,對於上面的多包請求,這就是最特別的一點
}
returnvalue;
}
/*
總結一下setup
1. composite_setup()爲我們考慮了標準請求。
2. struct usb_function和struct usb_configuration只要實現一個setup,都實現的話會用struct usb_function。
3. 我們實現的setup從上面看主要是處理特殊請求。
*/
好了,基礎的模塊都說完了。下期再見!