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

📄 itdptd.c

📁 usb isp1761驱动源代码 可编进内核。
💻 C
📖 第 1 页 / 共 3 页
字号:
    qha_free(qha_cache, first_itd);
    urb->hcpriv = 0;
    return;
}/* phcd_iso_itd_free_list */

/*
 * phcd_submit_iso - ISO transfer URB submit routine
 *
 * phci_hcd *hcd
 *      - Main host controller driver structure
 * struct urb *urb
 *  - USB Request Block, contains information regarding the type and how much data
 *    is requested to be transferred.
 * unsigned long *status
 *  - Variable provided by the calling routine that will contain the status of the 
 *        phcd_submit_iso actions
 *
 * API Description
 * This is mainly responsible for:
 *  - Allocating memory for the endpoint information structure (pQHead_st)
 *  - Requesting for bus bandwidth from the USB core
 *  - Allocating and initializing Payload and PTD memory
 */
unsigned long phcd_submit_iso( phci_hcd *hcd,
	struct usb_host_endpoint *ep,
        struct urb *urb,
        unsigned long *status
        )
{
    struct _periodic_list *periodic_list;
    struct hcd_dev *dev;
    struct ehci_qh *qhead;
    struct ehci_itd *itd, *prev_itd;
    struct list_head *itd_list;

    unsigned long ep_in, max_pkt, mult;
    unsigned long bus_time, high_speed, start_frame;
    unsigned long flags, packets;

    iso_dbg(ISO_DBG_ENTRY, "phcd_submit_iso Entry\n");

    /* Local variable initialization */
    high_speed = 0;
    periodic_list = &hcd->periodic_list[0];
    dev = (struct hcd_dev *) bus_to_hcd(urb->dev->bus);
    urb->hcpriv = (void *) 0;
    prev_itd = (struct ehci_itd *) 0;
    itd = (struct ehci_itd *) 0;
    start_frame = 0;

    ep_in = usb_pipein(urb->pipe);

    /* 
     * Take the endpoint, if there is still no memory allocated
     * for it allocate some and indicate this is for ISO.
     */
    qhead  = ep->hcpriv;
    if(!qhead)
    {
        /* 
         * TO DO: Check who free this up, I did not observed this
         * freed up 
         */
        qhead = phci_hcd_qh_alloc(hcd);
        if(qhead == 0)
        {
            iso_dbg(ISO_DBG_ERR,"[phcd_submit_iso Error]: Not enough memory\n");
            return -ENOMEM;
        }
        qhead->type = TD_PTD_BUFF_TYPE_ISTL;
        ep->hcpriv = qhead;
    } /* if(!qhead) */

    /* 
     * Get the number of additional packets that the endpoint can support during a 
     * single microframe.
     */
    max_pkt = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); 

    /* 
     * We need to add 1 since our Multi starts with 1 instead of the USB specs defined
     * zero (0).
     */
    mult  = 1 + ((max_pkt >> 11) & 0x3);

    /* This is the actual length per for the whole transaction */
    max_pkt *= mult;

    /* Check bandwidth */
    bus_time= 0;

    if(urb->dev->speed == USB_SPEED_FULL)
    {
        if(urb->bandwidth == 0)
        {                       
            bus_time = usb_check_bandwidth(urb->dev, urb);
            if(bus_time < 0)
            {                           
                usb_dec_dev_use(urb->dev);
                *status = bus_time;
                return *status;
            }
        }
    } /*if(urb->dev->speed == USB_SPEED_FULL)  */   
    else /*HIGH SPEED*/
    {
        high_speed = 1;

        /* 
         * Calculate bustime as dictated by the USB Specs Section 5.11.3 
         * for high speed ISO
         */
        bus_time = 633232L;
        bus_time +=   (2083L * ((3167L + BitTime(max_pkt) * 1000L)/1000L));
        bus_time = bus_time/1000L;
        bus_time += BW_HOST_DELAY;
        bus_time = NS_TO_US(bus_time);
    }

    usb_claim_bandwidth(urb->dev, urb, bus_time, 1);

    /* Initialize the start split (ssplit) and complete split (csplit) variables of qhead */
    if( phcd_iso_scheduling_info(hcd, qhead, max_pkt, high_speed, ep_in) < 0 )
    {
        iso_dbg(ISO_DBG_ERR, "[phcd_submit_iso Error]: No space available\n");
        return -ENOSPC;
    }

    if(urb->iso_frame_desc[0].offset != 0)
    {
        *status = -EINVAL;
        iso_dbg(ISO_DBG_ERR, "[phcd_submit_iso Error]: Invalid value\n");
        return *status;
    }

    if(qhead->next_uframe == -1 ||
            hcd->periodic_sched == 0)
    {   
        /* Calculate the current frame number */
        if(urb->transfer_flags & URB_ISO_ASAP)
            start_frame = isp1761_reg_read32( hcd->dev,
                    hcd->regs.frameindex, 
                    start_frame
                    );
        else
            start_frame = urb->start_frame;

        INIT_LIST_HEAD(&hcd->urb_list);

        /* The only valid bits of the frame index is the lower 14 bits. */
        start_frame = start_frame & 0xFF;

        /* 
         * Remove the count for the micro frame (uSOF) and just leave the 
         * count for the frame (SOF). Since 1 SOF is equal to 8 uSOF then
         * shift right by three is like dividing it by 8 (each shift is divide by two)
         */ 
        start_frame >>= 3;

        start_frame += 2;                           
        qhead->next_uframe = start_frame + urb->number_of_packets;

    } /* if(qhead->next_uframe == -1 || hcd->periodic_sched == 0) */
    else
    {
        /* 
         * The periodic frame list size is only 32 elements deep, so we need 
         * the frame index to be less than or equal to 32 (actually 31 if we 
         * start from 0) 
         */
        start_frame = (qhead->next_uframe) % PTD_PERIODIC_SIZE;
        qhead->next_uframe = start_frame + urb->number_of_packets;
        qhead->next_uframe %= PTD_PERIODIC_SIZE;
    }

    spin_lock_irqsave(&hcd->lock, flags);
    iso_dbg(ISO_DBG_DATA,"[phcd_submit_iso]: Number of packets: %d\n", urb->number_of_packets);
    iso_dbg(ISO_DBG_DATA,"[phcd_submit_iso]: Packet Length: %d\n",
            urb->iso_frame_desc[0].length);
    iso_dbg(ISO_DBG_DATA,"[phcd_submit_iso]: Max packet: %d\n", (int) max_pkt);

    /* Make as many tds as number of packets */
    for(packets = 0; packets < urb->number_of_packets; packets++)
    {
        /* 
         * Allocate memory for the ITD data structure and initialize it.
         *
         * This data structure follows the format of the ITD
         * structure defined by the EHCI standard on the top part
         * but also contains Philips specific elements in the bottom
         * part
         */
        itd = (struct ehci_itd *) kmalloc(sizeof(struct ehci_itd), GFP_ATOMIC);
        if(!itd)
        {
            *status = -ENOMEM;

            /* Handle ITD list cleanup */
            if(urb->hcpriv)
            {
                phcd_iso_itd_free_list(hcd, urb, *status);
            }
            iso_dbg(ISO_DBG_ERR,"[phcd_submit_iso Error]: No memory available\n");
            return *status;
        }

        memset(itd, 0, sizeof(struct ehci_itd));

        INIT_LIST_HEAD(&itd->itd_list);

        itd->itd_dma = cpu_to_le32(itd);
        itd->urb = urb;

        /* 
         * Indicate that this ITD is the last in the list.
         *
         * Also set the itd_index to TD_PTD_INV_PTD_INDEX 
         * (0xFFFFFFFF). This would indicate when we allocate
         * a PTD that this ITD did not have a PTD allocated
         * before.
         */

        itd->hw_next = EHCI_LIST_END;
        itd->itd_index = TD_PTD_INV_PTD_INDEX;

        /* This ITD will go into this frame*/
        itd->framenumber = start_frame + packets;

        /* Number of the packet*/
        itd->index = packets;

        itd->framenumber = itd->framenumber % PTD_PERIODIC_SIZE;
        itd->ssplit = qhead->ssplit;
        itd->csplit = qhead->csplit;

        /* Initialize the following elements of the ITS structure
         *      > itd->length = length;                 -- the size of the request
         *      > itd->multi = multi;                   -- the number of transactions for 
         *                                         this EP per micro frame
         *      > itd->hw_bufp[0] = buf_dma;    -- The base address of the buffer where 
         *                                         to put the data (this base address was
         *                                         the buffer provided plus the offset)
         * And then, allocating memory from the PAYLOAD memory area, where the data 
         * coming from the requesting party will be placed or data requested by the 
         * requesting party will be retrieved when it is available.
         */
        *status  = phcd_iso_itd_fill(hcd, itd, urb, packets);

        if(*status !=0)
        {
            /* Handle ITD list cleanup */
            if(urb->hcpriv)
            {
                phcd_iso_itd_free_list(hcd, urb, *status);
            }
            iso_dbg(ISO_DBG_ERR,"[phcd_submit_iso Error]: Error in filling up ITD\n");
            return *status;
        }

        /* 
         * If this ITD is not the head/root ITD, link this ITD to the ITD 
         * that came before it.
         */
        if(prev_itd)
            prev_itd->hw_next = cpu_to_le32(itd);

        prev_itd = itd;

        /*               
         * Allocate an ISO PTD from the ISO PTD map list and
         * set the equivalent bit of the allocated PTD to active
         * in the bitmap so that this PTD will be included into
         * the periodic schedule
         */
        phcd_iso_get_itd_ptd_index(hcd, itd);

        /*if we dont have any space left*/
        if(itd->itd_index == TD_PTD_INV_PTD_INDEX)
        {
            *status  =  -ENOSPC;

            /* Handle ITD list cleanup */
            if(urb->hcpriv)
            {
                phcd_iso_itd_free_list(hcd, urb, *status);
            }
            return *status;                     
        }

        /* Insert this td into the periodic list*/
        periodic_list[itd->framenumber].framenumber = itd->framenumber;
        itd_list = &periodic_list[itd->framenumber].itd_head;
        list_add_tail(&itd->itd_list, itd_list);

        /* Inidcate that a new ITD have been scheduled */
        hcd->periodic_sched++;

        /* Determine if there are any ITD scheduled before this one. */
        if(urb->hcpriv == 0)
            urb->hcpriv = itd;
    }/* for(packets = 0; packets... */

    spin_unlock_irqrestore(&hcd->lock, flags);   

    /* Last td of current transaction*/
    itd->hw_next = EHCI_LIST_END;
    urb->error_count = 0;
    return *status;
} /* phcd_submit_iso */
#endif /* CONFIG_ISO_SUPPORT */

⌨️ 快捷键说明

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