]>
Commit | Line | Data |
---|---|---|
232c150a WD |
1 | /* |
2 | * (C) Copyright 2003 | |
3 | * Gerry Hamel, geh@ti.com, Texas Instruments | |
4 | * | |
16c8d5e7 WD |
5 | * (C) Copyright 2006 |
6 | * Bryan O'Donoghue, deckard@CodeHermit.ie | |
7 | * | |
232c150a WD |
8 | * Based on |
9 | * linux/drivers/usbd/ep0.c | |
10 | * | |
11 | * Copyright (c) 2000, 2001, 2002 Lineo | |
12 | * Copyright (c) 2001 Hewlett Packard | |
13 | * | |
14 | * By: | |
15 | * Stuart Lynne <sl@lineo.com>, | |
16 | * Tom Rushworth <tbr@lineo.com>, | |
17 | * Bruce Balden <balden@lineo.com> | |
18 | * | |
1a459660 | 19 | * SPDX-License-Identifier: GPL-2.0+ |
232c150a WD |
20 | */ |
21 | ||
22 | /* | |
23 | * This is the builtin ep0 control function. It implements all required functionality | |
24 | * for responding to control requests (SETUP packets). | |
25 | * | |
26 | * XXX | |
27 | * | |
28 | * Currently we do not pass any SETUP packets (or other) to the configured | |
29 | * function driver. This may need to change. | |
30 | * | |
31 | * XXX | |
16c8d5e7 WD |
32 | * |
33 | * As alluded to above, a simple callback cdc_recv_setup has been implemented | |
386eda02 | 34 | * in the usb_device data structure to facilicate passing |
16c8d5e7 WD |
35 | * Common Device Class packets to a function driver. |
36 | * | |
37 | * XXX | |
232c150a WD |
38 | */ |
39 | ||
40 | #include <common.h> | |
2731b9a8 | 41 | #include <usbdevice.h> |
232c150a WD |
42 | |
43 | #if 0 | |
44 | #define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args) | |
45 | #else | |
46 | #define dbg_ep0(lvl,fmt,args...) | |
47 | #endif | |
48 | ||
49 | /* EP0 Configuration Set ********************************************************************* */ | |
50 | ||
51 | ||
52 | /** | |
53 | * ep0_get_status - fill in URB data with appropriate status | |
54 | * @device: | |
55 | * @urb: | |
56 | * @index: | |
57 | * @requesttype: | |
58 | * | |
59 | */ | |
60 | static int ep0_get_status (struct usb_device_instance *device, | |
61 | struct urb *urb, int index, int requesttype) | |
62 | { | |
63 | char *cp; | |
64 | ||
65 | urb->actual_length = 2; | |
16c8d5e7 | 66 | cp = (char*)urb->buffer; |
232c150a WD |
67 | cp[0] = cp[1] = 0; |
68 | ||
69 | switch (requesttype) { | |
70 | case USB_REQ_RECIPIENT_DEVICE: | |
71 | cp[0] = USB_STATUS_SELFPOWERED; | |
72 | break; | |
73 | case USB_REQ_RECIPIENT_INTERFACE: | |
74 | break; | |
75 | case USB_REQ_RECIPIENT_ENDPOINT: | |
76 | cp[0] = usbd_endpoint_halted (device, index); | |
77 | break; | |
78 | case USB_REQ_RECIPIENT_OTHER: | |
79 | urb->actual_length = 0; | |
80 | default: | |
81 | break; | |
82 | } | |
83 | dbg_ep0 (2, "%02x %02x", cp[0], cp[1]); | |
84 | return 0; | |
85 | } | |
86 | ||
87 | /** | |
88 | * ep0_get_one | |
89 | * @device: | |
90 | * @urb: | |
91 | * @result: | |
92 | * | |
93 | * Set a single byte value in the urb send buffer. Return non-zero to signal | |
94 | * a request error. | |
95 | */ | |
96 | static int ep0_get_one (struct usb_device_instance *device, struct urb *urb, | |
97 | __u8 result) | |
98 | { | |
99 | urb->actual_length = 1; /* XXX 2? */ | |
100 | ((char *) urb->buffer)[0] = result; | |
101 | return 0; | |
102 | } | |
103 | ||
104 | /** | |
105 | * copy_config | |
106 | * @urb: pointer to urb | |
107 | * @data: pointer to configuration data | |
108 | * @length: length of data | |
109 | * | |
110 | * Copy configuration data to urb transfer buffer if there is room for it. | |
111 | */ | |
16c8d5e7 | 112 | void copy_config (struct urb *urb, void *data, int max_length, |
232c150a WD |
113 | int max_buf) |
114 | { | |
115 | int available; | |
116 | int length; | |
117 | ||
118 | /*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */ | |
119 | /* urb->actual_length, urb->buffer_length, max_buf, max_length, data); */ | |
120 | ||
121 | if (!data) { | |
122 | dbg_ep0 (1, "data is NULL"); | |
123 | return; | |
124 | } | |
16c8d5e7 | 125 | length = max_length; |
232c150a WD |
126 | |
127 | if (length > max_length) { | |
128 | dbg_ep0 (1, "length: %d >= max_length: %d", length, | |
129 | max_length); | |
130 | return; | |
131 | } | |
132 | /*dbg_ep0(1, " actual: %d buf: %d max_buf: %d max_length: %d length: %d", */ | |
133 | /* urb->actual_length, urb->buffer_length, max_buf, max_length, length); */ | |
134 | ||
135 | if ((available = | |
136 | /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) { | |
137 | return; | |
138 | } | |
139 | /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */ | |
140 | /* urb->actual_length, urb->buffer_length, max_buf, length, available); */ | |
141 | ||
142 | if (length > available) { | |
143 | length = available; | |
144 | } | |
145 | /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */ | |
146 | /* urb->actual_length, urb->buffer_length, max_buf, length, available); */ | |
147 | ||
148 | memcpy (urb->buffer + urb->actual_length, data, length); | |
149 | urb->actual_length += length; | |
150 | ||
151 | dbg_ep0 (3, | |
152 | "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d", | |
153 | urb->actual_length, urb->buffer_length, max_buf, max_length, | |
154 | available); | |
155 | } | |
156 | ||
157 | /** | |
158 | * ep0_get_descriptor | |
159 | * @device: | |
160 | * @urb: | |
161 | * @max: | |
162 | * @descriptor_type: | |
163 | * @index: | |
164 | * | |
165 | * Called by ep0_rx_process for a get descriptor device command. Determine what | |
166 | * descriptor is being requested, copy to send buffer. Return zero if ok to send, | |
167 | * return non-zero to signal a request error. | |
168 | */ | |
169 | static int ep0_get_descriptor (struct usb_device_instance *device, | |
170 | struct urb *urb, int max, int descriptor_type, | |
171 | int index) | |
172 | { | |
173 | int port = 0; /* XXX compound device */ | |
232c150a WD |
174 | |
175 | /*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */ | |
176 | ||
177 | if (!urb || !urb->buffer || !urb->buffer_length | |
178 | || (urb->buffer_length < 255)) { | |
179 | dbg_ep0 (2, "invalid urb %p", urb); | |
180 | return -1L; | |
181 | } | |
182 | ||
183 | /* setup tx urb */ | |
184 | urb->actual_length = 0; | |
232c150a WD |
185 | |
186 | dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type)); | |
187 | ||
188 | switch (descriptor_type) { | |
189 | case USB_DESCRIPTOR_TYPE_DEVICE: | |
190 | { | |
191 | struct usb_device_descriptor *device_descriptor; | |
232c150a WD |
192 | if (! |
193 | (device_descriptor = | |
194 | usbd_device_device_descriptor (device, port))) { | |
195 | return -1; | |
196 | } | |
197 | /* copy descriptor for this device */ | |
198 | copy_config (urb, device_descriptor, | |
199 | sizeof (struct usb_device_descriptor), | |
200 | max); | |
201 | ||
202 | /* correct the correct control endpoint 0 max packet size into the descriptor */ | |
203 | device_descriptor = | |
204 | (struct usb_device_descriptor *) urb->buffer; | |
232c150a WD |
205 | |
206 | } | |
386eda02 | 207 | dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length); |
232c150a WD |
208 | break; |
209 | ||
210 | case USB_DESCRIPTOR_TYPE_CONFIGURATION: | |
211 | { | |
232c150a WD |
212 | struct usb_configuration_descriptor |
213 | *configuration_descriptor; | |
214 | struct usb_device_descriptor *device_descriptor; | |
232c150a WD |
215 | if (! |
216 | (device_descriptor = | |
217 | usbd_device_device_descriptor (device, port))) { | |
218 | return -1; | |
219 | } | |
220 | /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */ | |
e73b5212 HW |
221 | if (index >= device_descriptor->bNumConfigurations) { |
222 | dbg_ep0 (0, "index too large: %d >= %d", index, | |
232c150a WD |
223 | device_descriptor-> |
224 | bNumConfigurations); | |
225 | return -1; | |
226 | } | |
227 | ||
228 | if (! | |
229 | (configuration_descriptor = | |
230 | usbd_device_configuration_descriptor (device, | |
231 | port, | |
232 | index))) { | |
233 | dbg_ep0 (0, | |
234 | "usbd_device_configuration_descriptor failed: %d", | |
235 | index); | |
236 | return -1; | |
237 | } | |
16c8d5e7 | 238 | dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength)); |
232c150a | 239 | copy_config (urb, configuration_descriptor, |
232c150a | 240 | |
16c8d5e7 WD |
241 | cpu_to_le16(configuration_descriptor->wTotalLength), |
242 | max); | |
232c150a | 243 | } |
16c8d5e7 | 244 | |
232c150a WD |
245 | break; |
246 | ||
247 | case USB_DESCRIPTOR_TYPE_STRING: | |
248 | { | |
249 | struct usb_string_descriptor *string_descriptor; | |
232c150a | 250 | if (!(string_descriptor = usbd_get_string (index))) { |
16c8d5e7 | 251 | serial_printf("Invalid string index %d\n", index); |
232c150a WD |
252 | return -1; |
253 | } | |
386eda02 | 254 | dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength); |
232c150a WD |
255 | copy_config (urb, string_descriptor, string_descriptor->bLength, max); |
256 | } | |
257 | break; | |
258 | case USB_DESCRIPTOR_TYPE_INTERFACE: | |
16c8d5e7 | 259 | serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n"); |
232c150a WD |
260 | return -1; |
261 | case USB_DESCRIPTOR_TYPE_ENDPOINT: | |
16c8d5e7 | 262 | serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n"); |
232c150a WD |
263 | return -1; |
264 | case USB_DESCRIPTOR_TYPE_HID: | |
265 | { | |
16c8d5e7 | 266 | serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n"); |
232c150a WD |
267 | return -1; /* unsupported at this time */ |
268 | #if 0 | |
269 | int bNumInterface = | |
270 | le16_to_cpu (urb->device_request.wIndex); | |
271 | int bAlternateSetting = 0; | |
272 | int class = 0; | |
273 | struct usb_class_descriptor *class_descriptor; | |
274 | ||
275 | if (!(class_descriptor = | |
276 | usbd_device_class_descriptor_index (device, | |
277 | port, 0, | |
278 | bNumInterface, | |
279 | bAlternateSetting, | |
280 | class)) | |
281 | || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) { | |
282 | dbg_ep0 (3, "[%d] interface is not HID", | |
283 | bNumInterface); | |
284 | return -1; | |
285 | } | |
286 | /* copy descriptor for this class */ | |
287 | copy_config (urb, class_descriptor, | |
288 | class_descriptor->descriptor.hid.bLength, | |
289 | max); | |
290 | #endif | |
291 | } | |
292 | break; | |
293 | case USB_DESCRIPTOR_TYPE_REPORT: | |
294 | { | |
16c8d5e7 | 295 | serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n"); |
232c150a WD |
296 | return -1; /* unsupported at this time */ |
297 | #if 0 | |
298 | int bNumInterface = | |
299 | le16_to_cpu (urb->device_request.wIndex); | |
300 | int bAlternateSetting = 0; | |
301 | int class = 0; | |
302 | struct usb_class_report_descriptor *report_descriptor; | |
303 | ||
304 | if (!(report_descriptor = | |
305 | usbd_device_class_report_descriptor_index | |
306 | (device, port, 0, bNumInterface, | |
307 | bAlternateSetting, class)) | |
308 | || report_descriptor->bDescriptorType != | |
309 | USB_DT_REPORT) { | |
310 | dbg_ep0 (3, "[%d] descriptor is not REPORT", | |
311 | bNumInterface); | |
312 | return -1; | |
313 | } | |
314 | /* copy report descriptor for this class */ | |
315 | /*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */ | |
316 | if (max - urb->actual_length > 0) { | |
317 | int length = | |
318 | MIN (report_descriptor->wLength, | |
319 | max - urb->actual_length); | |
320 | memcpy (urb->buffer + urb->actual_length, | |
321 | &report_descriptor->bData[0], length); | |
322 | urb->actual_length += length; | |
323 | } | |
324 | #endif | |
325 | } | |
326 | break; | |
16c8d5e7 | 327 | case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: |
f9da0f89 | 328 | #if defined(CONFIG_USBD_HS) |
16c8d5e7 | 329 | { |
f9da0f89 VK |
330 | struct usb_qualifier_descriptor *qualifier_descriptor = |
331 | device->qualifier_descriptor; | |
332 | ||
333 | if (!qualifier_descriptor) | |
334 | return -1; | |
335 | ||
336 | /* copy descriptor for this device */ | |
337 | copy_config(urb, qualifier_descriptor, | |
338 | sizeof(struct usb_qualifier_descriptor), | |
339 | max); | |
340 | ||
16c8d5e7 | 341 | } |
f9da0f89 VK |
342 | dbg_ep0(3, "copied qualifier descriptor, actual_length: 0x%x", |
343 | urb->actual_length); | |
344 | #else | |
345 | return -1; | |
346 | #endif | |
347 | break; | |
348 | ||
232c150a WD |
349 | default: |
350 | return -1; | |
351 | } | |
352 | ||
353 | ||
16c8d5e7 | 354 | dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d", |
232c150a WD |
355 | urb->buffer, urb->buffer_length, urb->actual_length, |
356 | device->bus->endpoint_array[0].tx_packetSize); | |
357 | /* | |
358 | if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) { | |
359 | dbg_ep0(0, "adding null byte"); | |
360 | urb->buffer[urb->actual_length++] = 0; | |
361 | dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d", | |
362 | urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize); | |
363 | } | |
364 | */ | |
365 | return 0; | |
366 | ||
367 | } | |
368 | ||
369 | /** | |
370 | * ep0_recv_setup - called to indicate URB has been received | |
371 | * @urb: pointer to struct urb | |
372 | * | |
373 | * Check if this is a setup packet, process the device request, put results | |
374 | * back into the urb and return zero or non-zero to indicate success (DATA) | |
375 | * or failure (STALL). | |
376 | * | |
377 | */ | |
378 | int ep0_recv_setup (struct urb *urb) | |
379 | { | |
380 | /*struct usb_device_request *request = urb->buffer; */ | |
381 | /*struct usb_device_instance *device = urb->device; */ | |
382 | ||
383 | struct usb_device_request *request; | |
384 | struct usb_device_instance *device; | |
385 | int address; | |
386 | ||
387 | dbg_ep0 (0, "entering ep0_recv_setup()"); | |
388 | if (!urb || !urb->device) { | |
389 | dbg_ep0 (3, "invalid URB %p", urb); | |
390 | return -1; | |
391 | } | |
392 | ||
393 | request = &urb->device_request; | |
394 | device = urb->device; | |
395 | ||
396 | dbg_ep0 (3, "urb: %p device: %p", urb, urb->device); | |
397 | ||
398 | ||
399 | /*dbg_ep0(2, "- - - - - - - - - -"); */ | |
400 | ||
401 | dbg_ep0 (2, | |
402 | "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s", | |
403 | request->bmRequestType, request->bRequest, | |
404 | le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex), | |
405 | le16_to_cpu (request->wLength), | |
406 | USBD_DEVICE_REQUESTS (request->bRequest)); | |
407 | ||
408 | /* handle USB Standard Request (c.f. USB Spec table 9-2) */ | |
409 | if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) { | |
16c8d5e7 WD |
410 | if(device->device_state <= STATE_CONFIGURED){ |
411 | /* Attempt to handle a CDC specific request if we are | |
412 | * in the configured state. | |
413 | */ | |
414 | return device->cdc_recv_setup(request,urb); | |
415 | } | |
232c150a WD |
416 | dbg_ep0 (1, "non standard request: %x", |
417 | request->bmRequestType & USB_REQ_TYPE_MASK); | |
418 | return -1; /* Stall here */ | |
419 | } | |
420 | ||
421 | switch (device->device_state) { | |
422 | case STATE_CREATED: | |
423 | case STATE_ATTACHED: | |
424 | case STATE_POWERED: | |
425 | /* It actually is important to allow requests in these states, | |
426 | * Windows will request descriptors before assigning an | |
427 | * address to the client. | |
428 | */ | |
429 | ||
430 | /*dbg_ep0 (1, "request %s not allowed in this state: %s", */ | |
431 | /* USBD_DEVICE_REQUESTS(request->bRequest), */ | |
432 | /* usbd_device_states[device->device_state]); */ | |
433 | /*return -1; */ | |
434 | break; | |
435 | ||
436 | case STATE_INIT: | |
437 | case STATE_DEFAULT: | |
438 | switch (request->bRequest) { | |
439 | case USB_REQ_GET_STATUS: | |
440 | case USB_REQ_GET_INTERFACE: | |
441 | case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ | |
442 | case USB_REQ_CLEAR_FEATURE: | |
443 | case USB_REQ_SET_FEATURE: | |
444 | case USB_REQ_SET_DESCRIPTOR: | |
445 | /* case USB_REQ_SET_CONFIGURATION: */ | |
446 | case USB_REQ_SET_INTERFACE: | |
447 | dbg_ep0 (1, | |
448 | "request %s not allowed in DEFAULT state: %s", | |
449 | USBD_DEVICE_REQUESTS (request->bRequest), | |
450 | usbd_device_states[device->device_state]); | |
451 | return -1; | |
452 | ||
453 | case USB_REQ_SET_CONFIGURATION: | |
454 | case USB_REQ_SET_ADDRESS: | |
455 | case USB_REQ_GET_DESCRIPTOR: | |
456 | case USB_REQ_GET_CONFIGURATION: | |
457 | break; | |
458 | } | |
459 | case STATE_ADDRESSED: | |
460 | case STATE_CONFIGURED: | |
461 | break; | |
462 | case STATE_UNKNOWN: | |
463 | dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s", | |
464 | USBD_DEVICE_REQUESTS (request->bRequest), | |
465 | usbd_device_states[device->device_state]); | |
466 | return -1; | |
467 | } | |
468 | ||
469 | /* handle all requests that return data (direction bit set on bm RequestType) */ | |
470 | if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) { | |
471 | ||
472 | dbg_ep0 (3, "Device-to-Host"); | |
473 | ||
474 | switch (request->bRequest) { | |
475 | ||
476 | case USB_REQ_GET_STATUS: | |
477 | return ep0_get_status (device, urb, request->wIndex, | |
478 | request->bmRequestType & | |
479 | USB_REQ_RECIPIENT_MASK); | |
480 | ||
481 | case USB_REQ_GET_DESCRIPTOR: | |
482 | return ep0_get_descriptor (device, urb, | |
483 | le16_to_cpu (request->wLength), | |
484 | le16_to_cpu (request->wValue) >> 8, | |
485 | le16_to_cpu (request->wValue) & 0xff); | |
486 | ||
487 | case USB_REQ_GET_CONFIGURATION: | |
16c8d5e7 | 488 | serial_printf("get config %d\n", device->configuration); |
232c150a WD |
489 | return ep0_get_one (device, urb, |
490 | device->configuration); | |
491 | ||
492 | case USB_REQ_GET_INTERFACE: | |
493 | return ep0_get_one (device, urb, device->alternate); | |
494 | ||
495 | case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ | |
496 | return -1; | |
497 | ||
498 | case USB_REQ_CLEAR_FEATURE: | |
499 | case USB_REQ_SET_FEATURE: | |
500 | case USB_REQ_SET_ADDRESS: | |
501 | case USB_REQ_SET_DESCRIPTOR: | |
502 | case USB_REQ_SET_CONFIGURATION: | |
503 | case USB_REQ_SET_INTERFACE: | |
504 | return -1; | |
505 | } | |
506 | } | |
507 | /* handle the requests that do not return data */ | |
508 | else { | |
509 | ||
510 | ||
511 | /*dbg_ep0(3, "Host-to-Device"); */ | |
512 | switch (request->bRequest) { | |
513 | ||
514 | case USB_REQ_CLEAR_FEATURE: | |
515 | case USB_REQ_SET_FEATURE: | |
516 | dbg_ep0 (0, "Host-to-Device"); | |
517 | switch (request-> | |
518 | bmRequestType & USB_REQ_RECIPIENT_MASK) { | |
519 | case USB_REQ_RECIPIENT_DEVICE: | |
520 | /* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */ | |
521 | /* XXX fall through for now as we do not support either */ | |
522 | case USB_REQ_RECIPIENT_INTERFACE: | |
523 | case USB_REQ_RECIPIENT_OTHER: | |
524 | dbg_ep0 (0, "request %s not", | |
525 | USBD_DEVICE_REQUESTS (request->bRequest)); | |
526 | default: | |
527 | return -1; | |
528 | ||
529 | case USB_REQ_RECIPIENT_ENDPOINT: | |
530 | dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue)); | |
531 | if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) { | |
532 | /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */ | |
533 | /* request->bRequest == USB_REQ_SET_FEATURE); */ | |
534 | /* NEED TO IMPLEMENT THIS!!! */ | |
535 | return -1; | |
536 | } else { | |
537 | dbg_ep0 (1, "request %s bad wValue: %04x", | |
538 | USBD_DEVICE_REQUESTS | |
539 | (request->bRequest), | |
540 | le16_to_cpu (request->wValue)); | |
541 | return -1; | |
542 | } | |
543 | } | |
544 | ||
545 | case USB_REQ_SET_ADDRESS: | |
546 | /* check if this is a re-address, reset first if it is (this shouldn't be possible) */ | |
547 | if (device->device_state != STATE_DEFAULT) { | |
548 | dbg_ep0 (1, "set_address: %02x state: %s", | |
549 | le16_to_cpu (request->wValue), | |
550 | usbd_device_states[device->device_state]); | |
551 | return -1; | |
552 | } | |
553 | address = le16_to_cpu (request->wValue); | |
554 | if ((address & 0x7f) != address) { | |
555 | dbg_ep0 (1, "invalid address %04x %04x", | |
556 | address, address & 0x7f); | |
557 | return -1; | |
558 | } | |
559 | device->address = address; | |
560 | ||
561 | /*dbg_ep0(2, "address: %d %d %d", */ | |
562 | /* request->wValue, le16_to_cpu(request->wValue), device->address); */ | |
563 | ||
232c150a WD |
564 | return 0; |
565 | ||
566 | case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */ | |
567 | dbg_ep0 (0, "set descriptor: NOT SUPPORTED"); | |
568 | return -1; | |
569 | ||
570 | case USB_REQ_SET_CONFIGURATION: | |
571 | /* c.f. 9.4.7 - the top half of wValue is reserved */ | |
e73b5212 HW |
572 | device->configuration = le16_to_cpu(request->wValue) & 0xff; |
573 | ||
232c150a WD |
574 | /* reset interface and alternate settings */ |
575 | device->interface = device->alternate = 0; | |
576 | ||
577 | /*dbg_ep0(2, "set configuration: %d", device->configuration); */ | |
578 | /*serial_printf("DEVICE_CONFIGURED.. event?\n"); */ | |
579 | return 0; | |
580 | ||
581 | case USB_REQ_SET_INTERFACE: | |
582 | device->interface = le16_to_cpu (request->wIndex); | |
583 | device->alternate = le16_to_cpu (request->wValue); | |
584 | /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */ | |
585 | serial_printf ("DEVICE_SET_INTERFACE.. event?\n"); | |
586 | return 0; | |
587 | ||
588 | case USB_REQ_GET_STATUS: | |
589 | case USB_REQ_GET_DESCRIPTOR: | |
590 | case USB_REQ_GET_CONFIGURATION: | |
591 | case USB_REQ_GET_INTERFACE: | |
592 | case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ | |
593 | return -1; | |
594 | } | |
595 | } | |
596 | return -1; | |
597 | } |