/* destroy an USB endpoint */ void fhci_ep0_free(struct fhci_usb *usb) { struct endpoint *ep; int size; ep = usb->ep0; if (ep) { if (ep->td_base) cpm_muram_free(cpm_muram_offset(ep->td_base)); if (kfifo_initialized(&ep->conf_frame_Q)) { size = cq_howmany(&ep->conf_frame_Q); for (; size; size--) { struct packet *pkt = cq_get(&ep->conf_frame_Q); kfree(pkt); } cq_delete(&ep->conf_frame_Q); } if (kfifo_initialized(&ep->empty_frame_Q)) { size = cq_howmany(&ep->empty_frame_Q); for (; size; size--) { struct packet *pkt = cq_get(&ep->empty_frame_Q); kfree(pkt); } cq_delete(&ep->empty_frame_Q); } if (kfifo_initialized(&ep->dummy_packets_Q)) { size = cq_howmany(&ep->dummy_packets_Q); for (; size; size--) { u8 *buff = cq_get(&ep->dummy_packets_Q); kfree(buff); } cq_delete(&ep->dummy_packets_Q); } kfree(ep); usb->ep0 = NULL; } }
/* * Collect the submitted frames and inform the application about them * It is also preparing the TDs for new frames. If the Tx interrupts * are disabled, the application should call that routine to get * confirmation about the submitted frames. Otherwise, the routine is * called frome the interrupt service routine during the Tx interrupt. * In that case the application is informed by calling the application * specific 'fhci_transaction_confirm' routine */ static void fhci_td_transaction_confirm(struct fhci_usb *usb) { struct endpoint *ep = usb->ep0; struct packet *pkt; struct usb_td __iomem *td; u16 extra_data; u16 td_status; u16 td_length; u32 buf; /* * collect transmitted BDs from the chip. The routine clears all BDs * with R bit = 0 and the pointer to data buffer is not NULL, that is * BDs which point to the transmitted data buffer */ while (1) { td = ep->conf_td; td_status = in_be16(&td->status); td_length = in_be16(&td->length); buf = in_be32(&td->buf_ptr); extra_data = in_be16(&td->extra); /* check if the TD is empty */ if (!(!(td_status & TD_R) && ((td_status & ~TD_W) || buf))) break; /* check if it is a dummy buffer */ else if ((buf == DUMMY_BD_BUFFER) && !(td_status & ~TD_W)) break; /* mark TD as empty */ clrbits16(&td->status, ~TD_W); out_be16(&td->length, 0); out_be32(&td->buf_ptr, 0); out_be16(&td->extra, 0); /* advance the TD pointer */ ep->conf_td = next_bd(ep->td_base, ep->conf_td, td_status); /* check if it is a dummy buffer(type2) */ if ((buf == DUMMY2_BD_BUFFER) && !(td_status & ~TD_W)) continue; pkt = cq_get(&ep->conf_frame_Q); if (!pkt) fhci_err(usb->fhci, "no frame to confirm\n"); if (td_status & TD_ERRORS) { if (td_status & TD_RXER) { if (td_status & TD_CR) pkt->status = USB_TD_RX_ER_CRC; else if (td_status & TD_AB) pkt->status = USB_TD_RX_ER_BITSTUFF; else if (td_status & TD_OV) pkt->status = USB_TD_RX_ER_OVERUN; else if (td_status & TD_BOV) pkt->status = USB_TD_RX_DATA_OVERUN; else if (td_status & TD_NO) pkt->status = USB_TD_RX_ER_NONOCT; else fhci_err(usb->fhci, "illegal error " "occured\n"); } else if (td_status & TD_NAK) pkt->status = USB_TD_TX_ER_NAK; else if (td_status & TD_TO) pkt->status = USB_TD_TX_ER_TIMEOUT; else if (td_status & TD_UN) pkt->status = USB_TD_TX_ER_UNDERUN; else if (td_status & TD_STAL) pkt->status = USB_TD_TX_ER_STALL; else fhci_err(usb->fhci, "illegal error occured\n"); } else if ((extra_data & TD_TOK_IN) && pkt->len > td_length - CRC_SIZE) { pkt->status = USB_TD_RX_DATA_UNDERUN; } if (extra_data & TD_TOK_IN) pkt->len = td_length - CRC_SIZE; else if (pkt->info & PKT_ZLP) pkt->len = 0; else pkt->len = td_length; fhci_transaction_confirm(usb, pkt); } }
static void *get_empty_frame(struct fhci_usb *usb) { return cq_get(usb->ep0->empty_frame_Q); }