📄 usbs_sa11x0.c
字号:
for (retries = 0; !read && (retries < MAX_RETRIES); retries++) {
if ((count - emptied) != *EP0_WRITE_COUNT) {
DBG(("EP0_empty_fifo, inconsistency, read %d bytes of %d, but fifo count %d\n", emptied, count, *EP0_WRITE_COUNT));
ok = false;
} else {
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 void
usbs_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.
//
// 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))) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -