📄 usbtarget.c
字号:
} 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 voidprovide_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 voidreset_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_returnhandle_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 voidrun_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 voidrun_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; } CYG_ASSERTC((usb_io_mechanism_usb == test->test_params.bulk.io_mechanism) || \ (usb_io_mechanism_dev == test->test_params.bulk.io_mechanism)); if (usb_io_mechanism_dev == test->test_params.bulk.io_mechanism) { if (((const char*)0 == usbs_testing_endpoints[ep_index].devtab_entry) || (0 != cyg_io_lookup(usbs_testing_endpoints[ep_index].devtab_entry, &io_handle))) { test->result_pass = 0; snprintf(test->result_message, USBTEST_MAX_MESSAGE, "Target, bulk OUT transfer on endpoint %d: no devtab entry", endpoint_number); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -