/* These are needed for handling the toggle bits: *anurbcanbedequeuedwhileatdisinprogress *aftercheckingthetd,thetogglebitmightneedto
* be fixed */ struct c67x00_ep_data *ep_data; unsignedint pipe;
};
struct c67x00_urb_priv { struct list_head hep_node; struct urb *urb; int port; int cnt; /* packet number for isoc */ int status; struct c67x00_ep_data *ep_data;
};
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
c67x00->urb_iso_count--; if (c67x00->urb_iso_count == 0)
c67x00->max_frame_bw = MAX_FRAME_BW_STD;
}
/* TODO this might be not so efficient when we've got many urbs! *Alternatives: **onlyclearwhenneeded **keepalistoftdswitheachurbp
*/
list_for_each_entry(td, &c67x00->td_list, td_list) if (urb == td->urb)
td->urb = NULL;
/* hold a reference to udev as long as this endpoint lives,
* this is needed to possibly fix the data toggle */
ep_data->dev = usb_get_dev(urb->dev);
hep->hcpriv = ep_data;
/* For ISOC and INT endpoints, start ASAP: */
ep_data->next_frame = frame_add(c67x00->current_frame, 1);
/* Add the endpoint data to one of the pipe lists; must be added
in order of endpoint address */
type = usb_pipetype(urb->pipe); if (list_empty(&ep_data->node)) {
list_add(&ep_data->node, &c67x00->list[type]);
} else { struct c67x00_ep_data *prev;
if (!list_empty(&ep->urb_list))
dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n");
spin_lock_irqsave(&c67x00->lock, flags);
/* loop waiting for all transfers in the endpoint queue to complete */ while (c67x00_ep_data_free(ep)) { /* Drop the lock so we can sleep waiting for the hardware */
spin_unlock_irqrestore(&c67x00->lock, flags);
/* it could happen that we reinitialize this completion, while *somebodywaswaitingforthatcompletion.Thetimeoutand
* while loop handle such cases, but this might be improved */
reinit_completion(&c67x00->endpoint_disable);
c67x00_sched_kick(c67x00);
wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ);
switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL:
urb->interval = SETUP_STAGE; break; case PIPE_INTERRUPT: break; case PIPE_BULK: break; case PIPE_ISOCHRONOUS: if (c67x00->urb_iso_count == 0)
c67x00->max_frame_bw = MAX_FRAME_BW_ISO;
c67x00->urb_iso_count++; /* Assume always URB_ISO_ASAP, FIXME */ if (list_empty(&urbp->ep_data->queue))
urb->start_frame = urbp->ep_data->next_frame; else { /* Go right after the last one */ struct urb *last_urb;
staticint c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb, int len, int periodic)
{ struct c67x00_urb_priv *urbp = urb->hcpriv; int bit_time;
/* According to the C67x00 BIOS user manual, page 3-18,19, the *followingcalculationsprovidethefullspeedbittimesfor *atransaction. * *FS(in)=112.5+9.36*BC+HOST_DELAY *FS(in,iso)=90.5+9.36*BC+HOST_DELAY *FS(out)=112.5+9.36*BC+HOST_DELAY *FS(out,iso)=78.4+9.36*BC+HOST_DELAY *LS(in)=802.4+75.78*BC+HOST_DELAY *LS(out)=802.6+74.67*BC+HOST_DELAY * *HOST_DELAY==106forthec67200andc67300.
*/
/* make calculations in 1/100 bit times to maintain resolution */ if (urbp->ep_data->dev->speed == USB_SPEED_LOW) { /* Low speed pipe */ if (usb_pipein(urb->pipe))
bit_time = 80240 + 7578*len; else
bit_time = 80260 + 7467*len;
} else { /* FS pipes */ if (usb_pipeisoc(urb->pipe))
bit_time = usb_pipein(urb->pipe) ? 9050 : 7840; else
bit_time = 11250;
bit_time += 936*len;
}
/* Scale back down to integer bit times. Use a host delay of 106.
* (this is the only place it is used) */
bit_time = ((bit_time+50) / 100) + 106;
if (unlikely(bit_time + c67x00->bandwidth_allocated >=
c67x00->max_frame_bw)) return -EMSGSIZE;
if (unlikely(c67x00->next_td_addr + CY_TD_SIZE >=
c67x00->td_base_addr + SIE_TD_SIZE)) return -EMSGSIZE;
if (unlikely(c67x00->next_buf_addr + len >=
c67x00->buf_base_addr + SIE_TD_BUF_SIZE)) return -EMSGSIZE;
if (periodic) { if (unlikely(bit_time + c67x00->periodic_bw_allocated >=
MAX_PERIODIC_BW(c67x00->max_frame_bw))) return -EMSGSIZE;
c67x00->periodic_bw_allocated += bit_time;
}
if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe)
|| usb_pipeint(urb->pipe))) return -EMSGSIZE; /* Not really an error, but expected */
td = kzalloc(sizeof(*td), GFP_ATOMIC); if (!td) return -ENOMEM;
staticint c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
{ int remaining; int toggle; int pid; int ret = 0; int maxps; int need_empty;
staticvoid c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type, int (*add)(struct c67x00_hcd *, struct urb *))
{ struct c67x00_ep_data *ep_data; struct urb *urb;
/* traverse every endpoint on the list */
list_for_each_entry(ep_data, &c67x00->list[type], node) { if (!list_empty(&ep_data->queue)) { /* and add the first urb */ /* isochronous transfer rely on this */
urb = list_entry(ep_data->queue.next, struct c67x00_urb_priv,
hep_node)->urb;
add(c67x00, urb);
}
}
}
/* Check if we can proceed */ if (!list_empty(&c67x00->td_list)) {
dev_warn(c67x00_hcd_dev(c67x00), "TD list not empty! This should not happen!\n");
list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) {
dbg_td(c67x00, td, "Unprocessed td");
c67x00_release_td(td);
}
}
/* Remove all td's from the list which come *afterlast_tdandaremeantforthesamepipe.
* This is used when a short packet has occurred */ staticinlinevoid c67x00_clear_pipe(struct c67x00_hcd *c67x00, struct c67x00_td *last_td)
{ struct c67x00_td *td, *tmp;
td = last_td;
tmp = last_td; while (td->td_list.next != &c67x00->td_list) {
td = list_entry(td->td_list.next, struct c67x00_td, td_list); if (td->pipe == last_td->pipe) {
c67x00_release_td(td);
td = tmp;
}
tmp = td;
}
}
/* When an error occurs, all td's for that pipe go into an *inactivestate.Thisstatematchessuccessfultransfersso
* we must make sure not to service them. */ if (td->status & TD_ERROR_MASK) {
c67x00_giveback_urb(c67x00, urb,
c67x00_td_to_error(c67x00, td)); goto cont;
}
if ((td->status & TD_STATUSMASK_NAK) || !td_sequence_ok(td) ||
!td_acked(td)) goto cont;
/* Sequence ok and acked, don't need to fix toggle */
ack_ok = 1;
if (unlikely(td->status & TD_STATUSMASK_OVF)) { if (td_residue(td) & TD_RESIDUE_OVERFLOW) { /* Overflow */
c67x00_giveback_urb(c67x00, urb, -EOVERFLOW); goto cont;
}
}
cont: if (clear_endpoint)
c67x00_clear_pipe(c67x00, td); if (ack_ok)
usb_settoggle(td_udev(td), usb_pipeendpoint(td->pipe),
usb_pipeout(td->pipe),
!(td->ctrl_reg & SEQ_SEL)); /* next in list could have been removed, due to clear_pipe! */
tmp = list_entry(td->td_list.next, typeof(*td), td_list);
c67x00_release_td(td);
}
}
staticinlineint c67x00_all_tds_processed(struct c67x00_hcd *c67x00)
{ /* If all tds are processed, we can check the previous frame (if *therewasany)andstartournextframe.
*/ return !c67x00_ll_husb_get_current_td(c67x00->sie);
}
/* *SendtdtoC67X00
*/ staticvoid c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
{ int len = td_length(td);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.