aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/wusbcore/rh.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/wusbcore/rh.c')
-rw-r--r--drivers/usb/wusbcore/rh.c104
1 files changed, 37 insertions, 67 deletions
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
index 267a64325106..95c6fa3bf6b2 100644
--- a/drivers/usb/wusbcore/rh.c
+++ b/drivers/usb/wusbcore/rh.c
@@ -71,19 +71,20 @@
71 */ 71 */
72#include "wusbhc.h" 72#include "wusbhc.h"
73 73
74#define D_LOCAL 0
75#include <linux/uwb/debug.h>
76
77/* 74/*
78 * Reset a fake port 75 * Reset a fake port
79 * 76 *
80 * This can be called to reset a port from any other state or to reset 77 * Using a Reset Device IE is too heavyweight as it causes the device
81 * it when connecting. In Wireless USB they are different; when doing 78 * to enter the UnConnected state and leave the cluster, this can mean
82 * a new connect that involves going over the authentication. When 79 * that when the device reconnects it is connected to a different fake
83 * just reseting, its a different story. 80 * port.
81 *
82 * Instead, reset authenticated devices with a SetAddress(0), followed
83 * by a SetAddresss(AuthAddr).
84 * 84 *
85 * The Linux USB stack resets a port twice before it considers it 85 * For unauthenticated devices just pretend to reset but do nothing.
86 * enabled, so we have to detect and ignore that. 86 * If the device initialization continues to fail it will eventually
87 * time out after TrustTimeout and enter the UnConnected state.
87 * 88 *
88 * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. 89 * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
89 * 90 *
@@ -97,20 +98,20 @@ static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
97{ 98{
98 int result = 0; 99 int result = 0;
99 struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); 100 struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx);
101 struct wusb_dev *wusb_dev = port->wusb_dev;
100 102
101 d_fnstart(3, wusbhc->dev, "(wusbhc %p port_idx %u)\n", 103 port->status |= USB_PORT_STAT_RESET;
102 wusbhc, port_idx); 104 port->change |= USB_PORT_STAT_C_RESET;
103 if (port->reset_count == 0) { 105
104 wusbhc_devconnect_auth(wusbhc, port_idx); 106 if (wusb_dev->addr & WUSB_DEV_ADDR_UNAUTH)
105 port->reset_count++; 107 result = 0;
106 } else if (port->reset_count == 1)
107 /* see header */
108 d_printf(2, wusbhc->dev, "Ignoring second reset on port_idx "
109 "%u\n", port_idx);
110 else 108 else
111 result = wusbhc_dev_reset(wusbhc, port_idx); 109 result = wusb_dev_update_address(wusbhc, wusb_dev);
112 d_fnend(3, wusbhc->dev, "(wusbhc %p port_idx %u) = %d\n", 110
113 wusbhc, port_idx, result); 111 port->status &= ~USB_PORT_STAT_RESET;
112 port->status |= USB_PORT_STAT_ENABLE;
113 port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE;
114
114 return result; 115 return result;
115} 116}
116 117
@@ -138,7 +139,6 @@ int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
138 size_t cnt, size; 139 size_t cnt, size;
139 unsigned long *buf = (unsigned long *) _buf; 140 unsigned long *buf = (unsigned long *) _buf;
140 141
141 d_fnstart(1, wusbhc->dev, "(wusbhc %p)\n", wusbhc);
142 /* WE DON'T LOCK, see comment */ 142 /* WE DON'T LOCK, see comment */
143 size = wusbhc->ports_max + 1 /* hub bit */; 143 size = wusbhc->ports_max + 1 /* hub bit */;
144 size = (size + 8 - 1) / 8; /* round to bytes */ 144 size = (size + 8 - 1) / 8; /* round to bytes */
@@ -147,8 +147,6 @@ int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
147 set_bit(cnt + 1, buf); 147 set_bit(cnt + 1, buf);
148 else 148 else
149 clear_bit(cnt + 1, buf); 149 clear_bit(cnt + 1, buf);
150 d_fnend(1, wusbhc->dev, "(wusbhc %p) %u, buffer:\n", wusbhc, (int)size);
151 d_dump(1, wusbhc->dev, _buf, size);
152 return size; 150 return size;
153} 151}
154EXPORT_SYMBOL_GPL(wusbhc_rh_status_data); 152EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
@@ -197,9 +195,7 @@ static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue,
197static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature) 195static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature)
198{ 196{
199 int result; 197 int result;
200 struct device *dev = wusbhc->dev;
201 198
202 d_fnstart(4, dev, "(%p, feature 0x%04u)\n", wusbhc, feature);
203 switch (feature) { 199 switch (feature) {
204 case C_HUB_LOCAL_POWER: 200 case C_HUB_LOCAL_POWER:
205 /* FIXME: maybe plug bit 0 to the power input status, 201 /* FIXME: maybe plug bit 0 to the power input status,
@@ -211,7 +207,6 @@ static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature)
211 default: 207 default:
212 result = -EPIPE; 208 result = -EPIPE;
213 } 209 }
214 d_fnend(4, dev, "(%p, feature 0x%04u), %d\n", wusbhc, feature, result);
215 return result; 210 return result;
216} 211}
217 212
@@ -238,14 +233,10 @@ static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf,
238static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature, 233static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature,
239 u8 selector, u8 port_idx) 234 u8 selector, u8 port_idx)
240{ 235{
241 int result = -EINVAL;
242 struct device *dev = wusbhc->dev; 236 struct device *dev = wusbhc->dev;
243 237
244 d_fnstart(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d)\n",
245 feature, selector, port_idx);
246
247 if (port_idx > wusbhc->ports_max) 238 if (port_idx > wusbhc->ports_max)
248 goto error; 239 return -EINVAL;
249 240
250 switch (feature) { 241 switch (feature) {
251 /* According to USB2.0[11.24.2.13]p2, these features 242 /* According to USB2.0[11.24.2.13]p2, these features
@@ -255,35 +246,27 @@ static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature,
255 case USB_PORT_FEAT_C_SUSPEND: 246 case USB_PORT_FEAT_C_SUSPEND:
256 case USB_PORT_FEAT_C_CONNECTION: 247 case USB_PORT_FEAT_C_CONNECTION:
257 case USB_PORT_FEAT_C_RESET: 248 case USB_PORT_FEAT_C_RESET:
258 result = 0; 249 return 0;
259 break;
260
261 case USB_PORT_FEAT_POWER: 250 case USB_PORT_FEAT_POWER:
262 /* No such thing, but we fake it works */ 251 /* No such thing, but we fake it works */
263 mutex_lock(&wusbhc->mutex); 252 mutex_lock(&wusbhc->mutex);
264 wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER; 253 wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER;
265 mutex_unlock(&wusbhc->mutex); 254 mutex_unlock(&wusbhc->mutex);
266 result = 0; 255 return 0;
267 break;
268 case USB_PORT_FEAT_RESET: 256 case USB_PORT_FEAT_RESET:
269 result = wusbhc_rh_port_reset(wusbhc, port_idx); 257 return wusbhc_rh_port_reset(wusbhc, port_idx);
270 break;
271 case USB_PORT_FEAT_ENABLE: 258 case USB_PORT_FEAT_ENABLE:
272 case USB_PORT_FEAT_SUSPEND: 259 case USB_PORT_FEAT_SUSPEND:
273 dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n", 260 dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n",
274 port_idx, feature, selector); 261 port_idx, feature, selector);
275 result = -ENOSYS; 262 return -ENOSYS;
276 break;
277 default: 263 default:
278 dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n", 264 dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n",
279 port_idx, feature, selector); 265 port_idx, feature, selector);
280 result = -EPIPE; 266 return -EPIPE;
281 break;
282 } 267 }
283error: 268
284 d_fnend(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d) = %d\n", 269 return 0;
285 feature, selector, port_idx, result);
286 return result;
287} 270}
288 271
289/* 272/*
@@ -294,17 +277,13 @@ error:
294static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, 277static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
295 u8 selector, u8 port_idx) 278 u8 selector, u8 port_idx)
296{ 279{
297 int result = -EINVAL; 280 int result = 0;
298 struct device *dev = wusbhc->dev; 281 struct device *dev = wusbhc->dev;
299 282
300 d_fnstart(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d)\n",
301 wusbhc, feature, selector, port_idx);
302
303 if (port_idx > wusbhc->ports_max) 283 if (port_idx > wusbhc->ports_max)
304 goto error; 284 return -EINVAL;
305 285
306 mutex_lock(&wusbhc->mutex); 286 mutex_lock(&wusbhc->mutex);
307 result = 0;
308 switch (feature) { 287 switch (feature) {
309 case USB_PORT_FEAT_POWER: /* fake port always on */ 288 case USB_PORT_FEAT_POWER: /* fake port always on */
310 /* According to USB2.0[11.24.2.7.1.4], no need to implement? */ 289 /* According to USB2.0[11.24.2.7.1.4], no need to implement? */
@@ -324,10 +303,8 @@ static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
324 break; 303 break;
325 case USB_PORT_FEAT_SUSPEND: 304 case USB_PORT_FEAT_SUSPEND:
326 case USB_PORT_FEAT_C_SUSPEND: 305 case USB_PORT_FEAT_C_SUSPEND:
327 case 0xffff: /* ??? FIXME */
328 dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n", 306 dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n",
329 port_idx, feature, selector); 307 port_idx, feature, selector);
330 /* dump_stack(); */
331 result = -ENOSYS; 308 result = -ENOSYS;
332 break; 309 break;
333 default: 310 default:
@@ -337,9 +314,7 @@ static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
337 break; 314 break;
338 } 315 }
339 mutex_unlock(&wusbhc->mutex); 316 mutex_unlock(&wusbhc->mutex);
340error: 317
341 d_fnend(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d) = "
342 "%d\n", wusbhc, feature, selector, port_idx, result);
343 return result; 318 return result;
344} 319}
345 320
@@ -351,22 +326,17 @@ error:
351static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx, 326static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx,
352 u32 *_buf, u16 wLength) 327 u32 *_buf, u16 wLength)
353{ 328{
354 int result = -EINVAL;
355 u16 *buf = (u16 *) _buf; 329 u16 *buf = (u16 *) _buf;
356 330
357 d_fnstart(1, wusbhc->dev, "(wusbhc %p port_idx %u wLength %u)\n",
358 wusbhc, port_idx, wLength);
359 if (port_idx > wusbhc->ports_max) 331 if (port_idx > wusbhc->ports_max)
360 goto error; 332 return -EINVAL;
333
361 mutex_lock(&wusbhc->mutex); 334 mutex_lock(&wusbhc->mutex);
362 buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status); 335 buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status);
363 buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change); 336 buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change);
364 result = 0;
365 mutex_unlock(&wusbhc->mutex); 337 mutex_unlock(&wusbhc->mutex);
366error: 338
367 d_fnend(1, wusbhc->dev, "(wusbhc %p) = %d, buffer:\n", wusbhc, result); 339 return 0;
368 d_dump(1, wusbhc->dev, _buf, wLength);
369 return result;
370} 340}
371 341
372/* 342/*