📄 usbs_upd985xx.c
字号:
return; } } // We have a valid receive, with the data held in uncached->ep0_rx_buffer. // Are we expecting the remaining data of a control transfer? if (ep0.rx_expecting_data) { // Was this data interrupted by a new setup packet? if (0 != (ep0.rx_indicator.status & RXMBOX_STATUS_SETUP_SETUP)) { // NOTE: it is not clear from the documentation exactly what // happens here, e.g. is it guaranteed that the new control // packet appears at the start of the buffer rather than // after any data previously received? Given typical // USB host-side implementations this scenario is considered // sufficiently unlikely that no further investigation has // been carried out. // Inform higher-level code that the receive has been aborted. if ((usbs_control_return (*)(usbs_control_endpoint*, int)) 0 != ep0.common.complete_fn) { (*ep0.common.complete_fn)(&ep0.common, -EIO); } ep0.rx_expecting_data = false; ep0.common.buffer = (unsigned char*) 0; ep0.common.buffer_size = 0; ep0.common.fill_buffer_fn = 0; ep0.common.complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, int)) 0; // Fall through the main control message handling code below. } else { // Data was expected and received. Transfer the data to the // user's buffer, and perform completion. usbs_control_return result; cyg_uint32 size = ep0.rx_indicator.status & RXMBOX_STATUS_SIZE_MASK; CYG_ASSERT( (usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn, \ "A completion function should be provided for OUT control messages"); CYG_ASSERT(size == ep0.common.buffer_size, "Inconsistency between buffer and transfer sizes"); memcpy(ep0.common.buffer, uncached->ep0_rx_buffer, size); result = (*ep0.common.complete_fn)(&ep0.common, 0); ep0.common.buffer = (unsigned char*) 0; ep0.common.buffer_size = 0; ep0.common.complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, int)) 0; ep0.rx_expecting_data = false; // Start another receive for the next control message. // Note that there has been a window where there was no receive // in progress for endpoint 0, even though according to the // USB spec a device must always be able to accept new // control messages. ep0_start_rx(8); return; } } // When we get here we should have an eight-byte control message // in uncached->ep0_rx_buffer. This should get moved into // the ep0.common.control_buffer so that higher-level code sees // it in the appropriate location. CYG_ASSERT((ep0.rx_indicator.address == &(uncached->ep0_rx_bufdescs[0])) || \ (ep0.rx_indicator.address == &(uncached->ep0_rx_bufdescs[2])), \ "Received ep0 data should involve the ep0 rx buffer descriptor"); CYG_ASSERT(8 == (ep0.rx_indicator.status & RXMBOX_STATUS_SIZE_MASK), "Control messages should be 8 bytes"); memcpy(ep0.common.control_buffer, uncached->ep0_rx_buffer, 8); // If we have received a control packet then any reset signals really // will have come from the host and must be processed normally. // Make sure that reset interrupts are no longer masked off. if (0 == (*USBS_IMR2 & IBUS_SWAP32(USBS_GSR2_URST))) { *USBS_IMR2 |= IBUS_SWAP32(USBS_GSR2_URST); FLUSH_IBUS(); usbs_upd985xx_gsr2_mask |= USBS_GSR2_URST; } { usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN; usb_devreq* req = (usb_devreq*) ep0.common.control_buffer; int length, direction, protocol, recipient; // Now we need to do some decoding of the data. A non-zero // length field indicates that there will be a subsequent // IN or OUT phase. The direction is controlled by the // top bit of the first byte. The protocol is determined // by other bits of the top byte. length = (req->length_hi << 8) | req->length_lo; direction = req->type & USB_DEVREQ_DIRECTION_MASK; protocol = req->type & USB_DEVREQ_TYPE_MASK; recipient = req->type & USB_DEVREQ_RECIPIENT_MASK; DBG(("ep0, new control request: type %x, code %x\n", req->type, req->request)); DBG((" %s, length %d, value hi %x lo %x, index hi %x lo %x\n", (USB_DEVREQ_DIRECTION_OUT == direction) ? "out" : "in", length, req->value_hi, req->value_lo, req->index_hi, req->index_lo)); if (USB_DEVREQ_TYPE_STANDARD == protocol) { // First see if the request can be handled entirely in // this module. if (USB_DEVREQ_SET_ADDRESS == req->request) { // The USB device address should be in value_lo. // No more data is expected. int old_state = ep0.common.state; int address = req->value_lo; if ((0 != length) || (address > 127)) { result = USBS_CONTROL_RETURN_STALL; } else { *USBS_GMR = (*USBS_GMR & ~(USBS_GMR_FA_MASK | USBS_GMR_VT)) | (address << USBS_GMR_FA_SHIFT); FLUSH_IBUS(); result = USBS_CONTROL_RETURN_HANDLED; } // Switch to addressed state, informing higher-level // code of this. if (USBS_STATE_ADDRESSED != (old_state & USBS_STATE_MASK)) { ep0.common.state = USBS_STATE_ADDRESSED; if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != ep0.common.state_change_fn) { (*ep0.common.state_change_fn)(&ep0.common, ep0.common.state_change_data, USBS_STATE_CHANGE_ADDRESSED, old_state); } } // End of SET_ADDRESS handling } else if (USB_DEVREQ_GET_STATUS == req->request) { // GET_STATUS on the device as a whole is used to // check the remote-wakeup and self-powered bits. // GET_STATUS on an endpoint is used to determine // the halted condition. // GET_STATUS on anything else has to be left to // other code. if (USB_DEVREQ_RECIPIENT_DEVICE == recipient) { // The host should expect two bytes back. if ((2 == length) && (USB_DEVREQ_DIRECTION_IN == direction)) { ep0.common.control_buffer[0] = 0; // Not self-powered, no remote wakeup ep0.common.control_buffer[1] = 0; ep0.common.buffer = ep0.common.control_buffer; ep0.common.buffer_size = 2; result = USBS_CONTROL_RETURN_HANDLED; } else { result = USBS_CONTROL_RETURN_STALL; } } else if (USB_DEVREQ_RECIPIENT_ENDPOINT == recipient) { if ((2 == length) && (USB_DEVREQ_DIRECTION_IN == direction)) { int endpoint = req->index_lo; if (0 == endpoint) { // get-status on endpoint 0 is either undefined or always valid. // endpoint 0 is always up. ep0.common.control_buffer[0] = 0; result = USBS_CONTROL_RETURN_HANDLED; }#ifdef CYGPKG_DEVS_USB_UPD985XX_EP3 else if (((USB_DEVREQ_INDEX_DIRECTION_IN | 3) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep0.common.control_buffer[0] = ep3.common.halted; result = USBS_CONTROL_RETURN_HANDLED; }#endif #ifdef CYGPKG_DEVS_USB_UPD985XX_EP4 else if (((USB_DEVREQ_INDEX_DIRECTION_OUT | 4) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep0.common.control_buffer[0] = ep4.common.halted; result = USBS_CONTROL_RETURN_HANDLED; }#endif #ifdef CYGPKG_DEVS_USB_UPD985XX_EP5 else if (((USB_DEVREQ_INDEX_DIRECTION_IN | 5) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep0.common.control_buffer[0] = ep5.common.halted; result = USBS_CONTROL_RETURN_HANDLED; }#endif else { // An invalid endpoint has been specified or the // endpoint can only be examined in configured state. result = USBS_CONTROL_RETURN_STALL; } if (USBS_CONTROL_RETURN_HANDLED == result) { ep0.common.control_buffer[1] = 0; ep0.common.buffer = ep0.common.control_buffer; ep0.common.buffer_size = 2; } } else { result = USBS_CONTROL_RETURN_STALL; } } // Endpoint or device get-status } else if (USB_DEVREQ_CLEAR_FEATURE == req->request) { // CLEAR_FEATURE operates in much the same way as // GET_STATUS if (USB_DEVREQ_RECIPIENT_DEVICE == recipient) { // No data should be transferred, and only remote-wakeup can be cleared. if ((0 != length) || (USB_DEVREQ_FEATURE_DEVICE_REMOTE_WAKEUP != req->value_lo)) { result = USBS_CONTROL_RETURN_STALL; } else { // Clearing remote-wakeup is a no-op. result = USBS_CONTROL_RETURN_HANDLED; } } else if (USB_DEVREQ_RECIPIENT_ENDPOINT == recipient) { // The only feature that can be cleared is endpoint-halt, no data should be transferred. if ((0 != length) || (USB_DEVREQ_FEATURE_ENDPOINT_HALT != req->value_lo)) { result = USBS_CONTROL_RETURN_STALL; } else { int endpoint = req->index_lo; if (0 == endpoint) { // Clearing halt on endpoint 0 is always a no-op since that endpoint cannot be halted }#ifdef CYGPKG_DEVS_USB_UPD985XX_EP3 else if (((USB_DEVREQ_INDEX_DIRECTION_IN | 3) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep3_set_halted(&ep3.common, false); result = USBS_CONTROL_RETURN_HANDLED; }#endif#ifdef CYGPKG_DEVS_USB_UPD985XX_EP4 else if (((USB_DEVREQ_INDEX_DIRECTION_OUT | 4) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep4_set_halted(&ep4.common, false); result = USBS_CONTROL_RETURN_HANDLED; }#endif#ifdef CYGPKG_DEVS_USB_UPD985XX_EP5 else if (((USB_DEVREQ_INDEX_DIRECTION_IN | 5) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep5_set_halted(&ep5.common, false); result = USBS_CONTROL_RETURN_HANDLED; }#endif else { // Invalid endpoint or not in configured state. result = USBS_CONTROL_RETURN_STALL; } } } // Endpoing or device clear-feature } else if (USB_DEVREQ_SET_FEATURE == req->request) { // SET_FEATURE also operates in much the same way as // GET_STATUS if (USB_DEVREQ_RECIPIENT_DEVICE == recipient) { // The only valid feature that can be set is remote-wakeup, // which is not supported by this driver. result = USBS_CONTROL_RETURN_STALL; } else if (USB_DEVREQ_RECIPIENT_ENDPOINT == recipient) { // Only the halt condition can be set, and no data should be transferred. // Halting endpoint 0 should probably be disallowed although the // standard does not explicitly say so. if ((0 != length) || (USB_DEVREQ_FEATURE_ENDPOINT_HALT != req->value_lo) || (USBS_STATE_CONFIGURED != (ep0.common.state & USBS_STATE_MASK))) { result = USBS_CONTROL_RETURN_STALL; } else { int endpoint = req->index_lo; if (0) { }#ifdef CYGPKG_DEVS_USB_UPD985XX_EP3 else if ((USB_DEVREQ_INDEX_DIRECTION_IN | 3) == endpoint) { ep3_set_halted(&ep3.common, true); result = USBS_CONTROL_RETURN_HANDLED; }#endif #ifdef CYGPKG_DEVS_USB_UPD985XX_EP4 else if ((USB_DEVREQ_INDEX_DIRECTION_OUT | 4) == endpoint) { ep4_set_halted(&ep4.common, true); result = USBS_CONTROL_RETURN_HANDLED; }#endif #ifdef CYGPKG_DEVS_USB_UPD985XX_EP5 else if ((USB_DEVREQ_INDEX_DIRECTION_IN | 5) == endpoint) { ep5_set_halted(&ep5.common, true); result = USBS_CONTROL_RETURN_HANDLED; }#endif else { result = USBS_CONTROL_RETURN_STALL; } } } // Endpoint or device set-feature } // If the result has not been handled yet, pass it to // the installed callback function (if any). if (USBS_CONTROL_RETURN_UNKNOWN == result) { if ((usbs_control_return (*)(usbs_control_endpoint*, void*))0 != ep0.common.standard_control_fn) { result = (*ep0.common.standard_control_fn)(&ep0.common, ep0.common.standard_control_data); } } // If the result has still not been handled, leave it to // the default implementation in the USB slave common place. if (USBS_CONTROL_RETURN_UNKNOWN == result) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -