X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=doc%2Fhtml%2Fref%2Fusbs-testing.html;fp=doc%2Fhtml%2Fref%2Fusbs-testing.html;h=0000000000000000000000000000000000000000;hb=739c21725ce2774a605a0f1de3edaac2c43aea0f;hp=7fd68165b933c429ebf529d85147dcd691a8c1b2;hpb=ae71e0fa8076a1b59600b3a0ea10155a2cb534ae;p=karo-tx-redboot.git diff --git a/doc/html/ref/usbs-testing.html b/doc/html/ref/usbs-testing.html deleted file mode 100644 index 7fd68165..00000000 --- a/doc/html/ref/usbs-testing.html +++ /dev/null @@ -1,2285 +0,0 @@ - - - - - - - - -
The support for USB testing provided by the eCos USB common slave -package is somewhat different in nature from the kind of testing used -in many other packages. One obvious problem is that USB tests cannot -be run on just a bare target platform: instead the target platform -must be connected to a suitable USB host machine, and that host -machine must be running appropriate software for the test code to -interact with. This is very different from say a kernel test which -typically will have no external dependencies. Another important -difference between USB testing and say a C library -strcmp test is sensitivity to timing and to -hardware boundary conditions: although a simple test case that just -performs a small number of USB transfers is better than no testing at -all, it should also be possible to run tests for hours or days on end, -under a variety of loads. In order to provide the required -functionality the basic architecture of the USB testing support is as -follows:
There is a single target-side program - usbtarget. By default when this is run - on a target platform it will appear to do nothing. In fact it is - waiting to be contacted by another program - usbhost which will tell it what test or - tests to run. usbtarget provides - mechanisms for running a wide range of tests. -
usbtarget is a generic program, but USB - testing depends to some extent on the functionality provided by the - hardware. For example there is no point in testing bulk transmits - to endpoint 12 if the target hardware does not support an endpoint - 12. Therefore each USB device driver should supply information about - what the hardware is actually capable of, in the form of an array of - usbs_testing_endpoint data structures. -
There is a single host-side program - usbhost, which acts as a counterpart to - usbtarget. Again - usbhost has no built-in knowledge of - the test or tests that are supposed to run, it only provides - mechanisms for running a wide range of tests. On start-up - usbhost will search the USB bus for - hardware running the target-side program, specifically a USB device - that identifies itself as the product "Red Hat eCos - USB test". -
usbhost contains a Tcl interpreter, and - will execute any Tcl scripts specified on the command line - together with appropriate arguments. The Tcl interpreter has been - extended with various commands such as - usbtest::bulktest, so the script can perform - the desired test or tests. -
Adding a new test simply involves writing a short Tcl script that - invokes the appropriate USB-specific commands. Running multiple - tests involves passing appropriate arguments to - usbhost, or alternatively writing a - single script that just invokes other scripts. -
The current implementation of usbhost -depends heavily on functionality provided by the Linux kernel and in -particular the usbdevfs support. It uses -/proc/bus/usb/devices to find out what devices -are attached to the bus, and will then access the device by opening -/proc/bus/usb/xxx/yyy and performing -ioctl operations. This allows USB testing to take -place without having to write a new host-side device driver, but -getting the code working on host machines not running Linux would -obviously be problematical.
The target-side component of the USB testing software consists of a -single program usbtarget which contains -support for a range of different tests, under the control of host-side -software. This program is not built by default alongside other eCos -test cases since it will only operate in certain environments, -specifically when the target board's connector is plugged into a Linux -host, and when the appropriate host-side software has been installed -on that host. Instead the user must enable a configuration option -CYGBLD_IO_USB_SLAVE_USBTEST to add the program to -the list of tests for the current configuration.
Starting the usbtarget program does not -require anything unusual, so it can be run in a normal -gdb session just like any eCos application. -After initialization the program will wait for activity from the host. -Depending on the hardware, the Linux host will detect that a new USB -peripheral is present on the bus either when the -usbtarget initialization is complete or -when the cable between target and host is connected. The host will -perform the normal USB enumeration sequence and discover that the -peripheral does not match any known vendor or product id and that -there is no device driver for "Red Hat eCos USB -test", so it will ignore the peripheral. When the -usbhost program is run on the host it will -connect to the target-side software, and testing can now commence.
Note: In theory the host-side software should be built when the package is -installed in the component repository, and removed when a package -is uninstalled. The current eCos administration tool does not provide -this functionality.
The host-side software should be built via the usual sequence of -"configure/make/make install". It can only be built on a -Linux host and the configure script contains an -explicit test for this. Because the eCos component repository should -generally be treated as a read-only resource the configure script will -also prevent you from trying to build inside the source tree. Instead -a separate build tree is required. Hence a typical sequence for -building the host-side software would be as follows:
$ mkdir usbhost_build -$ cd usbhost_build -$ <repo>packages/io/usb/slave/current/host/configure <args> -$ make -<output from make> -$ su -$ make install -<output from make install> -$ |
During make install the following actions will take -place:
usbhost will be installed in /usr/local/bin, -or some other bin directory if -the default location is changed at configure-time using a ---prefix= or similar option. It will be -installed as the executable -usbhost_<version>, for example -usbhost_current, thus allowing several -releases of the USB slave package to co-exist. For convenience a -symbolic link from usbhost to this executable -will be created, so users can just run usbhost to -access the most recently-installed version.
usbchmod will be installed in -/usr/local/libexec/ecos/io_usb_slave_<version>. -This program should only be run by usbhost, -not invoked directly, so it is not placed in the bin -directory. Again the presence of the package version in the directory -name allows multiple releases of the package to co-exist.
A Tcl script usbhost.tcl will get installed in -the same directory as usbchmod. This Tcl -script is loaded automatically by the -usbhost executable.
A number of additional Tcl scripts, for example -list.tcl will get installed alongside -usbhost.tcl. These correspond to various test -cases provided as standard. If a given test case is specified on the -command line and cannot be found relative to the current directory -then usbhost will search the install -directory for these test cases.
Note: Strictly speaking installing the usbhost.tcl and -other Tcl scripts below the libexec -directory deviates from standard practice: they are -architecture-independent data files so should be installed below -the share subdirectory. In -practice the files are sufficiently small that there is no point in -sharing them, and keeping them below libexec -simplifies the host-side software somewhat.
The usbhost should be run only when there is a -suitable target attached to the USB bus and running the -usbtarget program. It will search -/proc/bus/usb/devices for an entry corresponding -to this program, invoke usbchmod if -necessary to change the access rights, and then interact with -usbtarget over the USB bus. -usbhost should be invoked as follows:
$ usbhost [-v|--version] [-h|--help] [-V|--verbose] <test> [<test parameters>] |
The -v or --version -option will display version information for -usbhost including the version of the USB -slave package that was used to build the executable.
The -h or --help option -will display usage information.
The -V or --verbose -option can be used to obtain more information at run-time, for example -some output for every USB transfer. This option can be repeated -multiple times to increase the amount of output.
The first argument that does not begin with a hyphen specifies a test -that should be run, in the form of a Tcl script. For example an -argument of list.tcl will cause -usbhost to look for a script with that -name, adding a .tcl suffix if necessarary, and -run that script. usbhost will look in the -current directory first, then in the install tree for standard test -scripts provided by the USB slave package.
Some test scripts may want their own parameters, for example a -duration in seconds. These can be passed on the command line after -the name of the test, for example -usbhost mytest 60.
Each test is defined by a Tcl script, running inside an interpreter -provided by usbhost. In addition to the -normal Tcl functionality this interpreter provides a number of -variables and functions related to USB testing. For example there is a -variable bulk_in_endpoints that lists all the -endpoints on the target that can perform bulk IN operations, and a -related array bulk_in which contains information -such as the minimum and maximum packets sizes. There is a function -bulktest which can be used to perform bulk tests -on a particular endpoint. A simple test script aimed at specific -hardware could ignore the information variables since it would know -exactly what USB hardware is available on the target, whereas a -general-purpose script would use the information to adapt to the -hardware capabilities.
To avoid namespace pollution all USB-related Tcl variables and -functions live in the usbtest:: namespace. -Therefore accessing requires either explicitly including the -namespace any references, for example -$usbtest::bulk_in_endpoints, or by using Tcl's -namespace import facility.
A very simple test script might look like this:
usbtest::bulktest 1 out 4000 -usbtest::bulktest 2 in 4000 -if { [usbtest::start 60] } { - puts "Test successful" -} else - puts "Test failed" - foreach result $usbtest::results { - puts $result - } -} |
This would perform a test run involving 4000 bulk transfers from the -host to the target's endpoint 1, and concurrently 4000 bulk transfers -from endpoint 2. Default settings for packet sizes, contents, and -delays would be used. The actual test would not start running until -usbtest is invoked, and it is expected that the -test would complete within 60 seconds. If any failures occur then they -are reported.
Each target-side USB device driver provides information about the -actual capabilities of the hardware, for example which endpoints are -available. Strictly speaking it provides information about what is -actually supported by the device driver, which may be a subset of what -the hardware is capable of. For example, the hardware may support -isochronous transfers on a particular endpoint but if there is no -software support for this in the driver then this endpoint will not be -listed. When usbhost first contacts the -usbtarget program running on the target -platform, it obtains this information and makes it available to test -scripts via Tcl variables:
This is a simple list of the endpoints which can support bulk IN - transfers. For example if the target-side hardware supports - these transfers on endpoints 3 and 5 then the value would be - "3 5" Typical test scripts would - iterate over the list using something like: -
if { 0 != [llength $usbtest::bulk_in_endpoints] } { - puts"Bulk IN endpoints: $usbtest::bulk_in_endpoints" - foreach endpoint $usbtest:bulk_in_endpoints { - … - } - } - |
This array holds additional information about each bulk IN endpoint. - The array is indexed by two fields, the endpoint number and one of - min_size, max_size, - max_in_padding and devtab: -
This field specifies a lower bound on the size of bulk transfers, - and will typically will have a value of 1. -
Note: The typical minimum transfer size of a single byte is not strictly - speaking correct, since under some circumstances it can make sense - to have a transfer size of zero bytes. However current target-side - device drivers interpret a request to transfer zero bytes as a way - for higher-level code to determine whether or not an endpoint is - stalled, so it is not actually possible to perform zero-byte - transfers. This issue will be addressed at some future point. -
This field specifies an upper bound on the size of bulk transfers. - Some target-side drivers may be limited to transfers of say - 0x0FFFF bytes because of hardware limitations. In practice the - transfer size is likely to be limited primarily to limit memory - consumption of the test code on the target hardware, and to ensure - that tests complete reasonably quickly. At the time of writing - transfers are limited to 4K. -
On some hardware it may be necessary for the target-side device - driver to send more data than is actually intended. For example - the SA11x0 USB hardware cannot perform bulk transfers that are - an exact multiple of 64 bytes, instead it must pad such - transfers with an extra byte and the host must be ready to - accept and discard this byte. The - max_in_padding field indicates the amount of - padding that is required. The low-level code inside - usbhost will use this field - automatically, and there is no need for test scripts to adjust - packet sizes for padding. The field is provided for - informational purposes only. -
This is a string indicating whether or not the - target-side USB device driver supports access to this endpoint - via entries in the device table, in other words through - conventional calls like open and - write. Some device drivers may only - support low-level USB access because typically that is what gets - used by USB class-specific packages such as USB-ethernet. - An empty string indicates that no devtab entry is available, - otherwise it will be something like - "/dev/usbs2w". -
Typical test scripts would access this data using something like: -
foreach endpoint $usbtest:bulk_in_endpoints { - puts "Endpoint $endpoint: " - puts " minimum transfer size $usbtest::bulk_in($endpoint,min_size)" - puts " maximum transfer size $usbtest::bulk_in($endpoint,max_size)" - if { 0 == $usbtest::bulk_in($endpoint,max_in_padding) } { - puts " no IN padding required" - } else { - puts " $usbtest::bulk_in($endpoint,max_in_padding) bytes of IN padding required" - } - if { "" == $usbtest::bulk_in($endpoint,devtab) } { - puts " no devtab entry provided" - } else { - puts " corresponding devtab entry is $usbtest::bulk_in($endpoint,devtab)" - } - } - |
This is a simple list of the endpoints which can support bulk OUT - transfers. It is analogous to - bulk_in_endpoints. -
This array holds additional information about each bulk OUT - endpoint. It can be accessed in the same way as - bulk_in(), except that there is no - max_in_padding field because that field only - makes sense for IN transfers. -
This array holds information about the control endpoint. It contains - two fields, min_size and - max_size. Note that there is no variable - control_endpoints because a USB target always - supports a single control endpoint 0. Similarly - the control array does not use an endpoint number - as the first index because that would be redundant. -
These variables provide the same information as - bulk_in_endpoints and bulk_in, - but for endpoints that support isochronous IN transfers. -
These variables provide the same information as - bulk_out_endpoints and bulk_out, - but for endpoints that support isochronous OUT transfers. -
These variables provide the same information as - bulk_in_endpoints and bulk_in, - but for endpoints that support interrupt IN transfers. -
These variables provide the same information as - bulk_out_endpoints and bulk_out, - but for endpoints that support interrupt OUT transfers. -
The main function for initiating a bulk test is -usbtest::bulktest. This takes three compulsory -arguments, and can be given a number of additional arguments to -control the exact behaviour. The compulsory arguments are:
This specifies the endpoint to use. It should correspond to - one of the entries in - usbtest::bulk_in_endpoints or - usbtest::bulk_out_endpoints, depending on the - transfer direction. -
This should be either in or out. -
This specifies the number of transfers that should take place. The - testing software does not currently support the concept of performing - transfers for a given period of time because synchronising this on - both the host and a wide range of targets is difficult. However it - is relatively easy to work out the approximate time a number of bulk - transfers should take place, based on a typical bandwidth of - 1MB/second and assuming say a 1ms overhead per transfer. - Alternatively a test script could perform a small initial run to - determine what performance can actually be expected from a given - target, and then use this information to run a much longer test. -
Additional arguments can be used to control the exact transfer. For -example a txdelay+ argument can be used to -slowly increase the delay between transfers. All such arguments involve -a value which can be passed either as part of the argument itself, -for example txdelay+=5, or as a subsequent -argument, txdelay+ 5. The possible arguments fall -into a number of categories: data, I/O mechanism, transmit size, -receive size, transmit delay, and receive delay.
An obvious parameter to control is the actual data that gets sent. -This can be controlled by the argument data -which can take one of five values: none, -bytefill, intfill, -byteseq and wordseq. The default -value is none.
The transmit code will not attempt to fill the buffer in any way, - and the receive code will not check it. The actual data that gets - transferred will be whatever happened to be in the buffer before - the transfer started. -
The entire buffer will be filled with a single byte, as per - memset. -
The buffer will be treated as an array of 32-bit integers, and will - be filled with the same integer repeated the appropriate number of - times. If the buffer size is not a multiple of four bytes then - the last few bytes will be set to 0. -
The buffer will be filled with a sequence of bytes, generated by - a linear congruential generator. If the first byte in the buffer is - filled with the value x, the next byte will be - (m*x)+i. For example a sequence of slowly - incrementing bytes can be achieved by setting both the multiplier - and the increment to 1. Alternatively a pseudo-random number - sequence can be achieved using values 1103515245 and 12345, as - per the standard C library rand function. - For convenience these two constants are available as Tcl - variables usbtest::MULTIPLIER and - usbtest::INCREMENT. -
This acts like byteseq, except that the buffer is - treated as an array of 32-bit integers rather than as an array of - bytes. If the buffer is not a multiple of four bytes then the last - few bytes will be filled with zeroes. -
The above requires three additional parameters -data1, data* and -data+. data1 specifies -the value to be used for byte or word fills, or the first number when -calculating a sequence. The default value is 0. -data* and data+ specify -the multiplier and increment for a sequence, and have default values -of 1 and 0 respectively. For -example, to perform a bulk transfer of a pseudo-random sequence of -integers starting with 42 the following code could be used:
bulktest 2 IN 1000 data=wordseq data1=42 \ - data* $usbtest::MULTIPLIER data+ $usbtest::INCREMENT |
The above parameters define what data gets transferred for the first -transfer, but a test can involve multiple transfers. The data format -will be the same for all transfers, but it is possible to adjust the -current value, the multiplier, and the increment between each -transfer. This is achieved with parameters data1*, -data1+, data**, -data*+, data+*, and -data++, with default values of 1 for each -multiplier and 0 for each increment. For example, if the multiplier -for the first transfer is set to 2 using -data*, and arguments -data** 2 and data*+ -1 are also -supplied, then the multiplier for subsequent transfers will be -3, 5, 9, -….
Note: Currently it is not possible for a test script to send specific data, -for example a specific sequence of bytes captured by a protocol analyser -that caused a problem. If the transfer was from host to target then -the target would have to know the exact sequence of bytes to expect, -which means transferring data over the USB bus when that data is known -to have caused problems in the past. Similarly for target to host -transfers the target would have to know what bytes to send. A possible -future extension of the USB testing support would allow for bounce -operations, where a given message is first sent to the target and then -sent back to the host, with only the host checking that the data was -returned correctly.
On the target side USB transfers can happen using either low-level -USB calls such as usbs_start_rx_buffer, or by -higher-level calls which go through the device table. By default the -target-side code will use the low-level calls. If it is desired to -test the higher-level calls instead, for example because those are -what the application uses, then that can be achieved with an -argument mechanism=devtab.
The next set of arguments can be used to control the size of the -transmitted buffer: txsize1, -txsize>=, txsize<= -txsize*, txsize/, -and txsize+.
txsize1 determines the size of the first -transfer, and has a default value of 32 bytes. The size of the next -transfer is calculated by first multiplying by the -txsize* value, then dividing by the -txsize/ value, and finally adding the -txsize+ value. The defaults for these are -1, 1, and 0 -respectively, which means that the transfer size will remain -unchanged. If for example the transfer size should increase by -approximately 50 per cent each time then suitable values might be -txsize* 3, txsize/ 2, -and txsize+ 1.
The txsize>= and -txsize<= arguments can be used to impose -lower and upper bounds on the transfer. By default the -min_size and max_size values -appropriate for the endpoint will be used. If at any time the -current size falls outside the bounds then it will be normalized.
The receive size, in other words the number of bytes that either host -or target will expect to receive as opposed to the number of bytes -that actually get sent, can be adjusted using a similar set of -arguments: rxsize1, -rxsize>=, -rxsize<=, -rxsize*, rxsize/ and -rxsize+. The current receive size will be -adjusted between transfers just like the transmit size. However when -communicating over USB it is not a good idea to attempt to receive -less data than will actually be sent: typically neither the hardware -nor the software will be able to do anything useful with the excess, -so there will be problems. Therefore if at any time the calculated -receive size is less than the transmit size, the actual receive will -be for the exact number of bytes that will get transmitted. However -this will not affect the calculations for the next receive size.
The default values for rxsize1, -rxsize*, rxsize/ and -rxsize+ are 0, -1, 1 and 0 -respectively. This means that the calculated receive size will always -be less than the transmit size, so the receive operation will be for -the exact number of bytes transmitted. For some USB protocols this -would not accurately reflect the traffic that will happen. For example -with USB-ethernet transfer sizes will vary between 16 and 1516 bytes, -so the receiver will always expect up to 1516 bytes. This can be -achieved using rxsize1 1516, leaving the -other parameters at their default values.
For target hardware which involves non-zero -max_in_padding, on the host side the padding will -be added automatically to the receive size if necessary.
Typically during the testing there will be some minor delays between -transfers on both host and target. Some of these delays will be caused -by timeslicing, for example another process running on the host, or a -concurrent test thread running inside the target. Other delays will be -caused by the USB bus itself, for example activity from another device -on the bus. However it is desirable that test cases be allowed to -inject additional and somewhat more controlled delays into the system, -for example to make sure that the target behaves correctly even if the -target is not yet ready to receive data from the host.
The transmit delay is controlled by six parameters: -txdelay1, txdelay*, -txdelay/, txdelay+, -txdelay>= and -txdelay<=. The default values for these are -0, 1, 1, -0, 0 and -1000000000 respectively, so that by default -transmits will happen as quickly as possible. Delays are measured in -nanoseconds, so a value of 1000000 would correspond -to a delay of 0.001 seconds or one millisecond. By default delays have -an upper bound of one second. Between transfers the transmit delay is -updated in much the same was as the transfer sizes.
The receive delay is controlled by a similar set of six parameters: -rxdelay1, rxdelay*, -rxdelay/, rxdelay+, -rxdelay>= and -rxdelay<=. The default values for these are -the same as for transmit delays.
The transmit delay is used on the side which sends data over the USB -bus, so for a bulk IN transfer it is the target that sends data and -hence sleeps for the specified transmit delay, while the host receives -data sleeps for the receive delay. For an OUT transfer the positions -are reversed.
It should be noted that although the delays are measured in -nanoseconds, the actual delays will be much less precise and are -likely to be of the order of milliseconds. The exact details will -depend on the kernel clock speed.
Support for testing other types of USB traffic such as isochronous -transfers is not yet implemented.
A USB test script should prepare one or more transfers using -appropriate functions such as usbtest::bulktest. -Once all the individual tests have been prepared they can be started -by a call to usbtest::start. This takes a single -argument, a maximum duration measured in seconds. If all transfers -have not been completed in the specified time then any remaining -transfers will be aborted.
usbtest::start will return 1 -if all the tests have succeeded, or 0 if any of -them have failed. More detailed reports will be stored in the -Tcl variable usbtests::results, which will be a -list of string messages.
A number of test scripts are provided as standard. These are located -in the host subdirectory of the -common USB slave package, and will be installed as part of the process -of building the host-side software. When a script is specified on the -command line usbhost will first search for -it in the current directory, then in the install tree. Standard -test scripts include the following:
This script simply displays information about the capabilities - of the target platform, as provided by the target-side USB - device driver. It can help with tracking down problems, but its - primary purpose is to let users check that everything is working - correctly: if running usbhost list.tcl - outputs sensible information then the user knows that the - target side is running correctly and that communication between - host and target is possible. -
The target-side code can provide information about what - is happening while tests are prepared and run. This facility - should not normally be used since the extra I/O involved will - significantly affect the behaviour of the system, but in some - circumstances it may prove useful. Since an eCos application - cannot easily be given command-line arguments the target-side - verbosity level cannot be controlled using - -V or --verbose - options. Instead it can be controlled from inside - gdb by changing the integer - variable verbose. Alternatively it can - be manipulated by running the test script - verbose.tcl. This script takes a single - argument, the desired verbosity level, which should be a small - integer. For example, to disable target-side run-time logging - the command usbhost verbose 0 can - be used. -
If all transfers succeed within the specified time then both host and -target remain in synch and further tests can be run without problem. -However, if at any time a failure occurs then things get more -complicated. For example, if the current test involves a series of -bulk OUT transfers and the target detects that for one of these -transfers it received less data than was expected then the test has -failed, and the target will stop accepting data on this endpoint. -However the host-side software may not have detected anything wrong -and is now blocked trying to send the next lot of data.
The test code goes to considerable effort to recover from problems -such as these. On the host-side separate threads are used for -concurrent transfers, and on the target-side appropriate asynchronous -I/O mechanisms are used. In addition there is a control thread on the -host that checks the state of all the main host-side threads, and the -state of the target using private control messages. If it discovers -that one side has stopped sending or receiving data because of an -error and the other side is blocked as a result, it will set certain -flags and then cause one additional transfer to take place. That -additional transfer will have the effect of unblocking the other side, -which then discovers that an error has occurred by checking the -appropriate flags. In this way both host and target should end up back -in synch, and it is possible to move on to the next set of tests.
However, the above assumes that the testing has not triggered any -serious hardware conditions. If instead the target-side hardware has -been left in some strange state so that, for example, it will no -longer raise an interrupt for traffic on a particular endpoint then -recovery is not currently possible, and the testing software will just -hang.
A possible future enhancement to the testing software would allow the -host-side to raise a USB reset signal whenever a failure occurs, in -the hope that this would clear any remaining problems within the -target-side USB hardware.