]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/io/usb/slave/v2_0/src/usbs.c
c1435de4c9a7f9e13a058776966218a4126750d9
[karo-tx-redboot.git] / packages / io / usb / slave / v2_0 / src / usbs.c
1 //==========================================================================
2 //
3 //      usbs.c
4 //
5 //      Generic USB slave-side support
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    bartv
44 // Contributors: bartv
45 // Date:         2000-10-04
46 //
47 //####DESCRIPTIONEND####
48 //
49 //==========================================================================
50
51 #include <pkgconf/system.h>
52 #include <cyg/infra/cyg_type.h>
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
55 #include <cyg/infra/diag.h>
56 #include <cyg/io/usb/usbs.h>
57 #include <cyg/hal/drv_api.h>
58
59 // ----------------------------------------------------------------------------
60 // Devtab entry support. This code can be compiled with no overheads as
61 // long as the necessary support package is in place.
62 #ifdef CYGPKG_IO
63 # include <cyg/io/io.h>
64 # include <cyg/io/devtab.h>
65 // ----------------------------------------------------------------------------
66 // read()/write() functions applied to USB endpoints. These just
67 // indirect via the usbs_endpoint structures and wait for the
68 // callback to happen.
69
70 typedef struct usbs_callback_data {
71     bool                completed;
72     int                 result;
73     cyg_drv_mutex_t     lock;
74     cyg_drv_cond_t      signal;
75 } usbs_callback_data;
76
77 static void
78 usbs_devtab_callback(void* arg, int result)
79 {
80     usbs_callback_data* callback_data = (usbs_callback_data*) arg;
81     callback_data->result       = result;
82     callback_data->completed    = true;
83     cyg_drv_cond_signal(&(callback_data->signal));
84 }
85     
86 Cyg_ErrNo
87 usbs_devtab_cwrite(cyg_io_handle_t handle, const void* buf, cyg_uint32* size)
88 {
89     usbs_callback_data  wait;
90     cyg_devtab_entry_t* devtab_entry;
91     usbs_tx_endpoint*   endpoint;
92     int                 result = ENOERR;
93     
94     CYG_REPORT_FUNCTION();
95     
96     wait.completed      = 0;
97     cyg_drv_mutex_init(&wait.lock);
98     cyg_drv_cond_init(&wait.signal, &wait.lock);
99
100     devtab_entry      = (cyg_devtab_entry_t*) handle;
101     CYG_CHECK_DATA_PTR( devtab_entry, "A valid endpoint must be supplied");
102     endpoint          = (usbs_tx_endpoint*) devtab_entry->priv;
103     
104     CYG_CHECK_DATA_PTR( endpoint, "The handle must correspond to a USB endpoint");
105     CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The endpoint must have a start_tx function");
106
107     endpoint->buffer            = (unsigned char*) buf;
108     endpoint->buffer_size       = (int) *size;
109     endpoint->complete_fn       = &usbs_devtab_callback;
110     endpoint->complete_data     = (void*) &wait;
111     (*endpoint->start_tx_fn)(endpoint);
112     
113     cyg_drv_mutex_lock(&wait.lock);
114     while (!wait.completed) {
115         cyg_drv_cond_wait(&wait.signal);
116     }
117     cyg_drv_mutex_unlock(&wait.lock);
118     if (wait.result < 0) {
119         result = wait.result;
120     } else {
121         *size = wait.result;
122     }
123     
124     cyg_drv_cond_destroy(&wait.signal);
125     cyg_drv_mutex_destroy(&wait.lock);
126
127     CYG_REPORT_RETURN();
128     return result;
129 }
130
131 Cyg_ErrNo
132 usbs_devtab_cread(cyg_io_handle_t handle, void* buf, cyg_uint32* size)
133 {
134     usbs_callback_data  wait;
135     cyg_devtab_entry_t* devtab_entry;
136     usbs_rx_endpoint*   endpoint;
137     int                 result = ENOERR;
138     
139     CYG_REPORT_FUNCTION();
140     
141     wait.completed      = 0;
142     cyg_drv_mutex_init(&wait.lock);
143     cyg_drv_cond_init(&wait.signal, &wait.lock);
144
145     devtab_entry      = (cyg_devtab_entry_t*) handle;
146     CYG_CHECK_DATA_PTR( devtab_entry, "A valid endpoint must be supplied");
147     endpoint          = (usbs_rx_endpoint*) devtab_entry->priv;
148     
149     CYG_CHECK_DATA_PTR( endpoint, "The handle must correspond to a USB endpoint");
150     CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The endpoint must have a start_rx function");
151
152     endpoint->buffer            = (unsigned char*) buf;
153     endpoint->buffer_size       = (int) *size;
154     endpoint->complete_fn       = &usbs_devtab_callback;
155     endpoint->complete_data     = (void*) &wait;
156     (*endpoint->start_rx_fn)(endpoint);
157     cyg_drv_mutex_lock(&wait.lock);
158     while (!wait.completed) {
159         cyg_drv_cond_wait(&wait.signal);
160     }
161     cyg_drv_mutex_unlock(&wait.lock);
162     if (wait.result < 0) {
163         result = wait.result;
164     } else {
165         *size = wait.result;
166     }
167     
168     cyg_drv_cond_destroy(&wait.signal);
169     cyg_drv_mutex_destroy(&wait.lock);
170
171     CYG_REPORT_RETURN();
172     return result;
173 }
174
175 // ----------------------------------------------------------------------------
176 // More devtab functions, this time related to ioctl() style operations.
177 Cyg_ErrNo
178 usbs_devtab_get_config(cyg_io_handle_t handle, cyg_uint32 code, void* buf, cyg_uint32* size)
179 {
180     return -EINVAL;
181 }
182
183 Cyg_ErrNo
184 usbs_devtab_set_config(cyg_io_handle_t handle, cyg_uint32 code, const void* buf, cyg_uint32* size)
185 {
186     return -EINVAL;
187 }
188
189 #endif  //  CYGPKG_IO
190
191 // ----------------------------------------------------------------------------
192 // USB-specific functions that are useful for applications/packages which
193 // do not want to use the devtab interface. These may get called in DSR
194 // context.
195
196 void
197 usbs_start_rx(usbs_rx_endpoint* endpoint)
198 {
199     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
200     CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The USB endpoint must support receive operations");
201     (*endpoint->start_rx_fn)(endpoint);
202 }
203
204 void
205 usbs_start_rx_buffer(usbs_rx_endpoint* endpoint,
206                      unsigned char* buf, int size,
207                      void (*callback_fn)(void *, int), void* callback_arg)
208 {
209     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
210     CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The USB endpoint must support receive operations");
211
212     endpoint->buffer            = buf;
213     endpoint->buffer_size       = size;
214     endpoint->complete_fn       = callback_fn;
215     endpoint->complete_data     = callback_arg;
216     (*endpoint->start_rx_fn)(endpoint);
217 }
218
219 void
220 usbs_start_tx(usbs_tx_endpoint* endpoint)
221 {
222     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
223     CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The USB endpoint must support receive operations");
224     (*endpoint->start_tx_fn)(endpoint);
225 }
226
227 void
228 usbs_start_tx_buffer(usbs_tx_endpoint* endpoint,
229                      const unsigned char* buf, int size,
230                      void (*callback_fn)(void*, int), void *callback_arg)
231 {
232     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
233     CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The USB endpoint must support receive operations");
234
235     endpoint->buffer            = buf;
236     endpoint->buffer_size       = size;
237     endpoint->complete_fn       = callback_fn;
238     endpoint->complete_data     = callback_arg;
239     (*endpoint->start_tx_fn)(endpoint);
240 }
241
242 void
243 usbs_start(usbs_control_endpoint* endpoint)
244 {
245     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
246     CYG_CHECK_FUNC_PTR( endpoint->start_fn, "The USB endpoint should have a start function");
247
248     (*endpoint->start_fn)(endpoint);
249 }
250
251 cyg_bool
252 usbs_rx_endpoint_halted(usbs_rx_endpoint* endpoint)
253 {
254    CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
255    return endpoint->halted;
256 }
257
258 cyg_bool
259 usbs_tx_endpoint_halted(usbs_tx_endpoint* endpoint)
260 {
261    CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
262    return endpoint->halted;
263 }
264
265 void
266 usbs_set_rx_endpoint_halted(usbs_rx_endpoint* endpoint, cyg_bool halted)
267 {
268     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
269     CYG_CHECK_FUNC_PTR( endpoint->set_halted_fn, "The USB endpoint should have a set-halted function");
270     (*endpoint->set_halted_fn)(endpoint, halted);
271 }
272
273 void
274 usbs_set_tx_endpoint_halted(usbs_tx_endpoint* endpoint, cyg_bool halted)
275 {
276     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
277     CYG_CHECK_FUNC_PTR( endpoint->set_halted_fn, "The USB endpoint should have a set-halted function");
278     (*endpoint->set_halted_fn)(endpoint, halted);
279 }
280
281 void
282 usbs_start_rx_endpoint_wait(usbs_rx_endpoint* endpoint, void (*callback_fn)(void*, int), void* callback_data)
283 {
284     endpoint->buffer            = (unsigned char*) 0;
285     endpoint->buffer_size       = 0;
286     endpoint->complete_fn       = callback_fn;
287     endpoint->complete_data     = callback_data;
288     (*endpoint->start_rx_fn)(endpoint);
289 }
290
291 void
292 usbs_start_tx_endpoint_wait(usbs_tx_endpoint* endpoint, void (*callback_fn)(void*, int), void* callback_data)
293 {
294     endpoint->buffer            = (unsigned char*) 0;
295     endpoint->buffer_size       = 0;
296     endpoint->complete_fn       = callback_fn;
297     endpoint->complete_data     = callback_data;
298     (*endpoint->start_tx_fn)(endpoint);
299 }
300
301
302 // ----------------------------------------------------------------------------
303 // Handling of standard control messages. This will be invoked by
304 // a USB device driver, usually at DSR level, to process any control
305 // messages that cannot be handled by the hardware itself and that
306 // have also not been handled by the application-specific handler
307 // (if any).
308 //
309 // Because this function can run at DSR level performance is important.
310 //
311 // The various standard control messages are affected as follows:
312 //
313 // clear-feature: nothing can be done here about device requests to
314 // disable remote-wakeup or about endpoint halt requests. It appears
315 // to be legal to clear no features on an interface.
316 //
317 // get-configuration: if the device is not configured a single byte 0
318 // should be returned. Otherwise this code assumes only one configuration
319 // is supported and its id can be extracted from the enumeration data.
320 // For more complicated devices get-configuration has to be handled
321 // at a higher-level.
322 //
323 // get-descriptor: this is the big one. It is used to obtain
324 // the enumeration data. An auxiliary refill function is needed.
325 //
326 // get-interface: this can be used to identify the current variant
327 // for a given interface within a configuration. For simple devices
328 // there will be only interface, 0. For anything more complicated
329 // higher level code will have to take care of the request.
330 //
331 // get-status. Much the same as clear-feature.
332 //
333 // set-address. Must be handled at the device driver level.
334 //
335 // set-configuration: a value of 0 is used to deconfigure the device,
336 // which can be handled here. Otherwise this code assumes that only
337 // a single configuration is supported and enables that. For anything
338 // more complicated higher-level code has to handle this request.
339 //
340 // set-descriptor: used to update the enumeration data. This is not
341 // supported here, although higher-level code can choose to do so.
342 //
343 // set-feature. See clear-feature and get-status.
344 //
345 // set-interface. Variant interfaces are not supported by the
346 // base code so this request has to be handled at a higher level.
347 //
348 // synch-frame. This is only relevant for isochronous transfers
349 // which are not yet supported, and anyway it is not clear what
350 // could be done about these requests here.
351
352 // This refill function handles GET_DESCRIPTOR requests for a
353 // configuration. For details of the control_buffer usage see
354 // the relevant code in the main callback.
355 static void
356 usbs_configuration_descriptor_refill(usbs_control_endpoint* endpoint)
357 {
358     usb_devreq* req                 = (usb_devreq*) endpoint->control_buffer;
359     int         length              = (req->length_hi << 8) | req->length_lo;
360     int         sent                = (req->index_hi << 8)  | req->index_lo;
361     int         current_interface   = req->type;
362     int         last_interface      = req->request;
363     int         current_endpoint    = req->value_lo;
364     int         last_endpoint       = req->value_hi;
365     cyg_bool    done                = false;
366
367     if (current_endpoint == last_endpoint) {
368         // The next transfer should be a single interface - unless we have already finished.
369         if (current_interface == last_interface) {
370             done = true;
371         } else {
372             endpoint->buffer            = (unsigned char*) &(endpoint->enumeration_data->interfaces[current_interface]);
373             if (USB_INTERFACE_DESCRIPTOR_LENGTH >= (length - sent)) {
374                 endpoint->buffer_size = length - sent;
375                 done = true;
376             } else {
377                 endpoint->buffer_size   = USB_INTERFACE_DESCRIPTOR_LENGTH;
378                 sent                   += USB_INTERFACE_DESCRIPTOR_LENGTH;
379                 // Note that an interface with zero endpoints is ok. We'll just move
380                 // to the next interface in the next call.
381                 last_endpoint           = current_endpoint +
382                     endpoint->enumeration_data->interfaces[current_interface].number_endpoints;
383                 current_interface++;
384             }
385         }
386     } else {
387         // The next transfer should be a single endpoint. The
388         // endpoints are actually contiguous array elements
389         // but may not be packed, so they have to be transferred
390         // one at a time.
391         endpoint->buffer     = (unsigned char*) &(endpoint->enumeration_data->endpoints[current_endpoint]);
392         if ((sent + USB_ENDPOINT_DESCRIPTOR_LENGTH) >= length) {
393             endpoint->buffer_size = length - sent;
394             done = true;
395         } else {
396             endpoint->buffer_size = USB_ENDPOINT_DESCRIPTOR_LENGTH;
397             current_endpoint ++;
398         }
399     }
400
401     if (done) {
402         endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0;
403     } else {
404         req->type       = (unsigned char) current_interface;
405         req->value_lo   = (unsigned char) current_endpoint;
406         req->value_hi   = (unsigned char) last_endpoint;
407         req->index_hi   = (unsigned char) (sent >> 8);
408         req->index_lo   = (unsigned char) (sent & 0x00FF);
409     }
410 }
411
412 usbs_control_return
413 usbs_handle_standard_control(usbs_control_endpoint* endpoint)
414 {
415     usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN;
416     usb_devreq*         req    = (usb_devreq*) endpoint->control_buffer;
417     int                 length;
418     int                 direction;
419     int                 recipient;
420
421     length      = (req->length_hi << 8) | req->length_lo;
422     direction   = req->type & USB_DEVREQ_DIRECTION_MASK;
423     recipient   = req->type & USB_DEVREQ_RECIPIENT_MASK;
424
425     if (USB_DEVREQ_CLEAR_FEATURE == req->request) {
426         
427         if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) {
428             // The host should expect no data back, the device must
429             // be configured, and there are no defined features to clear.
430             if ((0 == length) &&
431                 (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) &&
432                 (0 == req->value_lo)) {
433
434                 int interface_id = req->index_lo;
435                 CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \
436                             "Higher level code should have handled this request");
437
438                 if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) {                
439                     result = USBS_CONTROL_RETURN_HANDLED;
440                 } else {
441                     result = USBS_CONTROL_RETURN_STALL;
442                 }
443                 
444             } else {
445                 result = USBS_CONTROL_RETURN_STALL;
446             }
447         }
448         
449     } else if (USB_DEVREQ_GET_CONFIGURATION == req->request) {
450
451         // Return a single byte 0 if the device is not currently
452         // configured. Otherwise assume a single configuration
453         // in the enumeration data and return its id.
454         if ((1 == length) && (USB_DEVREQ_DIRECTION_IN == direction)) {
455             
456             if (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) {
457                 CYG_ASSERT( 1 == endpoint->enumeration_data->device.number_configurations, \
458                             "Higher level code should have handled this request");
459                 endpoint->control_buffer[0] = endpoint->enumeration_data->configurations[0].configuration_id;
460             } else {
461                 endpoint->control_buffer[0] = 0;
462             }
463             endpoint->buffer            = endpoint->control_buffer;
464             endpoint->buffer_size       = 1;
465             endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
466             endpoint->complete_fn       = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
467             result = USBS_CONTROL_RETURN_HANDLED;
468             
469         } else {
470             result = USBS_CONTROL_RETURN_STALL;
471         }
472             
473     } else if (USB_DEVREQ_GET_DESCRIPTOR == req->request) {
474
475         // The descriptor type is in value_hi. The descriptor index
476         // is in value_lo.
477         // The hsot must expect at least one byte of data.
478         if ((0 == length) || (USB_DEVREQ_DIRECTION_IN != direction)) {
479             
480             result = USBS_CONTROL_RETURN_STALL;
481             
482         } else if (USB_DEVREQ_DESCRIPTOR_TYPE_DEVICE == req->value_hi) {
483
484             // The device descriptor is easy, it is a single field in the
485             // enumeration data.
486             endpoint->buffer            = (unsigned char*) &(endpoint->enumeration_data->device);
487             endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
488             endpoint->complete_fn       = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
489             if (length < USB_DEVICE_DESCRIPTOR_LENGTH) {
490                 endpoint->buffer_size = length;
491             } else {
492                 endpoint->buffer_size = USB_DEVICE_DESCRIPTOR_LENGTH;
493             }
494             result = USBS_CONTROL_RETURN_HANDLED;
495             
496         } else if (USB_DEVREQ_DESCRIPTOR_TYPE_CONFIGURATION == req->value_hi) {
497
498             // This is where things get messy. We need to supply the
499             // specified configuration data, followed by some number of
500             // interfaces and endpoints. Plus there are length limits
501             // to consider. First check that the specified index is valid.
502             if (req->value_lo >= endpoint->enumeration_data->device.number_configurations) {
503                 result = USBS_CONTROL_RETURN_STALL;
504             } else {
505                 // No such luck. OK, supplying the initial block is easy.
506                 endpoint->buffer        = (unsigned char*) &(endpoint->enumeration_data->configurations[req->value_lo]);
507                 endpoint->complete_fn   = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
508
509                 // How much data was actually requested. If only the
510                 // configuration itself is of interest then there is
511                 // no need to worry about the rest.
512                 if (length <= USB_CONFIGURATION_DESCRIPTOR_LENGTH) {
513                     endpoint->buffer_size       = length;
514                     endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
515                 } else {
516                     int i, j;
517                     int start_interface;
518                     int start_endpoint;
519                     endpoint->buffer_size       = USB_CONFIGURATION_DESCRIPTOR_LENGTH;
520                     endpoint->fill_buffer_fn    = &usbs_configuration_descriptor_refill;
521
522                     // The descriptor refill_fn needs to know what next to transfer.
523                     // The desired interfaces and endpoints will be contiguous so
524                     // we need to keep track of the following:
525                     // 1) the current interface index being transferred.
526                     // 2) the last interface that should be transferred.
527                     // 3) the current endpoint index that should be transferred.
528                     // 4) the last endpoint index. This marks interface/endpoint transitions.
529                     // 5) how much has been transferred to date.
530                     // This information can be held in the control_buffer,
531                     // with the length field being preserved.
532                     start_interface = 0;
533                     start_endpoint  = 0;
534                     // For all configurations up to the desired one.
535                     for (i = 0; i < req->value_lo; i++) {
536                         int config_interfaces = endpoint->enumeration_data->configurations[i].number_interfaces;
537
538                         // For all interfaces in this configuration.
539                         for (j = 0; j < config_interfaces; j++) {
540                             // Add the number of endpoints in this interface to the current count.
541                             CYG_ASSERT( (j + start_interface) < endpoint->enumeration_data->total_number_interfaces, \
542                                         "Valid interface count in enumeration data");
543                             start_endpoint += endpoint->enumeration_data->interfaces[j + start_interface].number_endpoints;
544                         }
545                         // And update the index for the starting interface.
546                         start_interface += config_interfaces;
547                     }
548                     CYG_ASSERT( start_interface < endpoint->enumeration_data->total_number_interfaces, \
549                                 "Valid interface count in enumeration data");
550                     CYG_ASSERT( ((0 == endpoint->enumeration_data->total_number_endpoints) && (0 == start_endpoint)) || \
551                                 (start_endpoint < endpoint->enumeration_data->total_number_endpoints), \
552                                 "Valid endpoint count in enumeration data");
553
554                     req->type           = (unsigned char) start_interface;
555                     req->request        = (unsigned char) (start_interface +
556                                                            endpoint->enumeration_data->configurations[req->value_lo].number_interfaces
557                                                            );
558                     req->value_lo       = (unsigned char) start_endpoint;
559                     req->value_hi       = (unsigned char) start_endpoint;
560                     req->index_lo       = USB_CONFIGURATION_DESCRIPTOR_LENGTH;
561                     req->index_hi       = 0;
562                 }
563                 result = USBS_CONTROL_RETURN_HANDLED;
564             }
565             
566             
567         } else if (USB_DEVREQ_DESCRIPTOR_TYPE_STRING == req->value_hi) {
568
569             // As long as the index is valid, the rest is easy since
570             // the strings are just held in a simple array.
571             // NOTE: if multiple languages have to be supported
572             // then things get more difficult.
573             if (req->value_lo >= endpoint->enumeration_data->total_number_strings) {
574                 result = USBS_CONTROL_RETURN_STALL;
575             } else {
576                 endpoint->buffer                = (unsigned char*) endpoint->enumeration_data->strings[req->value_lo];
577                 endpoint->fill_buffer_fn        = (void (*)(usbs_control_endpoint*)) 0;
578                 endpoint->complete_fn           = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
579
580                 if (length < endpoint->buffer[0]) {
581                     endpoint->buffer_size = length;
582                 } else {
583                     endpoint->buffer_size = endpoint->buffer[0];
584                 }
585                 result = USBS_CONTROL_RETURN_HANDLED;
586             }
587             
588         } else {
589             result = USBS_CONTROL_RETURN_STALL;
590         }
591         
592     } else if (USB_DEVREQ_GET_INTERFACE == req->request) {
593
594         if ((1 != length) ||
595             (USB_DEVREQ_DIRECTION_IN != direction) ||
596             (USBS_STATE_CONFIGURED != (endpoint->state & USBS_STATE_MASK))) {
597             
598             result = USBS_CONTROL_RETURN_STALL;
599             
600         } else {
601             int interface_id;
602             
603             CYG_ASSERT( (1 == endpoint->enumeration_data->device.number_configurations) && \
604                         (1 == endpoint->enumeration_data->total_number_interfaces),       \
605                         "Higher level code should have handled this request");
606
607             interface_id = (req->index_hi << 8) | req->index_lo;
608             if (interface_id != endpoint->enumeration_data->interfaces[0].interface_id) {
609                 result = USBS_CONTROL_RETURN_STALL;
610             } else {
611                 endpoint->control_buffer[0] = endpoint->enumeration_data->interfaces[0].alternate_setting;
612                 endpoint->buffer            = endpoint->control_buffer;
613                 endpoint->buffer_size       = 1;
614                 endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
615                 endpoint->complete_fn       = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
616                 result = USBS_CONTROL_RETURN_HANDLED;
617             }
618         }
619         
620     } else if (USB_DEVREQ_GET_STATUS == req->request) {
621
622         if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) {
623             // The host should expect two bytes back, the device must
624             // be configured, the interface number must be valid.
625             // The host should expect no data back, the device must
626             // be configured, and there are no defined features to clear.
627             if ((2 == length) &&
628                 (USB_DEVREQ_DIRECTION_IN == direction) &&
629                 (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK))) {
630
631                 int interface_id = req->index_lo;
632                 CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \
633                             "Higher level code should have handled this request");
634
635                 if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) {
636                     
637                     // The request is legit, but there are no defined features for an interface...
638                     endpoint->control_buffer[0] = 0;
639                     endpoint->control_buffer[1] = 0;
640                     endpoint->buffer            = endpoint->control_buffer;
641                     endpoint->buffer_size       = 2;
642                     endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
643                     endpoint->complete_fn       = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
644                     result = USBS_CONTROL_RETURN_HANDLED;
645                     
646                 } else {
647                     result = USBS_CONTROL_RETURN_STALL;
648                 }
649             } else {
650                 result = USBS_CONTROL_RETURN_STALL;
651             }
652         }
653         
654     } else if (USB_DEVREQ_SET_CONFIGURATION == req->request) {
655
656         // Changing to configuration 0 means a state change from
657         // configured to addressed. Changing to anything else means a
658         // state change to configured. Both involve invoking the
659         // state change callback. If there are multiple configurations
660         // to choose from then this request has to be handled at
661         // a higher level. 
662         int old_state = endpoint->state;
663         if (0 == req->value_lo) {
664             endpoint->state = USBS_STATE_ADDRESSED;
665             if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != endpoint->state_change_fn) {
666                 (*endpoint->state_change_fn)(endpoint, endpoint->state_change_data,
667                                              USBS_STATE_CHANGE_DECONFIGURED, old_state);
668             }
669             result = USBS_CONTROL_RETURN_HANDLED;
670                 
671         } else {
672             CYG_ASSERT(1 == endpoint->enumeration_data->device.number_configurations, \
673                        "Higher level code should have handled this request");
674             if (req->value_lo == endpoint->enumeration_data->configurations[0].configuration_id) {
675                 endpoint->state = USBS_STATE_CONFIGURED;
676                 if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != endpoint->state_change_fn) {
677                     (*endpoint->state_change_fn)(endpoint, endpoint->state_change_data,
678                                                  USBS_STATE_CHANGE_CONFIGURED, old_state);
679                 }
680                 result = USBS_CONTROL_RETURN_HANDLED;
681             } else {
682                 result = USBS_CONTROL_RETURN_STALL;
683             }
684         }
685         
686     } else if (USB_DEVREQ_SET_FEATURE == req->request) {
687         
688         if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) {
689             // The host should expect no data back, the device must
690             // be configured, and there are no defined features to clear.
691             if ((0 == length) &&
692                 (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) &&
693                 (0 == req->value_lo)) {
694
695                 int interface_id = req->index_lo;
696                 CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \
697                             "Higher level code should have handled this request");
698
699                 if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) {                
700                     result = USBS_CONTROL_RETURN_HANDLED;
701                 } else {
702                     result = USBS_CONTROL_RETURN_STALL;
703                 }
704                 
705             } else {
706                 result = USBS_CONTROL_RETURN_STALL;
707             }
708         }
709         
710     }
711     
712     return result;
713 }