]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/usb/slave/v2_0/src/usbs.c
unified MX27, MX25, MX37 trees
[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     cyg_drv_dsr_lock();
115     while (!wait.completed) {
116         cyg_drv_cond_wait(&wait.signal);
117     }
118     cyg_drv_dsr_unlock();
119     cyg_drv_mutex_unlock(&wait.lock);
120     if (wait.result < 0) {
121         result = wait.result;
122     } else {
123         *size = wait.result;
124     }
125     
126     cyg_drv_cond_destroy(&wait.signal);
127     cyg_drv_mutex_destroy(&wait.lock);
128
129     CYG_REPORT_RETURN();
130     return result;
131 }
132
133 Cyg_ErrNo
134 usbs_devtab_cread(cyg_io_handle_t handle, void* buf, cyg_uint32* size)
135 {
136     usbs_callback_data  wait;
137     cyg_devtab_entry_t* devtab_entry;
138     usbs_rx_endpoint*   endpoint;
139     int                 result = ENOERR;
140     
141     CYG_REPORT_FUNCTION();
142     
143     wait.completed      = 0;
144     cyg_drv_mutex_init(&wait.lock);
145     cyg_drv_cond_init(&wait.signal, &wait.lock);
146
147     devtab_entry      = (cyg_devtab_entry_t*) handle;
148     CYG_CHECK_DATA_PTR( devtab_entry, "A valid endpoint must be supplied");
149     endpoint          = (usbs_rx_endpoint*) devtab_entry->priv;
150     
151     CYG_CHECK_DATA_PTR( endpoint, "The handle must correspond to a USB endpoint");
152     CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The endpoint must have a start_rx function");
153
154     endpoint->buffer            = (unsigned char*) buf;
155     endpoint->buffer_size       = (int) *size;
156     endpoint->complete_fn       = &usbs_devtab_callback;
157     endpoint->complete_data     = (void*) &wait;
158     (*endpoint->start_rx_fn)(endpoint);
159     cyg_drv_mutex_lock(&wait.lock);
160     cyg_drv_dsr_lock();
161     while (!wait.completed) {
162         cyg_drv_cond_wait(&wait.signal);
163     }
164     cyg_drv_dsr_unlock();
165     cyg_drv_mutex_unlock(&wait.lock);
166     if (wait.result < 0) {
167         result = wait.result;
168     } else {
169         *size = wait.result;
170     }
171     
172     cyg_drv_cond_destroy(&wait.signal);
173     cyg_drv_mutex_destroy(&wait.lock);
174
175     CYG_REPORT_RETURN();
176     return result;
177 }
178
179 // ----------------------------------------------------------------------------
180 // More devtab functions, this time related to ioctl() style operations.
181 Cyg_ErrNo
182 usbs_devtab_get_config(cyg_io_handle_t handle, cyg_uint32 code, void* buf, cyg_uint32* size)
183 {
184     return -EINVAL;
185 }
186
187 Cyg_ErrNo
188 usbs_devtab_set_config(cyg_io_handle_t handle, cyg_uint32 code, const void* buf, cyg_uint32* size)
189 {
190     return -EINVAL;
191 }
192
193 #endif  //  CYGPKG_IO
194
195 // ----------------------------------------------------------------------------
196 // USB-specific functions that are useful for applications/packages which
197 // do not want to use the devtab interface. These may get called in DSR
198 // context.
199
200 void
201 usbs_start_rx(usbs_rx_endpoint* endpoint)
202 {
203     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
204     CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The USB endpoint must support receive operations");
205     (*endpoint->start_rx_fn)(endpoint);
206 }
207
208 void
209 usbs_start_rx_buffer(usbs_rx_endpoint* endpoint,
210                      unsigned char* buf, int size,
211                      void (*callback_fn)(void *, int), void* callback_arg)
212 {
213     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
214     CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The USB endpoint must support receive operations");
215
216     endpoint->buffer            = buf;
217     endpoint->buffer_size       = size;
218     endpoint->complete_fn       = callback_fn;
219     endpoint->complete_data     = callback_arg;
220     (*endpoint->start_rx_fn)(endpoint);
221 }
222
223 void
224 usbs_start_tx(usbs_tx_endpoint* endpoint)
225 {
226     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
227     CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The USB endpoint must support receive operations");
228     (*endpoint->start_tx_fn)(endpoint);
229 }
230
231 void
232 usbs_start_tx_buffer(usbs_tx_endpoint* endpoint,
233                      const unsigned char* buf, int size,
234                      void (*callback_fn)(void*, int), void *callback_arg)
235 {
236     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
237     CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The USB endpoint must support receive operations");
238
239     endpoint->buffer            = buf;
240     endpoint->buffer_size       = size;
241     endpoint->complete_fn       = callback_fn;
242     endpoint->complete_data     = callback_arg;
243     (*endpoint->start_tx_fn)(endpoint);
244 }
245
246 void
247 usbs_start(usbs_control_endpoint* endpoint)
248 {
249     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
250     CYG_CHECK_FUNC_PTR( endpoint->start_fn, "The USB endpoint should have a start function");
251
252     (*endpoint->start_fn)(endpoint);
253 }
254
255 cyg_bool
256 usbs_rx_endpoint_halted(usbs_rx_endpoint* endpoint)
257 {
258    CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
259    return endpoint->halted;
260 }
261
262 cyg_bool
263 usbs_tx_endpoint_halted(usbs_tx_endpoint* endpoint)
264 {
265    CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
266    return endpoint->halted;
267 }
268
269 void
270 usbs_set_rx_endpoint_halted(usbs_rx_endpoint* endpoint, cyg_bool halted)
271 {
272     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
273     CYG_CHECK_FUNC_PTR( endpoint->set_halted_fn, "The USB endpoint should have a set-halted function");
274     (*endpoint->set_halted_fn)(endpoint, halted);
275 }
276
277 void
278 usbs_set_tx_endpoint_halted(usbs_tx_endpoint* endpoint, cyg_bool halted)
279 {
280     CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied");
281     CYG_CHECK_FUNC_PTR( endpoint->set_halted_fn, "The USB endpoint should have a set-halted function");
282     (*endpoint->set_halted_fn)(endpoint, halted);
283 }
284
285 void
286 usbs_start_rx_endpoint_wait(usbs_rx_endpoint* endpoint, void (*callback_fn)(void*, int), void* callback_data)
287 {
288     endpoint->buffer            = (unsigned char*) 0;
289     endpoint->buffer_size       = 0;
290     endpoint->complete_fn       = callback_fn;
291     endpoint->complete_data     = callback_data;
292     (*endpoint->start_rx_fn)(endpoint);
293 }
294
295 void
296 usbs_start_tx_endpoint_wait(usbs_tx_endpoint* endpoint, void (*callback_fn)(void*, int), void* callback_data)
297 {
298     endpoint->buffer            = (unsigned char*) 0;
299     endpoint->buffer_size       = 0;
300     endpoint->complete_fn       = callback_fn;
301     endpoint->complete_data     = callback_data;
302     (*endpoint->start_tx_fn)(endpoint);
303 }
304
305
306 // ----------------------------------------------------------------------------
307 // Handling of standard control messages. This will be invoked by
308 // a USB device driver, usually at DSR level, to process any control
309 // messages that cannot be handled by the hardware itself and that
310 // have also not been handled by the application-specific handler
311 // (if any).
312 //
313 // Because this function can run at DSR level performance is important.
314 //
315 // The various standard control messages are affected as follows:
316 //
317 // clear-feature: nothing can be done here about device requests to
318 // disable remote-wakeup or about endpoint halt requests. It appears
319 // to be legal to clear no features on an interface.
320 //
321 // get-configuration: if the device is not configured a single byte 0
322 // should be returned. Otherwise this code assumes only one configuration
323 // is supported and its id can be extracted from the enumeration data.
324 // For more complicated devices get-configuration has to be handled
325 // at a higher-level.
326 //
327 // get-descriptor: this is the big one. It is used to obtain
328 // the enumeration data. An auxiliary refill function is needed.
329 //
330 // get-interface: this can be used to identify the current variant
331 // for a given interface within a configuration. For simple devices
332 // there will be only interface, 0. For anything more complicated
333 // higher level code will have to take care of the request.
334 //
335 // get-status. Much the same as clear-feature.
336 //
337 // set-address. Must be handled at the device driver level.
338 //
339 // set-configuration: a value of 0 is used to deconfigure the device,
340 // which can be handled here. Otherwise this code assumes that only
341 // a single configuration is supported and enables that. For anything
342 // more complicated higher-level code has to handle this request.
343 //
344 // set-descriptor: used to update the enumeration data. This is not
345 // supported here, although higher-level code can choose to do so.
346 //
347 // set-feature. See clear-feature and get-status.
348 //
349 // set-interface. Variant interfaces are not supported by the
350 // base code so this request has to be handled at a higher level.
351 //
352 // synch-frame. This is only relevant for isochronous transfers
353 // which are not yet supported, and anyway it is not clear what
354 // could be done about these requests here.
355
356 // This refill function handles GET_DESCRIPTOR requests for a
357 // configuration. For details of the control_buffer usage see
358 // the relevant code in the main callback.
359 static void
360 usbs_configuration_descriptor_refill(usbs_control_endpoint* endpoint)
361 {
362     usb_devreq* req                 = (usb_devreq*) endpoint->control_buffer;
363     int         length              = (req->length_hi << 8) | req->length_lo;
364     int         sent                = (req->index_hi << 8)  | req->index_lo;
365     int         current_interface   = req->type;
366     int         last_interface      = req->request;
367     int         current_endpoint    = req->value_lo;
368     int         last_endpoint       = req->value_hi;
369     cyg_bool    done                = false;
370
371     if (current_endpoint == last_endpoint) {
372         // The next transfer should be a single interface - unless we have already finished.
373         if (current_interface == last_interface) {
374             done = true;
375         } else {
376             endpoint->buffer            = (unsigned char*) &(endpoint->enumeration_data->interfaces[current_interface]);
377             if (USB_INTERFACE_DESCRIPTOR_LENGTH >= (length - sent)) {
378                 endpoint->buffer_size = length - sent;
379                 done = true;
380             } else {
381                 endpoint->buffer_size   = USB_INTERFACE_DESCRIPTOR_LENGTH;
382                 sent                   += USB_INTERFACE_DESCRIPTOR_LENGTH;
383                 // Note that an interface with zero endpoints is ok. We'll just move
384                 // to the next interface in the next call.
385                 last_endpoint           = current_endpoint +
386                     endpoint->enumeration_data->interfaces[current_interface].number_endpoints;
387                 current_interface++;
388             }
389         }
390     } else {
391         // The next transfer should be a single endpoint. The
392         // endpoints are actually contiguous array elements
393         // but may not be packed, so they have to be transferred
394         // one at a time.
395         endpoint->buffer     = (unsigned char*) &(endpoint->enumeration_data->endpoints[current_endpoint]);
396         if ((sent + USB_ENDPOINT_DESCRIPTOR_LENGTH) >= length) {
397             endpoint->buffer_size = length - sent;
398             done = true;
399         } else {
400             endpoint->buffer_size = USB_ENDPOINT_DESCRIPTOR_LENGTH;
401             current_endpoint ++;
402         }
403     }
404
405     if (done) {
406         endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0;
407     } else {
408         req->type       = (unsigned char) current_interface;
409         req->value_lo   = (unsigned char) current_endpoint;
410         req->value_hi   = (unsigned char) last_endpoint;
411         req->index_hi   = (unsigned char) (sent >> 8);
412         req->index_lo   = (unsigned char) (sent & 0x00FF);
413     }
414 }
415
416 usbs_control_return
417 usbs_handle_standard_control(usbs_control_endpoint* endpoint)
418 {
419     usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN;
420     usb_devreq*         req    = (usb_devreq*) endpoint->control_buffer;
421     int                 length;
422     int                 direction;
423     int                 recipient;
424
425     length      = (req->length_hi << 8) | req->length_lo;
426     direction   = req->type & USB_DEVREQ_DIRECTION_MASK;
427     recipient   = req->type & USB_DEVREQ_RECIPIENT_MASK;
428
429     if (USB_DEVREQ_CLEAR_FEATURE == req->request) {
430         
431         if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) {
432             // The host should expect no data back, the device must
433             // be configured, and there are no defined features to clear.
434             if ((0 == length) &&
435                 (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) &&
436                 (0 == req->value_lo)) {
437
438                 int interface_id = req->index_lo;
439                 CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \
440                             "Higher level code should have handled this request");
441
442                 if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) {                
443                     result = USBS_CONTROL_RETURN_HANDLED;
444                 } else {
445                     result = USBS_CONTROL_RETURN_STALL;
446                 }
447                 
448             } else {
449                 result = USBS_CONTROL_RETURN_STALL;
450             }
451         }
452         
453     } else if (USB_DEVREQ_GET_CONFIGURATION == req->request) {
454
455         // Return a single byte 0 if the device is not currently
456         // configured. Otherwise assume a single configuration
457         // in the enumeration data and return its id.
458         if ((1 == length) && (USB_DEVREQ_DIRECTION_IN == direction)) {
459             
460             if (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) {
461                 CYG_ASSERT( 1 == endpoint->enumeration_data->device.number_configurations, \
462                             "Higher level code should have handled this request");
463                 endpoint->control_buffer[0] = endpoint->enumeration_data->configurations[0].configuration_id;
464             } else {
465                 endpoint->control_buffer[0] = 0;
466             }
467             endpoint->buffer            = endpoint->control_buffer;
468             endpoint->buffer_size       = 1;
469             endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
470             endpoint->complete_fn       = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
471             result = USBS_CONTROL_RETURN_HANDLED;
472             
473         } else {
474             result = USBS_CONTROL_RETURN_STALL;
475         }
476             
477     } else if (USB_DEVREQ_GET_DESCRIPTOR == req->request) {
478
479         // The descriptor type is in value_hi. The descriptor index
480         // is in value_lo.
481         // The hsot must expect at least one byte of data.
482         if ((0 == length) || (USB_DEVREQ_DIRECTION_IN != direction)) {
483             
484             result = USBS_CONTROL_RETURN_STALL;
485             
486         } else if (USB_DEVREQ_DESCRIPTOR_TYPE_DEVICE == req->value_hi) {
487
488             // The device descriptor is easy, it is a single field in the
489             // enumeration data.
490             endpoint->buffer            = (unsigned char*) &(endpoint->enumeration_data->device);
491             endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
492             endpoint->complete_fn       = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
493             if (length < USB_DEVICE_DESCRIPTOR_LENGTH) {
494                 endpoint->buffer_size = length;
495             } else {
496                 endpoint->buffer_size = USB_DEVICE_DESCRIPTOR_LENGTH;
497             }
498             result = USBS_CONTROL_RETURN_HANDLED;
499             
500         } else if (USB_DEVREQ_DESCRIPTOR_TYPE_CONFIGURATION == req->value_hi) {
501
502             // This is where things get messy. We need to supply the
503             // specified configuration data, followed by some number of
504             // interfaces and endpoints. Plus there are length limits
505             // to consider. First check that the specified index is valid.
506             if (req->value_lo >= endpoint->enumeration_data->device.number_configurations) {
507                 result = USBS_CONTROL_RETURN_STALL;
508             } else {
509                 // No such luck. OK, supplying the initial block is easy.
510                 endpoint->buffer        = (unsigned char*) &(endpoint->enumeration_data->configurations[req->value_lo]);
511                 endpoint->complete_fn   = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
512
513                 // How much data was actually requested. If only the
514                 // configuration itself is of interest then there is
515                 // no need to worry about the rest.
516                 if (length <= USB_CONFIGURATION_DESCRIPTOR_LENGTH) {
517                     endpoint->buffer_size       = length;
518                     endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
519                 } else {
520                     int i, j;
521                     int start_interface;
522                     int start_endpoint;
523                     endpoint->buffer_size       = USB_CONFIGURATION_DESCRIPTOR_LENGTH;
524                     endpoint->fill_buffer_fn    = &usbs_configuration_descriptor_refill;
525
526                     // The descriptor refill_fn needs to know what next to transfer.
527                     // The desired interfaces and endpoints will be contiguous so
528                     // we need to keep track of the following:
529                     // 1) the current interface index being transferred.
530                     // 2) the last interface that should be transferred.
531                     // 3) the current endpoint index that should be transferred.
532                     // 4) the last endpoint index. This marks interface/endpoint transitions.
533                     // 5) how much has been transferred to date.
534                     // This information can be held in the control_buffer,
535                     // with the length field being preserved.
536                     start_interface = 0;
537                     start_endpoint  = 0;
538                     // For all configurations up to the desired one.
539                     for (i = 0; i < req->value_lo; i++) {
540                         int config_interfaces = endpoint->enumeration_data->configurations[i].number_interfaces;
541
542                         // For all interfaces in this configuration.
543                         for (j = 0; j < config_interfaces; j++) {
544                             // Add the number of endpoints in this interface to the current count.
545                             CYG_ASSERT( (j + start_interface) < endpoint->enumeration_data->total_number_interfaces, \
546                                         "Valid interface count in enumeration data");
547                             start_endpoint += endpoint->enumeration_data->interfaces[j + start_interface].number_endpoints;
548                         }
549                         // And update the index for the starting interface.
550                         start_interface += config_interfaces;
551                     }
552                     CYG_ASSERT( start_interface < endpoint->enumeration_data->total_number_interfaces, \
553                                 "Valid interface count in enumeration data");
554                     CYG_ASSERT( ((0 == endpoint->enumeration_data->total_number_endpoints) && (0 == start_endpoint)) || \
555                                 (start_endpoint < endpoint->enumeration_data->total_number_endpoints), \
556                                 "Valid endpoint count in enumeration data");
557
558                     req->type           = (unsigned char) start_interface;
559                     req->request        = (unsigned char) (start_interface +
560                                                            endpoint->enumeration_data->configurations[req->value_lo].number_interfaces
561                                                            );
562                     req->value_lo       = (unsigned char) start_endpoint;
563                     req->value_hi       = (unsigned char) start_endpoint;
564                     req->index_lo       = USB_CONFIGURATION_DESCRIPTOR_LENGTH;
565                     req->index_hi       = 0;
566                 }
567                 result = USBS_CONTROL_RETURN_HANDLED;
568             }
569             
570             
571         } else if (USB_DEVREQ_DESCRIPTOR_TYPE_STRING == req->value_hi) {
572
573             // As long as the index is valid, the rest is easy since
574             // the strings are just held in a simple array.
575             // NOTE: if multiple languages have to be supported
576             // then things get more difficult.
577             if (req->value_lo >= endpoint->enumeration_data->total_number_strings) {
578                 result = USBS_CONTROL_RETURN_STALL;
579             } else {
580                 endpoint->buffer                = (unsigned char*) endpoint->enumeration_data->strings[req->value_lo];
581                 endpoint->fill_buffer_fn        = (void (*)(usbs_control_endpoint*)) 0;
582                 endpoint->complete_fn           = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
583
584                 if (length < endpoint->buffer[0]) {
585                     endpoint->buffer_size = length;
586                 } else {
587                     endpoint->buffer_size = endpoint->buffer[0];
588                 }
589                 result = USBS_CONTROL_RETURN_HANDLED;
590             }
591             
592         } else {
593             result = USBS_CONTROL_RETURN_STALL;
594         }
595         
596     } else if (USB_DEVREQ_GET_INTERFACE == req->request) {
597
598         if ((1 != length) ||
599             (USB_DEVREQ_DIRECTION_IN != direction) ||
600             (USBS_STATE_CONFIGURED != (endpoint->state & USBS_STATE_MASK))) {
601             
602             result = USBS_CONTROL_RETURN_STALL;
603             
604         } else {
605             int interface_id;
606             
607             CYG_ASSERT( (1 == endpoint->enumeration_data->device.number_configurations) && \
608                         (1 == endpoint->enumeration_data->total_number_interfaces),       \
609                         "Higher level code should have handled this request");
610
611             interface_id = (req->index_hi << 8) | req->index_lo;
612             if (interface_id != endpoint->enumeration_data->interfaces[0].interface_id) {
613                 result = USBS_CONTROL_RETURN_STALL;
614             } else {
615                 endpoint->control_buffer[0] = endpoint->enumeration_data->interfaces[0].alternate_setting;
616                 endpoint->buffer            = endpoint->control_buffer;
617                 endpoint->buffer_size       = 1;
618                 endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
619                 endpoint->complete_fn       = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
620                 result = USBS_CONTROL_RETURN_HANDLED;
621             }
622         }
623         
624     } else if (USB_DEVREQ_GET_STATUS == req->request) {
625
626         if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) {
627             // The host should expect two bytes back, the device must
628             // be configured, the interface number must be valid.
629             // The host should expect no data back, the device must
630             // be configured, and there are no defined features to clear.
631             if ((2 == length) &&
632                 (USB_DEVREQ_DIRECTION_IN == direction) &&
633                 (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK))) {
634
635                 int interface_id = req->index_lo;
636                 CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \
637                             "Higher level code should have handled this request");
638
639                 if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) {
640                     
641                     // The request is legit, but there are no defined features for an interface...
642                     endpoint->control_buffer[0] = 0;
643                     endpoint->control_buffer[1] = 0;
644                     endpoint->buffer            = endpoint->control_buffer;
645                     endpoint->buffer_size       = 2;
646                     endpoint->fill_buffer_fn    = (void (*)(usbs_control_endpoint*)) 0;
647                     endpoint->complete_fn       = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0;
648                     result = USBS_CONTROL_RETURN_HANDLED;
649                     
650                 } else {
651                     result = USBS_CONTROL_RETURN_STALL;
652                 }
653             } else {
654                 result = USBS_CONTROL_RETURN_STALL;
655             }
656         }
657         
658     } else if (USB_DEVREQ_SET_CONFIGURATION == req->request) {
659
660         // Changing to configuration 0 means a state change from
661         // configured to addressed. Changing to anything else means a
662         // state change to configured. Both involve invoking the
663         // state change callback. If there are multiple configurations
664         // to choose from then this request has to be handled at
665         // a higher level. 
666         int old_state = endpoint->state;
667         if (0 == req->value_lo) {
668             endpoint->state = USBS_STATE_ADDRESSED;
669             if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != endpoint->state_change_fn) {
670                 (*endpoint->state_change_fn)(endpoint, endpoint->state_change_data,
671                                              USBS_STATE_CHANGE_DECONFIGURED, old_state);
672             }
673             result = USBS_CONTROL_RETURN_HANDLED;
674                 
675         } else {
676             CYG_ASSERT(1 == endpoint->enumeration_data->device.number_configurations, \
677                        "Higher level code should have handled this request");
678             if (req->value_lo == endpoint->enumeration_data->configurations[0].configuration_id) {
679                 endpoint->state = USBS_STATE_CONFIGURED;
680                 if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != endpoint->state_change_fn) {
681                     (*endpoint->state_change_fn)(endpoint, endpoint->state_change_data,
682                                                  USBS_STATE_CHANGE_CONFIGURED, old_state);
683                 }
684                 result = USBS_CONTROL_RETURN_HANDLED;
685             } else {
686                 result = USBS_CONTROL_RETURN_STALL;
687             }
688         }
689         
690     } else if (USB_DEVREQ_SET_FEATURE == req->request) {
691         
692         if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) {
693             // The host should expect no data back, the device must
694             // be configured, and there are no defined features to clear.
695             if ((0 == length) &&
696                 (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) &&
697                 (0 == req->value_lo)) {
698
699                 int interface_id = req->index_lo;
700                 CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \
701                             "Higher level code should have handled this request");
702
703                 if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) {                
704                     result = USBS_CONTROL_RETURN_HANDLED;
705                 } else {
706                     result = USBS_CONTROL_RETURN_STALL;
707                 }
708                 
709             } else {
710                 result = USBS_CONTROL_RETURN_STALL;
711             }
712         }
713         
714     }
715     
716     return result;
717 }