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

📄 pehci.c

📁 usb isp1761驱动源代码 可编进内核。
💻 C
📖 第 1 页 / 共 5 页
字号:
            td_ptd_map->ptd_ram_data_addr,
            qh
            /*td_ptd_map->datatoggle*/);

    if(qh->type == TD_PTD_BUFF_TYPE_INTL){
        phci_hcd_qhint_schedule(hcd, qh,qtd,(isp1761_qhint *)qha,qtd->urb);
    }


    length = PTD_XFERRED_LENGTH(qha->td_info1 >> 3);
    if(length > HC_ATL_PL_SIZE){
        err("Never Error: Bogus length,length %d(max %d)\n",(int)qtd->length, HC_ATL_PL_SIZE);
    }

    /*write qha into the header of the host controller*/
    isp1761_mem_write(hcd->dev, td_ptd_map->ptd_header_addr,0,(u32 *)(qha),PHCI_QHA_LENGTH,0);
    /*if this is SETUP/OUT token , then need to write into the buffer*/
    /*length should be valid*/
    if(qtd->length && ( length <= HC_ATL_PL_SIZE))
        switch(PTD_PID(qha->td_info2)){
            case OUT_PID:
            case SETUP_PID:
                isp1761_mem_write(hcd->dev, (u32)mem_addr->phy_addr, 0,(void*)(le32_to_cpu(qtd->hw_buf[0])),length,0);
                break;
        }

    /*qtd is scheduled*/
    qtd->state &= ~QTD_STATE_NEW;
    qtd->state |= QTD_STATE_SCHEDULED;

    pehci_entry("-- %s: Exit\n",__FUNCTION__);
    return;
}



static void 
pehci_hcd_urb_complete(phci_hcd *hcd,struct ehci_qh *qh, struct urb *urb, 
        td_ptd_map_t    *td_ptd_map)
{

    static u32 remove  = 0;
    urb_priv_t *urb_priv = (urb_priv_t *)urb->hcpriv;

    pehci_entry("++ %s: Entered\n",__FUNCTION__);
    pehci_check("complete the td , length: %d\n", td_ptd_map->qtd->length);
    urb_priv->timeout = 0;

    if((td_ptd_map->state == TD_PTD_REMOVE) ||
            (urb_priv->state == DELETE_URB)    ||
            !HCD_IS_RUNNING(hcd->state))
        remove = 1;

    qh->qh_state = QH_STATE_COMPLETING;
    /*remove the done tds*/
    spin_lock(&hcd_data_lock);
    phci_hcd_urb_free_priv(hcd, urb_priv,qh);
    spin_unlock(&hcd_data_lock);

    urb_priv->timeout = 0;
    kfree(urb_priv);
    urb->hcpriv = 0;


    /*if normal completion???*/
    if(urb->status == -EINPROGRESS)
        urb->status = 0;

    spin_unlock(&hcd->lock);
    usb_hcd_giveback_urb (&hcd->usb_hcd, urb);
    spin_lock(&hcd->lock);

    /*lets handle to the remove case*/
    if(remove){
        remove  = 0;
        if(list_empty(&qh->qtd_list)){
            pehci_check("no transfers anymore, free the endpoint\n");
            phci_hcd_release_td_ptd_index(qh);
        }
    }
    pehci_entry("-- %s: Exit\n",__FUNCTION__);
}

/*update the error status of the td*/
    static void
pehci_hcd_update_error_status(u32 ptdstatus,struct urb *urb)
{
    /*if ptd status is halted*/
    if(ptdstatus & PTD_STATUS_HALTED){
        if(ptdstatus & PTD_XACT_ERROR){
            /*transaction error results due to retry count goes to zero*/
            if(PTD_RETRY(ptdstatus)){
                /*halt the endpoint*/
                pehci_check("transaction error , retries %d\n", PTD_RETRY(ptdstatus));
                urb->status = -EPIPE;}
            else {
                pehci_check("transaction error , retries %d\n", PTD_RETRY(ptdstatus));
                /*protocol error*/
                urb->status = -EPROTO;}
        }
        else if(ptdstatus & PTD_BABBLE){
            pehci_check("babble error, qha %x\n", ptdstatus);
            /*babble error*/
            urb->status = -EOVERFLOW;}
        else if(PTD_RETRY(ptdstatus)){
            pehci_check("endpoint halted with retrie remaining %d\n",PTD_RETRY(ptdstatus));
            urb->status = -EPIPE;}
        else { /*unknown error, i will report it as halted, as i will never see xact error bit set*/
            pehci_check("protocol error, qha %x\n", ptdstatus);
            urb->status = -EPIPE;}

            /*if halted need to recover*/
            if (urb->status == -EPIPE) {
            }
    }
}

