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] - Rev 825
Go to most recent revision | Compare with Previous | Blame | View Log
//========================================================================== // // usbs.c // // Generic USB slave-side support // //========================================================================== // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2010 Free Software Foundation, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later // version. // // eCos is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): bartv // Contributors: bartv // Date: 2000-10-04 // //####DESCRIPTIONEND#### // //========================================================================== #include <pkgconf/system.h> #include <cyg/infra/cyg_type.h> #include <cyg/infra/cyg_ass.h> #include <cyg/infra/cyg_trac.h> #include <cyg/infra/diag.h> #include <cyg/io/usb/usbs.h> #include <cyg/hal/drv_api.h> // ---------------------------------------------------------------------------- // Devtab entry support. This code can be compiled with no overheads as // long as the necessary support package is in place. #ifdef CYGPKG_IO # include <cyg/io/io.h> # include <cyg/io/devtab.h> // ---------------------------------------------------------------------------- // read()/write() functions applied to USB endpoints. These just // indirect via the usbs_endpoint structures and wait for the // callback to happen. typedef struct usbs_callback_data { bool completed; int result; cyg_drv_mutex_t lock; cyg_drv_cond_t signal; } usbs_callback_data; static void usbs_devtab_callback(void* arg, int result) { usbs_callback_data* callback_data = (usbs_callback_data*) arg; callback_data->result = result; callback_data->completed = true; cyg_drv_cond_signal(&(callback_data->signal)); } Cyg_ErrNo usbs_devtab_cwrite(cyg_io_handle_t handle, const void* buf, cyg_uint32* size) { usbs_callback_data wait; cyg_devtab_entry_t* devtab_entry; usbs_tx_endpoint* endpoint; int result = ENOERR; CYG_REPORT_FUNCTION(); wait.completed = 0; cyg_drv_mutex_init(&wait.lock); cyg_drv_cond_init(&wait.signal, &wait.lock); devtab_entry = (cyg_devtab_entry_t*) handle; CYG_CHECK_DATA_PTR( devtab_entry, "A valid endpoint must be supplied"); endpoint = (usbs_tx_endpoint*) devtab_entry->priv; CYG_CHECK_DATA_PTR( endpoint, "The handle must correspond to a USB endpoint"); CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The endpoint must have a start_tx function"); endpoint->buffer = (unsigned char*) buf; endpoint->buffer_size = (int) *size; endpoint->complete_fn = &usbs_devtab_callback; endpoint->complete_data = (void*) &wait; (*endpoint->start_tx_fn)(endpoint); cyg_drv_mutex_lock(&wait.lock); cyg_drv_dsr_lock(); while (!wait.completed) { cyg_drv_cond_wait(&wait.signal); } cyg_drv_dsr_unlock(); cyg_drv_mutex_unlock(&wait.lock); if (wait.result < 0) { result = wait.result; } else { *size = wait.result; } cyg_drv_cond_destroy(&wait.signal); cyg_drv_mutex_destroy(&wait.lock); CYG_REPORT_RETURN(); return result; } Cyg_ErrNo usbs_devtab_cread(cyg_io_handle_t handle, void* buf, cyg_uint32* size) { usbs_callback_data wait; cyg_devtab_entry_t* devtab_entry; usbs_rx_endpoint* endpoint; int result = ENOERR; CYG_REPORT_FUNCTION(); wait.completed = 0; cyg_drv_mutex_init(&wait.lock); cyg_drv_cond_init(&wait.signal, &wait.lock); devtab_entry = (cyg_devtab_entry_t*) handle; CYG_CHECK_DATA_PTR( devtab_entry, "A valid endpoint must be supplied"); endpoint = (usbs_rx_endpoint*) devtab_entry->priv; CYG_CHECK_DATA_PTR( endpoint, "The handle must correspond to a USB endpoint"); CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The endpoint must have a start_rx function"); endpoint->buffer = (unsigned char*) buf; endpoint->buffer_size = (int) *size; endpoint->complete_fn = &usbs_devtab_callback; endpoint->complete_data = (void*) &wait; (*endpoint->start_rx_fn)(endpoint); cyg_drv_mutex_lock(&wait.lock); cyg_drv_dsr_lock(); while (!wait.completed) { cyg_drv_cond_wait(&wait.signal); } cyg_drv_dsr_unlock(); cyg_drv_mutex_unlock(&wait.lock); if (wait.result < 0) { result = wait.result; } else { *size = wait.result; } cyg_drv_cond_destroy(&wait.signal); cyg_drv_mutex_destroy(&wait.lock); CYG_REPORT_RETURN(); return result; } // ---------------------------------------------------------------------------- // More devtab functions, this time related to ioctl() style operations. Cyg_ErrNo usbs_devtab_get_config(cyg_io_handle_t handle, cyg_uint32 code, void* buf, cyg_uint32* size) { return -EINVAL; } Cyg_ErrNo usbs_devtab_set_config(cyg_io_handle_t handle, cyg_uint32 code, const void* buf, cyg_uint32* size) { return -EINVAL; } #endif // CYGPKG_IO // ---------------------------------------------------------------------------- // USB-specific functions that are useful for applications/packages which // do not want to use the devtab interface. These may get called in DSR // context. usbs_rx_endpoint* usbs_get_rx_endpoint(usbs_control_endpoint* control_endpoint, cyg_uint8 endpoint_id) { CYG_CHECK_DATA_PTR(control_endpoint, "A valid control endpoint must be supplied"); CYG_CHECK_FUNC_PTR(control_endpoint->get_rxep_fn, "Dynamic endpoint access not supported"); if (control_endpoint->state != USBS_STATE_CONFIGURED) return NULL; return (*control_endpoint->get_rxep_fn)(control_endpoint, endpoint_id); } usbs_tx_endpoint* usbs_get_tx_endpoint(usbs_control_endpoint* control_endpoint, cyg_uint8 endpoint_id) { CYG_CHECK_DATA_PTR(control_endpoint, "A valid control endpoint must be supplied"); CYG_CHECK_FUNC_PTR(control_endpoint->get_txep_fn, "Dynamic endpoint access not supported"); if (control_endpoint->state != USBS_STATE_CONFIGURED) return NULL; return (*control_endpoint->get_txep_fn)(control_endpoint, endpoint_id); } void usbs_start_rx(usbs_rx_endpoint* endpoint) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The USB endpoint must support receive operations"); (*endpoint->start_rx_fn)(endpoint); } void usbs_start_rx_buffer(usbs_rx_endpoint* endpoint, unsigned char* buf, int size, void (*callback_fn)(void *, int), void* callback_arg) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The USB endpoint must support receive operations"); endpoint->buffer = buf; endpoint->buffer_size = size; endpoint->complete_fn = callback_fn; endpoint->complete_data = callback_arg; (*endpoint->start_rx_fn)(endpoint); } void usbs_start_tx(usbs_tx_endpoint* endpoint) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The USB endpoint must support receive operations"); (*endpoint->start_tx_fn)(endpoint); } void usbs_start_tx_buffer(usbs_tx_endpoint* endpoint, const unsigned char* buf, int size, void (*callback_fn)(void*, int), void *callback_arg) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The USB endpoint must support receive operations"); endpoint->buffer = buf; endpoint->buffer_size = size; endpoint->complete_fn = callback_fn; endpoint->complete_data = callback_arg; (*endpoint->start_tx_fn)(endpoint); } void usbs_start(usbs_control_endpoint* endpoint) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); CYG_CHECK_FUNC_PTR( endpoint->start_fn, "The USB endpoint should have a start function"); (*endpoint->start_fn)(endpoint); } cyg_bool usbs_rx_endpoint_halted(usbs_rx_endpoint* endpoint) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); return endpoint->halted; } cyg_bool usbs_tx_endpoint_halted(usbs_tx_endpoint* endpoint) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); return endpoint->halted; } void usbs_set_rx_endpoint_halted(usbs_rx_endpoint* endpoint, cyg_bool halted) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); CYG_CHECK_FUNC_PTR( endpoint->set_halted_fn, "The USB endpoint should have a set-halted function"); (*endpoint->set_halted_fn)(endpoint, halted); } void usbs_set_tx_endpoint_halted(usbs_tx_endpoint* endpoint, cyg_bool halted) { CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); CYG_CHECK_FUNC_PTR( endpoint->set_halted_fn, "The USB endpoint should have a set-halted function"); (*endpoint->set_halted_fn)(endpoint, halted); } void usbs_start_rx_endpoint_wait(usbs_rx_endpoint* endpoint, void (*callback_fn)(void*, int), void* callback_data) { endpoint->buffer = (unsigned char*) 0; endpoint->buffer_size = 0; endpoint->complete_fn = callback_fn; endpoint->complete_data = callback_data; (*endpoint->start_rx_fn)(endpoint); } void usbs_start_tx_endpoint_wait(usbs_tx_endpoint* endpoint, void (*callback_fn)(void*, int), void* callback_data) { endpoint->buffer = (unsigned char*) 0; endpoint->buffer_size = 0; endpoint->complete_fn = callback_fn; endpoint->complete_data = callback_data; (*endpoint->start_tx_fn)(endpoint); } // ---------------------------------------------------------------------------- // Handling of standard control messages. This will be invoked by // a USB device driver, usually at DSR level, to process any control // messages that cannot be handled by the hardware itself and that // have also not been handled by the application-specific handler // (if any). // // Because this function can run at DSR level performance is important. // // The various standard control messages are affected as follows: // // clear-feature: nothing can be done here about device requests to // disable remote-wakeup or about endpoint halt requests. It appears // to be legal to clear no features on an interface. // // get-configuration: if the device is not configured a single byte 0 // should be returned. Otherwise this code assumes only one configuration // is supported and its id can be extracted from the enumeration data. // For more complicated devices get-configuration has to be handled // at a higher-level. // // get-descriptor: this is the big one. It is used to obtain // the enumeration data. An auxiliary refill function is needed. // // get-interface: this can be used to identify the current variant // for a given interface within a configuration. For simple devices // there will be only interface, 0. For anything more complicated // higher level code will have to take care of the request. // // get-status. Much the same as clear-feature. // // set-address. Must be handled at the device driver level. // // set-configuration: a value of 0 is used to deconfigure the device, // which can be handled here. Otherwise this code assumes that only // a single configuration is supported and enables that. For anything // more complicated higher-level code has to handle this request. // // set-descriptor: used to update the enumeration data. This is not // supported here, although higher-level code can choose to do so. // // set-feature. See clear-feature and get-status. // // set-interface. Variant interfaces are not supported by the // base code so this request has to be handled at a higher level. // // synch-frame. This is only relevant for isochronous transfers // which are not yet supported, and anyway it is not clear what // could be done about these requests here. // This refill function handles GET_DESCRIPTOR requests for a // configuration. For details of the control_buffer usage see // the relevant code in the main callback. static void usbs_configuration_descriptor_refill(usbs_control_endpoint* endpoint) { usb_devreq* req = (usb_devreq*) endpoint->control_buffer; int length = (req->length_hi << 8) | req->length_lo; int sent = (req->index_hi << 8) | req->index_lo; int current_interface = req->type; int last_interface = req->request; int current_endpoint = req->value_lo; int last_endpoint = req->value_hi; cyg_bool done = false; if (current_endpoint == last_endpoint) { // The next transfer should be a single interface - unless we have already finished. if (current_interface == last_interface) { done = true; } else { endpoint->buffer = (unsigned char*) &(endpoint->enumeration_data->interfaces[current_interface]); if (USB_INTERFACE_DESCRIPTOR_LENGTH >= (length - sent)) { endpoint->buffer_size = length - sent; done = true; } else { endpoint->buffer_size = USB_INTERFACE_DESCRIPTOR_LENGTH; sent += USB_INTERFACE_DESCRIPTOR_LENGTH; // Note that an interface with zero endpoints is ok. We'll just move // to the next interface in the next call. last_endpoint = current_endpoint + endpoint->enumeration_data->interfaces[current_interface].number_endpoints; current_interface++; } } } else { // The next transfer should be a single endpoint. The // endpoints are actually contiguous array elements // but may not be packed, so they have to be transferred // one at a time. endpoint->buffer = (unsigned char*) &(endpoint->enumeration_data->endpoints[current_endpoint]); if ((sent + USB_ENDPOINT_DESCRIPTOR_LENGTH) >= length) { endpoint->buffer_size = length - sent; done = true; } else { endpoint->buffer_size = USB_ENDPOINT_DESCRIPTOR_LENGTH; current_endpoint ++; } } if (done) { endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; } else { req->type = (unsigned char) current_interface; req->value_lo = (unsigned char) current_endpoint; req->value_hi = (unsigned char) last_endpoint; req->index_hi = (unsigned char) (sent >> 8); req->index_lo = (unsigned char) (sent & 0x00FF); } } usbs_control_return usbs_handle_standard_control(usbs_control_endpoint* endpoint) { usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN; usb_devreq* req = (usb_devreq*) endpoint->control_buffer; int length; int direction; int recipient; length = (req->length_hi << 8) | req->length_lo; direction = req->type & USB_DEVREQ_DIRECTION_MASK; recipient = req->type & USB_DEVREQ_RECIPIENT_MASK; if (USB_DEVREQ_CLEAR_FEATURE == req->request) { if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) { // The host should expect no data back, the device must // be configured, and there are no defined features to clear. if ((0 == length) && (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) && (0 == req->value_lo)) { int interface_id = req->index_lo; CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \ "Higher level code should have handled this request"); if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) { result = USBS_CONTROL_RETURN_HANDLED; } else { result = USBS_CONTROL_RETURN_STALL; } } else { result = USBS_CONTROL_RETURN_STALL; } } } else if (USB_DEVREQ_GET_CONFIGURATION == req->request) { // Return a single byte 0 if the device is not currently // configured. Otherwise assume a single configuration // in the enumeration data and return its id. if ((1 == length) && (USB_DEVREQ_DIRECTION_IN == direction)) { if (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) { CYG_ASSERT( 1 == endpoint->enumeration_data->device.number_configurations, \ "Higher level code should have handled this request"); endpoint->control_buffer[0] = endpoint->enumeration_data->configurations[0].configuration_id; } else { endpoint->control_buffer[0] = 0; } endpoint->buffer = endpoint->control_buffer; endpoint->buffer_size = 1; endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; result = USBS_CONTROL_RETURN_HANDLED; } else { result = USBS_CONTROL_RETURN_STALL; } } else if (USB_DEVREQ_GET_DESCRIPTOR == req->request) { // The descriptor type is in value_hi. The descriptor index // is in value_lo. // The hsot must expect at least one byte of data. if ((0 == length) || (USB_DEVREQ_DIRECTION_IN != direction)) { result = USBS_CONTROL_RETURN_STALL; } else if (USB_DEVREQ_DESCRIPTOR_TYPE_DEVICE == req->value_hi) { // The device descriptor is easy, it is a single field in the // enumeration data. endpoint->buffer = (unsigned char*) &(endpoint->enumeration_data->device); endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; if (length < USB_DEVICE_DESCRIPTOR_LENGTH) { endpoint->buffer_size = length; } else { endpoint->buffer_size = USB_DEVICE_DESCRIPTOR_LENGTH; } result = USBS_CONTROL_RETURN_HANDLED; } else if (USB_DEVREQ_DESCRIPTOR_TYPE_CONFIGURATION == req->value_hi) { // This is where things get messy. We need to supply the // specified configuration data, followed by some number of // interfaces and endpoints. Plus there are length limits // to consider. First check that the specified index is valid. if (req->value_lo >= endpoint->enumeration_data->device.number_configurations) { result = USBS_CONTROL_RETURN_STALL; } else { // No such luck. OK, supplying the initial block is easy. endpoint->buffer = (unsigned char*) &(endpoint->enumeration_data->configurations[req->value_lo]); endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; // How much data was actually requested. If only the // configuration itself is of interest then there is // no need to worry about the rest. if (length <= USB_CONFIGURATION_DESCRIPTOR_LENGTH) { endpoint->buffer_size = length; endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; } else { int i, j; int start_interface; int start_endpoint; endpoint->buffer_size = USB_CONFIGURATION_DESCRIPTOR_LENGTH; endpoint->fill_buffer_fn = &usbs_configuration_descriptor_refill; // The descriptor refill_fn needs to know what next to transfer. // The desired interfaces and endpoints will be contiguous so // we need to keep track of the following: // 1) the current interface index being transferred. // 2) the last interface that should be transferred. // 3) the current endpoint index that should be transferred. // 4) the last endpoint index. This marks interface/endpoint transitions. // 5) how much has been transferred to date. // This information can be held in the control_buffer, // with the length field being preserved. start_interface = 0; start_endpoint = 0; // For all configurations up to the desired one. for (i = 0; i < req->value_lo; i++) { int config_interfaces = endpoint->enumeration_data->configurations[i].number_interfaces; // For all interfaces in this configuration. for (j = 0; j < config_interfaces; j++) { // Add the number of endpoints in this interface to the current count. CYG_ASSERT( (j + start_interface) < endpoint->enumeration_data->total_number_interfaces, \ "Valid interface count in enumeration data"); start_endpoint += endpoint->enumeration_data->interfaces[j + start_interface].number_endpoints; } // And update the index for the starting interface. start_interface += config_interfaces; } CYG_ASSERT( start_interface < endpoint->enumeration_data->total_number_interfaces, \ "Valid interface count in enumeration data"); CYG_ASSERT( ((0 == endpoint->enumeration_data->total_number_endpoints) && (0 == start_endpoint)) || \ (start_endpoint < endpoint->enumeration_data->total_number_endpoints), \ "Valid endpoint count in enumeration data"); req->type = (unsigned char) start_interface; req->request = (unsigned char) (start_interface + endpoint->enumeration_data->configurations[req->value_lo].number_interfaces ); req->value_lo = (unsigned char) start_endpoint; req->value_hi = (unsigned char) start_endpoint; req->index_lo = USB_CONFIGURATION_DESCRIPTOR_LENGTH; req->index_hi = 0; } result = USBS_CONTROL_RETURN_HANDLED; } } else if (USB_DEVREQ_DESCRIPTOR_TYPE_STRING == req->value_hi) { // As long as the index is valid, the rest is easy since // the strings are just held in a simple array. // NOTE: if multiple languages have to be supported // then things get more difficult. if (req->value_lo >= endpoint->enumeration_data->total_number_strings) { result = USBS_CONTROL_RETURN_STALL; } else { endpoint->buffer = (unsigned char*) endpoint->enumeration_data->strings[req->value_lo]; endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; if (length < endpoint->buffer[0]) { endpoint->buffer_size = length; } else { endpoint->buffer_size = endpoint->buffer[0]; } result = USBS_CONTROL_RETURN_HANDLED; } } else { result = USBS_CONTROL_RETURN_STALL; } } else if (USB_DEVREQ_GET_INTERFACE == req->request) { if ((1 != length) || (USB_DEVREQ_DIRECTION_IN != direction) || (USBS_STATE_CONFIGURED != (endpoint->state & USBS_STATE_MASK))) { result = USBS_CONTROL_RETURN_STALL; } else { int interface_id; CYG_ASSERT( (1 == endpoint->enumeration_data->device.number_configurations) && \ (1 == endpoint->enumeration_data->total_number_interfaces), \ "Higher level code should have handled this request"); interface_id = (req->index_hi << 8) | req->index_lo; if (interface_id != endpoint->enumeration_data->interfaces[0].interface_id) { result = USBS_CONTROL_RETURN_STALL; } else { endpoint->control_buffer[0] = endpoint->enumeration_data->interfaces[0].alternate_setting; endpoint->buffer = endpoint->control_buffer; endpoint->buffer_size = 1; endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; result = USBS_CONTROL_RETURN_HANDLED; } } } else if (USB_DEVREQ_GET_STATUS == req->request) { if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) { // The host should expect two bytes back, the device must // be configured, the interface number must be valid. // The host should expect no data back, the device must // be configured, and there are no defined features to clear. if ((2 == length) && (USB_DEVREQ_DIRECTION_IN == direction) && (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK))) { int interface_id = req->index_lo; CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \ "Higher level code should have handled this request"); if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) { // The request is legit, but there are no defined features for an interface... endpoint->control_buffer[0] = 0; endpoint->control_buffer[1] = 0; endpoint->buffer = endpoint->control_buffer; endpoint->buffer_size = 2; endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; result = USBS_CONTROL_RETURN_HANDLED; } else { result = USBS_CONTROL_RETURN_STALL; } } else { result = USBS_CONTROL_RETURN_STALL; } } } else if (USB_DEVREQ_SET_CONFIGURATION == req->request) { // Changing to configuration 0 means a state change from // configured to addressed. Changing to anything else means a // state change to configured. Both involve invoking the // state change callback. If there are multiple configurations // to choose from then this request has to be handled at // a higher level. int old_state = endpoint->state; if (0 == req->value_lo) { endpoint->state = USBS_STATE_ADDRESSED; if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != endpoint->state_change_fn) { (*endpoint->state_change_fn)(endpoint, endpoint->state_change_data, USBS_STATE_CHANGE_DECONFIGURED, old_state); } result = USBS_CONTROL_RETURN_HANDLED; } else { CYG_ASSERT(1 == endpoint->enumeration_data->device.number_configurations, \ "Higher level code should have handled this request"); if (req->value_lo == endpoint->enumeration_data->configurations[0].configuration_id) { endpoint->state = USBS_STATE_CONFIGURED; if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != endpoint->state_change_fn) { (*endpoint->state_change_fn)(endpoint, endpoint->state_change_data, USBS_STATE_CHANGE_CONFIGURED, old_state); } result = USBS_CONTROL_RETURN_HANDLED; } else { result = USBS_CONTROL_RETURN_STALL; } } } else if (USB_DEVREQ_SET_FEATURE == req->request) { if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) { // The host should expect no data back, the device must // be configured, and there are no defined features to clear. if ((0 == length) && (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) && (0 == req->value_lo)) { int interface_id = req->index_lo; CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \ "Higher level code should have handled this request"); if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) { result = USBS_CONTROL_RETURN_HANDLED; } else { result = USBS_CONTROL_RETURN_STALL; } } else { result = USBS_CONTROL_RETURN_STALL; } } } return result; }
Go to most recent revision | Compare with Previous | Blame | View Log