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

📄 qtdptd.c

📁 usb isp1761驱动源代码 可编进内核。
💻 C
📖 第 1 页 / 共 3 页
字号:
            td_ptd_map->ptd_header_addr, td_ptd_map->ptd_data_addr,
            td_ptd_map->ptd_ram_data_addr);
    pehci_entry("-- %s: Exit",__FUNCTION__);
    return payloadlocation;
}


/*--------------------------------------------------------------*
 * calculate the header location for the current
 * endpoint, if found returns a valid index
 * else invalid
 -----------------------------------------------------------*/
static void     
phci_hcd_get_qtd_ptd_index(struct ehci_qh *qh,
        struct ehci_qtd *qtd,
        struct ehci_itd *itd) 
{

    u8  buff_type = td_ptd_pipe_x_buff_type[qh->type];
    u8  qtd_ptd_index;/*, index;*/
    /*this is the location of the ptd's skip map/done map, also
      calculating the td header, payload, data start address 
      location*/        
    u8  bitmap = 0x1;
    u8  max_ptds;

    td_ptd_map_buff_t   *ptd_map_buff = &(td_ptd_map_buff[buff_type]);
    pehci_entry("++ %s, Entered, buffer type %d\n",__FUNCTION__, buff_type);

    /* ATL PTDs can wait */
    max_ptds = (buff_type == TD_PTD_BUFF_TYPE_ATL) 
        ? TD_PTD_MAX_BUFF_TDS : ptd_map_buff->max_ptds;

    for(qtd_ptd_index = 0; qtd_ptd_index < max_ptds; qtd_ptd_index++) {                 /* Find the first free slot */
        if(ptd_map_buff->map_list[qtd_ptd_index].state == TD_PTD_NEW) {
            /* Found a free slot */
            if( qh->qtd_ptd_index == TD_PTD_INV_PTD_INDEX ) {
                qh->qtd_ptd_index = qtd_ptd_index;
            }
            ptd_map_buff->map_list[qtd_ptd_index].datatoggle = 0;
            /*put the ptd_index into operational state*/
            ptd_map_buff->map_list[qtd_ptd_index].state = TD_PTD_ACTIVE;
            ptd_map_buff->map_list[qtd_ptd_index].qtd = qtd;
            /* No td transfer is in progress */
            ptd_map_buff->map_list[qtd_ptd_index].itd  = itd;
            /*initialize endpoint(queuehead)*/
            ptd_map_buff->map_list[qtd_ptd_index].qh = qh;
            ptd_map_buff->map_list[qtd_ptd_index].ptd_bitmap = 
                bitmap << qtd_ptd_index;
            phci_hcd_fill_ptd_addresses(&ptd_map_buff->map_list[qtd_ptd_index],qh->qtd_ptd_index,buff_type); 
            ptd_map_buff->map_list[qtd_ptd_index].lasttd = 0;
            ptd_map_buff->total_ptds ++;        /* update # of total td's */
            /*make the queuehead map, to process in the phci_schedule_ptds*/
            ptd_map_buff->active_ptd_bitmap |= (bitmap << qtd_ptd_index);
            break;
        }
    }
    pehci_entry("-- %s, Exit\n", __FUNCTION__);
    return;

} /* phci_get_td_ptd_index */



/* 
 * calculate the header location for the endpoint and
 * all tds on this endpoint will use the same
 * header location for all transfers on this endpoint.
 * also puts the endpoint into the linked state
 * */
    static void 
