1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
22731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
32731b9a8SJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2004
42731b9a8SJean-Christophe PLAGNIOL-VILLARD * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
52731b9a8SJean-Christophe PLAGNIOL-VILLARD *
62731b9a8SJean-Christophe PLAGNIOL-VILLARD * This code is based on linux driver for sl811hs chip, source at
72731b9a8SJean-Christophe PLAGNIOL-VILLARD * drivers/usb/host/sl811.c:
82731b9a8SJean-Christophe PLAGNIOL-VILLARD *
92731b9a8SJean-Christophe PLAGNIOL-VILLARD * SL811 Host Controller Interface driver for USB.
102731b9a8SJean-Christophe PLAGNIOL-VILLARD *
112731b9a8SJean-Christophe PLAGNIOL-VILLARD * Copyright (c) 2003/06, Courage Co., Ltd.
122731b9a8SJean-Christophe PLAGNIOL-VILLARD *
132731b9a8SJean-Christophe PLAGNIOL-VILLARD * Based on:
142731b9a8SJean-Christophe PLAGNIOL-VILLARD * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
152731b9a8SJean-Christophe PLAGNIOL-VILLARD * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
162731b9a8SJean-Christophe PLAGNIOL-VILLARD * Adam Richter, Gregory P. Smith;
172731b9a8SJean-Christophe PLAGNIOL-VILLARD * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
182731b9a8SJean-Christophe PLAGNIOL-VILLARD * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
192731b9a8SJean-Christophe PLAGNIOL-VILLARD */
202731b9a8SJean-Christophe PLAGNIOL-VILLARD
212731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
222731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <mpc8xx.h>
232731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <usb.h>
242731b9a8SJean-Christophe PLAGNIOL-VILLARD #include "sl811.h"
252731b9a8SJean-Christophe PLAGNIOL-VILLARD
262731b9a8SJean-Christophe PLAGNIOL-VILLARD #include "../../../board/kup/common/kup.h"
272731b9a8SJean-Christophe PLAGNIOL-VILLARD
282731b9a8SJean-Christophe PLAGNIOL-VILLARD #ifdef __PPC__
292731b9a8SJean-Christophe PLAGNIOL-VILLARD # define EIEIO __asm__ volatile ("eieio")
302731b9a8SJean-Christophe PLAGNIOL-VILLARD #else
312731b9a8SJean-Christophe PLAGNIOL-VILLARD # define EIEIO /* nothing */
322731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif
332731b9a8SJean-Christophe PLAGNIOL-VILLARD
342731b9a8SJean-Christophe PLAGNIOL-VILLARD #define SL811_ADR (0x50000000)
352731b9a8SJean-Christophe PLAGNIOL-VILLARD #define SL811_DAT (0x50000001)
362731b9a8SJean-Christophe PLAGNIOL-VILLARD
372731b9a8SJean-Christophe PLAGNIOL-VILLARD #ifdef SL811_DEBUG
382731b9a8SJean-Christophe PLAGNIOL-VILLARD static int debug = 9;
392731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif
402731b9a8SJean-Christophe PLAGNIOL-VILLARD
412731b9a8SJean-Christophe PLAGNIOL-VILLARD static int root_hub_devnum = 0;
422731b9a8SJean-Christophe PLAGNIOL-VILLARD static struct usb_port_status rh_status = { 0 };/* root hub port status */
432731b9a8SJean-Christophe PLAGNIOL-VILLARD
442731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
452731b9a8SJean-Christophe PLAGNIOL-VILLARD void *data, int buf_len, struct devrequest *cmd);
462731b9a8SJean-Christophe PLAGNIOL-VILLARD
sl811_write(__u8 index,__u8 data)472731b9a8SJean-Christophe PLAGNIOL-VILLARD static void sl811_write (__u8 index, __u8 data)
482731b9a8SJean-Christophe PLAGNIOL-VILLARD {
492731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = index;
502731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO;
512731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_DAT) = data;
522731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO;
532731b9a8SJean-Christophe PLAGNIOL-VILLARD }
542731b9a8SJean-Christophe PLAGNIOL-VILLARD
sl811_read(__u8 index)552731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_read (__u8 index)
562731b9a8SJean-Christophe PLAGNIOL-VILLARD {
572731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 data;
582731b9a8SJean-Christophe PLAGNIOL-VILLARD
592731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = index;
602731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO;
612731b9a8SJean-Christophe PLAGNIOL-VILLARD data = *(volatile unsigned char *) (SL811_DAT);
622731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO;
632731b9a8SJean-Christophe PLAGNIOL-VILLARD return (data);
642731b9a8SJean-Christophe PLAGNIOL-VILLARD }
652731b9a8SJean-Christophe PLAGNIOL-VILLARD
662731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
672731b9a8SJean-Christophe PLAGNIOL-VILLARD * Read consecutive bytes of data from the SL811H/SL11H buffer
682731b9a8SJean-Christophe PLAGNIOL-VILLARD */
sl811_read_buf(__u8 offset,__u8 * buf,__u8 size)692731b9a8SJean-Christophe PLAGNIOL-VILLARD static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size)
702731b9a8SJean-Christophe PLAGNIOL-VILLARD {
712731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = offset;
722731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO;
732731b9a8SJean-Christophe PLAGNIOL-VILLARD while (size--) {
742731b9a8SJean-Christophe PLAGNIOL-VILLARD *buf++ = *(volatile unsigned char *) (SL811_DAT);
752731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO;
762731b9a8SJean-Christophe PLAGNIOL-VILLARD }
772731b9a8SJean-Christophe PLAGNIOL-VILLARD }
782731b9a8SJean-Christophe PLAGNIOL-VILLARD
792731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
802731b9a8SJean-Christophe PLAGNIOL-VILLARD * Write consecutive bytes of data to the SL811H/SL11H buffer
812731b9a8SJean-Christophe PLAGNIOL-VILLARD */
sl811_write_buf(__u8 offset,__u8 * buf,__u8 size)822731b9a8SJean-Christophe PLAGNIOL-VILLARD static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size)
832731b9a8SJean-Christophe PLAGNIOL-VILLARD {
842731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = offset;
852731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO;
862731b9a8SJean-Christophe PLAGNIOL-VILLARD while (size--) {
872731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_DAT) = *buf++;
882731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO;
892731b9a8SJean-Christophe PLAGNIOL-VILLARD }
902731b9a8SJean-Christophe PLAGNIOL-VILLARD }
912731b9a8SJean-Christophe PLAGNIOL-VILLARD
usb_init_kup4x(void)922731b9a8SJean-Christophe PLAGNIOL-VILLARD int usb_init_kup4x (void)
932731b9a8SJean-Christophe PLAGNIOL-VILLARD {
942731b9a8SJean-Christophe PLAGNIOL-VILLARD volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
952731b9a8SJean-Christophe PLAGNIOL-VILLARD volatile memctl8xx_t *memctl = &immap->im_memctl;
962731b9a8SJean-Christophe PLAGNIOL-VILLARD int i;
972731b9a8SJean-Christophe PLAGNIOL-VILLARD unsigned char tmp;
982731b9a8SJean-Christophe PLAGNIOL-VILLARD
992731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl = &immap->im_memctl;
1002731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl->memc_or7 = 0xFFFF8726;
1012731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl->memc_br7 = 0x50000401; /* start at 0x50000000 */
1022731b9a8SJean-Christophe PLAGNIOL-VILLARD /* BP 14 low = USB ON */
1032731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC);
1042731b9a8SJean-Christophe PLAGNIOL-VILLARD /* PB 14 nomal port */
1052731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC);
1062731b9a8SJean-Christophe PLAGNIOL-VILLARD /* output */
1072731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbdir |= (BP_USB_VCC);
1082731b9a8SJean-Christophe PLAGNIOL-VILLARD
1092731b9a8SJean-Christophe PLAGNIOL-VILLARD puts ("USB: ");
1102731b9a8SJean-Christophe PLAGNIOL-VILLARD
1112731b9a8SJean-Christophe PLAGNIOL-VILLARD for (i = 0x10; i < 0xff; i++) {
1122731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(i, i);
1132731b9a8SJean-Christophe PLAGNIOL-VILLARD tmp = (sl811_read(i));
1142731b9a8SJean-Christophe PLAGNIOL-VILLARD if (tmp != i) {
1152731b9a8SJean-Christophe PLAGNIOL-VILLARD printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp);
1162731b9a8SJean-Christophe PLAGNIOL-VILLARD return (-1);
1172731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1182731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1192731b9a8SJean-Christophe PLAGNIOL-VILLARD printf ("SL811 ready\n");
1202731b9a8SJean-Christophe PLAGNIOL-VILLARD return (0);
1212731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1222731b9a8SJean-Christophe PLAGNIOL-VILLARD
1232731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
1242731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function resets SL811HS controller and detects the speed of
1252731b9a8SJean-Christophe PLAGNIOL-VILLARD * the connecting device
1262731b9a8SJean-Christophe PLAGNIOL-VILLARD *
1272731b9a8SJean-Christophe PLAGNIOL-VILLARD * Return: 0 = no device attached; 1 = USB device attached
1282731b9a8SJean-Christophe PLAGNIOL-VILLARD */
sl811_hc_reset(void)1292731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_hc_reset(void)
1302731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1312731b9a8SJean-Christophe PLAGNIOL-VILLARD int status ;
1322731b9a8SJean-Christophe PLAGNIOL-VILLARD
1332731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
1342731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
1352731b9a8SJean-Christophe PLAGNIOL-VILLARD
1362731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20);
1372731b9a8SJean-Christophe PLAGNIOL-VILLARD
1382731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Disable hardware SOF generation, clear all irq status. */
1392731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, 0);
1402731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2);
1412731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff);
1422731b9a8SJean-Christophe PLAGNIOL-VILLARD status = sl811_read(SL811_INTRSTS);
1432731b9a8SJean-Christophe PLAGNIOL-VILLARD
1442731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_INTR_NOTPRESENT) {
1452731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Device is not present */
1462731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "Device not present\n");
1472731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
1482731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
1492731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTR, SL811_INTR_INSRMV);
1502731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
1512731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1522731b9a8SJean-Christophe PLAGNIOL-VILLARD
1532731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Send SOF to address 0, endpoint 0. */
1542731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_LEN_B, 0);
1552731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
1562731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_B, 0x00);
1572731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_SOFLOW, SL811_12M_LOW);
1582731b9a8SJean-Christophe PLAGNIOL-VILLARD
1592731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_INTR_SPEED_FULL) {
1602731b9a8SJean-Christophe PLAGNIOL-VILLARD /* full speed device connect directly to root hub */
1612731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG (0, "Full speed Device attached\n");
1622731b9a8SJean-Christophe PLAGNIOL-VILLARD
1632731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
1642731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20);
1652731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
1662731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_SOF);
1672731b9a8SJean-Christophe PLAGNIOL-VILLARD
1682731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start the SOF or EOP */
1692731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
1702731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
1712731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
1722731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2);
1732731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff);
1742731b9a8SJean-Christophe PLAGNIOL-VILLARD } else {
1752731b9a8SJean-Christophe PLAGNIOL-VILLARD /* slow speed device connect directly to root-hub */
1762731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "Low speed Device attached\n");
1772731b9a8SJean-Christophe PLAGNIOL-VILLARD
1782731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
1792731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20);
1802731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
1812731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
1822731b9a8SJean-Christophe PLAGNIOL-VILLARD
1832731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start the SOF or EOP */
1842731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
1852731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
1862731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2);
1872731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff);
1882731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1892731b9a8SJean-Christophe PLAGNIOL-VILLARD
1902731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
1912731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A);
1922731b9a8SJean-Christophe PLAGNIOL-VILLARD
1932731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1;
1942731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1952731b9a8SJean-Christophe PLAGNIOL-VILLARD
usb_lowlevel_init(int index,enum usb_init_type init,void ** controller)19606d513ecSTroy Kisky int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
1972731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1982731b9a8SJean-Christophe PLAGNIOL-VILLARD root_hub_devnum = 0;
1992731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_hc_reset();
2002731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
2012731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2022731b9a8SJean-Christophe PLAGNIOL-VILLARD
usb_lowlevel_stop(int index)203c7e3b2b5SLucas Stach int usb_lowlevel_stop(int index)
2042731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2052731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_hc_reset();
2062731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
2072731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2082731b9a8SJean-Christophe PLAGNIOL-VILLARD
calc_needed_buswidth(int bytes,int need_preamble)2092731b9a8SJean-Christophe PLAGNIOL-VILLARD static int calc_needed_buswidth(int bytes, int need_preamble)
2102731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2112731b9a8SJean-Christophe PLAGNIOL-VILLARD return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048;
2122731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2132731b9a8SJean-Christophe PLAGNIOL-VILLARD
sl811_send_packet(struct usb_device * dev,unsigned long pipe,__u8 * buffer,int len)2142731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len)
2152731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2162731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
2172731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 status = 0;
2182731b9a8SJean-Christophe PLAGNIOL-VILLARD int err = 0, time_start = get_timer(0);
2192731b9a8SJean-Christophe PLAGNIOL-VILLARD int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
220c60795f4SIlya Yanok (dev->speed == USB_SPEED_LOW);
2212731b9a8SJean-Christophe PLAGNIOL-VILLARD
2222731b9a8SJean-Christophe PLAGNIOL-VILLARD if (len > 239)
2232731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1;
2242731b9a8SJean-Christophe PLAGNIOL-VILLARD
2252731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeout(pipe))
2262731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_DIR_OUT;
2272731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
2282731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_TOGGLE_1;
2292731b9a8SJean-Christophe PLAGNIOL-VILLARD if (need_preamble)
2302731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_PREAMBLE;
2312731b9a8SJean-Christophe PLAGNIOL-VILLARD
2322731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff);
2332731b9a8SJean-Christophe PLAGNIOL-VILLARD
2342731b9a8SJean-Christophe PLAGNIOL-VILLARD while (err < 3) {
2352731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_ADDR_A, 0x10);
2362731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_LEN_A, len);
2372731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeout(pipe) && len)
2382731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write_buf(0x10, buffer, len);
2392731b9a8SJean-Christophe PLAGNIOL-VILLARD
2402731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
2412731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))
2422731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_SOF;
2432731b9a8SJean-Christophe PLAGNIOL-VILLARD else
2442731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl &= ~SL811_USB_CTRL_SOF;
2452731b9a8SJean-Christophe PLAGNIOL-VILLARD
2462731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_A, ctrl);
2472731b9a8SJean-Christophe PLAGNIOL-VILLARD while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
2482731b9a8SJean-Christophe PLAGNIOL-VILLARD if (5*CONFIG_SYS_HZ < get_timer(time_start)) {
2492731b9a8SJean-Christophe PLAGNIOL-VILLARD printf("USB transmit timed out\n");
2502731b9a8SJean-Christophe PLAGNIOL-VILLARD return -USB_ST_CRC_ERR;
2512731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2522731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2532731b9a8SJean-Christophe PLAGNIOL-VILLARD
2542731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff);
2552731b9a8SJean-Christophe PLAGNIOL-VILLARD status = sl811_read(SL811_STS_A);
2562731b9a8SJean-Christophe PLAGNIOL-VILLARD
2572731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_ACK) {
2582731b9a8SJean-Christophe PLAGNIOL-VILLARD int remainder = sl811_read(SL811_CNT_A);
2592731b9a8SJean-Christophe PLAGNIOL-VILLARD if (remainder) {
2602731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "usb transfer remainder = %d\n", remainder);
2612731b9a8SJean-Christophe PLAGNIOL-VILLARD len -= remainder;
2622731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2632731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipein(pipe) && len)
2642731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_read_buf(0x10, buffer, len);
2652731b9a8SJean-Christophe PLAGNIOL-VILLARD return len;
2662731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2672731b9a8SJean-Christophe PLAGNIOL-VILLARD
2682731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)
2692731b9a8SJean-Christophe PLAGNIOL-VILLARD continue;
2702731b9a8SJean-Christophe PLAGNIOL-VILLARD
2712731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "usb transfer error %#x\n", (int)status);
2722731b9a8SJean-Christophe PLAGNIOL-VILLARD err++;
2732731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2742731b9a8SJean-Christophe PLAGNIOL-VILLARD
2752731b9a8SJean-Christophe PLAGNIOL-VILLARD err = 0;
2762731b9a8SJean-Christophe PLAGNIOL-VILLARD
2772731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_ERROR)
2782731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_BUF_ERR;
2792731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_TIMEOUT)
2802731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_CRC_ERR;
2812731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_STALL)
2822731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_STALLED;
2832731b9a8SJean-Christophe PLAGNIOL-VILLARD
2842731b9a8SJean-Christophe PLAGNIOL-VILLARD return -err;
2852731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2862731b9a8SJean-Christophe PLAGNIOL-VILLARD
submit_bulk_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len)2872731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
2882731b9a8SJean-Christophe PLAGNIOL-VILLARD int len)
2892731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2902731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_out = usb_pipeout(pipe);
2912731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe);
2922731b9a8SJean-Christophe PLAGNIOL-VILLARD int max = usb_maxpacket(dev, pipe);
2932731b9a8SJean-Christophe PLAGNIOL-VILLARD int done = 0;
2942731b9a8SJean-Christophe PLAGNIOL-VILLARD
2952731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n",
2962731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
2972731b9a8SJean-Christophe PLAGNIOL-VILLARD
2982731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0;
2992731b9a8SJean-Christophe PLAGNIOL-VILLARD
3002731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_A, usb_pipedevice(pipe));
3012731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep));
3022731b9a8SJean-Christophe PLAGNIOL-VILLARD while (done < len) {
3032731b9a8SJean-Christophe PLAGNIOL-VILLARD int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
3042731b9a8SJean-Christophe PLAGNIOL-VILLARD max > len - done ? len - done : max);
3052731b9a8SJean-Christophe PLAGNIOL-VILLARD if (res < 0) {
3062731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -res;
3072731b9a8SJean-Christophe PLAGNIOL-VILLARD return res;
3082731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3092731b9a8SJean-Christophe PLAGNIOL-VILLARD
3102731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!dir_out && res < max) /* short packet */
3112731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
3122731b9a8SJean-Christophe PLAGNIOL-VILLARD
3132731b9a8SJean-Christophe PLAGNIOL-VILLARD done += res;
3142731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dotoggle(dev, ep, dir_out);
3152731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3162731b9a8SJean-Christophe PLAGNIOL-VILLARD
3172731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = done;
3182731b9a8SJean-Christophe PLAGNIOL-VILLARD
3192731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
3202731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3212731b9a8SJean-Christophe PLAGNIOL-VILLARD
submit_control_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len,struct devrequest * setup)3222731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
3232731b9a8SJean-Christophe PLAGNIOL-VILLARD int len,struct devrequest *setup)
3242731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3252731b9a8SJean-Christophe PLAGNIOL-VILLARD int done = 0;
3262731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe);
3272731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe);
3282731b9a8SJean-Christophe PLAGNIOL-VILLARD
3292731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0;
3302731b9a8SJean-Christophe PLAGNIOL-VILLARD
3312731b9a8SJean-Christophe PLAGNIOL-VILLARD if (devnum == root_hub_devnum)
3322731b9a8SJean-Christophe PLAGNIOL-VILLARD return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);
3332731b9a8SJean-Christophe PLAGNIOL-VILLARD
3342731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",
3352731b9a8SJean-Christophe PLAGNIOL-VILLARD devnum, ep, buffer, len, (int)setup->requesttype,
3362731b9a8SJean-Christophe PLAGNIOL-VILLARD (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);
3372731b9a8SJean-Christophe PLAGNIOL-VILLARD
3382731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_A, devnum);
3392731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));
3402731b9a8SJean-Christophe PLAGNIOL-VILLARD /* setup phase */
3412731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, 1, 0);
3422731b9a8SJean-Christophe PLAGNIOL-VILLARD if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),
3432731b9a8SJean-Christophe PLAGNIOL-VILLARD (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {
3442731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_in = usb_pipein(pipe);
3452731b9a8SJean-Christophe PLAGNIOL-VILLARD int max = usb_maxpacket(dev, pipe);
3462731b9a8SJean-Christophe PLAGNIOL-VILLARD
3472731b9a8SJean-Christophe PLAGNIOL-VILLARD /* data phase */
3482731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A,
3492731b9a8SJean-Christophe PLAGNIOL-VILLARD PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));
3502731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, usb_pipeout(pipe), 1);
3512731b9a8SJean-Christophe PLAGNIOL-VILLARD while (done < len) {
3522731b9a8SJean-Christophe PLAGNIOL-VILLARD int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
3532731b9a8SJean-Christophe PLAGNIOL-VILLARD max > len - done ? len - done : max);
3542731b9a8SJean-Christophe PLAGNIOL-VILLARD if (res < 0) {
3552731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "status data failed!\n");
3562731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -res;
3572731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
3582731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3592731b9a8SJean-Christophe PLAGNIOL-VILLARD done += res;
3602731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dotoggle(dev, ep, usb_pipeout(pipe));
3612731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_in && res < max) /* short packet */
3622731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
3632731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3642731b9a8SJean-Christophe PLAGNIOL-VILLARD
3652731b9a8SJean-Christophe PLAGNIOL-VILLARD /* status phase */
3662731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A,
3672731b9a8SJean-Christophe PLAGNIOL-VILLARD PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep));
3682731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, !usb_pipeout(pipe), 1);
3692731b9a8SJean-Christophe PLAGNIOL-VILLARD if (sl811_send_packet(dev,
3702731b9a8SJean-Christophe PLAGNIOL-VILLARD !dir_in ? usb_rcvctrlpipe(dev, ep) :
3712731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_sndctrlpipe(dev, ep),
3722731b9a8SJean-Christophe PLAGNIOL-VILLARD 0, 0) < 0) {
3732731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "status phase failed!\n");
3742731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -1;
3752731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3762731b9a8SJean-Christophe PLAGNIOL-VILLARD } else {
3772731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "setup phase failed!\n");
3782731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -1;
3792731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3802731b9a8SJean-Christophe PLAGNIOL-VILLARD
3812731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = done;
3822731b9a8SJean-Christophe PLAGNIOL-VILLARD
3832731b9a8SJean-Christophe PLAGNIOL-VILLARD return done;
3842731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3852731b9a8SJean-Christophe PLAGNIOL-VILLARD
submit_int_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len,int interval)3862731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
3872731b9a8SJean-Christophe PLAGNIOL-VILLARD int len, int interval)
3882731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3892731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe,
3902731b9a8SJean-Christophe PLAGNIOL-VILLARD buffer, len, interval);
3912731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1;
3922731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3932731b9a8SJean-Christophe PLAGNIOL-VILLARD
3942731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
3952731b9a8SJean-Christophe PLAGNIOL-VILLARD * SL811 Virtual Root Hub
3962731b9a8SJean-Christophe PLAGNIOL-VILLARD */
3972731b9a8SJean-Christophe PLAGNIOL-VILLARD
3982731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Device descriptor */
3992731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_dev_des[] =
4002731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4012731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x12, /* __u8 bLength; */
4022731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bDescriptorType; Device */
4032731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x10, /* __u16 bcdUSB; v1.1 */
4042731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01,
4052731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
4062731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bDeviceSubClass; */
4072731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bDeviceProtocol; */
4082731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
4092731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 idVendor; */
4102731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00,
4112731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 idProduct; */
4122731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00,
4132731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 bcdDevice; */
4142731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00,
4152731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 iManufacturer; */
4162731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x02, /* __u8 iProduct; */
4172731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 iSerialNumber; */
4182731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01 /* __u8 bNumConfigurations; */
4192731b9a8SJean-Christophe PLAGNIOL-VILLARD };
4202731b9a8SJean-Christophe PLAGNIOL-VILLARD
4212731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Configuration descriptor */
4222731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_config_des[] =
4232731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4242731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bLength; */
4252731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x02, /* __u8 bDescriptorType; Configuration */
4262731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x19, /* __u16 wTotalLength; */
4272731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00,
4282731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bNumInterfaces; */
4292731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bConfigurationValue; */
4302731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 iConfiguration; */
4312731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x40, /* __u8 bmAttributes;
4322731b9a8SJean-Christophe PLAGNIOL-VILLARD Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
4332731b9a8SJean-Christophe PLAGNIOL-VILLARD 4..0: resvd */
4342731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 MaxPower; */
4352731b9a8SJean-Christophe PLAGNIOL-VILLARD
4362731b9a8SJean-Christophe PLAGNIOL-VILLARD /* interface */
4372731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 if_bLength; */
4382731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x04, /* __u8 if_bDescriptorType; Interface */
4392731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceNumber; */
4402731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bAlternateSetting; */
4412731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 if_bNumEndpoints; */
4422731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
4432731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceSubClass; */
4442731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceProtocol; */
4452731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_iInterface; */
4462731b9a8SJean-Christophe PLAGNIOL-VILLARD
4472731b9a8SJean-Christophe PLAGNIOL-VILLARD /* endpoint */
4482731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x07, /* __u8 ep_bLength; */
4492731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x05, /* __u8 ep_bDescriptorType; Endpoint */
4502731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
4512731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x03, /* __u8 ep_bmAttributes; Interrupt */
4522731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x08, /* __u16 ep_wMaxPacketSize; */
4532731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00,
4542731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xff /* __u8 ep_bInterval; 255 ms */
4552731b9a8SJean-Christophe PLAGNIOL-VILLARD };
4562731b9a8SJean-Christophe PLAGNIOL-VILLARD
4572731b9a8SJean-Christophe PLAGNIOL-VILLARD /* root hub class descriptor*/
4582731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_hub_des[] =
4592731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4602731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bLength; */
4612731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x29, /* __u8 bDescriptorType; Hub-descriptor */
4622731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bNbrPorts; */
4632731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 wHubCharacteristics; */
4642731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00,
4652731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x50, /* __u8 bPwrOn2pwrGood; 2ms */
4662731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bHubContrCurrent; 0 mA */
4672731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */
4682731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
4692731b9a8SJean-Christophe PLAGNIOL-VILLARD };
4702731b9a8SJean-Christophe PLAGNIOL-VILLARD
4712731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
4722731b9a8SJean-Christophe PLAGNIOL-VILLARD * helper routine for returning string descriptors in UTF-16LE
4732731b9a8SJean-Christophe PLAGNIOL-VILLARD * input can actually be ISO-8859-1; ASCII is its 7-bit subset
4742731b9a8SJean-Christophe PLAGNIOL-VILLARD */
ascii2utf(char * s,u8 * utf,int utfmax)4752731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ascii2utf (char *s, u8 *utf, int utfmax)
4762731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4772731b9a8SJean-Christophe PLAGNIOL-VILLARD int retval;
4782731b9a8SJean-Christophe PLAGNIOL-VILLARD
4792731b9a8SJean-Christophe PLAGNIOL-VILLARD for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
4802731b9a8SJean-Christophe PLAGNIOL-VILLARD *utf++ = *s++;
4812731b9a8SJean-Christophe PLAGNIOL-VILLARD *utf++ = 0;
4822731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4832731b9a8SJean-Christophe PLAGNIOL-VILLARD return retval;
4842731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4852731b9a8SJean-Christophe PLAGNIOL-VILLARD
4862731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
4872731b9a8SJean-Christophe PLAGNIOL-VILLARD * root_hub_string is used by each host controller's root hub code,
4882731b9a8SJean-Christophe PLAGNIOL-VILLARD * so that they're identified consistently throughout the system.
4892731b9a8SJean-Christophe PLAGNIOL-VILLARD */
usb_root_hub_string(int id,int serial,char * type,__u8 * data,int len)4902731b9a8SJean-Christophe PLAGNIOL-VILLARD static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
4912731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4922731b9a8SJean-Christophe PLAGNIOL-VILLARD char buf [30];
4932731b9a8SJean-Christophe PLAGNIOL-VILLARD
4942731b9a8SJean-Christophe PLAGNIOL-VILLARD /* assert (len > (2 * (sizeof (buf) + 1)));
4952731b9a8SJean-Christophe PLAGNIOL-VILLARD assert (strlen (type) <= 8);*/
4962731b9a8SJean-Christophe PLAGNIOL-VILLARD
4972731b9a8SJean-Christophe PLAGNIOL-VILLARD /* language ids */
4982731b9a8SJean-Christophe PLAGNIOL-VILLARD if (id == 0) {
4992731b9a8SJean-Christophe PLAGNIOL-VILLARD *data++ = 4; *data++ = 3; /* 4 bytes data */
5002731b9a8SJean-Christophe PLAGNIOL-VILLARD *data++ = 0; *data++ = 0; /* some language id */
5012731b9a8SJean-Christophe PLAGNIOL-VILLARD return 4;
5022731b9a8SJean-Christophe PLAGNIOL-VILLARD
5032731b9a8SJean-Christophe PLAGNIOL-VILLARD /* serial number */
5042731b9a8SJean-Christophe PLAGNIOL-VILLARD } else if (id == 1) {
5052731b9a8SJean-Christophe PLAGNIOL-VILLARD sprintf (buf, "%#x", serial);
5062731b9a8SJean-Christophe PLAGNIOL-VILLARD
5072731b9a8SJean-Christophe PLAGNIOL-VILLARD /* product description */
5082731b9a8SJean-Christophe PLAGNIOL-VILLARD } else if (id == 2) {
5092731b9a8SJean-Christophe PLAGNIOL-VILLARD sprintf (buf, "USB %s Root Hub", type);
5102731b9a8SJean-Christophe PLAGNIOL-VILLARD
5112731b9a8SJean-Christophe PLAGNIOL-VILLARD /* id 3 == vendor description */
5122731b9a8SJean-Christophe PLAGNIOL-VILLARD
5132731b9a8SJean-Christophe PLAGNIOL-VILLARD /* unsupported IDs --> "stall" */
5142731b9a8SJean-Christophe PLAGNIOL-VILLARD } else
5152731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
5162731b9a8SJean-Christophe PLAGNIOL-VILLARD
5172731b9a8SJean-Christophe PLAGNIOL-VILLARD ascii2utf (buf, data + 2, len - 2);
5182731b9a8SJean-Christophe PLAGNIOL-VILLARD data [0] = 2 + strlen(buf) * 2;
5192731b9a8SJean-Christophe PLAGNIOL-VILLARD data [1] = 3;
5202731b9a8SJean-Christophe PLAGNIOL-VILLARD return data [0];
5212731b9a8SJean-Christophe PLAGNIOL-VILLARD }
5222731b9a8SJean-Christophe PLAGNIOL-VILLARD
5232731b9a8SJean-Christophe PLAGNIOL-VILLARD /* helper macro */
5242731b9a8SJean-Christophe PLAGNIOL-VILLARD #define OK(x) len = (x); break
5252731b9a8SJean-Christophe PLAGNIOL-VILLARD
5262731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
5272731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles all USB request to the the virtual root hub
5282731b9a8SJean-Christophe PLAGNIOL-VILLARD */
sl811_rh_submit_urb(struct usb_device * usb_dev,unsigned long pipe,void * data,int buf_len,struct devrequest * cmd)5292731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
5302731b9a8SJean-Christophe PLAGNIOL-VILLARD void *data, int buf_len, struct devrequest *cmd)
5312731b9a8SJean-Christophe PLAGNIOL-VILLARD {
5322731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 data_buf[16];
5332731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 *bufp = data_buf;
5342731b9a8SJean-Christophe PLAGNIOL-VILLARD int len = 0;
5352731b9a8SJean-Christophe PLAGNIOL-VILLARD int status = 0;
5362731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 bmRType_bReq;
537b0b20d47SWolfgang Denk __u16 wValue = le16_to_cpu (cmd->value);
538b0b20d47SWolfgang Denk __u16 wLength = le16_to_cpu (cmd->length);
539b0b20d47SWolfgang Denk #ifdef SL811_DEBUG
540b0b20d47SWolfgang Denk __u16 wIndex = le16_to_cpu (cmd->index);
541b0b20d47SWolfgang Denk #endif
5422731b9a8SJean-Christophe PLAGNIOL-VILLARD
5432731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeint(pipe)) {
5442731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "interrupt transfer unimplemented!\n");
5452731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
5462731b9a8SJean-Christophe PLAGNIOL-VILLARD }
5472731b9a8SJean-Christophe PLAGNIOL-VILLARD
5482731b9a8SJean-Christophe PLAGNIOL-VILLARD bmRType_bReq = cmd->requesttype | (cmd->request << 8);
5492731b9a8SJean-Christophe PLAGNIOL-VILLARD
5502731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n",
5512731b9a8SJean-Christophe PLAGNIOL-VILLARD bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength);
5522731b9a8SJean-Christophe PLAGNIOL-VILLARD
5532731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Request Destination:
5542731b9a8SJean-Christophe PLAGNIOL-VILLARD without flags: Device,
5552731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_INTERFACE: interface,
5562731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_ENDPOINT: endpoint,
5572731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_TYPE_CLASS means HUB here,
5582731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here
5592731b9a8SJean-Christophe PLAGNIOL-VILLARD */
5602731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (bmRType_bReq) {
5612731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS:
5622731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(1);
5632731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2);
5642731b9a8SJean-Christophe PLAGNIOL-VILLARD
5652731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_INTERFACE:
5662731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(0);
5672731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2);
5682731b9a8SJean-Christophe PLAGNIOL-VILLARD
5692731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_ENDPOINT:
5702731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(0);
5712731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2);
5722731b9a8SJean-Christophe PLAGNIOL-VILLARD
5732731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_TYPE_CLASS:
5742731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u32 *)bufp = cpu_to_le32(0);
5752731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(4);
5762731b9a8SJean-Christophe PLAGNIOL-VILLARD
5772731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
5782731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus);
5792731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(4);
5802731b9a8SJean-Christophe PLAGNIOL-VILLARD
5812731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
5822731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) {
5832731b9a8SJean-Christophe PLAGNIOL-VILLARD case 1:
5842731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
5852731b9a8SJean-Christophe PLAGNIOL-VILLARD }
5862731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
5872731b9a8SJean-Christophe PLAGNIOL-VILLARD
5882731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
5892731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) {
5902731b9a8SJean-Christophe PLAGNIOL-VILLARD case C_HUB_LOCAL_POWER:
5912731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
5922731b9a8SJean-Christophe PLAGNIOL-VILLARD
5932731b9a8SJean-Christophe PLAGNIOL-VILLARD case C_HUB_OVER_CURRENT:
5942731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
5952731b9a8SJean-Christophe PLAGNIOL-VILLARD }
5962731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
5972731b9a8SJean-Christophe PLAGNIOL-VILLARD
5982731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
5992731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) {
6002731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_ENABLE:
6012731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
6022731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6032731b9a8SJean-Christophe PLAGNIOL-VILLARD
6042731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_SUSPEND:
6052731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
6062731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6072731b9a8SJean-Christophe PLAGNIOL-VILLARD
6082731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_POWER:
6092731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
6102731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6112731b9a8SJean-Christophe PLAGNIOL-VILLARD
6122731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_CONNECTION:
6132731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
6142731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6152731b9a8SJean-Christophe PLAGNIOL-VILLARD
6162731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_ENABLE:
6172731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
6182731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6192731b9a8SJean-Christophe PLAGNIOL-VILLARD
6202731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_SUSPEND:
6212731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
6222731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6232731b9a8SJean-Christophe PLAGNIOL-VILLARD
6242731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_OVER_CURRENT:
6252731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
6262731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6272731b9a8SJean-Christophe PLAGNIOL-VILLARD
6282731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_RESET:
6292731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
6302731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6312731b9a8SJean-Christophe PLAGNIOL-VILLARD }
6322731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
6332731b9a8SJean-Christophe PLAGNIOL-VILLARD
6342731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
6352731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) {
6362731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_SUSPEND:
6372731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
6382731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6392731b9a8SJean-Christophe PLAGNIOL-VILLARD
6402731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_RESET:
6412731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_RESET;
6422731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange = 0;
6432731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
6442731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
6452731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
6462731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6472731b9a8SJean-Christophe PLAGNIOL-VILLARD
6482731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_POWER:
6492731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_POWER;
6502731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6512731b9a8SJean-Christophe PLAGNIOL-VILLARD
6522731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_ENABLE:
6532731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
6542731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6552731b9a8SJean-Christophe PLAGNIOL-VILLARD }
6562731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
6572731b9a8SJean-Christophe PLAGNIOL-VILLARD
6582731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_ADDRESS:
6592731b9a8SJean-Christophe PLAGNIOL-VILLARD root_hub_devnum = wValue;
6602731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6612731b9a8SJean-Christophe PLAGNIOL-VILLARD
6622731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_DESCRIPTOR:
6632731b9a8SJean-Christophe PLAGNIOL-VILLARD switch ((wValue & 0xff00) >> 8) {
6642731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_DEVICE:
6652731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_dev_des);
6662731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_dev_des;
6672731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len);
6682731b9a8SJean-Christophe PLAGNIOL-VILLARD
6692731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_CONFIG:
6702731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_config_des);
6712731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_config_des;
6722731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len);
6732731b9a8SJean-Christophe PLAGNIOL-VILLARD
6742731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_STRING:
6752731b9a8SJean-Christophe PLAGNIOL-VILLARD len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength);
6762731b9a8SJean-Christophe PLAGNIOL-VILLARD if (len > 0) {
6772731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = data;
6782731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len);
6792731b9a8SJean-Christophe PLAGNIOL-VILLARD }
6802731b9a8SJean-Christophe PLAGNIOL-VILLARD
6812731b9a8SJean-Christophe PLAGNIOL-VILLARD default:
6822731b9a8SJean-Christophe PLAGNIOL-VILLARD status = -32;
6832731b9a8SJean-Christophe PLAGNIOL-VILLARD }
6842731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
6852731b9a8SJean-Christophe PLAGNIOL-VILLARD
6862731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
6872731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_hub_des);
6882731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_hub_des;
6892731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len);
6902731b9a8SJean-Christophe PLAGNIOL-VILLARD
6912731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_CONFIGURATION:
6922731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp[0] = 0x01;
6932731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(1);
6942731b9a8SJean-Christophe PLAGNIOL-VILLARD
6952731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_CONFIGURATION:
6962731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0);
6972731b9a8SJean-Christophe PLAGNIOL-VILLARD
6982731b9a8SJean-Christophe PLAGNIOL-VILLARD default:
6992731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(1, "unsupported root hub command\n");
7002731b9a8SJean-Christophe PLAGNIOL-VILLARD status = -32;
7012731b9a8SJean-Christophe PLAGNIOL-VILLARD }
7022731b9a8SJean-Christophe PLAGNIOL-VILLARD
7032731b9a8SJean-Christophe PLAGNIOL-VILLARD len = min(len, buf_len);
7042731b9a8SJean-Christophe PLAGNIOL-VILLARD if (data != bufp)
7052731b9a8SJean-Christophe PLAGNIOL-VILLARD memcpy(data, bufp, len);
7062731b9a8SJean-Christophe PLAGNIOL-VILLARD
7072731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(5, "len = %d, status = %d\n", len, status);
7082731b9a8SJean-Christophe PLAGNIOL-VILLARD
7092731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dev->status = status;
7102731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dev->act_len = len;
7112731b9a8SJean-Christophe PLAGNIOL-VILLARD
7122731b9a8SJean-Christophe PLAGNIOL-VILLARD return status == 0 ? len : status;
7132731b9a8SJean-Christophe PLAGNIOL-VILLARD }
714