Deleted Added
full compact
usb_handle_request.c (186730) usb_handle_request.c (187173)
1/* $FreeBSD: head/sys/dev/usb2/core/usb2_handle_request.c 186730 2009-01-04 00:12:01Z alfred $ */
1/* $FreeBSD: head/sys/dev/usb2/core/usb2_handle_request.c 187173 2009-01-13 19:03:12Z thompsa $ */
2/*-
3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <dev/usb2/include/usb2_defs.h>
28#include <dev/usb2/include/usb2_mfunc.h>
29#include <dev/usb2/include/usb2_error.h>
30#include <dev/usb2/include/usb2_standard.h>
31
32#define USB_DEBUG_VAR usb2_debug
33
34#include <dev/usb2/core/usb2_core.h>
35#include <dev/usb2/core/usb2_process.h>
36#include <dev/usb2/core/usb2_busdma.h>
37#include <dev/usb2/core/usb2_transfer.h>
38#include <dev/usb2/core/usb2_device.h>
39#include <dev/usb2/core/usb2_debug.h>
40#include <dev/usb2/core/usb2_dynamic.h>
41#include <dev/usb2/core/usb2_hub.h>
42
43#include <dev/usb2/controller/usb2_controller.h>
44#include <dev/usb2/controller/usb2_bus.h>
45
46/* enum */
47
48enum {
49 ST_DATA,
50 ST_POST_STATUS,
51};
52
53/* function prototypes */
54
55static uint8_t usb2_handle_get_stall(struct usb2_device *, uint8_t);
56static usb2_error_t usb2_handle_remote_wakeup(struct usb2_xfer *, uint8_t);
57static usb2_error_t usb2_handle_request(struct usb2_xfer *);
58static usb2_error_t usb2_handle_set_config(struct usb2_xfer *, uint8_t);
59static usb2_error_t usb2_handle_set_stall(struct usb2_xfer *, uint8_t,
60 uint8_t);
61static usb2_error_t usb2_handle_iface_request(struct usb2_xfer *, void **,
62 uint16_t *, struct usb2_device_request, uint16_t,
63 uint8_t);
64
65/*------------------------------------------------------------------------*
66 * usb2_handle_request_callback
67 *
68 * This function is the USB callback for generic USB Device control
69 * transfers.
70 *------------------------------------------------------------------------*/
71void
72usb2_handle_request_callback(struct usb2_xfer *xfer)
73{
74 usb2_error_t err;
75
76 /* check the current transfer state */
77
78 switch (USB_GET_STATE(xfer)) {
79 case USB_ST_SETUP:
80 case USB_ST_TRANSFERRED:
81
82 /* handle the request */
83 err = usb2_handle_request(xfer);
84
85 if (err) {
86
87 if (err == USB_ERR_BAD_CONTEXT) {
88 /* we need to re-setup the control transfer */
2/*-
3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <dev/usb2/include/usb2_defs.h>
28#include <dev/usb2/include/usb2_mfunc.h>
29#include <dev/usb2/include/usb2_error.h>
30#include <dev/usb2/include/usb2_standard.h>
31
32#define USB_DEBUG_VAR usb2_debug
33
34#include <dev/usb2/core/usb2_core.h>
35#include <dev/usb2/core/usb2_process.h>
36#include <dev/usb2/core/usb2_busdma.h>
37#include <dev/usb2/core/usb2_transfer.h>
38#include <dev/usb2/core/usb2_device.h>
39#include <dev/usb2/core/usb2_debug.h>
40#include <dev/usb2/core/usb2_dynamic.h>
41#include <dev/usb2/core/usb2_hub.h>
42
43#include <dev/usb2/controller/usb2_controller.h>
44#include <dev/usb2/controller/usb2_bus.h>
45
46/* enum */
47
48enum {
49 ST_DATA,
50 ST_POST_STATUS,
51};
52
53/* function prototypes */
54
55static uint8_t usb2_handle_get_stall(struct usb2_device *, uint8_t);
56static usb2_error_t usb2_handle_remote_wakeup(struct usb2_xfer *, uint8_t);
57static usb2_error_t usb2_handle_request(struct usb2_xfer *);
58static usb2_error_t usb2_handle_set_config(struct usb2_xfer *, uint8_t);
59static usb2_error_t usb2_handle_set_stall(struct usb2_xfer *, uint8_t,
60 uint8_t);
61static usb2_error_t usb2_handle_iface_request(struct usb2_xfer *, void **,
62 uint16_t *, struct usb2_device_request, uint16_t,
63 uint8_t);
64
65/*------------------------------------------------------------------------*
66 * usb2_handle_request_callback
67 *
68 * This function is the USB callback for generic USB Device control
69 * transfers.
70 *------------------------------------------------------------------------*/
71void
72usb2_handle_request_callback(struct usb2_xfer *xfer)
73{
74 usb2_error_t err;
75
76 /* check the current transfer state */
77
78 switch (USB_GET_STATE(xfer)) {
79 case USB_ST_SETUP:
80 case USB_ST_TRANSFERRED:
81
82 /* handle the request */
83 err = usb2_handle_request(xfer);
84
85 if (err) {
86
87 if (err == USB_ERR_BAD_CONTEXT) {
88 /* we need to re-setup the control transfer */
89 usb2_needs_explore(xfer->udev->bus, 0);
89 usb2_needs_explore(xfer->xroot->bus, 0);
90 break;
91 }
92 /*
93 * If no control transfer is active,
94 * receive the next SETUP message:
95 */
96 goto tr_restart;
97 }
98 usb2_start_hardware(xfer);
99 break;
100
101 default:
102 if (xfer->error != USB_ERR_CANCELLED) {
103 /* should not happen - try stalling */
104 goto tr_restart;
105 }
106 break;
107 }
108 return;
109
110tr_restart:
111 xfer->frlengths[0] = sizeof(struct usb2_device_request);
112 xfer->nframes = 1;
113 xfer->flags.manual_status = 1;
114 xfer->flags.force_short_xfer = 0;
115 xfer->flags.stall_pipe = 1; /* cancel previous transfer, if any */
116 usb2_start_hardware(xfer);
117}
118
119/*------------------------------------------------------------------------*
120 * usb2_handle_set_config
121 *
122 * Returns:
123 * 0: Success
124 * Else: Failure
125 *------------------------------------------------------------------------*/
126static usb2_error_t
127usb2_handle_set_config(struct usb2_xfer *xfer, uint8_t conf_no)
128{
90 break;
91 }
92 /*
93 * If no control transfer is active,
94 * receive the next SETUP message:
95 */
96 goto tr_restart;
97 }
98 usb2_start_hardware(xfer);
99 break;
100
101 default:
102 if (xfer->error != USB_ERR_CANCELLED) {
103 /* should not happen - try stalling */
104 goto tr_restart;
105 }
106 break;
107 }
108 return;
109
110tr_restart:
111 xfer->frlengths[0] = sizeof(struct usb2_device_request);
112 xfer->nframes = 1;
113 xfer->flags.manual_status = 1;
114 xfer->flags.force_short_xfer = 0;
115 xfer->flags.stall_pipe = 1; /* cancel previous transfer, if any */
116 usb2_start_hardware(xfer);
117}
118
119/*------------------------------------------------------------------------*
120 * usb2_handle_set_config
121 *
122 * Returns:
123 * 0: Success
124 * Else: Failure
125 *------------------------------------------------------------------------*/
126static usb2_error_t
127usb2_handle_set_config(struct usb2_xfer *xfer, uint8_t conf_no)
128{
129 struct usb2_device *udev = xfer->xroot->udev;
129 usb2_error_t err = 0;
130
131 /*
132 * We need to protect against other threads doing probe and
133 * attach:
134 */
135 USB_XFER_UNLOCK(xfer);
136 mtx_lock(&Giant); /* XXX */
130 usb2_error_t err = 0;
131
132 /*
133 * We need to protect against other threads doing probe and
134 * attach:
135 */
136 USB_XFER_UNLOCK(xfer);
137 mtx_lock(&Giant); /* XXX */
137 sx_xlock(xfer->udev->default_sx + 1);
138 sx_xlock(udev->default_sx + 1);
138
139 if (conf_no == USB_UNCONFIG_NO) {
140 conf_no = USB_UNCONFIG_INDEX;
141 } else {
142 /*
143 * The relationship between config number and config index
144 * is very simple in our case:
145 */
146 conf_no--;
147 }
148
139
140 if (conf_no == USB_UNCONFIG_NO) {
141 conf_no = USB_UNCONFIG_INDEX;
142 } else {
143 /*
144 * The relationship between config number and config index
145 * is very simple in our case:
146 */
147 conf_no--;
148 }
149
149 if (usb2_set_config_index(xfer->udev, conf_no)) {
150 if (usb2_set_config_index(udev, conf_no)) {
150 DPRINTF("set config %d failed\n", conf_no);
151 err = USB_ERR_STALLED;
152 goto done;
153 }
151 DPRINTF("set config %d failed\n", conf_no);
152 err = USB_ERR_STALLED;
153 goto done;
154 }
154 if (usb2_probe_and_attach(xfer->udev, USB_IFACE_INDEX_ANY)) {
155 if (usb2_probe_and_attach(udev, USB_IFACE_INDEX_ANY)) {
155 DPRINTF("probe and attach failed\n");
156 err = USB_ERR_STALLED;
157 goto done;
158 }
159done:
160 mtx_unlock(&Giant); /* XXX */
156 DPRINTF("probe and attach failed\n");
157 err = USB_ERR_STALLED;
158 goto done;
159 }
160done:
161 mtx_unlock(&Giant); /* XXX */
161 sx_unlock(xfer->udev->default_sx + 1);
162 sx_unlock(udev->default_sx + 1);
162 USB_XFER_LOCK(xfer);
163 return (err);
164}
165
166/*------------------------------------------------------------------------*
167 * usb2_handle_iface_request
168 *
169 * Returns:
170 * 0: Success
171 * Else: Failure
172 *------------------------------------------------------------------------*/
173static usb2_error_t
174usb2_handle_iface_request(struct usb2_xfer *xfer,
175 void **ppdata, uint16_t *plen,
176 struct usb2_device_request req, uint16_t off, uint8_t state)
177{
178 struct usb2_interface *iface;
179 struct usb2_interface *iface_parent; /* parent interface */
163 USB_XFER_LOCK(xfer);
164 return (err);
165}
166
167/*------------------------------------------------------------------------*
168 * usb2_handle_iface_request
169 *
170 * Returns:
171 * 0: Success
172 * Else: Failure
173 *------------------------------------------------------------------------*/
174static usb2_error_t
175usb2_handle_iface_request(struct usb2_xfer *xfer,
176 void **ppdata, uint16_t *plen,
177 struct usb2_device_request req, uint16_t off, uint8_t state)
178{
179 struct usb2_interface *iface;
180 struct usb2_interface *iface_parent; /* parent interface */
180 struct usb2_device *udev = xfer->udev;
181 struct usb2_device *udev = xfer->xroot->udev;
181 int error;
182 uint8_t iface_index;
183
184 if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
185 iface_index = req.wIndex[0]; /* unicast */
186 } else {
187 iface_index = 0; /* broadcast */
188 }
189
190 /*
191 * We need to protect against other threads doing probe and
192 * attach:
193 */
194 USB_XFER_UNLOCK(xfer);
195 mtx_lock(&Giant); /* XXX */
196 sx_xlock(udev->default_sx + 1);
197
198 error = ENXIO;
199
200tr_repeat:
201 iface = usb2_get_iface(udev, iface_index);
202 if ((iface == NULL) ||
203 (iface->idesc == NULL)) {
204 /* end of interfaces non-existing interface */
205 goto tr_stalled;
206 }
207 /* forward request to interface, if any */
208
209 if ((error != 0) &&
210 (error != ENOTTY) &&
211 (iface->subdev != NULL) &&
212 device_is_attached(iface->subdev)) {
213#if 0
214 DEVMETHOD(usb2_handle_request, NULL); /* dummy */
215#endif
216 error = USB2_HANDLE_REQUEST(iface->subdev,
217 &req, ppdata, plen,
218 off, (state == ST_POST_STATUS));
219 }
220 iface_parent = usb2_get_iface(udev, iface->parent_iface_index);
221
222 if ((iface_parent == NULL) ||
223 (iface_parent->idesc == NULL)) {
224 /* non-existing interface */
225 iface_parent = NULL;
226 }
227 /* forward request to parent interface, if any */
228
229 if ((error != 0) &&
230 (error != ENOTTY) &&
231 (iface_parent != NULL) &&
232 (iface_parent->subdev != NULL) &&
233 ((req.bmRequestType & 0x1F) == UT_INTERFACE) &&
234 (iface_parent->subdev != iface->subdev) &&
235 device_is_attached(iface_parent->subdev)) {
236 error = USB2_HANDLE_REQUEST(iface_parent->subdev,
237 &req, ppdata, plen, off,
238 (state == ST_POST_STATUS));
239 }
240 if (error == 0) {
241 /* negativly adjust pointer and length */
242 *ppdata = ((uint8_t *)(*ppdata)) - off;
243 *plen += off;
244 goto tr_valid;
245 } else if (error == ENOTTY) {
246 goto tr_stalled;
247 }
248 if ((req.bmRequestType & 0x1F) != UT_INTERFACE) {
249 iface_index++; /* iterate */
250 goto tr_repeat;
251 }
252 if (state == ST_POST_STATUS) {
253 /* we are complete */
254 goto tr_valid;
255 }
256 switch (req.bmRequestType) {
257 case UT_WRITE_INTERFACE:
258 switch (req.bRequest) {
259 case UR_SET_INTERFACE:
260 /*
261 * Handle special case. If we have parent interface
262 * we just reset the endpoints, because this is a
263 * multi interface device and re-attaching only a
264 * part of the device is not possible. Also if the
265 * alternate setting is the same like before we just
266 * reset the interface endoints.
267 */
268 if ((iface_parent != NULL) ||
269 (iface->alt_index == req.wValue[0])) {
270 error = usb2_reset_iface_endpoints(udev,
271 iface_index);
272 if (error) {
273 DPRINTF("alt setting failed %s\n",
274 usb2_errstr(error));
275 goto tr_stalled;
276 }
277 break;
278 }
279 error = usb2_set_alt_interface_index(udev,
280 iface_index, req.wValue[0]);
281 if (error) {
282 DPRINTF("alt setting failed %s\n",
283 usb2_errstr(error));
284 goto tr_stalled;
285 }
286 error = usb2_probe_and_attach(udev,
287 iface_index);
288 if (error) {
289 DPRINTF("alt setting probe failed\n");
290 goto tr_stalled;
291 }
292 break;
293 default:
294 goto tr_stalled;
295 }
296 break;
297
298 case UT_READ_INTERFACE:
299 switch (req.bRequest) {
300 case UR_GET_INTERFACE:
301 *ppdata = &iface->alt_index;
302 *plen = 1;
303 break;
304
305 default:
306 goto tr_stalled;
307 }
308 break;
309 default:
310 goto tr_stalled;
311 }
312tr_valid:
313 mtx_unlock(&Giant);
314 sx_unlock(udev->default_sx + 1);
315 USB_XFER_LOCK(xfer);
316 return (0);
317
318tr_stalled:
319 mtx_unlock(&Giant);
320 sx_unlock(udev->default_sx + 1);
321 USB_XFER_LOCK(xfer);
322 return (USB_ERR_STALLED);
323}
324
325/*------------------------------------------------------------------------*
326 * usb2_handle_stall
327 *
328 * Returns:
329 * 0: Success
330 * Else: Failure
331 *------------------------------------------------------------------------*/
332static usb2_error_t
333usb2_handle_set_stall(struct usb2_xfer *xfer, uint8_t ep, uint8_t do_stall)
334{
182 int error;
183 uint8_t iface_index;
184
185 if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
186 iface_index = req.wIndex[0]; /* unicast */
187 } else {
188 iface_index = 0; /* broadcast */
189 }
190
191 /*
192 * We need to protect against other threads doing probe and
193 * attach:
194 */
195 USB_XFER_UNLOCK(xfer);
196 mtx_lock(&Giant); /* XXX */
197 sx_xlock(udev->default_sx + 1);
198
199 error = ENXIO;
200
201tr_repeat:
202 iface = usb2_get_iface(udev, iface_index);
203 if ((iface == NULL) ||
204 (iface->idesc == NULL)) {
205 /* end of interfaces non-existing interface */
206 goto tr_stalled;
207 }
208 /* forward request to interface, if any */
209
210 if ((error != 0) &&
211 (error != ENOTTY) &&
212 (iface->subdev != NULL) &&
213 device_is_attached(iface->subdev)) {
214#if 0
215 DEVMETHOD(usb2_handle_request, NULL); /* dummy */
216#endif
217 error = USB2_HANDLE_REQUEST(iface->subdev,
218 &req, ppdata, plen,
219 off, (state == ST_POST_STATUS));
220 }
221 iface_parent = usb2_get_iface(udev, iface->parent_iface_index);
222
223 if ((iface_parent == NULL) ||
224 (iface_parent->idesc == NULL)) {
225 /* non-existing interface */
226 iface_parent = NULL;
227 }
228 /* forward request to parent interface, if any */
229
230 if ((error != 0) &&
231 (error != ENOTTY) &&
232 (iface_parent != NULL) &&
233 (iface_parent->subdev != NULL) &&
234 ((req.bmRequestType & 0x1F) == UT_INTERFACE) &&
235 (iface_parent->subdev != iface->subdev) &&
236 device_is_attached(iface_parent->subdev)) {
237 error = USB2_HANDLE_REQUEST(iface_parent->subdev,
238 &req, ppdata, plen, off,
239 (state == ST_POST_STATUS));
240 }
241 if (error == 0) {
242 /* negativly adjust pointer and length */
243 *ppdata = ((uint8_t *)(*ppdata)) - off;
244 *plen += off;
245 goto tr_valid;
246 } else if (error == ENOTTY) {
247 goto tr_stalled;
248 }
249 if ((req.bmRequestType & 0x1F) != UT_INTERFACE) {
250 iface_index++; /* iterate */
251 goto tr_repeat;
252 }
253 if (state == ST_POST_STATUS) {
254 /* we are complete */
255 goto tr_valid;
256 }
257 switch (req.bmRequestType) {
258 case UT_WRITE_INTERFACE:
259 switch (req.bRequest) {
260 case UR_SET_INTERFACE:
261 /*
262 * Handle special case. If we have parent interface
263 * we just reset the endpoints, because this is a
264 * multi interface device and re-attaching only a
265 * part of the device is not possible. Also if the
266 * alternate setting is the same like before we just
267 * reset the interface endoints.
268 */
269 if ((iface_parent != NULL) ||
270 (iface->alt_index == req.wValue[0])) {
271 error = usb2_reset_iface_endpoints(udev,
272 iface_index);
273 if (error) {
274 DPRINTF("alt setting failed %s\n",
275 usb2_errstr(error));
276 goto tr_stalled;
277 }
278 break;
279 }
280 error = usb2_set_alt_interface_index(udev,
281 iface_index, req.wValue[0]);
282 if (error) {
283 DPRINTF("alt setting failed %s\n",
284 usb2_errstr(error));
285 goto tr_stalled;
286 }
287 error = usb2_probe_and_attach(udev,
288 iface_index);
289 if (error) {
290 DPRINTF("alt setting probe failed\n");
291 goto tr_stalled;
292 }
293 break;
294 default:
295 goto tr_stalled;
296 }
297 break;
298
299 case UT_READ_INTERFACE:
300 switch (req.bRequest) {
301 case UR_GET_INTERFACE:
302 *ppdata = &iface->alt_index;
303 *plen = 1;
304 break;
305
306 default:
307 goto tr_stalled;
308 }
309 break;
310 default:
311 goto tr_stalled;
312 }
313tr_valid:
314 mtx_unlock(&Giant);
315 sx_unlock(udev->default_sx + 1);
316 USB_XFER_LOCK(xfer);
317 return (0);
318
319tr_stalled:
320 mtx_unlock(&Giant);
321 sx_unlock(udev->default_sx + 1);
322 USB_XFER_LOCK(xfer);
323 return (USB_ERR_STALLED);
324}
325
326/*------------------------------------------------------------------------*
327 * usb2_handle_stall
328 *
329 * Returns:
330 * 0: Success
331 * Else: Failure
332 *------------------------------------------------------------------------*/
333static usb2_error_t
334usb2_handle_set_stall(struct usb2_xfer *xfer, uint8_t ep, uint8_t do_stall)
335{
336 struct usb2_device *udev = xfer->xroot->udev;
335 usb2_error_t err;
336
337 USB_XFER_UNLOCK(xfer);
337 usb2_error_t err;
338
339 USB_XFER_UNLOCK(xfer);
338 err = usb2_set_endpoint_stall(xfer->udev,
339 usb2_get_pipe_by_addr(xfer->udev, ep), do_stall);
340 err = usb2_set_endpoint_stall(udev,
341 usb2_get_pipe_by_addr(udev, ep), do_stall);
340 USB_XFER_LOCK(xfer);
341 return (err);
342}
343
344/*------------------------------------------------------------------------*
345 * usb2_handle_get_stall
346 *
347 * Returns:
348 * 0: Success
349 * Else: Failure
350 *------------------------------------------------------------------------*/
351static uint8_t
352usb2_handle_get_stall(struct usb2_device *udev, uint8_t ea_val)
353{
354 struct usb2_pipe *pipe;
355 uint8_t halted;
356
357 pipe = usb2_get_pipe_by_addr(udev, ea_val);
358 if (pipe == NULL) {
359 /* nothing to do */
360 return (0);
361 }
362 USB_BUS_LOCK(udev->bus);
363 halted = pipe->is_stalled;
364 USB_BUS_UNLOCK(udev->bus);
365
366 return (halted);
367}
368
369/*------------------------------------------------------------------------*
370 * usb2_handle_remote_wakeup
371 *
372 * Returns:
373 * 0: Success
374 * Else: Failure
375 *------------------------------------------------------------------------*/
376static usb2_error_t
377usb2_handle_remote_wakeup(struct usb2_xfer *xfer, uint8_t is_on)
378{
379 struct usb2_device *udev;
380 struct usb2_bus *bus;
381
342 USB_XFER_LOCK(xfer);
343 return (err);
344}
345
346/*------------------------------------------------------------------------*
347 * usb2_handle_get_stall
348 *
349 * Returns:
350 * 0: Success
351 * Else: Failure
352 *------------------------------------------------------------------------*/
353static uint8_t
354usb2_handle_get_stall(struct usb2_device *udev, uint8_t ea_val)
355{
356 struct usb2_pipe *pipe;
357 uint8_t halted;
358
359 pipe = usb2_get_pipe_by_addr(udev, ea_val);
360 if (pipe == NULL) {
361 /* nothing to do */
362 return (0);
363 }
364 USB_BUS_LOCK(udev->bus);
365 halted = pipe->is_stalled;
366 USB_BUS_UNLOCK(udev->bus);
367
368 return (halted);
369}
370
371/*------------------------------------------------------------------------*
372 * usb2_handle_remote_wakeup
373 *
374 * Returns:
375 * 0: Success
376 * Else: Failure
377 *------------------------------------------------------------------------*/
378static usb2_error_t
379usb2_handle_remote_wakeup(struct usb2_xfer *xfer, uint8_t is_on)
380{
381 struct usb2_device *udev;
382 struct usb2_bus *bus;
383
382 udev = xfer->udev;
384 udev = xfer->xroot->udev;
383 bus = udev->bus;
384
385 USB_BUS_LOCK(bus);
386
387 if (is_on) {
388 udev->flags.remote_wakeup = 1;
389 } else {
390 udev->flags.remote_wakeup = 0;
391 }
392
393 USB_BUS_UNLOCK(bus);
394
395 /* In case we are out of sync, update the power state. */
396
397 usb2_bus_power_update(udev->bus);
398
399 return (0); /* success */
400}
401
402/*------------------------------------------------------------------------*
403 * usb2_handle_request
404 *
405 * Internal state sequence:
406 *
407 * ST_DATA -> ST_POST_STATUS
408 *
409 * Returns:
410 * 0: Ready to start hardware
411 * Else: Stall current transfer, if any
412 *------------------------------------------------------------------------*/
413static usb2_error_t
414usb2_handle_request(struct usb2_xfer *xfer)
415{
416 struct usb2_device_request req;
417 struct usb2_device *udev;
418 const void *src_zcopy; /* zero-copy source pointer */
419 const void *src_mcopy; /* non zero-copy source pointer */
420 uint16_t off; /* data offset */
421 uint16_t rem; /* data remainder */
422 uint16_t max_len; /* max fragment length */
423 uint16_t wValue;
424 uint16_t wIndex;
425 uint8_t state;
426 usb2_error_t err;
427 union {
428 uWord wStatus;
429 uint8_t buf[2];
430 } temp;
431
432 /*
433 * Filter the USB transfer state into
434 * something which we understand:
435 */
436
437 switch (USB_GET_STATE(xfer)) {
438 case USB_ST_SETUP:
439 state = ST_DATA;
440
441 if (!xfer->flags_int.control_act) {
442 /* nothing to do */
443 goto tr_stalled;
444 }
445 break;
446
447 default: /* USB_ST_TRANSFERRED */
448 if (!xfer->flags_int.control_act) {
449 state = ST_POST_STATUS;
450 } else {
451 state = ST_DATA;
452 }
453 break;
454 }
455
456 /* reset frame stuff */
457
458 xfer->frlengths[0] = 0;
459
460 usb2_set_frame_offset(xfer, 0, 0);
461 usb2_set_frame_offset(xfer, sizeof(req), 1);
462
463 /* get the current request, if any */
464
465 usb2_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
466
467 if (xfer->flags_int.control_rem == 0xFFFF) {
468 /* first time - not initialised */
469 rem = UGETW(req.wLength);
470 off = 0;
471 } else {
472 /* not first time - initialised */
473 rem = xfer->flags_int.control_rem;
474 off = UGETW(req.wLength) - rem;
475 }
476
477 /* set some defaults */
478
479 max_len = 0;
480 src_zcopy = NULL;
481 src_mcopy = NULL;
385 bus = udev->bus;
386
387 USB_BUS_LOCK(bus);
388
389 if (is_on) {
390 udev->flags.remote_wakeup = 1;
391 } else {
392 udev->flags.remote_wakeup = 0;
393 }
394
395 USB_BUS_UNLOCK(bus);
396
397 /* In case we are out of sync, update the power state. */
398
399 usb2_bus_power_update(udev->bus);
400
401 return (0); /* success */
402}
403
404/*------------------------------------------------------------------------*
405 * usb2_handle_request
406 *
407 * Internal state sequence:
408 *
409 * ST_DATA -> ST_POST_STATUS
410 *
411 * Returns:
412 * 0: Ready to start hardware
413 * Else: Stall current transfer, if any
414 *------------------------------------------------------------------------*/
415static usb2_error_t
416usb2_handle_request(struct usb2_xfer *xfer)
417{
418 struct usb2_device_request req;
419 struct usb2_device *udev;
420 const void *src_zcopy; /* zero-copy source pointer */
421 const void *src_mcopy; /* non zero-copy source pointer */
422 uint16_t off; /* data offset */
423 uint16_t rem; /* data remainder */
424 uint16_t max_len; /* max fragment length */
425 uint16_t wValue;
426 uint16_t wIndex;
427 uint8_t state;
428 usb2_error_t err;
429 union {
430 uWord wStatus;
431 uint8_t buf[2];
432 } temp;
433
434 /*
435 * Filter the USB transfer state into
436 * something which we understand:
437 */
438
439 switch (USB_GET_STATE(xfer)) {
440 case USB_ST_SETUP:
441 state = ST_DATA;
442
443 if (!xfer->flags_int.control_act) {
444 /* nothing to do */
445 goto tr_stalled;
446 }
447 break;
448
449 default: /* USB_ST_TRANSFERRED */
450 if (!xfer->flags_int.control_act) {
451 state = ST_POST_STATUS;
452 } else {
453 state = ST_DATA;
454 }
455 break;
456 }
457
458 /* reset frame stuff */
459
460 xfer->frlengths[0] = 0;
461
462 usb2_set_frame_offset(xfer, 0, 0);
463 usb2_set_frame_offset(xfer, sizeof(req), 1);
464
465 /* get the current request, if any */
466
467 usb2_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
468
469 if (xfer->flags_int.control_rem == 0xFFFF) {
470 /* first time - not initialised */
471 rem = UGETW(req.wLength);
472 off = 0;
473 } else {
474 /* not first time - initialised */
475 rem = xfer->flags_int.control_rem;
476 off = UGETW(req.wLength) - rem;
477 }
478
479 /* set some defaults */
480
481 max_len = 0;
482 src_zcopy = NULL;
483 src_mcopy = NULL;
482 udev = xfer->udev;
484 udev = xfer->xroot->udev;
483
484 /* get some request fields decoded */
485
486 wValue = UGETW(req.wValue);
487 wIndex = UGETW(req.wIndex);
488
489 DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x "
490 "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType,
491 req.bRequest, wValue, wIndex, off, rem, state);
492
493 /* demultiplex the control request */
494
495 switch (req.bmRequestType) {
496 case UT_READ_DEVICE:
497 if (state != ST_DATA) {
498 break;
499 }
500 switch (req.bRequest) {
501 case UR_GET_DESCRIPTOR:
502 goto tr_handle_get_descriptor;
503 case UR_GET_CONFIG:
504 goto tr_handle_get_config;
505 case UR_GET_STATUS:
506 goto tr_handle_get_status;
507 default:
508 goto tr_stalled;
509 }
510 break;
511
512 case UT_WRITE_DEVICE:
513 switch (req.bRequest) {
514 case UR_SET_ADDRESS:
515 goto tr_handle_set_address;
516 case UR_SET_CONFIG:
517 goto tr_handle_set_config;
518 case UR_CLEAR_FEATURE:
519 switch (wValue) {
520 case UF_DEVICE_REMOTE_WAKEUP:
521 goto tr_handle_clear_wakeup;
522 default:
523 goto tr_stalled;
524 }
525 break;
526 case UR_SET_FEATURE:
527 switch (wValue) {
528 case UF_DEVICE_REMOTE_WAKEUP:
529 goto tr_handle_set_wakeup;
530 default:
531 goto tr_stalled;
532 }
533 break;
534 default:
535 goto tr_stalled;
536 }
537 break;
538
539 case UT_WRITE_ENDPOINT:
540 switch (req.bRequest) {
541 case UR_CLEAR_FEATURE:
542 switch (wValue) {
543 case UF_ENDPOINT_HALT:
544 goto tr_handle_clear_halt;
545 default:
546 goto tr_stalled;
547 }
548 break;
549 case UR_SET_FEATURE:
550 switch (wValue) {
551 case UF_ENDPOINT_HALT:
552 goto tr_handle_set_halt;
553 default:
554 goto tr_stalled;
555 }
556 break;
557 default:
558 goto tr_stalled;
559 }
560 break;
561
562 case UT_READ_ENDPOINT:
563 switch (req.bRequest) {
564 case UR_GET_STATUS:
565 goto tr_handle_get_ep_status;
566 default:
567 goto tr_stalled;
568 }
569 break;
570 default:
571 /* we use "USB_ADD_BYTES" to de-const the src_zcopy */
572 err = usb2_handle_iface_request(xfer,
573 USB_ADD_BYTES(&src_zcopy, 0),
574 &max_len, req, off, state);
575 if (err == 0) {
576 goto tr_valid;
577 }
578 /*
579 * Reset zero-copy pointer and max length
580 * variable in case they were unintentionally
581 * set:
582 */
583 src_zcopy = NULL;
584 max_len = 0;
585
586 /*
587 * Check if we have a vendor specific
588 * descriptor:
589 */
590 goto tr_handle_get_descriptor;
591 }
592 goto tr_valid;
593
594tr_handle_get_descriptor:
595 (usb2_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len);
596 if (src_zcopy == NULL) {
597 goto tr_stalled;
598 }
599 goto tr_valid;
600
601tr_handle_get_config:
602 temp.buf[0] = udev->curr_config_no;
603 src_mcopy = temp.buf;
604 max_len = 1;
605 goto tr_valid;
606
607tr_handle_get_status:
608
609 wValue = 0;
610
611 USB_BUS_LOCK(udev->bus);
612 if (udev->flags.remote_wakeup) {
613 wValue |= UDS_REMOTE_WAKEUP;
614 }
615 if (udev->flags.self_powered) {
616 wValue |= UDS_SELF_POWERED;
617 }
618 USB_BUS_UNLOCK(udev->bus);
619
620 USETW(temp.wStatus, wValue);
621 src_mcopy = temp.wStatus;
622 max_len = sizeof(temp.wStatus);
623 goto tr_valid;
624
625tr_handle_set_address:
626 if (state == ST_DATA) {
627 if (wValue >= 0x80) {
628 /* invalid value */
629 goto tr_stalled;
630 } else if (udev->curr_config_no != 0) {
631 /* we are configured ! */
632 goto tr_stalled;
633 }
634 } else if (state == ST_POST_STATUS) {
635 udev->address = (wValue & 0x7F);
636 goto tr_bad_context;
637 }
638 goto tr_valid;
639
640tr_handle_set_config:
641 if (state == ST_DATA) {
642 if (usb2_handle_set_config(xfer, req.wValue[0])) {
643 goto tr_stalled;
644 }
645 }
646 goto tr_valid;
647
648tr_handle_clear_halt:
649 if (state == ST_DATA) {
650 if (usb2_handle_set_stall(xfer, req.wIndex[0], 0)) {
651 goto tr_stalled;
652 }
653 }
654 goto tr_valid;
655
656tr_handle_clear_wakeup:
657 if (state == ST_DATA) {
658 if (usb2_handle_remote_wakeup(xfer, 0)) {
659 goto tr_stalled;
660 }
661 }
662 goto tr_valid;
663
664tr_handle_set_halt:
665 if (state == ST_DATA) {
666 if (usb2_handle_set_stall(xfer, req.wIndex[0], 1)) {
667 goto tr_stalled;
668 }
669 }
670 goto tr_valid;
671
672tr_handle_set_wakeup:
673 if (state == ST_DATA) {
674 if (usb2_handle_remote_wakeup(xfer, 1)) {
675 goto tr_stalled;
676 }
677 }
678 goto tr_valid;
679
680tr_handle_get_ep_status:
681 if (state == ST_DATA) {
682 temp.wStatus[0] =
683 usb2_handle_get_stall(udev, req.wIndex[0]);
684 temp.wStatus[1] = 0;
685 src_mcopy = temp.wStatus;
686 max_len = sizeof(temp.wStatus);
687 }
688 goto tr_valid;
689
690tr_valid:
691 if (state == ST_POST_STATUS) {
692 goto tr_stalled;
693 }
694 /* subtract offset from length */
695
696 max_len -= off;
697
698 /* Compute the real maximum data length */
699
700 if (max_len > xfer->max_data_length) {
701 max_len = xfer->max_data_length;
702 }
703 if (max_len > rem) {
704 max_len = rem;
705 }
706 /*
707 * If the remainder is greater than the maximum data length,
708 * we need to truncate the value for the sake of the
709 * comparison below:
710 */
711 if (rem > xfer->max_data_length) {
712 rem = xfer->max_data_length;
713 }
714 if (rem != max_len) {
715 /*
716 * If we don't transfer the data we can transfer, then
717 * the transfer is short !
718 */
719 xfer->flags.force_short_xfer = 1;
720 xfer->nframes = 2;
721 } else {
722 /*
723 * Default case
724 */
725 xfer->flags.force_short_xfer = 0;
726 xfer->nframes = max_len ? 2 : 1;
727 }
728 if (max_len > 0) {
729 if (src_mcopy) {
730 src_mcopy = USB_ADD_BYTES(src_mcopy, off);
731 usb2_copy_in(xfer->frbuffers + 1, 0,
732 src_mcopy, max_len);
733 } else {
734 usb2_set_frame_data(xfer,
735 USB_ADD_BYTES(src_zcopy, off), 1);
736 }
737 xfer->frlengths[1] = max_len;
738 } else {
739 /* the end is reached, send status */
740 xfer->flags.manual_status = 0;
741 xfer->frlengths[1] = 0;
742 }
743 DPRINTF("success\n");
744 return (0); /* success */
745
746tr_stalled:
747 DPRINTF("%s\n", (state == ST_POST_STATUS) ?
748 "complete" : "stalled");
749 return (USB_ERR_STALLED);
750
751tr_bad_context:
752 DPRINTF("bad context\n");
753 return (USB_ERR_BAD_CONTEXT);
754}
485
486 /* get some request fields decoded */
487
488 wValue = UGETW(req.wValue);
489 wIndex = UGETW(req.wIndex);
490
491 DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x "
492 "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType,
493 req.bRequest, wValue, wIndex, off, rem, state);
494
495 /* demultiplex the control request */
496
497 switch (req.bmRequestType) {
498 case UT_READ_DEVICE:
499 if (state != ST_DATA) {
500 break;
501 }
502 switch (req.bRequest) {
503 case UR_GET_DESCRIPTOR:
504 goto tr_handle_get_descriptor;
505 case UR_GET_CONFIG:
506 goto tr_handle_get_config;
507 case UR_GET_STATUS:
508 goto tr_handle_get_status;
509 default:
510 goto tr_stalled;
511 }
512 break;
513
514 case UT_WRITE_DEVICE:
515 switch (req.bRequest) {
516 case UR_SET_ADDRESS:
517 goto tr_handle_set_address;
518 case UR_SET_CONFIG:
519 goto tr_handle_set_config;
520 case UR_CLEAR_FEATURE:
521 switch (wValue) {
522 case UF_DEVICE_REMOTE_WAKEUP:
523 goto tr_handle_clear_wakeup;
524 default:
525 goto tr_stalled;
526 }
527 break;
528 case UR_SET_FEATURE:
529 switch (wValue) {
530 case UF_DEVICE_REMOTE_WAKEUP:
531 goto tr_handle_set_wakeup;
532 default:
533 goto tr_stalled;
534 }
535 break;
536 default:
537 goto tr_stalled;
538 }
539 break;
540
541 case UT_WRITE_ENDPOINT:
542 switch (req.bRequest) {
543 case UR_CLEAR_FEATURE:
544 switch (wValue) {
545 case UF_ENDPOINT_HALT:
546 goto tr_handle_clear_halt;
547 default:
548 goto tr_stalled;
549 }
550 break;
551 case UR_SET_FEATURE:
552 switch (wValue) {
553 case UF_ENDPOINT_HALT:
554 goto tr_handle_set_halt;
555 default:
556 goto tr_stalled;
557 }
558 break;
559 default:
560 goto tr_stalled;
561 }
562 break;
563
564 case UT_READ_ENDPOINT:
565 switch (req.bRequest) {
566 case UR_GET_STATUS:
567 goto tr_handle_get_ep_status;
568 default:
569 goto tr_stalled;
570 }
571 break;
572 default:
573 /* we use "USB_ADD_BYTES" to de-const the src_zcopy */
574 err = usb2_handle_iface_request(xfer,
575 USB_ADD_BYTES(&src_zcopy, 0),
576 &max_len, req, off, state);
577 if (err == 0) {
578 goto tr_valid;
579 }
580 /*
581 * Reset zero-copy pointer and max length
582 * variable in case they were unintentionally
583 * set:
584 */
585 src_zcopy = NULL;
586 max_len = 0;
587
588 /*
589 * Check if we have a vendor specific
590 * descriptor:
591 */
592 goto tr_handle_get_descriptor;
593 }
594 goto tr_valid;
595
596tr_handle_get_descriptor:
597 (usb2_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len);
598 if (src_zcopy == NULL) {
599 goto tr_stalled;
600 }
601 goto tr_valid;
602
603tr_handle_get_config:
604 temp.buf[0] = udev->curr_config_no;
605 src_mcopy = temp.buf;
606 max_len = 1;
607 goto tr_valid;
608
609tr_handle_get_status:
610
611 wValue = 0;
612
613 USB_BUS_LOCK(udev->bus);
614 if (udev->flags.remote_wakeup) {
615 wValue |= UDS_REMOTE_WAKEUP;
616 }
617 if (udev->flags.self_powered) {
618 wValue |= UDS_SELF_POWERED;
619 }
620 USB_BUS_UNLOCK(udev->bus);
621
622 USETW(temp.wStatus, wValue);
623 src_mcopy = temp.wStatus;
624 max_len = sizeof(temp.wStatus);
625 goto tr_valid;
626
627tr_handle_set_address:
628 if (state == ST_DATA) {
629 if (wValue >= 0x80) {
630 /* invalid value */
631 goto tr_stalled;
632 } else if (udev->curr_config_no != 0) {
633 /* we are configured ! */
634 goto tr_stalled;
635 }
636 } else if (state == ST_POST_STATUS) {
637 udev->address = (wValue & 0x7F);
638 goto tr_bad_context;
639 }
640 goto tr_valid;
641
642tr_handle_set_config:
643 if (state == ST_DATA) {
644 if (usb2_handle_set_config(xfer, req.wValue[0])) {
645 goto tr_stalled;
646 }
647 }
648 goto tr_valid;
649
650tr_handle_clear_halt:
651 if (state == ST_DATA) {
652 if (usb2_handle_set_stall(xfer, req.wIndex[0], 0)) {
653 goto tr_stalled;
654 }
655 }
656 goto tr_valid;
657
658tr_handle_clear_wakeup:
659 if (state == ST_DATA) {
660 if (usb2_handle_remote_wakeup(xfer, 0)) {
661 goto tr_stalled;
662 }
663 }
664 goto tr_valid;
665
666tr_handle_set_halt:
667 if (state == ST_DATA) {
668 if (usb2_handle_set_stall(xfer, req.wIndex[0], 1)) {
669 goto tr_stalled;
670 }
671 }
672 goto tr_valid;
673
674tr_handle_set_wakeup:
675 if (state == ST_DATA) {
676 if (usb2_handle_remote_wakeup(xfer, 1)) {
677 goto tr_stalled;
678 }
679 }
680 goto tr_valid;
681
682tr_handle_get_ep_status:
683 if (state == ST_DATA) {
684 temp.wStatus[0] =
685 usb2_handle_get_stall(udev, req.wIndex[0]);
686 temp.wStatus[1] = 0;
687 src_mcopy = temp.wStatus;
688 max_len = sizeof(temp.wStatus);
689 }
690 goto tr_valid;
691
692tr_valid:
693 if (state == ST_POST_STATUS) {
694 goto tr_stalled;
695 }
696 /* subtract offset from length */
697
698 max_len -= off;
699
700 /* Compute the real maximum data length */
701
702 if (max_len > xfer->max_data_length) {
703 max_len = xfer->max_data_length;
704 }
705 if (max_len > rem) {
706 max_len = rem;
707 }
708 /*
709 * If the remainder is greater than the maximum data length,
710 * we need to truncate the value for the sake of the
711 * comparison below:
712 */
713 if (rem > xfer->max_data_length) {
714 rem = xfer->max_data_length;
715 }
716 if (rem != max_len) {
717 /*
718 * If we don't transfer the data we can transfer, then
719 * the transfer is short !
720 */
721 xfer->flags.force_short_xfer = 1;
722 xfer->nframes = 2;
723 } else {
724 /*
725 * Default case
726 */
727 xfer->flags.force_short_xfer = 0;
728 xfer->nframes = max_len ? 2 : 1;
729 }
730 if (max_len > 0) {
731 if (src_mcopy) {
732 src_mcopy = USB_ADD_BYTES(src_mcopy, off);
733 usb2_copy_in(xfer->frbuffers + 1, 0,
734 src_mcopy, max_len);
735 } else {
736 usb2_set_frame_data(xfer,
737 USB_ADD_BYTES(src_zcopy, off), 1);
738 }
739 xfer->frlengths[1] = max_len;
740 } else {
741 /* the end is reached, send status */
742 xfer->flags.manual_status = 0;
743 xfer->frlengths[1] = 0;
744 }
745 DPRINTF("success\n");
746 return (0); /* success */
747
748tr_stalled:
749 DPRINTF("%s\n", (state == ST_POST_STATUS) ?
750 "complete" : "stalled");
751 return (USB_ERR_STALLED);
752
753tr_bad_context:
754 DPRINTF("bad context\n");
755 return (USB_ERR_BAD_CONTEXT);
756}