usbs.c

来自「eCos操作系统源码」· C语言 代码 · 共 714 行 · 第 1/3 页

C
714
字号
        // 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;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?