⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pehci.c

📁 ISP 1761 usb host driver for linux
💻 C
📖 第 1 页 / 共 5 页
字号:
    u32 usofstatus = 0;
    struct urb *urb;
    struct ehci_qtd *qtd = 0;
    struct ehci_qh *qh = 0;
#ifdef LINUX_269    
    struct _isp1761_qhint *qhint = hcd->qhint;
#else
    struct _isp1761_qhint *qhint = &hcd->qhint;
#endif
    td_ptd_map_t                *td_ptd_map;
    td_ptd_map_buff_t   *ptd_map_buff;
    struct isp1761_mem_addr *mem_addr = 0;
    u32 dontschedule = 0;       

    ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_INTL]);
    pendingmap = ptd_map_buff->pending_ptd_bitmap;

    /*read the done map for interrupt transfers*/
    donetoclear = donemap = isp1761_reg_read32(hcd->dev, hcd->regs.inttddonemap,donemap);
    if(donemap){
        /*skip done tds*/
        skipmap = isp1761_reg_read32(hcd->dev, hcd->regs.inttdskipmap, skipmap);
        skipmap |= donemap;
        isp1761_reg_write32(hcd->dev, hcd->regs.inttdskipmap, skipmap);
        donemap |=      pendingmap;
    }
    /*if sof interrupt is enabled*/
#ifdef MSEC_INT_BASED
    else{
        /*if there is something pending , put this transfer in*/
        if(ptd_map_buff->pending_ptd_bitmap){
            pehci_hcd_schedule_pending_ptds(hcd,pendingmap,(u8)TD_PTD_BUFF_TYPE_INTL,1);
        }
        return;
    }
#else
    else{
        return;
    }