phci_hcd_qh_link_async (phci_hcd *hcd, struct ehci_qh *qh, int *status)
{
    struct ehci_qtd *qtd = 0;
    struct list_head *qtd_list = &qh->qtd_list;

    td_ptd_map_buff_t       *ptd_map_buff;
    td_ptd_map_t            *td_ptd_map;

    /*  take the first td, in case we are not able to schedule the new td
        and this is going for remove
     */
    qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);

    pehci_entry("++ %s: Entered\n", __FUNCTION__);

    /* Assign a td-ptd index for this ed so that we can put ptd's in the HC buffers */

    qh->qtd_ptd_index = TD_PTD_INV_PTD_INDEX;
    phci_hcd_get_qtd_ptd_index(qh, qtd, NULL);  /* Get a td-ptd index */
    if(qh->qtd_ptd_index ==  TD_PTD_INV_PTD_INDEX){
        err("can not find the location in our buffer\n");
        *status = -ENOSPC;
        return;
    }


#ifdef MSEC_INT_BASED
    /*first transfers in sof interrupt goes into pending*/
    ptd_map_buff = &(td_ptd_map_buff[qh->type]);
    td_ptd_map = &ptd_map_buff->map_list[qh->qtd_ptd_index];
    ptd_map_buff->pending_ptd_bitmap |= td_ptd_map->ptd_bitmap;

#endif
    /* open the halt so that it acessed */
    qh->hw_token &= ~__constant_cpu_to_le32 (QTD_STS_HALT);
    qh->qh_state = QH_STATE_LINKED;
    qh->qh_state |= QH_STATE_TAKE_NEXT;
    pehci_entry("-- %s: Exit , qh %p\n", __FUNCTION__, qh);


}

/*-------------------------------------------------------------------------*/

/* 
 * mainly used for setting up current td on current 
 * endpoint(queuehead), endpoint may be new or
 * halted one
 * */

    static inline void
