Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1183217
  • 博文数量: 221
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2139
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(221)

文章存档

2024年(6)

2023年(8)

2022年(2)

2021年(2)

2020年(29)

2019年(11)

2018年(23)

2017年(41)

2016年(76)

2015年(23)

我的朋友
最近访客

分类: LINUX

2020-09-04 20:14:25

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) |
给主人留下些什么吧!~~