usbs_sa11x0.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,380 行 · 第 1/5 页
C
1,380 行
} 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) &&
(USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) {
ep2_set_halted(&ep2.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 the hardware.
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_SA11X0_EP1
else if ((USB_DEVREQ_INDEX_DIRECTION_OUT | 1) == endpoint) {
ep1_set_halted(&ep1.common, true);
result = USBS_CONTROL_RETURN_HANDLED;
}
#endif
#ifdef CYGPKG_DEVS_USB_SA11X0_EP2
else if ((USB_DEVREQ_INDEX_DIRECTION_IN | 2) == endpoint) {
ep2_set_halted(&ep2.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 1
if ((USBS_CONTROL_RETURN_UNKNOWN == result) &&
(USB_DEVREQ_SET_INTERFACE == req->request)) {
// This code should not be necessary. For
// non-trivial applications which involve
// alternate interfaces and the like, this request
// should be handled by the application itself.
// For other applications, the default handler
// will ignore this request so we end up falling
// through without actually handling the request
// and hence returning a stall condition. That
// is legitimate behaviour according to the standard.
//
// However, there are appear to be problems with
// the SA1110 USB hardware when it comes to stall
// conditions: they appear to affect some
// subsequent messages from target to host as
// well. Hence rather than returning a stall
// condition this code instead generates a dummy
// reply, which is also valid according to the
// standard. This avoids complications with certain
// USB compliance testers.
if ((0 != length) ||
(0 != req->value_hi) || (0 != req->index_hi) ||
(USBS_STATE_CONFIGURED != (ep0.common.state & USBS_STATE_MASK))) {
result = USBS_CONTROL_RETURN_STALL;
} else {
int interface_id;
int alternate;
CYG_ASSERT( (1 == ep0.common.enumeration_data->device.number_configurations) && \
(1 == ep0.common.enumeration_data->total_number_interfaces), \
"Higher level code should have handled this request");
interface_id = req->index_lo;
alternate = req->value_lo;
if ((interface_id != ep0.common.enumeration_data->interfaces[0].interface_id) ||
(alternate != ep0.common.enumeration_data->interfaces[0].alternate_setting)) {
result = USBS_CONTROL_RETURN_STALL;
} else {
result = USBS_CONTROL_RETURN_HANDLED;
}
}
}
#endif
// If the result has still not been handled, leave it to
// the default implementation in the USB slave common package
if (USBS_CONTROL_RETURN_UNKNOWN == result) {
result = usbs_handle_standard_control(&ep0.common);
}
} else {
// The other three types of control message can be
// handled by similar code.
usbs_control_return (*callback_fn)(usbs_control_endpoint*, void*);
void* callback_arg;
//DBG(("non-standard control request %x", req->request));
if (USB_DEVREQ_TYPE_CLASS == protocol) {
callback_fn = ep0.common.class_control_fn;
callback_arg = ep0.common.class_control_data;
} else if (USB_DEVREQ_TYPE_VENDOR == protocol) {
callback_fn = ep0.common.vendor_control_fn;
callback_arg = ep0.common.vendor_control_data;
} else {
callback_fn = ep0.common.reserved_control_fn;
callback_arg = ep0.common.reserved_control_data;
}
if ((usbs_control_return (*)(usbs_control_endpoint*, void*)) 0 == callback_fn) {
result = USBS_CONTROL_RETURN_STALL;
} else {
result = (*callback_fn)(&ep0.common, callback_arg);
}
}
//DBG(("Control request done, %d\n", result));
if (USBS_CONTROL_RETURN_HANDLED != result) {
// This control request cannot be handled. Generate a stall.
usbs_sa11x0_poke(EP0_CONTROL,
EP0_FORCE_STALL | EP0_SERVICED_OPR | EP0_DATA_END,
EP0_FORCE_STALL,
EP0_OUT_READY);
} else {
// The control request has been handled. Is there any more
// data to be transferred?
if (0 == length) {
usbs_sa11x0_poke(EP0_CONTROL,
EP0_SERVICED_OPR | EP0_DATA_END,
EP0_DATA_END,
EP0_OUT_READY);
} else {
// The endpoint should now go into IN or OUT mode while the
// remaining data is transferred.
ep0.transmitted = 0;
ep0.length = length;
if (USB_DEVREQ_DIRECTION_OUT == direction) {
// Wait for the next packet from the host.
ep0.ep_state = EP0_STATE_OUT;
CYG_ASSERT( (unsigned char*) 0 != ep0.common.buffer, "A receive buffer should have been provided");
CYG_ASSERT( (usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn, \
"A completion function should be provided for OUT control messages");
} else {
ep0.ep_state = EP0_STATE_IN;
usbs_sa11x0_ep0_fill_fifo();
}
}
} // Control message handled
} // Received 8-byte control message
} // Idle state, i.e. control message
} // ep0_dsr
#ifdef CYGPKG_DEVS_USB_SA11X0_EP1
// ----------------------------------------------------------------------------
// Endpoint 1 is used for OUT transfers, i.e. receive operations. Only
// the bulk protocol is supported by the hardware. The semantics allow
// for two different modes of operation: higher-level code can ask for
// exactly one or more bulk packets of 64 bytes each, allowing buffer
// requirements to be determined from a header; alternatively the
// rx request can just supply a large buffer. Processing the first
// packet of a larger transfer separately does not introduce any
// special problems at the protocol level.
//
// It is not legal to receive just part of a packet and expect the
// hardware or the driver to buffer the rest. Not all hardware will
// be capable of doing this buffering, and there should not be
// a driver design requirement to provide buffering space.
//
//
// The hardware design for endpoint 1 is flawed in a number of
// respects. The receive fifo is only 20 bytes, less than the packet
// size, so it is essential to use DMA (there is a configuration
// option to allow for communication protocols where packets will
// never exceed 16 bytes, but that is not the normal case). The DMA
// engine is triggered by a receive-fifo-service high-water mark
// bit. DMA transfers operate in bursts of eight bytes. Therefore
// it would make sense if the high-water mark was set when the
// receive fifo contained eight bytes or more.
//
// Instead the high-water mark is set when the fifo contains twelve
// bytes or more. Worse, there is no way of measuring how many bytes
// there are left in the fifo without actually extracting those bytes.
//
// For a full-size 64-byte packet, the first 56 bytes will be
// transferred by DMA and the remainder will remain in the fifo. For a
// partial packet of between 56 and 63 bytes, the first 56 bytes will
// be transferred by DMA and the remainder will remain in the fifo. There
// is no way to distinguish between these scenarios without emptying
// the fifo.
//
// The result is that there is never any point in attempting a DMA
// transfer of more than 56 bytes, and for every endpoint 1 interrupt
// it is necessary to read the remainder from the fifo. This adds
// a lot of software overhead, and it is not clear that DMA is
// particularly useful. It is still necessary because of the limited
// fifo size.
//
//
// Because DMA involves the use of physical rather than virtual
// memory, there are also cache interaction problems. Specifically it
// would be necessary to invalidate cache lines after a DMA transfer
// has completed, but that only works sensibly if the buffer is
// aligned to a cache-line boundary and is a multiple of the
// cache-line size. Imposing such restrictions on higher-level code
// is undesirable. Also the DMA engines have an apparently undocumented
// restriction that the buffer must be eight-byte aligned.
//
// To work around all these problems, the receive code works in terms
// of a small private buffer. After a packet has been received, data
// will be copied from this private buffer to the destination. Obviously
// this copy operation is overhead and, because the code is expected
// to run at DSR level, However the copy operation is limited to at
// most 64 bytes, which is not good but not disastrous either.
//
// For data transfers the entry points are:
//
// 1) ep1_start_rx_packet() - prepare to receive another packet from
// the host.
// 2) ep1_clear_error() - an error condition has occurred (CRC,
// bit-stuffing, fifo overrun). It appears that the only way
// to clear this is to clear the receive-packet-complete bit,
// which unfortunately allows in another packet fr
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?