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