/* SETUP starts a new control request. Devices are not allowed to * STALL or NAK these; they must cancel any pending control requests. */ static void setup_packet( struct sl811 *sl811, struct sl811h_ep *ep, struct urb *urb, u8 bank, u8 control ) { u8 addr; u8 len; void __iomem *data_reg; addr = SL811HS_PACKET_BUF(bank == 0); len = sizeof(struct usb_ctrlrequest); data_reg = sl811->data_reg; sl811_write_buf(sl811, addr, urb->setup_packet, len); /* autoincrementing */ sl811_write(sl811, bank + SL11H_BUFADDRREG, addr); writeb(len, data_reg); writeb(SL_SETUP /* | ep->epnum */, data_reg); writeb(usb_pipedevice(urb->pipe), data_reg); /* always OUT/data0 */ ; sl811_write(sl811, bank + SL11H_HOSTCTLREG, control | SL11H_HCTLMASK_OUT); ep->length = 0; PACKET("SETUP qh%p\n", ep); }
/* OUT packets can be used with any type of endpoint. * urb->iso_frame_desc is currently ignored here... */ static void out_packet( struct sl811 *sl811, struct sl811h_ep *ep, struct urb *urb, u8 bank, u8 control ) { void *buf; u8 addr; u8 len; void __iomem *data_reg; buf = urb->transfer_buffer + urb->actual_length; prefetch(buf); len = min((int)ep->maxpacket, urb->transfer_buffer_length - urb->actual_length); if (!(control & SL11H_HCTLMASK_ISOCH) && usb_gettoggle(urb->dev, ep->epnum, 1)) control |= SL11H_HCTLMASK_TOGGLE; addr = SL811HS_PACKET_BUF(bank == 0); data_reg = sl811->data_reg; sl811_write_buf(sl811, addr, buf, len); /* autoincrementing */ sl811_write(sl811, bank + SL11H_BUFADDRREG, addr); writeb(len, data_reg); writeb(SL_OUT | ep->epnum, data_reg); writeb(usb_pipedevice(urb->pipe), data_reg); sl811_write(sl811, bank + SL11H_HOSTCTLREG, control | SL11H_HCTLMASK_OUT); ep->length = len; PACKET("OUT%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "", !!usb_gettoggle(urb->dev, ep->epnum, 1), ep, len); }
static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len) { __u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE; __u16 status = 0; int err = 0, time_start = get_timer(0); int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) && (dev->speed == USB_SPEED_LOW); if (len > 239) return -1; if (usb_pipeout(pipe)) ctrl |= SL811_USB_CTRL_DIR_OUT; if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) ctrl |= SL811_USB_CTRL_TOGGLE_1; if (need_preamble) ctrl |= SL811_USB_CTRL_PREAMBLE; sl811_write(SL811_INTRSTS, 0xff); while (err < 3) { sl811_write(SL811_ADDR_A, 0x10); sl811_write(SL811_LEN_A, len); if (usb_pipeout(pipe) && len) sl811_write_buf(0x10, buffer, len); if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) && sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble)) ctrl |= SL811_USB_CTRL_SOF; else ctrl &= ~SL811_USB_CTRL_SOF; sl811_write(SL811_CTRL_A, ctrl); while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) { if (5*CONFIG_SYS_HZ < get_timer(time_start)) { printf("USB transmit timed out\n"); return -USB_ST_CRC_ERR; } } sl811_write(SL811_INTRSTS, 0xff); status = sl811_read(SL811_STS_A); if (status & SL811_USB_STS_ACK) { int remainder = sl811_read(SL811_CNT_A); if (remainder) { PDEBUG(0, "usb transfer remainder = %d\n", remainder); len -= remainder; } if (usb_pipein(pipe) && len) sl811_read_buf(0x10, buffer, len); return len; } if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK) continue; PDEBUG(0, "usb transfer error %#x\n", (int)status); err++; } err = 0; if (status & SL811_USB_STS_ERROR) err |= USB_ST_BUF_ERR; if (status & SL811_USB_STS_TIMEOUT) err |= USB_ST_CRC_ERR; if (status & SL811_USB_STS_STALL) err |= USB_ST_STALLED; return -err; }