#endif


    ormask = isp1761_reg_read32(hcd->dev, hcd->regs.int_irq_mask_or, ormask);
    /*process all the endpoints first those are done*/
    donetoclear = donemap;
    while(donetoclear){
        /*index is the number of endpoints open currently*/
        index = donetoclear & mask;
        donetoclear &= ~mask;
        mask <<= 1;
        /*what if we are in the middle of schedule
          where nothing is done*/
        if(!index ){
            location++;
            continue;
        }

        /*read our td_ptd_map*/
        td_ptd_map = &ptd_map_buff->map_list[location];

        /*if this one is already in the removal*/
        if(td_ptd_map->state == TD_PTD_REMOVE ||
                td_ptd_map->state ==  TD_PTD_NEW){
            pehci_check("interrupt td is being removed\n");
            /*this will be handled by urb_remove*/
            /*if this is last urb no need to complete it again*/
            donemap &= ~td_ptd_map->ptd_bitmap;
            /*if there is something pending*/
            ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
            continue;
        }


        /*if we found something already in*/
        if(!(skipmap & td_ptd_map->ptd_bitmap)){
            pehci_check("intr td_ptd_map %x,skipnap %x\n",
                    td_ptd_map->ptd_bitmap,skipmap);
            donemap &= ~td_ptd_map->ptd_bitmap;
            /*in case pending*/
            ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap; ;
            location++;
            continue;
        }


        if(td_ptd_map->state ==  TD_PTD_NEW){
            pehci_check("interrupt not come here, map %x,location %d\n", td_ptd_map->ptd_bitmap,location);
            donemap &= ~td_ptd_map->ptd_bitmap;
            /*in case pending*/
            ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
            donemap &= ~td_ptd_map->ptd_bitmap;
            location++;
            continue;
        }

        /*move to the next schedule*/
        location ++;
        /*endpoint, td, urb and memory
         * for current transfer*/
        qh = td_ptd_map->qh;
        qtd = td_ptd_map->qtd;
        if(qtd->state & QTD_STATE_NEW){
            /*we need to schedule it*/
            goto schedule;
        }
        urb = qtd->urb;
        mem_addr = &qtd->mem_addr;

        /*clear the irq mask for this transfer*/
        ormask &= ~td_ptd_map->ptd_bitmap;
        isp1761_reg_write32(hcd->dev, hcd->regs.int_irq_mask_or, ormask);

        ptd_map_buff->active_ptds--;
        memset(qhint, 0, sizeof(struct _isp1761_qhint));

        /*read this ptd from the ram address,address is in the
          td_ptd_map->ptd_header_addr*/
        isp1761_mem_read(hcd->dev, td_ptd_map->ptd_header_addr,0,(u32 *)(qhint),PHCI_QHA_LENGTH,0);

        /*statuc of 8 uframes*/
        for(i=0;i<8;i++){
            /*take care of errors*/
            usofstatus = qhint->td_info5 >> (8 + i * 3);
            switch(usofstatus & 0x7){
                case INT_UNDERRUN:
                    pehci_print("under run , %x\n", usofstatus);
                    break;
                case INT_EXACT:
                    pehci_print("transaction error, %x\n", usofstatus);
                    break;
                case INT_BABBLE:
                    pehci_print("babble error, %x\n", usofstatus);
                    break;
            }
        }

        if(urb->dev->speed != USB_SPEED_HIGH)
            /*length is 1K for full/low speed device*/
            length = PTD_XFERRED_NONHSLENGTH(qhint->td_info4);
        else
            /*length is 32K for high speed device*/
            length = PTD_XFERRED_LENGTH(qhint->td_info4);

        pehci_hcd_update_error_status(qhint->td_info4, urb);
        /*halted, need to finish all the transfer on this endpoint*/
        if(qhint->td_info4 & PTD_STATUS_HALTED){
            //td_ptd_map->lasttd = 1;
            qtd->state |= QTD_STATE_LAST;
            /*in case of halt, next transfer will start with toggle zero,
             *USB speck, 5.8.5*/
            qh->datatoggle = td_ptd_map->datatoggle = 0;
            donemap &= ~td_ptd_map->ptd_bitmap;
            ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
            dontschedule = 1;
            goto copylength;
        }


copylength:
        /*preserve the current data toggle*/
        qh->datatoggle = td_ptd_map->datatoggle = PTD_NEXTTOGGLE(qhint->td_info4);
        /*copy data from the host*/
        switch(PTD_PID(qhint->td_info2)){
            case IN_PID:
                if(length && (length <= MAX_PTD_BUFFER_SIZE))
                    /*do read only when there is somedata*/
	#ifdef LINUX_269                
                    isp1761_mem_read(hcd->dev,(u32)mem_addr->phy_addr,0,(le32_to_cpu(qtd->hw_buf[0])),length,0);
	#else
	                isp1761_mem_read(hcd->dev,(u32)mem_addr->phy_addr,0,(void*)(le32_to_cpu(qtd->hw_buf[0])),length,0);
	#endif
            case OUT_PID:
                urb->actual_length += length;
                qh->hw_current = qtd->hw_next;
                phci_hcd_mem_free(&qtd->mem_addr);
                qtd->state &= ~QTD_STATE_NEW;
                qtd->state |= QTD_STATE_DONE;
                break;
        }

        if(qtd->state & QTD_STATE_LAST){
            pehci_hcd_urb_complete(hcd,qh,urb,td_ptd_map,regs);
            if(dontschedule){ /*cleanup will start from drivers*/
                dontschedule = 0;
                continue;
            }

            /*take the next if in the queue*/
            if(!list_empty(&qh->qtd_list)){
                struct list_head *head;
                /*last td of previous urb*/
                head = &qh->qtd_list;
                qtd = list_entry(head->next,struct ehci_qtd, qtd_list);
                td_ptd_map->qtd = qtd;
                qh->hw_current = cpu_to_le32(qtd);
                qh->qh_state = QH_STATE_LINKED;

            }else{
                td_ptd_map->qtd = (struct ehci_qtd *) le32_to_cpu(0);
                qh->hw_current = cpu_to_le32(0);
                qh->qh_state = QH_STATE_TAKE_NEXT;
                donemap &= ~td_ptd_map->ptd_bitmap;
                ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
                continue;
            }

        }

schedule:    
        {
            /*current td comes from qh->hw_current*/    
            ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
            ormask |= td_ptd_map->ptd_bitmap;
            ptd_map_buff->active_ptds++;
            pehci_check("inter schedule next qtd %p, active tds %d\n", qtd,ptd_map_buff->active_ptds);
            pehci_hcd_qtd_schedule(hcd,qtd,qh,td_ptd_map);
        }        

    } /*end of while*/


    /*clear all the tds inside this routine*/
    skipmap &= ~donemap;
    isp1761_reg_write32(hcd->dev, hcd->regs.inttdskipmap, skipmap);
    ormask |= donemap;
    isp1761_reg_write32(hcd->dev, hcd->regs.int_irq_mask_or,ormask);
}

