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);
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;
}
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,
{
int dir_out = usb_pipeout(pipe);
int ep = usb_pipeendpoint(pipe);
- __u8* buf = (__u8*)buffer;
int max = usb_maxpacket(dev, pipe);
int done = 0;
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;
}
{
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;
}
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;
}
* 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];
/* serial number */
} else if (id == 1) {
- sprintf (buf, "%x", serial);
+ sprintf (buf, "%#x", serial);
/* product description */
} else if (id == 2) {
} 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];
}