自娱自乐5之Linux gadget驱动4(接受发送,complete函数,setup函数)

来源:互联网 发布:java p2p 合肥学院 编辑:程序博客网 时间:2024/06/14 09:55

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从上面看主要是处理特殊请求。

*/

好了,基础的模块都说完了。下期再见!

原创粉丝点击