📄 usbtarget.c
字号:
/*{{{ Banner *//*=================================================================//// target.c//// USB testing - target-side////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// This program performs appropriate USB initialization and initializes// itself as a specific type of USB peripheral, Red Hat eCos testing.// There is no actual host-side device driver for this, instead there is// a test application which performs ioctl's on /proc/bus/usb/... and// makes appropriate functionality available to a Tcl script.//// Author(s): bartv// Date: 2001-07-04//####DESCRIPTIONEND####//==========================================================================*//*}}}*//*{{{ #include's */#include <stdio.h>#include <cyg/infra/cyg_ass.h>#include <cyg/infra/diag.h>#include <cyg/kernel/kapi.h>#include <cyg/hal/hal_arch.h>#include <cyg/io/io.h>#include <cyg/io/usb/usbs.h>#include <cyg/infra/testcase.h>#include "protocol.h"/*}}}*//*{{{ Statics */// ----------------------------------------------------------------------------// Statics.// The number of endpoints supported by the device driver.static int number_endpoints = 0;// The control endpointstatic usbs_control_endpoint* control_endpoint = (usbs_control_endpoint*) 0;// Buffers for incoming and outgoing data, and a length field.static unsigned char class_request[USBTEST_MAX_CONTROL_DATA + 1];static unsigned char class_reply[USBTEST_MAX_CONTROL_DATA + 1];static int class_request_size = 0;// This semaphore is used by DSRs to wake up the main thread when work has to// be done at thread level.static cyg_sem_t main_wakeup;// And this function pointer identifies the work that has to be done.static void (*main_thread_action)(void) = (void (*)(void)) 0;// Is the system still busy processing a previous request? This variable is// checked in response to the synch request. It may get updated in// DSRs as well as at thread level, hence volatile.static volatile int idle = 1;// Are any tests currently running?static int running = 0;// Has the current batch of tests been terminated by the host? This// flag is checked by the various test handlers at appropriate// intervals, and helps to handle the case where one of the side has// terminated early because an error has been detected.static int current_tests_terminated = 0;// A counter for the number of threads involved in the current batch of tests.static int thread_counter = 0;// An extra buffer for recovery operations, for example to accept and discard// data which the host is still trying to send.static unsigned char recovery_buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA];/*}}}*//*{{{ Logging */// ----------------------------------------------------------------------------// The target-side code can provide various levels of run-time logging.// Obviously the verbose flag cannot be controlled by a command-line// argument, but it can be set from inside gdb or alternatively by// a request from the host.//// NOTE: is printf() the best I/O routine to use here?static int verbose = 0;#define VERBOSE(_level_, _format_, _args_...) \ do { \ if (verbose >= _level_) { \ diag_printf(_format_, ## _args_); \ } \ } while (0);/*}}}*//*{{{ Utilities */// ----------------------------------------------------------------------------// A reimplementation of nanosleep, to avoid having to pull in the// POSIX compatibility testing for USB testing.static voidusbs_nanosleep(int delay){ cyg_tick_count_t ticks; cyg_resolution_t resolution = cyg_clock_get_resolution(cyg_real_time_clock()); // (resolution.dividend/resolution.divisor) == nanoseconds/tick // e.g. 1000000000/100, i.e. 10000000 ns or 10 ms per tick // So ticks = (delay * divisor) / dividend // e.g. (10000000 * 100) / 1000000000 // with a likely value of 0 for delays of less than the clock resolution, // so round those up to one tick. cyg_uint64 tmp = (cyg_uint64) delay; tmp *= (cyg_uint64) resolution.divisor; tmp /= (cyg_uint64) resolution.dividend; ticks = (int) tmp; if (0 != ticks) { cyg_thread_delay(ticks); }}// ----------------------------------------------------------------------------// Fix any problems in the driver-supplied endpoint data//// Maximum transfer sizes are limited not just by the capabilities// of the driver but also by the testing code itself, since e.g.// buffers for transfers are statically allocated.static voidfix_driver_endpoint_data(void){ int i; for (i = 0; !USBS_TESTING_ENDPOINTS_IS_TERMINATOR(usbs_testing_endpoints[i]); i++) { if (USB_ENDPOINT_DESCRIPTOR_ATTR_BULK == usbs_testing_endpoints[i].endpoint_type) { if ((-1 == usbs_testing_endpoints[i].max_size) || (usbs_testing_endpoints[i].max_size > USBTEST_MAX_BULK_DATA)) { usbs_testing_endpoints[i].max_size = USBTEST_MAX_BULK_DATA; } } }}// ----------------------------------------------------------------------------// A heartbeat thread.//// USB tests can run for a long time with no traffic on the debug channel,// which can cause problems. To avoid problems it is possible to have a// heartbeat thread running in the background, sending output at one// second intervals.//// Depending on the configuration the output may still be line-buffered,// but that is still sufficient to keep things happy.static cyg_bool heartbeat = false;static cyg_thread heartbeat_data;static cyg_handle_t heartbeat_handle;static char heartbeat_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];static voidheartbeat_function(cyg_addrword_t arg __attribute((unused))){ char* message = "alive\n"; int i; for ( i = 0; ; i = (i + 1) % 6) { usbs_nanosleep(1000000000); if (heartbeat) { diag_write_char(message[i]); } }}static voidstart_heartbeat(void){ cyg_thread_create( 0, &heartbeat_function, 0, "heartbeat", heartbeat_stack, CYGNUM_HAL_STACK_SIZE_TYPICAL, &heartbeat_handle, &heartbeat_data); cyg_thread_resume(heartbeat_handle);}/*}}}*//*{{{ Endpoint usage */// ----------------------------------------------------------------------------// It is important to keep track of which endpoints are currently in use,// because the behaviour of the USB I/O routines is undefined if there are// concurrent attempts to communicate on the same endpoint. Normally this is// not a problem because the host will ensure that a given endpoint is used// for only one endpoint at a time, but when performing recovery action it// is important that the system is sure that a given endpoint can be accessed// safely.static cyg_bool in_endpoint_in_use[16];static cyg_bool out_endpoint_in_use[16];// Lock the given endpoint. In theory this is only ever accessed from a single// test thread at a time, but just in case...static voidlock_endpoint(int endpoint, int direction){ CYG_ASSERTC((endpoint >=0) && (endpoint < 16)); CYG_ASSERTC((USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN == direction) || (USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT == direction)); cyg_scheduler_lock(); if (0 == endpoint) { // Comms traffic on endpoint 0 is implemented using reserved control messages. // It is not really possible to have concurrent IN and OUT operations because // the two would interfere with each other. CYG_ASSERTC(!in_endpoint_in_use[0] && !out_endpoint_in_use[0]); in_endpoint_in_use[0] = true; out_endpoint_in_use[0] = true; } else if (USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN == direction) { CYG_ASSERTC(!in_endpoint_in_use[endpoint]); in_endpoint_in_use[endpoint] = true; } else { CYG_ASSERTC(!out_endpoint_in_use[endpoint]); out_endpoint_in_use[endpoint] = true; } cyg_scheduler_unlock();}static voidunlock_endpoint(int endpoint, int direction){ CYG_ASSERTC((endpoint >= 0) && (endpoint < 16)); CYG_ASSERTC((USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN == direction) || (USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT == direction)); if (0 == endpoint) { CYG_ASSERTC(in_endpoint_in_use[0] && out_endpoint_in_use[0]); in_endpoint_in_use[0] = false; out_endpoint_in_use[0] = false; } else if (USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN == direction) { CYG_ASSERTC(in_endpoint_in_use[endpoint]); in_endpoint_in_use[endpoint] = false; } else { CYG_ASSERTC(out_endpoint_in_use[endpoint]); out_endpoint_in_use[endpoint] = false; }}static cyg_boolis_endpoint_locked(int endpoint, int direction){ cyg_bool result = false; if (0 == endpoint) { result = in_endpoint_in_use[0]; } else if (USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN == direction) { result = in_endpoint_in_use[endpoint]; } else { result = out_endpoint_in_use[endpoint]; } return result;}// For a given endpoint number, direction and protocol, search through the table // supplied by the device driver of all available endpoints. This can be used// to e.g. get hold of the name of the devtab entry or a pointer to the endpoint// data structure itself.static intlookup_endpoint(int endpoint_number, int direction, int protocol){ int result = -1; int i; for (i = 0; !USBS_TESTING_ENDPOINTS_IS_TERMINATOR(usbs_testing_endpoints[i]); i++) { 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -