/* confirm submitted packet */ void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt) { struct td *td; struct packet *td_pkt; struct ed *ed; u32 trans_len; bool td_done = false; td = fhci_remove_td_from_frame(usb->actual_frame); td_pkt = td->pkt; trans_len = pkt->len; td->status = pkt->status; if (td->type == FHCI_TA_IN && td_pkt->info & PKT_DUMMY_PACKET) { if ((td->data + td->actual_len) && trans_len) memcpy(td->data + td->actual_len, pkt->data, trans_len); cq_put(usb->ep0->dummy_packets_Q, pkt->data); } recycle_frame(usb, pkt); ed = td->ed; if (ed->mode == FHCI_TF_ISO) { if (ed->td_list.next->next != &ed->td_list) { struct td *td_next = list_entry(ed->td_list.next->next, struct td, node); td_next->start_frame = usb->actual_frame->frame_num; } td->actual_len = trans_len; td_done = true; } else if ((td->status & USB_TD_ERROR) &&
static void recycle_frame(struct fhci_usb *usb, struct packet *pkt) { pkt->data = NULL; pkt->len = 0; pkt->status = USB_TD_OK; pkt->info = 0; pkt->priv_data = NULL; cq_put(usb->ep0->empty_frame_Q, pkt); }
/* * Submitting a data frame to a specified endpoint of a USB device * The frame is put in the driver's transmit queue for this endpoint * * Arguments: * usb A pointer to the USB structure * pkt A pointer to the user frame structure * trans_type Transaction tyep - IN,OUT or SETUP * dest_addr Device address - 0~127 * dest_ep Endpoint number of the device - 0~16 * trans_mode Pipe type - ISO,Interrupt,bulk or control * dest_speed USB speed - Low speed or FULL speed * data_toggle Data sequence toggle - 0 or 1 */ u32 fhci_host_transaction(struct fhci_usb *usb, struct packet *pkt, enum fhci_ta_type trans_type, u8 dest_addr, u8 dest_ep, enum fhci_tf_mode trans_mode, enum fhci_speed dest_speed, u8 data_toggle) { struct endpoint *ep = usb->ep0; struct usb_td __iomem *td; u16 extra_data; u16 td_status; fhci_usb_disable_interrupt(usb); /* start from the next BD that should be filled */ td = ep->empty_td; td_status = in_be16(&td->status); if (td_status & TD_R && in_be16(&td->length)) { /* if the TD is not free */ fhci_usb_enable_interrupt(usb); return -1; } /* get the next TD in the ring */ ep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status); fhci_usb_enable_interrupt(usb); pkt->priv_data = td; out_be32(&td->buf_ptr, virt_to_phys(pkt->data)); /* sets up transaction parameters - addr,endp,dir,and type */ extra_data = (dest_ep << TD_ENDP_SHIFT) | dest_addr; switch (trans_type) { case FHCI_TA_IN: extra_data |= TD_TOK_IN; break; case FHCI_TA_OUT: extra_data |= TD_TOK_OUT; break; case FHCI_TA_SETUP: extra_data |= TD_TOK_SETUP; break; } if (trans_mode == FHCI_TF_ISO) extra_data |= TD_ISO; out_be16(&td->extra, extra_data); /* sets up the buffer descriptor */ td_status = ((td_status & TD_W) | TD_R | TD_L | TD_I | TD_CNF); if (!(pkt->info & PKT_NO_CRC)) td_status |= TD_TC; switch (trans_type) { case FHCI_TA_IN: if (data_toggle) pkt->info |= PKT_PID_DATA1; else pkt->info |= PKT_PID_DATA0; break; default: if (data_toggle) { td_status |= TD_PID_DATA1; pkt->info |= PKT_PID_DATA1; } else { td_status |= TD_PID_DATA0; pkt->info |= PKT_PID_DATA0; } break; } if ((dest_speed == FHCI_LOW_SPEED) && (usb->port_status == FHCI_PORT_FULL)) td_status |= TD_LSP; out_be16(&td->status, td_status); /* set up buffer length */ if (trans_type == FHCI_TA_IN) out_be16(&td->length, pkt->len + CRC_SIZE); else out_be16(&td->length, pkt->len); /* put the frame to the confirmation queue */ cq_put(&ep->conf_frame_Q, pkt); if (cq_howmany(&ep->conf_frame_Q) == 1) out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO); return 0; }
/* * create the endpoint structure * * arguments: * usb A pointer to the data structure of the USB * data_mem The data memory partition(BUS) * ring_len TD ring length */ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, u32 ring_len) { struct endpoint *ep; struct usb_td __iomem *td; unsigned long ep_offset; char *err_for = "enpoint PRAM"; int ep_mem_size; u32 i; /* we need at least 3 TDs in the ring */ if (!(ring_len > 2)) { fhci_err(usb->fhci, "illegal TD ring length parameters\n"); return -EINVAL; } ep = kzalloc(sizeof(*ep), GFP_KERNEL); if (!ep) return -ENOMEM; ep_mem_size = ring_len * sizeof(*td) + sizeof(struct fhci_ep_pram); ep_offset = cpm_muram_alloc(ep_mem_size, 32); if (IS_ERR_VALUE(ep_offset)) goto err; ep->td_base = cpm_muram_addr(ep_offset); /* zero all queue pointers */ if (cq_new(&ep->conf_frame_Q, ring_len + 2) || cq_new(&ep->empty_frame_Q, ring_len + 2) || cq_new(&ep->dummy_packets_Q, ring_len + 2)) { err_for = "frame_queues"; goto err; } for (i = 0; i < (ring_len + 1); i++) { struct packet *pkt; u8 *buff; pkt = kmalloc(sizeof(*pkt), GFP_KERNEL); if (!pkt) { err_for = "frame"; goto err; } buff = kmalloc(1028 * sizeof(*buff), GFP_KERNEL); if (!buff) { kfree(pkt); err_for = "buffer"; goto err; } cq_put(&ep->empty_frame_Q, pkt); cq_put(&ep->dummy_packets_Q, buff); } /* we put the endpoint parameter RAM right behind the TD ring */ ep->ep_pram_ptr = (void __iomem *)ep->td_base + sizeof(*td) * ring_len; ep->conf_td = ep->td_base; ep->empty_td = ep->td_base; ep->already_pushed_dummy_bd = false; /* initialize tds */ td = ep->td_base; for (i = 0; i < ring_len; i++) { out_be32(&td->buf_ptr, 0); out_be16(&td->status, 0); out_be16(&td->length, 0); out_be16(&td->extra, 0); td++; } td--; out_be16(&td->status, TD_W); /* for last TD set Wrap bit */ out_be16(&td->length, 0); /* endpoint structure has been created */ usb->ep0 = ep; return 0; err: fhci_ep0_free(usb); kfree(ep); fhci_err(usb->fhci, "no memory for the %s\n", err_for); return -ENOMEM; }