am8268 usb从机驱动udc笔记
drivers/usb/am7x/am7x_udc.c
static int __init am7x_udc_probe(struct platform_device *pdev)
{
struct aotg_udc *udc ;
int retval = 0;
struct device *dev = &pdev->dev;
unsigned long dma_weight;
udc= &controller;
udc_reinit(udc);
spin_lock_init(&udc->lock);
udc->transceiver = otg_get_transceiver();
retval = request_irq(IRQ_USB, aotg_udc_irq,
IRQF_SHARED |IRQF_DISABLED, udc->gadget.name,
(void *)udc);
/*register driver*/
retval = device_register(&udc->gadget.dev);
}
/* ---------------------------------------------------------------------------
* handle interrupt
* ---------------------------------------------------------------------------
*/
//linux板子作为usb从机设备时接收ubuntu usb过来的数据的入口函数为irq中断函数
static irqreturn_t aotg_udc_irq(int irqnum,void *_udc)
{
struct aotg_udc *udc = (struct aotg_udc *)_udc;
//DMSG_UDC("@@@---irqvector=%x----\n",irqvector);
switch(irqvector){
case UIV_USBRESET:
/*enable ep0IN interrupt*/
aotg_writeb(EP0_IN_IRQ,IN07IEN);
aotg_writeb(EP0_OUT_IRQ,OUT07IEN);
case UIV_HSPEED:
INFO("@@@---uhsi\n");
udc->gadget.speed = USB_SPEED_HIGH;
udc->highspeed = 1;
case UIV_SUSPEND:
case UIV_EP1IN:
//INFO("EP1IRQ\n");
aotg_writeb(EP1_IN_IRQ,IN07IRQ); /*clear ep1in irq*/
handle_ep(udc,2);
break;
#ifdef SUPPORT_INTIN
case UIV_EP2IN:
aotg_writeb(EP2_IN_IRQ,IN07IRQ); /*clear ep2in irq*/
handle_ep(udc,3);
break;
case UIV_EP2OUT:
aotg_writeb(EP2_OUT_IRQ,IN07IRQ); /*clear ep2out irq*/
handle_ep(udc,4);
break;
case UIV_EP3IN:
aotg_writeb(EP3_IN_IRQ,IN07IRQ); /*clear ep3in irq*/
handle_ep(udc,5);
break;
case UIV_EP3OUT:
aotg_writeb(EP3_OUT_IRQ,IN07IRQ); /*clear ep3out irq*/
handle_ep(udc,6);
break;
#endif
#ifdef SUPPORT_ISOOUT
case UIV_EP4IN:
aotg_writeb(EP4_IN_IRQ,IN07IRQ); /*clear ep4in irq*/
handle_ep(udc,7);
break;
case UIV_EP4OUT:
aotg_writeb(EP4_OUT_IRQ,IN07IRQ); /*clear ep4out irq*/
handle_ep(udc,8);
break;
#endif
case UIV_EP1OUT:
aotg_writeb(EP1_OUT_IRQ,OUT07IRQ); /*clear ep1out irq*/
handle_ep(udc,1);
break;
case UIV_SUDAV:
aotg_clear_pendbits(USBIRQ_SUDAV,USBIRQ); /*clear sudav irq*/
handle_setup(udc);
break;
case UIV_EP0IN:
//从端点0 in 方向(板子->ubuntu)的数据 进入这里
aotg_writeb(EP0_IN_IRQ,IN07IRQ); /*clear ep0in irq*/
handle_ep0(udc);
break;
case UIV_EP0OUT:
//从端点0 out 方向(ubuntu->板子)的数据 进入这里
aotg_writeb(EP0_OUT_IRQ,OUT07IRQ); /*clear ep0out irq*/
handle_ep0(udc);
break;
default:
break;
}
return IRQ_HANDLED;
}
drivers/usb/am7x/am7x_udc.c
static void handle_ep0(struct aotg_udc *_udc)
{
struct aotg_udc * udc = _udc;
struct aotg_ep *ep0 = &udc->ep[0];
struct aotg_request *req;
switch (udc->ep0state) {
case EP0_IN_DATA_PHASE:
//从板子 经过ep0 in方向进入host ubuntu的数据到这里
if(req) {
if(write_ep0_fifo(ep0,req))
udc->ep0state = EP0_END_XFER;
}
break;
case EP0_END_XFER:
/*ACK*/
handle_status();
/*cleanup*/
udc->req_pending = 0;
udc->ep0state = EP0_WAIT_FOR_SETUP;
if(req) {
done(ep0, req, 0);
req = NULL;
}
break;
case EP0_OUT_DATA_PHASE:
//从ubuntu 经过ep0 out方向进入板子的数据到这里
break;
case EP0_STALL:
if(req) {
done(ep0,req,-ESHUTDOWN);
req = NULL;
}
break;
default:
DMSG_CTRL("@@@---ep0in irq error,odd state %d\n",udc->ep0state);
}
}
usb_ep_queue函数调用的是aotg_ep_queue(struct usb_ep *_ep, struct usb_request *_req,gfp_t gfp_flags)这个函数drivers/usb/am7x/am7x_udc.c
req->complete = f_audio_complete;
err = usb_ep_queue(out_ep,req, GFP_ATOMIC);
usb_ep_queue排队的req被发送出去后成功会调用f_audio_complete
static void handle_setup(struct aotg_udc *udc)
{
#if 1
// goto delegate when bRequestType is class
//goto delegate when bRequestType is not standard
/* USB_CDC_SEND_ENCAPSULATED_COMMAND */
if ((u.r.bRequestType == 0x21) && (u.r.bRequest == 0x00))
goto delegate;
/* USB_CDC_GET_ENCAPSULATED_RESPONSE */
if ((u.r.bRequestType == 0xa1) && (u.r.bRequest == 0x01))
goto delegate;
if ((u.r.bRequestType == 0x22) && (u.r.bRequest == 0x01))
goto delegate;
if ((u.r.bRequestType == 0xa1) && (u.r.bRequest == 0x83))
goto delegate;
if ((u.r.bRequestType == 0x21) && (u.r.bRequest == 0x01))
goto delegate;
//add by
if( u.r.bRequestType & (0x03 << 5)) //if bit 5 bit 6 is not all zero usb 2.0协议 class有关的(非标准的)bmRequestType 不是Standard的都goto delegate 交给audio.c和f_uac1.c来处理
goto delegate;
#endif
switch (u.r.bRequest) {
case USB_REQ_GET_STATUS:
if(reciptype == USB_RECIP_INTERFACE) {
}else if(reciptype == USB_RECIP_DEVICE) {
}else if(reciptype == USB_RECIP_ENDPOINT) {
}
case USB_REQ_CLEAR_FEATURE:
if((u.r.bRequestType == USB_RECIP_DEVICE) && (u.r.wValue == USB_DEVICE_REMOTE_WAKEUP)){
}
else if((u.r.bRequestType == USB_RECIP_ENDPOINT) && (u.r.wValue == USB_ENDPOINT_HALT)) {
}else {
//pr_notice("goto stall 3\n");
goto stall;}
/*ACK the status stage*/
handle_status();
return;
case USB_REQ_SET_FEATURE:
if((u.r.bRequestType == USB_RECIP_DEVICE)) {
}else if((u.r.bRequestType == USB_RECIP_ENDPOINT) && (u.r.wValue == USB_ENDPOINT_HALT)) {
}else
goto stall;
/*ACK the status stage*/
handle_status();
return;
case USB_REQ_SET_ADDRESS:
return;
/*delegate sub request to the upper gadget driver*/
case USB_REQ_SET_INTERFACE:
goto delegate;
case USB_REQ_SET_CONFIGURATION:
//DMSG_CTRL("@@@---USB_REQ_SET_CONFIGURATION\n");
if (u.r.bRequestType == USB_RECIP_DEVICE) {
}else
goto stall;
/*delegate to the upper gadget driver*/
break;
default:
/*delegate to the upper gadget driver*/
break;
}
/* gadget drivers see class/vendor specific requests,
* {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION},
* and more
* The gadget driver may return an error here,
* causing an immediate protocol stall.
*
* Else it must issue a response, either queueing a
* response buffer for the DATA stage, or halting ep0
* (causing a protocol stall, not a real halt). A
* zero length buffer means no DATA stage.
*
* It's fine to issue that response after the setup()
* call returns.
*/
delegate:
//DMSG_CTRL("@@@---delegate\n");
if (u.r.bRequestType & USB_DIR_IN)
udc->ep0state = EP0_IN_DATA_PHASE;
else
udc->ep0state = EP0_OUT_DATA_PHASE;
status = udc->driver->setup (&udc->gadget, &u.r); /*delegate*/ //此处setup为audio.c里面的audio_setup
if(status < 0) {
stall:
udc->ep0state = EP0_STALL;
}
return;
}
setcur endpoint=4-out CS=SAMPLING_FREQ_CONTROL
setup包 22 01 00 01 04 00 03 00 进来先走的handle_setup
aotg_udc_irq 函数里面有
case UIV_SUDAV:
aotg_clear_pendbits(USBIRQ_SUDAV,USBIRQ); /*clear sudav irq*/
handle_setup(udc);
break;
阅读(1131) | 评论(0) | 转发(0) |