phci_hcd_qh_update (phci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
{
    /*make this current td*/
    qh->hw_current = QTD_NEXT (qtd->qtd_dma);
    qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
    qh->hw_alt_next = EHCI_LIST_END;
    /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
    wmb (); 
    qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
}

/*
 * used for ATL, INT transfers  
 * function creates new endpoint, 
 * calculates bandwidth for interrupt transfers,
 * and initialize the qh based on endpoint type/speed
 * */
struct ehci_qh *
phci_hcd_make_qh (
        phci_hcd                *hcd,
        struct urb              *urb,
        struct list_head *qtd_list,
        int *status) 
{
    struct ehci_qh              *qh = 0;
    u32                 info1 = 0, info2 = 0;
    int                 is_input, type;
    int                 maxp = 0;
    int mult = 0;
    int bustime = 0;
    struct ehci_qtd *qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);


    pehci_entry("++ %s: Entered\n",__FUNCTION__);   

    qh = phci_hcd_qh_alloc (hcd);
    if (!qh){
        *status  = -ENOMEM;
        return 0;
    }

    /*
     * init endpoint/device data for this QH
     */
    info1 |= usb_pipeendpoint(urb->pipe) << 8;
    info1 |= usb_pipedevice(urb->pipe) << 0;

    is_input = usb_pipein(urb->pipe);
    type = usb_pipetype (urb->pipe);
    maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);
    mult = 1 + ((maxp >> 11) & 0x3);

    /*set this queueheads index to invalid*/
    qh->qtd_ptd_index = TD_PTD_INV_PTD_INDEX;

    switch(type){
        case PIPE_CONTROL:
        case PIPE_BULK:
            qh->type = TD_PTD_BUFF_TYPE_ATL;
            break;

        case PIPE_INTERRUPT:
            qh->type = TD_PTD_BUFF_TYPE_INTL;
            break;
        case PIPE_ISOCHRONOUS:
            qh->type = TD_PTD_BUFF_TYPE_ISTL;
            break;

    }



    if (type == PIPE_INTERRUPT) {
        /*for this interrupt transfer check how much bustime in usecs required*/

        bustime = usb_check_bandwidth(urb->dev, urb);

        if(bustime < 0){
            *status  = -ENOSPC; 
            goto done;
        }

        usb_claim_bandwidth(urb->dev,urb,bustime,usb_pipeisoc(urb->pipe));

        qh->usecs = bustime;

        qh->start = NO_FRAME;

        if (urb->dev->speed == USB_SPEED_HIGH) {
            qh->c_usecs = 0;
            qh->gap_uf = 0;
            /*after how many uframes this interrupt is to be executed*/
            qh->period = urb->interval >> 3;
            if (qh->period < 1) {
                printk("intr period %d uframes,\n",
                        urb->interval);
            }
            /*restore the original urb->interval in qh->period*/
            qh->period = urb->interval;

        } else {
            /* gap is f(FS/LS transfer times) */
            qh->gap_uf = 1 + 7;/*usb_calc_bus_time (urb->dev->speed,
                                 is_input, 0, maxp) / (125 * 1000);*/

            if (is_input) {             /* SPLIT, gap, CSPLIT+DATA */

                qh->c_usecs = qh->usecs + 1;/*HS_USECS (0);*/
                qh->usecs = 10;/*HS_USECS (1);*/
            } else {            /* SPLIT+DATA, gap, CSPLIT */
                qh->usecs += 10;/*HS_USECS (1);*/
                qh->c_usecs = 1;/*HS_USECS (0);*/
            }


            /*take the period ss/cs scheduling will be
              handled by submit urb
             */
            qh->period = urb->interval;
        }
    }

    /* using TT? */
    switch (urb->dev->speed) {
        case USB_SPEED_LOW:
            info1 |= (1 << 12); /* EPS "low" */
            /* FALL THROUGH */

        case USB_SPEED_FULL:
            /* EPS 0 means "full" */
            if (type != PIPE_INTERRUPT)
                info1 |= (EHCI_TUNE_RL_TT << 28);
            if (type == PIPE_CONTROL) {
                info1 |= (1 << 27);     /* for TT */
                info1 |= 1 << 14;       /* toggle from qtd */
            }
            info1 |= maxp << 16;

            info2 |= (EHCI_TUNE_MULT_TT << 30);
            info2 |= urb->dev->ttport << 23;
            info2 |= urb->dev->tt->hub->devnum << 16;
            break;


        case USB_SPEED_HIGH:            /* no TT involved */
            info1 |= (2 << 12); /* EPS "high" */
            if (type == PIPE_CONTROL) {
                info1 |= (EHCI_TUNE_RL_HS << 28);
                info1 |= 64 << 16;      /* usb2 fixed maxpacket */

                info1 |= 1 << 14;       /* toggle from qtd */
                info2 |= (EHCI_TUNE_MULT_HS << 30);
            } else if (type == PIPE_BULK) {
                info1 |= (EHCI_TUNE_RL_HS << 28);
                info1 |= 512 << 16;     /* usb2 fixed maxpacket */
                info2 |= (EHCI_TUNE_MULT_HS << 30);
            } else {            /* PIPE_INTERRUPT */
                info1 |= (maxp & 0x7ff)/*max_packet (maxp)*/ << 16;
                info2 |= mult/*hb_mult (maxp)*/ << 30;
            }
            break;

        default:
            pehci_print("bogus dev %p speed %d", urb->dev, urb->dev->speed);
done:
            qha_free(qha_cache, qh);
            return 0;
    }/*end of switch*/

    /* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */

    /* init as halted, toggle clear, advance to dummy */
    qh->qh_state = QH_STATE_IDLE;
    qh->hw_info1 = cpu_to_le32 (info1);
    qh->hw_info2 = cpu_to_le32 (info2);
    /*link the tds here*/
    list_splice(qtd_list, &qh->qtd_list);
    phci_hcd_qh_update (hcd, qh, qtd);
    qh->hw_token = cpu_to_le32 (QTD_STS_HALT);
    if(!usb_pipecontrol(urb->pipe))
        usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
    pehci_entry("-- %s: Exit, qh %p\n",__FUNCTION__,qh);   
    return qh;
}


