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

📄 itdptd.c

📁 usb isp1761驱动源代码 可编进内核。
💻 C
📖 第 1 页 / 共 3 页
字号:
/******************************************************************************
 * Philips ISP176x Isochronous Transfer support code file
 *
 * (c) 2002 Koninklijke Philips Electronics N.V. All rights reserved. <usb.linux@philips.com>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * File Name: itdptd.c
 * 
 *
 * History:     
 *
 * Date                 Author/Modified by      Comments
 * ------------------------------------------------------------------------------
 * Jan 16, 2006         Grant H.                  Initial version
 * Feb 6, 2006          Grant H.               First stable release
 *
 ********************************************************************************
 */

#ifdef CONFIG_ISO_SUPPORT

/*
 * phcd_iso_itd_to_ptd - convert an ITD into a PTD
 *
 * phci_hcd *hcd
 *      - Main host controller driver structure
 * struct ehci_itd *itd
 *  - Isochronous Transfer Descriptor, contains elements as defined by the
 *        EHCI standard plus a few more Philips specific elements.
 * struct urb *urb
 *  - USB Request Block, contains information regarding the type and how much data
 *    is requested to be transferred.
 * void  * ptd 
 *  - Points to the ISO ptd structure that needs to be initialized
 *
 * API Description
 * This is mainly responsible for:
 *  -Initializing the PTD that will be used for the ISO transfer
 */
void * phcd_iso_itd_to_ptd( phci_hcd *hcd,
        struct ehci_itd *itd,
        struct urb *urb,
        void  * ptd
        )
{
    struct _isp1761_isoptd *iso_ptd;
    struct isp1761_mem_addr *mem_addr;

    unsigned long max_packet, mult, length, td_info1, td_info3;
    unsigned long token, port_num, hub_num, data_addr;
    unsigned long frame_number;

    iso_dbg(ISO_DBG_ENTRY, "phcd_iso_itd_to_ptd entry\n");

    /* Variable initialization */
    iso_ptd = (struct _isp1761_isoptd *)ptd;
    mem_addr = &itd->mem_addr;

    /*
     * For both ISO and INT endpoints descriptors, new bit fields we added to
     * specify whether or not the endpoint supports high bandwidth, and if so
     * the number of additional packets that the endpoint can support during a 
     * single microframe.
     * Bits 12:11 specify whether the endpoint supports high-bandwidth transfers
     * Valid values:
     *             00 None (1 transaction/uFrame)
     *             01 1 additional transaction
     *             10 2 additional transactions
     *             11 reserved
     */
    max_packet = 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_packet >> 11) & 0x3);
    max_packet &= 0x7ff;

    /* This is the size of the request (bytes to write or bytes to read) */
    length = itd->length;

    /*
     * Set V bit to indicate that there is payload to be sent or received. And 
     * indicate that the current PTD is active.
     */
    td_info1 = QHA_VALID;

    /* 
     * Set the number of bytes that can be transferred by this PTD. This indicates
     * the depth of the data field.
     */
    td_info1 |= (length << 3);

    /*
     * Set the maximum packet length which indicates the maximum number of bytes that
     * can be sent to or received from the endpoint in a single data packet.
     */
    if (urb->dev->speed != USB_SPEED_HIGH)
    {
        /* 
         * According to the ISP1761 specs for sITDs, OUT token max packet should
         * not be more  than 188 bytes, while IN token max packet not more than
         * 192 bytes (ISP1761 Rev 3.01, Table 72, page 79
         */
        if(usb_pipein(urb->pipe) &&
                (max_packet > 192))
        {
            iso_dbg(ISO_DBG_INFO, "[phcd_iso_itd_to_ptd]: IN Max packet over maximum\n");
            max_packet = 192;                   
        }

        if((!usb_pipein(urb->pipe)) &&
                (max_packet > 188))
        {
            iso_dbg(ISO_DBG_INFO, "[phcd_iso_itd_to_ptd]: OUT Max packet over maximum\n");
            max_packet = 188;                   
        }
    }
    td_info1 |= (max_packet << 18);

    /*
     * Place the FIRST BIT of the endpoint number here.
     */
    td_info1 |= (usb_pipeendpoint(urb->pipe) << 31);

    /*
     * Set the number of successive packets the HC can submit to the endpoint.
     */
    if(urb->dev->speed == USB_SPEED_HIGH)
    {
        td_info1 |= MULTI(mult);
    }

    /* Set the first DWORD */
    iso_ptd->td_info1 = td_info1;
    iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD0 = 0x%08x\n", iso_ptd->td_info1);

    /*
     * Since the first bit have already been added on the first DWORD of the PTD         
     * we only need to add the last 3-bits of the endpoint number.
     */
    token = (usb_pipeendpoint(urb->pipe) & 0xE) >> 1;

    /*
     * Get the device address and set it accordingly to its assigned bits of the 2nd
     * DWORD.
     */
    token |= usb_pipedevice(urb->pipe) << 3;

    /* See a split transaction is needed */
    if(urb->dev->speed != USB_SPEED_HIGH)
    {
        /* 
         * If we are performing a SPLIT transaction indicate that it is so by setting
         * the S bit of the second DWORD.
         */             
        token |= 1 << 14;

        port_num = urb->dev->ttport;
        hub_num = urb->dev->tt->hub->devnum;

        /* Set the the port number of the hub or embedded TT */
        token |= port_num << 18;

        /* 
         * Set the hub address, this should be zero for the internal or
         * embedded hub
         */
        token |= hub_num << 25;
    } /* if(urb->dev->speed != USB_SPEED_HIGH) */

    /* 
     * Determine if the direction of this pipe is IN, if so set the Token bit of 
     * the second DWORD to indicate it as IN. Since it is initialized to zero and
     * zero indicates an OUT token, then we do not need anything to the Token bit
     * if it is an OUT token.
     */
    if(usb_pipein(urb->pipe))
        token |= (IN_PID << 10);

    /* Set endpoint type to Isochronous */
    token |= EPTYPE_ISO;

    /* Set the second DWORD */  
    iso_ptd->td_info2 = token;  
    iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD1 = 0x%08x\n", iso_ptd->td_info2);

    /*
     * Get the physical address of the memory location that was allocated for this PTD 
     * in the PAYLOAD region, using the formula indicated in sectin 7.2.2 of the ISP1761 specs
     * rev 3.01 page 17 to 18.
     */
    data_addr = ( (unsigned long) (mem_addr->phy_addr) & 0xffff ) - 0x400;
    data_addr >>= 3;

    /*  Set it to its location in the third DWORD */
    td_info3 = data_addr << 8;

    /*
     * Set the frame number when this PTD will be sent for ISO OUT or IN
     * Bits 0 to 2 are don't care, only bits 3 to 7.
     */
    frame_number = itd->framenumber;
    td_info3 |= (frame_number << 3);

    /* Set the third DWORD */
    iso_ptd->td_info3 = td_info3;
    iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD2 = 0x%08x\n", iso_ptd->td_info3);

    /* 
     * Set the A bit of the fourth DWORD to 1 to indicate that this PTD is active.
     * This have the same functionality with the V bit of DWORD0 
     */
    iso_ptd->td_info4 = QHA_ACTIVE;
    iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD3 = 0x%08x\n", iso_ptd->td_info4);

    /* Set the fourth DWORD to specify which uSOFs the start split needs to be placed */
    iso_ptd->td_info5 = itd->ssplit;
    iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD4 = 0x%08x\n", iso_ptd->td_info5);

    /* 
     * Set the fifth DWORD to specify which uSOFs the complete split needs to be sent.
     * This is VALID only for IN (since ISO transfers don't have handshake stages)
     */
    iso_ptd->td_info6 = itd->csplit;
    iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD5 = 0x%08x\n", iso_ptd->td_info6);

    iso_dbg(ISO_DBG_EXIT, "phcd_iso_itd_to_ptd exit\n");
    return iso_ptd;
}/* phcd_iso_itd_to_ptd */

