📄 itdptd.c
字号:
/******************************************************************************
* 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 + -