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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [io/] [usb/] [slave/] [v2_0/] [src/] [usbs.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
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
}

powered by: WebSVN 2.1.0

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