X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fsl811_usb.c;h=b0cdf0bc2c77d270c63ec9e9c18940b2736290da;hb=592391a6e5c8999e546671ac8efd71a311a03f07;hp=a18e54d775c00c0bdc92e5c1b65695598a8af76c;hpb=5cf91d6bdc3e60bd43f9ba1bbb97a43ee49b2b2d;p=oweals%2Fu-boot.git diff --git a/drivers/sl811_usb.c b/drivers/sl811_usb.c index a18e54d775..b0cdf0bc2c 100644 --- a/drivers/sl811_usb.c +++ b/drivers/sl811_usb.c @@ -226,33 +226,50 @@ int usb_lowlevel_stop(void) return 0; } -int sl811_send_packet(int dir_to_host, int data1, __u8 *buffer, int len) +static int calc_needed_buswidth(int bytes, int need_preamble) +{ + return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048; +} + +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; - int err = 0; + __u16 status = 0; + int err = 0, time_start = get_timer(0); + int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) && + usb_pipeslow(pipe); if (len > 239) return -1; - if (!dir_to_host) + if (usb_pipeout(pipe)) ctrl |= SL811_USB_CTRL_DIR_OUT; - if (data1) + 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_ADDR_A, 0x10); - sl811_write(SL811_LEN_A, len); - if (!dir_to_host && len) - sl811_write_buf(0x10, buffer, len); + sl811_write(SL811_INTRSTS, 0xff); while (err < 3) { - if (sl811_read(SL811_SOFCNTDIV)*64 < len * 8 * 2) + 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)) - ; /* do nothing */ + while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) { + if (5*CFG_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); @@ -263,7 +280,7 @@ int sl811_send_packet(int dir_to_host, int data1, __u8 *buffer, int len) PDEBUG(0, "usb transfer remainder = %d\n", remainder); len -= remainder; } - if (dir_to_host && len) + if (usb_pipein(pipe) && len) sl811_read_buf(0x10, buffer, len); return len; } @@ -275,7 +292,16 @@ int sl811_send_packet(int dir_to_host, int data1, __u8 *buffer, int len) err++; } - return -1; + 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; } int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, @@ -283,7 +309,6 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, { int dir_out = usb_pipeout(pipe); int ep = usb_pipeendpoint(pipe); - __u8* buf = (__u8*)buffer; int max = usb_maxpacket(dev, pipe); int done = 0; @@ -295,11 +320,10 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, sl811_write(SL811_DEV_A, usb_pipedevice(pipe)); sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep)); while (done < len) { - int res = sl811_send_packet(!dir_out, usb_gettoggle(dev, ep, dir_out), - buf+done, + int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done, max > len - done ? len - done : max); if (res < 0) { - dev->status = res; + dev->status = -res; return res; } @@ -320,45 +344,52 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, { int done = 0; int devnum = usb_pipedevice(pipe); + int ep = usb_pipeendpoint(pipe); dev->status = 0; if (devnum == root_hub_devnum) return sl811_rh_submit_urb(dev, pipe, buffer, len, setup); - PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x\n", - devnum, usb_pipeendpoint(pipe), buffer, len, (int)setup->requesttype, - (int)setup->request); + PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n", + devnum, ep, buffer, len, (int)setup->requesttype, + (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64); sl811_write(SL811_DEV_A, devnum); - sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, 0)); + sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep)); /* setup phase */ - if (sl811_send_packet(0, 0, (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) { - int dir_in = setup->requesttype & USB_DIR_IN; - __u8* buf = (__u8*)buffer; - int data1 = 1; + usb_settoggle(dev, ep, 1, 0); + if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep), + (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) { + int dir_in = usb_pipein(pipe); int max = usb_maxpacket(dev, pipe); /* data phase */ sl811_write(SL811_PIDEP_A, - PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, 0)); + PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep)); + usb_settoggle(dev, ep, usb_pipeout(pipe), 1); while (done < len) { - int res = sl811_send_packet(dir_in, data1, buf+done, + int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done, max > len - done ? len - done : max); - if (res < 0) - return res; + if (res < 0) { + PDEBUG(0, "status data failed!\n"); + dev->status = -res; + return 0; + } done += res; - + usb_dotoggle(dev, ep, usb_pipeout(pipe)); if (dir_in && res < max) /* short packet */ break; - - data1 = !data1; } /* status phase */ sl811_write(SL811_PIDEP_A, - PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, 0)); - if (sl811_send_packet(!dir_in, 1, 0, 0) < 0) { + PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep)); + usb_settoggle(dev, ep, !usb_pipeout(pipe), 1); + if (sl811_send_packet(dev, + !dir_in ? usb_rcvctrlpipe(dev, ep) : + usb_sndctrlpipe(dev, ep), + 0, 0) < 0) { PDEBUG(0, "status phase failed!\n"); dev->status = -1; } @@ -375,7 +406,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len, int interval) { - PDEBUG(7, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe, + PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe, buffer, len, interval); return -1; } @@ -476,7 +507,7 @@ static int ascii2utf (char *s, u8 *utf, int utfmax) * root_hub_string is used by each host controller's root hub code, * so that they're identified consistently throughout the system. */ -int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len) +static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len) { char buf [30]; @@ -491,7 +522,7 @@ int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len) /* serial number */ } else if (id == 1) { - sprintf (buf, "%x", serial); + sprintf (buf, "%#x", serial); /* product description */ } else if (id == 2) { @@ -503,7 +534,8 @@ int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len) } else return 0; - data [0] = 2 + ascii2utf (buf, data + 2, len - 2); + ascii2utf (buf, data + 2, len - 2); + data [0] = 2 + strlen(buf) * 2; data [1] = 3; return data [0]; }