/*
 * phcd_iso_scheduling_info - Initializing the start split and complete split.
 *
 * phci_hcd *hcd
 *      - Main host controller driver structure
 * struct ehci_qh *qhead
 *  - Contains information about the endpoint.
 * unsigned long max_pkt
 *  - Maximum packet size that the endpoint in capable of handling
 * unsigned long high_speed
 *  - Indicates if the bus is a high speed bus
 * unsigned long ep_in
 *  - Inidcates if the endpoint is an IN endpoint
 *
 * API Description
 * This is mainly responsible for:
 *  - Determining the number of start split needed during an OUT transaction or
 *    the number of complete splits needed during an IN transaction.
 */
unsigned long phcd_iso_scheduling_info( phci_hcd *hcd,
        struct ehci_qh *qhead,
        unsigned long max_pkt,
        unsigned long high_speed,
        unsigned long ep_in
        )
{
    unsigned long count, usof, temp;

    /* Local variable initialization */
    usof = 0x1;

    if(high_speed)
    {
        qhead->csplit = 0;

        /* Always send high speed transfers in first uframes */
        qhead->ssplit = 0x1;
        return 0;
    }

    /* Determine how many 188 byte-transfers are needed to send all data */
    count = max_pkt/188;

    /* 
     * Check is the data is not a factor of 188, if it is not then we need 
     * one more 188 transfer to move the last set of data less than 188.
     */
    if(max_pkt % 188)
        count += 1;

    /* 
     * Remember that usof was initialized to 0x1 so that means
     * that usof is always guranteed a value of 0x1 and then
     * depending on the maxp, other bits of usof will also be set.
     */
    for(temp = 0; temp < count; temp++)
        usof |= (0x1 << temp);

    if(ep_in)
    {
        /* 
         * Send start split into first frame.
         */     
        qhead->ssplit = 0x1;

⌨️ 快捷键说明

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