#ifdef CONFIG_ISO_SUPPORT /* New code for ISO support */

/*******************************************************************
 * phcd_iso_handler - ISOCHRONOUS Transfer handler
 *
 * phci_hcd *hcd,
 *      Host controller driver structure which contains almost all data
 *      needed by the host controller driver to process data and interact
 *      with the host controller.
 *
 * struct pt_regs *regs
 *
 * API Description
 * This is the ISOCHRONOUS Transfer handler, mainly responsible for:
 *  - Checking the periodic list if there are any ITDs for scheduling or 
 *    removal.
 *  - For ITD scheduling, converting an ITD into a PTD, which is the data 
 *    structure that the host contrtoller can understand and process.
 *  - For ITD completion, checking the transfer status and performing the 
 *    required actions depending on status.
 *  - Freeing up memory used by an ITDs once it is not needed anymore.
 ************************************************************************/
void phcd_iso_handler(phci_hcd *hcd)
{
    struct _isp1761_isoptd *iso_ptd;
    struct isp1761_mem_addr *mem_addr;
    struct ehci_itd *itd, *current_itd; 
    td_ptd_map_t *td_ptd_map;
    td_ptd_map_buff_t *ptd_map_buff;

    struct list_head *itd_sched, *itd_remove, *position, *lst_temp;     
    struct urb *urb;

    unsigned long buff_stat, skip_map;
    unsigned long last_map;
    unsigned long frame_num, rmv_frm_num, sched_frm_num;
    unsigned long uframe_cnt, usof_stat, length;
    unsigned char schedule, remove, last_td;

    /* Local variable initialization */                 
    buff_stat = 0;
    skip_map = 0;
    frame_num = 0;
    schedule = FALSE;
    remove = FALSE;     
    iso_ptd = &hcd->isotd;
    last_map = 0;

    /* Check if there are any ITDs scheduled  for processing */
    if( hcd->periodic_sched == 0 )
    {
        return;
    }

    ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL]);

    /* Read buffer status register to check later if the ISO buffer is filled or not */
    buff_stat = isp1761_reg_read32(hcd->dev, hcd->regs.buffer_status, buff_stat);

    /* Read the contents of the ISO skipmap register */
    skip_map = isp1761_reg_read32(hcd->dev, hcd->regs.isotdskipmap, skip_map);

    /* Read the contents of the ISO lastmap  register */
    last_map = isp1761_reg_read32(hcd->dev, hcd->regs.isotdlastmap, last_map);

    /* Get also the frame number, which we will use as index into the periodic frame list */
    frame_num = isp1761_reg_read32(hcd->dev, hcd->regs.frameindex, frame_num);

    /* Bits 0 to 2 are don't care, only bits 3 to 7 are used as index */
    frame_num &= 0xff;
    frame_num >>= 3;

    /* Get a copy of the current frame number to adjust it depending on what we will be processing */
    rmv_frm_num = frame_num;
    sched_frm_num = frame_num;

    /* For ITD removal, work on the ITD linked to the frame prior to the current frame */
    if(rmv_frm_num == 0)
        rmv_frm_num = 31;
    else
        rmv_frm_num = rmv_frm_num - 1;

    rmv_frm_num %= PTD_PERIODIC_SIZE;

    /* Process ITDs linked to this frame, checking for completed ITDs */
    itd_remove = &hcd->periodic_list[rmv_frm_num].itd_head;
    iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: Removal Frame number: %d\n", (int) rmv_frm_num);            

    /* For ITD scheduling, work on the ITD linked to the frame after the current frame */
    if(sched_frm_num == 31)
        sched_frm_num = 0;
    else
        sched_frm_num = sched_frm_num + 1;

    sched_frm_num %= PTD_PERIODIC_SIZE;

    /* Process ITDs linked to this frame, checking if there are any that needs to be scheduled */
    itd_sched = &hcd->periodic_list[sched_frm_num].itd_head;
    iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: Schedule Frame number: %d\n", (int) sched_frm_num);         

    /* Check if the ITD lists are empty */
    if( !list_empty(itd_sched))
    {
        iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: ISO schedule list not empty\n");          
        schedule = TRUE;
    }
    else
    {
        iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: ISO schedule list empty\n");              
    }

    if( !list_empty(itd_remove))
    {
        iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: ISO remove list not empty\n");            
        remove = TRUE;
    }
    else
    {
        iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: ISO remove list empty\n");                
    }

    if( schedule == TRUE )
    {
        iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: Something is scheduled\n");               
        /* There is an ITD to be scheduled, go over and check each ITD in this list */
        list_for_each(position, itd_sched)
        {
            /* Get an ITD in the list for processing */
            itd = list_entry(position, struct ehci_itd, itd_list);

            iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: ITD Index: %d\n", itd->itd_index);            
            /* Get the PTD allocated for this ITD. */                   
            td_ptd_map = &ptd_map_buff->map_list[itd->itd_index];
            memset(iso_ptd, 0, sizeof(struct _isp1761_isoptd));                 

            /* Create a PTD from an ITD*/
            phcd_iso_itd_to_ptd( hcd,
                    itd,
                    itd->urb,
                    (void *) iso_ptd
                    );

            /* Indicate that this ITD's PTD have been filled up */
            ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;

            /*
             * Place the newly initialized ISO PTD structure into the location allocated 
             * for this PTD in the ISO PTD memory region.
             */
            isp1761_mem_write( hcd->dev,
                    td_ptd_map->ptd_header_addr,
                    0,
                    (__u32 *) iso_ptd,
                    PHCI_QHA_LENGTH,
                    0
                    );

            /* 
             * Set this flag to avoid unlinking before schedule
             * at particular frame number
             */
            td_ptd_map->state = TD_PTD_IN_SCHEDULE;

            /* 
             * If the length is not zero and the direction is OUT then copy the
             * data to be transferred into the PAYLOAD memory area.
             */
            if(itd->length)
            {
                switch(PTD_PID(iso_ptd->td_info2)) 
                {
                    case OUT_PID:                                       
                        /* Get the Payload memory allocated for this PTD */
                        mem_addr = &itd->mem_addr;
                        isp1761_mem_write( hcd->dev,
                                (unsigned long )mem_addr->phy_addr,
                                0,
                                (__u32 *) (le32_to_cpu(itd->hw_bufp[0])),
                                itd->length,
                                0
                                );
                        break;
                } /* switch(PTD_PID(iso_ptd->td_info2)) */
            } /* if(itd->length) */

            /* If this is the last td, indicate to complete the URB */
            if(itd->hw_next == EHCI_LIST_END)
                td_ptd_map->lasttd = 1;

            /*
             * Clear the bit corresponding to this PTD in the skip map so that it will be
             * processed on the next schedule traversal.
             */
            skip_map &= ~td_ptd_map->ptd_bitmap;                

            iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: Skip Map: 0x%08x\n", (unsigned int) skip_map);
            isp1761_reg_write32(hcd->dev, hcd->regs.isotdskipmap, skip_map);

            /* 
             * Update the last map register to indicate that the newly created PTD is the 
             * last PTD added only if it is larger than the previous bitmap.
             */                 
            if(last_map < td_ptd_map->ptd_bitmap)
            {
                isp1761_reg_write32(hcd->dev, hcd->regs.isotdlastmap, td_ptd_map->ptd_bitmap);
                iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: Last Map: 0x%08x\n", td_ptd_map->ptd_bitmap);     
            }

            /*
             * Set the ISO_BUF_FILL bit to 1 to indicate that there is a PTD for ISO that needs to
             * be processed.
             */
            iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: Buffer Status: 0x%08x\n", (unsigned int) (buff_stat | ISO_BUFFER));
            isp1761_reg_write32(hcd->dev, hcd->regs.buffer_status, (buff_stat | ISO_BUFFER));
        } /* list_for_each(position, itd_sched) */      

        iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: ISO-Frame scheduling done\n");
    } /* if( schedule == TRUE ) */

    if( remove == TRUE)
    {
        iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: Something is for removal\n");             
        list_for_each_safe(position, lst_temp, itd_remove)
        {
            last_td = FALSE;

            /* Get an ITD in the list for processing */
            itd = list_entry(position, struct ehci_itd, itd_list);

            /* Get the PTD that was allocated for this particular ITD. */
            td_ptd_map = &ptd_map_buff->map_list[itd->itd_index];

            iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: ITD Index: %d\n", itd->itd_index);            
            urb = itd->urb;

⌨️ 快捷键说明

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