/*atl(bulk/control) transfer handler*/
/*1. read done map
  2. read the ptd to see any errors
  3. copy the payload to and from
  4. update ehci td
  5. make new ptd if transfer there and earlier done
  6. schedule
 */
    static void
pehci_hcd_atl_worker(phci_hcd *hcd,struct pt_regs *regs)
{
    u32 donemap = 0, donetoclear=0;
    u32 pendingmap = 0;
    u32 rl = 0; 
    u32 mask = 0x1,index = 0;
    u32 location = 0;
    u32 nakcount = 0;
    u32 active = 0;
    u32 length = 0;
    u32 skipmap = 0;
    u32 tempskipmap = 0;        
    u32 ormask=0;
    struct urb *urb;
    struct ehci_qtd *qtd = 0;
    struct ehci_qh *qh;
    struct _isp1761_qha   atlqha;
    struct _isp1761_qha *qha;
    td_ptd_map_t       *td_ptd_map;
    td_ptd_map_buff_t   *ptd_map_buff;
    urb_priv_t          *urbpriv = 0;   
    struct isp1761_mem_addr *mem_addr = 0;
    u32 dontschedule = 0;       

    ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ATL]);
    pendingmap = ptd_map_buff->pending_ptd_bitmap;

#ifdef MSEC_INT_BASED
    /*running on skipmap rather donemap,
      some cases donemap may not be set 
      for complete transfer
     */                 
    skipmap = isp1761_reg_read32(hcd->dev, hcd->regs.atltdskipmap, skipmap);
    tempskipmap = ~skipmap;
    if(tempskipmap){
        donemap = isp1761_reg_read32(hcd->dev, hcd->regs.atltddonemap,donemap);
        skipmap |= donemap;
        isp1761_reg_write32(hcd->dev, hcd->regs.atltdskipmap, skipmap);
        qha = &atlqha;
        donemap |= pendingmap;
        tempskipmap &= ~donemap;
    }

    /*if sof interrupt enabled*/
    else{
        /*if there is something pending , put this transfer in*/
        if(pendingmap){
            pehci_hcd_schedule_pending_ptds(hcd,pendingmap,(u8)TD_PTD_BUFF_TYPE_ATL,1);
        }
        return;
    }
#else

    donemap = isp1761_reg_read32(hcd->dev, hcd->regs.atltddonemap,donemap);
    if(donemap){
        skipmap = isp1761_reg_read32(hcd->dev, hcd->regs.atltdskipmap, skipmap);
        skipmap |= donemap;
        isp1761_reg_write32(hcd->dev, hcd->regs.atltdskipmap, skipmap);
        qha = &atlqha;
    }
    else{
        return;

    }
#endif

    /*read the interrupt mask registers*/
    ormask = isp1761_reg_read32(hcd->dev, hcd->regs.atl_irq_mask_or, ormask);


    /*this map is used only to update and
     * scheduling for the tds who are not
     * complete. the tds those are complete
     * new schedule will happen from
     * td_ptd_submit_urb routine
     * */
    donetoclear = donemap;
    /*we will be processing skipped tds also*/
    donetoclear |= tempskipmap; 
    /*process all the endpoints first those are done*/
    while(donetoclear){
        /*index is the number of endpoint open currently*/
        index = donetoclear & mask;
        donetoclear &= ~mask;
        mask <<= 1;
        /*what if we are in the middle of schedule
          where nothing is done
         */
        if(!index ){
            location++;
            continue;
        }

        /*read our td_ptd_map*/
        td_ptd_map = &ptd_map_buff->map_list[location];

        /*urb is in remove*/
        if(td_ptd_map->state == TD_PTD_NEW ||
                td_ptd_map->state ==  TD_PTD_REMOVE){
            pehci_check("atl td is being removed,map %x, skipmap %x\n", td_ptd_map->ptd_bitmap, skipmap);
            pehci_check("temp skipmap %x, pendign map %x,done %x\n",tempskipmap, pendingmap,donemap);

            /*unlink urb will take care of this*/
            donemap &= ~td_ptd_map->ptd_bitmap;
            /*in case pending*/
            ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
            location++;
            continue;
        }


        /*move to the next endpoint*/
        loca

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -