📄 usbs_sa11x0.c
字号:
buf[emptied] = *EP0_DATA; for (checks = 0; !read && (checks < MAX_CHECKS); checks++) { if ((count - emptied) > *EP0_WRITE_COUNT) { //DBG(("Read %d byte (%x) after %d checks, %d retries\n", emptied, buf[emptied], checks, retries)); read = true; emptied++; } } } } if (ok && !read) { DBG(("EP0 empty fifo, failed to read byte from fifo\n")); ok = false; } } return emptied;}// This is where all the hard work happens. It is a very large routine// for a DSR, but in practice nearly all of it is nested if's and very// little code actually gets executed. Note that there may be// invocations of callback functions and the driver has no control// over how much time those will take, but those callbacks should be// simple.static voidusbs_sa11x0_ep0_dsr(void){ int hw_state = *EP0_CONTROL; // Handle the stall bits. // // Force-stall should not be a problem. It is set by the code here // if the host needs to be told that the control message was // unacceptable and is cleared automatically by the hardware after // the stall is sent. // NOTE: it is not clear the hardware actually works in this // respect. The FORCE_STALL bit has been observed still set during // the next interrupt, and the host appears to receive spurious // data back in response to the next control packet. // // Sent-stall is set by the hardware following a protocol // violation, e.g. if there is an IN token when a new control // message is expected. There is nothing the software can do about // this. However if we are in the middle of an IN or OUT transfer // then those are not going to complete successfully. if (0 != (hw_state & EP0_SENT_STALL)) { if (EP0_STATE_IDLE != ep0.ep_state) { if ((usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn) { (*ep0.common.complete_fn)(&ep0.common, -EIO); } ep0.ep_state = EP0_STATE_IDLE; 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; } usbs_sa11x0_poke(EP0_CONTROL, EP0_SENT_STALL, 0, EP0_SENT_STALL); } // STALL condition // Next, check whether we have received a new control message // while still busy processing an old one. if (0 != (hw_state & EP0_SETUP_END)) { if (EP0_STATE_IDLE != ep0.ep_state) { if ((usbs_control_return (*)(usbs_control_endpoint*, int)) 0 != ep0.common.complete_fn) { (*ep0.common.complete_fn)(&ep0.common, -EIO); } ep0.ep_state = EP0_STATE_IDLE; 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; } // We are now back in idle state so the control message will be // extracted and processed. usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_SETUP_END, 0, EP0_SETUP_END); } // Interrupted control transaction // The endpoint can be in one of three states: IN, OUT, or IDLE. // For the first two it should mean that there is more data to be // transferred, which is pretty straightforward. IDLE means // that a new control message has arrived. if ((EP0_STATE_IN == ep0.ep_state) && (0 == (EP0_IN_READY & hw_state))) { usbs_sa11x0_ep0_fill_fifo(); } else if ((EP0_STATE_OUT == ep0.ep_state) && (0 != (EP0_OUT_READY & hw_state))) { // A host->device transfer. Higher level code must have // provided a suitable buffer. CYG_ASSERT( (unsigned char*)0 != ep0.common.buffer, "A receive buffer should have been provided" ); ep0.transmitted += usbs_sa11x0_ep0_empty_fifo(ep0.common.buffer + ep0.transmitted); if (ep0.transmitted != ep0.length) { // The host is not allowed to send more data than it // indicated in the original control message, and all // messages until the last one should be full size. CYG_ASSERT( ep0.transmitted < ep0.length, "The host must not send more data than expected"); CYG_ASSERT( 0 == (ep0.transmitted % EP0_FIFO_SIZE), "All OUT packets until the last one should be full-size"); usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_OPR, 0, EP0_OUT_READY); } else { // The whole transfer is now complete. Invoke the // completion function, and based on its return value // either generate a stall or complete the message. usbs_control_return result; CYG_ASSERT( (usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn, \ "A completion function should be provided for OUT control messages"); 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; if (USBS_CONTROL_RETURN_HANDLED == result) { usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_OPR | EP0_DATA_END, EP0_DATA_END, EP0_OUT_READY); } else { usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_OPR | EP0_DATA_END | EP0_FORCE_STALL, EP0_FORCE_STALL, EP0_OUT_READY); } // Also remember to switch back to IDLE state ep0.ep_state = EP0_STATE_IDLE; } } else if (0 != (EP0_OUT_READY & hw_state)) { int emptied = usbs_sa11x0_ep0_empty_fifo(ep0.common.control_buffer); if (8 != emptied) { // This indicates a serious problem somewhere. Respond by // stalling. Hopefully the host will take some action that // sorts out the mess. usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_OPR | EP0_DATA_END | EP0_FORCE_STALL, EP0_FORCE_STALL, EP0_OUT_READY); } else { 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;#if 0 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));#endif if (0 != length){ // Clear the fifo straightaway. There is no harm in // doing this here. It may or may not do some good. usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_OPR, 0, EP0_OUT_READY); } 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 address = req->value_lo; if ((0 != length) || (address > 127)) { result = USBS_CONTROL_RETURN_STALL; } else { // poke_value() cannot be used here because // setting the address does not take effect // until the status phase. *USBS_ADDRESS = address; result = USBS_CONTROL_RETURN_HANDLED; } } 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_SA11X0_EP1 else if (((USB_DEVREQ_INDEX_DIRECTION_OUT | 1) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep0.common.control_buffer[0] = ep1.common.halted; result = USBS_CONTROL_RETURN_HANDLED; }#endif #ifdef CYGPKG_DEVS_USB_SA11X0_EP2 else if (((USB_DEVREQ_INDEX_DIRECTION_IN | 2) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep0.common.control_buffer[0] = ep2.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_SA11X0_EP1 else if (((USB_DEVREQ_INDEX_DIRECTION_OUT | 1) == endpoint) && (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) { ep1_set_halted(&ep1.common, false); result = USBS_CONTROL_RETURN_HANDLED; }#endif#ifdef CYGPKG_DEVS_USB_SA11X0_EP2 else if (((USB_DEVREQ_INDEX_DIRECTION_IN | 2) == endpoint) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -