OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [usb/] [slave/] [current/] [src/] [usbs.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.