/*-----------------------------------------------------------*/
/*
 * Hardware maintains data toggle (like OHCI) ... here we (re)initialize
 * the hardware data toggle in the QH, and set the pseudo-toggle in udev
 * so we can see if usb_clear_halt() was called.  NOP for control, since
 * we set up qh->hw_info1 to always use the QTD toggle bits. 
 */
    static inline void
phci_hcd_clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
{
    pehci_print("clear toggle, dev %d ep 0x%x-%s\n",
            udev->devnum, ep, is_out ? "out" : "in");
    qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
    usb_settoggle (udev, ep, is_out, 1);
}

/*-------------------------------------------------------------------------*/

/*
 * For control/bulk/interrupt, return QH with these TDs appended.
 * Allocates and initializes the QH if necessary.
 * Returns null if it can't allocate a QH it needs to.
 * If the QH has TDs (urbs) already, that's great.
 */
struct ehci_qh * 
phci_hcd_qh_append_tds (
        phci_hcd                *hcd, 
	struct usb_host_endpoint *ep,
        struct urb              *urb,
        struct list_head        *qtd_list,
        void                    **ptr,
        int               *status
        )
{
    int epnum;
    struct ehci_qh              *qh = 0;
    struct ehci_qtd *qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
    td_ptd_map_buff_t   *ptd_map_buff;
    td_ptd_map_t                *td_ptd_map;



    pehci_entry("++ %s: Entered\n",__FUNCTION__);   

    epnum = ep->desc.bEndpointAddress;
    qh = (struct ehci_qh *) *ptr;
    if(likely(qh != 0)){
        u32     hw_next = QTD_NEXT (qtd->qtd_dma);
        pehci_print("%Queue head already %p\n",qh);

        ptd_map_buff = &(td_ptd_map_buff[qh->type]);
        td_ptd_map = &ptd_map_buff->map_list[qh->qtd_ptd_index];

        /* maybe patch the qh used for set_address */
        if (unlikely (epnum == 0
                    && le32_to_cpu (qh->hw_info1 & 0x7f) == 0))
            qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe));

        /* is an URB is queued to this qh already? */
        if (unlikely (!list_empty (&qh->qtd_list))) {
            struct ehci_qtd             *last_qtd;
            /* update the last qtd's "next" pointer */
            last_qtd = list_entry (qh->qtd_list.prev,
                    struct ehci_qtd, qtd_list);

            /*queue head is not empty just add the
              td at the end of it , and return from here
             */  
            last_qtd->hw_next = hw_next;

            /*set the status as positive*/
            *status = (u32)QUEUE_HEAD_NOT_EMPTY;

            /* no URB queued */
        } else {

            if(td_ptd_map->state == TD_PTD_NEW){
                qh->qh_state = QH_STATE_IDLE;
            }
            td_ptd_map->qtd = qtd;      
            /* usb_clear_halt() means qh data toggle gets reset */
            if (usb_pipebulk (urb->pipe)
                    && unlikely (!usb_gettoggle (urb->dev,
                            (epnum & 0x0f),
                            !(epnum & 0x10)))) {

                phci_hcd_clear_toggle(urb->dev,
                        epnum & 0x0f, !(epnum & 0x10), qh);

                /*reset our data toggle*/
                td_ptd_map->datatoggle = 0;
                qh->datatoggle = 0;
                qh->ping = 0;

            }
            phci_hcd_qh_update (hcd,qh, qtd);
        }
        /*put everything in pedning, will be cleared during scheduling*/
        ptd_map_buff->pending_ptd_bitmap |= td_ptd_map->ptd_bitmap;
        list_splice (qtd_list, qh->qtd_list.prev);
    }else{
        qh = phci_hcd_make_qh(hcd, urb, qtd_list, status);
        *ptr = qh;
    }
    pehci_entry("-- %s: Exit qh %p\n",__FUNCTION__,qh);   
    return qh;
}

/*link qtds to endpoint(qh)*/
struct ehci_qh * 

⌨️ 快捷键说明

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