📄 usbtarget.c
字号:
if ((usbs_testing_endpoints[i].endpoint_type == protocol) &&
(usbs_testing_endpoints[i].endpoint_number == endpoint_number) &&
(usbs_testing_endpoints[i].endpoint_direction == direction)) {
result = i;
break;
}
}
return result;
}
/*}}}*/
/*{{{ Enumeration data */
// ----------------------------------------------------------------------------
// The enumeration data.
//
// For simplicity this configuration involves just a single interface.
// The target has to list all the endpoints, or the Linux kernel will
// not allow application code to access them. Hence the information
// provided by the device drivers has to be turned into endpoint descriptors.
usb_configuration_descriptor usb_configuration = {
length: USB_CONFIGURATION_DESCRIPTOR_LENGTH,
type: USB_CONFIGURATION_DESCRIPTOR_TYPE,
total_length_lo: USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(1, 0),
total_length_hi: USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(1, 0),
number_interfaces: 1,
configuration_id: 1, // id 0 is special according to the spec
configuration_str: 0,
attributes: USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED |
USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED,
max_power: 50
};
usb_interface_descriptor usb_interface = {
length: USB_INTERFACE_DESCRIPTOR_LENGTH,
type: USB_INTERFACE_DESCRIPTOR_TYPE,
interface_id: 0,
alternate_setting: 0,
number_endpoints: 0,
interface_class: USB_INTERFACE_DESCRIPTOR_CLASS_VENDOR,
interface_subclass: USB_INTERFACE_DESCRIPTOR_SUBCLASS_VENDOR,
interface_protocol: USB_INTERFACE_DESCRIPTOR_PROTOCOL_VENDOR,
interface_str: 0
};
usb_endpoint_descriptor usb_endpoints[USBTEST_MAX_ENDPOINTS];
const unsigned char* usb_strings[] = {
"\004\003\011\004",
"\020\003R\000e\000d\000 \000H\000a\000t\000",
"\054\003R\000e\000d\000 \000H\000a\000t\000 \000e\000C\000o\000s\000 \000"
"U\000S\000B\000 \000t\000e\000s\000t\000"
};
usbs_enumeration_data usb_enum_data = {
{
length: USB_DEVICE_DESCRIPTOR_LENGTH,
type: USB_DEVICE_DESCRIPTOR_TYPE,
usb_spec_lo: USB_DEVICE_DESCRIPTOR_USB11_LO,
usb_spec_hi: USB_DEVICE_DESCRIPTOR_USB11_HI,
device_class: USB_DEVICE_DESCRIPTOR_CLASS_VENDOR,
device_subclass: USB_DEVICE_DESCRIPTOR_SUBCLASS_VENDOR,
device_protocol: USB_DEVICE_DESCRIPTOR_PROTOCOL_VENDOR,
max_packet_size: 8,
vendor_lo: 0x42, // Note: this is not an allocated vendor id
vendor_hi: 0x42,
product_lo: 0x00,
product_hi: 0x01,
device_lo: 0x00,
device_hi: 0x01,
manufacturer_str: 1,
product_str: 2,
serial_number_str: 0,
number_configurations: 1
},
total_number_interfaces: 1,
total_number_endpoints: 0,
total_number_strings: 3,
configurations: &usb_configuration,
interfaces: &usb_interface,
endpoints: usb_endpoints,
strings: usb_strings
};
static void
provide_endpoint_enumeration_data(void)
{
int enum_endpoint_count = 0;
int i;
for (i = 0; !USBS_TESTING_ENDPOINTS_IS_TERMINATOR(usbs_testing_endpoints[i]); i++) {
// The control endpoint need not appear in the enumeration data.
if (USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL == usbs_testing_endpoints[i].endpoint_type) {
continue;
}
usb_endpoints[enum_endpoint_count].length = USB_ENDPOINT_DESCRIPTOR_LENGTH;
usb_endpoints[enum_endpoint_count].type = USB_ENDPOINT_DESCRIPTOR_TYPE;
usb_endpoints[enum_endpoint_count].endpoint = usbs_testing_endpoints[i].endpoint_number |
usbs_testing_endpoints[i].endpoint_direction;
switch (usbs_testing_endpoints[i].endpoint_type) {
case USB_ENDPOINT_DESCRIPTOR_ATTR_BULK:
usb_endpoints[enum_endpoint_count].attributes = USB_ENDPOINT_DESCRIPTOR_ATTR_BULK;
usb_endpoints[enum_endpoint_count].max_packet_lo = 64;
usb_endpoints[enum_endpoint_count].max_packet_hi = 0;
usb_endpoints[enum_endpoint_count].interval = 0;
break;
case USB_ENDPOINT_DESCRIPTOR_ATTR_ISOCHRONOUS:
usb_endpoints[enum_endpoint_count].attributes = USB_ENDPOINT_DESCRIPTOR_ATTR_ISOCHRONOUS;
usb_endpoints[enum_endpoint_count].max_packet_lo = usbs_testing_endpoints[i].max_size & 0x0FF;
usb_endpoints[enum_endpoint_count].max_packet_hi = (usbs_testing_endpoints[i].max_size >> 8) & 0x0FF;
usb_endpoints[enum_endpoint_count].interval = 1;
break;
case USB_ENDPOINT_DESCRIPTOR_ATTR_INTERRUPT:
usb_endpoints[enum_endpoint_count].attributes = USB_ENDPOINT_DESCRIPTOR_ATTR_INTERRUPT;
usb_endpoints[enum_endpoint_count].max_packet_lo = (unsigned char) usbs_testing_endpoints[i].max_size;
usb_endpoints[enum_endpoint_count].max_packet_hi = 0;
usb_endpoints[enum_endpoint_count].interval = 1; // NOTE: possibly incorrect
break;
}
enum_endpoint_count++;
}
usb_interface.number_endpoints = enum_endpoint_count;
usb_enum_data.total_number_endpoints = enum_endpoint_count;
usb_configuration.total_length_lo = USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(1, enum_endpoint_count);
usb_configuration.total_length_hi = USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(1, enum_endpoint_count);
}
/*}}}*/
/*{{{ Host/target common code */
#define TARGET
#include "common.c"
/*}}}*/
/*{{{ The tests */
/*{{{ UsbTest structure */
// ----------------------------------------------------------------------------
// All the information associated with a particular testcase. Much of this
// is identical to the equivalent host-side structure, but some additional
// information is needed so the structure and associated routines are not
// shared.
typedef struct UsbTest {
// A unique identifier to make verbose output easier to understand
int id;
// Which test should be run
usbtest which_test;
// Test-specific details.
union {
UsbTest_Bulk bulk;
UsbTest_ControlIn control_in;
} test_params;
// How to recover from any problems. Specifically, what kind of message
// could the target send or receive that would unlock the thread on this
// side.
UsbTest_Recovery recovery;
// The test result, to be collected and passed back to the host.
int result_pass;
char result_message[USBTEST_MAX_MESSAGE];
// Support for synchronization. This allows the UsbTest structure to be
// used as the callback data for low-level USB calls.
cyg_sem_t sem;
int transferred;
// Some tests may need extra cancellation support
void (*cancel_fn)(struct UsbTest*);
unsigned char buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA];
} UsbTest;
// Reset the information in a given test. This is used by the pool allocation
// code. The data union is left alone, filling in the appropriate union
// member is left to other code.
static void
reset_usbtest(UsbTest* test)
{
static int next_id = 1;
test->id = next_id++;
test->which_test = usbtest_invalid;
usbtest_recovery_reset(&(test->recovery));
test->result_pass = 0;
test->result_message[0] = '\0';
cyg_semaphore_init(&(test->sem), 0);
test->transferred = 0;
test->cancel_fn = (void (*)(UsbTest*)) 0;
}
// Forward declaration. The pool code depends on run_test(), setting up a test requires the pool.
static UsbTest* pool_allocate(void);
/*}}}*/
/*{{{ Bulk transfers */
/*{{{ handle_test_bulk() */
// Prepare for a bulk transfer test. This means allocating a thread to do
// the work, and extracting the test parameters from the current buffer.
// The thread allocation code does not require any locking since all worker
// threads should be idle when starting a new thread, so the work can be
// done entirely at DSR level and no synch is required.
static usbs_control_return
handle_test_bulk(usb_devreq* req)
{
UsbTest* test;
int index = 0;
test = pool_allocate();
unpack_usbtest_bulk(&(test->test_params.bulk), class_request, &index);
test->which_test = (USB_DEVREQ_DIRECTION_IN == (test->test_params.bulk.endpoint & USB_DEVREQ_DIRECTION_MASK)) ?
usbtest_bulk_in : usbtest_bulk_out;
VERBOSE(3, "Preparing USB bulk test on endpoint %d, direction %s, for %d packets\n", \
test->test_params.bulk.endpoint & ~USB_DEVREQ_DIRECTION_MASK, \
(usbtest_bulk_in == test->which_test) ? "IN" : "OUT", \
test->test_params.bulk.number_packets);
VERBOSE(3, " I/O mechanism is %s\n", \
(usb_io_mechanism_usb == test->test_params.bulk.io_mechanism) ? "low-level USB" : \
(usb_io_mechanism_dev == test->test_params.bulk.io_mechanism) ? "devtab" : "<invalid>");
VERBOSE(3, " Data format %s, data1 %d, data* %d, data+ %d, data1* %d, data1+ %d, data** %d, data*+ %d, data+* %d, data++ %d\n",\
(usbtestdata_none == test->test_params.bulk.data.format) ? "none" : \
(usbtestdata_bytefill == test->test_params.bulk.data.format) ? "bytefill" : \
(usbtestdata_wordfill == test->test_params.bulk.data.format) ? "wordfill" : \
(usbtestdata_byteseq == test->test_params.bulk.data.format) ? "byteseq" : \
(usbtestdata_wordseq == test->test_params.bulk.data.format) ? "wordseq" : "<invalid>", \
test->test_params.bulk.data.seed, \
test->test_params.bulk.data.multiplier, \
test->test_params.bulk.data.increment, \
test->test_params.bulk.data.transfer_seed_multiplier, \
test->test_params.bulk.data.transfer_seed_increment, \
test->test_params.bulk.data.transfer_multiplier_multiplier, \
test->test_params.bulk.data.transfer_multiplier_increment, \
test->test_params.bulk.data.transfer_increment_multiplier, \
test->test_params.bulk.data.transfer_increment_increment);
VERBOSE(3, " txsize1 %d, txsize>= %d, txsize<= %d, txsize* %d, txsize/ %d, txsize+ %d\n", \
test->test_params.bulk.tx_size, test->test_params.bulk.tx_size_min, \
test->test_params.bulk.tx_size_max, test->test_params.bulk.tx_size_multiplier, \
test->test_params.bulk.tx_size_divisor, test->test_params.bulk.tx_size_increment);
VERBOSE(3, " rxsize1 %d, rxsize>= %d, rxsize<= %d, rxsize* %d, rxsize/ %d, rxsize+ %d\n", \
test->test_params.bulk.rx_size, test->test_params.bulk.rx_size_min, \
test->test_params.bulk.rx_size_max, test->test_params.bulk.rx_size_multiplier, \
test->test_params.bulk.rx_size_divisor, test->test_params.bulk.rx_size_increment);
VERBOSE(3, " txdelay1 %d, txdelay>= %d, txdelay<= %d, txdelay* %d, txdelay/ %d, txdelay+ %d\n", \
test->test_params.bulk.tx_delay, test->test_params.bulk.tx_delay_min, \
test->test_params.bulk.tx_delay_max, test->test_params.bulk.tx_delay_multiplier, \
test->test_params.bulk.tx_delay_divisor, test->test_params.bulk.tx_delay_increment);
VERBOSE(3, " rxdelay1 %d, rxdelay>= %d, rxdelay<= %d, rxdelay* %d, rxdelay/ %d, rxdelay+ %d\n", \
test->test_params.bulk.rx_delay, test->test_params.bulk.rx_delay_min, \
test->test_params.bulk.rx_delay_max, test->test_params.bulk.rx_delay_multiplier, \
test->test_params.bulk.rx_delay_divisor, test->test_params.bulk.rx_delay_increment);
return USBS_CONTROL_RETURN_HANDLED;
}
/*}}}*/
/*{{{ run_test_bulk_out() */
// The same callback can be used for IN and OUT transfers. Note that
// starting the next transfer is left to the thread, it is not done
// at DSR level.
static void
run_test_bulk_in_out_callback(void* callback_arg, int transferred)
{
UsbTest* test = (UsbTest*) callback_arg;
test->transferred = transferred;
cyg_semaphore_post(&(test->sem));
}
// OUT transfers, i.e. the host will be sending some number of
// packets. The I/O can happen in a number of different ways, e.g. via
// the low-level USB API or via devtab routines.
static void
run_test_bulk_out(UsbTest* test)
{
unsigned char* buf;
int endpoint_number = test->test_params.bulk.endpoint & ~USB_DEVREQ_DIRECTION_MASK;
int ep_index;
usbs_rx_endpoint* endpoint = 0;
cyg_io_handle_t io_handle = (cyg_io_handle_t)0;
int alignment;
int transferred;
int i;
VERBOSE(1, "Starting test %d, bulk out on endpoint %d\n", test->id, endpoint_number);
ep_index = lookup_endpoint(endpoint_number, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT, USB_ENDPOINT_DESCRIPTOR_ATTR_BULK);
if (ep_index == -1) {
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Target, bulk OUT transfer on endpoint %d: no such bulk endpoint", endpoint_number);
return;
}
endpoint = (usbs_rx_endpoint*) usbs_testing_endpoints[ep_index].endpoint;
alignment = usbs_testing_endpoints[ep_index].alignment;
if (0 != alignment) {
buf = (unsigned char*) ((((cyg_uint32)test->buffer) + alignment - 1) & ~(alignment - 1));
} else {
buf = test->buffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -