读书人

自娱自乐五之Linux gadget驱动4(接受

发布时间: 2013-09-05 16:02:07 作者: rapoo

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

*/

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

读书人网 >UNIXLINUX

热点推荐