190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Wireless USB Host Controller
390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Root Hub operations
490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Copyright (C) 2005-2006 Intel Corporation
790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * This program is free software; you can redistribute it and/or
1090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * modify it under the terms of the GNU General Public License version
1190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * 2 as published by the Free Software Foundation.
1290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
1390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * This program is distributed in the hope that it will be useful,
1490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * but WITHOUT ANY WARRANTY; without even the implied warranty of
1590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * GNU General Public License for more details.
1790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
1890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * You should have received a copy of the GNU General Public License
1990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * along with this program; if not, write to the Free Software
2090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * 02110-1301, USA.
2290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
2390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
2490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * We fake a root hub that has fake ports (as many as simultaneous
2590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * devices the Wireless USB Host Controller can deal with). For each
2690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * port we keep an state in @wusbhc->port[index] identical to the one
2790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * specified in the USB2.0[ch11] spec and some extra device
2890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * information that complements the one in 'struct usb_device' (as
2990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * this lacs a hcpriv pointer).
3090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
3190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Note this is common to WHCI and HWA host controllers.
3290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
3390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Through here we enable most of the state changes that the USB stack
3490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * will use to connect or disconnect devices. We need to do some
3590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * forced adaptation of Wireless USB device states vs. wired:
3690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
3790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *        USB:                 WUSB:
3890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
3990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Port   Powered-off          port slot n/a
4090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *        Powered-on           port slot available
4190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *        Disconnected         port slot available
4290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *        Connected            port slot assigned device
4390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *        		       device sent DN_Connect
4490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *                             device was authenticated
4590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *        Enabled              device is authenticated, transitioned
4690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *                             from unauth -> auth -> default address
4790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *                             -> enabled
4890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *        Reset                disconnect
4990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *        Disable              disconnect
5090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
5190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * This maps the standard USB port states with the WUSB device states
5290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * so we can fake ports without having to modify the USB stack.
5390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
5490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * FIXME: this process will change in the future
5590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
5690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
5790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * ENTRY POINTS
5890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
5990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Our entry points into here are, as in hcd.c, the USB stack root hub
6090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * ops defined in the usb_hcd struct:
6190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
6290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * wusbhc_rh_status_data()	Provide hub and port status data bitmap
6390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
6490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * wusbhc_rh_control()          Execution of all the major requests
6590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *                              you can do to a hub (Set|Clear
6690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *                              features, get descriptors, status, etc).
6790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
6890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * wusbhc_rh_[suspend|resume]() That
6990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
7090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * wusbhc_rh_start_port_reset() ??? unimplemented
7190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
725a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
73f940fcd8eadfe5b909a1474b57de7755edeee62bPaul Gortmaker#include <linux/export.h>
7490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez#include "wusbhc.h"
7590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
7690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
7790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Reset a fake port
7890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
794656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * Using a Reset Device IE is too heavyweight as it causes the device
804656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * to enter the UnConnected state and leave the cluster, this can mean
814656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * that when the device reconnects it is connected to a different fake
824656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * port.
8390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
844656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * Instead, reset authenticated devices with a SetAddress(0), followed
854656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * by a SetAddresss(AuthAddr).
864656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel *
874656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * For unauthenticated devices just pretend to reset but do nothing.
884656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * If the device initialization continues to fail it will eventually
894656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel * time out after TrustTimeout and enter the UnConnected state.
9090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
9190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
9290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
9390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Supposedly we are the only thread accesing @wusbhc->port; in any
9490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * case, maybe we should move the mutex locking from
9590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * wusbhc_devconnect_auth() to here.
9690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
9790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @port_idx refers to the wusbhc's port index, not the USB port number
9890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
9990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezstatic int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
10090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
10190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	int result = 0;
10290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx);
1034656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel	struct wusb_dev *wusb_dev = port->wusb_dev;
1044656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel
1059a9b1d17ba59b78e4bae67f7a7cf546986a42e7dDavid Vrabel	if (wusb_dev == NULL)
1069a9b1d17ba59b78e4bae67f7a7cf546986a42e7dDavid Vrabel		return -ENOTCONN;
1079a9b1d17ba59b78e4bae67f7a7cf546986a42e7dDavid Vrabel
1084656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel	port->status |= USB_PORT_STAT_RESET;
1094656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel	port->change |= USB_PORT_STAT_C_RESET;
11090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
1114656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel	if (wusb_dev->addr & WUSB_DEV_ADDR_UNAUTH)
1124656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel		result = 0;
11390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	else
1144656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel		result = wusb_dev_update_address(wusbhc, wusb_dev);
1154656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel
1164656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel	port->status &= ~USB_PORT_STAT_RESET;
1174656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel	port->status |= USB_PORT_STAT_ENABLE;
1184656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel	port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE;
1194656d5de9555e263c5b4c0462b5af7e7bded1b42David Vrabel
12090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	return result;
12190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
12290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
12390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
12490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Return the hub change status bitmap
12590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
12690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * The bits in the change status bitmap are cleared when a
12790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4].
12890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
12990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
13090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
13190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * WARNING!! This gets called from atomic context; we cannot get the
13290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *           mutex--the only race condition we can find is some bit
13390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *           changing just after we copy it, which shouldn't be too
13490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *           big of a problem [and we can't make it an spinlock
13590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *           because other parts need to take it and sleep] .
13690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
13725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi *           @usb_hcd is refcounted, so it won't disappear under us
13890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *           and before killing a host, the polling of the root hub
13990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *           would be stopped anyway.
14090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
14190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezint wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
14290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
14390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
144467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	size_t cnt, size, bits_set = 0;
14590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
14690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	/* WE DON'T LOCK, see comment */
147467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	/* round up to bytes.  Hub bit is bit 0 so add 1. */
148467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8);
149467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese
150467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	/* clear the output buffer. */
151467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	memset(_buf, 0, size);
152467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	/* set the bit for each changed port. */
153467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	for (cnt = 0; cnt < wusbhc->ports_max; cnt++) {
154467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese
155467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese		if (wusb_port_by_idx(wusbhc, cnt)->change) {
156467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese			const int bitpos = cnt+1;
157467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese
158467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese			_buf[bitpos/8] |= (1 << (bitpos % 8));
159467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese			bits_set++;
160467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese		}
161467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	}
162467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese
163467d296f47731bcba578cfdea8416b4c152c4f1bThomas Pugliese	return bits_set ? size : 0;
16490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
16590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
16690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
16790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
16832b801e9fa5e05c179b86802ccb19b3b97d47471Justin P. Mattock * Return the hub's descriptor
16990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
17090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * NOTE: almost cut and paste from ehci-hub.c
17190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
17290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked
17390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
17490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezstatic int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue,
17590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez				   u16 wIndex,
17690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez				   struct usb_hub_descriptor *descr,
17790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez				   u16 wLength)
17890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
17990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	u16 temp = 1 + (wusbhc->ports_max / 8);
18090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	u8 length = 7 + 2 * temp;
18190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
18290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	if (wLength < length)
18390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		return -ENOSPC;
18490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	descr->bDescLength = 7 + 2 * temp;
18590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	descr->bDescriptorType = 0x29;	/* HUB type */
18690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	descr->bNbrPorts = wusbhc->ports_max;
18790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	descr->wHubCharacteristics = cpu_to_le16(
18890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		0x00			/* All ports power at once */
18990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		| 0x00			/* not part of compound device */
19090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		| 0x10			/* No overcurrent protection */
19190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		| 0x00			/* 8 FS think time FIXME ?? */
19290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		| 0x00);		/* No port indicators */
19390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	descr->bPwrOn2PwrGood = 0;
19490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	descr->bHubContrCurrent = 0;
19590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
196dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	memset(&descr->u.hs.DeviceRemovable[0], 0, temp);
197dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	memset(&descr->u.hs.DeviceRemovable[temp], 0xff, temp);
19890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	return 0;
19990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
20090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
20190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
20290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Clear a hub feature
20390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
20490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
20590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
20690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Nothing to do, so no locking needed ;)
20790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
20890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezstatic int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature)
20990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
21090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	int result;
21190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
21290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	switch (feature) {
21390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case C_HUB_LOCAL_POWER:
21490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		/* FIXME: maybe plug bit 0 to the power input status,
21590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		 * if any?
21690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		 * see wusbhc_rh_get_hub_status() */
21790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case C_HUB_OVER_CURRENT:
21890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = 0;
21990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
22090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	default:
22190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = -EPIPE;
22290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	}
22390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	return result;
22490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
22590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
22690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
22790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Return hub status (it is always zero...)
22890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
22990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
23090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
23190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Nothing to do, so no locking needed ;)
23290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
23390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezstatic int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf,
23490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez				    u16 wLength)
23590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
23690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	/* FIXME: maybe plug bit 0 to the power input status (if any)? */
23790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	*buf = 0;
23890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	return 0;
23990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
24090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
24190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
24290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Set a port feature
24390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
24490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
24590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
24690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezstatic int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature,
24790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez				   u8 selector, u8 port_idx)
24890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
24990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	struct device *dev = wusbhc->dev;
25090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
25190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	if (port_idx > wusbhc->ports_max)
252bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel		return -EINVAL;
25390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
25490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	switch (feature) {
25590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		/* According to USB2.0[11.24.2.13]p2, these features
25690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		 * are not required to be implemented. */
25790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_OVER_CURRENT:
25890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_ENABLE:
25990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_SUSPEND:
26090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_CONNECTION:
26190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_RESET:
262bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel		return 0;
26390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_POWER:
26490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		/* No such thing, but we fake it works */
26590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		mutex_lock(&wusbhc->mutex);
26690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER;
26790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		mutex_unlock(&wusbhc->mutex);
268bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel		return 0;
26990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_RESET:
270bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel		return wusbhc_rh_port_reset(wusbhc, port_idx);
27190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_ENABLE:
27290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_SUSPEND:
27390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n",
27490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez			port_idx, feature, selector);
275bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel		return -ENOSYS;
27690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	default:
27790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n",
27890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez			port_idx, feature, selector);
279bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel		return -EPIPE;
28090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	}
281bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel
282bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel	return 0;
28390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
28490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
28590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
28690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Clear a port feature...
28790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
28890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
28990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
29090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezstatic int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
29190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez				     u8 selector, u8 port_idx)
29290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
293bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel	int result = 0;
29490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	struct device *dev = wusbhc->dev;
29590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
29690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	if (port_idx > wusbhc->ports_max)
297bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel		return -EINVAL;
29890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
29990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	mutex_lock(&wusbhc->mutex);
30090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	switch (feature) {
30190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_POWER:	/* fake port always on */
30290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		/* According to USB2.0[11.24.2.7.1.4], no need to implement? */
30390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_OVER_CURRENT:
30490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
30590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_RESET:
30690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET;
30790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
30890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_CONNECTION:
30990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION;
31090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
31190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_ENABLE:
31290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		__wusbhc_dev_disable(wusbhc, port_idx);
31390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
31490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_ENABLE:
31590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE;
31690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
31790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_SUSPEND:
31890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case USB_PORT_FEAT_C_SUSPEND:
31990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n",
32090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez			port_idx, feature, selector);
32190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = -ENOSYS;
32290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
32390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	default:
32490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n",
32590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez			port_idx, feature, selector);
32690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = -EPIPE;
32790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
32890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	}
32990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	mutex_unlock(&wusbhc->mutex);
330bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel
33190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	return result;
33290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
33390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
33490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
33590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Return the port's status
33690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
33790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
33890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
33990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezstatic int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx,
34090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez				     u32 *_buf, u16 wLength)
34190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
342d767d888750a8e15656b7ee15d68f90a151b8936Harvey Harrison	__le16 *buf = (__le16 *)_buf;
34390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
34490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	if (port_idx > wusbhc->ports_max)
345bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel		return -EINVAL;
346bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel
34790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	mutex_lock(&wusbhc->mutex);
34890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status);
34990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change);
35090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	mutex_unlock(&wusbhc->mutex);
351bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel
352bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel	return 0;
35390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
35490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
35590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
35690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Entry point for Root Hub operations
35790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez *
35890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
35990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
36090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezint wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue,
36190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		      u16 wIndex, char *buf, u16 wLength)
36290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
36390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	int result = -ENOSYS;
36490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
36590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
36690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	switch (reqntype) {
36790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case GetHubDescriptor:
36890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = wusbhc_rh_get_hub_descr(
36990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez			wusbhc, wValue, wIndex,
37090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez			(struct usb_hub_descriptor *) buf, wLength);
37190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
37290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case ClearHubFeature:
37390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = wusbhc_rh_clear_hub_feat(wusbhc, wValue);
37490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
37590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case GetHubStatus:
37690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength);
37790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
37890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
37990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case SetPortFeature:
38090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8,
38190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez						 (wIndex & 0xff) - 1);
38290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
38390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case ClearPortFeature:
38490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8,
38590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez						   (wIndex & 0xff) - 1);
38690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
38790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case GetPortStatus:
38890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1,
38990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez						   (u32 *)buf, wLength);
39090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		break;
39190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
39290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	case SetHubFeature:
39390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	default:
39490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) "
39590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez			"UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype,
39690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez			wValue, wIndex, buf, wLength);
39790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		/* dump_stack(); */
39890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		result = -ENOSYS;
39990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	}
40090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	return result;
40190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
40290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wusbhc_rh_control);
40390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
40490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezint wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx)
40590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
40690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
40790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n",
40890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		__func__, usb_hcd, wusbhc, port_idx);
40990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	WARN_ON(1);
41090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	return -ENOSYS;
41190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
41290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset);
41390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
41490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezstatic void wusb_port_init(struct wusb_port *port)
41590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
41690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	port->status |= USB_PORT_STAT_HIGH_SPEED;
41790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
41890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
41990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez/*
42090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez * Alloc fake port specific fields and status.
42190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez */
42290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezint wusbhc_rh_create(struct wusbhc *wusbhc)
42390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
42490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	int result = -ENOMEM;
42590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	size_t port_size, itr;
42690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]);
42790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	wusbhc->port = kzalloc(port_size, GFP_KERNEL);
42890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	if (wusbhc->port == NULL)
42990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		goto error_port_alloc;
43090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	for (itr = 0; itr < wusbhc->ports_max; itr++)
43190ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez		wusb_port_init(&wusbhc->port[itr]);
43290ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	result = 0;
43390ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezerror_port_alloc:
43490ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	return result;
43590ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
43690ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez
43790ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalezvoid wusbhc_rh_destroy(struct wusbhc *wusbhc)
43890ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez{
43990ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez	kfree(wusbhc->port);
44090ff96f22426a9d1a06df97dead0a9098facb567Inaky Perez-Gonzalez}
441