diff options
Diffstat (limited to 'drivers/usb/wusbcore/rh.c')
-rw-r--r-- | drivers/usb/wusbcore/rh.c | 104 |
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 | } |
154 | EXPORT_SYMBOL_GPL(wusbhc_rh_status_data); | 152 | EXPORT_SYMBOL_GPL(wusbhc_rh_status_data); |
@@ -197,9 +195,7 @@ static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue, | |||
197 | static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature) | 195 | static 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, | |||
238 | static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature, | 233 | static 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 | } |
283 | error: | 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: | |||
294 | static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, | 277 | static 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); |
340 | error: | 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: | |||
351 | static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx, | 326 | static 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); |
366 | error: | 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 | /* |