📄 itdptd.c
字号:
/*
* Inidicate that we can send a complete split starting from
* the third uFrame to how much complete split is needed to
* retrieve all data.
*
* Of course, the first uFrame is reserved for the start split, the
* second is reserved for the TT to send the request and get some
* data.
*/
qhead->csplit = (usof << 2);
} /* if(ep_in) */
else
{
/*
* For ISO OUT we don't need to send out a complete split
* since we do not require and data coming in to us (since ISO
* do not have integrity checking/handshake).
*
* For start split we indicate that we send a start split from the
* first uFrame up to the the last uFrame needed to retrieve all
* data
*/
qhead->ssplit = usof;
qhead->csplit = 0;
} /* else for if(ep_in) */
return 0;
}/* phcd_iso_scheduling_info */
/*
* phcd_iso_itd_fill - Allocate memory from the PAYLOAD memory region
*
* phci_hcd *pHcd_st
* - 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.
* unsigned long packets
* - Total number of packets to completely transfer this ISO transfer request.
*
* API Description
* This is mainly responsible for:
* - 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)
* - 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.
*/
unsigned long phcd_iso_itd_fill ( phci_hcd *hcd,
struct ehci_itd *itd,
struct urb *urb,
unsigned long packets
)
{
unsigned long length, offset, pipe;
unsigned long max_pkt, mult;
dma_addr_t buff_dma;
struct isp1761_mem_addr *mem_addr;
iso_dbg(ISO_DBG_ENTRY, "phcd_iso_itd_fill entry\n");
/*
* The value for both these variables are supplied by the one
* who submitted the URB.
*/
length = urb->iso_frame_desc[packets].length;
offset = urb->iso_frame_desc[packets].offset;
/* Initialize the status and actual length of this packet*/
urb->iso_frame_desc[packets].actual_length = 0;
urb->iso_frame_desc[packets].status = -EXDEV;
/* Buffer for this packet*/
buff_dma = cpu_to_le32((unsigned char *)urb->transfer_buffer + offset);
/* Memory for this packet*/
mem_addr = &itd->mem_addr;
pipe = urb->pipe;
max_pkt = usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe));
mult = 1 + ((max_pkt >> 11) & 0x3);
max_pkt = max_pkt & 0x7FF;
max_pkt *= mult;
if( (length < 0) || (max_pkt < length) )
{
iso_dbg(ISO_DBG_ERR,"[phcd_iso_itd_fill Error]: No available memory.\n");
return -ENOSPC;
}
itd->buf_dma = buff_dma;
/*
* Allocate memory in the PAYLOAD memory region for the
* data buffer for this ITD
*/
phci_hcd_mem_alloc(length, mem_addr, 0);
if( length && ( (mem_addr->phy_addr == 0 ) ||
(mem_addr->virt_addr == 0) ) )
{
mem_addr = 0;
iso_dbg(ISO_DBG_ERR, "[phcd_iso_itd_fill Error]: No payload memory available\n");
return -ENOMEM;
}
/* Length of this packet */
itd->length = length;
/* Number of transaction per uframe */
itd->multi = mult;
/* Buffer address, one ptd per packet */
itd->hw_bufp[0] = buff_dma;
iso_dbg(ISO_DBG_EXIT, "phcd_iso_itd_fill exit\n");
return 0;
} /* phcd_iso_itd_fill */
/*
* phcd_iso_get_itd_ptd_index - Allocate an ISO PTD from the ISO PTD map list
*
* 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.
*
* API Description
* This is mainly responsible for:
* - Allocating an ISO PTD from the ISO PTD map list
* - Set the equivalent bit of the allocated PTD to active
* in the bitmap so that this PTD will be included into
* the periodic schedule
*/
void phcd_iso_get_itd_ptd_index( phci_hcd *hcd, struct ehci_itd *itd )
{
td_ptd_map_buff_t *ptd_map_buff;
unsigned long buff_type, max_ptds;
unsigned char itd_index, bitmap;
/* Local variable initialization */
bitmap = 0x1;
buff_type = td_ptd_pipe_x_buff_type[TD_PTD_BUFF_TYPE_ISTL];
ptd_map_buff = (td_ptd_map_buff_t *) &(td_ptd_map_buff[buff_type]);
max_ptds = ptd_map_buff->max_ptds;
for(itd_index = 0; itd_index < max_ptds; itd_index++)
{
/*
* ISO have 32 PTDs, the first thing to do is look for a free PTD.
*/
if(ptd_map_buff->map_list[itd_index].state == TD_PTD_NEW)
{
/*
* Determine if this is a newly allocated ITD by checking the
* itd_index, since it was set to TD_PTD_INV_PTD_INDEX during
* initialization
*/
if( itd->itd_index == TD_PTD_INV_PTD_INDEX )
{
itd->itd_index = itd_index;
}
/* Once there is a free slot, indicate that it is already taken */
ptd_map_buff->map_list[itd_index].datatoggle = 0;
ptd_map_buff->map_list[itd_index].state = TD_PTD_ACTIVE;
ptd_map_buff->map_list[itd_index].qtd = NULL;
/* Put a connection to the ITD with the PTD maplist */
ptd_map_buff->map_list[itd_index].itd = itd;
ptd_map_buff->map_list[itd_index].qh = NULL;
/* ptd_bitmap just holds the bit assigned to this PTD. */
ptd_map_buff->map_list[itd_index].ptd_bitmap = bitmap << itd_index;
phci_hcd_fill_ptd_addresses(&ptd_map_buff->map_list[itd_index],
itd->itd_index, buff_type);
/*
* Indicate that this ITD is the last in the list and update
* the number of active PTDs
*/
ptd_map_buff->map_list[itd_index].lasttd = 0;
ptd_map_buff->total_ptds ++;
/* TO DO: This variable is not used from what I have seen. */
ptd_map_buff->active_ptd_bitmap |= (bitmap << itd_index);
break;
}/* if(ptd_map_buff->map_list[itd_index].state == TD_PTD_NEW) */
}/* for(itd_index = 0; itd_index < max_ptds; itd_index++) */
return;
}/* phcd_iso_get_itd_ptd_index */
/*
* phcd_iso_itd_free_list - Free memory used by ITDs in ITD list
*
* 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 contain the status of the
* ITD list.
*
* API Description
* This is mainly responsible for:
* - Cleaning up memory used by each ITD in the ITD list
*/
void phcd_iso_itd_free_list( phci_hcd *hcd,
struct urb *urb,
unsigned long status
)
{
td_ptd_map_buff_t *ptd_map_buff;
struct ehci_itd *first_itd, *next_itd, *itd;
td_ptd_map_t *td_ptd_map;
/* Local variable initialization */
ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL]);
first_itd = (struct ehci_itd *) urb->hcpriv;
itd = first_itd;
/*
* Check if there is only one ITD, if so immediately
* go and clean it up.
*/
if(itd->hw_next == EHCI_LIST_END)
{
if(itd->itd_index != TD_PTD_INV_PTD_INDEX)
{
td_ptd_map = &ptd_map_buff->map_list[itd->itd_index];
td_ptd_map->state = TD_PTD_NEW;
}
if(status != -ENOMEM)
phci_hcd_mem_free(&itd->mem_addr);
list_del (&itd->itd_list);
qha_free(qha_cache, itd);
urb->hcpriv = 0;
return;
} /* if(itd->hw_next == EHCI_LIST_END) */
while(1)
{
/* Get the ITD following the head ITD */
next_itd = (struct ehci_itd *) le32_to_cpu(itd->hw_next);
if(next_itd->hw_next == EHCI_LIST_END)
{
/*
* If the next ITD is the end of the list, check if space have
* already been allocated in the PTD array.
*/
if(next_itd->itd_index != TD_PTD_INV_PTD_INDEX)
{
/* Free up its allocation */
td_ptd_map = &ptd_map_buff->map_list[next_itd->itd_index];
td_ptd_map->state = TD_PTD_NEW;
}
/*
* If the error is not about memory allocation problems, then
* free up the memory used.
*/
if(status != -ENOMEM)
{
iso_dbg(ISO_DBG_ERR,"[phcd_iso_itd_free_list Error]: Memory not available\n");
phci_hcd_mem_free(&next_itd->mem_addr);
}
/* Remove from the ITD list and free up space allocated for ITD structure */
list_del (&next_itd->itd_list);
qha_free(qha_cache, next_itd);
break;
} /* if(next_itd->hw_next == EHCI_LIST_END)*/
/*
* If ITD is not the end of the list, it only means that it already have everything allocated
* and there is no need to check which procedure failed. So just free all resourcs immediately
*/
itd->hw_next = next_itd->hw_next;
td_ptd_map = &ptd_map_buff->map_list[next_itd->itd_index];
td_ptd_map->state = TD_PTD_NEW;
phci_hcd_mem_free(&next_itd->mem_addr);
list_del (&next_itd->itd_list);
qha_free(qha_cache, next_itd);
} /* while(1) */
/* Now work on the head ITD, it is the last one processed. */
if(first_itd->itd_index != TD_PTD_INV_PTD_INDEX)
{
td_ptd_map = &ptd_map_buff->map_list[first_itd->itd_index];
td_ptd_map->state = TD_PTD_NEW;
}
if(status != -ENOMEM)
{
iso_dbg(ISO_DBG_ERR,"[phcd_iso_itd_free_list Error]: No memory\n");
phci_hcd_mem_free(&first_itd->mem_addr);
}
list_del (&first_itd->itd_list);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -