自娛自樂5之Linux gadget驅動4(接受發送,complete函數,setup函數)

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從上面看主要是處理特殊請求。

*/

好了,基礎的模塊都說完了。下期再見!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章