OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/rtos/ecos-2.0/packages/io/usb
    from Rev 174 to Rev 27
    Reverse comparison

Rev 174 → Rev 27

/eth/slave/v2_0/doc/usbseth-protocol.html File deleted \ No newline at end of file
/eth/slave/v2_0/doc/usbseth-init.html File deleted \ No newline at end of file
/eth/slave/v2_0/doc/tcpip.png Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
eth/slave/v2_0/doc/tcpip.png Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: eth/slave/v2_0/doc/tcpip.fig =================================================================== --- eth/slave/v2_0/doc/tcpip.fig (revision 174) +++ eth/slave/v2_0/doc/tcpip.fig (nonexistent) @@ -1,33 +0,0 @@ -#FIG 3.2 -Portrait -Center -Inches -Letter -100.00 -Single --2 -1200 2 -2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 600 600 2400 600 2400 2400 600 2400 600 600 -2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 4200 600 6000 600 6000 2400 4200 2400 4200 600 -2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 - 6600 300 6600 2700 -2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 - 2400 2100 4200 2100 -2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 1 4 - 0 0 1.00 60.00 120.00 - 0 0 1.00 60.00 120.00 - 1500 1125 1500 1500 4950 1500 4950 1200 -2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 - 6000 2100 6600 2100 -2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 1 3 - 0 0 1.00 60.00 120.00 - 0 0 1.00 60.00 120.00 - 5175 1200 5175 1500 6600 1500 -4 0 0 50 0 0 12 0.0000 4 135 945 6150 2925 real network\001 -4 0 0 50 0 0 12 0.0000 4 135 735 1125 2100 USB host\001 -4 0 0 50 0 0 12 0.0000 4 180 1155 4500 2100 USB peripheral\001 -4 0 0 50 0 0 12 0.0000 4 135 675 2925 1950 USB bus\001 -4 0 0 50 0 0 12 0.0000 4 135 540 1200 1050 TCP/IP\001 -4 0 0 50 0 0 12 0.0000 4 135 540 4800 1050 TCP/IP\001 Index: eth/slave/v2_0/doc/usbseth-netdev.html =================================================================== --- eth/slave/v2_0/doc/usbseth-netdev.html (revision 174) +++ eth/slave/v2_0/doc/usbseth-netdev.html (nonexistent) @@ -1,219 +0,0 @@ - - - - - - - - - - - -Network Device for the eCos TCP/IP Stack
eCos Support for Developing USB-ethernet Peripherals
PrevNext

Network Device for the eCos TCP/IP Stack

Name

Network Device -- USB-ethernet support for the eCos TCP/IP Stack

Description

If the USB peripheral involves running the eCos TCP/IP stack and that -stack needs to use USB-ethernet as a transport layer (or as one of the -transports), then the USB-ethernet package can provide a suitable -network device driver. It is still necessary for higher-level code to -perform appropriate initialization by calling usbs_eth_init, but -after that it will be the TCP/IP stack rather than application code -that transmits or receives ethernet frames.

Not all peripherals involving the USB-ethernet package will require a -TCP/IP stack. Hence the provision of the network device is controlled -by a configuration option CYGPKG_USBS_ETHDRV. By -default this will be enabled if the TCP/IP package -CYGPKG_NET is loaded, and disabled otherwise.

There are a number of other configuration options related to the -network device. CYGFUN_USBS_ETHDRV_STATISTICS -determines whether or not the package will maintain statistics, mainly -intended for SNMP: by default this will be enabled if the SNMP support -package CYGPKG_SNMPAGENT is loaded, and disabled -otherwise. The name of the ethernet device is controlled by -CYGDATA_USBS_ETHDRV_NAME, and has a default value -of either eth0 or eth1 -depending on whether or not there is another network device driver -present in the configuration.

Usually eCos network device drivers default to using DHCP for -obtaining necessary information such as IP addresses. This is not -appropriate for USB-ethernet devices. On the host-side the -USB-ethernet network device will not exist until the USB peripheral -has been plugged in and communication has been established. Therefore -any DHCP daemon on the host would not be listening on that network -device at the point that eCos requests its IP and other information. A -related issue is that the use of DHCP would imply the presence of a -DHCP daemon on every affected host machine, as opposed to a single -daemon (plus backups) for the network as a whole. For these reasons -the USB-ethernet package precludes the use of DHCP as a way of setting -the IP address, instead requiring alternatives such as manual -configuration.


PrevHomeNext
USB-ethernet State Handling Example Host-side Device Driver
\ No newline at end of file Index: eth/slave/v2_0/doc/io-usb-slave-eth.html =================================================================== --- eth/slave/v2_0/doc/io-usb-slave-eth.html (revision 174) +++ eth/slave/v2_0/doc/io-usb-slave-eth.html (nonexistent) @@ -1,168 +0,0 @@ - - - - - - - - - - - -eCos Support for Developing USB-ethernet Peripherals

I. eCos Support for Developing USB-ethernet Peripherals

Table of Contents
Introduction — eCos support for developing USB ethernet peripherals
Initializing the USB-ethernet Package — Initializing the USB-ethernet Package
USB-ethernet Data Transfers — Exchanging ethernet packets with the USB host
USB-ethernet State Handling — Maintaining the USB-ethernet connection with the host
Network Device for the eCos TCP/IP Stack — USB-ethernet support for the eCos TCP/IP Stack
Example Host-side Device Driver — Provide host-side support for the eCos USB-ethernet package
Communication Protocol — Protocol used between the host-side device driver and the eCos -USB-ethernet package

  Next
  Introduction
\ No newline at end of file Index: eth/slave/v2_0/doc/usbseth-data.html =================================================================== --- eth/slave/v2_0/doc/usbseth-data.html (revision 174) +++ eth/slave/v2_0/doc/usbseth-data.html (nonexistent) @@ -1,374 +0,0 @@ - - - - - - - - - - - -USB-ethernet Data Transfers
eCos Support for Developing USB-ethernet Peripherals
PrevNext

USB-ethernet Data Transfers

Name

USB-ethernet Data Transfers -- Exchanging ethernet packets with the USB host

Synopsis

#include <cyg/io/usb/usbs_eth.h>

void usbs_eth_start_rx(usbs_eth* usbseth, unsigned char* buffer, void (*)(usbs_eth*, void*, int) complete_fn, void* complete_data);

void usbs_eth_start_tx(usbs_eth* usbseth, unsigned char* buffer, void (*)(usbs_eth*, void*, int) complete_fn, void* complete_data);

Description

The USB-ethernet package provides two main modes of operation. In the -first mode it provides a network device -driver for use by a TCP/IP stack running inside the USB -peripheral. All incoming ethernet packages should be passed up the -TCP/IP stack, and only the stack will generate outgoing packets. Apart -from initialization and possibly -certain control operations, -higher-level code will not interact with the USB-ethernet package -directly.

In the second mode there is no TCP/IP stack running inside the USB -peripheral. For example, a simple USB-ethernet converter has an -ethernet chip and a USB port: ethernet packets received by the -ethernet chip need to be forwarded to the USB host, and ethernet -packets sent by the USB host need to be sent out of the ethernet chip. -usbs_eth_start_rx and -usbs_eth_start_tx allow for this lower-level -access to the USB-ethernet package.

The two modes of operation are mutually exclusive. If the network -device driver mode is enabled then application code should communicate -at the TCP/IP level, and not by using the lower-level functions. -Instead, it is the network device driver that will make use of these -functions, and it assumes that it has exclusive access. The package -does not perform any locking.

The transmit and receive functions work in much the same way. The -first argument identifies the usbs_eth -structure that should be used. For the majority of applications this -will be usbs_eth0. The second argument specifies -the location of the ethernet packet; outgoing for -usbs_eth_start_tx and incoming for -usbs_eth_start_rx. This buffer should correspond -to the protocol:

  1. Outgoing packets can consist of up to 1516 bytes, consisting of a -two-byte header specific to USB-ethernet followed by a standard -ethernet frame (a header with 6-byte destination address, 6-byte -source address and a further two bytes, followed by a payload of -up to 1500 bytes). The two-byte USB-ethernet header consists simply of -the size of the ethernet frame, i.e. the size of the rest of the -packet not including the USB-ethernet header, with the least -significant byte first.

  2. For incoming packets the supplied buffer should usually be at least -1516 bytes. There may be special circumstances in which a smaller -buffer might be safe; for example, if the host-side device driver is -modified to support only smaller packets. Once the packet has been -received the buffer will contain a two-byte header specific to -USB-ethernet, followed by a normal ethernet frame. The header -gives the size of the ethernet frame, excluding the header, with the -least significant byte first.

Both usbs_eth_start_tx and -usbs_eth_start_rx are asynchronous: the transfer -is started and, some time later, a completion function will be invoked. -The third and fourth arguments to both -usbs_eth_start_tx and -usbs_eth_start_rx supply the completion function -and an argument to that function respectively. The completion function -will be invoked with three arguments: a pointer to the -usbs_eth data structure, usually -usbs_eth0; the supplied completion data ; and a -return code field. A negative value indicates that an error occurred, -for example -EPIPE if the connection between USB -host and peripheral has been broken, or -EAGAIN if -an endpoint has been halted. A positive value indicates the total size -of the transfer, which should correspond to the size in the -USB-ethernet header plus an additional two bytes for the header -itself.

If the data transfer is succesful then the completion function will -typically be invoked in DSR context rather than in thread context, -although this depends on the implementation of the underlying USB -device driver. Therefore the completion function is restricted in what -it can do; in particular, it must not make any calls that will or may -block such as locking a mutex or allocating memory. The kernel -documentation should be consulted for more details of DSR's and -interrupt handling generally. Note that if the transfer finishes -quickly then the completion function may be invoked before -usbs_eth_start_rx or -usbs_eth_start_tx returns. This is especially -likely to happen if the current thread is descheduled after starting -the data transfer but before returning from these functions.

For transmit operations, it is possible for -usbs_eth_start_tx to invoke the completion -function immediately. If there is no current connection between host -and target then the transmit will fail immediately with --EPIPE. In addition the USB-ethernet package will -check the destination MAC address and make sure that the ethernet -frame really is intended for the host: either it must be for the -address specified in the initialization call usbs_eth_init, or -it must be a broadcast packet, or the host must have enabled -promiscuous mode.


PrevHomeNext
Initializing the USB-ethernet Package USB-ethernet State Handling
\ No newline at end of file Index: eth/slave/v2_0/doc/usbseth-intro.html =================================================================== --- eth/slave/v2_0/doc/usbseth-intro.html (revision 174) +++ eth/slave/v2_0/doc/usbseth-intro.html (nonexistent) @@ -1,314 +0,0 @@ - - - - - - - - - - - -Introduction
eCos Support for Developing USB-ethernet Peripherals
PrevNext

Introduction

Name

Introduction -- eCos support for developing USB ethernet peripherals

Introduction

The eCos USB-ethernet package provides additional support for USB -peripherals that involve some sort of ethernet-style network. This can -be a traditional ethernet, or it can involve some other networking -technology that uses ethernet frames as a unit of transfer. It -provides functions to transfer ethernet frames over the USB bus, -handles certain control messages from the host, and optionally it can -provide a network device driver for use by the eCos TCP/IP stack. -The package comes with an example host-side device driver.

The USB-ethernet package is not tied to any specific hardware. It -requires the presence of USB hardware and a suitable device driver, -but not all USB peripherals involve ethernet communications. Hence the -configuration system cannot load the package automatically for -specific targets, in the way that a USB device driver or an ethernet -driver can be loaded automatically. Instead, the package has to be -added explicitly. When using the command line tools this will involve -an operation like the following:

$ ecosconfig add usbs_eth

Typically, this will automatically cause the USB device driver to -become active. Loading the USB-ethernet package automatically provides -functionality for initialization, -data transfer, and the handling of -control messages and state -changes. If the current configuration includes the eCos TCP/IP stack -then the network device driver -support will be enabled as well by default, allowing the stack to -exchange ethernet frames over the USB bus.

There is a USB standard for a class of communication devices including -ethernet. The package does not implement this standard, due to -limitations in the hardware for which the package was first developed. -Instead, the package uses its own protocol between USB -host device driver and the -peripheral.

Usage Scenarios

The USB-ethernet package can be used several different scenarios. In -a simple scenario, the peripheral serves only to connect the USB host -to a suitable network:

After initialization, and once the USB connection between host and -peripheral has been established, higher-level code needs to detect -packets that are intended for the host, and to forward these. This can -be achieved by the low-level usbs_eth_start_tx -function. Similarly, higher-level code needs to detect packets coming -from the host, using usbs_eth_start_rx, and to -forward these using the real network. As far as the host is concerned -it is connected directly to the network. In this scenario there is no -confusion about addresses: there is a single MAC address for the -host/peripheral combination, corresponding to the connection to the -real network, and it is this address which should be supplied during -initialization.

In a more complicated scenario, there is a TCP/IP stack running inside -the peripheral.

This involves the USB-ethernet package providing a service both to the -host and to the eCos TCP/IP stack. It achieves the latter by acting as -an eCos network device. Typically, the TCP/IP stack will be configured -to act as a network bridge. The USB peripheral needs to examine the -packets arriving over the real network. Some of these packets will be -intended for the host, while others will be intended for the -peripheral itself. To distinguish between these two scenarios, two -distinct MAC addresses are needed: one for the host, and one for the -peripheral. Similarly, packets sent by the host may have to be -forwarded via the real network, or they may be intended for the TCP/IP -stack inside the peripheral. Packets generated inside the peripheral's -TCP/IP stack may need to be sent via the real network or over the USB -bus. The network bridge software will have to take care of all these -possibilities. Unusually for a network bridge, one of the network -segments being bridged will only ever have one machine attached.

There are other possible usage scenarios. For example, the peripheral -might not be attached to a real network at all. Instead it could be -the USB host that acts as a network bridge, allowing a TCP/IP stack -inside the peripheral to communicate with the outside world. The -various details will depend on the exact type of peripheral being -developed.


PrevHomeNext
eCos Support for Developing USB-ethernet Peripherals Initializing the USB-ethernet Package
\ No newline at end of file Index: eth/slave/v2_0/doc/usbseth-host.html =================================================================== --- eth/slave/v2_0/doc/usbseth-host.html (revision 174) +++ eth/slave/v2_0/doc/usbseth-host.html (nonexistent) @@ -1,328 +0,0 @@ - - - - - - - - - - - -Example Host-side Device Driver
eCos Support for Developing USB-ethernet Peripherals
PrevNext

Example Host-side Device Driver

Name

Example Host-side Device Driver -- Provide host-side support for the eCos USB-ethernet package

Description

The USB-ethernet package is supplied with a single host-side device -driver. This driver has been developed against the Linux kernel -2.2.16-22, as shipped with Red Hat 7. The driver is provided as is and -should not be considered production quality: for example it only -checks for a bogus vendor id 0x4242 rather than an -official vendor id supplied by the USB Implementers Forum. Also, if the -peripheral involves multiple configurations or multiple interfaces, it -will fail to detect this. However, the driver can be used for simple -testing and as the basis of a full device driver. Details of the -protocol used between host and peripheral can be found in the Communication Protocol section.

The host-side device driver can be found in the host subdirectory of the USB-ethernet -package, specifically the file ecos_usbeth.c, and -comes with a Makefile. Both files may need -to be modified for specific applications. For example, the vendor id -table ecos_usbeth_implementations may need to be -updated for the specific USB peripheral being built. The -Makefile assumes that the Linux kernel sources -reside in /usr/src/linux, and -that the kernel has already been configured and built. Assuming this -is the case, the device driver can be built simply by invoking -make with no additional arguments. This will result -in a dynamically loadable kernel module, -ecos_usbeth.o, in the current directory.

Note: As normal for Linux kernel builds, the generated files such as -ecos_usbeth.o live in the same directory as the -source tree. This is very different from eCos where the source tree -(or component repository) is kept separate from any builds. There may -be problems if the component repository is kept read-only or if it is -put under source code control. Any such problems can be avoided by -making a copy of the host -subdirectory and building that copy.

Loading the kernel module into the current system requires root -privileges. If the generic USB support is also a loadable module and -has not been loaded already, this must happen first:

# insmod usb-uhci








    -Using /lib/modules/2.2.16-22/usb/usb-uhci.o

Depending on the host hardware, the uhci or -usb-ohci modules may be more appropriate. Loading -the generic USB module will typically result in a number of messages -to the logfile /var/log/messages, giving details -of the specific host-side hardware that has been detected plus any -hubs. The next step is to load the USB-ethernet module:

# insmod ecos_usbeth.o

This should result in a number of additional diagnostics in the -logfile:

Apr 1 18:01:08 grumpy kernel: eCos USB-ethernet device driver








    -Apr 1 18:01:08 grumpy kernel: usb.c: registered new driver ecos_usbeth

If a suitable USB peripheral is now connected the host will detect -this, assign an address in the local USB network, obtain enumeration -data, and find a suitable device driver. Assuming the peripheral and -device driver agree on the supported vendor ids, the -ecos_usbeth.o module will be selected and this -will be reported in the system log:

Apr 1 18:04:12 grumpy kernel: usb.c: USB new device connect, assigned device number 3








    -Apr 1 18:04:12 grumpy kernel: eCos-based USB ethernet peripheral active at eth1

What can happen next depends very much on the software that is running -on top of the USB-ethernet package inside the peripheral. For example, -if there is a TCP/IP stack then it should be possible to bring up a -network connection between host and peripheral using -ifconfig.


PrevHomeNext
Network Device for the eCos TCP/IP Stack Communication Protocol
\ No newline at end of file Index: eth/slave/v2_0/doc/simple.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: eth/slave/v2_0/doc/simple.png =================================================================== --- eth/slave/v2_0/doc/simple.png (revision 174) +++ eth/slave/v2_0/doc/simple.png (nonexistent)
eth/slave/v2_0/doc/simple.png Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: eth/slave/v2_0/doc/makefile =================================================================== --- eth/slave/v2_0/doc/makefile (revision 174) +++ eth/slave/v2_0/doc/makefile (nonexistent) @@ -1,55 +0,0 @@ -#============================================================================= -# -# makefile -# -# For building the USB-ethernet package documentation -# -#============================================================================= -#####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#### -# -# Author(s): bartv -# Date: 2001-01-11 -#####DESCRIPTIONEND#### -#============================================================================= - -TOPLEVEL := ../../../../../.. -MAIN_SGML := usbseth.sgml -MAIN_HTML := io-usb-slave-eth.html -MAIN_PDF := io-usb-slave-eth.pdf -OTHER_SGML := -PICTURES := simple tcpip - -include $(TOPLEVEL)/pkgconf/rules.doc Index: eth/slave/v2_0/doc/simple.fig =================================================================== --- eth/slave/v2_0/doc/simple.fig (revision 174) +++ eth/slave/v2_0/doc/simple.fig (nonexistent) @@ -1,23 +0,0 @@ -#FIG 3.2 -Portrait -Center -Inches -Letter -100.00 -Single --2 -1200 2 -2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 600 600 2400 600 2400 2400 600 2400 600 600 -2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 - 2400 1500 4200 1500 -2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 4200 600 6000 600 6000 2400 4200 2400 4200 600 -2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 - 6000 1500 6600 1500 -2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 - 6600 300 6600 2700 -4 0 0 50 0 0 12 0.0000 4 135 675 3000 1425 USB bus\001 -4 0 0 50 0 0 12 0.0000 4 135 735 1200 1425 USB host\001 -4 0 0 50 0 0 12 0.0000 4 180 1155 4500 1425 USB peripheral\001 -4 0 0 50 0 0 12 0.0000 4 135 945 6150 2925 real network\001 Index: eth/slave/v2_0/doc/usbseth-control.html =================================================================== --- eth/slave/v2_0/doc/usbseth-control.html (revision 174) +++ eth/slave/v2_0/doc/usbseth-control.html (nonexistent) @@ -1,309 +0,0 @@ - - - - - - - - - - - -USB-ethernet State Handling
eCos Support for Developing USB-ethernet Peripherals
PrevNext

USB-ethernet State Handling

Name

USB-ethernet State Handling -- Maintaining the USB-ethernet connection with the host

Synopsis

#include <cyg/io/usb/usbs_eth.h>

usbs_control_return usbs_eth_class_control_handler(usbs_control_endpoint* ep0, void* callback_data);

void usbs_eth_state_change_handler(usbs_control_endpoint* ep0, void* callback_data, usbs_state_change change, int old_state);

void usbs_eth_disable(usbs_eth* usbseth>);

void usbs_eth_enable(usbs_eth* usbseth>);

Description

When the USB-ethernet package is initialized by a call to usbs_eth_init it -installs usbs_eth_state_change_handler to handle -USB state changes. This allows the package to detect when the -connection between the host and the peripheral is established or -broken, resulting in internal calls to -usbs_eth_enable and -usbs_eth_disable respectively. This is -appropriate if no other code needs to access the USB device. However, -if there is other code, either other USB-related packages or the -application itself, that needs to perform I/O over the USB bus, then -typically the USB-ethernet package should not have exclusive access to -state change events. Instead, the assumption is that higher-level -code, typically provided by the application, will install an -alternative state change handler in the control endpoint data -structure after the call to usbs_eth_init. This -alternative handler will either chain into -usbs_eth_state_change_handler when appropriate, -or else it will invoke usbs_eth_enable and -usbs_eth_disable directly. For further details of -state change handlers and control endpoints generally, see the -documentation for the common USB-slave package.

Similarly, usbs_eth_init will install -usbs_eth_class_control_handler in the control -endpoint data structure as the appropriate handler for class-specific -USB control messages. This code will handle the ethernet-specific -control messages , for example -requests by the host to enable or disable promiscuous mode or to -obtain the MAC address. If the USB device is not shared with any other -code then this is both necessary and sufficient. However, if other code -is involved and if that code also needs to process certain control -messages, higher-level code should install its own handler and chain -to the USB-ethernet one when appropriate. It should be noted that the -request code is encoded in just a single byte, so there is a real -possibility that exactly the same number will be used by different -protocols for different requests. Any such problems will have to be -identified and resolved by application developers, and may involve -modifying the source code for the USB-ethernet package.

As an alternative to chaining the state change handler, higher-level -code can instead call usbs_eth_disable and -usbs_eth_enable directly. These functions may -also be called if the USB-ethernet package should become inactive for -reasons not related directly to events on the USB bus. The main effect -of usbs_eth_enable is to restart receive -operations and to allow transmits. The main effect of -usbs_eth_disable is to block further transmits: -any current receive operations need to be aborted at the USB level, -for example by halting the appropriate endpoint.


PrevHomeNext
USB-ethernet Data Transfers Network Device for the eCos TCP/IP Stack
\ No newline at end of file Index: eth/slave/v2_0/doc/usbseth.sgml =================================================================== --- eth/slave/v2_0/doc/usbseth.sgml (revision 174) +++ eth/slave/v2_0/doc/usbseth.sgml (nonexistent) @@ -1,810 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eCos Support for Developing USB-ethernet Peripherals - - - - - -Introduction - - -Introduction -eCos support for developing USB ethernet peripherals - - -Introduction - -The eCos USB-ethernet package provides additional support for USB -peripherals that involve some sort of ethernet-style network. This can -be a traditional ethernet, or it can involve some other networking -technology that uses ethernet frames as a unit of transfer. It -provides functions to transfer ethernet frames over the USB bus, -handles certain control messages from the host, and optionally it can -provide a network device driver for use by the eCos TCP/IP stack. -The package comes with an example host-side device driver. - - -The USB-ethernet package is not tied to any specific hardware. It -requires the presence of USB hardware and a suitable device driver, -but not all USB peripherals involve ethernet communications. Hence the -configuration system cannot load the package automatically for -specific targets, in the way that a USB device driver or an ethernet -driver can be loaded automatically. Instead, the package has to be -added explicitly. When using the command line tools this will involve -an operation like the following: - - -$ ecosconfig add usbs_eth - - -Typically, this will automatically cause the USB device driver to -become active. Loading the USB-ethernet package automatically provides -functionality for initialization, -data transfer, and the handling of -control messages and state -changes. If the current configuration includes the eCos TCP/IP stack -then the network device driver -support will be enabled as well by default, allowing the stack to -exchange ethernet frames over the USB bus. - - -There is a USB standard for a class of communication devices including -ethernet. The package does not implement this standard, due to -limitations in the hardware for which the package was first developed. -Instead, the package uses its own protocol between USB -host device driver and the -peripheral. - - - -Usage Scenarios - -The USB-ethernet package can be used several different scenarios. In -a simple scenario, the peripheral serves only to connect the USB host -to a suitable network: - - - - - - - - - -After initialization, and once the USB connection between host and -peripheral has been established, higher-level code needs to detect -packets that are intended for the host, and to forward these. This can -be achieved by the low-level usbs_eth_start_tx -function. Similarly, higher-level code needs to detect packets coming -from the host, using usbs_eth_start_rx, and to -forward these using the real network. As far as the host is concerned -it is connected directly to the network. In this scenario there is no -confusion about addresses: there is a single MAC address for the -host/peripheral combination, corresponding to the connection to the -real network, and it is this address which should be supplied during -initialization. - - -In a more complicated scenario, there is a TCP/IP stack running inside -the peripheral. - - - - - - - - - -This involves the USB-ethernet package providing a service both to the -host and to the eCos TCP/IP stack. It achieves the latter by acting as -an eCos network device. Typically, the TCP/IP stack will be configured -to act as a network bridge. The USB peripheral needs to examine the -packets arriving over the real network. Some of these packets will be -intended for the host, while others will be intended for the -peripheral itself. To distinguish between these two scenarios, two -distinct MAC addresses are needed: one for the host, and one for the -peripheral. Similarly, packets sent by the host may have to be -forwarded via the real network, or they may be intended for the TCP/IP -stack inside the peripheral. Packets generated inside the peripheral's -TCP/IP stack may need to be sent via the real network or over the USB -bus. The network bridge software will have to take care of all these -possibilities. Unusually for a network bridge, one of the network -segments being bridged will only ever have one machine attached. - - -There are other possible usage scenarios. For example, the peripheral -might not be attached to a real network at all. Instead it could be -the USB host that acts as a network bridge, allowing a TCP/IP stack -inside the peripheral to communicate with the outside world. The -various details will depend on the exact type of peripheral being -developed. - - - - - - - - - -Initializing the USB-ethernet Package - - -usbs_eth_init -Initializing the USB-ethernet Package - - - - - -#include <cyg/io/usb/usbs_eth.h> - - -void usbs_eth_init -usbs_eth* usbeth -usbs_control_endpoint* ep0 -usbs_rx_endpoint* ep1 -usbs_tx_endpoint* ep2 -unsigned char* mac_address - - - - -Description - -The USB-ethernet package is not tied to any specific hardware. It -requires certain functionality: there must be USB-slave hardware -supported by a device driver; there must also be two endpoints for -bulk transfers between host and peripheral, one for each direction; -there must also be a control endpoint, although of course that is -implicit with any USB hardware. - - -However, USB-slave hardware may well provide more endpoints than the -minimum required for ethernet support. Some of those endpoints might -be used by other packages, while other endpoints might be used -directly by the application, or might not be needed for the peripheral -being built. There is also the possibility of a USB peripheral that -supports multiple configurations, with the ethernet support active in -only some of those configurations. The USB-ethernet package has no -knowledge about any of this, so it relies on higher-level code to tell -it which endpoints should be used and other information. This is the -purpose of the usbs_eth_init function. - - -The first argument identifies the specific -usbs_eth data structure that is affected. It -is expected that the vast majority of affected applications will only -provide a single USB-ethernet device to a single host, and the package -automatically provides a suitable data structure -usbs_eth0 to support this. If multiple -usbs_eth structures are needed for some -reason then these need to be instantiated by other code, and each one -needs to be initialised by a call to -usbs_eth_init(). - - -The next three arguments identify the endpoints that should be used -for USB communications: a control endpoint, a receive endpoint for -ethernet packets coming from the host to the peripheral, and a -transmit endpoint for ethernet packets going in the other direction. -Obviously all three endpoints should be provided by the same USB -hardware. The USB-ethernet package assumes that it has sole access to -the receive and transmit endpoints, subject to the use of -usbs_eth_disable and -usbs_eth_enable control functions. The package -also assumes that no other code is interested in USB state changes or -class control messages: it installs handlers -usbs_eth_state_change_handler -and -usbs_eth_class_control_handler -in the control endpoint. If any other code does need to handle USB -state changes or class control messages then replacement handlers -should be installed after the call to -usbs_eth_init, and those replacements should -invoke the USB-ethernet ones when appropriate. - - -The final argument to usbs_eth_init specifies -the MAC address (or Ethernet Station Address) that should be provided -to the host-side device driver. Since the USB-ethernet package does not -interact directly with a real ethernet device it cannot obtain the MAC -address from any hardware. Instead, it must be supplied by higher-level -code. The details depend on the scenario in which the -USB-ethernet package is being used. - - -The call to usbs_eth_init should normally happen -after the enumeration data has been provided but before the underlying -USB device driver has been started. If the USB device were to be -started first then a connection between host and peripheral could be -established immediately, and the host-side device driver would attempt -to contact the USB-ethernet package for information such as the MAC -address. - - -int -main(int argc, char** argv) -{ - unsigned char host_MAC[6] = { 0x40, 0x5d, 0x90, 0xa9, 0xbc, 0x02 }; - - usbs_sa11x0_ep0.enumeration_data = &usb_enum_data; - … - usbs_eth_init(&usbs_eth0, &usbs_sa11x0_ep0, &usbs_sa11x0_ep1, &usbs_sa11x0_ep2, host_MAC); - … - usbs_start(&usbs_sa11x0_ep0); - … -} - - - - - - - - - - -USB-ethernet Data Transfers - - -USB-ethernet Data Transfers -Exchanging ethernet packets with the USB host - - - - - -#include <cyg/io/usb/usbs_eth.h> - - - -void usbs_eth_start_rx -usbs_eth* usbseth -unsigned char* buffer -void (*)(usbs_eth*, void*, int) complete_fn -void* complete_data - - - -void usbs_eth_start_tx -usbs_eth* usbseth -unsigned char* buffer -void (*)(usbs_eth*, void*, int) complete_fn -void* complete_data - - - - - -Description - -The USB-ethernet package provides two main modes of operation. In the -first mode it provides a network device -driver for use by a TCP/IP stack running inside the USB -peripheral. All incoming ethernet packages should be passed up the -TCP/IP stack, and only the stack will generate outgoing packets. Apart -from initialization and possibly -certain control operations, -higher-level code will not interact with the USB-ethernet package -directly. - - -In the second mode there is no TCP/IP stack running inside the USB -peripheral. For example, a simple USB-ethernet converter has an -ethernet chip and a USB port: ethernet packets received by the -ethernet chip need to be forwarded to the USB host, and ethernet -packets sent by the USB host need to be sent out of the ethernet chip. -usbs_eth_start_rx and -usbs_eth_start_tx allow for this lower-level -access to the USB-ethernet package. - - -The two modes of operation are mutually exclusive. If the network -device driver mode is enabled then application code should communicate -at the TCP/IP level, and not by using the lower-level functions. -Instead, it is the network device driver that will make use of these -functions, and it assumes that it has exclusive access. The package -does not perform any locking. - - -The transmit and receive functions work in much the same way. The -first argument identifies the usbs_eth -structure that should be used. For the majority of applications this -will be usbs_eth0. The second argument specifies -the location of the ethernet packet; outgoing for -usbs_eth_start_tx and incoming for -usbs_eth_start_rx. This buffer should correspond -to the protocol: - - - - -Outgoing packets can consist of up to 1516 bytes, consisting of a -two-byte header specific to USB-ethernet followed by a standard -ethernet frame (a header with 6-byte destination address, 6-byte -source address and a further two bytes, followed by a payload of -up to 1500 bytes). The two-byte USB-ethernet header consists simply of -the size of the ethernet frame, i.e. the size of the rest of the -packet not including the USB-ethernet header, with the least -significant byte first. - - - - -For incoming packets the supplied buffer should usually be at least -1516 bytes. There may be special circumstances in which a smaller -buffer might be safe; for example, if the host-side device driver is -modified to support only smaller packets. Once the packet has been -received the buffer will contain a two-byte header specific to -USB-ethernet, followed by a normal ethernet frame. The header -gives the size of the ethernet frame, excluding the header, with the -least significant byte first. - - - - -Both usbs_eth_start_tx and -usbs_eth_start_rx are asynchronous: the transfer -is started and, some time later, a completion function will be invoked. -The third and fourth arguments to both -usbs_eth_start_tx and -usbs_eth_start_rx supply the completion function -and an argument to that function respectively. The completion function -will be invoked with three arguments: a pointer to the -usbs_eth data structure, usually -usbs_eth0; the supplied completion data ; and a -return code field. A negative value indicates that an error occurred, -for example -EPIPE if the connection between USB -host and peripheral has been broken, or -EAGAIN if -an endpoint has been halted. A positive value indicates the total size -of the transfer, which should correspond to the size in the -USB-ethernet header plus an additional two bytes for the header -itself. - - -If the data transfer is succesful then the completion function will -typically be invoked in DSR context rather than in thread context, -although this depends on the implementation of the underlying USB -device driver. Therefore the completion function is restricted in what -it can do; in particular, it must not make any calls that will or may -block such as locking a mutex or allocating memory. The kernel -documentation should be consulted for more details of DSR's and -interrupt handling generally. Note that if the transfer finishes -quickly then the completion function may be invoked before -usbs_eth_start_rx or -usbs_eth_start_tx returns. This is especially -likely to happen if the current thread is descheduled after starting -the data transfer but before returning from these functions. - - -For transmit operations, it is possible for -usbs_eth_start_tx to invoke the completion -function immediately. If there is no current connection between host -and target then the transmit will fail immediately with --EPIPE. In addition the USB-ethernet package will -check the destination MAC address and make sure that the ethernet -frame really is intended for the host: either it must be for the -address specified in the initialization call usbs_eth_init, or -it must be a broadcast packet, or the host must have enabled -promiscuous mode. - - - - - - - - - - -USB-ethernet State Handling - - -USB-ethernet State Handling -Maintaining the USB-ethernet connection with the host - - - - - -#include <cyg/io/usb/usbs_eth.h> - - - -usbs_control_return usbs_eth_class_control_handler -usbs_control_endpoint* ep0 -void* callback_data - - - -void usbs_eth_state_change_handler -usbs_control_endpoint* ep0 -void* callback_data -usbs_state_change change -int old_state - - - -void usbs_eth_disable -usbs_eth* usbseth> - - -void usbs_eth_enable -usbs_eth* usbseth> - - - - - -Description - -When the USB-ethernet package is initialized by a call to usbs_eth_init it -installs usbs_eth_state_change_handler to handle -USB state changes. This allows the package to detect when the -connection between the host and the peripheral is established or -broken, resulting in internal calls to -usbs_eth_enable and -usbs_eth_disable respectively. This is -appropriate if no other code needs to access the USB device. However, -if there is other code, either other USB-related packages or the -application itself, that needs to perform I/O over the USB bus, then -typically the USB-ethernet package should not have exclusive access to -state change events. Instead, the assumption is that higher-level -code, typically provided by the application, will install an -alternative state change handler in the control endpoint data -structure after the call to usbs_eth_init. This -alternative handler will either chain into -usbs_eth_state_change_handler when appropriate, -or else it will invoke usbs_eth_enable and -usbs_eth_disable directly. For further details of -state change handlers and control endpoints generally, see the -documentation for the common USB-slave package. - - -Similarly, usbs_eth_init will install -usbs_eth_class_control_handler in the control -endpoint data structure as the appropriate handler for class-specific -USB control messages. This code will handle the ethernet-specific -control messages , for example -requests by the host to enable or disable promiscuous mode or to -obtain the MAC address. If the USB device is not shared with any other -code then this is both necessary and sufficient. However, if other code -is involved and if that code also needs to process certain control -messages, higher-level code should install its own handler and chain -to the USB-ethernet one when appropriate. It should be noted that the -request code is encoded in just a single byte, so there is a real -possibility that exactly the same number will be used by different -protocols for different requests. Any such problems will have to be -identified and resolved by application developers, and may involve -modifying the source code for the USB-ethernet package. - - -As an alternative to chaining the state change handler, higher-level -code can instead call usbs_eth_disable and -usbs_eth_enable directly. These functions may -also be called if the USB-ethernet package should become inactive for -reasons not related directly to events on the USB bus. The main effect -of usbs_eth_enable is to restart receive -operations and to allow transmits. The main effect of -usbs_eth_disable is to block further transmits: -any current receive operations need to be aborted at the USB level, -for example by halting the appropriate endpoint. - - - - - - - - - - -Network Device for the eCos TCP/IP Stack - - -Network Device -USB-ethernet support for the eCos TCP/IP Stack - - -Description - -If the USB peripheral involves running the eCos TCP/IP stack and that -stack needs to use USB-ethernet as a transport layer (or as one of the -transports), then the USB-ethernet package can provide a suitable -network device driver. It is still necessary for higher-level code to -perform appropriate initialization by calling usbs_eth_init, but -after that it will be the TCP/IP stack rather than application code -that transmits or receives ethernet frames. - - -Not all peripherals involving the USB-ethernet package will require a -TCP/IP stack. Hence the provision of the network device is controlled -by a configuration option CYGPKG_USBS_ETHDRV. By -default this will be enabled if the TCP/IP package -CYGPKG_NET is loaded, and disabled otherwise. - - -There are a number of other configuration options related to the -network device. CYGFUN_USBS_ETHDRV_STATISTICS -determines whether or not the package will maintain statistics, mainly -intended for SNMP: by default this will be enabled if the SNMP support -package CYGPKG_SNMPAGENT is loaded, and disabled -otherwise. The name of the ethernet device is controlled by -CYGDATA_USBS_ETHDRV_NAME, and has a default value -of either eth0 or eth1 -depending on whether or not there is another network device driver -present in the configuration. - - -Usually eCos network device drivers default to using DHCP for -obtaining necessary information such as IP addresses. This is not -appropriate for USB-ethernet devices. On the host-side the -USB-ethernet network device will not exist until the USB peripheral -has been plugged in and communication has been established. Therefore -any DHCP daemon on the host would not be listening on that network -device at the point that eCos requests its IP and other information. A -related issue is that the use of DHCP would imply the presence of a -DHCP daemon on every affected host machine, as opposed to a single -daemon (plus backups) for the network as a whole. For these reasons -the USB-ethernet package precludes the use of DHCP as a way of setting -the IP address, instead requiring alternatives such as manual -configuration. - - - - - - - - - - -Example Host-side Device Driver - - -Example Host-side Device Driver -Provide host-side support for the eCos USB-ethernet package - - -Description - -The USB-ethernet package is supplied with a single host-side device -driver. This driver has been developed against the Linux kernel -2.2.16-22, as shipped with Red Hat 7. The driver is provided as is and -should not be considered production quality: for example it only -checks for a bogus vendor id 0x4242 rather than an -official vendor id supplied by the USB Implementers Forum. Also, if the -peripheral involves multiple configurations or multiple interfaces, it -will fail to detect this. However, the driver can be used for simple -testing and as the basis of a full device driver. Details of the -protocol used between host and peripheral can be found in the Communication Protocol section. - - -The host-side device driver can be found in the host subdirectory of the USB-ethernet -package, specifically the file ecos_usbeth.c, and -comes with a Makefile. Both files may need -to be modified for specific applications. For example, the vendor id -table ecos_usbeth_implementations may need to be -updated for the specific USB peripheral being built. The -Makefile assumes that the Linux kernel sources -reside in /usr/src/linux, and -that the kernel has already been configured and built. Assuming this -is the case, the device driver can be built simply by invoking -make with no additional arguments. This will result -in a dynamically loadable kernel module, -ecos_usbeth.o, in the current directory. - - - -As normal for Linux kernel builds, the generated files such as -ecos_usbeth.o live in the same directory as the -source tree. This is very different from eCos where the source tree -(or component repository) is kept separate from any builds. There may -be problems if the component repository is kept read-only or if it is -put under source code control. Any such problems can be avoided by -making a copy of the host -subdirectory and building that copy. - - - -Loading the kernel module into the current system requires root -privileges. If the generic USB support is also a loadable module and -has not been loaded already, this must happen first: - - -# insmod usb-uhci -Using /lib/modules/2.2.16-22/usb/usb-uhci.o - - -Depending on the host hardware, the uhci or -usb-ohci modules may be more appropriate. Loading -the generic USB module will typically result in a number of messages -to the logfile /var/log/messages, giving details -of the specific host-side hardware that has been detected plus any -hubs. The next step is to load the USB-ethernet module: - - -# insmod ecos_usbeth.o - - -This should result in a number of additional diagnostics in the -logfile: - - -Apr 1 18:01:08 grumpy kernel: eCos USB-ethernet device driver -Apr 1 18:01:08 grumpy kernel: usb.c: registered new driver ecos_usbeth - - -If a suitable USB peripheral is now connected the host will detect -this, assign an address in the local USB network, obtain enumeration -data, and find a suitable device driver. Assuming the peripheral and -device driver agree on the supported vendor ids, the -ecos_usbeth.o module will be selected and this -will be reported in the system log: - - -Apr 1 18:04:12 grumpy kernel: usb.c: USB new device connect, assigned device number 3 -Apr 1 18:04:12 grumpy kernel: eCos-based USB ethernet peripheral active at eth1 - - -What can happen next depends very much on the software that is running -on top of the USB-ethernet package inside the peripheral. For example, -if there is a TCP/IP stack then it should be possible to bring up a -network connection between host and peripheral using -ifconfig. - - - - - - - - - - -Communication Protocol - - -Communication Protocol -Protocol used between the host-side device driver and the eCos -USB-ethernet package - - -Description - -There is a USB standard for the protocol to be used between the host -and a class of communication devices, including ethernet. However, the -eCos USB-ethernet package does not implement this protocol: the target -hardware for which the package was first developed had certain -limitations, and could not implement the standard. Instead, the package -implements a simple new protocol. - - -A USB-ethernet peripheral involves bulk transfers on two endpoints: -one endpoint will be used for packets from host to peripheral and the -other will be used for the opposite direction. Transfers in both -directions are variable length, with a lower limit of 16 bytes and an -upper limit of 1516 bytes. The first two bytes of each transfer -constitute a header specific to USB-ethernet. The next 14 bytes form -the normal header for an ethernet frame: destination MAC address, -source MAC address, and a protocol field. The remaining data, up to -1500 bytes, are the payload. The first two bytes give the size of the -ethernet frame, least significant byte first, with a value between 14 -and 1514. - - -For example an ARP request from host to peripheral involves an -ethernet frame of 42 bytes (0x002A), with the usual 14-byte header and -a 28-byte payload. The destination is the broadcast address -0xFFFFFFFFFFFF. The source depends on the MAC address specified for -the host in the call to usbs_eth_init, e.g. -0x405D90A9BC02. The remaining data is as specified by the appropriate -IETF RFC's. The actual bulk -USB transfer involves the following sequence of 44 bytes: - - -2a 00 ff ff ff ff ff ff 40 5d 90 a9 bc 02 08 06 -00 01 08 00 06 04 00 01 40 5d 90 a9 bc 02 0a 00 -00 01 00 00 00 00 00 00 0a 00 00 02 - - -In addition there are two control messages. These will be sent by the -host to endpoint 0, the control endpoint, and by default they will -be handled by -usbs_eth_class_control_handler. If class-specific -control messages are intercepted by other code then it is the -responsibility of that code to invoke the USB-ethernet handler when -appropriate. - - -The first control message can be used by the host to obtain a MAC -address: - - -#define ECOS_USBETH_CONTROL_GET_MAC_ADDRESS 0x01 - - -The control message's type field should specify IN as the direction. -The request field should be 0x01. The length fields -should specify a size of 6 bytes. The remaining fields of the control -message will be ignored by the USB-ethernet package. The response -consists of the 6-byte MAC address supplied by the initialization call -usbs_eth_init. - - -The second control message can be used by the host to enable or -disable promiscuous mode. - - -#define ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE 0x02 - - -This control message involves no further data so the length field -should be set to 0. The value field should be non-zero to enable -promiscuous mode, zero to disable it. The request field should be -0x02. The remaining fields in the control message -will be ignored. It is the responsibility of the host-side device -driver to keep track of whether or not promiscuous mode is currently -enabled. It will be disabled when the peripheral changes to -Configured state, typically at the point where the host-side device -driver has been activated. - - - - - - - - - Index: eth/slave/v2_0/ChangeLog =================================================================== --- eth/slave/v2_0/ChangeLog (revision 174) +++ eth/slave/v2_0/ChangeLog (nonexistent) @@ -1,150 +0,0 @@ -2003-03-23 Iztok Zupet - - * doc/usbseth.sgml: Remove .eps and .gif and introduce .png for - for PDF output. - * doc/simple.gif, doc/tcpip.gif: Delete. - * doc/simple.png, doc/tcpip.png: New files to replace GIFs. - -2003-02-25 Jonathan Larmour - - * doc/usbseth.sgml: Declare as not to get - correct TOC numbering. - -2003-02-24 Jonathan Larmour - - * cdl/usbs_eth.cdl: Fix doc link. - - * doc/usbseth.sgml: Comment out DOCTYPE for now to allow building - with standard doc build. - -2002-07-26 David Smith - - * host/ecos_usbeth.c (ecos_usbeth_probe): - Two changes to the code that checks to see if this is the correct - driver for the USB peripheral that was just loaded. Fixed a bug - that was comparing the product id of the peripheral to the vendor - id. Supports multiple implementations (vendor id/product id sets) - so that the same driver could be used for several devices. - -2001-07-10 Bart Veer - - * doc/usbseth.sgml, doc/*.html: - Document the below changes. - - * cdl/usbs_eth.cdl: - The USB-ethernet device now registers itself as either eth0 or - eth1 by default, depending on what else is present in the system. - Also bootp/dhcp support is prohibited for this network device on - the ground that it is rather unlikely that a host will provide - a dhcp service for a network device that does not exist until the - host-target connection has been fully established. - - -2001-07-02 Bart Veer - - * host/ecos_usbeth.c (ecos_usbeth_probe): - Determine the endpoints to use for transmits and receives - from the descriptors supplied by the device. - -2001-06-28 Bart Veer - - * include/usbs_eth.h, src/usbsethdrv.c, src/usbseth.c: - Align receive boundaries to cacheline boundaries, and - always transfer a multiple of the cacheline size. This - avoids problems with some USB device drivers. - -2001-05-21 Bart Veer - - * host/ecos_usbeth.c (ecos_usbeth_start_tx): - Cope with targets that have problems receiving zero-byte - packets. - -2001-02-02 Bart Veer - - * cdl/usbs_eth.cdl: - Add doc property to point at the HTML - - * doc/usbseth.sgml, doc/*.html: - Incorporate changes from docs department, regenerate HTML - -2001-01-26 Bart Veer - - * src/usbsethdrv.c (usbs_ethdrv_ioctl): - Change chipset specification to null, since there is no real - hardware involved, plus SNMP cleanup. - -2001-01-22 Bart Veer - - * doc/usbseth.sgml, doc/makefile, doc/simple.fig, doc/tcpip.fig: - Added documentation. - -2000-12-15 Bart Veer - - * src/usbsethdrv.c: - Enable poll functions. - -2000-11-29 Bart Veer - - * host/ecos_usbeth.c: - Remove debugging and fix the MTU - -2000-11-28 Bart Veer - - * cdl/usbs_eth.cdl - * include/usbs_eth.h - * src/usbseth.c - * src/usbsethdrv - Clean-up, adding missing functionality such as SNMP support, - update to current USB API. - -2000-11-24 Bart Veer - - * host/ecos_usbeth.c: - Ignore runt packets, cope with the confusion between - CRC errors and timeouts. - - * include/usbs_eth.h, src/usbseth.c - Clean up alignments. - -2000-11-22 Bart Veer - - * include/usbs_eth.h: Fix nested #include protection - -2000-11-21 Bart Veer - - * First check-in of eCos USB support. - -//=========================================================================== -//####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#### -//=========================================================================== Index: eth/slave/v2_0/src/usbsethdrv.c =================================================================== --- eth/slave/v2_0/src/usbsethdrv.c (revision 174) +++ eth/slave/v2_0/src/usbsethdrv.c (nonexistent) @@ -1,616 +0,0 @@ -//========================================================================== -// -// usbethdrv.c -// -// Network device driver for USB-ethernet devices. -// -//========================================================================== -//####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#### -// -// Author(s): bartv -// Contributors: bartv -// Date: 2000-10-04 -// -//####DESCRIPTIONEND#### -//========================================================================== - -#include -#include -#include -#include - -#define __ECOS 1 -#include -#include -#include - -#include -#include - -// ---------------------------------------------------------------------------- -// The network driver data structure. -ETH_DRV_SC(usbs_eth_sc0, - (void*) &usbs_eth0, - CYGDAT_USBS_ETHDRV_NAME, - usbs_ethdrv_start, - usbs_ethdrv_stop, - usbs_ethdrv_ioctl, - usbs_ethdrv_can_send, - usbs_ethdrv_send, - usbs_ethdrv_recv, - usbs_ethdrv_deliver, - usbs_ethdrv_poll, - usbs_ethdrv_intvector); - -NETDEVTAB_ENTRY(usbs_eth_netdev0, - "usbs_eth0", - usbs_ethdrv_init, - &usbs_eth_sc0); - -// ---------------------------------------------------------------------------- -// Statics gathering. The following macro can be used to increment a -// statistic without having to use a #ifdef for the statistics -// configuration option everywhere. -#ifdef CYGFUN_USBS_ETHDRV_STATISTICS -# define INCR_STAT(a) \ - CYG_MACRO_START \ - (a) += 1; \ - CYG_MACRO_END -#else -# define INCR_STAT(a) CYG_EMPTY_STATEMENT -#endif - -// Various constants related to SNMP statistics. It is not clear -// what these are all for. -#ifdef CYGFUN_USBS_ETHDRV_STATISTICS -# define CYGDAT_USBS_ETHDRV_DESCRIPTION "eCos USB ethernet device" -#endif -// ---------------------------------------------------------------------------- -// Utility functions. -// -// The TCP/IP stack works in terms of scatter/gather buffers. USB tends to -// involve DMA operations so it is more convenient to work in terms of -// 1514 byte flat buffers. Actually, the first two bytes of the buffer -// are used to hold the ethernet frame size to work around restrictions -// with certain hardware implementations of USB that may be unable to -// transfer certain packet sizes. - -static bool -scatter(unsigned char* buf, struct eth_drv_sg* sg, int sg_len) -{ - unsigned int size; - - size = buf[0] | (buf[1] << 8); - buf++; buf++; - - CYG_ASSERT((size >= CYGNUM_USBS_ETH_MIN_FRAME_SIZE) && (size <= CYGNUM_USBS_ETH_MAX_FRAME_SIZE),\ - "ethernet frame size limits must be observed"); - - while ((size > 0) && (sg_len > 0)) { - if (size > sg->len) { - memcpy((void*) sg->buf, buf, sg->len); - buf += sg->len; - size -= sg->len; - sg++; - sg_len--; - } else { - memcpy((void*) sg->buf, buf, size); - size = 0; - } - } - - return 0 == size; -} - -static bool -gather(unsigned char* buf, unsigned int size, struct eth_drv_sg* sg, int sg_len) -{ - unsigned int left = size; - unsigned char* base = buf; - - buf++; buf++; - while ((left > 0) && (sg_len > 0)) { - if (left > sg->len) { - memcpy(buf, (void*) sg->buf, sg->len); - buf += sg->len; - left -= sg->len; - sg++; - sg_len--; - } else { - memcpy(buf, (void*) sg->buf, left); - left = 0; - } - } - size = size - left; - base[0] = size & 0x00FF; - base[1] = (size >> 8) & 0x00FF; - - return 0 == left; -} - - -// ---------------------------------------------------------------------------- -// usbs_ethdrv_init() -// -// This function is called during system initialization to decide -// whether or not this particular network device is usable. For -// USB-ethernet this is problematical, the device is only really -// usable once both sides have come up. The typical sequence -// of events is something like: -// -// 1) the eCos peripheral is powered up. Static constructors are -// run resulting in basic initialization. -// -// 2) the eCos TCP/IP stack initialization happens. Roughly in -// parallel the eCos USB slave side is initialized as well, -// i.e. enumeration data is supplied to control endpoints, -// endpoints are associated with application classes, and so -// on. The relative order of TCP/IP and USB initialization is -// not particularly important. -// -// It is the TCP/IP stack's initialization code that will -// invoke usbs_eth_init(). -// -// 3) host-side USB detects that the eCos peripheral has been -// connected or powered up. It goes through the enumeration -// process and will end up loading a host-side network driver. -// This connects to the eCos-side USB ethernet code to -// e.g. obtain the MAC address. -// -// 4) when the host-side is ready, the eCos side can be brought up. -// The required call is (sc->funs->eth_drv->init)(sc, enaddr) -// -// In practice it is easier for now to invoke the init() function -// immediately. There are not going to be any incoming packets -// until the host is ready, and can_send() can just return false -// for the time being. -// -// Invoked in: thread context only -// ---------------------------------------------------------------------------- - -static bool -usbs_ethdrv_init(struct cyg_netdevtab_entry* ndp) -{ - struct eth_drv_sc* sc = (struct eth_drv_sc*)(ndp->device_instance); - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - - (*sc->funs->eth_drv->init)(sc, eth->ecos_MAC); - return true; -} - -// ---------------------------------------------------------------------------- -// The receive process that is used to transfer a received ethernet -// packet into the stack. The calling sequence is somewhat convoluted. -// It started off as: -// -// 1) Ethernet hw ISR invoked by hardware, schedules its own -// hw_dsr(), and blocks further interrupts in the ethernet chip -// 2) hw_dsr() calls generic eth_drv_dsr() from io/eth common package -// 3) eth_drv_dsr() interacts with the TCP/IP stack and allocates mbufs -// (typically, the TCP/IP stack might not be in use) -// 4) eth_drv_dsr() calls usbs_eth_recv() to transfer the data to mbufs -// 5) eth_drv_dsr() returns to hw_dsr() which reenables interrupts -// 6) hw_dsr() completes and everything can proceed. -// -// The problem with this is that the whole ethernet packet gets copied -// inside a DSR, affecting dispatch latency (but not interrupt latency). -// This is bad. Hence there is an alternative route involving a separate -// thread in the TCP/IP stack. -// -// 1) Ethernet hw ISR runs as before, scheduling hw_dsr() -// 2) hw_dsr() calls up into eth_drv_dsr() -// 3) eth_drv_dsr() wakes up a thread inside the TCP/IP stack -// 4) eth_drv_dsr() returns to hw_dsr(), which performs no further -// processing. Ethernet chip interrupts remain disabled. -// 5) The TCP/IP thread ends up calling hw_deliver(). This should take -// care of any pending activity. For every buffered packet there should -// be a call to a generic recv() function which then goes back into -// the driver-specific recv() function. -// -// The advantage is that ethernet packet copying now happens at thread -// level rather than DSR level so thread priorities can be used to -// schedule things. -// -// USB-ethernet does not interact directly with any hardware, instead -// it just passes information to lower levels of USB code. The reception -// process is started by usbs_ethdrv_start() when the TCP/IP stack brings -// up the interface. -// -// When the USB transfer has completed a callback will be invoked, at -// DSR level. Assuming the transfer went ok, the callback will invoke -// eth_drv_dsr() to inform the higher level code. -// -// The deliver function can check the state of the buffer -// and go through the sc->funs->eth_drv->recv()/recv() sequence -// to transfer the data into the stack. -// -// usbs_ethdrv_recv() does a scatter from the internal buffer into the -// mbuf, thus freeing up the buffer. This allows it to start another -// receive, -// -// Synchronisation involves the scheduler lock because the recv -// callback is invoked inside a DSR. - -static void usbs_ethdrv_halted_callback(void*, int); - -static void -usbs_ethdrv_recv_callback(usbs_eth* eth, void* callback_data, int size) -{ - cyg_bool resubmit = true; - - struct eth_drv_sc* sc = (struct eth_drv_sc*) callback_data; - CYG_ASSERT( eth == (usbs_eth*)(sc->driver_private), "USB and TCP/IP worlds need to be consistent"); - - INCR_STAT(eth->interrupts); - if (!eth->ecos_up) { - // This message should just be discarded since the eCos TCP/IP - // stack is not expecting anything from this interface. - // Reception will resume when the interface comes back up. - eth->rx_active = false; - resubmit = false; - } else if (size < 0) { - // An error has occurred. The likely possibilities are: - // -EPIPE: connection to the host has been broken - // -EAGAIN: the endpoint is haltedn - // -EMSGSIZE: bogus message from host - // -EIO: other - - if (-EAGAIN == size) { - // EAGAIN should be handled by waiting for the endpoint to be reset. - resubmit = false; - usbs_start_rx_endpoint_wait(eth->rx_endpoint, &usbs_ethdrv_halted_callback, (void*) sc); - } else if (-EMSGSIZE == size) { - // Do nothing for now - } else { - // EPIPE should be resubmitted, the usbseth.c will use the - // pending rx support. EIO could mean anything. - } - } else if (0 == size) { - // The endpoint is no longer halted. Just do the resubmit at - // the end. - } else { - // A packet has been received. Now do a size sanity check - // based on the first two bytes. - int real_size = eth->rx_bufptr[0] + (eth->rx_bufptr[1] << 8); - if (real_size < CYGNUM_USBS_ETH_MIN_FRAME_SIZE) { - INCR_STAT(eth->rx_short_frames); - } else if (real_size > CYGNUM_USBS_ETH_MAX_FRAME_SIZE) { - INCR_STAT(eth->rx_too_long_frames); - } else { - // The packet appears to be valid. Inform higher level - // code and mark the buffer as in use. - resubmit = false; - eth->rx_buffer_full = true; - eth->rx_active = false; - eth_drv_dsr(0, 0, (cyg_addrword_t) sc); - } - } - - if (resubmit) { - eth->rx_active = true; - usbs_eth_start_rx(eth, eth->rx_bufptr, &usbs_ethdrv_recv_callback, callback_data); - } -} - -// Another callback, used to wait while an endpoint is halted. -static void -usbs_ethdrv_halted_callback(void* callback_data, int size) -{ - struct eth_drv_sc* sc = (struct eth_drv_sc*) callback_data; - usbs_ethdrv_recv_callback((usbs_eth*) sc->driver_private, callback_data, 0); -} - -// Start a receive operation. It is not possible to abort an existing -// rx operation, so a valid sequence of events is: start, rx ongoing, -// stop, restart. The rx_active field is used to keep track of whether -// or not there is still a receive in progress. The receive callback -// will just discard incoming data if the eCos stack is not currently -// running. -static void -usbs_ethdrv_start_recv(struct eth_drv_sc* sc, usbs_eth* eth) -{ - cyg_drv_dsr_lock(); - if (!eth->rx_active) { - eth->rx_active = true; - usbs_eth_start_rx(eth, eth->rx_bufptr, &usbs_ethdrv_recv_callback, (void*) sc); - } - cyg_drv_dsr_unlock(); -} - -// This is invoked from the delivery thread when a valid buffer -// has been received. The buffer should be scattered into the -// supplied list, then another receive should be started. - -static void -usbs_ethdrv_recv(struct eth_drv_sc* sc, - struct eth_drv_sg* sg_list, int sg_len) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - - CYG_ASSERT( eth->rx_buffer_full, "This function should only be called when there is a buffer available"); - (void) scatter(eth->rx_bufptr, sg_list, sg_len); - eth->rx_buffer_full = false; - eth->rx_active = true; - usbs_eth_start_rx(eth, eth->rx_bufptr, &usbs_ethdrv_recv_callback, (void*) sc); -} - -// ---------------------------------------------------------------------------- -// Now for the transmit process. -// -// When an application thread writes down a socket the data gets moved -// into mbufs, and then passed to the appropriate device driver - which -// may or may not be able to process it immediately. There is also a -// timeout thread within the TCP/IP to handle retransmits etc. -// -// The stack will start by calling usbs_ethdrv_can_send() to determine -// whether or not the driver can accept the packet. For the purposes -// of the USB-ethernet driver this is true provided both host -// and target are up and there is a spare buffer available. -// -// If the usbs_eth_can_send() returns true then there will be a call -// to usbs_ethdrv_send(). This gathers the data into a single -// buffer. If there is no transmit in progress yet then one is started. -// -// At some point the packet will have been transmitted and a callback -// gets invoked. This needs to call eth_drv_dsr(), waking up the -// delivery thread. The deliver() function can then check which -// transmissions have completed and inform the higher level code -// via sc->funs->eth_drv->tx_done(). The buffer can be re-used at -// that point. - -static void -usbs_ethdrv_send_callback(usbs_eth* eth, void* callback_data, int size) -{ - struct eth_drv_sc* sc = (struct eth_drv_sc*) callback_data; - CYG_ASSERT( eth == (usbs_eth*)(sc->driver_private), "USB and TCP/IP worlds need to be consistent"); - - INCR_STAT(eth->interrupts); - - // There are a variety of possible error codes. -EAGAIN indicates - // that the endpoint is stalled. -EPIPE indicates that the - // connection to the host has been lost. These are not really - // particularly interesting. Whatever happens the buffer - // must be cleared and higher-level code informed so that - // the mbufs can be released. - if (size > 0) { - INCR_STAT(eth->tx_count); - } - eth->tx_done = true; - eth_drv_dsr(0, 0, (cyg_addrword_t) sc); -} - -// Is it possible to send an ethernet frame? This requires -// an empty buffer, i.e. there should be no existing -// transmit in progress. It also requires that the host -// is connected and that the endpoint is not currently halted. -static int -usbs_ethdrv_can_send(struct eth_drv_sc* sc) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - return eth->host_up && !eth->tx_buffer_full && !eth->tx_endpoint->halted; -} - -// Actually start a packet transmission. This means collecting -// all the data into a single buffer and then invoking the -// lower-level code. The latter may discard the packet immediately -// if the MAC is not appropriate: it would be more efficient to -// catch that here, especially for large packets, but the check -// has to happen inside the lower-level code anyway in case -// that is being invoked directly rather than via the driver. -// -// There is a possible recursion problem, -// send->start_tx->tx_done->can_send->send, which is guarded -// against using the tx_in_send flag. - -static void -usbs_ethdrv_send(struct eth_drv_sc* sc, - struct eth_drv_sg* sgl_list, int sg_len, int total_len, - unsigned long key) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - - CYG_ASSERT( 0 == eth->tx_in_send, "send() should not be invoked recursively"); - CYG_ASSERT( total_len <= CYGNUM_USBS_ETH_MAX_FRAME_SIZE, "ethernet maximum frame size should be observed"); - CYG_ASSERT( CYGNUM_USBS_ETH_MIN_FRAME_SIZE <= total_len, "ethernet minimum frame size should be observed"); - - eth->tx_in_send = true; - CYG_ASSERT( !eth->tx_buffer_full, "the transmit buffer should be empty"); - gather(eth->tx_buffer, CYGNUM_USBS_ETH_MAX_FRAME_SIZE, sgl_list, sg_len); - eth->tx_buffer_full = true; - eth->tx_done = false; - eth->tx_key = key; - usbs_eth_start_tx(eth, eth->tx_buffer, &usbs_ethdrv_send_callback, (void*) sc); - eth->tx_in_send = false; -} - -// ---------------------------------------------------------------------------- -// Deliver needs to take into account both receive and transmit buffers. - -static void -usbs_ethdrv_deliver(struct eth_drv_sc* sc) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - - if (eth->rx_buffer_full) { - int size = eth->rx_bufptr[0] + (eth->rx_bufptr[1] << 8); - (*sc->funs->eth_drv->recv)(sc, size); - } - if (eth->tx_done) { - unsigned long key = eth->tx_key; - eth->tx_buffer_full = false; - eth->tx_done = false; - (*sc->funs->eth_drv->tx_done)(sc, key, 1); - } -} - -// ---------------------------------------------------------------------------- -// usbs_ethdrv_start() -// -// This gets called by the TCP/IP stack later on during -// initialization, when the stack is ready to send and receive -// packets. It may get called multiple times while the stack -// is running, with different flags values. -// -// As far as transmits are concerned, nothing needs to be done. If no -// transmit is in progress then everything is fine anyway. If a -// transmit is already in progress then it must be allowed to complete -// via the usual route. Receives should however be restarted, the -// start function has appropriate safeguards. -// -// Invoked in: thread context only -// ---------------------------------------------------------------------------- - -static void -usbs_ethdrv_start(struct eth_drv_sc* sc, unsigned char* enaddr, int flags) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - if (!eth->ecos_up) { - eth->ecos_up = true; - usbs_ethdrv_start_recv(sc, eth); - } -} - -// ---------------------------------------------------------------------------- -// usbs_ethdrv_stop() -// -// Similarly this gets called by the TCP/IP stack to bring the network -// interface down. Nothing should happen for any packets currently -// being transmitted or received, that would cause confusion everywhere. -// The receive callback checks the ecos_up flag and does the right -// thing. The TCP/IP stack should not call can_send() after taking -// the interface down so no new transmits will be initiated. -// -// Invoked in: thread context only -// ---------------------------------------------------------------------------- - -static void -usbs_ethdrv_stop(struct eth_drv_sc* sc) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - eth->ecos_up = false; -} - -// ---------------------------------------------------------------------------- -// usbs_eth_ioctl() -// -// The operations to worry about here are: -// -// SET_MAC_ADDRESS,via the SIOCSIFHWADDR ioctl -// -// GET_IF_STATS and GET_IF_STATS_UD, to report gathered statistics. -// -// Invoked in: thread context only -// ---------------------------------------------------------------------------- - -static int -usbs_ethdrv_ioctl(struct eth_drv_sc* sc, unsigned long key, void* data, int data_length) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - int result = EINVAL; - - switch(key) { - case ETH_DRV_SET_MAC_ADDRESS: - { - if (6 == data_length) { - memcpy(eth->ecos_MAC, data, 6); - result = 0; - } - } - break; -#if defined(CYGFUN_USBS_ETHDRV_STATISTICS) && defined(ETH_DRV_GET_IF_STATS_UD) - case ETH_DRV_GET_IF_STATS_UD: - case ETH_DRV_GET_IF_STATS: - { - static unsigned char my_chipset[] = { 0, 0 }; - struct ether_drv_stats *p = (struct ether_drv_stats*) data; - int i; - strcpy(p->description, CYGDAT_USBS_ETHDRV_DESCRIPTION); - for ( i = 0; i < SNMP_CHIPSET_LEN; i++ ) { - if ( 0 == (p->snmp_chipset[i] = my_chipset[i]) ) { - break; - } - } - p->duplex = 3; // 3 == duplex - p->operational = (eth->host_up && eth->ecos_up) ? 3 : 2; // 3 == up, 2 == down - p->speed = 10 * 1000000; - p->supports_dot3 = 1; - p->rx_too_long_frames = eth->rx_too_long_frames; - p->rx_short_frames = eth->rx_short_frames; - p->interrupts = eth->interrupts; - p->rx_count = eth->rx_count; - p->tx_count = eth->tx_count; - p->tx_queue_len = 1; - } - break; -#endif - - default: - break; - } - - return result; -} - - -// ---------------------------------------------------------------------------- -// usbs_ethdrv_poll() -// -// On real ethernet hardware this is used by RedBoot once the -// application has started running, so that the network device can be -// used for debugging purposes as well as for the application's own -// needs. The lower-level USB device may supply a poll function as well. -// ---------------------------------------------------------------------------- -static void -usbs_ethdrv_poll(struct eth_drv_sc* sc) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - (*eth->control_endpoint->poll_fn)(eth->control_endpoint); -} - -// ---------------------------------------------------------------------------- -// usbs_ethdrv_intvector() -// -// See usbs_eth_poll(). -// ---------------------------------------------------------------------------- - -static int -usbs_ethdrv_intvector(struct eth_drv_sc* sc) -{ - usbs_eth* eth = (usbs_eth*)(sc->driver_private); - return eth->control_endpoint->interrupt_vector; -} - - Index: eth/slave/v2_0/src/usbseth.c =================================================================== --- eth/slave/v2_0/src/usbseth.c (revision 174) +++ eth/slave/v2_0/src/usbseth.c (nonexistent) @@ -1,321 +0,0 @@ -//========================================================================== -// -// usbseth.c -// -// Support for USB-ethernet devices, slave-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#### -// -// Author(s): bartv -// Contributors: bartv -// Date: 2000-10-04 -// -//####DESCRIPTIONEND#### -// -//========================================================================== - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define __ECOS 1 -#include - -#ifdef CYGPKG_USBS_ETHDRV -#include -#include -#endif - -// ---------------------------------------------------------------------------- -// Static data. -// -// usbs_eth0 contains the per-device data, both the low-level data -// such as which endpoints to use and the network-driver data such as -// SNMP statistics. If this package is loaded then the assumption -// is that there should be at least one USB-ethernet device. Additional -// ones can be instantiated in application code if necessary. A call -// to usbs_eth_init() is required for initialization. -usbs_eth usbs_eth0; - -// ---------------------------------------------------------------------------- -// Initialization. This should be called explicitly by application code -// at an appropriate point in the system startup. -void -usbs_eth_init(usbs_eth* eth, usbs_control_endpoint* ctrl, usbs_rx_endpoint* rx, usbs_tx_endpoint* tx, unsigned char* mac) -{ - eth->control_endpoint = ctrl; - eth->rx_endpoint = rx; - eth->tx_endpoint = tx; - eth->host_up = false; - eth->host_promiscuous = false; - memcpy(eth->host_MAC, mac, 6); - eth->rx_pending_buf = (unsigned char*) 0; - - // Install default handlers for some messages. Higher level code - // may override this. - ctrl->state_change_fn = &usbs_eth_state_change_handler; - ctrl->state_change_data = (void*) eth; - ctrl->class_control_fn = &usbs_eth_class_control_handler; - ctrl->class_control_data = (void*) eth; - -#ifdef CYGPKG_USBS_ETHDRV - eth->ecos_up = false; - eth->rx_active = false; -# ifdef CYGFUN_USBS_ETHDRV_STATISTICS - eth->interrupts = 0; - eth->tx_count = 0; - eth->rx_count = 0; -# endif -# ifndef HAL_DCACHE_LINE_SIZE - eth->rx_bufptr = eth->rx_buffer; -# else -# endif - eth->rx_bufptr = (unsigned char*) ((((cyg_uint32)eth->rx_buffer) + HAL_DCACHE_LINE_SIZE - 1) - & ~(HAL_DCACHE_LINE_SIZE - 1)); - eth->rx_buffer_full = false; - eth->tx_in_send = false; - eth->tx_buffer_full = false; - eth->tx_done = false; -#endif -} - - -// ---------------------------------------------------------------------------- -// Generic transmit and receive operations. These can be called -// explicitly by application code, or implicitly via the eCos ethernet -// device driver code in usbsethdrv.c. These two modes of operation -// should not be mixed since the routines do not perform any -// synchronization themselves, instead they rely on higher level code. - -// Packet transmission. The exported function is usbs_eth_start_tx(), -// which can be invoked from thread context or DSR context. The -// supplied buffer must already be in a form that can be transmitted -// directly out of the USB endpoint with no further processing -// (although it is necessary to extract the size information from the -// buffer). -// -// When the underlying USB transfer has completed the USB code will invoke -// usbs_eth_tx_callback(), usually in DSR context although possibly in -// thread context depending on the specific USB implementation. The -// underlying USB driver may have had to do some padding so the amount -// transferred may be slightly greater than requested. - -static void -usbs_eth_tx_callback(void* usbs_callback_arg, int size) -{ - usbs_eth* eth = (usbs_eth*) usbs_callback_arg; - CYG_ASSERT( (size < 0) || (size >= CYGNUM_USBS_ETH_MINTU), "returned size must be valid."); - (*eth->tx_callback_fn)(eth, eth->tx_callback_arg, size); -} - -void -usbs_eth_start_tx(usbs_eth* eth, unsigned char* buf, void (*callback_fn)(usbs_eth*, void*, int), void* callback_arg) -{ - int size; - cyg_bool address_ok = false; - static const unsigned char broadcast_mac[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - - size = buf[0] + (buf[1] << 8); - CYG_ASSERT( (size < 0) || ((size >= CYGNUM_USBS_ETH_MIN_FRAME_SIZE) && (size <= CYGNUM_USBS_ETH_MAX_FRAME_SIZE)), \ - "ethernet frame size constraints must be observed"); - - if ((0 == memcmp(buf + 2, eth->host_MAC, 6)) || - (0 == memcmp(buf + 2, broadcast_mac, 6))) { - address_ok = true; - } - - // The following checks involve data that can change as a result - // of control operations, so it is necessary to synchronize with - // those. The control operations will typically run at DSR level - // so a DSR lock has to be used. - - cyg_drv_dsr_lock(); - if (eth->host_up && (address_ok || eth->host_promiscuous)) { - - eth->tx_callback_fn = callback_fn; - eth->tx_callback_arg = callback_arg; - eth->tx_endpoint->buffer = buf; - eth->tx_endpoint->buffer_size = size + 2; - eth->tx_endpoint->complete_fn = &usbs_eth_tx_callback; - eth->tx_endpoint->complete_data = (void*) eth; - (*(eth->tx_endpoint->start_tx_fn))(eth->tx_endpoint); - - } else { - // Packets not intended for the host can be discarded quietly. - // A broken connection needs to be reported. - (*callback_fn)(eth, callback_arg, eth->host_up ? size : -EPIPE); - } - cyg_drv_dsr_unlock(); -} - -// Packet reception. This simply involves starting a transfer for -// up to the maximum ethernet frame size. The lower-level USB code -// will detect the end of the transfer. The exported function is -// usbs_eth_start_rx(). -static void -usbs_eth_rx_callback(void* usbs_callback_arg, int size) -{ - usbs_eth* eth = (usbs_eth*) usbs_callback_arg; - - CYG_ASSERT( (size <= 0) || ((size >= CYGNUM_USBS_ETH_MINTU) && (size <= CYGNUM_USBS_ETH_MAXTU)), \ - "ethernet frame size constraints must be observed"); - - (*eth->rx_callback_fn)(eth, eth->rx_callback_arg, size); -} - -void -usbs_eth_start_rx(usbs_eth* eth, unsigned char* buf, void (*callback_fn)(usbs_eth*, void*, int), void* callback_arg) -{ - eth->rx_callback_fn = callback_fn; - eth->rx_callback_arg = callback_arg; - - cyg_drv_dsr_lock(); - if (eth->host_up) { - eth->rx_endpoint->buffer = buf; - eth->rx_endpoint->buffer_size = CYGNUM_USBS_ETH_RXSIZE; - eth->rx_endpoint->complete_fn = &usbs_eth_rx_callback; - eth->rx_endpoint->complete_data = (void*) eth; - (*(eth->rx_endpoint->start_rx_fn))(eth->rx_endpoint); - } else { - CYG_ASSERT( (void*) 0 == eth->rx_pending_buf, "No RX operation should be in progress"); - eth->rx_pending_buf = buf; - } - cyg_drv_dsr_unlock(); -} - -// ---------------------------------------------------------------------------- -// Control operations. The host may send two types of application-specific -// control messages, one to get the MAC address and one to enable/disable -// promiscuous mode on the host side. This callback will typically be invoked -// in DSR context. - -// These constants need to be shared somehow with the driver in ../host/, -// but if some variant of that driver becomes part of the Linux kernel -// then its sources must be self-contained with no dependencies on -// eCos sources or headers. Hence a duplicate definition for now. -#define USBS_ETH_CONTROL_GET_MAC_ADDRESS 0x01 -#define USBS_ETH_CONTROL_SET_PROMISCUOUS_MODE 0x02 - -usbs_control_return -usbs_eth_class_control_handler(usbs_control_endpoint* endpoint, void* callback_data) -{ - usbs_control_return result = USBS_CONTROL_RETURN_STALL; - - usbs_eth* eth = (usbs_eth*) callback_data; - usb_devreq* devreq = (usb_devreq*) endpoint->control_buffer; - int size = (devreq->length_hi << 8) + devreq->length_lo; - - CYG_ASSERT(endpoint == eth->control_endpoint, "USB ethernet control messages correctly routed"); - - if (USBS_ETH_CONTROL_GET_MAC_ADDRESS == devreq->request) { - // This should be an IN operation for at least six bytes. - if ((size >= 6) && - (USB_DEVREQ_DIRECTION_IN == (devreq->type & USB_DEVREQ_DIRECTION_MASK))) { - - endpoint->buffer = eth->host_MAC; - endpoint->buffer_size = 6; - result = USBS_CONTROL_RETURN_HANDLED; - } - // Otherwise drop through with a return value of STALL - - } else if (USBS_ETH_CONTROL_SET_PROMISCUOUS_MODE == devreq->request) { - // The length should be 0, no more data is expected by either side. - if (0 == size) { - // The new promiscuity mode is encoded in value_lo; - eth->host_promiscuous = devreq->value_lo; - result = USBS_CONTROL_RETURN_HANDLED; - } - } - - return result; -} - -// State changes. As far as the ethernet code is concerned, if there -// is a change to CONFIGURED state then the device has come up, -// otherwise if there is a change from CONFIGURED state it has gone -// down. All other state changes are irrelevant. -void -usbs_eth_state_change_handler(usbs_control_endpoint* endpoint, void* callback_data, usbs_state_change change, int old_state) -{ - usbs_eth* eth = (usbs_eth*) callback_data; - CYG_ASSERT(endpoint == eth->control_endpoint, "USB ethernet state changes correctly routed"); - - if (USBS_STATE_CHANGE_CONFIGURED == change) { - if (USBS_STATE_CONFIGURED != old_state) { - usbs_eth_enable(eth); - } - } else if ((USBS_STATE_CHANGE_RESUMED == change) && (USBS_STATE_CONFIGURED == (USBS_STATE_MASK & old_state))) { - usbs_eth_enable(eth); - } else if (eth->host_up) { - usbs_eth_disable(eth); - } -} - -// Disabling the ethernet device means clearing the host_up flag. -// This will block future transmits and receives but not any -// that are currently underway. -void -usbs_eth_disable(usbs_eth* eth) -{ - eth->host_up = false; -} - -// Enabling the ethernet device means setting the host_up flag and -// possibly activating a pending rx operation. -void -usbs_eth_enable(usbs_eth* eth) -{ - if (!eth->host_up) { - eth->host_up = true; - eth->host_promiscuous = false; - if ((void*) 0 != eth->rx_pending_buf) { - eth->rx_endpoint->buffer = eth->rx_pending_buf; - eth->rx_endpoint->buffer_size = CYGNUM_USBS_ETH_RXSIZE; - eth->rx_endpoint->complete_fn = &usbs_eth_rx_callback; - eth->rx_endpoint->complete_data = (void*) eth; - eth->rx_pending_buf = (void*) 0; - (*(eth->rx_endpoint->start_rx_fn))(eth->rx_endpoint); - } - } -} - Index: eth/slave/v2_0/host/ecos_usbeth.c =================================================================== --- eth/slave/v2_0/host/ecos_usbeth.c (revision 174) +++ eth/slave/v2_0/host/ecos_usbeth.c (nonexistent) @@ -1,572 +0,0 @@ -//========================================================================== -// -// ecos_usbeth.c -// -// Linux device driver for eCos-based USB ethernet peripherals. -// -//========================================================================== -//####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#### -// -// Author(s): bartv -// Contributors: bartv -// Date: 2000-11-12 -// -//####DESCRIPTIONEND#### -//========================================================================== - -#include -#include -#include -#include -#include - -#ifdef MODULE -MODULE_AUTHOR("Bart Veer "); -MODULE_DESCRIPTION("USB ethernet driver for eCos-based peripherals"); -#endif - -// This array identifies specific implementations of eCos USB-ethernet -// devices. All implementations should add their vendor and device -// details. - -typedef struct ecos_usbeth_impl { - const char* name; - __u16 vendor; - __u16 id; -} ecos_usbeth_impl; - -const static ecos_usbeth_impl ecos_usbeth_implementations[] = { - { "eCos ether", 0x4242, 0x4242 }, - { (const char*) 0, 0, 0 } -}; - - -// Constants. These have to be kept in sync with the target-side -// code. -#define ECOS_USBETH_MAXTU 1516 -#define ECOS_USBETH_MAX_CONTROL_TU 8 -#define ECOS_USBETH_CONTROL_GET_MAC_ADDRESS 0x01 -#define ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE 0x02 - -// The main data structure. It keeps track of both the USB -// and network side of things, and provides buffers for -// the various operations. -// -// NOTE: currently this driver only supports a single -// plugged-in device. Theoretically multiple eCos-based -// USB ethernet devices could be plugged in to a single -// host and each one would require an ecos_usbeth -// structure. -typedef struct ecos_usbeth { - spinlock_t usb_lock; - int target_promiscuous; - struct usb_device* usb_dev; - struct net_device* net_dev; - struct net_device_stats stats; - struct urb rx_urb; - struct urb tx_urb; - unsigned char rx_buffer[ECOS_USBETH_MAXTU]; - unsigned char tx_buffer[ECOS_USBETH_MAXTU]; -} ecos_usbeth; - - -// open() -// Invoked by the TCP/IP stack when the interface is brought up. -// This just starts a receive operation. -static int -ecos_usbeth_open(struct net_device* net) -{ - ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; - int res; - - netif_start_queue(net); - res = usb_submit_urb(&(usbeth->rx_urb)); - if (0 != res) { - printk("ecos_usbeth: failed to start USB receives, %d\n", res); - } - MOD_INC_USE_COUNT; - return 0; -} - -// close() -// Invoked by the TCP/IP stack when the interface is taken down. -// Any active USB operations need to be cancelled. During -// a disconnect this may get called twice, once for the -// disconnect and once for the network interface being -// brought down. -static int -ecos_usbeth_close(struct net_device* net) -{ - ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; - - if (0 != netif_running(net)) { - netif_stop_queue(net); - net->start = 0; - - if (-EINPROGRESS == usbeth->rx_urb.status) { - usb_unlink_urb(&(usbeth->rx_urb)); - } - if (-EINPROGRESS == usbeth->tx_urb.status) { - usb_unlink_urb(&(usbeth->tx_urb)); - } - MOD_DEC_USE_COUNT; - } - - return 0; -} - -// Reception. -// probe() fills in an rx_urb. When the net device is brought up -// the urb is activated, and this callback gets run for incoming -// data. -static void -ecos_usbeth_rx_callback(struct urb* urb) -{ - ecos_usbeth* usbeth = (ecos_usbeth*) urb->context; - struct net_device* net = usbeth->net_dev; - struct sk_buff* skb; - int len; - int res; - - if (0 != urb->status) { - // This happens numerous times during a disconnect. Do not - // issue a warning, but do clear the status field or things - // get confused when resubmitting. - // - // Some host hardware does not distinguish between CRC errors - // (very rare) and timeouts (perfectly normal). Do not - // increment the error count if it might have been a timeout. - if (USB_ST_CRC != urb->status) { - usbeth->stats.rx_errors++; - } - urb->status = 0; - } else if (2 > urb->actual_length) { - // With some hardware the target may have to send a bogus - // first packet. Just ignore those. - - } else { - len = usbeth->rx_buffer[0] + (usbeth->rx_buffer[1] << 8); - if (len > (urb->actual_length - 2)) { - usbeth->stats.rx_errors++; - usbeth->stats.rx_length_errors++; - printk("ecos_usbeth: warning, packet size mismatch, got %d bytes, expected %d\n", - urb->actual_length, len); - } else { - skb = dev_alloc_skb(len + 2); - if ((struct sk_buff*)0 == skb) { - printk("ecos_usbeth: failed to alloc skb, dropping packet\n"); - usbeth->stats.rx_dropped++; - } else { -#if 0 - { - int i; - printk("--------------------------------------------------------------\n"); - printk("ecos_usbeth RX: total size %d\n", len); - for (i = 0; (i < len) && (i < 128); i+= 8) { - printk("rx %x %x %x %x %x %x %x %x\n", - usbeth->rx_buffer[i+0], usbeth->rx_buffer[i+1], usbeth->rx_buffer[i+2], usbeth->rx_buffer[i+3], - usbeth->rx_buffer[i+4], usbeth->rx_buffer[i+5], usbeth->rx_buffer[i+6], usbeth->rx_buffer[i+7]); - } - printk("--------------------------------------------------------------\n"); - } -#endif - skb->dev = net; - eth_copy_and_sum(skb, &(usbeth->rx_buffer[2]), len, 0); - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, net); - netif_rx(skb); - usbeth->stats.rx_packets++; - usbeth->stats.rx_bytes += len; - } - } - } - - if (0 != netif_running(net)) { - res = usb_submit_urb(&(usbeth->rx_urb)); - if (0 != res) { - printk("ecos_usbeth: failed to restart USB receives after packet, %d\n", res); - } - } -} - -// start_tx(). -// Transmit a single packet. The relevant USB protocol requires a -// 2-byte length field at the start, the incoming buffer has no space -// for this, and the URB API does not support any form of -// scatter/gather. Therefore unfortunately the whole packet has to be -// copied. The callback function is specified when the URB is filled -// in by probe(). -static void -ecos_usbeth_tx_callback(struct urb* urb) -{ - ecos_usbeth* usbeth = (ecos_usbeth*) urb->context; - spin_lock(&usbeth->usb_lock); - if (0 != netif_running(usbeth->net_dev)) { - netif_wake_queue(usbeth->net_dev); - } - spin_unlock(&usbeth->usb_lock); -} - -static int -ecos_usbeth_start_tx(struct sk_buff* skb, struct net_device* net) -{ - ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; - int res; - - if ((skb->len + 2) > ECOS_USBETH_MAXTU) { - printk("ecos_usbeth: oversized packet of %d bytes\n", skb->len); - return 0; - } - - if (netif_queue_stopped(net)) { - // Another transmission already in progress. - // USB bulk operations should complete within 5s. - int current_delay = jiffies - net->trans_start; - if (current_delay < (5 * HZ)) { - return 1; - } else { - // There has been a timeout. Discard this message. - //printk("transmission timed out\n"); - usbeth->stats.tx_errors++; - dev_kfree_skb(skb); - return 0; - } - } - - spin_lock(&usbeth->usb_lock); - usbeth->tx_buffer[0] = skb->len & 0x00FF; - usbeth->tx_buffer[1] = (skb->len >> 8) & 0x00FF; - memcpy(&(usbeth->tx_buffer[2]), skb->data, skb->len); - usbeth->tx_urb.transfer_buffer_length = skb->len + 2; - - // Some targets are unhappy about receiving 0-length packets, not - // just sending them. - if (0 == (usbeth->tx_urb.transfer_buffer_length % 64)) { - usbeth->tx_urb.transfer_buffer_length++; - } -#if 0 - { - int i; - printk("--------------------------------------------------------------\n"); - printk("ecos_usbeth start_tx: len %d\n", skb->len + 2); - for (i = 0; (i < (skb->len + 2)) && (i < 128); i+= 8) { - printk("tx %x %x %x %x %x %x %x %x\n", - usbeth->tx_buffer[i], usbeth->tx_buffer[i+1], usbeth->tx_buffer[i+2], usbeth->tx_buffer[i+3], - usbeth->tx_buffer[i+4], usbeth->tx_buffer[i+5], usbeth->tx_buffer[i+6], usbeth->tx_buffer[i+7]); - } - printk("--------------------------------------------------------------\n"); - } -#endif - res = usb_submit_urb(&(usbeth->tx_urb)); - if (0 == res) { - netif_stop_queue(net); - net->trans_start = jiffies; - usbeth->stats.tx_packets++; - usbeth->stats.tx_bytes += skb->len; - } else { - printk("ecos_usbeth: failed to start USB packet transmission, %d\n", res); - usbeth->stats.tx_errors++; - } - - spin_unlock(&usbeth->usb_lock); - dev_kfree_skb(skb); - return 0; -} - - -// set_rx_mode() -// Invoked by the network stack to enable/disable promiscuous mode or -// for multicasting. The latter is not yet supported on the target -// side. The former involves a USB control message. The main call -// is not allowed to block. -static void -ecos_usbeth_set_rx_mode_callback(struct urb* urb) -{ - kfree(urb->setup_packet); - usb_free_urb(urb); -} - -static void -ecos_usbeth_set_rx_mode(struct net_device* net) -{ - ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; - __u16 promiscuous = net->flags & IFF_PROMISC; - int res; - - if (promiscuous != usbeth->target_promiscuous) { - devrequest* req; - urb_t* urb; - - urb = usb_alloc_urb(0); - if ((urb_t*)0 == urb) { - return; - } - req = kmalloc(sizeof(devrequest), GFP_KERNEL); - if ((devrequest*)0 == req) { - usb_free_urb(urb); - return; - } - req->requesttype = USB_TYPE_CLASS | USB_RECIP_DEVICE; - req->request = ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE; - req->value = cpu_to_le16p(&promiscuous); - req->index = 0; - req->length = 0; - - FILL_CONTROL_URB(urb, - usbeth->usb_dev, - usb_sndctrlpipe(usbeth->usb_dev, 0), - (unsigned char*) req, - (void*) 0, - 0, - &ecos_usbeth_set_rx_mode_callback, - (void*) usbeth); - res = usb_submit_urb(urb); - if (0 != res) { - kfree(req); - usb_free_urb(urb); - } else { - usbeth->target_promiscuous = promiscuous; - } - } -} - -// netdev_stats() -// Supply the current network statistics. These are held in -// the stats field of the ecos_usbeth structure -static struct net_device_stats* -ecos_usbeth_netdev_stats(struct net_device* net) -{ - ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; - return &(usbeth->stats); -} - -// ioctl() -// Currently none of the network ioctl()'s are supported -static int -ecos_usbeth_ioctl(struct net_device* net, struct ifreq* request, int command) -{ - return -EINVAL; -} - -// probe(). -// This is invoked by the generic USB code when a new device has -// been detected and its configuration details have been extracted -// and stored in the usbdev structure. The interface_id specifies -// a specific USB interface, to cope with multifunction peripherals. -// -// FIXME; right now this code only copes with simple enumeration data. -// OK, to be really honest it just looks for the vendor and device ids -// in the simple test cases and ignores everything else. -// -// On success it should return a non-NULL pointer, which happens to be -// a newly allocated ecos_usbeth structure. This will get passed to -// the disconnect function. Filling in the ecos_usbeth structure will, -// amongst other things, register this as a network device driver. -// The MAC address is obtained from the peripheral via a control -// request. - -static void* -ecos_usbeth_probe(struct usb_device* usbdev, unsigned int interface_id) -{ - struct net_device* net; - ecos_usbeth* usbeth; - int res; - unsigned char MAC[6]; - unsigned char dummy[1]; - int tx_endpoint = -1; - int rx_endpoint = -1; - const ecos_usbeth_impl* impl; - int found_impl = 0; - - // See if this is the correct driver for this USB peripheral. - impl = ecos_usbeth_implementations; - while (impl->name != NULL) { - if ((usbdev->descriptor.idVendor != impl->vendor) || - (usbdev->descriptor.idProduct != impl->id)) { - found_impl = 1; - break; - } - impl++; - } - if (! found_impl) { - return (void*) 0; - } - - // For now only support USB-ethernet peripherals consisting of a single - // configuration, with a single interface, with two bulk endpoints. - if ((1 != usbdev->descriptor.bNumConfigurations) || - (1 != usbdev->config[0].bNumInterfaces) || - (2 != usbdev->config[0].interface[0].altsetting->bNumEndpoints)) { - return (void*) 0; - } - if ((0 == (usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & USB_DIR_IN)) && - (0 != (usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & USB_DIR_IN))) { - tx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress; - rx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & ~USB_DIR_IN; - } - if ((0 != (usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & USB_DIR_IN)) && - (0 == (usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & USB_DIR_IN))) { - tx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress; - rx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & ~USB_DIR_IN; - } - if (-1 == tx_endpoint) { - return (void*) 0; - } - - res = usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue); - if (0 != res) { - printk("ecos_usbeth: failed to set configuration, %d\n", res); - return (void*) 0; - } - res = usb_control_msg(usbdev, - usb_rcvctrlpipe(usbdev, 0), - ECOS_USBETH_CONTROL_GET_MAC_ADDRESS, - USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, - 0, - 0, - (void*) MAC, - 6, - 5 * HZ); - if (6 != res) { - printk("ecos_usbeth: failed to get MAC address, %d\n", res); - return (void*) 0; - } - - res = usb_control_msg(usbdev, - usb_sndctrlpipe(usbdev, 0), // pipe - ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE, // request - USB_TYPE_CLASS | USB_RECIP_DEVICE, // requesttype - 0, // value - 0, // index - (void*) dummy, // data - 0, // size - 5 * HZ); // timeout - if (0 != res) { - printk("ecos_usbeth: failed to disable promiscous mode, %d\n", res); - } - - usbeth = (ecos_usbeth*) kmalloc(sizeof(ecos_usbeth), GFP_KERNEL); - if ((ecos_usbeth*)0 == usbeth) { - printk("ecos_usbeth: failed to allocate memory for usbeth data structure\n"); - return (void*) 0; - } - memset(usbeth, 0, sizeof(ecos_usbeth)); - - net = init_etherdev(0, 0); - if ((struct net_device*) 0 == net) { - kfree(usbeth); - printk("ecos_usbeth: failed to allocate memory for net data structure\n"); - return (void*) 0; - } - - usbeth->usb_lock = SPIN_LOCK_UNLOCKED; - usbeth->usb_dev = usbdev; - FILL_BULK_URB(&(usbeth->tx_urb), usbdev, usb_sndbulkpipe(usbdev, tx_endpoint), - usbeth->tx_buffer, ECOS_USBETH_MAXTU, &ecos_usbeth_tx_callback, (void*) usbeth); - FILL_BULK_URB(&(usbeth->rx_urb), usbdev, usb_rcvbulkpipe(usbdev, rx_endpoint), - usbeth->rx_buffer, ECOS_USBETH_MAXTU, &ecos_usbeth_rx_callback, (void*) usbeth); - - usbeth->net_dev = net; - usbeth->target_promiscuous = 0; - - net->priv = (void*) usbeth; - net->open = &ecos_usbeth_open; - net->stop = &ecos_usbeth_close; - net->do_ioctl = &ecos_usbeth_ioctl; - net->hard_start_xmit = &ecos_usbeth_start_tx; - net->set_multicast_list = &ecos_usbeth_set_rx_mode; - net->get_stats = &ecos_usbeth_netdev_stats; - net->mtu = 1500; // ECOS_USBETH_MAXTU - 2; - memcpy(net->dev_addr, MAC, 6); - - printk("eCos-based USB ethernet peripheral active at %s\n", net->name); - MOD_INC_USE_COUNT; - return (void*) usbeth; -} - -// disconnect(). -// Invoked after probe() has recognized a device but that device -// has gone away. -static void -ecos_usbeth_disconnect(struct usb_device* usbdev, void* data) -{ - ecos_usbeth* usbeth = (ecos_usbeth*) data; - if (!usbeth) { - printk("ecos_usbeth: warning, disconnecting unconnected device\n"); - return; - } - if (0 != netif_running(usbeth->net_dev)) { - ecos_usbeth_close(usbeth->net_dev); - } - unregister_netdev(usbeth->net_dev); - if (-EINPROGRESS == usbeth->rx_urb.status) { - usb_unlink_urb(&(usbeth->rx_urb)); - } - if (-EINPROGRESS == usbeth->tx_urb.status) { - usb_unlink_urb(&(usbeth->tx_urb)); - } - kfree(usbeth); - MOD_DEC_USE_COUNT; -} - -static struct usb_driver ecos_usbeth_driver = { - name: "ecos_usbeth", - probe: ecos_usbeth_probe, - disconnect: ecos_usbeth_disconnect, -}; - -// init() -// Called when the module is loaded. It just registers the device with -// the generic USB code. Nothing else can really be done until -// the USB code detects that a device has been attached. -int __init -ecos_usbeth_init(void) -{ - printk("eCos USB-ethernet device driver\n"); - return usb_register(&ecos_usbeth_driver); -} - -// exit() -// Called when the module is unloaded. disconnect() will be -// invoked if appropriate. -void __exit -ecos_usbeth_exit(void) -{ - usb_deregister(&ecos_usbeth_driver); -} - -module_init(ecos_usbeth_init); -module_exit(ecos_usbeth_exit); Index: eth/slave/v2_0/host/COPYING =================================================================== --- eth/slave/v2_0/host/COPYING (revision 174) +++ eth/slave/v2_0/host/COPYING (nonexistent) @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program 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 of the License, or - (at your option) any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. Index: eth/slave/v2_0/host/Makefile =================================================================== --- eth/slave/v2_0/host/Makefile (revision 174) +++ eth/slave/v2_0/host/Makefile (nonexistent) @@ -1,95 +0,0 @@ -# -# Makefile for the Linux device driver for eCos USB-ethernet -# devices. This makefile has been cloned from the one in -# /usr/src/linux-2.2.16/drivers/usb -# - -# This makefile will chain to the Linux makefile if appropriate. -# The toplevel Linux makefile sets the variable KERNELRELEASE -ifeq (,$(KERNELRELEASE)) - -default: - make -C /usr/src/linux SUBDIRS=$(shell pwd) modules - -modules: default - -modules_install: - @echo Support for installing this module not yet implemented. - -else - -# A recursive invocation of this makefile from the Linux one. - -# Build this driver as a module. -CONFIG_USB_ECOS_USBETH = m - -# Subdirs. - -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) -MOD_IN_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) - -# The target object and module list name. - -O_TARGET := -M_OBJS := -O_OBJS := -MOD_LIST_NAME := ECOS_USBETH_MODULE - -# Objects that export symbols. - -export-objs := - -# Multipart objects. - -list-multi := - -# Optional parts of multipart objects. - -# Object file lists. - -obj-y := -obj-m := -obj-n := -obj- := - -# Object files in subdirectories - -# Each configuration option enables a list of files. - -obj-$(CONFIG_USB_ECOS_USBETH) += ecos_usbeth.o - -# Extract lists of the multi-part drivers. -# The 'int-*' lists are the intermediate files used to build the multi's. - -multi-y := $(filter $(list-multi), $(obj-y)) -multi-m := $(filter $(list-multi), $(obj-m)) -int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) -int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) - -# Files that are both resident and modular: remove from modular. - -obj-m := $(filter-out $(obj-y), $(obj-m)) -int-m := $(filter-out $(int-y), $(int-m)) - -# Take multi-part drivers out of obj-y and put components in. - -obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) - -# Translate to Rules.make lists. - -O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) -OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) -MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) - -# The global Rules.make. - -include $(TOPDIR)/Rules.make - -# Link rules for multi-part drivers. - -endif Index: common/v2_0/cdl/usb.cdl =================================================================== --- common/v2_0/cdl/usb.cdl (revision 174) +++ common/v2_0/cdl/usb.cdl (nonexistent) @@ -1,63 +0,0 @@ -# ==================================================================== -# -# usb.cdl -# -# USB support -# -# ==================================================================== -#####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#### -# -# Author(s): bartv -# Original data: bartv -# Contributors: -# Date: 2000-10-04 -# -#####DESCRIPTIONEND#### -# -# ==================================================================== - -cdl_package CYGPKG_IO_USB { - display "USB Support" - include_dir "cyg/io/usb" - parent CYGPKG_IO - - cdl_interface CYGHWR_IO_USB_HOST { - display "Availability of USB host-side hardware" - } - cdl_interface CYGHWR_IO_USB_SLAVE { - display "Availability of USB slave-side hardware" - } -} Index: common/v2_0/include/usb.h =================================================================== --- common/v2_0/include/usb.h (revision 174) +++ common/v2_0/include/usb.h (nonexistent) @@ -1,249 +0,0 @@ -#ifndef CYGONCE_USB_H -# define CYGONCE_USB_H -//========================================================================== -// -// include/usb.h -// -// Data common to USB host and USB slave -// -//========================================================================== -//####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#### -// -// Author(s): bartv -// Contributors: bartv -// Date: 2000-10-04 -// -//####DESCRIPTIONEND#### -//========================================================================== - -#ifdef __cplusplus -extern "C" { -#endif - -// USB device requests, the setup packet. -// -// The structure is defined entirely in terms of bytes, eliminating -// any confusion about who is supposed to swap what when. This avoids -// endianness-related portability problems, and eliminates any need -// to worry about alignment. Also for some requests the value field -// is split into separate bytes anyway. -typedef struct usb_devreq { - unsigned char type; - unsigned char request; - unsigned char value_lo; - unsigned char value_hi; - unsigned char index_lo; - unsigned char index_hi; - unsigned char length_lo; - unsigned char length_hi; -} usb_devreq __attribute__((packed)); - -// Encoding of the request_type -#define USB_DEVREQ_DIRECTION_OUT 0 -#define USB_DEVREQ_DIRECTION_IN (1 << 7) -#define USB_DEVREQ_DIRECTION_MASK (1 << 7) - -#define USB_DEVREQ_TYPE_STANDARD 0 -#define USB_DEVREQ_TYPE_CLASS (0x1 << 5) -#define USB_DEVREQ_TYPE_VENDOR (0x2 << 5) -#define USB_DEVREQ_TYPE_RESERVED (0x3 << 5) -#define USB_DEVREQ_TYPE_MASK (0x3 << 5) - -#define USB_DEVREQ_RECIPIENT_DEVICE 0x00 -#define USB_DEVREQ_RECIPIENT_INTERFACE 0x01 -#define USB_DEVREQ_RECIPIENT_ENDPOINT 0x02 -#define USB_DEVREQ_RECIPIENT_OTHER 0x03 -#define USB_DEVREQ_RECIPIENT_MASK 0x1F - -// The standard request codes. -#define USB_DEVREQ_GET_STATUS 0 -#define USB_DEVREQ_CLEAR_FEATURE 1 -#define USB_DEVREQ_SET_FEATURE 3 -#define USB_DEVREQ_SET_ADDRESS 5 -#define USB_DEVREQ_GET_DESCRIPTOR 6 -#define USB_DEVREQ_SET_DESCRIPTOR 7 -#define USB_DEVREQ_GET_CONFIGURATION 8 -#define USB_DEVREQ_SET_CONFIGURATION 9 -#define USB_DEVREQ_GET_INTERFACE 10 -#define USB_DEVREQ_SET_INTERFACE 11 -#define USB_DEVREQ_SYNCH_FRAME 12 - -// Descriptor types. These are placed in value_hi for the -// GET_DESCRIPTOR and SET_DESCRIPTOR requests, with an index -// in value_lo. They also go into the type fields of the -// various descriptor structures. -#define USB_DEVREQ_DESCRIPTOR_TYPE_DEVICE 1 -#define USB_DEVREQ_DESCRIPTOR_TYPE_CONFIGURATION 2 -#define USB_DEVREQ_DESCRIPTOR_TYPE_STRING 3 -#define USB_DEVREQ_DESCRIPTOR_TYPE_INTERFACE 4 -#define USB_DEVREQ_DESCRIPTOR_TYPE_ENDPOINT 5 - -// Feature selectors. These go into value_lo for the CLEAR_FEATURE and -// SET_FEATURE requests, and in the first response byte for -// GET_STATUS. -#define USB_DEVREQ_FEATURE_DEVICE_REMOTE_WAKEUP 1 -#define USB_DEVREQ_FEATURE_ENDPOINT_HALT 0 - -// Index decoding. When the CLEAR_FEATURE, SET_FEATURE and GET_STATUS -// requests is applied to an endpoint (as per the recipient field in -// the type field) index_lo identifies the endpoint. -#define USB_DEVREQ_INDEX_DIRECTION_OUT 0 -#define USB_DEVREQ_INDEX_DIRECTION_IN (1 << 7) -#define USB_DEVREQ_INDEX_DIRECTION_MASK (1 << 7) -#define USB_DEVREQ_INDEX_ENDPOINT_MASK 0x0F - -// Descriptors for the GET_DESCRIPTOR and SET_DESCRIPTOR requests. -typedef struct usb_device_descriptor { - unsigned char length; // USB_DEVICE_DESCRIPTOR_LENGTH == 18 - unsigned char type; // USB_DEVREQ_DESCRIPTOR_TYPE - unsigned char usb_spec_lo; - unsigned char usb_spec_hi; - unsigned char device_class; - unsigned char device_subclass; - unsigned char device_protocol; - unsigned char max_packet_size; - unsigned char vendor_lo; - unsigned char vendor_hi; - unsigned char product_lo; - unsigned char product_hi; - unsigned char device_lo; - unsigned char device_hi; - unsigned char manufacturer_str; - unsigned char product_str; - unsigned char serial_number_str; - unsigned char number_configurations; -} usb_device_descriptor __attribute__((packed)); - -#define USB_DEVICE_DESCRIPTOR_LENGTH 18 -#define USB_DEVICE_DESCRIPTOR_TYPE USB_DEVREQ_DESCRIPTOR_TYPE_DEVICE -#define USB_DEVICE_DESCRIPTOR_USB11_LO 0x10 -#define USB_DEVICE_DESCRIPTOR_USB11_HI 0x01 - -#define USB_DEVICE_DESCRIPTOR_CLASS_INTERFACE 0x00 -#define USB_DEVICE_DESCRIPTOR_CLASS_VENDOR 0x00FF -#define USB_DEVICE_DESCRIPTOR_SUBCLASS_INTERFACE 0x00 -#define USB_DEVICE_DESCRIPTOR_SUBCLASS_VENDOR 0x00FF -#define USB_DEVICE_DESCRIPTOR_PROTOCOL_INTERFACE 0x00 -#define USB_DEVICE_DESCRIPTOR_PROTOCOL_VENDOR 0x00FF - -typedef struct usb_configuration_descriptor { - unsigned char length; - unsigned char type; - unsigned char total_length_lo; - unsigned char total_length_hi; - unsigned char number_interfaces; - unsigned char configuration_id; - unsigned char configuration_str; - unsigned char attributes; - unsigned char max_power; -} usb_configuration_descriptor __attribute__((packed)); - -#define USB_CONFIGURATION_DESCRIPTOR_LENGTH 9 -#define USB_CONFIGURATION_DESCRIPTOR_TYPE USB_DEVREQ_DESCRIPTOR_TYPE_CONFIGURATION -#define USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED (1 << 7) -#define USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED (1 << 6) -#define USB_CONFIGURATION_DESCRIPTOR_ATTR_REMOTE_WAKEUP (1 << 5) - -typedef struct usb_interface_descriptor { - unsigned char length; - unsigned char type; - unsigned char interface_id; - unsigned char alternate_setting; - unsigned char number_endpoints; - unsigned char interface_class; - unsigned char interface_subclass; - unsigned char interface_protocol; - unsigned char interface_str; -} usb_interface_descriptor __attribute__((packed)); - -#define USB_INTERFACE_DESCRIPTOR_LENGTH 9 -#define USB_INTERFACE_DESCRIPTOR_TYPE USB_DEVREQ_DESCRIPTOR_TYPE_INTERFACE -#define USB_INTERFACE_DESCRIPTOR_CLASS_VENDOR 0x00FF -#define USB_INTERFACE_DESCRIPTOR_SUBCLASS_VENDOR 0x00FF -#define USB_INTERFACE_DESCRIPTOR_PROTOCOL_VENDOR 0x00FF - -typedef struct usb_endpoint_descriptor { - unsigned char length; - unsigned char type; - unsigned char endpoint; - unsigned char attributes; - unsigned char max_packet_lo; - unsigned char max_packet_hi; - unsigned char interval; -} usb_endpoint_descriptor; - -#define USB_ENDPOINT_DESCRIPTOR_LENGTH 7 -#define USB_ENDPOINT_DESCRIPTOR_TYPE USB_DEVREQ_DESCRIPTOR_TYPE_ENDPOINT -#define USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT 0 -#define USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN (1 << 7) -#define USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL 0x00 -#define USB_ENDPOINT_DESCRIPTOR_ATTR_ISOCHRONOUS 0x01 -#define USB_ENDPOINT_DESCRIPTOR_ATTR_BULK 0x02 -#define USB_ENDPOINT_DESCRIPTOR_ATTR_INTERRUPT 0x03 - -// String descriptors. If these are used at all then string 0 -// must be a table of supported LANGID codes. For a simple device -// which only supports US English, the following sequence of -// four bytes should suffice for string 0. In practice string -// constants tend to be used which makes the use of these -// #define's difficult. -#define USB_STRING_DESCRIPTOR_STRING0_LENGTH 4 -#define USB_STRING_DESCRIPTOR_STRING0_TYPE USB_DEVREQ_DESCRIPTOR_TYPE_STRING -#define USB_STRING_DESCRIPTOR_STRING0_LANGID_LO 0x09 -#define USB_STRING_DESCRIPTOR_STRING0_LANGID_HI 0x04 - -// For subsequent strings the length and data will have to be -// determined by the application developer or by a suitable tool. -#define USB_STRING_DESCRIPTOR_TYPE USB_DEVREQ_DESCRIPTOR_TYPE_STRING - -// Utility macros to calculate the total_length fields in a -// configuration descriptor. -#define USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(interfaces, endpoints) \ - (USB_CONFIGURATION_DESCRIPTOR_LENGTH + \ - (interfaces * USB_INTERFACE_DESCRIPTOR_LENGTH) + \ - (endpoints * USB_ENDPOINT_DESCRIPTOR_LENGTH)) % 256 - -#define USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(interfaces, endpoints) \ - (USB_CONFIGURATION_DESCRIPTOR_LENGTH + \ - (interfaces * USB_INTERFACE_DESCRIPTOR_LENGTH) + \ - (endpoints * USB_ENDPOINT_DESCRIPTOR_LENGTH)) / 256 - -#ifdef __cplusplus -} // extern "C" { -#endif - -#endif // CYGONCE_USB_H - Index: common/v2_0/ChangeLog =================================================================== --- common/v2_0/ChangeLog (revision 174) +++ common/v2_0/ChangeLog (nonexistent) @@ -1,47 +0,0 @@ -2001-01-25 Bart Veer - - * cdl/usb.cdl: - Correctly parent below CYGPKG_IO - -2000-11-22 Bart Veer - - * include/usb.h: Fix nested #include protection. - -2000-11-21 Bart Veer - - * First check-in of eCos USB support. - -//=========================================================================== -//####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#### -//=========================================================================== Index: slave/v2_0/cdl/usbs.cdl =================================================================== --- slave/v2_0/cdl/usbs.cdl (revision 174) +++ slave/v2_0/cdl/usbs.cdl (nonexistent) @@ -1,134 +0,0 @@ -# ==================================================================== -# -# usbs.cdl -# -# USB slave-side support -# -# ==================================================================== -#####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#### -# -# Author(s): bartv -# Original data: bartv -# Contributors: -# Date: 2000-10-04 -# -#####DESCRIPTIONEND#### -# -# ==================================================================== - -cdl_package CYGPKG_IO_USB_SLAVE { - display "USB slave-side support" - parent CYGPKG_IO_USB - include_dir "cyg/io/usb" - active_if CYGHWR_IO_USB_SLAVE - doc ref/io-usb-slave.html - - compile usbs.c - - cdl_interface CYGINT_IO_USB_SLAVE_CLIENTS { - display "Number of clients of USB devices" - description " - This counter keeps track of the number of clients of - USB devices, especially application-class packages such - as the USB-ethernet support. It can be used by USB - device drivers for default settings. - " - } - - cdl_option CYGGLO_IO_USB_SLAVE_APPLICATION { - display "Application code uses USB devices" - default_value 0 - implements CYGINT_IO_USB_SLAVE_CLIENTS - description " - If the USB devices are accessed by application code - rather than by other packages then enabling this - option will cause the USB device drivers to be enabled. - " - } - - cdl_option CYGGLO_IO_USB_SLAVE_PROVIDE_DEVTAB_ENTRIES { - display "Provide devtab entries by default" - default_value CYGPKG_IO - requires CYGPKG_IO - description " - The USB slave-side endpoints can typically be accessed in two - different ways. There is support for the traditional way of - doing I/O with open/read/write calls, which involves the - use of devtab entries. It is also possible to use a - USB-specific API, defined largely in terms of asynchronous - operations and callbacks (the read/write implementation uses - these lower-level calls). If neither the application nor - any other USB-related packages require the higher-level - read/write calls then it is possible to save some memory - by eliminating the devtab entries. - " - } - - cdl_interface CYGHWR_IO_USB_SLAVE_OUT_ENDPOINTS { - display "Number of available host->slave endpoints" - } - cdl_interface CYGHWR_IO_USB_SLAVE_IN_ENDPOINTS { - display "Number of available slave->host endpoints" - } - - cdl_option CYGBLD_IO_USB_SLAVE_USBTEST { - display "Build the main USB test program" - doc ref/usbs-testing.html - description " - The USB slave-side software is supplied with host-side - and target-side software that allows a variety of testing - to be performed. The slave-side software is not built - by default since it can only operate in specific environments - and in conjunction with the host-side software. Enabling - this option causes the slave-side software to be added - to the list of test cases for the current configuration." - default_value 0 - implements CYGINT_IO_USB_SLAVE_CLIENTS - requires { is_substr(CYGPKG_IO_USB_SLAVE_TESTS, " tests/usbtarget") } - - requires CYGFUN_KERNEL_API_C CYGFUN_KERNEL_THREADS_TIMER !CYGINT_KNEREL_SCHEDULER_UNIQUE_PRIORITIES - requires CYGPKG_LIBC_STDIO CYGSEM_LIBC_STDIO_THREAD_SAFE_STREAMS - } - - cdl_option CYGPKG_IO_USB_SLAVE_TESTS { - display "Kernel tests" - flavor data - no_define - default_value { "" } - description "This option specifies the set of tests to be - built for the USB slave package" - } -} Index: slave/v2_0/tests/usbtarget.c =================================================================== --- slave/v2_0/tests/usbtarget.c (revision 174) +++ slave/v2_0/tests/usbtarget.c (nonexistent) @@ -1,1848 +0,0 @@ -/*{{{ 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 -#include -#include -#include -#include -#include -#include -#include -#include "protocol.h" - -/*}}}*/ - -/*{{{ Statics */ - -// ---------------------------------------------------------------------------- -// Statics. - -// The number of endpoints supported by the device driver. -static int number_endpoints = 0; - -// The control endpoint -static 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 void -usbs_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 void -fix_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 void -heartbeat_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 void -start_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 void -lock_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 void -unlock_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_bool -is_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 int -lookup_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; - } - } - 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" : ""); - 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" : "", \ - 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; - } - - 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; - } - } - - // Make sure nobody else is using this endpoint - lock_endpoint(endpoint_number, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT); - - for (i = 0; i < test->test_params.bulk.number_packets; i++) { - int rx_size = test->test_params.bulk.rx_size; - int tx_size = test->test_params.bulk.tx_size; - - VERBOSE(2, "Bulk OUT test %d: iteration %d, rx size %d, tx size %d\n", test->id, i, rx_size, tx_size); - - if (rx_size < tx_size) { - rx_size = tx_size; - VERBOSE(2, "Bulk OUT test %d: iteration %d, packet size reset to %d to match tx size\n", - test->id, i, rx_size); - } - - test->recovery.endpoint = endpoint_number | USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT; - test->recovery.protocol = USB_ENDPOINT_DESCRIPTOR_ATTR_BULK; - test->recovery.size = rx_size; - - // Make sure there is no old data lying around - if (usbtestdata_none != test->test_params.bulk.data.format) { - memset(buf, 0, rx_size); - } - - // Do the actual transfer, using the I/O mechanism specified for this test. - switch (test->test_params.bulk.io_mechanism) - { - case usb_io_mechanism_usb : - { - test->transferred = 0; - usbs_start_rx_buffer(endpoint, buf, rx_size, &run_test_bulk_in_out_callback, (void*) test); - cyg_semaphore_wait(&(test->sem)); - transferred = test->transferred; - break; - } - - case usb_io_mechanism_dev : - { - int result; - transferred = rx_size; - result = cyg_io_read(io_handle, (void*) buf, &transferred); - if (result < 0) { - transferred = result; - } - break; - } - - default: - CYG_FAIL("Invalid test mechanism specified"); - break; - } - - // Has this test been aborted for some reason? - if (current_tests_terminated) { - VERBOSE(2, "Bulk OUT test %d: iteration %d, termination detected\n", test->id, i); - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Target, bulk OUT transfer on endpoint %d: transfer aborted after iteration %d", endpoint_number, i); - break; - } - - // If an error occurred, abort this run - if (transferred < 0) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Target, bulk OUT transfer on endpoint %d: transfer failed with %d", endpoint_number, transferred); - VERBOSE(2, "Bulk OUT test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message); - break; - } - - // Did the host send the expected amount of data? - if (transferred < test->test_params.bulk.tx_size) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Target, bulk OUT transfer on endpoint %d : the host only sent %d bytes when %d were expected", - endpoint_number, transferred, tx_size); - VERBOSE(2, "Bulk OUT test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message); - break; - } - - if (verbose >= 3) { - // Output the first 32 bytes of data - char msg[256]; - int index; - int j; - index = snprintf(msg, 255, "Bulk OUT test %d: iteration %d, transferred %d\n Data %s:", - test->id, i, transferred, - (usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : ""); - - for (j = 0; ((j + 3) < transferred) && (j < 32); j+= 4) { - index += snprintf(msg+index, 255-index, " %02x%02x%02x%02x", - buf[j], buf[j+1], buf[j+2], buf[j+3]); - } - if (j < 32) { - index += snprintf(msg+index, 255-index, " "); - for ( ; j < transferred; j++) { - index += snprintf(msg+index, 255-index, "%02x", buf[j]); - } - - } - VERBOSE(3, "%s\n", msg); - } - - // Is the data correct? - if (!usbtest_check_buffer(&(test->test_params.bulk.data), buf, transferred)) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Target, bulk OUT transfer on endpoint %d : mismatch between received and expected data", endpoint_number); - VERBOSE(2, "Bulk OUt test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message); - break; - } - - if (0 != test->test_params.bulk.rx_delay) { - VERBOSE(2, "Bulk OUT test %d: iteration %d, sleeping for %d nanoseconds\n", test->id, \ - i, test->test_params.bulk.rx_delay); - usbs_nanosleep(test->test_params.bulk.rx_delay); - } - - // Move on to the next transfer - USBTEST_BULK_NEXT(test->test_params.bulk); - } - - // Always unlock the endpoint on completion - unlock_endpoint(endpoint_number, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT); - - // If all the packets have been transferred this test has passed. - if (i >= test->test_params.bulk.number_packets) { - test->result_pass = 1; - } - - VERBOSE(1, "Test %d bulk OUT on endpoint %d, result %d\n", test->id, endpoint_number, test->result_pass); -} - -/*}}}*/ -/*{{{ run_test_bulk_in() */ - -// IN transfers, i.e. the host is expected to receive some data. These are slightly -// easier than OUT transfers because it is the host that will do the checking. -static void -run_test_bulk_in(UsbTest* test) -{ - unsigned char* buf; - int endpoint_number = test->test_params.bulk.endpoint & ~USB_DEVREQ_DIRECTION_MASK; - int ep_index; - usbs_tx_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 IN on endpoint %d\n", test->id, endpoint_number); - - ep_index = lookup_endpoint(endpoint_number, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN, USB_ENDPOINT_DESCRIPTOR_ATTR_BULK); - if (ep_index == -1) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Target, bulk IN transfer on endpoint %d: no such bulk endpoint", endpoint_number); - return; - } - endpoint = (usbs_tx_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 IN transfer on endpoint %d: no devtab entry", endpoint_number); - return; - } - } - - // Make sure nobody else is using this endpoint - lock_endpoint(endpoint_number, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN); - - for (i = 0; i < test->test_params.bulk.number_packets; i++) { - int packet_size = test->test_params.bulk.tx_size; - - test->recovery.endpoint = endpoint_number | USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN; - test->recovery.protocol = USB_ENDPOINT_DESCRIPTOR_ATTR_BULK; - test->recovery.size = packet_size + usbs_testing_endpoints[ep_index].max_in_padding; - - // Make sure the buffer contains the data expected by the host - usbtest_fill_buffer(&(test->test_params.bulk.data), buf, packet_size); - - if (verbose < 3) { - VERBOSE(2, "Bulk OUT test %d: iteration %d, packet size %d\n", test->id, i, packet_size); - } else { - // Output the first 32 bytes of data as well. - char msg[256]; - int index; - int j; - index = snprintf(msg, 255, "Bulk IN test %d: iteration %d, packet size %d\n Data %s:", - test->id, i, packet_size, - (usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : ""); - - for (j = 0; ((j + 3) < packet_size) && (j < 32); j+= 4) { - index += snprintf(msg+index, 255-index, " %02x%02x%02x%02x", - buf[j], buf[j+1], buf[j+2], buf[j+3]); - } - if (j < 32) { - index += snprintf(msg+index, 255-index, " "); - for ( ; j < packet_size; j++) { - index += snprintf(msg+index, 255-index, "%02x", buf[j]); - } - - } - VERBOSE(3, "%s\n", msg); - } - - // Do the actual transfer, using the I/O mechanism specified for this test. - switch (test->test_params.bulk.io_mechanism) - { - case usb_io_mechanism_usb : - { - test->transferred = 0; - usbs_start_tx_buffer(endpoint, buf, packet_size, &run_test_bulk_in_out_callback, (void*) test); - cyg_semaphore_wait(&(test->sem)); - transferred = test->transferred; - break; - } - - case usb_io_mechanism_dev : - { - int result; - transferred = packet_size; - result = cyg_io_write(io_handle, (void*) buf, &transferred); - if (result < 0) { - transferred = result; - } - break; - } - - default: - CYG_FAIL("Invalid test mechanism specified"); - break; - } - - // Has this test been aborted for some reason? - if (current_tests_terminated) { - VERBOSE(2, "Bulk IN test %d: iteration %d, termination detected\n", test->id, i); - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Target, bulk IN transfer on endpoint %d : terminated on iteration %d, packet_size %d\n", - endpoint_number, i, packet_size); - break; - } - - // If an error occurred, abort this run - if (transferred < 0) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Target, bulk IN transfer on endpoint %d: transfer failed with %d", endpoint_number, transferred); - VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message); - break; - } - - // No need to check the transfer size, the USB code is only - // allowed to send the exact amount of data requested. - - if (0 != test->test_params.bulk.tx_delay) { - VERBOSE(2, "Bulk IN test %d: iteration %d, sleeping for %d nanoseconds\n", test->id, i, \ - test->test_params.bulk.tx_delay); - usbs_nanosleep(test->test_params.bulk.tx_delay); - } - - // Move on to the next transfer - USBTEST_BULK_NEXT(test->test_params.bulk); - } - - // Always unlock the endpoint on completion - unlock_endpoint(endpoint_number, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN); - - // If all the packets have been transferred this test has passed. - if (i >= test->test_params.bulk.number_packets) { - test->result_pass = 1; - } - - VERBOSE(1, "Test %d bulk IN on endpoint %d, result %d\n", test->id, endpoint_number, test->result_pass); -} - -/*}}}*/ - -/*}}}*/ -/*{{{ Control IN transfers */ - -// Control-IN transfers. These have to be handled a little bit differently -// from bulk transfers. The target never actually initiates anything. Instead -// the host will send reserved control messages which are handled at DSR -// level and passed to handle_reserved_control_messages() below. Assuming -// a control-IN test is in progress, that will take appropriate action. The -// thread will be woken up only once all packets have been transferred, or -// on abnormal termination. - -// Is a control-IN test currently in progress? -static UsbTest* control_in_test = 0; - -// What is the expected packet size? -static int control_in_test_packet_size = 0; - -// How many packets have been transferred so far? -static int control_in_packets_transferred = 0; - -// Cancel a control-in test. handle_test_control_in() will have updated the static -// control_in_test so that handle_reserved_control_messages() knows what to do. -// If the test is not actually going to be run then system consistency demands -// that this update be undone. Also, the endpoint will have been locked to -// detect concurrent tests on the control endpoint. -static void -cancel_test_control_in(UsbTest* test) -{ - CYG_ASSERTC(test == control_in_test); - control_in_test = (UsbTest*) 0; - control_in_test_packet_size = 0; - control_in_packets_transferred = 0; - unlock_endpoint(0, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN); - test->cancel_fn = (void (*)(UsbTest*)) 0; -} - -// Prepare for a control-IN transfer test. -static usbs_control_return -handle_test_control_in(usb_devreq* req) -{ - UsbTest* test; - int index = 0; - - CYG_ASSERTC((UsbTest*)0 == control_in_test); - - test = pool_allocate(); - unpack_usbtest_control_in(&(test->test_params.control_in), class_request, &index); - - lock_endpoint(0, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN); - test->which_test = usbtest_control_in; - test->recovery.endpoint = 0; - test->recovery.protocol = USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL; - test->recovery.size = 0; // Does not actually matter - test->cancel_fn = &cancel_test_control_in; - - // Assume a pass. Failures are easy to detect. - test->result_pass = 1; - - control_in_test = test; - control_in_test_packet_size = test->test_params.control_in.packet_size_initial; - control_in_packets_transferred = 0; - - return USBS_CONTROL_RETURN_HANDLED; -} - -// The thread for a control-in test. Actually all the hard work is done at DSR -// level, so this thread serves simply to detect when the test has completed -// and to perform some clean-ups. -static void -run_test_control_in(UsbTest* test) -{ - CYG_ASSERTC(test == control_in_test); - - cyg_semaphore_wait(&(test->sem)); - - // The DSR has detected that the test is complete. - control_in_test = (UsbTest*) 0; - control_in_test_packet_size = 0; - control_in_packets_transferred = 0; - test->cancel_fn = (void (*)(UsbTest*)) 0; - unlock_endpoint(0, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN); -} - -// ---------------------------------------------------------------------------- -// This is installed from inside main() as the handler for reserved -// control messages. -static usbs_control_return -handle_reserved_control_messages(usbs_control_endpoint* endpoint, void* data) -{ - usb_devreq* req = (usb_devreq*) endpoint->control_buffer; - usbs_control_return result; - - CYG_ASSERT(endpoint == control_endpoint, "control endpoint mismatch"); - switch(req->request) { - case USBTEST_RESERVED_CONTROL_IN: - { - unsigned char* buf; - int len; - - if ((UsbTest*)0 == control_in_test) { - result = USBS_CONTROL_RETURN_STALL; - break; - } - - // Is this test over? If so indicate a failure because we - // cannot have received all the control packets. - if (current_tests_terminated) { - control_in_test->result_pass = 0; - snprintf(control_in_test->result_message, USBTEST_MAX_MESSAGE, - "Target, control IN transfer: not all packets received."); - cyg_semaphore_post(&(control_in_test->sem)); - control_in_test = (UsbTest*) 0; - result = USBS_CONTROL_RETURN_STALL; - break; - } - - // A control-IN test is indeed in progress, and the current state is - // held in control_in_test and control_in_test_packet_size. Check that - // the packet size matches up, i.e. that host and target are in sync. - len = (req->length_hi << 8) || req->length_lo; - if (control_in_test_packet_size != len) { - control_in_test->result_pass = 0; - snprintf(control_in_test->result_message, USBTEST_MAX_MESSAGE, - "Target, control IN transfer on endpoint %d : the host only requested %d bytes instead of %d", - len, control_in_test_packet_size); - cyg_semaphore_post(&(control_in_test->sem)); - control_in_test = (UsbTest*) 0; - result = USBS_CONTROL_RETURN_STALL; - break; - } - - // Prepare a suitable reply buffer. This is happening at - // DSR level so runtime is important, but with an upper - // bound of 255 bytes the buffer should be small enough. - buf = control_in_test->buffer; - usbtest_fill_buffer(&(control_in_test->test_params.control_in.data), buf, control_in_test_packet_size); - control_endpoint->buffer_size = control_in_test_packet_size; - control_endpoint->buffer = buf; - USBTEST_CONTROL_NEXT_PACKET_SIZE(control_in_test_packet_size, control_in_test->test_params.control_in); - - // Have all the packets been transferred? - control_in_packets_transferred++; - if (control_in_packets_transferred == control_in_test->test_params.control_in.number_packets) { - cyg_semaphore_post(&(control_in_test->sem)); - control_in_test = (UsbTest*) 0; - } - result = USBS_CONTROL_RETURN_HANDLED; - break; - } - default: - CYG_FAIL("Unexpected reserved control message"); - break; - } - - return result; -} - -/*}}}*/ - -// FIXME: add more tests. - -// This utility is invoked from a thread in the thread pool whenever there is -// work to be done. It simply dispatches to the appropriate handler. -static void -run_test(UsbTest* test) -{ - switch(test->which_test) - { - case usbtest_bulk_out : run_test_bulk_out(test); break; - case usbtest_bulk_in : run_test_bulk_in(test); break; - case usbtest_control_in: run_test_control_in(test); break; - default: - CYG_TEST_FAIL_EXIT("Internal error, attempt to run unknown test.\n"); - break; - } -} - -/*}}}*/ -/*{{{ The thread pool */ - -// ---------------------------------------------------------------------------- -// Just like on the host side, it is desirable to have a pool of -// threads available to perform test operations. Strictly speaking -// some tests will run without needing a separate thread, since many -// operations can be performed at DSR level. However typical -// application code will involve threads and it is desirable for test -// code to behave the same way. Also, some operations like validating -// the transferred data are expensive, and best done in thread context. - -typedef struct PoolEntry { - cyg_sem_t wakeup; - cyg_thread thread_data; - cyg_handle_t thread_handle; - char thread_name[16]; - char thread_stack[2 * CYGNUM_HAL_STACK_SIZE_TYPICAL]; - cyg_bool in_use; - cyg_bool running; - UsbTest test; -} PoolEntry; - -// This array must be uninitialized, or the executable size would -// be ludicrous. -PoolEntry pool[USBTEST_MAX_CONCURRENT_TESTS]; - -// The entry point for every thread in the pool. It just loops forever, -// waiting until it is supposed to run a test. -static void -pool_thread_function(cyg_addrword_t arg) -{ - PoolEntry* pool_entry = (PoolEntry*) arg; - - for ( ; ; ) { - cyg_semaphore_wait(&(pool_entry->wakeup)); - run_test(&(pool_entry->test)); - pool_entry->running = 0; - } -} - -// Initialize all threads in the pool. -static void -pool_initialize(void) -{ - int i; - for (i = 0; i < USBTEST_MAX_CONCURRENT_TESTS; i++) { - cyg_semaphore_init(&(pool[i].wakeup), 0); - pool[i].in_use = 0; - pool[i].running = 0; - sprintf(pool[i].thread_name, "worker%d", i); - cyg_thread_create( 0, &pool_thread_function, (cyg_addrword_t) &(pool[i]), - pool[i].thread_name, pool[i].thread_stack, 2 * CYGNUM_HAL_STACK_SIZE_TYPICAL, - &(pool[i].thread_handle), &(pool[i].thread_data)); - cyg_thread_resume(pool[i].thread_handle); - } -} - -// Allocate a single entry in the thread pool -static UsbTest* -pool_allocate(void) -{ - UsbTest* result = (UsbTest*) 0; - - if (thread_counter == USBTEST_MAX_CONCURRENT_TESTS) { - CYG_TEST_FAIL_EXIT("Internal error, thread resources exhaused.\n"); - } - - result = &(pool[thread_counter].test); - thread_counter++; - reset_usbtest(result); - return result; -} - -// Start all the threads that are supposed to be running tests. -static void -pool_start(void) -{ - int i; - for (i = 0; i < thread_counter; i++) { - pool[i].running = 1; - cyg_semaphore_post(&(pool[i].wakeup)); - } -} - -/*}}}*/ -/*{{{ Class control messages */ - -// ---------------------------------------------------------------------------- -// Handle class control messages. These provide the primary form of -// communication between host and target. There are requests to find out -// the number of endpoints, details of each endpoint, prepare a test run, -// abort a test run, get status, terminate the target-side, and so on. -// The handlers for starting specific test cases are kept alongside -// the test cases themselves. -// -// Note that these handlers will typically be invoked from DSR context -// and hence they are subject to the usual DSR restrictions. -// -// Problems have been experienced in some hosts sending control messages -// that involve additional host->target data. An ugly workaround is -// in place whereby any such data is sent in advance using separate -// control messages. - -/*{{{ endpoint count */ - -// How many endpoints are supported by this device? That information is -// determined during initialization. -static usbs_control_return -handle_endpoint_count(usb_devreq* req) -{ - CYG_ASSERTC((1 == req->length_lo) && (0 == req->length_hi) && \ - ((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - - class_reply[0] = (unsigned char) number_endpoints; - control_endpoint->buffer = class_reply; - control_endpoint->buffer_size = 1; - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ endpoint details */ - -// The host wants to know the details of a specific USB endpoint. -// The format is specified in protocol.h -static usbs_control_return -handle_endpoint_details(usb_devreq* req) -{ - int buf_index; - - CYG_ASSERTC((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN); - CYG_ASSERTC((USBTEST_MAX_CONTROL_DATA == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC(req->index_lo < number_endpoints); - CYG_ASSERTC((0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - - class_reply[0] = (unsigned char) usbs_testing_endpoints[req->index_lo].endpoint_type; - class_reply[1] = (unsigned char) usbs_testing_endpoints[req->index_lo].endpoint_number; - class_reply[2] = (unsigned char) usbs_testing_endpoints[req->index_lo].endpoint_direction; - class_reply[3] = (unsigned char) usbs_testing_endpoints[req->index_lo].max_in_padding; - buf_index = 4; - pack_int(usbs_testing_endpoints[req->index_lo].min_size, class_reply, &buf_index); - pack_int(usbs_testing_endpoints[req->index_lo].max_size, class_reply, &buf_index); - if (NULL == usbs_testing_endpoints[req->index_lo].devtab_entry) { - class_reply[buf_index] = '\0'; - control_endpoint->buffer_size = buf_index + 1; - } else { - int len = strlen(usbs_testing_endpoints[req->index_lo].devtab_entry) + buf_index + 1; - if (len > USBTEST_MAX_CONTROL_DATA) { - return USBS_CONTROL_RETURN_STALL; - } else { - strcpy(&(class_reply[buf_index]), usbs_testing_endpoints[req->index_lo].devtab_entry); - control_endpoint->buffer_size = len; - } - } - control_endpoint->buffer = class_reply; - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ sync */ - -// The host wants to know whether or not the target is currently busy doing -// stuff. This information is held in a static. -static usbs_control_return -handle_sync(usb_devreq* req) -{ - CYG_ASSERTC((1 == req->length_lo) && (0 == req->length_hi) && \ - ((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(0 == class_request_size, "A sync operation should not involve any data"); - - class_reply[0] = (unsigned char) idle; - control_endpoint->buffer = class_reply; - control_endpoint->buffer_size = 1; - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ pass/fail */ - -// Allow the host to generate some pass or fail messages, and -// optionally terminate the test. These are synchronous requests -// so the data can be left in class_request. - -static int passfail_request = 0; - -// Invoked from thread context -static void -handle_passfail_action(void) -{ - switch (passfail_request) { - case USBTEST_PASS: - CYG_TEST_PASS(class_request); - break; - case USBTEST_PASS_EXIT: - CYG_TEST_PASS(class_request); - CYG_TEST_EXIT("Exiting normally as requested by the host"); - break; - case USBTEST_FAIL: - CYG_TEST_FAIL(class_request); - break; - case USBTEST_FAIL_EXIT: - CYG_TEST_FAIL(class_request); - CYG_TEST_EXIT("Exiting normally as requested by the host"); - break; - default: - CYG_FAIL("Bogus invocation of usbtest_main_passfail"); - break; - } -} - -// Invoked from DSR context -static usbs_control_return -handle_passfail(usb_devreq* req) -{ - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(class_request_size > 0, "A pass/fail message should be supplied"); - CYG_ASSERT(idle, "Pass/fail messages are only allowed when idle"); - CYG_ASSERT((void (*)(void))0 == main_thread_action, "No thread operation should be pending."); - - passfail_request = req->request; - idle = false; - main_thread_action = &handle_passfail_action; - cyg_semaphore_post(&main_wakeup); - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ abort */ - -// The host has concluded that there is no easy way to get both target and -// host back to a sensible state. For example there may be a thread that -// is blocked waiting for some I/O that is not going to complete. The abort -// should be handled at thread level, not DSR level, so that the host -// still sees the low-level USB handshake. - -static void -handle_abort_action(void) -{ - CYG_TEST_FAIL_EXIT("Test abort requested by host application"); -} - -static usbs_control_return -handle_abort(usb_devreq* req) -{ - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(idle, "Abort messages are only allowed when idle"); - CYG_ASSERT((void (*)(void))0 == main_thread_action, "No thread operation should be pending."); - - idle = false; - main_thread_action = &handle_abort_action; - cyg_semaphore_post(&main_wakeup); - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ cancel */ - -// Invoked from thread context -// Cancelling pending test cases simply involves iterating over the allocated -// entries in the pool, invoking any cancellation functions that have been -// defined, and then resetting the tread count. The actual tests have not -// yet started so none of the threads will be active. -static void -handle_cancel_action(void) -{ - int i; - for (i = 0; i < thread_counter; i++) { - if ((void (*)(UsbTest*))0 != pool[i].test.cancel_fn) { - (*(pool[i].test.cancel_fn))(&(pool[i].test)); - pool[i].test.cancel_fn = (void (*)(UsbTest*)) 0; - } - } - thread_counter = 0; -} - -// Invoked from DSR context -static usbs_control_return -handle_cancel(usb_devreq* req) -{ - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(0 == class_request_size, "A cancel operation should not involve any data"); - CYG_ASSERT(idle, "Cancel requests are only allowed when idle"); - CYG_ASSERT(!running, "Cancel requests cannot be sent once the system is running"); - CYG_ASSERT((void (*)(void))0 == main_thread_action, "No thread operation should be pending."); - - idle = false; - main_thread_action = &handle_cancel_action; - cyg_semaphore_post(&main_wakeup); - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ start */ - -// Start the tests running. This just involves waking up the pool threads -// and setting the running flag, with the latter serving primarily for -// assertions. - -static usbs_control_return -handle_start(usb_devreq* req) -{ - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(0 == class_request_size, "A start operation should not involve any data"); - CYG_ASSERT(!running, "Start requests cannot be sent if the system is already running"); - - current_tests_terminated = false; - running = true; - pool_start(); - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ finished */ - -// Have all the tests finished? This involves checking all the threads -// involved in the current batch of tests and seeing whether or not -// their running flag is still set. - -static usbs_control_return -handle_finished(usb_devreq* req) -{ - int i; - int result = 1; - - CYG_ASSERTC((1 == req->length_lo) && (0 == req->length_hi) && \ - ((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(0 == class_request_size, "A finished operation should not involve any data"); - CYG_ASSERT(running, "Finished requests can only be sent if the system is already running"); - - for (i = 0; i < thread_counter; i++) { - if (pool[i].running) { - result = 0; - break; - } - } - class_reply[0] = (unsigned char) result; - control_endpoint->buffer = class_reply; - control_endpoint->buffer_size = 1; - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ set terminated */ - -// A timeout has occurred, or there is some other failure. The first step -// in recovery is to set the terminated flag so that as recovery action -// takes place and the threads wake up they make no attempt to continue -// doing more transfers. - -static usbs_control_return -handle_set_terminated(usb_devreq* req) -{ - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(0 == class_request_size, "A set-terminated operation should not involve any data"); - CYG_ASSERT(running, "The terminated flag can only be set when there are running tests"); - - current_tests_terminated = 1; - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ get recovery */ - -// Return the recovery information for one of the threads involved in the -// current batch of tests, so that the host can perform a USB operation -// that will sort out that thread. -static usbs_control_return -handle_get_recovery(usb_devreq* req) -{ - int buffer_index; - - CYG_ASSERT(current_tests_terminated, "Recovery should only be attempted when the terminated flag is set"); - CYG_ASSERT(running, "If there are no tests running then recovery is impossible"); - CYG_ASSERTC((12 == req->length_lo) && (0 == req->length_hi) && \ - ((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN)); - CYG_ASSERTC(req->index_lo <= thread_counter); - CYG_ASSERTC((0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(0 == class_request_size, "A get-recovery operation should not involve any data"); - - control_endpoint->buffer = class_reply; - if (!pool[req->index_lo].running) { - // Actually, this particular thread has terminated so no recovery is needed. - control_endpoint->buffer_size = 0; - } else { - buffer_index = 0; - pack_usbtest_recovery(&(pool[req->index_lo].test.recovery), class_reply, &buffer_index); - control_endpoint->buffer_size = buffer_index; - } - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ perform recovery */ - -// The host has identified a course of action that could unlock a thread -// on the host-side that is currently blocked performing a USB operation. -// Typically this involves either sending or accepting some data. If the -// endpoint is still locked, in other words if there is a still a local -// thread attempting to communicate on the specified endpoint, then -// things are messed up: both sides are trying to communicate, but nothing -// is happening. The eCos USB API is such that attempting multiple -// concurrent operations on a single endpoint is disallowed, so -// the recovery request has to be ignored. If things do not sort themselves -// out then the whole test run will have to be aborted. - -// A dummy completion function for when a recovery operation has completed. -static void -recovery_callback(void* callback_arg, int transferred) -{ - CYG_UNUSED_PARAM(void*, callback_arg); - CYG_UNUSED_PARAM(int, transferred); -} - -static usbs_control_return -handle_perform_recovery(usb_devreq* req) -{ - int buffer_index; - int endpoint_number; - int endpoint_direction; - UsbTest_Recovery recovery; - - CYG_ASSERT(current_tests_terminated, "Recovery should only be attempted when the terminated flag is set"); - CYG_ASSERT(running, "If there are no tests running then recovery is impossible"); - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(12 == class_request_size, "A perform-recovery operation requires recovery data"); - - buffer_index = 0; - unpack_usbtest_recovery(&recovery, class_request, &buffer_index); - endpoint_number = recovery.endpoint & ~USB_DEVREQ_DIRECTION_MASK; - endpoint_direction = recovery.endpoint & USB_DEVREQ_DIRECTION_MASK; - - if (!is_endpoint_locked(endpoint_number, endpoint_direction)) { - // Locking the endpoint here would be good, but the endpoint would then - // have to be unlocked again - probably in the recovery callback. - // This complication is ignored for now. - - if (USB_ENDPOINT_DESCRIPTOR_ATTR_BULK == recovery.protocol) { - int ep_index = lookup_endpoint(endpoint_number, endpoint_direction, USB_ENDPOINT_DESCRIPTOR_ATTR_BULK); - CYG_ASSERTC(-1 != ep_index); - - if (USB_DEVREQ_DIRECTION_IN == endpoint_direction) { - // The host wants some data. Supply it. A single byte will do fine to - // complete the transfer. - usbs_start_tx_buffer((usbs_tx_endpoint*) usbs_testing_endpoints[ep_index].endpoint, - recovery_buffer, 1, &recovery_callback, (void*) 0); - } else { - // The host is trying to send some data. Accept all of it. - usbs_start_rx_buffer((usbs_rx_endpoint*) usbs_testing_endpoints[ep_index].endpoint, - recovery_buffer, recovery.size, &recovery_callback, (void*) 0); - } - } - - // No support for isochronous or interrupt transfers yet. - // handle_reserved_control_messages() should generate stalls which - // have the desired effect. - } - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ get result */ - -// Return the result of one the tests. This can be a single byte for -// a pass, or a single byte plus a message for a failure. - -static usbs_control_return -handle_get_result(usb_devreq* req) -{ - CYG_ASSERTC((USBTEST_MAX_CONTROL_DATA == req->length_lo) && (0 == req->length_hi) && \ - ((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN)); - CYG_ASSERTC(req->index_lo <= thread_counter); - CYG_ASSERTC((0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(0 == class_request_size, "A get-result operation should not involve any data"); - CYG_ASSERT(running, "Results can only be sent if a run is in progress"); - CYG_ASSERT(!pool[req->index_lo].running, "Cannot request results for a test that has not completed"); - - class_reply[0] = pool[req->index_lo].test.result_pass; - if (class_reply[0]) { - control_endpoint->buffer_size = 1; - } else { - strncpy(&(class_reply[1]), pool[req->index_lo].test.result_message, USBTEST_MAX_CONTROL_DATA - 2); - class_reply[USBTEST_MAX_CONTROL_DATA - 1] = '\0'; - control_endpoint->buffer_size = 1 + strlen(&(class_reply[1])) + 1; - } - control_endpoint->buffer = class_reply; - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ batch done */ - -// A batch of test has been completed - at least, the host thinks so. -// If the host is correct then all that is required here is to reset -// the thread pool and clear the global running flag - that is sufficient -// to allow a new batch of tests to be started. - -static usbs_control_return -handle_batch_done(usb_devreq* req) -{ - int i; - - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi)); - CYG_ASSERT(0 == class_request_size, "A batch-done operation should not involve any data"); - CYG_ASSERT(running, "There must be a current batch of tests"); - - for (i = 0; i < thread_counter; i++) { - CYG_ASSERTC(!pool[i].running); - } - thread_counter = 0; - running = false; - - return USBS_CONTROL_RETURN_HANDLED; - -} - -/*}}}*/ -/*{{{ verbosity */ - -static usbs_control_return -handle_verbose(usb_devreq* req) -{ - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi)); - CYG_ASSERT(0 == class_request_size, "A set-verbosity operation should not involve any data"); - - verbose = (req->value_hi << 8) + req->value_lo; - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ initialise bulk out endpoint */ - -// ---------------------------------------------------------------------------- -// Accept an initial endpoint on a bulk endpoint. This avoids problems -// on some hardware such as the SA11x0 which can start to accept data -// before the software is ready for it. - -static void handle_init_callback(void* arg, int result) -{ - idle = true; -} - -static usbs_control_return -handle_init_bulk_out(usb_devreq* req) -{ - static char buf[64]; - int ep_index; - usbs_rx_endpoint* endpoint; - - CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi)); - CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi)); - CYG_ASSERTC((0 == req->value_hi) && (0 < req->value_lo) && (req->value_lo < 16)); - CYG_ASSERT(0 == class_request_size, "An init_bulk_out operation should not involve any data"); - - ep_index = lookup_endpoint(req->value_lo, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT, USB_ENDPOINT_DESCRIPTOR_ATTR_BULK); - CYG_ASSERTC(-1 != ep_index); - endpoint = (usbs_rx_endpoint*) usbs_testing_endpoints[ep_index].endpoint; - - idle = false; - usbs_start_rx_buffer(endpoint, buf, 64, &handle_init_callback, (void*) 0); - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ -/*{{{ additional control data */ - -// Accumulate some more data in the control buffer, ahead of an upcoming -// request. -static usbs_control_return -handle_control_data(usb_devreq* req) -{ - class_request[class_request_size + 0] = req->value_hi; - class_request[class_request_size + 1] = req->value_lo; - class_request[class_request_size + 2] = req->index_hi; - class_request[class_request_size + 3] = req->index_lo; - - switch(req->request) { - case USBTEST_CONTROL_DATA1 : class_request_size += 1; break; - case USBTEST_CONTROL_DATA2 : class_request_size += 2; break; - case USBTEST_CONTROL_DATA3 : class_request_size += 3; break; - case USBTEST_CONTROL_DATA4 : class_request_size += 4; break; - } - - return USBS_CONTROL_RETURN_HANDLED; -} - -/*}}}*/ - -typedef struct class_handler { - int request; - usbs_control_return (*handler)(usb_devreq*); -} class_handler; -static class_handler class_handlers[] = { - { USBTEST_ENDPOINT_COUNT, &handle_endpoint_count }, - { USBTEST_ENDPOINT_DETAILS, &handle_endpoint_details }, - { USBTEST_PASS, &handle_passfail }, - { USBTEST_PASS_EXIT, &handle_passfail }, - { USBTEST_FAIL, &handle_passfail }, - { USBTEST_FAIL_EXIT, &handle_passfail }, - { USBTEST_SYNCH, &handle_sync }, - { USBTEST_ABORT, &handle_abort }, - { USBTEST_CANCEL, &handle_cancel }, - { USBTEST_START, &handle_start }, - { USBTEST_FINISHED, &handle_finished }, - { USBTEST_SET_TERMINATED, &handle_set_terminated }, - { USBTEST_GET_RECOVERY, &handle_get_recovery }, - { USBTEST_PERFORM_RECOVERY, &handle_perform_recovery }, - { USBTEST_GET_RESULT, &handle_get_result }, - { USBTEST_BATCH_DONE, &handle_batch_done }, - { USBTEST_VERBOSE, &handle_verbose }, - { USBTEST_INIT_BULK_OUT, &handle_init_bulk_out }, - { USBTEST_TEST_BULK, &handle_test_bulk }, - { USBTEST_TEST_CONTROL_IN, &handle_test_control_in }, - { USBTEST_CONTROL_DATA1, &handle_control_data }, - { USBTEST_CONTROL_DATA2, &handle_control_data }, - { USBTEST_CONTROL_DATA3, &handle_control_data }, - { USBTEST_CONTROL_DATA4, &handle_control_data }, - { -1, (usbs_control_return (*)(usb_devreq*)) 0 } -}; - -static usbs_control_return -handle_class_control_messages(usbs_control_endpoint* endpoint, void* data) -{ - usb_devreq* req = (usb_devreq*) endpoint->control_buffer; - int request = req->request; - usbs_control_return result; - int i; - - VERBOSE(3, "Received control message %02x\n", request); - - CYG_ASSERT(endpoint == control_endpoint, "control endpoint mismatch"); - result = USBS_CONTROL_RETURN_UNKNOWN; - for (i = 0; (usbs_control_return (*)(usb_devreq*))0 != class_handlers[i].handler; i++) { - if (request == class_handlers[i].request) { - result = (*(class_handlers[i].handler))(req); - if ((USBTEST_CONTROL_DATA1 != request) && - (USBTEST_CONTROL_DATA2 != request) && - (USBTEST_CONTROL_DATA3 != request) && - (USBTEST_CONTROL_DATA4 != request)) { - // Reset the request data buffer after all normal requests. - class_request_size = 0; - } - break; - } - } - CYG_UNUSED_PARAM(void*, data); - if (USBS_CONTROL_RETURN_HANDLED != result) { - VERBOSE(1, "Control message %02x not handled\n", request); - } - - return result; -} - -/*}}}*/ -/*{{{ main() */ - -// ---------------------------------------------------------------------------- -// Initialization. -int -main(int argc, char** argv) -{ - int i; - - CYG_TEST_INIT(); - - // The USB device driver should have provided an array of endpoint - // descriptors, usbs_testing_endpoints(). One entry in this array - // should be a control endpoint, which is needed for initialization. - // It is also useful to know how many endpoints there are. - for (i = 0; !USBS_TESTING_ENDPOINTS_IS_TERMINATOR(usbs_testing_endpoints[i]); i++) { - if ((0 == usbs_testing_endpoints[i].endpoint_number) && - (USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL== usbs_testing_endpoints[i].endpoint_type)) { - CYG_ASSERT((usbs_control_endpoint*)0 == control_endpoint, "There should be only one control endpoint"); - control_endpoint = (usbs_control_endpoint*) usbs_testing_endpoints[i].endpoint; - } - } - if ((usbs_control_endpoint*)0 == control_endpoint) { - CYG_TEST_FAIL_EXIT("Unable to find a USB control endpoint"); - } - number_endpoints = i; - CYG_ASSERT(number_endpoints <= USBTEST_MAX_ENDPOINTS, "impossible number of endpoints"); - - // Some of the information provided may not match the actual capabilities - // of the testing code, e.g. max_size limits. - fix_driver_endpoint_data(); - - // This semaphore is used for communication between the DSRs that process control - // messages and the main thread - cyg_semaphore_init(&main_wakeup, 0); - - // Take care of the pool of threads and related data. - pool_initialize(); - - // Start the heartbeat thread, to make sure that the gdb session stays - // alive. - start_heartbeat(); - - // Now it is possible to start up the USB device driver. The host can detect - // this, connect, get the enumeration data, and then testing will proceed - // in response to class control messages. - provide_endpoint_enumeration_data(); - control_endpoint->enumeration_data = &usb_enum_data; - control_endpoint->class_control_fn = &handle_class_control_messages; - control_endpoint->reserved_control_fn = &handle_reserved_control_messages; - usbs_start(control_endpoint); - - // Now it is over to the host to detect this target and start performing tests. - // Much of this is handled at DSR level, in response to USB control messages. - // Some of those control messages require action at thread level, and that is - // achieved by signalling a semaphore and waking up this thread. A static - // function pointer is used to keep track of what operation is actually required. - for (;;) { - void (*handler)(void); - - cyg_semaphore_wait(&main_wakeup); - handler = main_thread_action; - main_thread_action = 0; - CYG_CHECK_FUNC_PTR(handler, "Main thread woken up when there is nothing to be done"); - (*handler)(); - idle = true; - } -} - -/*}}}*/ Index: slave/v2_0/tests/protocol.h =================================================================== --- slave/v2_0/tests/protocol.h (revision 174) +++ slave/v2_0/tests/protocol.h (nonexistent) @@ -1,194 +0,0 @@ -//================================================================= -// -// protocol.h -// -// USB testing - host<->target protocol -// -//========================================================================== -//####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 header file is shared between target and host, and serves to -// define certain aspects of the protocol used between the two such -// as request codes. -// -// Author(s): bartv -// Date: 2001-07-04 -//####DESCRIPTIONEND#### -//========================================================================== - -// The largest control packet that will be sent or expected. -#define USBTEST_MAX_CONTROL_DATA 255 - -// The largest error message that can be sent. -#define USBTEST_MAX_MESSAGE 254 - -// The largest bulk transfer that will be sent or expected. Because of -// the use of the USB devfs support in the Linux kernel this is -// currently limited to a single page, i.e. 4096 bytes. To allow for -// padding, it is actually reduced to a slightly smaller size of 4090 -// bytes. This should still be sufficient to test most interesting -// boundary conditions, apart from the transition to >64K. -// -// A small amount of additional buffer space should be allocated by -// both host and target to allow for padding and possibly cache -// alignment. All other protocols involve smaller transfers than this, -// <= 64 bytes for interrupt transfers, <= 1023 for isochronous. -#define USBTEST_MAX_BULK_DATA (4096) -#define USBTEST_MAX_BULK_DATA_EXTRA 1024 - -// The maximum number of tests that can be run concurrently. Each -// needs a separate thread, stack, and buffer so there are memory -// consumption implications. -#define USBTEST_MAX_CONCURRENT_TESTS 8 - -// Allow the host to find out the number of endpoints supported on -// this target. The theoretical maximum number of endpoints is 91 -// (endpoint 0 control, endpoint 1-15 for both IN and OUT bulk, iso -// and interrupt) so a single byte response will suffice. The value -// and index fields are not used. -#define USBTEST_MAX_ENDPOINTS 91 -#define USBTEST_ENDPOINT_COUNT 0x001 - -// Get hold of additional information about a specific entry in the -// array of endpoint details. The index field in the request -// identifies the entry of interest. The reply information is as per -// the usbs_testing_endpoint structure, and consists of: -// 1) one byte, the endpoint type (control, bulk, ...) -// 2) one byte, the endpoint number (as opposed to the array index number) -// 3) one byte for direction, USB_DIR_IN or USB_DIR_OUT -// 4) one byte for max_in_padding, usually 0 -// 5) four bytes for min_size, 32-bit little-endian integer -// 6) four bytes for max_size, 32-bit little-endian integer -// 7) an additional n bytes for the devtab name, max ~240 bytes -// although usually far less. -#define USBTEST_ENDPOINT_DETAILS 0x002 - -// Report pass or failure. The host will send a string of up to -// MAX_CONTROL_DATA bytes. The value and index fields are not used. -#define USBTEST_PASS 0x003 -#define USBTEST_PASS_EXIT 0x004 -#define USBTEST_FAIL 0x005 -#define USBTEST_FAIL_EXIT 0x006 - -// Synchronise. One problem with the current eCos USB API is that -// there is no way to have a delayed response to a control message. -// Any such support would be tricky, there are significant differences -// in the hardware implementations and also timing constraints that -// need to be satisfied. Instead the entire response to any control -// request has to be prepared at DSR level. Usually this does not -// cause any problems, e.g. for handling the standard control -// messages, but for USB testing it may not be possible to handle a -// request entirely at DSR level - yet the next full request should -// not come in until the current one has been handled at thread-level. -// To work around this there is support for a synchronization control -// message. The return value is a single byte, 1 if the target is -// ready for new requests, 0 if there is a still a request being -// processed. The host can then perform some polling. -#define USBTEST_SYNCH 0x007 - -// Abort. There is no easy way to get both host and target back to a -// known state, so abort the current test run. -#define USBTEST_ABORT 0x008 - -// Cancel the current batch of tests. Something has gone wrong at the -// Tcl level, so any tests already prepared must be abandoned. No -// additional data is required. -#define USBTEST_CANCEL 0x009 - -// Start the current batch of tests. No additional data is involved -// or expected. -#define USBTEST_START 0x00A - -// Has the current batch of tests finished? The host side polls the -// target at regular intervals for this information. -#define USBTEST_FINISHED 0x00B - -// Set the test-terminated flag. Something has gone wrong, probably a -// timeout. -#define USBTEST_SET_TERMINATED 0x00C - -// Get hold of recovery information for thread i in the target, where -// the index field of the request identifies the thread. The result -// is zero-bytes if the specified test has already finished, otherwise -// a recovery structure. -#define USBTEST_GET_RECOVERY 0x00D - -// The target should perform a recovery action to unlock a thread -// on the host. The request holds a recovery structure. -#define USBTEST_PERFORM_RECOVERY 0x00E - -// Collect the test result. The result is a single byte that indicates -// pass or fail, optionally followed by a failure message. -#define USBTEST_GET_RESULT 0x00F - -// The current batch of tests has completed. Perform any final clean-ups. -#define USBTEST_BATCH_DONE 0x010 - -// Set the verbosity level on the target-side -#define USBTEST_VERBOSE 0x011 - -// Perform endpoint initialization to ensure host and target -// can actually communicate over a given endpoint -#define USBTEST_INIT_CONTROL 0x012 -#define USBTEST_INIT_BULK_IN 0x013 -#define USBTEST_INIT_BULK_OUT 0x014 -#define USBTEST_INIT_ISO_IN 0x015 -#define USBTEST_INIT_ISO_OUT 0x016 -#define USBTEST_INIT_INTERRUPT_IN 0x017 -#define USBTEST_INIT_INTERRUPT_OUT 0x018 - - -// A standard bulk test. The data consists of a UsbTest_Bulk -// structure, suitably packed. -#define USBTEST_TEST_BULK 0x040 - -// A control-IN test. The host will send reserved control messages with -// an appropriate length field, and the target should return that data. -#define USBTEST_TEST_CONTROL_IN 0x041 - -// Sub-protocols for reserved control messages, supporting test operations -// other than control-IN. -#define USBTEST_RESERVED_CONTROL_IN 0x01 - -// Work around a problem with control messages that involve additional -// data from host to target. This problem is not yet well-understood. -// The workaround involves sending multiple control packets with -// up to four bytes encoded in the index and value fields. -#define USBTEST_CONTROL_DATA1 0x0F1 -#define USBTEST_CONTROL_DATA2 0x0F2 -#define USBTEST_CONTROL_DATA3 0x0F3 -#define USBTEST_CONTROL_DATA4 0x0F4 - Index: slave/v2_0/tests/common.c =================================================================== --- slave/v2_0/tests/common.c (revision 174) +++ slave/v2_0/tests/common.c (nonexistent) @@ -1,681 +0,0 @@ -/*{{{ Banner */ - -/*================================================================= -// -// common.c -// -// USB testing - code common to host and target -// -//========================================================================== -//####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 module contains some definitions and functions that are common to -// both the host and target side of USB testing, for example filling in -// a buffer with well-known data and validating the contents at the other end. -// The module is #include'd by other code rather than compiled separately, -// which simplifies the build process. -// -// Author(s): bartv -// Date: 2001-08-14 -//####DESCRIPTIONEND#### -//========================================================================== -*/ - -/*}}}*/ - -/*{{{ Simple data pack and unpack operations */ - -// ---------------------------------------------------------------------------- -// Utilities to pack and unpack data into buffers. -// -// Integers are transferred with 32 bits of precision, irrespective -// of the capabilities of either target and host. - -static inline void -pack_int(int datum, unsigned char* buffer, int* index_ptr) -{ - int index = *index_ptr; - buffer[index++] = (datum >> 0) & 0x0FF; - buffer[index++] = (datum >> 8) & 0x0FF; - buffer[index++] = (datum >> 16) & 0x0FF; - buffer[index++] = (datum >> 24) & 0x0FF; - *index_ptr = index; -} - -static inline int -unpack_int(unsigned char* buffer, int* index_ptr) -{ - int index = *index_ptr; - int result; - - result = (buffer[index++] << 0); - result |= (buffer[index++] << 8); - result |= (buffer[index++] << 16); - result |= (buffer[index++] << 24); - *index_ptr = index; - return result; -} - -/*}}}*/ -/*{{{ Buffer data and validation */ - -// ---------------------------------------------------------------------------- -// The data required for a given test. For some test cases, for -// example when trying to achieve maximum throughput, it does not -// matter what data is transferred. For other tests it is important to -// validate that the data sent and received match up, and there should -// be some control over the actual data: some tests might want to send -// a long sequence of byte 0, while others want to send more random data -// for which a simple random number generator is useful. -// -// Exactly the same routines are used on both host and target to fill in -// and check buffers, and they are sufficiently simple that the routines -// should get compiled in compatible ways. -// -// There is no support at present for sending specific data, e.g. a -// specific ethernet packet that appears to be causing problems. Knowledge -// of specific data cannot be compiled into the test code, so the only -// way to implement something like this would be to transfer the -// problematical data over the USB bus in order to determine whether or -// not the bus is capable of reliably transferring this data. That is -// not entirely impossible (checksums, use of alternative endpoints), -// but it is not implemented. -// -// An alternative approach would be to support a bounce operation -// involving both an IN and an OUT endpoint, doing validation only on -// the host. Again that is not yet implemented. -// -// The byte_fill and int_fill options are actually redundant because the -// same effect can be achieved using a multiplier of 1 and an increment -// of 0, but they can be implemented much more efficiently so may be -// useful for benchmarks. - -typedef enum usbtestdata { - usbtestdata_none = 0, // There is nothing useful in the data - usbtestdata_bytefill = 1, // The data consists of a single byte, repeated - usbtestdata_wordfill = 2, // Or a single integer - usbtestdata_byteseq = 3, // Or a pseudo-random sequence (a * seed) + b - usbtestdata_wordseq = 4 // as either bytes or integers -} usbtestdata; - -typedef struct UsbTestData { - usbtestdata format; - int seed; - int multiplier; // 1103515245 - int increment; // 12345 - int transfer_seed_multiplier; - int transfer_seed_increment; - int transfer_multiplier_multiplier; - int transfer_multiplier_increment; - int transfer_increment_multiplier; - int transfer_increment_increment; -} UsbTestData; - -static void -usbtest_fill_buffer(UsbTestData* how, unsigned char* buffer, int length) -{ - switch(how->format) - { - case usbtestdata_none: - return; - - case usbtestdata_bytefill: - // Leave it to the system to optimise memset(). - memset(buffer, (how->seed & 0x0FF), length); - break; - - case usbtestdata_wordfill: - { - // The buffer may not be a multiple of four bytes, so the last entry is always - // zero'd. - int i; - int index = 0; - for (i = 0; i < (length / 4); i++) { - pack_int(how->seed, buffer, &index); - } - pack_int(0, buffer, &index); - break; - } - - case usbtestdata_byteseq: - { - int i; - for (i = 0; i < length; i++) { - buffer[i] = (how->seed & 0x00FF); - how->seed *= how->multiplier; - how->seed += how->increment; - } - break; - } - - case usbtestdata_wordseq: - { - int i; - int index = 0; - for (i = 0; i < (length / 4); i++) { - pack_int(how->seed, buffer, &index); - how->seed *= how->multiplier; - how->seed += how->increment; - } - pack_int(0, buffer, &index); - break; - } - } - - // After each transfer update the seed, multiplier and increment - // ready for the next one. - how->seed *= how->transfer_seed_multiplier; - how->seed += how->transfer_seed_increment; - how->multiplier *= how->transfer_multiplier_multiplier; - how->multiplier += how->transfer_multiplier_increment; - how->increment *= how->transfer_increment_multiplier; - how->increment += how->transfer_increment_increment; -} - -static int -usbtest_check_buffer(UsbTestData* how, unsigned char* buffer, int length) -{ - int result = 1; - - switch(how->format) { - case usbtestdata_none: - break; - - case usbtestdata_bytefill: - { - int i; - result = 1; - for (i = 0; i < length; i++) { - if (buffer[i] != (how->seed & 0x00FF)) { - result = 0; - break; - } - } - break; - } - - case usbtestdata_wordfill: - { - int i; - int index = 0; - for (i = 0; i < (length / 4); i++) { - int datum = unpack_int(buffer, &index); - if (datum != (how->seed & 0x0FFFFFFFF)) { - result = 0; - break; - } - } - for (i = 4 * i; result && (i < length); i++) { - if (0 != buffer[i]) { - result = 0; - break; - } - } - break; - } - - case usbtestdata_byteseq: - { - int i; - for (i = 0; i < length; i++) { - if (buffer[i] != (how->seed & 0x00FF)) { - result = 0; - break; - } - how->seed *= how->multiplier; - how->seed += how->increment; - } - break; - } - - case usbtestdata_wordseq: - { - int i; - int index = 0; - - for (i = 0; i < (length / 4); i++) { - int datum = unpack_int(buffer, &index); - if (datum != (how->seed & 0x0FFFFFFFF)) { - result = 0; - break; - } - how->seed *= how->multiplier; - how->seed += how->increment; - } - for (i = 4 * i; result && (i < length); i++) { - if (0 != buffer[i]) { - result = 0; - break; - } - } - break; - } - } - - // After each transfer update the seed, multiplier and increment - // ready for the next transfer. - how->seed *= how->transfer_seed_multiplier; - how->seed += how->transfer_seed_increment; - how->multiplier *= how->transfer_multiplier_multiplier; - how->multiplier += how->transfer_multiplier_increment; - how->increment *= how->transfer_increment_multiplier; - how->increment += how->transfer_increment_increment; - - return result; -} - -#ifdef HOST -static void -pack_usbtestdata(UsbTestData* data, unsigned char* buf, int* index) -{ - pack_int((int)data->format, buf, index); - pack_int((int)data->seed, buf, index); - pack_int((int)data->multiplier, buf, index); - pack_int((int)data->increment, buf, index); - pack_int((int)data->transfer_seed_multiplier, buf, index); - pack_int((int)data->transfer_seed_increment, buf, index); - pack_int((int)data->transfer_multiplier_multiplier, buf, index); - pack_int((int)data->transfer_multiplier_increment, buf, index); - pack_int((int)data->transfer_increment_multiplier, buf, index); - pack_int((int)data->transfer_increment_increment, buf, index); -} -#endif - -#ifdef TARGET -static void -unpack_usbtestdata(UsbTestData* data, unsigned char* buf, int* index) -{ - data->format = (usbtestdata) unpack_int(buf, index); - data->seed = unpack_int(buf, index); - data->multiplier = unpack_int(buf, index); - data->increment = unpack_int(buf, index); - data->transfer_seed_multiplier = unpack_int(buf, index); - data->transfer_seed_increment = unpack_int(buf, index); - data->transfer_multiplier_multiplier= unpack_int(buf, index); - data->transfer_multiplier_increment = unpack_int(buf, index); - data->transfer_increment_multiplier = unpack_int(buf, index); - data->transfer_increment_increment = unpack_int(buf, index); -} -#endif - -/*}}}*/ -/*{{{ Testcase definitions */ - -// ---------------------------------------------------------------------------- -// Definitions of the supported test cases. The actual implementations need -// to vary between host and target. - -typedef enum usbtest { - usbtest_invalid = 0, - usbtest_bulk_out = 1, - usbtest_bulk_in = 2, - usbtest_control_in = 3 -} usbtest; - -// What I/O mechanism should be used on the target to process data? -typedef enum usb_io_mechanism { - usb_io_mechanism_usb = 1, // The low-level USB-specific API - usb_io_mechanism_dev = 2 // cyg_devio_cread() et al -} usb_io_mechanism; - -// Bulk transfers. The same structure can be used for IN and OUT transfers. -// The endpoint number will be or'd with either USB_DIR_IN or USB_DIR_OUT, -// or the equivalent under eCos. -typedef struct UsbTest_Bulk { - int number_packets; - int endpoint; - int tx_size; - int tx_size_min; - int tx_size_max; - int tx_size_multiplier; - int tx_size_divisor; - int tx_size_increment; - int rx_size; - int rx_size_min; - int rx_size_max; - int rx_size_multiplier; - int rx_size_divisor; - int rx_size_increment; - int rx_padding; - int tx_delay; - int tx_delay_min; - int tx_delay_max; - int tx_delay_multiplier; - int tx_delay_divisor; - int tx_delay_increment; - int rx_delay; - int rx_delay_min; - int rx_delay_max; - int rx_delay_multiplier; - int rx_delay_divisor; - int rx_delay_increment; - usb_io_mechanism io_mechanism; - UsbTestData data; -} UsbTest_Bulk; - -#ifdef HOST -static void -pack_usbtest_bulk(UsbTest_Bulk* test, unsigned char* buffer, int* index) -{ - pack_int(test->number_packets, buffer, index); - pack_int(test->endpoint, buffer, index); - pack_int(test->tx_size, buffer, index); - pack_int(test->tx_size_min, buffer, index); - pack_int(test->tx_size_max, buffer, index); - pack_int(test->tx_size_multiplier, buffer, index); - pack_int(test->tx_size_divisor, buffer, index); - pack_int(test->tx_size_increment, buffer, index); - pack_int(test->rx_size, buffer, index); - pack_int(test->rx_size_min, buffer, index); - pack_int(test->rx_size_max, buffer, index); - pack_int(test->rx_size_multiplier, buffer, index); - pack_int(test->rx_size_divisor, buffer, index); - pack_int(test->rx_size_increment, buffer, index); - // There is no need to transfer the padding field. It is only of - // interest on the host, and this message is being packed - // for the target side. - pack_int(test->tx_delay, buffer, index); - pack_int(test->tx_delay_min, buffer, index); - pack_int(test->tx_delay_max, buffer, index); - pack_int(test->tx_delay_multiplier, buffer, index); - pack_int(test->tx_delay_divisor, buffer, index); - pack_int(test->tx_delay_increment, buffer, index); - pack_int(test->rx_delay, buffer, index); - pack_int(test->rx_delay_min, buffer, index); - pack_int(test->rx_delay_max, buffer, index); - pack_int(test->rx_delay_multiplier, buffer, index); - pack_int(test->rx_delay_divisor, buffer, index); - pack_int(test->rx_delay_increment, buffer, index); - pack_int((int)test->io_mechanism, buffer, index); - pack_usbtestdata(&(test->data), buffer, index); -} -#endif - -#ifdef TARGET -static void -unpack_usbtest_bulk(UsbTest_Bulk* test, unsigned char* buffer, int* index) -{ - test->number_packets = unpack_int(buffer, index); - test->endpoint = unpack_int(buffer, index); - test->tx_size = unpack_int(buffer, index); - test->tx_size_min = unpack_int(buffer, index); - test->tx_size_max = unpack_int(buffer, index); - test->tx_size_multiplier = unpack_int(buffer, index); - test->tx_size_divisor = unpack_int(buffer, index); - test->tx_size_increment = unpack_int(buffer, index); - test->rx_size = unpack_int(buffer, index); - test->rx_size_min = unpack_int(buffer, index); - test->rx_size_max = unpack_int(buffer, index); - test->rx_size_multiplier = unpack_int(buffer, index); - test->rx_size_divisor = unpack_int(buffer, index); - test->rx_size_increment = unpack_int(buffer, index); - test->tx_delay = unpack_int(buffer, index); - test->tx_delay_min = unpack_int(buffer, index); - test->tx_delay_max = unpack_int(buffer, index); - test->tx_delay_multiplier = unpack_int(buffer, index); - test->tx_delay_divisor = unpack_int(buffer, index); - test->tx_delay_increment = unpack_int(buffer, index); - test->rx_delay = unpack_int(buffer, index); - test->rx_delay_min = unpack_int(buffer, index); - test->rx_delay_max = unpack_int(buffer, index); - test->rx_delay_multiplier = unpack_int(buffer, index); - test->rx_delay_divisor = unpack_int(buffer, index); - test->rx_delay_increment = unpack_int(buffer, index); - test->io_mechanism = (usb_io_mechanism) unpack_int(buffer, index); - unpack_usbtestdata(&(test->data), buffer, index); -} -#endif - -// A macro for moving on the next packet size. This also has to be shared between host -// and target, if the two got out of synch then testing would go horribly wrong. -// -// The new packet size is determined using a multiplier and increment, -// so to e.g. increase packet sizes by 4 bytes each time the -// multiplier would be 1 and the increment would be 4, or to double -// packet sizes the multiplier would be 2 and the increment would be -// 0. On underflow or overflow the code tries to adjust the packet size -// back to within the accepted range. - -#define USBTEST_NEXT_TX_SIZE(_x_) \ - do { \ - _x_.tx_size *= _x_.tx_size_multiplier; \ - _x_.tx_size /= _x_.tx_size_divisor; \ - _x_.tx_size += _x_.tx_size_increment; \ - if (_x_.tx_size < _x_.tx_size_min) { \ - if (_x_.tx_size_min == _x_.tx_size_max) { \ - _x_.tx_size = _x_.tx_size_min; \ - } else { \ - int tmp = _x_.tx_size_min - _x_.tx_size; \ - tmp %= _x_.tx_size_max - _x_.tx_size_min; \ - _x_.tx_size = tmp + _x_.tx_size_min; \ - } \ - } else if (_x_.tx_size > _x_.tx_size_max) { \ - if (_x_.tx_size_min == _x_.tx_size_max) { \ - _x_.tx_size = _x_.tx_size_max; \ - } else { \ - int tmp = _x_.tx_size - _x_.tx_size_max; \ - tmp %= _x_.tx_size_max - _x_.tx_size_min; \ - _x_.tx_size = tmp + _x_.tx_size_min; \ - } \ - } \ - } while ( 0 ) - -// A similar macro for moving on to the next receive size. This is less -// critical since care is taken to always receive at least the current -// tx size plus padding. -// Note that padding needs to be added by the calling code, not here, -// since padding is only applicable on the host-side and this macro -// is used on both host and target. -#define USBTEST_NEXT_RX_SIZE(_x_) \ - do { \ - _x_.rx_size *= _x_.rx_size_multiplier; \ - _x_.rx_size /= _x_.rx_size_divisor; \ - _x_.rx_size += _x_.rx_size_increment; \ - if (_x_.rx_size < _x_.rx_size_min) { \ - if (_x_.rx_size_min == _x_.rx_size_max) { \ - _x_.rx_size = _x_.rx_size_min; \ - } else { \ - int tmp = _x_.rx_size_min - _x_.rx_size; \ - tmp %= _x_.rx_size_max - _x_.rx_size_min; \ - _x_.rx_size = tmp + _x_.rx_size_min; \ - } \ - } else if (_x_.rx_size > _x_.rx_size_max) { \ - if (_x_.rx_size_min == _x_.rx_size_max) { \ - _x_.rx_size = _x_.rx_size_max; \ - } else { \ - int tmp = _x_.rx_size - _x_.rx_size_max; \ - tmp %= _x_.rx_size_max - _x_.rx_size_min; \ - _x_.rx_size = tmp + _x_.rx_size_min; \ - } \ - } \ - } while ( 0 ) - -// And a macro for adjusting the transmit delay. -#define USBTEST_NEXT_TX_DELAY(_x_) \ - do { \ - _x_.tx_delay *= _x_.tx_delay_multiplier; \ - _x_.tx_delay /= _x_.tx_delay_divisor; \ - _x_.tx_delay += _x_.tx_delay_increment; \ - if (_x_.tx_delay < _x_.tx_delay_min) { \ - if (_x_.tx_delay_min == _x_.tx_delay_max) { \ - _x_.tx_delay = _x_.tx_delay_min; \ - } else { \ - int tmp = _x_.tx_delay_min - _x_.tx_delay; \ - tmp %= _x_.tx_delay_max - _x_.tx_delay_min; \ - _x_.tx_delay = tmp + _x_.tx_delay_min; \ - } \ - } else if (_x_.tx_delay > _x_.tx_delay_max) { \ - if (_x_.tx_delay_min == _x_.tx_delay_max) { \ - _x_.tx_delay = _x_.tx_delay_max; \ - } else { \ - int tmp = _x_.tx_delay - _x_.tx_delay_max; \ - tmp %= _x_.tx_delay_max - _x_.tx_delay_min; \ - _x_.tx_delay = tmp + _x_.tx_delay_min; \ - } \ - } \ - } while ( 0 ) - -#define USBTEST_NEXT_RX_DELAY(_x_) \ - do { \ - _x_.rx_delay *= _x_.rx_delay_multiplier; \ - _x_.rx_delay /= _x_.rx_delay_divisor; \ - _x_.rx_delay += _x_.rx_delay_increment; \ - if (_x_.rx_delay < _x_.rx_delay_min) { \ - if (_x_.rx_delay_min == _x_.rx_delay_max) { \ - _x_.rx_delay = _x_.rx_delay_min; \ - } else { \ - int tmp = _x_.rx_delay_min - _x_.rx_delay; \ - tmp %= _x_.rx_delay_max - _x_.rx_delay_min; \ - _x_.rx_delay = tmp + _x_.rx_delay_min; \ - } \ - } else if (_x_.rx_delay > _x_.rx_delay_max) { \ - if (_x_.rx_delay_min == _x_.rx_delay_max) { \ - _x_.rx_delay = _x_.rx_delay_max; \ - } else { \ - int tmp = _x_.rx_delay - _x_.rx_delay_max; \ - tmp %= _x_.rx_delay_max - _x_.rx_delay_min; \ - _x_.rx_delay = tmp + _x_.rx_delay_min; \ - } \ - } \ - } while ( 0 ) - -#define USBTEST_BULK_NEXT(_bulk_) \ - USBTEST_NEXT_TX_SIZE(_bulk_); \ - USBTEST_NEXT_RX_SIZE(_bulk_); \ - USBTEST_NEXT_TX_DELAY(_bulk_); \ - USBTEST_NEXT_RX_DELAY(_bulk_); - -// Control transfers, receives -typedef struct UsbTest_ControlIn { - int number_packets; - int packet_size_initial; - int packet_size_min; - int packet_size_max; - int packet_size_multiplier; - int packet_size_increment; - UsbTestData data; -} UsbTest_ControlIn; - -#ifdef HOST -static void -pack_usbtest_control_in(UsbTest_ControlIn* test, unsigned char* buffer, int* index) -{ - pack_int(test->number_packets, buffer, index); - pack_int(test->packet_size_initial, buffer, index); - pack_int(test->packet_size_min, buffer, index); - pack_int(test->packet_size_max, buffer, index); - pack_int(test->packet_size_multiplier, buffer, index); - pack_int(test->packet_size_increment, buffer, index); - pack_usbtestdata(&(test->data), buffer, index); -} -#endif - -#ifdef TARGET -static void -unpack_usbtest_control_in(UsbTest_ControlIn* test, unsigned char* buffer, int* index) -{ - test->number_packets = unpack_int(buffer, index); - test->packet_size_initial = unpack_int(buffer, index); - test->packet_size_min = unpack_int(buffer, index); - test->packet_size_max = unpack_int(buffer, index); - test->packet_size_multiplier = unpack_int(buffer, index); - test->packet_size_increment = unpack_int(buffer, index); - unpack_usbtestdata(&(test->data), buffer, index); -} -#endif - -// For now control packet sizes are adjusted in exactly the same way as bulk transfers. -#define USBTEST_CONTROL_NEXT_PACKET_SIZE(_packet_size_, _control_) \ - _packet_size_ = (_packet_size_ * _control_.packet_size_multiplier) + _control_.packet_size_increment; \ - if (_packet_size_ < _control_.packet_size_min) { \ - _packet_size_ += _control_.packet_size_max - _control_.packet_size_min; \ - if (_packet_size_ < _control_.packet_size_min) { \ - _packet_size_ = _control_.packet_size_initial; \ - } \ - } else if (_packet_size_ > _control_.packet_size_max) { \ - _packet_size_ -= _control_.packet_size_max - _control_.packet_size_min; \ - if (_packet_size_ > _control_.packet_size_max) { \ - _packet_size_ = _control_.packet_size_initial; \ - } \ - } - -/*}}}*/ -/*{{{ Recovery support */ - -// ---------------------------------------------------------------------------- -// When things go wrong threads on either the host or the target may get -// locked up waiting for further communication that never happens, because -// the other side has already raised an error. Recovery is possible by -// performing an extra I/O operation. For example, if a thread on the -// target is blocked waiting on an OUT endpoint then recovery is possible -// by the host sending some data to that endpoint. Similarly if a thread -// on the host is blocked then recovery involves the target either sending -// or receiving some additional data. There are alternative approaches such -// as stalling endpoints, but making sure that the requested communication -// actually happens involves fewer dependencies on exactly how those -// operations behave. - -typedef struct UsbTest_Recovery { - int endpoint; // Top bit indicates direction, -1 indicates invalid - int protocol; - int size; -} UsbTest_Recovery; - -static void -pack_usbtest_recovery(UsbTest_Recovery* recovery, unsigned char* buffer, int* index) -{ - pack_int(recovery->endpoint, buffer, index); - pack_int(recovery->protocol, buffer, index); - pack_int(recovery->size, buffer, index); -} - -static void -unpack_usbtest_recovery(UsbTest_Recovery* recovery, unsigned char* buffer, int *index) -{ - recovery->endpoint = unpack_int(buffer, index); - recovery->protocol = unpack_int(buffer, index); - recovery->size = unpack_int(buffer, index); -} - -static void -usbtest_recovery_reset(UsbTest_Recovery* recovery) -{ - recovery->endpoint = -1; - recovery->protocol = 0; - recovery->size = 0; -} - -/*}}}*/ Index: slave/v2_0/include/usbs.h =================================================================== --- slave/v2_0/include/usbs.h (revision 174) +++ slave/v2_0/include/usbs.h (nonexistent) @@ -1,426 +0,0 @@ -#ifndef CYGONCE_USBS_H -# define CYGONCE_USBS_H -//========================================================================== -// -// include/usbs.h -// -// The generic USB slave-side support -// -//========================================================================== -//####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#### -// -// Author(s): bartv -// Contributors: bartv -// Date: 2000-10-04 -// Purpose: -// Description: USB slave-side support -// -// -//####DESCRIPTIONEND#### -//========================================================================== - -# include -# include -# include - -#ifdef __cplusplus -extern "C" { -#endif - -// The USB slave-side eCos support involves a number of different -// components: -// -// 1) a hardware-specific package to drive a specific chip implementation. -// This provides access to the endpoints. All the hardware-specific -// packages implement a common interface. -// -// 2) a common package (this one). This defines the interface implemented -// by the hardware-specific packages. It also provides support for -// the various generic control messages, using information provided -// by higher-level code and invoking callbacks as appropriate. -// -// 3) some number of support packages for particular types of -// application, for example ethernet or mass-storage. -// -// Typically there will only be one USB slave device, although the design -// does allow for multiple devices. Each device should provide a -// usbs_control_endpoint structure and zero or more usbs_data_endpoint -// structures. Each usbs_data_endpoint structure supports uni-directional -// transfers on a single endpoint. If an endpoint can support multiple -// types of transfer then there will be some control operation to switch -// between bulk, interrupt and isochronous. -// -// Access to the USB endpoints can go either via usbs_ calls which -// take a usbs_endpoint structure, or via open/read/write calls. The -// latter is more likely to be used in application code since it -// involves a familiar interface. The former is more appropriate for -// eCos packages layered on top of the USB code. The difference is -// synchronous vs. asynchronous: the open/read/write model involves -// blocking operations, implying a need for extra threads; the usbs_ -// calls involve start operations and a completion callback. In -// practice the read and write calls are implemented using the -// lower-level code. - -// Enumeration data. This requires information about the hardware, -// specifically what endpoints are available and what they get used -// for. It also requires information about the application class -// packages that are in the configuration, and quite possibly about -// things in application space. Some of the enumeration info such as -// the vendor id is inherently application-specific. Hence there is no -// way of generating part or all of the the enumeration information -// automatically, instead it is up to application code to supply this. -// -// The intention is that application provides all the data via const -// static objects, allowing the data to live in ROM. Alternatively the -// data structures can go into the .data section as normal, allowing -// them to be edited at run-time. -// -// There can be only one device descriptor, so that is part of the -// main enumeration data structure. There can be an unknown number of -// configurations so application code has to initialize an array of -// these. Ditto for interfaces and endpoints. The first x interfaces -// in the array correspond to the first configuration, the next y -// interfaces to the second configuration, etc. The endpoints array -// works in the same way. -// -// In the initial implementation multiple languages are not supported -// so a simple array of strings suffices. The first entry of these -// is still special in that it should define a single supported -// LANGID. All strings should be encoded as per the USB standard: -// a length field, a type code of USB_STRING_DESCRIPTOR_TYPE, -// and data in unicode format. In future multiple language support -// may be supported via configury with the default case remaining -// a single language, thus avoiding incompatibility problems. - -typedef struct usbs_enumeration_data { - usb_device_descriptor device; - int total_number_interfaces; - int total_number_endpoints; - int total_number_strings; - const usb_configuration_descriptor* configurations; - const usb_interface_descriptor* interfaces; - const usb_endpoint_descriptor* endpoints; - const unsigned char** strings; -} usbs_enumeration_data; - -// The current state of a USB device. This involves a bit to mark -// whether or not the device has been suspended, plus a state machine. -// On some hardware it may not be possible to distinguish between the -// detached, attached and powered states. If so then the initial state -// will be POWERED. - -#define USBS_STATE_DETACHED 0x01 -#define USBS_STATE_ATTACHED 0x02 -#define USBS_STATE_POWERED 0x03 -#define USBS_STATE_DEFAULT 0x04 -#define USBS_STATE_ADDRESSED 0x05 -#define USBS_STATE_CONFIGURED 0x06 -#define USBS_STATE_MASK 0x7F -#define USBS_STATE_SUSPENDED (1 << 7) - -// State changes. Application code or higher-level packages should -// install an appropriate state change function which will get -// invoked with details of the state change. -typedef enum { - USBS_STATE_CHANGE_DETACHED = 1, - USBS_STATE_CHANGE_ATTACHED = 2, - USBS_STATE_CHANGE_POWERED = 3, - USBS_STATE_CHANGE_RESET = 4, - USBS_STATE_CHANGE_ADDRESSED = 5, - USBS_STATE_CHANGE_CONFIGURED = 6, - USBS_STATE_CHANGE_DECONFIGURED = 7, - USBS_STATE_CHANGE_SUSPENDED = 8, - USBS_STATE_CHANGE_RESUMED = 9 -} usbs_state_change; - -typedef enum { - USBS_CONTROL_RETURN_HANDLED = 0, - USBS_CONTROL_RETURN_UNKNOWN = 1, - USBS_CONTROL_RETURN_STALL = 2 -} usbs_control_return; - -typedef struct usbs_control_endpoint { - // The state is maintained by the USB code and should not be - // modified by anything higher up. - int state; - - // The enumeration data should be supplied by higher level code, - // usually the application. Often this data will be constant. - const usbs_enumeration_data* enumeration_data; - - // This function pointer is supplied by the USB device driver. - // Application code should invoke it directly or via the - // usbs_start() function when the system is ready. Typically it - // will cause the USB lines to switch from tristate to active, - // and the USB host/hub should detect this. - void (*start_fn)(struct usbs_control_endpoint*); - - // This function is used for polled operation when interrupts - // are disabled. This can happen in some debugging contexts. - // Higher-level code may also need to know about the interrupt - // number(s) used. - void (*poll_fn)(struct usbs_control_endpoint*); - int interrupt_vector; - - // When a new control message arrives it will be in this buffer - // where the appropriate callback functions can examine it. The - // USB code will not modify the buffer unless a new control - // message arrives. The control_buffer can also be re-used - // by handlers to maintain some state information, e.g. - // for coping with complicated IN requests, but this is only - // allowed if they actually handle the request. - unsigned char control_buffer[8]; - - // This callback will be invoked by the USB code following a - // change in USB state, e.g. to SUSPENDED mode. Higher-level code - // should install a suitable function. There is some callback data - // as well. This gets passed explicitly to the callback function, - // in addition to the control endpoint structure. The reason is - // that the actual state change callback may be some sort of - // multiplexer inside a multifunction peripheral, and this - // multiplexer wants to invoke device-specific state change - // functions. However in simple devices those device-specific - // state change functions could be invoked directly. - void (*state_change_fn)(struct usbs_control_endpoint*, void*, usbs_state_change, int /* old state */); - void* state_change_data; - // When a standard control message arrives, the device driver will - // detect some requests such as SET_ADDRESS and handle it - // internally. Otherwise if higher-level code has installed a - // callback then that will be invoked. If the callback returns - // UNKNOWN then the default handler usbs_handle_standard_control() - // is used to process the request. - usbs_control_return (*standard_control_fn)(struct usbs_control_endpoint*, void*); - void* standard_control_data; - - // These three callbacks are used for other types of control - // messages. The generic USB code has no way of knowing what - // such control messages are about. - usbs_control_return (*class_control_fn)(struct usbs_control_endpoint*, void*); - void* class_control_data; - usbs_control_return (*vendor_control_fn)(struct usbs_control_endpoint*, void*); - void* vendor_control_data; - usbs_control_return (*reserved_control_fn)(struct usbs_control_endpoint*, void*); - void* reserved_control_data; - - // If a control operation involves transferring more data than - // just the initial eight-byte packet, the following fields are - // used to keep track of the current operation. The original - // control request indicates the direction of the transfer (IN or - // OUT) and a length field. For OUT this length is exact, for IN - // it is an upper bound. The transfer operates mostly as per the - // bulk protocol, but if the length requested is an exact multiple - // of the control fifo size (typically eight bytes) then there - // is no need for an empty packet at the end. - // - // For an OUT operation the control message handler should supply - // a suitable buffer via the "buffer" field below. The only other - // field of interest is the complete_fn which must be provided and - // will be invoked once all the data has arrived. Alternatively - // the OUT operation may get aborted if a new control message - // arrives. The second argument is an error code -EPIPE or -EIO, - // or zero to indicate success. The return code is used by the - // device driver during the status phase. - // - // IN is more complicated and the defined interface makes it - // possible to gather data from multiple locations, eliminating - // the need for copying into large buffers in some circumstances. - // Basically when an IN request arrives the device driver will - // look at the buffer and buffer_size fields, extracting data from - // there if possible. If the current buffer has been exhausted - // then the the refill function will be invoked, and this can - // reset the buffer and size fields to point somewhere else. - // This continues until such time that there is no longer - // a refill function and the current buffer is empty. The - // refill function can use the refill_data and refill_index - // to keep track of the current state. The control_buffer - // fields are available as well. At the end of the transfer, - // if a completion function has been supplied then it will - // be invoked. The return code will be ignored. - unsigned char* buffer; - int buffer_size; - void (*fill_buffer_fn)(struct usbs_control_endpoint*); - void* fill_data; - int fill_index; - usbs_control_return (*complete_fn)(struct usbs_control_endpoint*, int); -} usbs_control_endpoint; - -// Data endpoints are a little bit simpler, but not much. From the -// perspective of a device driver things a single buffer is most -// convenient, but that is quite likely to require a max-size buffer -// at a higher level and an additional copy operation. Supplying -// a vector of buffers is a bit more general, but in a layered -// system it may be desirable to prepend to this vector... -// A combination of a current buffer and a refill/empty function -// offers flexibility, at the cost of additional function calls -// from inside the device driver. -// -// FIXME: implement support for fill/empty functions. -// -// Some USB devices may prefer buffers of particular alignment, -// e.g. for DMA purposes. This is hard to reconcile with the -// current interface. However pushing such alignment restrictions -// etc. up into the higher levels is difficult, e.g. it does -// not map at all onto a conventional read/write interface. -// The device driver will just have to do the best it can. -// -// The completion function will be invoked at the end of the transfer. -// The second argument indicates per-transfer completion data. The -// third argument indicates the total amount received, or an error -// code: typically -EPIPE to indicate a broken conenction; -EAGAIN to -// indicate a stall condition; -EMSGSIZE if the host is sending more -// data than the target is expecting; or -EIO to indicate some other -// error. Individual device drivers should avoid generating other -// errors. -typedef struct usbs_rx_endpoint { - void (*start_rx_fn)(struct usbs_rx_endpoint*); - void (*set_halted_fn)(struct usbs_rx_endpoint*, cyg_bool); - void (*complete_fn)(void*, int); - void* complete_data; - unsigned char* buffer; - int buffer_size; - cyg_bool halted; -} usbs_rx_endpoint; - -typedef struct usbs_tx_endpoint { - void (*start_tx_fn)(struct usbs_tx_endpoint*); - void (*set_halted_fn)(struct usbs_tx_endpoint*, cyg_bool); - void (*complete_fn)(void*, int); - void* complete_data; - const unsigned char*buffer; - int buffer_size; - cyg_bool halted; -} usbs_tx_endpoint; - -// Functions called by device drivers. -extern usbs_control_return usbs_handle_standard_control(struct usbs_control_endpoint*); - -// Utility functions. These just invoke the corresponding function -// pointers in the endpoint structures. It is assumed that the -// necessary fields in the endpoint structures will have been -// filled in already. -extern void usbs_start(usbs_control_endpoint*); -extern void usbs_start_rx(usbs_rx_endpoint*); -extern void usbs_start_tx(usbs_tx_endpoint*); -extern void usbs_start_rx_buffer(usbs_rx_endpoint*, unsigned char*, int, void (*)(void*, int), void*); -extern void usbs_start_tx_buffer(usbs_tx_endpoint*, const unsigned char*, int, void (*)(void*, int), void*); -extern cyg_bool usbs_rx_endpoint_halted(usbs_rx_endpoint*); -extern cyg_bool usbs_tx_endpoint_halted(usbs_tx_endpoint*); -extern void usbs_set_rx_endpoint_halted(usbs_rx_endpoint*, cyg_bool); -extern void usbs_set_tx_endpoint_halted(usbs_tx_endpoint*, cyg_bool); -extern void usbs_start_rx_endpoint_wait(usbs_rx_endpoint*, void (*)(void*, int), void*); -extern void usbs_start_tx_endpoint_wait(usbs_tx_endpoint*, void (*)(void*, int), void*); - -// Functions that can go into devtab entries. These should not be -// called directly, they are intended only for use by USB device -// drivers. -#if defined(CYGPKG_IO) && defined(CYGPKG_ERROR) -#include -extern Cyg_ErrNo usbs_devtab_cwrite(cyg_io_handle_t, const void*, cyg_uint32*); -extern Cyg_ErrNo usbs_devtab_cread(cyg_io_handle_t, void*, cyg_uint32*); -extern Cyg_ErrNo usbs_devtab_get_config(cyg_io_handle_t, cyg_uint32, void*, cyg_uint32*); -extern Cyg_ErrNo usbs_devtab_set_config(cyg_io_handle_t, cyg_uint32, const void*, cyg_uint32*); -#endif - -// Additional support for testing. -// Test cases need to have some way of finding out about what support is -// actually provided by the USB device driver, for example what endpoints -// are available. There is no perfect way of achieving this. One approach -// would be to scan through the devtab table looking for devices of the -// form /dev/usbs1r. That is not reliable: the devtab entries may have been -// configured out if higher-level code uses the usb-specific API; or the -// devtab entries may have been renamed. Also having a devtab entry does not -// really give the kind of information a general-purpose testcase needs, -// for example upper bounds on transfer size. -// -// An alternative approach is to have a data structure that somehow -// defines the USB hardware, and the USB device driver then creates an -// instance of this. This is the approach actually taken. The problem -// now is how the test code can access this instance. Accessing by -// unique name is simple, as long as there is only one USB device in -// the system (which of course will usually be the case on the USB -// slave side). Alternative approaches such as creating a table at -// link time or a list during static construction time are vulnerable -// either to selective linking or to having these structures present -// in applications other than the test cases. In future it might be -// possible to address the latter issue by extending the build system -// support, e.g. a new library libtesting.a and a new object file -// testing.o. -// -// Note that a given endpoint could be used for bulk transfers some -// of the time, then for isochronous transfers, etc. It is the -// responsibility of the host to only perform one type of IN operation -// for a given endpoint number, and ditto for OUT. - -typedef struct usbs_testing_endpoint { - int endpoint_type; // One of ATTR_CONTROL, ATTR_BULK, ... - int endpoint_number; // Between 0 and 15 - int endpoint_direction; // ENDPOINT_IN or ENDPOINT_OUT - void* endpoint; // pointer to the usbs_control_endpoint, usbs_rx_endpoint, ... - const char* devtab_entry; // e.g. "/dev/usbs1r", or 0 if inaccessible via devtab - int min_size; // Minimum transfer size - int max_size; // -1 indicates no specific upper bound - int max_in_padding; // extra bytes that the target may send, usually 0. - // Primarily for SA11x0 hardware. It is assumed - // for now that no other hardware will exhibit - // comparable problems. - int alignment; // Buffer should be aligned to a suitable boundary -} usbs_testing_endpoint; - -// A specific instance provided by the device driver. The end of -// the table is indicated by a NULL endpoint field. -extern usbs_testing_endpoint usbs_testing_endpoints[]; - -#define USBS_TESTING_ENDPOINTS_TERMINATOR \ - { \ - endpoint_type : USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL, \ - endpoint_number : 0, \ - endpoint_direction : USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN, \ - endpoint : (void*) 0, \ - devtab_entry : (const char*) 0, \ - min_size : 0, \ - max_size : 0, \ - max_in_padding : 0, \ - alignment : 0 \ - } - -#define USBS_TESTING_ENDPOINTS_IS_TERMINATOR(_endpoint_) ((void*)0 == (_endpoint_).endpoint) - -#ifdef __cplusplus -} // extern "C" { -#endif - -#endif // CYGONCE_USBS_H - Index: slave/v2_0/doc/usbs-writing.html =================================================================== --- slave/v2_0/doc/usbs-writing.html (revision 174) +++ slave/v2_0/doc/usbs-writing.html (nonexistent) @@ -1,937 +0,0 @@ - - - - - - - - - - - -Writing a USB Device Driver -
eCos USB Slave Support
PrevNext

Writing a USB Device Driver

Name

Writing a USB Device Driver -- USB Device Driver Porting Guide

Introduction

Often the best way to write a USB device driver will be to start with -an existing one and modify it as necessary. The information given here -is intended primarily as an outline rather than as a complete guide.

Note: At the time of writing only one USB device driver has been -implemented. Hence it is possible, perhaps probable, that some -portability issues have not yet been addressed. One issue -involves the different types of transfer, for example the initial -target hardware had no support for isochronous or interrupt transfers, -so additional functionality may be needed to switch between transfer -types. Another issue would be hardware where a given endpoint number, -say endpoint 1, could be used for either receiving or transmitting -data, but not both because a single fifo is used. Issues like these -will have to be resolved as and when additional USB device drivers are -written.

The Control Endpoint

A USB device driver should provide a single usbs_control_endpoint -data structure for every USB device. Typical peripherals will have -only one USB port so there will be just one such data structure in the -entire system, but theoretically it is possible to have multiple USB -devices. These may all involve the same chip, in which case a single -device driver should support multiple device instances, or they may -involve different chips. The name or names of these data structures -are determined by the device driver, but appropriate care should be -taken to avoid name clashes.

A USB device cannot be used unless the control endpoint data structure -exists. However, the presence of USB hardware in the target processor -or board does not guarantee that the application will necessarily want -to use that hardware. To avoid unwanted code or data overheads, the -device driver can provide a configuration option to determine whether -or not the endpoint 0 data structure is actually provided. A default -value of CYGINT_IO_USB_SLAVE_CLIENTS ensures that -the USB driver will be enabled automatically if higher-level code does -require USB support, while leaving ultimate control to the user.

The USB device driver is responsible for filling in the -start_fn, -poll_fn and -interrupt_vector fields. Usually this can -be achieved by static initialization. The driver is also largely -responsible for maintaining the state -field. The control_buffer array should be -used to hold the first packet of a control message. The -buffer and other fields related to data -transfers will be managed jointly by higher-level code and -the device driver. The remaining fields are generally filled in by -higher-level code, although the driver should initialize them to NULL -values.

Hardware permitting, the USB device should be inactive until the -start_fn is invoked, for example by -tristating the appropriate pins. This prevents the host from -interacting with the peripheral before all other parts of the system -have initialized. It is expected that the -start_fn will only be invoked once, shortly -after power-up.

Where possible the device driver should detect state changes, such as -when the connection between host and peripheral is established, and -report these to higher-level -code via the state_change_fn callback, if -any. The state change to and from configured state cannot easily be -handled by the device driver itself, instead higher-level code such as -the common USB slave package will take care of this.

Once the connection between host and peripheral has been established, -the peripheral must be ready to accept control messages at all times, -and must respond to these within certain time constraints. For -example, the standard set-address control message must be handled -within 50ms. The USB specification provides more information on these -constraints. The device driver is responsible for receiving the -initial packet of a control message. This packet will always be eight -bytes and should be stored in the -control_buffer field. Certain standard -control messages should be detected and handled by the device driver -itself. The most important is set-address, but usually the get-status, -set-feature and clear-feature requests when applied to halted -endpoints should also be handled by the driver. Other standard control -messages should first be passed on to the -standard_control_fn callback (if any), and -finally to the default handler -usbs_handle_standard_control provided by the -common USB slave package. Class, vendor and reserved control messages -should always be dispatched to the appropriate callback and there is -no default handler for these.

Some control messages will involve further data transfer, not just the -initial packet. The device driver must handle this in accordance with -the USB specification and the buffer management strategy. The -driver is also responsible for keeping track of whether or not the -control operation has succeeded and generating an ACK or STALL -handshake.

The polling support is optional and may not be feasible on all -hardware. It is only used in certain specialised environments such as -RedBoot. A typical implementation of the polling function would just -check whether or not an interrupt would have occurred and, if so, call -the same code that the interrupt handler would.

Data Endpoints

In addition to the control endpoint data structure, a USB device -driver should also provide appropriate data -endpoint data structures. Obviously this is only relevant if -the USB support generally is desired, that is if the control endpoint is -provided. In addition, higher-level code may not require all the -endpoints, so it may be useful to provide configuration options that -control the presence of each endpoint. For example, the intended -application might only involve a single transmit endpoint and of -course control messages, so supporting receive endpoints might waste -memory.

Conceptually, data endpoints are much simpler than the control -endpoint. The device driver has to supply two functions, one for -data transfers and another to control the halted condition. These -implement the functionality for -usbs_start_rx_buffer, -usbs_start_tx_buffer, -usbs_set_rx_endpoint_halted and -usbs_set_tx_endpoint_halted. -The device driver is also responsible for maintaining the -halted status.

For data transfers, higher-level code will have filled in the -buffer, -buffer_size, -complete_fn and -complete_data fields. The transfer function -should arrange for the transfer to start, allowing the host to send or -receive packets. Typically this will result in an interrupt at the end -of the transfer or after each packet. Once the entire transfer has -been completed, the driver's interrupt handling code should invoke the -completion function. This can happen either in DSR context or thread -context, depending on the driver's implementation. There are a number -of special cases to consider. If the endpoint is halted when the -transfer is started then the completion function can be invoked -immediately with -EAGAIN. If the transfer cannot be -completed because the connection is broken then the completion -function should be invoked with -EPIPE. If the -endpoint is stalled during the transfer, either because of a standard -control message or because higher-level code calls the appropriate -set_halted_fn, then again the completion -function should be invoked with -EAGAIN. Finally, -the <usbs_start_rx_endpoint_wait and -usbs_start_tx_endpoint_wait functions involve -calling the device driver's data transfer function with a buffer size -of 0 bytes.

Note: Giving a buffer size of 0 bytes a special meaning is problematical -because it prevents transfers of that size. Such transfers are allowed -by the USB protocol, consisting of just headers and acknowledgements -and an empty data phase, although rarely useful. A future modification -of the device driver specification will address this issue, although -care has to be taken that the functionality remains accessible through -devtab entries as well as via low-level accesses.

Devtab Entries

For some applications or higher-level packages it may be more -convenient to use traditional open/read/write I/O calls rather than -the non-blocking USB I/O calls. To support this the device driver can -provide a devtab entry for each endpoint, for example:

#ifdef CYGVAR_DEVS_USB_SA11X0_EP1_DEVTAB_ENTRY








    -








    -static CHAR_DEVIO_TABLE(usbs_sa11x0_ep1_devtab_functions,








    -                        &cyg_devio_cwrite,








    -                        &usbs_devtab_cread,








    -                        &cyg_devio_bwrite,








    -                        &cyg_devio_bread,








    -                        &cyg_devio_select,








    -                        &cyg_devio_get_config,








    -                        &cyg_devio_set_config);








    -








    -static CHAR_DEVTAB_ENTRY(usbs_sa11x0_ep1_devtab_entry,








    -                         CYGDAT_DEVS_USB_SA11X0_DEVTAB_BASENAME "1r",








    -                         0,








    -                         &usbs_sa11x0_ep1_devtab_functions,








    -                         &usbs_sa11x0_devtab_dummy_init,








    -                         0,








    -                         (void*) &usbs_sa11x0_ep1);








    -#endif

Again care must be taken to avoid name clashes. This can be achieved -by having a configuration option to control the base name, with a -default value of e.g. /dev/usbs, and appending an -endpoint-specific string. This gives the application developer -sufficient control to eliminate any name clashes. The common USB slave -package provides functions usbs_devtab_cwrite and -usbs_devtab_cread, which can be used in the -function tables for transmit and receive endpoints respectively. The -private field priv of the devtab entry -should be a pointer to the underlying endpoint data structure.

Because devtab entries are never accessed directly, only indirectly, -they would usually be eliminated by the linker. To avoid this the -devtab entries should normally be defined in a separate source file -which ends up the special library libextras.a -rather than in the default library libtarget.a.

Not all applications or higher-level packages will want to use the -devtab entries and the blocking I/O facilities. It may be appropriate -for the device driver to provide additional configuration options that -control whether or not any or all of the devtab entries should be -provided, to avoid unnecessary memory overheads.

Interrupt Handling

A typical USB device driver will need to service interrupts for all of -the endpoints and possibly for additional USB events such as entering -or leaving suspended mode. Usually these interrupts need not be -serviced directly by the ISR. Instead, they can be left to a DSR. If -the peripheral is not able to accept or send another packet just yet, -the hardware will generate a NAK and the host will just retry a little -bit later. If high throughput is required then it may be desirable to -handle the bulk transfer protocol largely at ISR level, that is take -care of each packet in the ISR and only activate the DSR once the -whole transfer has completed.

Control messages may involve invoking arbitrary callback functions in -higher-level code. This should normally happen at DSR level. Doing it -at ISR level could seriously affect the system's interrupt latency and -impose unacceptable constraints on what operations can be performed by -those callbacks. If the device driver requires a thread anyway then it -may be appropriate to use this thread for invoking the callbacks, but -usually it is not worthwhile to add a new thread to the system just -for this; higher-level code is expected to write callbacks that -function sensibly at DSR level. Much the same applies to the -completion functions associated with data transfers. These should also -be invoked at DSR or thread level.

Support for USB Testing

Optionally a USB device driver can provide support for the -USB test software. This requires -defining a number of additional data structures, allowing the -generic test code to work out just what the hardware is capable of and -hence what testing can be performed.

The key data structure is -usbs_testing_endpoint, defined in cyg/io/usb/usbs.h. In addition some -commonly required constants are provided by the common USB package in -cyg/io/usb/usb.h. One -usbs_testing_endpoint structure should be -defined for each supported endpoint. The following fields need to be -filled in:

endpoint_type

This specifies the type of endpoint and should be one of - USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL, - BULK, ISOCHRONOUS or - INTERRUPT. -

endpoint_number

This identifies the number that should be used by the host - to address this endpoint. For a control endpoint it should - be 0. For other types of endpoints it should be between - 1 and 15. -

endpoint_direction

For control endpoints this field is irrelevant. For other - types of endpoint it should be either - USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN or - USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT. If a given - endpoint number can be used for traffic in both directions then - there should be two entries in the array, one for each direction. -

endpoint

This should be a pointer to the appropriate - usbs_control_endpoint, - usbs_rx_endpoint or - usbs_tx_endpoint structure, allowing the - generic testing code to perform low-level I/O. -

devtab_entry

If the endpoint also has an entry in the system's device table then - this field should give the corresponding string, for example - "/dev/usbs1r". This allows the - generic testing code to access the device via higher-level - calls like open and read. -

min_size

This indicates the smallest transfer size that the hardware can - support on this endpoint. Typically this will be one. -

Note: Strictly speaking a minimum size of one is not quite right since it - is valid for a USB transfer to involve zero bytes, in other words a - transfer that involves just headers and acknowledgements and an - empty data phase, and that should be tested as well. However current - device drivers interpret a transfer size of 0 as special, so that - would have to be resolved first. -

max_size

Similarly, this specifies the largest transfer size. For control - endpoints the USB protocol uses only two bytes to hold the transfer - length, so there is an upper bound of 65535 bytes. In practice - it is very unlikely that any control transfers would ever need to - be this large, and in fact such transfers would take a long time - and probably violate timing constraints. For other types of endpoint - any of the protocol, the hardware, or the device driver may impose - size limits. For example a given device driver might be unable to - cope with transfers larger than 65535 bytes. If it should be - possible to transfer arbitrary amounts of data then a value of - -1 indicates no upper limit, and transfer - sizes will be limited by available memory and by the capabilities - of the host machine. -

max_in_padding

This field is needed on some hardware where it is impossible to - send packets of a certain size. For example the hardware may be - incapable of sending an empty bulk packet to terminate a transfer - that is an exact multiple of the 64-byte bulk packet size. - Instead the driver has to do some padding and send an extra byte, - and the host has to be prepared to receive this extra byte. Such a - driver should specify a value of 1 for the - padding field. For most drivers this field should be set to - 0. -

A better solution would be for the device driver to supply a - fragment of Tcl code that would adjust the receive buffer size - only when necessary, rather than for every transfer. Forcing - receive padding on all transfers when only certain transfers - will actually be padded reduces the accuracy of certain tests. -

alignment

On some hardware data transfers may need to be aligned to certain - boundaries, for example a word boundary or a cacheline boundary. - Although in theory device drivers could hide such alignment - restrictions from higher-level code by having their own buffers and - performing appropriate copying, that would be expensive in terms of - both memory and cpu cycles. Instead the generic testing code will - align any buffers passed to the device driver to the specified - boundary. For example, if the driver requires that buffers be - aligned to a word boundary then it should specify an alignment - value of 4. -

The device driver should provide an array of these structures -usbs_testing_endpoints[]. The USB testing code -examines this array and uses the information to perform appropriate -tests. Because different USB devices support different numbers of -endpoints the number of entries in the array is not known in advance, -so instead the testing code looks for a special terminator -USBS_TESTING_ENDPOINTS_TERMINATOR. An example -array, showing just the control endpoint and the terminator, might -look like this:

usbs_testing_endpoint usbs_testing_endpoints[] = {








    -    {








    -        endpoint_type       : USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL,








    -        endpoint_number     : 0,








    -        endpoint_direction  : USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN,








    -        endpoint            : (void*) &ep0.common,








    -        devtab_entry        : (const char*) 0,








    -        min_size            : 1,








    -        max_size            : 0x0FFFF,








    -        max_in_padding      : 0,








    -        alignment           : 0








    -    },








    -    …,








    -    USBS_TESTING_ENDPOINTS_TERMINATOR








    -};

Note: The use of a single array usbs_testing_endpoints -limits USB testing to platforms with a single USB device: if there -were multiple devices, each defining their own instance of this array, -then there would a collision at link time. In practice this should not -be a major problem since typical USB peripherals only interact with a -single host machine via a single slave port. In addition, even if a -peripheral did have multiple slave ports the current USB testing code -would not support this since it would not know which port to use.


PrevHomeNext
Data Endpoints Testing
\ No newline at end of file Index: slave/v2_0/doc/usbs-enum.html =================================================================== --- slave/v2_0/doc/usbs-enum.html (revision 174) +++ slave/v2_0/doc/usbs-enum.html (nonexistent) @@ -1,834 +0,0 @@ - - - - - - - - - - - -USB Enumeration Data -
eCos USB Slave Support
PrevNext

USB Enumeration Data

Name

Enumeration Data -- The USB enumeration data structures

Synopsis

#include <cyg/io/usb/usb.h>








    -#include <cyg/io/usb/usbs.h>








    -








    -typedef struct usb_device_descriptor {








    -    …








    -} usb_device_descriptor __attribute__((packed));








    -








    -typedef struct usb_configuration_descriptor {








    -    …








    -} usb_configuration_descriptor __attribute__((packed));








    -








    -typedef struct usb_interface_descriptor {








    -    …








    -} usb_interface_descriptor __attribute__((packed));








    -








    -typedef struct usb_endpoint_descriptor {








    -    …








    -} usb_endpoint_descriptor;








    -








    -typedef struct usbs_enumeration_data {








    -    usb_device_descriptor               device;








    -    int                                 total_number_interfaces;








    -    int                                 total_number_endpoints;








    -    int                                 total_number_strings;








    -    const usb_configuration_descriptor* configurations;








    -    const usb_interface_descriptor*     interfaces;








    -    const usb_endpoint_descriptor*      endpoints;








    -    const unsigned char**               strings;








    -} usbs_enumeration_data;

USB Enumeration Data

When a USB host detects that a peripheral has been plugged in or -powered up, one of the first steps is to ask the peripheral to -describe itself by supplying enumeration data. Some of this data -depends on the class of peripheral. Other fields are vendor-specific. -There is also a dependency on the hardware, specifically which -endpoints are available should be used. In general it is not possible -for generic code to provide this information, so it is the -responsibility of application code to provide a suitable -usbs_enumeration_data data structure and -install it in the endpoint 0 data structure during initialization. -This must happen before the USB device is enabled by a call to -usbs_start, for example:

const usbs_enumeration_data usb_enum_data = {








    -    …








    -};








    -








    -int








    -main(int argc, char** argv)








    -{








    -    usbs_sa11x0_ep0.enumeration_data = &usb_enum_data;








    -    …








    -    usbs_start(&usbs_sa11x0_ep0);








    -    …








    -}

For most applications the enumeration data will be static, although -the usbs_enumeration_data structure can be -filled in at run-time if necessary. Full details of the enumeration -data can be found in the Universal Serial Bus specification obtainable -from the USB Implementers Forum web -site, although the meaning of most fields is fairly obvious. -The various data structures and utility macros are defined in the -header files cyg/io/usb/usb.h -and cyg/io/usb/usbs.h. Note -that the example code below makes use of the gcc labelled element -extension.

usb_device_descriptor

The main information about a USB peripheral comes from a single -usb_device_descriptor structure, which is -embedded in the usbs_enumeration_data -structure. A typical example might look like this:

const 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,








    -        vendor_hi:              0x42,








    -        product_lo:             0x42,








    -        product_hi:             0x42,








    -        device_lo:              0x00,








    -        device_hi:              0x01,








    -        manufacturer_str:       1,








    -        product_str:            2,








    -        serial_number_str:      0,








    -        number_configurations:  1








    -    },








    -    …








    -};

The length and type fields are specified by the USB standard. The -usb_spec_lo and -usb_spec_hi fields identify the particular -revision of the standard that the peripheral implements, for example -revision 1.1.

The device class, subclass, and protocol fields are used by generic -host-side USB software to determine which host-side device driver -should be loaded to interact with the peripheral. A number of standard -classes are defined, for example mass-storage devices and -human-interface devices. If a peripheral implements one of the -standard classes then a standard existing host-side device driver may -exist, eliminating the need to write a custom driver. The value -0xFF (VENDOR) is reserved for -peripherals that implement a vendor-specific protocol rather than a -standard one. Such peripherals will require a custom host-side device -driver. The value 0x00 -(INTERFACE) is reserved and indicates that the -protocol used by the peripheral is defined at the interface level -rather than for the peripheral as a whole.

The max_package_size field specifies the -maximum length of a control message. There is a lower bound of eight -bytes, and typical hardware will not support anything larger because -control messages are usually small and not performance-critical.

The vendor_lo and -vendor_hi fields specify a vendor id, which -must be obtained from the USB Implementor's Forum. The numbers used in -the code fragment above are examples only and must not be used in real -USB peripherals. The product identifier is determined by the vendor, -and different USB peripherals should use different identifiers. The -device identifier field should indicate a release number in -binary-coded decimal.

The above fields are all numerical in nature. A USB peripheral can -also provide a number of strings as described below, for example the name of the -vendor can be provided. The various _str -fields act as indices into an array of strings, with index 0 -indicating that no string is available.

A typical USB peripheral involves just a single configuration. However -more complicated peripherals can support multiple configurations. Only -one configuration will be active at any one time, and the host will -switch between them as appropriate. If a peripheral does involve -multiple configurations then typically it will be the responsibility -of application code to handle the standard -set-configuration control message.

usb_configuration_descriptor

A USB peripheral involves at least one and possible several different -configurations. The usbs_enumeration_data -structure requires a pointer to an array, possibly of length 1, of -usb_configuration_descriptor structures. -Usually a single structure suffices:

const 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, 2),








    -    total_length_hi:    USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(1, 2),








    -    number_interfaces:  1,








    -    configuration_id:   1,








    -    configuration_str:  0,








    -    attributes:         USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED |








    -                        USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED,








    -    max_power:          50








    -};








    -








    -const usbs_enumeration_data usb_enum_data = {








    -    …








    -    configurations:             &usb_configuration,








    -    …








    -};

The values for the length and -type fields are determined by the standard. -The total_length field depends on the -number of interfaces and endpoints used by this configuration, and -convenience macros are provided to calculate this: the first argument -to the macros specify the number of interfaces, the second the number -of endpoints. The number_interfaces field -is self-explanatory. If the peripheral involves multiple -configurations then each one must have a unique id, and this will be -used in the set-configuration control message. The id -0 is reserved, and a set-configuration control -message that uses this id indicates that the peripheral should be -inactive. Configurations can have a string description if required. -The attributes field must have the -REQUIRED bit set; the -SELF_POWERED bit informs the host that the -peripheral has its own power supply and will not draw any power over -the bus, leaving more bus power available to other peripherals; the -REMOTE_WAKEUP bit is used if the peripheral can -interrupt the host when the latter is in power-saving mode. For -peripherals that are not self-powered, the -max_power field specifies the power -requirements in units of 2mA.

usb_interface_descriptor

A USB configuration involves one or more interfaces, typically -corresponding to different streams of data. For example, one interface -might involve video data while another interface is for audio. -Multiple interfaces in a single configuration will be active at the -same time.

const usb_interface_descriptor usb_interface = {








    -    length:             USB_INTERFACE_DESCRIPTOR_LENGTH,








    -    type:               USB_INTERFACE_DESCRIPTOR_TYPE,








    -    interface_id:       0,








    -    alternate_setting:  0,








    -    number_endpoints:   2,








    -    interface_class:    USB_INTERFACE_DESCRIPTOR_CLASS_VENDOR,








    -    interface_subclass: USB_INTERFACE_DESCRIPTOR_SUBCLASS_VENDOR,








    -    interface_protocol: USB_INTERFACE_DESCRIPTOR_PROTOCOL_VENDOR,








    -    interface_str:      0








    -};








    -








    -const usbs_enumeration_data usb_enum_data = {








    -    …








    -    total_number_interfaces:    1,








    -    interfaces:                 &usb_interface,








    -    …








    -};

Again, the length and -type fields are specified by the standard. -Each interface within a configuration requires its own id. However, a -given interface may have several alternate settings, in other words -entries in the interfaces array with the same id but different -alternate_setting fields. For example, -there might be one setting which requires a bandwidth of 100K/s and -another setting that only needs 50K/s. The host can use the standard -set-interface control message to choose the most appropriate setting. -The handling of this request is the responsibility of higher-level -code, so the application may have to install its own handler.

The number of endpoints used by an interface is specified in the -number_endpoints field. Exact details of -which endpoints are used is held in a separate array of endpoint -descriptors. The class, subclass and protocol fields are used by -host-side code to determine which host-side device driver should -handle this specific interface. Usually this is determined on a -per-peripheral basis in the -usb_device_descriptor structure, but that can -defer the details to individual interfaces. A per-interface string -is allowed as well.

For USB peripherals involving multiple configurations, the array of -usb_interface_descriptor structures should -first contain all the interfaces for the first configuration, then all -the interfaces for the second configuration, and so on.

usb_endpoint_descriptor

The host also needs information about which endpoint should be used -for what. This involves an array of endpoint descriptors:

const usb_endpoint_descriptor usb_endpoints[] = {








    -    {








    -        length:         USB_ENDPOINT_DESCRIPTOR_LENGTH,








    -        type:           USB_ENDPOINT_DESCRIPTOR_TYPE,








    -        endpoint:       USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT | 1,








    -        attributes:     USB_ENDPOINT_DESCRIPTOR_ATTR_BULK,








    -        max_packet_lo:  64,








    -        max_packet_hi:  0,








    -        interval:       0








    -    },








    -    {








    -        length:         USB_ENDPOINT_DESCRIPTOR_LENGTH,








    -        type:           USB_ENDPOINT_DESCRIPTOR_TYPE,








    -        endpoint:       USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN | 2,








    -        attributes:     USB_ENDPOINT_DESCRIPTOR_ATTR_BULK,








    -        max_packet_lo:  64,








    -        max_packet_hi:  0,








    -        interval:       0








    -    }








    -};








    -








    -const usbs_enumeration_data usb_enum_data = {








    -    …








    -    total_number_endpoints:     2,








    -    endpoints:                  usb_endpoints,








    -    …








    -};

As usual the values for the length and -type fields are specified by the standard. -The endpoint field gives both the endpoint -number and the direction, so in the above example endpoint 1 is used -for OUT (host to peripheral) transfers and endpoint 2 is used for IN -(peripheral to host) transfers. The -attributes field indicates the USB protocol -that should be used on this endpoint: CONTROL, -ISOCHRONOUS, BULK or -INTERRUPT. The -max_packet field specifies the maximum size -of a single USB packet. For bulk transfers this will typically be 64 -bytes. For isochronous transfers this can be up to 1023 bytes. For -interrupt transfers it can be up to 64 bytes, although usually a -smaller value will be used. The interval -field is ignored for control and bulk transfers. For isochronous -transfers it should be set to 1. For interrupt transfers it can be a -value between 1 and 255, and indicates the number of milliseconds -between successive polling operations.

For USB peripherals involving multiple configurations or interfaces -the array of endpoint descriptors should be organized sequentially: -first the endpoints corresponding to the first interface of the first -configuration, then the second interface in that configuration, and so -on; then all the endpoints for all the interfaces in the second -configuration; etc.

Strings

The enumeration data can contain a number of strings with additional -information. Unicode encoding is used for the strings, and it is -possible for a peripheral to supply a given string in multiple -languages using the appropriate characters. The first two bytes of -each string give a length and type field. The first string is special; -after the two bytes header it consists of an array of 2-byte language -id codes, indicating the supported languages. The language code -0x0409 corresponds to English (United States).

const unsigned char* usb_strings[] = {








    -    "\004\003\011\004",








    -    "\020\003R\000e\000d\000 \000H\000a\000t\000"








    -};








    -








    -const usbs_enumeration_data usb_enum_data = {








    -    …








    -    total_number_strings:       2,








    -    strings:                    usb_strings,








    -    …








    -};

The default handler for standard control messages assumes that the -peripheral only uses a single language. If this is not the case then -higher-level code will have to handle the standard get-descriptor -control messages when a string descriptor is requested.

usbs_enumeration_data

The usbs_enumeration_data data structure -collects together all the various descriptors that make up the -enumeration data. It is the responsibility of application code to -supply a suitable data structure and install it in the control -endpoints's enumeration_data field before -the USB device is started.


PrevHomeNext
Introduction Starting up a USB Device
\ No newline at end of file Index: slave/v2_0/doc/usbs-start-rx.html =================================================================== --- slave/v2_0/doc/usbs-start-rx.html (revision 174) +++ slave/v2_0/doc/usbs-start-rx.html (nonexistent) @@ -1,444 +0,0 @@ - - - - - - - - - - - -Receiving Data from the Host -
eCos USB Slave Support
PrevNext

Receiving Data from the Host

Name

usbs_start_rx_buffer -- Receiving Data from the Host

Synopsis

#include <cyg/io/usb/usbs.h>

void usbs_start_rx_buffer(usbs_rx_endpoint* ep, unsigned char* buffer, int length, void (*)(void*,int) complete_fn, void * complete_data);

void usbs_start_rx(usbs_rx_endpoint* ep);

Description

usbs_start_rx_buffer is a USB-specific function -to accept a transfer from host to peripheral. It can be used for bulk, -interrupt or isochronous transfers, but not for control messages. -Instead those involve manipulating the usbs_control_endpoint -data structure directly. The function takes five arguments:

  1. The first argument identifies the specific endpoint that should be -used. Different USB devices will support different sets of endpoints -and the device driver will provide appropriate data structures. The -device driver's documentation should be consulted for details of which -endpoints are available.

  2. The buffer and length -arguments control the actual transfer. USB device drivers are not -expected to perform any buffering or to support partial transfers, so -the length specified should correspond to the maximum transfer that is -currently possible and the buffer should be at least this large. For -isochronous transfers the USB specification imposes an upper bound of -1023 bytes, and a smaller limit may be set in the enumeration data. Interrupt -transfers are similarly straightforward with an upper bound of 64 -bytes, or less as per the enumeration data. Bulk transfers are more -complicated because they can involve multiple 64-byte packets plus a -terminating packet of less than 64 bytes, so there is no predefined -limit on the transfer size. Instead it is left to higher-level -protocols to specify an appropriate upper bound.

    One technique that may work for bulk transfers is to exploit the fact -that such transfers happen in 64-byte packets: it may be possible to -receive an initial 64 bytes, corresponding to the first packet in the -transfer; these 64 bytes can then be examined to determine the total -transfer size, and the remaining data can be transferred in another -receive operation. This technique is not guaranteed to work with all -USB hardware. Also, if the delay between accepting the first packet and -the remainder of the transfer is excessive then this could cause -timeout problems for the host-side software. For these reasons this -technique should be avoided.

  3. usbs_start_rx_buffer is non-blocking. It merely -starts the receive operation, and does not wait for completion. At -some later point the USB device driver will invoke the completion -function parameter with two arguments: the completion data defined by -the last parameter and a result field. A result >= -0 indicates a successful transfer of that many -bytes, which may be less than the upper bound imposed by the -length argument. A result < -0 indicates an error. The most likely errors are --EPIPE to indicate that the connection between the -host and the target has been broken, and -EAGAIN -for when the endpoint has been halted. Specific USB device drivers may -specify additional error conditions.

The normal sequence of events is that the USB device driver will -update the appropriate hardware registers. At some point after that -the host will attempt to send data by transmitting an OUT token -followed by a data packet, and since a receive operation is now in -progress the data will be accepted and ACK'd. If there were no receive -operation then the peripheral would instead generate a NAK. The USB -hardware will generate an interrupt once the whole packet has been -received, and the USB device driver will service this interrupt and -arrange for a DSR to be called. Isochronous and interrupt transfers -involve just a single packet. However, bulk transfers may involve -multiple packets so the device driver has to check whether the packet -was a full 64 bytes or whether it was a terminating packet of less -than this. When the device driver DSR detects a complete transfer it -will inform higher-level code by invoking the supplied completion -function.

This means that the completion function will normally be invoked by a -DSR and not in thread context - although some USB device drivers may -have a different implementation. Therefore the completion function is -restricted in what it can do. In particular it must not make any -calls that will or may block such as locking a mutex or allocating -memory. The kernel documentation should be consulted for more details -of DSR's and interrupt handling generally.

It is possible that the completion function will be invoked before -usbs_start_rx_buffer returns. Such an event would -be unusual because the transfer cannot happen until the next time the -host tries to send data to this peripheral, but it may happen if for -example another interrupt happens and a higher priority thread is -scheduled to run. Also, if the endpoint is currently halted then the -completion function will be invoked immediately with --EAGAIN: typically this will happen in the current -thread rather than in a separate DSR. The completion function is -allowed to start another transfer immediately by calling -usbs_start_rx_buffer again.

USB device drivers are not expected to perform any locking. It is the -responsibility of higher-level code to ensure that there is only one -receive operation for a given endpoint in progress at any one time. If -there are concurrent calls to -usbs_start_rx_buffer then the resulting behaviour -is undefined. For typical USB applications this does not present any -problems, because only one piece of code will access a given endpoint -at any particular time.

The following code fragment illustrates a very simple use of -usbs_start_rx_buffer to implement a blocking -receive, using a semaphore to synchronise between the foreground -thread and the DSR. For a simple example like this no completion data -is needed.

static int error_code = 0;








    -static cyg_sem_t completion_wait;








    -








    -static void








    -completion_fn(void* data, int result)








    -{








    -    error_code = result;








    -    cyg_semaphore_post(&completion_wait);








    -}








    -








    -int








    -blocking_receive(usbs_rx_endpoint* ep, unsigned char* buf, int len)








    -{








    -    error_code = 0;








    -    usbs_start_rx_buffer(ep, buf, len, &completion_fn, NULL);








    -    cyg_semaphore_wait(&completion_wait);








    -    return error_code;








    -}

There is also a utility function usbs_start_rx. This -can be used by code that wants to manipulate data endpoints directly, specifically the -complete_fn, -complete_data, -buffer and -buffer_size fields. -usbs_start_tx just invokes a function -supplied by the device driver.


PrevHomeNext
Devtab Entries Sending Data to the Host
\ No newline at end of file Index: slave/v2_0/doc/usbs-devtab.html =================================================================== --- slave/v2_0/doc/usbs-devtab.html (revision 174) +++ slave/v2_0/doc/usbs-devtab.html (nonexistent) @@ -1,480 +0,0 @@ - - - - - - - - - - - -Devtab Entries -
eCos USB Slave Support
PrevNext

Devtab Entries

Name

Devtab Entries -- Data endpoint data structure

Synopsis

/dev/usb0c








    -/dev/usb1r








    -/dev/usb2w

Devtab Entries

USB device drivers provide two ways of transferring data between host -and peripheral. The first involves USB-specific functionality such as -usbs_start_rx_buffer. -This provides non-blocking I/O: a transfer is started, and some time -later the device driver will call a supplied completion function. The -second uses the conventional I/O model: there are entries in the -device table corresponding to the various endpoints. Standard calls -such as open can then be used to get a suitable -handle. Actual I/O happens via blocking read and -write calls. In practice the blocking operations -are simply implemented using the underlying non-blocking -functionality.

Each endpoint will have its own devtab entry. The exact names are -controlled by the device driver package, but typically the root will -be /dev/usb. This is followed by one or more -decimal digits giving the endpoint number, followed by -c for a control endpoint, r for -a receive endpoint (host to peripheral), and w for -a transmit endpoint (peripheral to host). If the target hardware -involves more than one USB device then different roots should be used, -for example /dev/usb0c and -/dev/usb1_0c. This may require explicit -manipulation of device driver configuration options by the application -developer.

At present the devtab entry for a control endpoint does not support -any I/O operations.

write operations

cyg_io_write and similar functions in -higher-level packages can be used to perform a transfer from -peripheral to host. Successive write operations will not be coalesced. -For example, when doing a 1000 byte write to an endpoint that uses the -bulk transfer protocol this will involve 15 full-size 64-byte packets -and a terminating 40-byte packet. USB device drivers are not expected -to do any locking, and if higher-level code performs multiple -concurrent write operations on a single endpoint then the resulting -behaviour is undefined.

A USB write operation will never transfer less -data than specified. It is the responsibility of higher-level code to -ensure that the amount of data being transferred is acceptable to the -host-side code. Usually this will be defined by a higher-level -protocol. If an attempt is made to transfer more data than the host -expects then the resulting behaviour is undefined.

There are two likely error conditions. EPIPE -indicates that the connection between host and target has been broken. -EAGAIN indicates that the endpoint has been -stalled, either at the request of the host or by other activity -inside the peripheral.

read operations

cyg_io_read and similar functions in higher-level -packages can be used to perform a transfer from host to peripheral. -This should be a complete transfer: higher-level protocols should -define an upper bound on the amount of data being transferred, and the -read operation should involve at least this -amount of data. The return value will indicate the actual transfer -size, which may be less than requested.

Some device drivers may support partial reads, but USB device drivers -are not expected to perform any buffering because that involves both -memory and code overheads. One technique that may work for bulk -transfers is to exploit the fact that such transfers happen in 64-byte -packets. It is possible to read an initial 64 -bytes, corresponding to the first packet in the transfer. These 64 -bytes can then be examined to determine the total transfer size, and -the remaining data can be transferred in another -read operation. This technique is not guaranteed -to work with all USB hardware. Also, if the delay between accepting -the first packet and the remainder of the transfer is excessive then -this could cause timeout problems for the host-side software. For -these reasons the use of partial reads should be avoided.

There are two likely error conditions. EPIPE -indicates that the connection between host and target has been broken. -EAGAIN indicates that the endpoint has been -stalled, either at the request of the host or by other activity -inside the peripheral.

USB device drivers are not expected to do any locking. If higher-level -code performs multiple concurrent read operations on a single endpoint -then the resulting behaviour is undefined.

select operations

Typical USB device drivers will not provide any support for -select. Consider bulk transfers from the host to -the peripheral. At the USB device driver level there is no way of -knowing in advance how large a transfer will be, so it is not feasible -for the device driver to buffer the entire transfer. It may be -possible to buffer part of the transfer, for example the first 64-byte -packet, and copy this into application space at the start of a -read, but this adds code and memory overheads. -Worse, it means that there is an unknown but potentially long delay -between a peripheral accepting the first packet of a transfer and the -remaining packets, which could confuse or upset the host-side -software.

With some USB hardware it may be possible for the device driver to -detect OUT tokens from the host without actually accepting the data, -and this would indicate that a read is likely to -succeed. However, it would not be reliable since the host-side I/O -operation could time out. A similar mechanism could be used to -implement select for outgoing data, but again -this would not be reliable.

Some device drivers may provide partial support for -select anyway, possibly under the control of a -configuration option. The device driver's documentation should be -consulted for further information. It is also worth noting that the -USB-specific non-blocking API can often be used as an alternative to -select.

get_config and -set_config operations

There are no set_config or -get_config (also known as -ioctl) operations defined for USB devices. -Some device drivers may provide hardware-specific facilities this way.

Note: Currently the USB-specific functions related to halted endpoints cannot be accessed readily -via devtab entries. This functionality should probably be made -available via set_config and -get_config. It may also prove useful to provide -a get_config operation that maps from the -devtab entries to the underlying endpoint data structures.

Presence

The devtab entries are optional. If the USB device is accessed -primarily by class-specific code such as the USB-ethernet package and -that package uses the USB-specific API directly, the devtab entries -are redundant. Even if application code does need to access the USB -device, the non-blocking API may be more convenient than the blocking -I/O provided via the devtab entries. In these cases the devtab entries -serve no useful purpose, but they still impose a memory overhead. It -is possible to suppress the presence of these entries by disabling the -configuration option -CYGGLO_IO_USB_SLAVE_PROVIDE_DEVTAB_ENTRIES.


PrevHomeNext
Starting up a USB Device Receiving Data from the Host
\ No newline at end of file Index: slave/v2_0/doc/usbs-start-tx.html =================================================================== --- slave/v2_0/doc/usbs-start-tx.html (revision 174) +++ slave/v2_0/doc/usbs-start-tx.html (nonexistent) @@ -1,436 +0,0 @@ - - - - - - - - - - - -Sending Data to the Host -
eCos USB Slave Support
PrevNext

Sending Data to the Host

Name

usbs_start_tx_buffer -- Sending Data to the Host

Synopsis

#include <cyg/io/usb/usbs.h>

void usbs_start_tx_buffer(usbs_tx_endpoint* ep, const unsigned char* buffer, int length, void (*)(void*,int) complete_fn, void * complete_data);

void usbs_start_tx(usbs_tx_endpoint* ep);

Description

usbs_start_tx_buffer is a USB-specific function -to transfer data from peripheral to host. It can be used for bulk, -interrupt or isochronous transfers, but not for control messages; -instead those involve manipulating the usbs_control_endpoint -data structure directly. The function takes five arguments:

  1. The first argument identifies the specific endpoint that should be -used. Different USB devices will support different sets of endpoints -and the device driver will provide appropriate data structures. The -device driver's documentation should be consulted for details of which -endpoints are available.

  2. The buffer and length -arguments control the actual transfer. USB device drivers are not -allowed to modify the buffer during the transfer, so the data can -reside in read-only memory. The transfer will be for all the data -specified, and it is the responsibility of higher-level code to make -sure that the host is expecting this amount of data. For isochronous -transfers the USB specification imposes an upper bound of 1023 bytes, -but a smaller limit may be set in the enumeration data. Interrupt -transfers have an upper bound of 64 bytes or less, as per the -enumeration data. Bulk transfers are more complicated because they can -involve multiple 64-byte packets plus a terminating packet of less -than 64 bytes, so the basic USB specification does not impose an upper -limit on the total transfer size. Instead it is left to higher-level -protocols to specify an appropriate upper bound. If the peripheral -attempts to send more data than the host is willing to accept then the -resulting behaviour is undefined and may well depend on the specific -host operating system being used.

    For bulk transfers, the USB device driver or the underlying hardware -will automatically split the transfer up into the appropriate number -of full-size 64-byte packets plus a single terminating packet, which -may be 0 bytes.

  3. usbs_start_tx_buffer is non-blocking. It merely -starts the transmit operation, and does not wait for completion. At -some later point the USB device driver will invoke the completion -function parameter with two arguments: the completion data defined by -the last parameter, and a result field. This result will be either an -error code < 0, or the amount of data -transferred which should correspond to the -length argument. The most likely errors are --EPIPE to indicate that the connection between the -host and the target has been broken, and -EAGAIN -for when the endpoint has been halted. Specific USB device drivers may -define additional error conditions.

The normal sequence of events is that the USB device driver will -update the appropriate hardware registers. At some point after that -the host will attempt to fetch data by transmitting an IN token. Since -a transmit operation is now in progress the peripheral can send a -packet of data, and the host will generate an ACK. At this point the -USB hardware will generate an interrupt, and the device driver will -service this interrupt and arrange for a DSR to be called. Isochronous -and interrupt transfers involve just a single packet. However, bulk -transfers may involve multiple packets so the device driver has to -check whether there is more data to send and set things up for the -next packet. When the device driver DSR detects a complete transfer it -will inform higher-level code by invoking the supplied completion -function.

This means that the completion function will normally be invoked by a -DSR and not in thread context - although some USB device drivers may -have a different implementation. Therefore the completion function is -restricted in what it can do, in particular it must not make any -calls that will or may block such as locking a mutex or allocating -memory. The kernel documentation should be consulted for more details -of DSR's and interrupt handling generally.

It is possible that the completion function will be invoked before -usbs_start_tx_buffer returns. Such an event would -be unusual because the transfer cannot happen until the next time the -host tries to fetch data from this peripheral, but it may happen if, -for example, another interrupt happens and a higher priority thread is -scheduled to run. Also, if the endpoint is currently halted then the -completion function will be invoked immediately with --EAGAIN: typically this will happen in the current -thread rather than in a separate DSR. The completion function is -allowed to start another transfer immediately by calling -usbs_start_tx_buffer again.

USB device drivers are not expected to perform any locking. It is the -responsibility of higher-level code to ensure that there is only one -transmit operation for a given endpoint in progress at any one time. -If there are concurrent calls to -usbs_start_tx_buffer then the resulting behaviour -is undefined. For typical USB applications this does not present any -problems because only piece of code will access a given endpoint at -any particular time.

The following code fragment illustrates a very simple use of -usbs_start_tx_buffer to implement a blocking -transmit, using a semaphore to synchronise between the foreground -thread and the DSR. For a simple example like this no completion data -is needed.

static int error_code = 0;








    -static cyg_sem_t completion_wait;








    -








    -static void








    -completion_fn(void* data, int result)








    -{








    -    error_code = result;








    -    cyg_semaphore_post(&completion_wait);








    -}








    -








    -int








    -blocking_transmit(usbs_tx_endpoint* ep, const unsigned char* buf, int len)








    -{








    -    error_code = 0;








    -    usbs_start_tx_buffer(ep, buf, len, &completion_fn, NULL);








    -    cyg_semaphore_wait(&completion_wait);








    -    return error_code;








    -}

There is also a utility function usbs_start. This -can be used by code that wants to manipulate data endpoints directly, specifically the -complete_fn, -complete_data, -buffer and -buffer_size fields. -usbs_start_tx just calls a function supplied by -the device driver.


PrevHomeNext
Receiving Data from the Host Halted Endpoints
\ No newline at end of file Index: slave/v2_0/doc/usbs-halt.html =================================================================== --- slave/v2_0/doc/usbs-halt.html (revision 174) +++ slave/v2_0/doc/usbs-halt.html (nonexistent) @@ -1,312 +0,0 @@ - - - - - - - - - - - -Halted Endpoints -
eCos USB Slave Support
PrevNext

Halted Endpoints

Name

Halted Endpoints -- Support for Halting and Halted Endpoints

Synopsis

#include <cyg/io/usb/usbs.h>

cyg_bool usbs_rx_endpoint_halted(usbs_rx_endpoint* ep);

void usbs_set_rx_endpoint_halted(usbs_rx_endpoint* ep, cyg_bool new_state);

void usbs_start_rx_endpoint_wait(usbs_rx_endpoint* ep, void (*)(void*, int) complete_fn, void * complete_data);

cyg_bool -usbs_tx_endpoint_halted(usbs_tx_endpoint* ep);

void usbs_set_tx_endpoint_halted(usbs_tx_endpoint* ep, cyg_bool new_state);

void usbs_start_tx_endpoint_wait(usbs_tx_endpoint* ep, void (*)(void*, int) complete_fn, void * complete_data);

Description

Normal USB traffic involves straightforward handshakes, with either an -ACK to indicate that a packet was transferred -without errors, or a NAK if an error occurred, or -if a peripheral is currently unable to process another packet from the -host, or has no packet to send to the host. There is a third form of -handshake, a STALL, which indicates that the -endpoint is currently halted.

When an endpoint is halted it means that the host-side code needs to -take some sort of recovery action before communication over that -endpoint can resume. The exact circumstances under which this can -happen are not defined by the USB specification, but one example would -be a protocol violation if say the peripheral attempted to transmit -more data to the host than was permitted by the protocol in use. The -host can use the standard control messages get-status, set-feature and -clear-feature to examine and manipulate the halted status of a given -endpoint. There are USB-specific functions which can be used inside -the peripheral to achieve the same effect. Once an endpoint has been -halted the host can then interact with the peripheral using class or -vendor control messages to perform appropriate recovery, and then the -halted condition can be cleared.

Halting an endpoint does not constitute a device state change, and -there is no mechanism by which higher-level code can be informed -immediately. However, any ongoing receive or transmit operations will -be aborted with an -EAGAIN error, and any new -receives or transmits will fail immediately with the same error.

There are six functions to support halted endpoints, one set for -receive endpoints and another for transmit endpoints, with both sets -behaving in essentially the same way. The first, -usbs_rx_endpoint_halted, can be used to determine -whether or not an endpoint is currently halted: it takes a single -argument that identifies the endpoint of interest. The second -function, usbs_set_rx_endpoint_halted, can be -used to change the halted condition of an endpoint: it takes two -arguments; one to identify the endpoint and another to specify the new -state. The last function -usbs_start_rx_endpoint_wait operates in much the -same way as usbs_start_rx_buffer: when the -endpoint is no longer halted the device driver will invoke the -supplied completion function with a status of 0. The completion -function has the same signature as that for a transfer operation. -Often it will be possible to use a single completion function and have -the foreground code invoke either -usbs_start_rx_buffer or -usbs_start_rx_endpoint_wait depending on the -current state of the endpoint.


PrevHomeNext
Sending Data to the Host Control Endpoints
\ No newline at end of file Index: slave/v2_0/doc/usbs-data.html =================================================================== --- slave/v2_0/doc/usbs-data.html (revision 174) +++ slave/v2_0/doc/usbs-data.html (nonexistent) @@ -1,377 +0,0 @@ - - - - - - - - - - - -Data Endpoints -
eCos USB Slave Support
PrevNext

Data Endpoints

Name

Data Endpoints -- Data endpoint data structures

Synopsis

#include <cyg/io/usb/usbs.h>








    -








    -typedef struct usbs_rx_endpoint {








    -    void                 (*start_rx_fn)(struct usbs_rx_endpoint*);








    -    void                 (*set_halted_fn)(struct usbs_rx_endpoint*, cyg_bool);








    -    void                 (*complete_fn)(void*, int);








    -    void*                complete_data;








    -    unsigned char*       buffer;








    -    int                  buffer_size;








    -    cyg_bool             halted;








    -} usbs_rx_endpoint;








    -








    -typedef struct usbs_tx_endpoint {








    -    void                 (*start_tx_fn)(struct usbs_tx_endpoint*);








    -    void                 (*set_halted_fn)(struct usbs_tx_endpoint*, cyg_bool);








    -    void                 (*complete_fn)(void*, int);








    -    void*                complete_data;








    -    const unsigned char* buffer;








    -    int                  buffer_size;








    -    cyg_bool             halted;








    -} usbs_tx_endpoint;

Receive and Transmit Data Structures

In addition to a single usbs_control_endpoint -data structure per USB slave device, the USB device driver should also -provide receive and transmit data structures corresponding to the -other endpoints. The names of these are determined by the device -driver. For example, the SA1110 USB device driver package provides -usbs_sa11x0_ep1 for receives and -usbs_sa11x0_ep2 for transmits.

Unlike control endpoints, the common USB slave package does provide a -number of utility routines to manipulate data endpoints. For example -usbs_start_rx_buffer -can be used to receive data from the host into a buffer. In addition -the USB device driver can provide devtab entries such as -/dev/usbs1r and /dev/usbs2w, so -higher-level code can open these devices and then -perform blocking read and -write operations.

However, the operation of data endpoints and the various -endpoint-related functions is relatively straightforward. First -consider a usbs_rx_endpoint structure. The -device driver will provide the members -start_rx_fn and -set_halted_fn, and it will maintain the -halted field. To receive data, higher-level -code sets the buffer, -buffer_size, -complete_fn and optionally the -complete_data fields. Next the -start_rx_fn member should be called. When -the transfer has finished the device driver will invoke the completion -function, using complete_data as the first -argument and a size field for the second argument. A negative size -indicates an error of some sort: -EGAIN indicates -that the endpoint has been halted, usually at the request of the host; --EPIPE indicates that the connection between the -host and the peripheral has been broken. Certain device drivers may -generate other error codes.

If higher-level code needs to halt or unhalt an endpoint then it can -invoke the set_halted_fn member. When an -endpoint is halted, invoking start_rx_fn -wit buffer_size set to 0 indicates that -higher-level code wants to block until the endpoint is no longer -halted; at that point the completion function will be invoked.

USB device drivers are allowed to assume that higher-level protocols -ensure that host and peripheral agree on the amount of data that will -be transferred, or at least on an upper bound. Therefore there is no -need for the device driver to maintain its own buffers, and copy -operations are avoided. If the host sends more data than expected then -the resulting behaviour is undefined.

Transmit endpoints work in essentially the same way as receive -endpoints. Higher-level code should set the -buffer and -buffer_size fields to point at the data to -be transferred, then call start_tx_fn, and -the device driver will invoked the completion function when the -transfer has completed.

USB device drivers are not expected to perform any locking. If at any -time there are two concurrent receive operations for a given endpoint, -or two concurrent transmit operations, then the resulting behaviour is -undefined. It is the responsibility of higher-level code to perform -any synchronisation that may be necessary. In practice, conflicts are -unlikely because typically a given endpoint will only be accessed -sequentially by just one part of the overall system.


PrevHomeNext
Control Endpoints Writing a USB Device Driver
\ No newline at end of file Index: slave/v2_0/doc/usbs-intro.html =================================================================== --- slave/v2_0/doc/usbs-intro.html (revision 174) +++ slave/v2_0/doc/usbs-intro.html (nonexistent) @@ -1,473 +0,0 @@ - - - - - - - - - - - -Introduction -
eCos USB Slave Support
PrevNext

Introduction

Name

Introduction -- eCos support for USB slave devices

Introduction

The eCos USB slave support allows developers to produce USB -peripherals. It consists of a number of different eCos packages:

  1. Device drivers for specific implementations of USB slave hardware, for -example the on-chip USB Device Controller provided by the Intel SA1110 -processor. A typical USB peripheral will only provide one USB slave -port and therefore only one such device driver package will be needed. -Usually the device driver package will be loaded automatically when -you create an eCos configuration for target hardware that has a USB -slave device. If you select a target which does have a USB slave -device but no USB device driver is loaded, this implies that no such -device driver is currently available.

  2. The common USB slave package. This serves two purposes. It defines the -API that specific device drivers should implement. It also provides -various utilities that will be needed by most USB device drivers and -applications, such as handlers for standard control messages. -Usually this package will be loaded automatically at the same time as -the USB device driver.

  3. The common USB package. This merely provides some information common -to both the host and slave sides of USB, such as details of the -control protocol. It is also used to place the other USB-related -packages appropriately in the overall configuration hierarchy. Usually -this package will be loaded at the same time as the USB device driver.

  4. Class-specific USB support packages. These make it easier to develop -specific classes of USB peripheral, such as a USB-ethernet device. If -no suitable package is available for a given class of peripheral then -the USB device driver can instead be accessed directly from -application code. Such packages will never be loaded automatically -since the configuration system has no way of knowing what class of USB -peripheral is being developed. Instead developers have to add the -appropriate package or packages explicitly.

These packages only provide support for developing USB peripherals, -not USB hosts.

USB Concepts

Information about USB can be obtained from a number of sources -including the USB Implementers Forum -web site. Only a brief summary is provided here.

A USB network is asymmetrical: it consists of a single host, one or -more slave devices, and possibly some number of intermediate hubs. The -host side is significantly more complicated than the slave side. -Essentially, all operations are initiated by the host. For example, if -the host needs to receive some data from a particular USB peripheral -then it will send an IN token to that peripheral; the latter should -respond with either a NAK or with appropriate data. Similarly, when -the host wants to transmit data to a peripheral it will send an OUT -token followed by the data; the peripheral will return a NAK if it is -currently unable to receive more data or if there was corruption, -otherwise it will return an ACK. All transfers are check-summed and -there is a clearly-defined error recovery process. USB peripherals can -only interact with the host, not with each other.

USB supports four different types of communication: control messages, -interrupt transfers, isochronous transfers, and bulk transfers. -Control messages are further subdivided into four categories: -standard, class, vendor and a reserved category. All USB peripherals -must respond to certain standard control messages, and usually this -will be handled by the common USB slave package (for complicated -peripherals, application support will be needed). Class and vendor -control messages may be handled by an class-specific USB support -package, for example the USB-ethernet package will handle control -messages such as getting the MAC address or enabling/disabling -promiscuous mode. Alternatively, some or all of these messages will -have to be handled by application code.

Interrupt transfers are used for devices which need to be polled -regularly. For example, a USB keyboard might be polled once every -millisecond. The host will not poll the device more frequently than -this, so interrupt transfers are best suited to peripherals that -involve a relatively small amount of data. Isochronous transfers are -intended for multimedia-related peripherals where typically a large -amount of video or audio data needs to be exchanged continuously. -Given appropriate host support a USB peripheral can reserve some of -the available bandwidth. Isochronous transfers are not reliable; if a -particular packet is corrupted then it will just be discarded and -software is expected to recover from this. Bulk transfers are used for -everything else: after taking care of any pending control, isochronous -and interrupt transfers the host will use whatever bandwidth remains -for bulk transfers. Bulk transfers are reliable.

Transfers are organized into USB packets, with the details depending -on the transfer type. Control messages always involve an initial -8-byte packet from host to peripheral, optionally followed by some -additional packets; in theory these additional packets can be up to 64 -bytes, but hardware may limit it to 8 bytes. Interrupt transfers -involve a single packet of up to 64 bytes. Isochronous transfers -involve a single packet of up to 1024 bytes. Bulk transfers involve -multiple packets. There will be some number, possibly zero, of 64-byte -packets. The transfer is terminated by a single packet of less than 64 -bytes. If the transfer involves an exact multiple of 64 bytes than the -final packet will be 0 bytes, consisting of just a header and checksum -which typically will be generated by the hardware. There is no -pre-defined limit on the size of a bulk transfer. Instead higher-level -protocols are expected to handle this, so for a USB-ethernet -peripheral the protocol could impose a limit of 1514 bytes of data -plus maybe some additional protocol overhead.

Transfers from the host to a peripheral are addressed not just to that -peripheral but to a specific endpoint within that peripheral. -Similarly, the host requests incoming data from a specific endpoint -rather than from the peripheral as a whole. For example, a combined -keyboard/touchpad device could provide the keyboard events on endpoint -1 and the mouse events on endpoint 2. A given USB peripheral can have -up to 16 endpoints for incoming data and another 16 for outgoing data. -However, given the comparatively high speed of USB I/O this endpoint -addressing is typically implemented in hardware rather than software, -and the hardware will only implement a small number of endpoints. -Endpoint 0 is generally used only for control messages.

In practice, many of these details are irrelevant to application code -or to class packages. Instead, such higher-level code usually just -performs blocking read and -write, or non-blocking USB-specific calls, to -transfer data between host and target via a specific endpoint. Control -messages are more complicated but are usually handled by existing -code.

When a USB peripheral is plugged into the host there is an initial -enumeration and configuration process. The peripheral provides -information such as its class of device (audio, video, etc.), a -vendor id, which endpoints should be used for what kind of data, and -so on. The host OS uses this information to identify a suitable host -device driver. This could be a generic driver for a class of -peripherals, or it could be a vendor-specific driver. Assuming a -suitable driver is installed the host will then activate the USB -peripheral and perform additional application-specific initialisation. -For example for a USB-ethernet device this would involve obtaining an -ethernet MAC address. Most USB peripherals will be fairly simple, but -it is possible to build multifunction peripherals with multiple -configurations, interfaces, and alternate interface settings.

It is not possible for any of the eCos packages to generate all the -enumeration data automatically. Some of the required information such -as the vendor id cannot be supplied by generic packages; only by the -application developer. Class support code such as the USB-ethernet -package could in theory supply some of the information automatically, -but there are also hardware dependencies such as which endpoints get -used for incoming and outgoing ethernet frames. Instead it is the -responsibility of the application developer to provide all the -enumeration data and perform some additional initialisation. In -addition, the common USB slave package can handle all the standard -control messages for a simple USB peripheral, but for something like a -multifunction peripheral additional application support is needed.

Note: The initial implementation of the eCos USB slave packages involved -hardware that only supported control and bulk transfers, not -isochronous or interrupt. There may be future changes to the USB -code and API to allow for isochronous and interrupt transfers, -especially the former. Other changes may be required to support -different USB devices. At present there is no support for USB remote -wakeups, since again it is not supported by the hardware.

eCos USB I/O Facilities

For protocols other than control messages, eCos provides two ways of -performing USB I/O. The first involves device table or devtab entries such -as /dev/usb1r, -with one entry per endpoint per USB device. It is possible to -open these devices and use conventional blocking -I/O functions such as read and -write to exchange data between host and -peripheral.

There is also a lower-level USB-specific API, consisting of functions -such as usbs_start_rx_buffer. -A USB device driver will supply a data structure for each endpoint, -for example a usbs_rx_endpoint -structure for every receive endpoint. The first argument to -usbs_start_rx_buffer should be a pointer to such -a data structure. The USB-specific API is non-blocking: the initial -call merely starts the transfer; some time later, once the transfer -has completed or has been aborted, the device driver will invoke a -completion function.

Control messages are different. With four different categories of -control messages including application and vendor specific ones, the -conventional -open/read/write -model of I/O cannot easily be applied. Instead, a USB device driver -will supply a usbs_control_endpoint -data structure which can be manipulated appropriately. In practice the -standard control messages will usually be handled by the common USB -slave package, and other control messages will be handled by -class-specific code such as the USB-ethernet package. Typically, -application code remains responsible for supplying the enumeration data and for actually starting up the USB device.

Enabling the USB code

If the target hardware contains a USB slave device then the -appropriate USB device driver and the common packages will typically -be loaded into the configuration automatically when that target is -selected (assuming a suitable device driver exists). However, the -driver will not necessarily be active. For example a processor might -have an on-chip USB device, but not all applications using that -processor will want to use USB functionality. Hence by default the USB -device is disabled, ensuring that applications do not suffer any -memory or other penalties for functionality that is not required.

If the application developer explicitly adds a class support package -such as the USB-ethernet one then this implies that the USB device is -actually needed, and the device will be enabled automatically. -However, if no suitable class package is available and the USB device -will instead be accessed by application code, it is necessary to -enable the USB device manually. Usually the easiest way to do this is -to enable the configuration option -CYGGLO_IO_USB_SLAVE_APPLICATION, and the USB device -driver and related packages will adjust accordingly. Alternatively, -the device driver may provide some configuration options to provide -more fine-grained control.


PrevHomeNext
eCos USB Slave Support USB Enumeration Data
\ No newline at end of file Index: slave/v2_0/doc/io-usb-slave.html =================================================================== --- slave/v2_0/doc/io-usb-slave.html (revision 174) +++ slave/v2_0/doc/io-usb-slave.html (nonexistent) @@ -1,188 +0,0 @@ - - - - - - - - - - - -eCos USB Slave Support -

I. eCos USB Slave Support

Table of Contents
Introduction — eCos support for USB slave devices
USB Enumeration Data — The USB enumeration data structures
Starting up a USB Device — Starting up a USB Device
Devtab Entries — Data endpoint data structure
Receiving Data from the Host — Receiving Data from the Host
Sending Data to the Host — Sending Data to the Host
Halted Endpoints — Support for Halting and Halted Endpoints
Control Endpoints — Control endpoint data structure
Data Endpoints — Data endpoint data structures
Writing a USB Device Driver — USB Device Driver Porting Guide
Testing — Testing of USB Device Drivers

  Next
  Introduction
\ No newline at end of file Index: slave/v2_0/doc/usbs-start.html =================================================================== --- slave/v2_0/doc/usbs-start.html (revision 174) +++ slave/v2_0/doc/usbs-start.html (nonexistent) @@ -1,264 +0,0 @@ - - - - - - - - - - - -Starting up a USB Device -
eCos USB Slave Support
PrevNext

Starting up a USB Device

Name

usbs_start -- Starting up a USB Device

Synopsis

#include <cyg/io/usb/usbs.h>

void usbs_start(usbs_control_endpoint* ep0);

Description

Initializing a USB device requires some support from higher-level -code, typically the application, in the form of enumeration data. -Hence it is not possible for the low-level USB driver to activate a -USB device itself. Instead the higher-level code has to take care of -this by invoking usbs_start. This function takes -a pointer to a USB control endpoint data structure. USB device drivers -should provide exactly one such data structure for every USB device, -so the pointer uniquely identifies the device.

const usbs_enumeration_data usb_enum_data = {








    -    …








    -};








    -








    -int








    -main(int argc, char** argv)








    -{








    -    usbs_sa11x0_ep0.enumeration_data = &usb_enum_data;








    -    …








    -    usbs_start(&usbs_sa11x0_ep0);








    -    …








    -}

The exact behaviour of usbs_start depends on the -USB hardware and the device driver. A typical implementation would -change the USB data pins from tristated to active. If the peripheral -is already plugged into a host then the latter should detect this -change and start interacting with the peripheral, including requesting -the enumeration data. Some of this may happen before -usbs_start returns, but given that multiple -interactions between USB host and peripheral are required it is likely -that the function will return before the peripheral is fully -configured. Control endpoints provide a mechanism for informing -higher-level code of USB state changes. -usbs_start will return even if the peripheral is -not currently connected to a host: it will not block until the -connection is established.

usbs_start should only be called once for a given -USB device. There are no defined error conditions. Note that the -function affects the entire USB device and not just the control -endpoint: there is no need to start any data endpoints as well.


PrevHomeNext
USB Enumeration Data Devtab Entries
\ No newline at end of file Index: slave/v2_0/doc/usbs-testing.html =================================================================== --- slave/v2_0/doc/usbs-testing.html (revision 174) +++ slave/v2_0/doc/usbs-testing.html (nonexistent) @@ -1,2267 +0,0 @@ - - - - - - - - - - - -Testing -
eCos USB Slave Support
Prev 

Testing

Name

Testing -- Testing of USB Device Drivers

Introduction

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:

  1. 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. -

  2. 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. -

  3. 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". -

  4. 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. -

  5. 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.

Building and Running the Target-side Code

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.

Building and Running the Host-side Code

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>








    -$
The location of the eCos component repository should be substituted -for <repo>.
If the package has been obtained via CVS or anonymous CVS then the -package version will be current, as per the -example. If instead the package has been obtained as part of a full -eCos release or as a separate .epk file then the -appropriate package version should be used instead of -current.
The configure script takes the usual arguments such -as --prefix= to specify where the executables -and support files should be installed. The only other parameter that -some users may wish to specify is the location of a suitable Tcl -installation. By default usbhost will use -the existing Tcl installation in /usr, -as provided by your Linux distribution. An alternative Tcl -installation can be specified using the parameter ---with-tcl=, or alternatively using some -combination of --with-tcl-include, ---with-tcl-lib and ---with-tcl-version.
One of the host-side executables that gets built, -usbchmod, needs to be installed with suid -root privileges. Although the Linux kernel makes it possible for -applications to perform low-level USB operations such as transmitting -bulk packets, by default access to this functionality is restricted to -programs with superuser privileges. It is undesirable to run a complex -program such as usbhost with such -privileges, especially since the program contains a general-purpose -Tcl interpreter. Therefore when usbhost -starts up and discovers that it does not have sufficient access to the -appropriate entries in /proc/bus/usb, -it spawns an instance of usbchmod to modify -the permissions on these entries. usbchmod -will only do this for a USB device "Red Hat eCos USB -test", so installing this program suid root should not -introduce any security problems.

During make install the following actions will take -place:

  1. 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.

  2. 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.

  3. A Tcl script usbhost.tcl will get installed in -the same directory as usbchmod. This Tcl -script is loaded automatically by the -usbhost executable.

  4. 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>]

  1. 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.

  2. The -h or --help option -will display usage information.

  3. 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.

  4. 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.

  5. 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.

Writing a Test

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.

Available Hardware

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:

bulk_in_endpoints

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 {








    -          …








    -      }








    -  }








    -  
bulk_in()

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: -

min_size

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. -

max_size

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. -

max_in_padding

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. -

devtab

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)"








    -      }








    -  }








    -  
bulk_out_endpoint

This is a simple list of the endpoints which can support bulk OUT - transfers. It is analogous to - bulk_in_endpoints. -

bulk_out()

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. -

control()

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. -

isochronous_in_endpoints and - isochronous_in()

These variables provide the same information as - bulk_in_endpoints and bulk_in, - but for endpoints that support isochronous IN transfers. -

isochronous_out_endpoints and - isochronous_out()

These variables provide the same information as - bulk_out_endpoints and bulk_out, - but for endpoints that support isochronous OUT transfers. -

interrupt_in_endpoints and - interrupt_in()

These variables provide the same information as - bulk_in_endpoints and bulk_in, - but for endpoints that support interrupt IN transfers. -

interrupt_out_endpoints and - interrupt_out()

These variables provide the same information as - bulk_out_endpoints and bulk_out, - but for endpoints that support interrupt OUT transfers. -

Testing Bulk 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:

endpoint

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. -

direction

This should be either in or out. -

number of transfers

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.

Data

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.

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. -

bytefill

The entire buffer will be filled with a single byte, as per - memset. -

intfill

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. -

byteseq

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. -

wordseq

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.

I/O Mechanism

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.

Transmit Size

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.

Receive Size

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.

Transmit and Receive Delays

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.

Other Types of Transfer

Support for testing other types of USB traffic such as isochronous -transfers is not yet implemented.

Starting a Test and Collecting Results

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.

Existing Test Scripts

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:

list.tcl

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. -

verbose.tcl

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. -

Possible Problems

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.


PrevHome 
Writing a USB Device Driver  
\ No newline at end of file Index: slave/v2_0/doc/makefile =================================================================== --- slave/v2_0/doc/makefile (revision 174) +++ slave/v2_0/doc/makefile (nonexistent) @@ -1,55 +0,0 @@ -#============================================================================= -# -# makefile -# -# For building the USB slave package documentation -# -#============================================================================= -#####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#### -# -# Author(s): bartv -# Date: 2001-01-11 -#####DESCRIPTIONEND#### -#============================================================================= - -TOPLEVEL := ../../../../.. -MAIN_SGML := usbs.sgml -MAIN_HTML := io-usb-slave.html -MAIN_PDF := io-usb-slave.pdf -OTHER_SGML := -PICTURES := - -include $(TOPLEVEL)/pkgconf/rules.doc Index: slave/v2_0/doc/usbs-control.html =================================================================== --- slave/v2_0/doc/usbs-control.html (revision 174) +++ slave/v2_0/doc/usbs-control.html (nonexistent) @@ -1,934 +0,0 @@ - - - - - - - - - - - -Control Endpoints -
eCos USB Slave Support
PrevNext

Control Endpoints

Name

Control Endpoints -- Control endpoint data structure

Synopsis

#include <cyg/io/usb/usbs.h>








    -








    -typedef struct usbs_control_endpoint {








    -    *hellip;








    -} usbs_control_endpoint;

usbs_control_endpoint Data Structure

The device driver for a USB slave device should supply one -usbs_control_endpoint data structure per USB -device. This corresponds to endpoint 0 which will be used for all -control message interaction between the host and that device. The data -structure is also used for internal management purposes, for example -to keep track of the current state. In a typical USB peripheral there -will only be one such data structure in the entire system, but if -there are multiple USB slave ports, allowing the peripheral to be -connected to multiple hosts, then there will be a separate data -structure for each one. The name or names of the data structures are -determined by the device drivers. For example, the SA11x0 USB device -driver package provides usbs_sa11x0_ep0.

The operations on a control endpoint do not fit cleanly into a -conventional open/read/write I/O model. For example, when the host -sends a control message to the USB peripheral this may be one of four -types: standard, class, vendor and reserved. Some or all of the -standard control messages will be handled automatically by the common -USB slave package or by the device driver itself. Other standard -control messages and the other types of control messages may be -handled by a class-specific package or by application code. Although -it would be possible to have devtab entries such as -/dev/usbs_ep0/standard and -/dev/usbs_ep0/class, and then support read and -write operations on these devtab entries, this would add significant -overhead and code complexity. Instead, all of the fields in the -control endpoint data structure are public and can be manipulated -directly by higher level code if and when required.

Control endpoints involve a number of callback functions, with -higher-level code installing suitable function pointers in the control -endpoint data structure. For example, if the peripheral involves -vendor-specific control messages then a suitable handler for these -messages should be installed. Although the exact details depend on the -device driver, typically these callback functions will be invoked at -DSR level rather than thread level. Therefore, only certain eCos -functions can be invoked; specifically, those functions that are -guaranteed not to block. If a potentially blocking function such as a -semaphore wait or a mutex lock operation is invoked from inside the -callback then the resulting behaviour is undefined, and the system as -a whole may fail. In addition, if one of the callback functions -involves significant processing effort then this may adversely affect -the system's real time characteristics. The eCos kernel documentation -should be consulted for more details of DSR handling.

Initialization

The usbs_control_endpoint data structure -contains the following fields related to initialization.

typedef struct usbs_control_endpoint {








    -    …








    -    const usbs_enumeration_data* enumeration_data;








    -    void                         (*start_fn)(usbs_control_endpoint*);








    -    …








    -};

It is the responsibility of higher-level code, usually the -application, to define the USB enumeration data. This needs to be -installed in the control endpoint data structure early on during -system startup, before the USB device is actually started and any -interaction with the host is possible. Details of the enumeration data -are supplied in the section USB Enumeration -Data. Typically, the enumeration data is constant for a given -peripheral, although it can be constructed dynamically if necessary. -However, the enumeration data cannot change while the peripheral is -connected to a host: the peripheral cannot easily claim to be a -keyboard one second and a printer the next.

The start_fn member is normally accessed -via the utility usbs_start rather -than directly. It is provided by the device driver and should be -invoked once the system is fully initialized and interaction with the -host is possible. A typical implementation would change the USB data -pins from tristated to active. If the peripheral is already plugged -into a host then the latter should detect this change and start -interacting with the peripheral, including requesting the enumeration -data.

State

There are three usbs_control_endpoint fields -related to the current state of a USB slave device, plus some state -constants and an enumeration of the possible state changes:

typedef struct usbs_control_endpoint {








    -    …








    -    int     state;








    -    void    (*state_change_fn)(struct usbs_control_endpoint*, void*,








    -                               usbs_state_change, int);








    -    void*   state_change_data;








    -    …








    -};








    -








    -#define USBS_STATE_DETACHED             0x01








    -#define USBS_STATE_ATTACHED             0x02








    -#define USBS_STATE_POWERED              0x03








    -#define USBS_STATE_DEFAULT              0x04








    -#define USBS_STATE_ADDRESSED            0x05








    -#define USBS_STATE_CONFIGURED           0x06








    -#define USBS_STATE_MASK                 0x7F








    -#define USBS_STATE_SUSPENDED            (1 << 7)








    -








    -typedef enum {








    -    USBS_STATE_CHANGE_DETACHED          = 1,








    -    USBS_STATE_CHANGE_ATTACHED          = 2,








    -    USBS_STATE_CHANGE_POWERED           = 3,








    -    USBS_STATE_CHANGE_RESET             = 4,








    -    USBS_STATE_CHANGE_ADDRESSED         = 5,








    -    USBS_STATE_CHANGE_CONFIGURED        = 6,








    -    USBS_STATE_CHANGE_DECONFIGURED      = 7,








    -    USBS_STATE_CHANGE_SUSPENDED         = 8,








    -    USBS_STATE_CHANGE_RESUMED           = 9








    -} usbs_state_change;

The USB standard defines a number of states for a given USB -peripheral. The initial state is detached, where -the peripheral is either not connected to a host at all or, from the -host's perspective, the peripheral has not started up yet because the -relevant pins are tristated. The peripheral then moves via -intermediate attached and -powered states to its default or -reset state, at which point the host and -peripheral can actually start exchanging data. The first message is -from host to peripheral and provides a unique 7-bit address within the -local USB network, resulting in a state change to -addressed. The host then requests enumeration -data and performs other initialization. If everything succeeds the -host sends a standard set-configuration control message, after which -the peripheral is configured and expected to be -up and running. Note that some USB device drivers may be unable to -distinguish between the detached, -attached and powered states -but generally this is not important to higher-level code.

A USB host should generate at least one token every millisecond. If a -peripheral fails to detect any USB traffic for a period of time then -typically this indicates that the host has entered a power-saving -mode, and the peripheral should do the same if possible. This -corresponds to the suspended bit. The actual -state is a combination of suspended and the -previous state, for example configured and -suspended rather than just -suspended. When the peripheral subsequently -detects USB traffic it would switch back to the -configured state.

The USB device driver and the common USB slave package will maintain -the current state in the control endpoint's -state field. There should be no need for -any other code to change this field, but it can be examined whenever -appropriate. In addition whenever a state change occurs the generic -code can invoke a state change callback function. By default, no such -callback function will be installed. Some class-specific packages such -as the USB-ethernet package will install a suitable function to keep -track of whether or not the host-peripheral connection is up, that is -whether or not ethernet packets can be exchanged. Application code can -also update this field. If multiple parties want to be informed of -state changes, for example both a class-specific package and -application code, then typically the application code will install its -state change handler after the class-specific package and is -responsible for chaining into the package's handler.

The state change callback function is invoked with four arguments. The -first identifies the control endpoint. The second is an arbitrary -pointer: higher-level code can fill in the -state_change_data field to set this. The -third argument specifies the state change that has occurred, and the -last argument supplies the previous state (the new state is readily -available from the control endpoint structure).

eCos does not provide any utility functions for updating or examining -the state_change_fn or -state_change_data fields. Instead, it is -expected that the fields in the -usbs_control_endpoint data structure will be -manipulated directly. Any utility functions would do just this, but -at the cost of increased code and cpu overheads.

Standard Control Messages

typedef struct usbs_control_endpoint {








    -    …








    -    unsigned char       control_buffer[8];








    -    usbs_control_return (*standard_control_fn)(struct usbs_control_endpoint*, void*);








    -    void*               standard_control_data;








    -    …








    -} usbs_control_endpoint;








    -








    -typedef enum {








    -    USBS_CONTROL_RETURN_HANDLED = 0,








    -    USBS_CONTROL_RETURN_UNKNOWN = 1,








    -    USBS_CONTROL_RETURN_STALL   = 2








    -} usbs_control_return;








    -








    -extern usbs_control_return usbs_handle_standard_control(struct usbs_control_endpoint*);

When a USB peripheral is connected to the host it must always respond -to control messages sent to endpoint 0. Control messages always -consist of an initial eight-byte header, containing fields such as a -request type. This may be followed by a further data transfer, either -from host to peripheral or from peripheral to host. The way this is -handled is described in the Buffer Management section below.

The USB device driver will always accept the initial eight-byte -header, storing it in the control_buffer -field. Then it determines the request type: standard, class, vendor, -or reserved. The way in which the last three of these are processed is -described in the section Other -Control Messages. Some -standard control messages will be handled by the device driver itself; -typically the set-address request and the -get-status, set-feature and -clear-feature requests when applied to endpoints.

If a standard control message cannot be handled by the device driver -itself, the driver checks the -standard_control_fn field in the control -endpoint data structure. If higher-level code has installed a suitable -callback function then this will be invoked with two argument, the -control endpoint data structure itself and the -standard_control_data field. The latter -allows the higher level code to associate arbitrary data with the -control endpoint. The callback function can return one of three -values: HANDLED to indicate that the request has -been processed; UNKNOWN if the message should be -handled by the default code; or STALL to indicate -an error condition. If higher level code has not installed a callback -function or if the callback function has returned -UNKNOWN then the device driver will invoke a -default handler, usbs_handle_standard_control -provided by the common USB slave package.

The default handler can cope with all of the standard control messages -for a simple USB peripheral. However, if the peripheral involves -multiple configurations, multiple interfaces in a configuration, or -alternate settings for an interface, then this cannot be handled by -generic code. For example, a multimedia peripheral may support various -alternate settings for a given data source with different bandwidth -requirements, and the host can select a setting that takes into -account the current load. Clearly higher-level code needs to be aware -when the host changes the current setting, so that it can adjust the -rate at which data is fed to or retrieved from the host. Therefore the -higher-level code needs to install its own standard control callback -and process appropriate messages, rather than leaving these to the -default handler.

The default handler will take care of the -get-descriptor request used to obtain the -enumeration data. It has support for string descriptors but ignores -language encoding issues. If language encoding is important for the -peripheral then this will have to be handled by an -application-specific standard control handler.

The header file <cyg/io/usb/usb.h> defines various -constants related to control messages, for example the function codes -corresponding to the standard request types. This header file is -provided by the common USB package, not by the USB slave package, -since the information is also relevant to USB hosts.

Other Control Messages

typedef struct usbs_control_endpoint {








    -    …








    -    usbs_control_return (*class_control_fn)(struct usbs_control_endpoint*, void*);








    -    void*               class_control_data;








    -    usbs_control_return (*vendor_control_fn)(struct usbs_control_endpoint*, void*);








    -    void*               vendor_control_data;








    -    usbs_control_return (*reserved_control_fn)(struct usbs_control_endpoint*, void*);








    -    void*               reserved_control_data;








    -    …








    -} usbs_control_endpoint;

Non-standard control messages always have to be processed by -higher-level code. This could be class-specific packages. For example, -the USB-ethernet package will handle requests for getting the MAC -address and for enabling or disabling promiscuous mode. In all cases -the device driver will store the initial request in the -control_buffer field, check for an -appropriate handler, and invoke it with details of the control -endpoint and any handler-specific data that has been installed -alongside the handler itself. The handler should return either -USBS_CONTROL_RETURN_HANDLED to report success or -USBS_CONTROL_RETURN_STALL to report failure. The -device driver will report this to the host.

If there are multiple parties interested in a particular type of -control messages, it is the responsibility of application code to -install an appropriate handler and process the requests appropriately.

Buffer Management

typedef struct usbs_control_endpoint {








    -    …








    -    unsigned char*      buffer;








    -    int                 buffer_size;








    -    void                (*fill_buffer_fn)(struct usbs_control_endpoint*);








    -    void*               fill_data;








    -    int                 fill_index;








    -    usbs_control_return (*complete_fn)(struct usbs_control_endpoint*, int);








    -    …








    -} usbs_control_endpoint;

Many USB control messages involve transferring more data than just the -initial eight-byte header. The header indicates the direction of the -transfer, OUT for host to peripheral or IN for peripheral to host. -It also specifies a length field, which is exact for an OUT transfer -or an upper bound for an IN transfer. Control message handlers can -manipulate six fields within the control endpoint data structure to -ensure that the transfer happens correctly.

For an OUT transfer, the handler should examine the length field in -the header and provide a single buffer for all the data. A -class-specific protocol would typically impose an upper bound on the -amount of data, allowing the buffer to be allocated statically. -The handler should update the buffer and -complete_fn fields. When all the data has -been transferred the completion callback will be invoked, and its -return value determines the response sent back to the host. The USB -standard allows for a new control message to be sent before the -current transfer has completed, effectively cancelling the current -operation. When this happens the completion function will also be -invoked. The second argument to the completion function specifies what -has happened, with a value of 0 indicating success and an error code -such as -EPIPE or -EIO -indicating that the current transfer has been cancelled.

IN transfers are a little bit more complicated. The required -information, for example the enumeration data, may not be in a single -contiguous buffer. Instead a mechanism is provided by which the buffer -can be refilled, thus allowing the transfer to move from one record to -the next. Essentially, the transfer operates as follows:

  1. When the host requests another chunk of data (typically eight bytes), -the USB device driver will examine the -buffer_size field. If non-zero then -buffer contains at least one more byte of -data, and then buffer_size is decremented.

  2. When buffer_size has dropped to 0, the -fill_buffer_fn field will be examined. If -non-null it will be invoked to refill the buffer.

  3. The fill_data and -fill_index fields are not used by the -device driver. Instead these fields are available to the refill -function to keep track of the current state of the transfer.

  4. When buffer_size is 0 and -fill_buffer_fn is NULL, no more data is -available and the transfer has completed.

  5. Optionally a completion function can be installed. This will be -invoked with 0 if the transfer completes successfully, or with an -error code if the transfer is cancelled because of another control -messsage.

If the requested data is contiguous then the only fields that need -to be manipulated are buffer and -buffer_size, and optionally -complete_fn. If the requested data is not -contiguous then the initial control message handler should update -fill_buffer_fn and some or all of the other -fields, as required. An example of this is the handling of the -standard get-descriptor control message by -usbs_handle_standard_control.

Polling Support

typedef struct usbs_control_endpoint {








    -    void                (*poll_fn)(struct usbs_control_endpoint*);








    -    int                 interrupt_vector;








    -    …








    -} usbs_control_endpoint;

In nearly all circumstances USB I/O should be interrupt-driven. -However, there are special environments such as RedBoot where polled -operation may be appropriate. If the device driver can operate in -polled mode then it will provide a suitable function via the -poll_fn field, and higher-level code can -invoke this regularly. This polling function will take care of all -endpoints associated with the device, not just the control endpoint. -If the USB hardware involves a single interrupt vector then this will -be identified in the data structure as well.


PrevHomeNext
Halted Endpoints Data Endpoints
\ No newline at end of file Index: slave/v2_0/doc/usbs.sgml =================================================================== --- slave/v2_0/doc/usbs.sgml (revision 174) +++ slave/v2_0/doc/usbs.sgml (nonexistent) @@ -1,3540 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eCos USB Slave Support - - - - - -Introduction - - -Introduction -eCos support for USB slave devices - - -Introduction - -The eCos USB slave support allows developers to produce USB -peripherals. It consists of a number of different eCos packages: - - - - - -Device drivers for specific implementations of USB slave hardware, for -example the on-chip USB Device Controller provided by the Intel SA1110 -processor. A typical USB peripheral will only provide one USB slave -port and therefore only one such device driver package will be needed. -Usually the device driver package will be loaded automatically when -you create an eCos configuration for target hardware that has a USB -slave device. If you select a target which does have a USB slave -device but no USB device driver is loaded, this implies that no such -device driver is currently available. - - - - - -The common USB slave package. This serves two purposes. It defines the -API that specific device drivers should implement. It also provides -various utilities that will be needed by most USB device drivers and -applications, such as handlers for standard control messages. -Usually this package will be loaded automatically at the same time as -the USB device driver. - - - - - -The common USB package. This merely provides some information common -to both the host and slave sides of USB, such as details of the -control protocol. It is also used to place the other USB-related -packages appropriately in the overall configuration hierarchy. Usually -this package will be loaded at the same time as the USB device driver. - - - - - -Class-specific USB support packages. These make it easier to develop -specific classes of USB peripheral, such as a USB-ethernet device. If -no suitable package is available for a given class of peripheral then -the USB device driver can instead be accessed directly from -application code. Such packages will never be loaded automatically -since the configuration system has no way of knowing what class of USB -peripheral is being developed. Instead developers have to add the -appropriate package or packages explicitly. - - - - - - -These packages only provide support for developing USB peripherals, -not USB hosts. - - - -USB Concepts - -Information about USB can be obtained from a number of sources -including the USB Implementers Forum -web site. Only a brief summary is provided here. - - -A USB network is asymmetrical: it consists of a single host, one or -more slave devices, and possibly some number of intermediate hubs. The -host side is significantly more complicated than the slave side. -Essentially, all operations are initiated by the host. For example, if -the host needs to receive some data from a particular USB peripheral -then it will send an IN token to that peripheral; the latter should -respond with either a NAK or with appropriate data. Similarly, when -the host wants to transmit data to a peripheral it will send an OUT -token followed by the data; the peripheral will return a NAK if it is -currently unable to receive more data or if there was corruption, -otherwise it will return an ACK. All transfers are check-summed and -there is a clearly-defined error recovery process. USB peripherals can -only interact with the host, not with each other. - - -USB supports four different types of communication: control messages, -interrupt transfers, isochronous transfers, and bulk transfers. -Control messages are further subdivided into four categories: -standard, class, vendor and a reserved category. All USB peripherals -must respond to certain standard control messages, and usually this -will be handled by the common USB slave package (for complicated -peripherals, application support will be needed). Class and vendor -control messages may be handled by an class-specific USB support -package, for example the USB-ethernet package will handle control -messages such as getting the MAC address or enabling/disabling -promiscuous mode. Alternatively, some or all of these messages will -have to be handled by application code. - - -Interrupt transfers are used for devices which need to be polled -regularly. For example, a USB keyboard might be polled once every -millisecond. The host will not poll the device more frequently than -this, so interrupt transfers are best suited to peripherals that -involve a relatively small amount of data. Isochronous transfers are -intended for multimedia-related peripherals where typically a large -amount of video or audio data needs to be exchanged continuously. -Given appropriate host support a USB peripheral can reserve some of -the available bandwidth. Isochronous transfers are not reliable; if a -particular packet is corrupted then it will just be discarded and -software is expected to recover from this. Bulk transfers are used for -everything else: after taking care of any pending control, isochronous -and interrupt transfers the host will use whatever bandwidth remains -for bulk transfers. Bulk transfers are reliable. - - -Transfers are organized into USB packets, with the details depending -on the transfer type. Control messages always involve an initial -8-byte packet from host to peripheral, optionally followed by some -additional packets; in theory these additional packets can be up to 64 -bytes, but hardware may limit it to 8 bytes. Interrupt transfers -involve a single packet of up to 64 bytes. Isochronous transfers -involve a single packet of up to 1024 bytes. Bulk transfers involve -multiple packets. There will be some number, possibly zero, of 64-byte -packets. The transfer is terminated by a single packet of less than 64 -bytes. If the transfer involves an exact multiple of 64 bytes than the -final packet will be 0 bytes, consisting of just a header and checksum -which typically will be generated by the hardware. There is no -pre-defined limit on the size of a bulk transfer. Instead higher-level -protocols are expected to handle this, so for a USB-ethernet -peripheral the protocol could impose a limit of 1514 bytes of data -plus maybe some additional protocol overhead. - - -Transfers from the host to a peripheral are addressed not just to that -peripheral but to a specific endpoint within that peripheral. -Similarly, the host requests incoming data from a specific endpoint -rather than from the peripheral as a whole. For example, a combined -keyboard/touchpad device could provide the keyboard events on endpoint -1 and the mouse events on endpoint 2. A given USB peripheral can have -up to 16 endpoints for incoming data and another 16 for outgoing data. -However, given the comparatively high speed of USB I/O this endpoint -addressing is typically implemented in hardware rather than software, -and the hardware will only implement a small number of endpoints. -Endpoint 0 is generally used only for control messages. - - -In practice, many of these details are irrelevant to application code -or to class packages. Instead, such higher-level code usually just -performs blocking read and -write, or non-blocking USB-specific calls, to -transfer data between host and target via a specific endpoint. Control -messages are more complicated but are usually handled by existing -code. - - -When a USB peripheral is plugged into the host there is an initial -enumeration and configuration process. The peripheral provides -information such as its class of device (audio, video, etc.), a -vendor id, which endpoints should be used for what kind of data, and -so on. The host OS uses this information to identify a suitable host -device driver. This could be a generic driver for a class of -peripherals, or it could be a vendor-specific driver. Assuming a -suitable driver is installed the host will then activate the USB -peripheral and perform additional application-specific initialisation. -For example for a USB-ethernet device this would involve obtaining an -ethernet MAC address. Most USB peripherals will be fairly simple, but -it is possible to build multifunction peripherals with multiple -configurations, interfaces, and alternate interface settings. - - -It is not possible for any of the eCos packages to generate all the -enumeration data automatically. Some of the required information such -as the vendor id cannot be supplied by generic packages; only by the -application developer. Class support code such as the USB-ethernet -package could in theory supply some of the information automatically, -but there are also hardware dependencies such as which endpoints get -used for incoming and outgoing ethernet frames. Instead it is the -responsibility of the application developer to provide all the -enumeration data and perform some additional initialisation. In -addition, the common USB slave package can handle all the standard -control messages for a simple USB peripheral, but for something like a -multifunction peripheral additional application support is needed. - - - -The initial implementation of the eCos USB slave packages involved -hardware that only supported control and bulk transfers, not -isochronous or interrupt. There may be future changes to the USB -code and API to allow for isochronous and interrupt transfers, -especially the former. Other changes may be required to support -different USB devices. At present there is no support for USB remote -wakeups, since again it is not supported by the hardware. - - - - -eCos USB I/O Facilities - -For protocols other than control messages, eCos provides two ways of -performing USB I/O. The first involves device table or devtab entries such -as /dev/usb1r, -with one entry per endpoint per USB device. It is possible to -open these devices and use conventional blocking -I/O functions such as read and -write to exchange data between host and -peripheral. - - -There is also a lower-level USB-specific API, consisting of functions -such as usbs_start_rx_buffer. -A USB device driver will supply a data structure for each endpoint, -for example a usbs_rx_endpoint -structure for every receive endpoint. The first argument to -usbs_start_rx_buffer should be a pointer to such -a data structure. The USB-specific API is non-blocking: the initial -call merely starts the transfer; some time later, once the transfer -has completed or has been aborted, the device driver will invoke a -completion function. - - -Control messages are different. With four different categories of -control messages including application and vendor specific ones, the -conventional -open/read/write -model of I/O cannot easily be applied. Instead, a USB device driver -will supply a usbs_control_endpoint -data structure which can be manipulated appropriately. In practice the -standard control messages will usually be handled by the common USB -slave package, and other control messages will be handled by -class-specific code such as the USB-ethernet package. Typically, -application code remains responsible for supplying the enumeration data and for actually starting up the USB device. - - - -Enabling the USB code - -If the target hardware contains a USB slave device then the -appropriate USB device driver and the common packages will typically -be loaded into the configuration automatically when that target is -selected (assuming a suitable device driver exists). However, the -driver will not necessarily be active. For example a processor might -have an on-chip USB device, but not all applications using that -processor will want to use USB functionality. Hence by default the USB -device is disabled, ensuring that applications do not suffer any -memory or other penalties for functionality that is not required. - - -If the application developer explicitly adds a class support package -such as the USB-ethernet one then this implies that the USB device is -actually needed, and the device will be enabled automatically. -However, if no suitable class package is available and the USB device -will instead be accessed by application code, it is necessary to -enable the USB device manually. Usually the easiest way to do this is -to enable the configuration option -CYGGLO_IO_USB_SLAVE_APPLICATION, and the USB device -driver and related packages will adjust accordingly. Alternatively, -the device driver may provide some configuration options to provide -more fine-grained control. - - - - - - - - - - -USB Enumeration Data - - -Enumeration Data -The USB enumeration data structures - - - - -#include <cyg/io/usb/usb.h> -#include <cyg/io/usb/usbs.h> - -typedef struct usb_device_descriptor { - … -} usb_device_descriptor __attribute__((packed)); - -typedef struct usb_configuration_descriptor { - … -} usb_configuration_descriptor __attribute__((packed)); - -typedef struct usb_interface_descriptor { - … -} usb_interface_descriptor __attribute__((packed)); - -typedef struct usb_endpoint_descriptor { - … -} usb_endpoint_descriptor; - -typedef struct usbs_enumeration_data { - usb_device_descriptor device; - int total_number_interfaces; - int total_number_endpoints; - int total_number_strings; - const usb_configuration_descriptor* configurations; - const usb_interface_descriptor* interfaces; - const usb_endpoint_descriptor* endpoints; - const unsigned char** strings; -} usbs_enumeration_data; - - - -USB Enumeration Data - -When a USB host detects that a peripheral has been plugged in or -powered up, one of the first steps is to ask the peripheral to -describe itself by supplying enumeration data. Some of this data -depends on the class of peripheral. Other fields are vendor-specific. -There is also a dependency on the hardware, specifically which -endpoints are available should be used. In general it is not possible -for generic code to provide this information, so it is the -responsibility of application code to provide a suitable -usbs_enumeration_data data structure and -install it in the endpoint 0 data structure during initialization. -This must happen before the USB device is enabled by a call to -usbs_start, for example: - - -const usbs_enumeration_data usb_enum_data = { - … -}; - -int -main(int argc, char** argv) -{ - usbs_sa11x0_ep0.enumeration_data = &usb_enum_data; - … - usbs_start(&usbs_sa11x0_ep0); - … -} - - -For most applications the enumeration data will be static, although -the usbs_enumeration_data structure can be -filled in at run-time if necessary. Full details of the enumeration -data can be found in the Universal Serial Bus specification obtainable -from the USB Implementers Forum web -site, although the meaning of most fields is fairly obvious. -The various data structures and utility macros are defined in the -header files cyg/io/usb/usb.h -and cyg/io/usb/usbs.h. Note -that the example code below makes use of the gcc labelled element -extension. - - -<structname>usb_device_descriptor</structname> - -The main information about a USB peripheral comes from a single -usb_device_descriptor structure, which is -embedded in the usbs_enumeration_data -structure. A typical example might look like this: - - -const 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, - vendor_hi: 0x42, - product_lo: 0x42, - product_hi: 0x42, - device_lo: 0x00, - device_hi: 0x01, - manufacturer_str: 1, - product_str: 2, - serial_number_str: 0, - number_configurations: 1 - }, - … -}; - - -The length and type fields are specified by the USB standard. The -usb_spec_lo and -usb_spec_hi fields identify the particular -revision of the standard that the peripheral implements, for example -revision 1.1. - - -The device class, subclass, and protocol fields are used by generic -host-side USB software to determine which host-side device driver -should be loaded to interact with the peripheral. A number of standard -classes are defined, for example mass-storage devices and -human-interface devices. If a peripheral implements one of the -standard classes then a standard existing host-side device driver may -exist, eliminating the need to write a custom driver. The value -0xFF (VENDOR) is reserved for -peripherals that implement a vendor-specific protocol rather than a -standard one. Such peripherals will require a custom host-side device -driver. The value 0x00 -(INTERFACE) is reserved and indicates that the -protocol used by the peripheral is defined at the interface level -rather than for the peripheral as a whole. - - -The max_package_size field specifies the -maximum length of a control message. There is a lower bound of eight -bytes, and typical hardware will not support anything larger because -control messages are usually small and not performance-critical. - - -The vendor_lo and -vendor_hi fields specify a vendor id, which -must be obtained from the USB Implementor's Forum. The numbers used in -the code fragment above are examples only and must not be used in real -USB peripherals. The product identifier is determined by the vendor, -and different USB peripherals should use different identifiers. The -device identifier field should indicate a release number in -binary-coded decimal. - - -The above fields are all numerical in nature. A USB peripheral can -also provide a number of strings as described below, for example the name of the -vendor can be provided. The various _str -fields act as indices into an array of strings, with index 0 -indicating that no string is available. - - -A typical USB peripheral involves just a single configuration. However -more complicated peripherals can support multiple configurations. Only -one configuration will be active at any one time, and the host will -switch between them as appropriate. If a peripheral does involve -multiple configurations then typically it will be the responsibility -of application code to handle the standard -set-configuration control message. - - - -<structname>usb_configuration_descriptor</structname> - -A USB peripheral involves at least one and possible several different -configurations. The usbs_enumeration_data -structure requires a pointer to an array, possibly of length 1, of -usb_configuration_descriptor structures. -Usually a single structure suffices: - - -const 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, 2), - total_length_hi: USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(1, 2), - number_interfaces: 1, - configuration_id: 1, - configuration_str: 0, - attributes: USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED | - USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED, - max_power: 50 -}; - -const usbs_enumeration_data usb_enum_data = { - … - configurations: &usb_configuration, - … -}; - - -The values for the length and -type fields are determined by the standard. -The total_length field depends on the -number of interfaces and endpoints used by this configuration, and -convenience macros are provided to calculate this: the first argument -to the macros specify the number of interfaces, the second the number -of endpoints. The number_interfaces field -is self-explanatory. If the peripheral involves multiple -configurations then each one must have a unique id, and this will be -used in the set-configuration control message. The id -0 is reserved, and a set-configuration control -message that uses this id indicates that the peripheral should be -inactive. Configurations can have a string description if required. -The attributes field must have the -REQUIRED bit set; the -SELF_POWERED bit informs the host that the -peripheral has its own power supply and will not draw any power over -the bus, leaving more bus power available to other peripherals; the -REMOTE_WAKEUP bit is used if the peripheral can -interrupt the host when the latter is in power-saving mode. For -peripherals that are not self-powered, the -max_power field specifies the power -requirements in units of 2mA. - - - -<structname>usb_interface_descriptor</structname> - -A USB configuration involves one or more interfaces, typically -corresponding to different streams of data. For example, one interface -might involve video data while another interface is for audio. -Multiple interfaces in a single configuration will be active at the -same time. - - -const usb_interface_descriptor usb_interface = { - length: USB_INTERFACE_DESCRIPTOR_LENGTH, - type: USB_INTERFACE_DESCRIPTOR_TYPE, - interface_id: 0, - alternate_setting: 0, - number_endpoints: 2, - interface_class: USB_INTERFACE_DESCRIPTOR_CLASS_VENDOR, - interface_subclass: USB_INTERFACE_DESCRIPTOR_SUBCLASS_VENDOR, - interface_protocol: USB_INTERFACE_DESCRIPTOR_PROTOCOL_VENDOR, - interface_str: 0 -}; - -const usbs_enumeration_data usb_enum_data = { - … - total_number_interfaces: 1, - interfaces: &usb_interface, - … -}; - - -Again, the length and -type fields are specified by the standard. -Each interface within a configuration requires its own id. However, a -given interface may have several alternate settings, in other words -entries in the interfaces array with the same id but different -alternate_setting fields. For example, -there might be one setting which requires a bandwidth of 100K/s and -another setting that only needs 50K/s. The host can use the standard -set-interface control message to choose the most appropriate setting. -The handling of this request is the responsibility of higher-level -code, so the application may have to install its own handler. - - -The number of endpoints used by an interface is specified in the -number_endpoints field. Exact details of -which endpoints are used is held in a separate array of endpoint -descriptors. The class, subclass and protocol fields are used by -host-side code to determine which host-side device driver should -handle this specific interface. Usually this is determined on a -per-peripheral basis in the -usb_device_descriptor structure, but that can -defer the details to individual interfaces. A per-interface string -is allowed as well. - - -For USB peripherals involving multiple configurations, the array of -usb_interface_descriptor structures should -first contain all the interfaces for the first configuration, then all -the interfaces for the second configuration, and so on. - - - -<structname>usb_endpoint_descriptor</structname> - -The host also needs information about which endpoint should be used -for what. This involves an array of endpoint descriptors: - - -const usb_endpoint_descriptor usb_endpoints[] = { - { - length: USB_ENDPOINT_DESCRIPTOR_LENGTH, - type: USB_ENDPOINT_DESCRIPTOR_TYPE, - endpoint: USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT | 1, - attributes: USB_ENDPOINT_DESCRIPTOR_ATTR_BULK, - max_packet_lo: 64, - max_packet_hi: 0, - interval: 0 - }, - { - length: USB_ENDPOINT_DESCRIPTOR_LENGTH, - type: USB_ENDPOINT_DESCRIPTOR_TYPE, - endpoint: USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN | 2, - attributes: USB_ENDPOINT_DESCRIPTOR_ATTR_BULK, - max_packet_lo: 64, - max_packet_hi: 0, - interval: 0 - } -}; - -const usbs_enumeration_data usb_enum_data = { - … - total_number_endpoints: 2, - endpoints: usb_endpoints, - … -}; - - -As usual the values for the length and -type fields are specified by the standard. -The endpoint field gives both the endpoint -number and the direction, so in the above example endpoint 1 is used -for OUT (host to peripheral) transfers and endpoint 2 is used for IN -(peripheral to host) transfers. The -attributes field indicates the USB protocol -that should be used on this endpoint: CONTROL, -ISOCHRONOUS, BULK or -INTERRUPT. The -max_packet field specifies the maximum size -of a single USB packet. For bulk transfers this will typically be 64 -bytes. For isochronous transfers this can be up to 1023 bytes. For -interrupt transfers it can be up to 64 bytes, although usually a -smaller value will be used. The interval -field is ignored for control and bulk transfers. For isochronous -transfers it should be set to 1. For interrupt transfers it can be a -value between 1 and 255, and indicates the number of milliseconds -between successive polling operations. - - -For USB peripherals involving multiple configurations or interfaces -the array of endpoint descriptors should be organized sequentially: -first the endpoints corresponding to the first interface of the first -configuration, then the second interface in that configuration, and so -on; then all the endpoints for all the interfaces in the second -configuration; etc. - - - -Strings - -The enumeration data can contain a number of strings with additional -information. Unicode encoding is used for the strings, and it is -possible for a peripheral to supply a given string in multiple -languages using the appropriate characters. The first two bytes of -each string give a length and type field. The first string is special; -after the two bytes header it consists of an array of 2-byte language -id codes, indicating the supported languages. The language code -0x0409 corresponds to English (United States). - - -const unsigned char* usb_strings[] = { - "\004\003\011\004", - "\020\003R\000e\000d\000 \000H\000a\000t\000" -}; - -const usbs_enumeration_data usb_enum_data = { - … - total_number_strings: 2, - strings: usb_strings, - … -}; - - -The default handler for standard control messages assumes that the -peripheral only uses a single language. If this is not the case then -higher-level code will have to handle the standard get-descriptor -control messages when a string descriptor is requested. - - - -<structname>usbs_enumeration_data</structname> - -The usbs_enumeration_data data structure -collects together all the various descriptors that make up the -enumeration data. It is the responsibility of application code to -supply a suitable data structure and install it in the control -endpoints's enumeration_data field before -the USB device is started. - - - - - - - - - - - -Starting up a USB Device - - -usbs_start -Starting up a USB Device - - - - - -#include <cyg/io/usb/usbs.h> - - -void usbs_start -usbs_control_endpoint* ep0 - - - - -Description - -Initializing a USB device requires some support from higher-level -code, typically the application, in the form of enumeration data. -Hence it is not possible for the low-level USB driver to activate a -USB device itself. Instead the higher-level code has to take care of -this by invoking usbs_start. This function takes -a pointer to a USB control endpoint data structure. USB device drivers -should provide exactly one such data structure for every USB device, -so the pointer uniquely identifies the device. - - -const usbs_enumeration_data usb_enum_data = { - … -}; - -int -main(int argc, char** argv) -{ - usbs_sa11x0_ep0.enumeration_data = &usb_enum_data; - … - usbs_start(&usbs_sa11x0_ep0); - … -} - - -The exact behaviour of usbs_start depends on the -USB hardware and the device driver. A typical implementation would -change the USB data pins from tristated to active. If the peripheral -is already plugged into a host then the latter should detect this -change and start interacting with the peripheral, including requesting -the enumeration data. Some of this may happen before -usbs_start returns, but given that multiple -interactions between USB host and peripheral are required it is likely -that the function will return before the peripheral is fully -configured. Control endpoints provide a mechanism for informing -higher-level code of USB state changes. -usbs_start will return even if the peripheral is -not currently connected to a host: it will not block until the -connection is established. - - -usbs_start should only be called once for a given -USB device. There are no defined error conditions. Note that the -function affects the entire USB device and not just the control -endpoint: there is no need to start any data endpoints as well. - - - - - - - - - -Devtab Entries - - -Devtab Entries -Data endpoint data structure - - - - -/dev/usb0c -/dev/usb1r -/dev/usb2w - - - -Devtab Entries - -USB device drivers provide two ways of transferring data between host -and peripheral. The first involves USB-specific functionality such as -usbs_start_rx_buffer. -This provides non-blocking I/O: a transfer is started, and some time -later the device driver will call a supplied completion function. The -second uses the conventional I/O model: there are entries in the -device table corresponding to the various endpoints. Standard calls -such as open can then be used to get a suitable -handle. Actual I/O happens via blocking read and -write calls. In practice the blocking operations -are simply implemented using the underlying non-blocking -functionality. - - -Each endpoint will have its own devtab entry. The exact names are -controlled by the device driver package, but typically the root will -be /dev/usb. This is followed by one or more -decimal digits giving the endpoint number, followed by -c for a control endpoint, r for -a receive endpoint (host to peripheral), and w for -a transmit endpoint (peripheral to host). If the target hardware -involves more than one USB device then different roots should be used, -for example /dev/usb0c and -/dev/usb1_0c. This may require explicit -manipulation of device driver configuration options by the application -developer. - - -At present the devtab entry for a control endpoint does not support -any I/O operations. - - -<function>write</function> operations - -cyg_io_write and similar functions in -higher-level packages can be used to perform a transfer from -peripheral to host. Successive write operations will not be coalesced. -For example, when doing a 1000 byte write to an endpoint that uses the -bulk transfer protocol this will involve 15 full-size 64-byte packets -and a terminating 40-byte packet. USB device drivers are not expected -to do any locking, and if higher-level code performs multiple -concurrent write operations on a single endpoint then the resulting -behaviour is undefined. - - -A USB write operation will never transfer less -data than specified. It is the responsibility of higher-level code to -ensure that the amount of data being transferred is acceptable to the -host-side code. Usually this will be defined by a higher-level -protocol. If an attempt is made to transfer more data than the host -expects then the resulting behaviour is undefined. - - -There are two likely error conditions. EPIPE -indicates that the connection between host and target has been broken. -EAGAIN indicates that the endpoint has been -stalled, either at the request of the host or by other activity -inside the peripheral. - - - -<function>read</function> operations - -cyg_io_read and similar functions in higher-level -packages can be used to perform a transfer from host to peripheral. -This should be a complete transfer: higher-level protocols should -define an upper bound on the amount of data being transferred, and the -read operation should involve at least this -amount of data. The return value will indicate the actual transfer -size, which may be less than requested. - - -Some device drivers may support partial reads, but USB device drivers -are not expected to perform any buffering because that involves both -memory and code overheads. One technique that may work for bulk -transfers is to exploit the fact that such transfers happen in 64-byte -packets. It is possible to read an initial 64 -bytes, corresponding to the first packet in the transfer. These 64 -bytes can then be examined to determine the total transfer size, and -the remaining data can be transferred in another -read operation. This technique is not guaranteed -to work with all USB hardware. Also, if the delay between accepting -the first packet and the remainder of the transfer is excessive then -this could cause timeout problems for the host-side software. For -these reasons the use of partial reads should be avoided. - - -There are two likely error conditions. EPIPE -indicates that the connection between host and target has been broken. -EAGAIN indicates that the endpoint has been -stalled, either at the request of the host or by other activity -inside the peripheral. - - -USB device drivers are not expected to do any locking. If higher-level -code performs multiple concurrent read operations on a single endpoint -then the resulting behaviour is undefined. - - - -<function>select</function> operations - -Typical USB device drivers will not provide any support for -select. Consider bulk transfers from the host to -the peripheral. At the USB device driver level there is no way of -knowing in advance how large a transfer will be, so it is not feasible -for the device driver to buffer the entire transfer. It may be -possible to buffer part of the transfer, for example the first 64-byte -packet, and copy this into application space at the start of a -read, but this adds code and memory overheads. -Worse, it means that there is an unknown but potentially long delay -between a peripheral accepting the first packet of a transfer and the -remaining packets, which could confuse or upset the host-side -software. - - -With some USB hardware it may be possible for the device driver to -detect OUT tokens from the host without actually accepting the data, -and this would indicate that a read is likely to -succeed. However, it would not be reliable since the host-side I/O -operation could time out. A similar mechanism could be used to -implement select for outgoing data, but again -this would not be reliable. - - -Some device drivers may provide partial support for -select anyway, possibly under the control of a -configuration option. The device driver's documentation should be -consulted for further information. It is also worth noting that the -USB-specific non-blocking API can often be used as an alternative to -select. - - - -<function>get_config</function> and -<function>set_config</function> operations - -There are no set_config or -get_config (also known as -ioctl) operations defined for USB devices. -Some device drivers may provide hardware-specific facilities this way. - - - -Currently the USB-specific functions related to halted endpoints cannot be accessed readily -via devtab entries. This functionality should probably be made -available via set_config and -get_config. It may also prove useful to provide -a get_config operation that maps from the -devtab entries to the underlying endpoint data structures. - - - - -Presence - -The devtab entries are optional. If the USB device is accessed -primarily by class-specific code such as the USB-ethernet package and -that package uses the USB-specific API directly, the devtab entries -are redundant. Even if application code does need to access the USB -device, the non-blocking API may be more convenient than the blocking -I/O provided via the devtab entries. In these cases the devtab entries -serve no useful purpose, but they still impose a memory overhead. It -is possible to suppress the presence of these entries by disabling the -configuration option -CYGGLO_IO_USB_SLAVE_PROVIDE_DEVTAB_ENTRIES. - - - - - - - - - - -Receiving Data from the Host - - -usbs_start_rx_buffer -Receiving Data from the Host - - - - - -#include <cyg/io/usb/usbs.h> - - -void usbs_start_rx_buffer -usbs_rx_endpoint* ep -unsigned char* buffer -int length -void (*)(void*,int) complete_fn -void * complete_data - - - -void usbs_start_rx -usbs_rx_endpoint* ep - - - - - -<function>Description</function> - -usbs_start_rx_buffer is a USB-specific function -to accept a transfer from host to peripheral. It can be used for bulk, -interrupt or isochronous transfers, but not for control messages. -Instead those involve manipulating the usbs_control_endpoint -data structure directly. The function takes five arguments: - - - - -The first argument identifies the specific endpoint that should be -used. Different USB devices will support different sets of endpoints -and the device driver will provide appropriate data structures. The -device driver's documentation should be consulted for details of which -endpoints are available. - - - - -The buffer and length -arguments control the actual transfer. USB device drivers are not -expected to perform any buffering or to support partial transfers, so -the length specified should correspond to the maximum transfer that is -currently possible and the buffer should be at least this large. For -isochronous transfers the USB specification imposes an upper bound of -1023 bytes, and a smaller limit may be set in the enumeration data. Interrupt -transfers are similarly straightforward with an upper bound of 64 -bytes, or less as per the enumeration data. Bulk transfers are more -complicated because they can involve multiple 64-byte packets plus a -terminating packet of less than 64 bytes, so there is no predefined -limit on the transfer size. Instead it is left to higher-level -protocols to specify an appropriate upper bound. - - -One technique that may work for bulk transfers is to exploit the fact -that such transfers happen in 64-byte packets: it may be possible to -receive an initial 64 bytes, corresponding to the first packet in the -transfer; these 64 bytes can then be examined to determine the total -transfer size, and the remaining data can be transferred in another -receive operation. This technique is not guaranteed to work with all -USB hardware. Also, if the delay between accepting the first packet and -the remainder of the transfer is excessive then this could cause -timeout problems for the host-side software. For these reasons this -technique should be avoided. - - - - -usbs_start_rx_buffer is non-blocking. It merely -starts the receive operation, and does not wait for completion. At -some later point the USB device driver will invoke the completion -function parameter with two arguments: the completion data defined by -the last parameter and a result field. A result >= -0 indicates a successful transfer of that many -bytes, which may be less than the upper bound imposed by the -length argument. A result < -0 indicates an error. The most likely errors are --EPIPE to indicate that the connection between the -host and the target has been broken, and -EAGAIN -for when the endpoint has been halted. Specific USB device drivers may -specify additional error conditions. - - - - -The normal sequence of events is that the USB device driver will -update the appropriate hardware registers. At some point after that -the host will attempt to send data by transmitting an OUT token -followed by a data packet, and since a receive operation is now in -progress the data will be accepted and ACK'd. If there were no receive -operation then the peripheral would instead generate a NAK. The USB -hardware will generate an interrupt once the whole packet has been -received, and the USB device driver will service this interrupt and -arrange for a DSR to be called. Isochronous and interrupt transfers -involve just a single packet. However, bulk transfers may involve -multiple packets so the device driver has to check whether the packet -was a full 64 bytes or whether it was a terminating packet of less -than this. When the device driver DSR detects a complete transfer it -will inform higher-level code by invoking the supplied completion -function. - - -This means that the completion function will normally be invoked by a -DSR and not in thread context - although some USB device drivers may -have a different implementation. Therefore the completion function is -restricted in what it can do. In particular it must not make any -calls that will or may block such as locking a mutex or allocating -memory. The kernel documentation should be consulted for more details -of DSR's and interrupt handling generally. - - -It is possible that the completion function will be invoked before -usbs_start_rx_buffer returns. Such an event would -be unusual because the transfer cannot happen until the next time the -host tries to send data to this peripheral, but it may happen if for -example another interrupt happens and a higher priority thread is -scheduled to run. Also, if the endpoint is currently halted then the -completion function will be invoked immediately with --EAGAIN: typically this will happen in the current -thread rather than in a separate DSR. The completion function is -allowed to start another transfer immediately by calling -usbs_start_rx_buffer again. - - -USB device drivers are not expected to perform any locking. It is the -responsibility of higher-level code to ensure that there is only one -receive operation for a given endpoint in progress at any one time. If -there are concurrent calls to -usbs_start_rx_buffer then the resulting behaviour -is undefined. For typical USB applications this does not present any -problems, because only one piece of code will access a given endpoint -at any particular time. - - -The following code fragment illustrates a very simple use of -usbs_start_rx_buffer to implement a blocking -receive, using a semaphore to synchronise between the foreground -thread and the DSR. For a simple example like this no completion data -is needed. - - -static int error_code = 0; -static cyg_sem_t completion_wait; - -static void -completion_fn(void* data, int result) -{ - error_code = result; - cyg_semaphore_post(&completion_wait); -} - -int -blocking_receive(usbs_rx_endpoint* ep, unsigned char* buf, int len) -{ - error_code = 0; - usbs_start_rx_buffer(ep, buf, len, &completion_fn, NULL); - cyg_semaphore_wait(&completion_wait); - return error_code; -} - - -There is also a utility function usbs_start_rx. This -can be used by code that wants to manipulate data endpoints directly, specifically the -complete_fn, -complete_data, -buffer and -buffer_size fields. -usbs_start_tx just invokes a function -supplied by the device driver. - - - - - - - - - -Sending Data to the Host - - -usbs_start_tx_buffer -Sending Data to the Host - - - - - -#include <cyg/io/usb/usbs.h> - - -void usbs_start_tx_buffer -usbs_tx_endpoint* ep -const unsigned char* buffer -int length -void (*)(void*,int) complete_fn -void * complete_data - - - -void usbs_start_tx -usbs_tx_endpoint* ep - - - - - -<function>Description</function> - -usbs_start_tx_buffer is a USB-specific function -to transfer data from peripheral to host. It can be used for bulk, -interrupt or isochronous transfers, but not for control messages; -instead those involve manipulating the usbs_control_endpoint -data structure directly. The function takes five arguments: - - - - -The first argument identifies the specific endpoint that should be -used. Different USB devices will support different sets of endpoints -and the device driver will provide appropriate data structures. The -device driver's documentation should be consulted for details of which -endpoints are available. - - - - -The buffer and length -arguments control the actual transfer. USB device drivers are not -allowed to modify the buffer during the transfer, so the data can -reside in read-only memory. The transfer will be for all the data -specified, and it is the responsibility of higher-level code to make -sure that the host is expecting this amount of data. For isochronous -transfers the USB specification imposes an upper bound of 1023 bytes, -but a smaller limit may be set in the enumeration data. Interrupt -transfers have an upper bound of 64 bytes or less, as per the -enumeration data. Bulk transfers are more complicated because they can -involve multiple 64-byte packets plus a terminating packet of less -than 64 bytes, so the basic USB specification does not impose an upper -limit on the total transfer size. Instead it is left to higher-level -protocols to specify an appropriate upper bound. If the peripheral -attempts to send more data than the host is willing to accept then the -resulting behaviour is undefined and may well depend on the specific -host operating system being used. - - -For bulk transfers, the USB device driver or the underlying hardware -will automatically split the transfer up into the appropriate number -of full-size 64-byte packets plus a single terminating packet, which -may be 0 bytes. - - - - -usbs_start_tx_buffer is non-blocking. It merely -starts the transmit operation, and does not wait for completion. At -some later point the USB device driver will invoke the completion -function parameter with two arguments: the completion data defined by -the last parameter, and a result field. This result will be either an -error code < 0, or the amount of data -transferred which should correspond to the -length argument. The most likely errors are --EPIPE to indicate that the connection between the -host and the target has been broken, and -EAGAIN -for when the endpoint has been halted. Specific USB device drivers may -define additional error conditions. - - - - -The normal sequence of events is that the USB device driver will -update the appropriate hardware registers. At some point after that -the host will attempt to fetch data by transmitting an IN token. Since -a transmit operation is now in progress the peripheral can send a -packet of data, and the host will generate an ACK. At this point the -USB hardware will generate an interrupt, and the device driver will -service this interrupt and arrange for a DSR to be called. Isochronous -and interrupt transfers involve just a single packet. However, bulk -transfers may involve multiple packets so the device driver has to -check whether there is more data to send and set things up for the -next packet. When the device driver DSR detects a complete transfer it -will inform higher-level code by invoking the supplied completion -function. - - -This means that the completion function will normally be invoked by a -DSR and not in thread context - although some USB device drivers may -have a different implementation. Therefore the completion function is -restricted in what it can do, in particular it must not make any -calls that will or may block such as locking a mutex or allocating -memory. The kernel documentation should be consulted for more details -of DSR's and interrupt handling generally. - - -It is possible that the completion function will be invoked before -usbs_start_tx_buffer returns. Such an event would -be unusual because the transfer cannot happen until the next time the -host tries to fetch data from this peripheral, but it may happen if, -for example, another interrupt happens and a higher priority thread is -scheduled to run. Also, if the endpoint is currently halted then the -completion function will be invoked immediately with --EAGAIN: typically this will happen in the current -thread rather than in a separate DSR. The completion function is -allowed to start another transfer immediately by calling -usbs_start_tx_buffer again. - - -USB device drivers are not expected to perform any locking. It is the -responsibility of higher-level code to ensure that there is only one -transmit operation for a given endpoint in progress at any one time. -If there are concurrent calls to -usbs_start_tx_buffer then the resulting behaviour -is undefined. For typical USB applications this does not present any -problems because only piece of code will access a given endpoint at -any particular time. - - -The following code fragment illustrates a very simple use of -usbs_start_tx_buffer to implement a blocking -transmit, using a semaphore to synchronise between the foreground -thread and the DSR. For a simple example like this no completion data -is needed. - - -static int error_code = 0; -static cyg_sem_t completion_wait; - -static void -completion_fn(void* data, int result) -{ - error_code = result; - cyg_semaphore_post(&completion_wait); -} - -int -blocking_transmit(usbs_tx_endpoint* ep, const unsigned char* buf, int len) -{ - error_code = 0; - usbs_start_tx_buffer(ep, buf, len, &completion_fn, NULL); - cyg_semaphore_wait(&completion_wait); - return error_code; -} - - -There is also a utility function usbs_start. This -can be used by code that wants to manipulate data endpoints directly, specifically the -complete_fn, -complete_data, -buffer and -buffer_size fields. -usbs_start_tx just calls a function supplied by -the device driver. - - - - - - - - - -Halted Endpoints - - -Halted Endpoints -Support for Halting and Halted Endpoints - - - - - - -#include <cyg/io/usb/usbs.h> - - - -cyg_bool usbs_rx_endpoint_halted -usbs_rx_endpoint* ep - - -void usbs_set_rx_endpoint_halted -usbs_rx_endpoint* ep -cyg_bool new_state - - -void usbs_start_rx_endpoint_wait -usbs_rx_endpoint* ep -void (*)(void*, int) complete_fn -void * complete_data - - - -cyg_bool -usbs_tx_endpoint_halted -usbs_tx_endpoint* ep - - -void usbs_set_tx_endpoint_halted -usbs_tx_endpoint* ep -cyg_bool new_state - - -void usbs_start_tx_endpoint_wait -usbs_tx_endpoint* ep -void (*)(void*, int) complete_fn -void * complete_data - - - - - -<function>Description</function> - -Normal USB traffic involves straightforward handshakes, with either an -ACK to indicate that a packet was transferred -without errors, or a NAK if an error occurred, or -if a peripheral is currently unable to process another packet from the -host, or has no packet to send to the host. There is a third form of -handshake, a STALL, which indicates that the -endpoint is currently halted. - - -When an endpoint is halted it means that the host-side code needs to -take some sort of recovery action before communication over that -endpoint can resume. The exact circumstances under which this can -happen are not defined by the USB specification, but one example would -be a protocol violation if say the peripheral attempted to transmit -more data to the host than was permitted by the protocol in use. The -host can use the standard control messages get-status, set-feature and -clear-feature to examine and manipulate the halted status of a given -endpoint. There are USB-specific functions which can be used inside -the peripheral to achieve the same effect. Once an endpoint has been -halted the host can then interact with the peripheral using class or -vendor control messages to perform appropriate recovery, and then the -halted condition can be cleared. - - -Halting an endpoint does not constitute a device state change, and -there is no mechanism by which higher-level code can be informed -immediately. However, any ongoing receive or transmit operations will -be aborted with an -EAGAIN error, and any new -receives or transmits will fail immediately with the same error. - - -There are six functions to support halted endpoints, one set for -receive endpoints and another for transmit endpoints, with both sets -behaving in essentially the same way. The first, -usbs_rx_endpoint_halted, can be used to determine -whether or not an endpoint is currently halted: it takes a single -argument that identifies the endpoint of interest. The second -function, usbs_set_rx_endpoint_halted, can be -used to change the halted condition of an endpoint: it takes two -arguments; one to identify the endpoint and another to specify the new -state. The last function -usbs_start_rx_endpoint_wait operates in much the -same way as usbs_start_rx_buffer: when the -endpoint is no longer halted the device driver will invoke the -supplied completion function with a status of 0. The completion -function has the same signature as that for a transfer operation. -Often it will be possible to use a single completion function and have -the foreground code invoke either -usbs_start_rx_buffer or -usbs_start_rx_endpoint_wait depending on the -current state of the endpoint. - - - - - - - - - -Control Endpoints - - -Control Endpoints -Control endpoint data structure - - - - -#include <cyg/io/usb/usbs.h> - -typedef struct usbs_control_endpoint { - *hellip; -} usbs_control_endpoint; - - - -<literal>usbs_control_endpoint</literal> Data Structure - -The device driver for a USB slave device should supply one -usbs_control_endpoint data structure per USB -device. This corresponds to endpoint 0 which will be used for all -control message interaction between the host and that device. The data -structure is also used for internal management purposes, for example -to keep track of the current state. In a typical USB peripheral there -will only be one such data structure in the entire system, but if -there are multiple USB slave ports, allowing the peripheral to be -connected to multiple hosts, then there will be a separate data -structure for each one. The name or names of the data structures are -determined by the device drivers. For example, the SA11x0 USB device -driver package provides usbs_sa11x0_ep0. - - -The operations on a control endpoint do not fit cleanly into a -conventional open/read/write I/O model. For example, when the host -sends a control message to the USB peripheral this may be one of four -types: standard, class, vendor and reserved. Some or all of the -standard control messages will be handled automatically by the common -USB slave package or by the device driver itself. Other standard -control messages and the other types of control messages may be -handled by a class-specific package or by application code. Although -it would be possible to have devtab entries such as -/dev/usbs_ep0/standard and -/dev/usbs_ep0/class, and then support read and -write operations on these devtab entries, this would add significant -overhead and code complexity. Instead, all of the fields in the -control endpoint data structure are public and can be manipulated -directly by higher level code if and when required. - - -Control endpoints involve a number of callback functions, with -higher-level code installing suitable function pointers in the control -endpoint data structure. For example, if the peripheral involves -vendor-specific control messages then a suitable handler for these -messages should be installed. Although the exact details depend on the -device driver, typically these callback functions will be invoked at -DSR level rather than thread level. Therefore, only certain eCos -functions can be invoked; specifically, those functions that are -guaranteed not to block. If a potentially blocking function such as a -semaphore wait or a mutex lock operation is invoked from inside the -callback then the resulting behaviour is undefined, and the system as -a whole may fail. In addition, if one of the callback functions -involves significant processing effort then this may adversely affect -the system's real time characteristics. The eCos kernel documentation -should be consulted for more details of DSR handling. - - -Initialization - -The usbs_control_endpoint data structure -contains the following fields related to initialization. - - -typedef struct usbs_control_endpoint { - … - const usbs_enumeration_data* enumeration_data; - void (*start_fn)(usbs_control_endpoint*); - … -}; - - -It is the responsibility of higher-level code, usually the -application, to define the USB enumeration data. This needs to be -installed in the control endpoint data structure early on during -system startup, before the USB device is actually started and any -interaction with the host is possible. Details of the enumeration data -are supplied in the section USB Enumeration -Data. Typically, the enumeration data is constant for a given -peripheral, although it can be constructed dynamically if necessary. -However, the enumeration data cannot change while the peripheral is -connected to a host: the peripheral cannot easily claim to be a -keyboard one second and a printer the next. - - -The start_fn member is normally accessed -via the utility usbs_start rather -than directly. It is provided by the device driver and should be -invoked once the system is fully initialized and interaction with the -host is possible. A typical implementation would change the USB data -pins from tristated to active. If the peripheral is already plugged -into a host then the latter should detect this change and start -interacting with the peripheral, including requesting the enumeration -data. - - - -State - -There are three usbs_control_endpoint fields -related to the current state of a USB slave device, plus some state -constants and an enumeration of the possible state changes: - - -typedef struct usbs_control_endpoint { - … - int state; - void (*state_change_fn)(struct usbs_control_endpoint*, void*, - usbs_state_change, int); - void* state_change_data; - … -}; - -#define USBS_STATE_DETACHED 0x01 -#define USBS_STATE_ATTACHED 0x02 -#define USBS_STATE_POWERED 0x03 -#define USBS_STATE_DEFAULT 0x04 -#define USBS_STATE_ADDRESSED 0x05 -#define USBS_STATE_CONFIGURED 0x06 -#define USBS_STATE_MASK 0x7F -#define USBS_STATE_SUSPENDED (1 << 7) - -typedef enum { - USBS_STATE_CHANGE_DETACHED = 1, - USBS_STATE_CHANGE_ATTACHED = 2, - USBS_STATE_CHANGE_POWERED = 3, - USBS_STATE_CHANGE_RESET = 4, - USBS_STATE_CHANGE_ADDRESSED = 5, - USBS_STATE_CHANGE_CONFIGURED = 6, - USBS_STATE_CHANGE_DECONFIGURED = 7, - USBS_STATE_CHANGE_SUSPENDED = 8, - USBS_STATE_CHANGE_RESUMED = 9 -} usbs_state_change; - - -The USB standard defines a number of states for a given USB -peripheral. The initial state is detached, where -the peripheral is either not connected to a host at all or, from the -host's perspective, the peripheral has not started up yet because the -relevant pins are tristated. The peripheral then moves via -intermediate attached and -powered states to its default or -reset state, at which point the host and -peripheral can actually start exchanging data. The first message is -from host to peripheral and provides a unique 7-bit address within the -local USB network, resulting in a state change to -addressed. The host then requests enumeration -data and performs other initialization. If everything succeeds the -host sends a standard set-configuration control message, after which -the peripheral is configured and expected to be -up and running. Note that some USB device drivers may be unable to -distinguish between the detached, -attached and powered states -but generally this is not important to higher-level code. - - -A USB host should generate at least one token every millisecond. If a -peripheral fails to detect any USB traffic for a period of time then -typically this indicates that the host has entered a power-saving -mode, and the peripheral should do the same if possible. This -corresponds to the suspended bit. The actual -state is a combination of suspended and the -previous state, for example configured and -suspended rather than just -suspended. When the peripheral subsequently -detects USB traffic it would switch back to the -configured state. - - -The USB device driver and the common USB slave package will maintain -the current state in the control endpoint's -state field. There should be no need for -any other code to change this field, but it can be examined whenever -appropriate. In addition whenever a state change occurs the generic -code can invoke a state change callback function. By default, no such -callback function will be installed. Some class-specific packages such -as the USB-ethernet package will install a suitable function to keep -track of whether or not the host-peripheral connection is up, that is -whether or not ethernet packets can be exchanged. Application code can -also update this field. If multiple parties want to be informed of -state changes, for example both a class-specific package and -application code, then typically the application code will install its -state change handler after the class-specific package and is -responsible for chaining into the package's handler. - - -The state change callback function is invoked with four arguments. The -first identifies the control endpoint. The second is an arbitrary -pointer: higher-level code can fill in the -state_change_data field to set this. The -third argument specifies the state change that has occurred, and the -last argument supplies the previous state (the new state is readily -available from the control endpoint structure). - - -eCos does not provide any utility functions for updating or examining -the state_change_fn or -state_change_data fields. Instead, it is -expected that the fields in the -usbs_control_endpoint data structure will be -manipulated directly. Any utility functions would do just this, but -at the cost of increased code and cpu overheads. - - - -Standard Control Messages - -typedef struct usbs_control_endpoint { - … - unsigned char control_buffer[8]; - usbs_control_return (*standard_control_fn)(struct usbs_control_endpoint*, void*); - void* standard_control_data; - … -} usbs_control_endpoint; - -typedef enum { - USBS_CONTROL_RETURN_HANDLED = 0, - USBS_CONTROL_RETURN_UNKNOWN = 1, - USBS_CONTROL_RETURN_STALL = 2 -} usbs_control_return; - -extern usbs_control_return usbs_handle_standard_control(struct usbs_control_endpoint*); - - -When a USB peripheral is connected to the host it must always respond -to control messages sent to endpoint 0. Control messages always -consist of an initial eight-byte header, containing fields such as a -request type. This may be followed by a further data transfer, either -from host to peripheral or from peripheral to host. The way this is -handled is described in the Buffer Management section below. - - -The USB device driver will always accept the initial eight-byte -header, storing it in the control_buffer -field. Then it determines the request type: standard, class, vendor, -or reserved. The way in which the last three of these are processed is -described in the section Other -Control Messages. Some -standard control messages will be handled by the device driver itself; -typically the set-address request and the -get-status, set-feature and -clear-feature requests when applied to endpoints. - - -If a standard control message cannot be handled by the device driver -itself, the driver checks the -standard_control_fn field in the control -endpoint data structure. If higher-level code has installed a suitable -callback function then this will be invoked with two argument, the -control endpoint data structure itself and the -standard_control_data field. The latter -allows the higher level code to associate arbitrary data with the -control endpoint. The callback function can return one of three -values: HANDLED to indicate that the request has -been processed; UNKNOWN if the message should be -handled by the default code; or STALL to indicate -an error condition. If higher level code has not installed a callback -function or if the callback function has returned -UNKNOWN then the device driver will invoke a -default handler, usbs_handle_standard_control -provided by the common USB slave package. - - -The default handler can cope with all of the standard control messages -for a simple USB peripheral. However, if the peripheral involves -multiple configurations, multiple interfaces in a configuration, or -alternate settings for an interface, then this cannot be handled by -generic code. For example, a multimedia peripheral may support various -alternate settings for a given data source with different bandwidth -requirements, and the host can select a setting that takes into -account the current load. Clearly higher-level code needs to be aware -when the host changes the current setting, so that it can adjust the -rate at which data is fed to or retrieved from the host. Therefore the -higher-level code needs to install its own standard control callback -and process appropriate messages, rather than leaving these to the -default handler. - - -The default handler will take care of the -get-descriptor request used to obtain the -enumeration data. It has support for string descriptors but ignores -language encoding issues. If language encoding is important for the -peripheral then this will have to be handled by an -application-specific standard control handler. - - -The header file <cyg/io/usb/usb.h> defines various -constants related to control messages, for example the function codes -corresponding to the standard request types. This header file is -provided by the common USB package, not by the USB slave package, -since the information is also relevant to USB hosts. - - - -Other Control Messages - -typedef struct usbs_control_endpoint { - … - usbs_control_return (*class_control_fn)(struct usbs_control_endpoint*, void*); - void* class_control_data; - usbs_control_return (*vendor_control_fn)(struct usbs_control_endpoint*, void*); - void* vendor_control_data; - usbs_control_return (*reserved_control_fn)(struct usbs_control_endpoint*, void*); - void* reserved_control_data; - … -} usbs_control_endpoint; - - -Non-standard control messages always have to be processed by -higher-level code. This could be class-specific packages. For example, -the USB-ethernet package will handle requests for getting the MAC -address and for enabling or disabling promiscuous mode. In all cases -the device driver will store the initial request in the -control_buffer field, check for an -appropriate handler, and invoke it with details of the control -endpoint and any handler-specific data that has been installed -alongside the handler itself. The handler should return either -USBS_CONTROL_RETURN_HANDLED to report success or -USBS_CONTROL_RETURN_STALL to report failure. The -device driver will report this to the host. - - -If there are multiple parties interested in a particular type of -control messages, it is the responsibility of application code to -install an appropriate handler and process the requests appropriately. - - - -Buffer Management - -typedef struct usbs_control_endpoint { - … - unsigned char* buffer; - int buffer_size; - void (*fill_buffer_fn)(struct usbs_control_endpoint*); - void* fill_data; - int fill_index; - usbs_control_return (*complete_fn)(struct usbs_control_endpoint*, int); - … -} usbs_control_endpoint; - - -Many USB control messages involve transferring more data than just the -initial eight-byte header. The header indicates the direction of the -transfer, OUT for host to peripheral or IN for peripheral to host. -It also specifies a length field, which is exact for an OUT transfer -or an upper bound for an IN transfer. Control message handlers can -manipulate six fields within the control endpoint data structure to -ensure that the transfer happens correctly. - - -For an OUT transfer, the handler should examine the length field in -the header and provide a single buffer for all the data. A -class-specific protocol would typically impose an upper bound on the -amount of data, allowing the buffer to be allocated statically. -The handler should update the buffer and -complete_fn fields. When all the data has -been transferred the completion callback will be invoked, and its -return value determines the response sent back to the host. The USB -standard allows for a new control message to be sent before the -current transfer has completed, effectively cancelling the current -operation. When this happens the completion function will also be -invoked. The second argument to the completion function specifies what -has happened, with a value of 0 indicating success and an error code -such as -EPIPE or -EIO -indicating that the current transfer has been cancelled. - - -IN transfers are a little bit more complicated. The required -information, for example the enumeration data, may not be in a single -contiguous buffer. Instead a mechanism is provided by which the buffer -can be refilled, thus allowing the transfer to move from one record to -the next. Essentially, the transfer operates as follows: - - - - -When the host requests another chunk of data (typically eight bytes), -the USB device driver will examine the -buffer_size field. If non-zero then -buffer contains at least one more byte of -data, and then buffer_size is decremented. - - - - -When buffer_size has dropped to 0, the -fill_buffer_fn field will be examined. If -non-null it will be invoked to refill the buffer. - - - - -The fill_data and -fill_index fields are not used by the -device driver. Instead these fields are available to the refill -function to keep track of the current state of the transfer. - - - - -When buffer_size is 0 and -fill_buffer_fn is NULL, no more data is -available and the transfer has completed. - - - - -Optionally a completion function can be installed. This will be -invoked with 0 if the transfer completes successfully, or with an -error code if the transfer is cancelled because of another control -messsage. - - - - -If the requested data is contiguous then the only fields that need -to be manipulated are buffer and -buffer_size, and optionally -complete_fn. If the requested data is not -contiguous then the initial control message handler should update -fill_buffer_fn and some or all of the other -fields, as required. An example of this is the handling of the -standard get-descriptor control message by -usbs_handle_standard_control. - - - -Polling Support - -typedef struct usbs_control_endpoint { - void (*poll_fn)(struct usbs_control_endpoint*); - int interrupt_vector; - … -} usbs_control_endpoint; - - -In nearly all circumstances USB I/O should be interrupt-driven. -However, there are special environments such as RedBoot where polled -operation may be appropriate. If the device driver can operate in -polled mode then it will provide a suitable function via the -poll_fn field, and higher-level code can -invoke this regularly. This polling function will take care of all -endpoints associated with the device, not just the control endpoint. -If the USB hardware involves a single interrupt vector then this will -be identified in the data structure as well. - - - - - - - - - - - - -Data Endpoints - - -Data Endpoints -Data endpoint data structures - - - - -#include <cyg/io/usb/usbs.h> - -typedef struct usbs_rx_endpoint { - void (*start_rx_fn)(struct usbs_rx_endpoint*); - void (*set_halted_fn)(struct usbs_rx_endpoint*, cyg_bool); - void (*complete_fn)(void*, int); - void* complete_data; - unsigned char* buffer; - int buffer_size; - cyg_bool halted; -} usbs_rx_endpoint; - -typedef struct usbs_tx_endpoint { - void (*start_tx_fn)(struct usbs_tx_endpoint*); - void (*set_halted_fn)(struct usbs_tx_endpoint*, cyg_bool); - void (*complete_fn)(void*, int); - void* complete_data; - const unsigned char* buffer; - int buffer_size; - cyg_bool halted; -} usbs_tx_endpoint; - - - -Receive and Transmit Data Structures - -In addition to a single usbs_control_endpoint -data structure per USB slave device, the USB device driver should also -provide receive and transmit data structures corresponding to the -other endpoints. The names of these are determined by the device -driver. For example, the SA1110 USB device driver package provides -usbs_sa11x0_ep1 for receives and -usbs_sa11x0_ep2 for transmits. - - -Unlike control endpoints, the common USB slave package does provide a -number of utility routines to manipulate data endpoints. For example -usbs_start_rx_buffer -can be used to receive data from the host into a buffer. In addition -the USB device driver can provide devtab entries such as -/dev/usbs1r and /dev/usbs2w, so -higher-level code can open these devices and then -perform blocking read and -write operations. - - -However, the operation of data endpoints and the various -endpoint-related functions is relatively straightforward. First -consider a usbs_rx_endpoint structure. The -device driver will provide the members -start_rx_fn and -set_halted_fn, and it will maintain the -halted field. To receive data, higher-level -code sets the buffer, -buffer_size, -complete_fn and optionally the -complete_data fields. Next the -start_rx_fn member should be called. When -the transfer has finished the device driver will invoke the completion -function, using complete_data as the first -argument and a size field for the second argument. A negative size -indicates an error of some sort: -EGAIN indicates -that the endpoint has been halted, usually at the request of the host; --EPIPE indicates that the connection between the -host and the peripheral has been broken. Certain device drivers may -generate other error codes. - - -If higher-level code needs to halt or unhalt an endpoint then it can -invoke the set_halted_fn member. When an -endpoint is halted, invoking start_rx_fn -wit buffer_size set to 0 indicates that -higher-level code wants to block until the endpoint is no longer -halted; at that point the completion function will be invoked. - - -USB device drivers are allowed to assume that higher-level protocols -ensure that host and peripheral agree on the amount of data that will -be transferred, or at least on an upper bound. Therefore there is no -need for the device driver to maintain its own buffers, and copy -operations are avoided. If the host sends more data than expected then -the resulting behaviour is undefined. - - -Transmit endpoints work in essentially the same way as receive -endpoints. Higher-level code should set the -buffer and -buffer_size fields to point at the data to -be transferred, then call start_tx_fn, and -the device driver will invoked the completion function when the -transfer has completed. - - -USB device drivers are not expected to perform any locking. If at any -time there are two concurrent receive operations for a given endpoint, -or two concurrent transmit operations, then the resulting behaviour is -undefined. It is the responsibility of higher-level code to perform -any synchronisation that may be necessary. In practice, conflicts are -unlikely because typically a given endpoint will only be accessed -sequentially by just one part of the overall system. - - - - - - - - - - - -Writing a USB Device Driver - - -Writing a USB Device Driver -USB Device Driver Porting Guide - - -Introduction - -Often the best way to write a USB device driver will be to start with -an existing one and modify it as necessary. The information given here -is intended primarily as an outline rather than as a complete guide. - - - -At the time of writing only one USB device driver has been -implemented. Hence it is possible, perhaps probable, that some -portability issues have not yet been addressed. One issue -involves the different types of transfer, for example the initial -target hardware had no support for isochronous or interrupt transfers, -so additional functionality may be needed to switch between transfer -types. Another issue would be hardware where a given endpoint number, -say endpoint 1, could be used for either receiving or transmitting -data, but not both because a single fifo is used. Issues like these -will have to be resolved as and when additional USB device drivers are -written. - - - - -The Control Endpoint - -A USB device driver should provide a single usbs_control_endpoint -data structure for every USB device. Typical peripherals will have -only one USB port so there will be just one such data structure in the -entire system, but theoretically it is possible to have multiple USB -devices. These may all involve the same chip, in which case a single -device driver should support multiple device instances, or they may -involve different chips. The name or names of these data structures -are determined by the device driver, but appropriate care should be -taken to avoid name clashes. - - -A USB device cannot be used unless the control endpoint data structure -exists. However, the presence of USB hardware in the target processor -or board does not guarantee that the application will necessarily want -to use that hardware. To avoid unwanted code or data overheads, the -device driver can provide a configuration option to determine whether -or not the endpoint 0 data structure is actually provided. A default -value of CYGINT_IO_USB_SLAVE_CLIENTS ensures that -the USB driver will be enabled automatically if higher-level code does -require USB support, while leaving ultimate control to the user. - - -The USB device driver is responsible for filling in the -start_fn, -poll_fn and -interrupt_vector fields. Usually this can -be achieved by static initialization. The driver is also largely -responsible for maintaining the state -field. The control_buffer array should be -used to hold the first packet of a control message. The -buffer and other fields related to data -transfers will be managed jointly by higher-level code and -the device driver. The remaining fields are generally filled in by -higher-level code, although the driver should initialize them to NULL -values. - - -Hardware permitting, the USB device should be inactive until the -start_fn is invoked, for example by -tristating the appropriate pins. This prevents the host from -interacting with the peripheral before all other parts of the system -have initialized. It is expected that the -start_fn will only be invoked once, shortly -after power-up. - - -Where possible the device driver should detect state changes, such as -when the connection between host and peripheral is established, and -report these to higher-level -code via the state_change_fn callback, if -any. The state change to and from configured state cannot easily be -handled by the device driver itself, instead higher-level code such as -the common USB slave package will take care of this. - - -Once the connection between host and peripheral has been established, -the peripheral must be ready to accept control messages at all times, -and must respond to these within certain time constraints. For -example, the standard set-address control message must be handled -within 50ms. The USB specification provides more information on these -constraints. The device driver is responsible for receiving the -initial packet of a control message. This packet will always be eight -bytes and should be stored in the -control_buffer field. Certain standard -control messages should be detected and handled by the device driver -itself. The most important is set-address, but usually the get-status, -set-feature and clear-feature requests when applied to halted -endpoints should also be handled by the driver. Other standard control -messages should first be passed on to the -standard_control_fn callback (if any), and -finally to the default handler -usbs_handle_standard_control provided by the -common USB slave package. Class, vendor and reserved control messages -should always be dispatched to the appropriate callback and there is -no default handler for these. - - -Some control messages will involve further data transfer, not just the -initial packet. The device driver must handle this in accordance with -the USB specification and the buffer management strategy. The -driver is also responsible for keeping track of whether or not the -control operation has succeeded and generating an ACK or STALL -handshake. - - -The polling support is optional and may not be feasible on all -hardware. It is only used in certain specialised environments such as -RedBoot. A typical implementation of the polling function would just -check whether or not an interrupt would have occurred and, if so, call -the same code that the interrupt handler would. - - - -Data Endpoints - -In addition to the control endpoint data structure, a USB device -driver should also provide appropriate data -endpoint data structures. Obviously this is only relevant if -the USB support generally is desired, that is if the control endpoint is -provided. In addition, higher-level code may not require all the -endpoints, so it may be useful to provide configuration options that -control the presence of each endpoint. For example, the intended -application might only involve a single transmit endpoint and of -course control messages, so supporting receive endpoints might waste -memory. - - -Conceptually, data endpoints are much simpler than the control -endpoint. The device driver has to supply two functions, one for -data transfers and another to control the halted condition. These -implement the functionality for -usbs_start_rx_buffer, -usbs_start_tx_buffer, -usbs_set_rx_endpoint_halted and -usbs_set_tx_endpoint_halted. -The device driver is also responsible for maintaining the -halted status. - - -For data transfers, higher-level code will have filled in the -buffer, -buffer_size, -complete_fn and -complete_data fields. The transfer function -should arrange for the transfer to start, allowing the host to send or -receive packets. Typically this will result in an interrupt at the end -of the transfer or after each packet. Once the entire transfer has -been completed, the driver's interrupt handling code should invoke the -completion function. This can happen either in DSR context or thread -context, depending on the driver's implementation. There are a number -of special cases to consider. If the endpoint is halted when the -transfer is started then the completion function can be invoked -immediately with -EAGAIN. If the transfer cannot be -completed because the connection is broken then the completion -function should be invoked with -EPIPE. If the -endpoint is stalled during the transfer, either because of a standard -control message or because higher-level code calls the appropriate -set_halted_fn, then again the completion -function should be invoked with -EAGAIN. Finally, -the <usbs_start_rx_endpoint_wait and -usbs_start_tx_endpoint_wait functions involve -calling the device driver's data transfer function with a buffer size -of 0 bytes. - - -Giving a buffer size of 0 bytes a special meaning is problematical -because it prevents transfers of that size. Such transfers are allowed -by the USB protocol, consisting of just headers and acknowledgements -and an empty data phase, although rarely useful. A future modification -of the device driver specification will address this issue, although -care has to be taken that the functionality remains accessible through -devtab entries as well as via low-level accesses. - - - -Devtab Entries - -For some applications or higher-level packages it may be more -convenient to use traditional open/read/write I/O calls rather than -the non-blocking USB I/O calls. To support this the device driver can -provide a devtab entry for each endpoint, for example: - - -#ifdef CYGVAR_DEVS_USB_SA11X0_EP1_DEVTAB_ENTRY - -static CHAR_DEVIO_TABLE(usbs_sa11x0_ep1_devtab_functions, - &cyg_devio_cwrite, - &usbs_devtab_cread, - &cyg_devio_bwrite, - &cyg_devio_bread, - &cyg_devio_select, - &cyg_devio_get_config, - &cyg_devio_set_config); - -static CHAR_DEVTAB_ENTRY(usbs_sa11x0_ep1_devtab_entry, - CYGDAT_DEVS_USB_SA11X0_DEVTAB_BASENAME "1r", - 0, - &usbs_sa11x0_ep1_devtab_functions, - &usbs_sa11x0_devtab_dummy_init, - 0, - (void*) &usbs_sa11x0_ep1); -#endif - - -Again care must be taken to avoid name clashes. This can be achieved -by having a configuration option to control the base name, with a -default value of e.g. /dev/usbs, and appending an -endpoint-specific string. This gives the application developer -sufficient control to eliminate any name clashes. The common USB slave -package provides functions usbs_devtab_cwrite and -usbs_devtab_cread, which can be used in the -function tables for transmit and receive endpoints respectively. The -private field priv of the devtab entry -should be a pointer to the underlying endpoint data structure. - - -Because devtab entries are never accessed directly, only indirectly, -they would usually be eliminated by the linker. To avoid this the -devtab entries should normally be defined in a separate source file -which ends up the special library libextras.a -rather than in the default library libtarget.a. - - -Not all applications or higher-level packages will want to use the -devtab entries and the blocking I/O facilities. It may be appropriate -for the device driver to provide additional configuration options that -control whether or not any or all of the devtab entries should be -provided, to avoid unnecessary memory overheads. - - - -Interrupt Handling - -A typical USB device driver will need to service interrupts for all of -the endpoints and possibly for additional USB events such as entering -or leaving suspended mode. Usually these interrupts need not be -serviced directly by the ISR. Instead, they can be left to a DSR. If -the peripheral is not able to accept or send another packet just yet, -the hardware will generate a NAK and the host will just retry a little -bit later. If high throughput is required then it may be desirable to -handle the bulk transfer protocol largely at ISR level, that is take -care of each packet in the ISR and only activate the DSR once the -whole transfer has completed. - - -Control messages may involve invoking arbitrary callback functions in -higher-level code. This should normally happen at DSR level. Doing it -at ISR level could seriously affect the system's interrupt latency and -impose unacceptable constraints on what operations can be performed by -those callbacks. If the device driver requires a thread anyway then it -may be appropriate to use this thread for invoking the callbacks, but -usually it is not worthwhile to add a new thread to the system just -for this; higher-level code is expected to write callbacks that -function sensibly at DSR level. Much the same applies to the -completion functions associated with data transfers. These should also -be invoked at DSR or thread level. - - - -Support for USB Testing - -Optionally a USB device driver can provide support for the -USB test software. This requires -defining a number of additional data structures, allowing the -generic test code to work out just what the hardware is capable of and -hence what testing can be performed. - - -The key data structure is -usbs_testing_endpoint, defined in cyg/io/usb/usbs.h. In addition some -commonly required constants are provided by the common USB package in -cyg/io/usb/usb.h. One -usbs_testing_endpoint structure should be -defined for each supported endpoint. The following fields need to be -filled in: - - - - endpoint_type - - This specifies the type of endpoint and should be one of - USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL, - BULK, ISOCHRONOUS or - INTERRUPT. - - - - endpoint_number - - This identifies the number that should be used by the host - to address this endpoint. For a control endpoint it should - be 0. For other types of endpoints it should be between - 1 and 15. - - - - endpoint_direction - - For control endpoints this field is irrelevant. For other - types of endpoint it should be either - USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN or - USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT. If a given - endpoint number can be used for traffic in both directions then - there should be two entries in the array, one for each direction. - - - - endpoint - - This should be a pointer to the appropriate - usbs_control_endpoint, - usbs_rx_endpoint or - usbs_tx_endpoint structure, allowing the - generic testing code to perform low-level I/O. - - - - devtab_entry - - If the endpoint also has an entry in the system's device table then - this field should give the corresponding string, for example - "/dev/usbs1r". This allows the - generic testing code to access the device via higher-level - calls like open and read. - - - - min_size - - This indicates the smallest transfer size that the hardware can - support on this endpoint. Typically this will be one. - - - Strictly speaking a minimum size of one is not quite right since it - is valid for a USB transfer to involve zero bytes, in other words a - transfer that involves just headers and acknowledgements and an - empty data phase, and that should be tested as well. However current - device drivers interpret a transfer size of 0 as special, so that - would have to be resolved first. - - - - - max_size - - Similarly, this specifies the largest transfer size. For control - endpoints the USB protocol uses only two bytes to hold the transfer - length, so there is an upper bound of 65535 bytes. In practice - it is very unlikely that any control transfers would ever need to - be this large, and in fact such transfers would take a long time - and probably violate timing constraints. For other types of endpoint - any of the protocol, the hardware, or the device driver may impose - size limits. For example a given device driver might be unable to - cope with transfers larger than 65535 bytes. If it should be - possible to transfer arbitrary amounts of data then a value of - -1 indicates no upper limit, and transfer - sizes will be limited by available memory and by the capabilities - of the host machine. - - - - max_in_padding - - This field is needed on some hardware where it is impossible to - send packets of a certain size. For example the hardware may be - incapable of sending an empty bulk packet to terminate a transfer - that is an exact multiple of the 64-byte bulk packet size. - Instead the driver has to do some padding and send an extra byte, - and the host has to be prepared to receive this extra byte. Such a - driver should specify a value of 1 for the - padding field. For most drivers this field should be set to - 0. - - - A better solution would be for the device driver to supply a - fragment of Tcl code that would adjust the receive buffer size - only when necessary, rather than for every transfer. Forcing - receive padding on all transfers when only certain transfers - will actually be padded reduces the accuracy of certain tests. - - - - alignment - - On some hardware data transfers may need to be aligned to certain - boundaries, for example a word boundary or a cacheline boundary. - Although in theory device drivers could hide such alignment - restrictions from higher-level code by having their own buffers and - performing appropriate copying, that would be expensive in terms of - both memory and cpu cycles. Instead the generic testing code will - align any buffers passed to the device driver to the specified - boundary. For example, if the driver requires that buffers be - aligned to a word boundary then it should specify an alignment - value of 4. - - - - - -The device driver should provide an array of these structures -usbs_testing_endpoints[]. The USB testing code -examines this array and uses the information to perform appropriate -tests. Because different USB devices support different numbers of -endpoints the number of entries in the array is not known in advance, -so instead the testing code looks for a special terminator -USBS_TESTING_ENDPOINTS_TERMINATOR. An example -array, showing just the control endpoint and the terminator, might -look like this: - - -usbs_testing_endpoint usbs_testing_endpoints[] = { - { - endpoint_type : USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL, - endpoint_number : 0, - endpoint_direction : USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN, - endpoint : (void*) &ep0.common, - devtab_entry : (const char*) 0, - min_size : 1, - max_size : 0x0FFFF, - max_in_padding : 0, - alignment : 0 - }, - …, - USBS_TESTING_ENDPOINTS_TERMINATOR -}; - - - - -The use of a single array usbs_testing_endpoints -limits USB testing to platforms with a single USB device: if there -were multiple devices, each defining their own instance of this array, -then there would a collision at link time. In practice this should not -be a major problem since typical USB peripherals only interact with a -single host machine via a single slave port. In addition, even if a -peripheral did have multiple slave ports the current USB testing code -would not support this since it would not know which port to use. - - - - - - - - - - - - -Testing - - -Testing -Testing of USB Device Drivers - - -Introduction - -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. - - - -Building and Running the Target-side Code - -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. - - - -Building and Running the Host-side Code - -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> -$ - - - - -The location of the eCos component repository should be substituted -for <repo>. - - - - -If the package has been obtained via CVS or anonymous CVS then the -package version will be current, as per the -example. If instead the package has been obtained as part of a full -eCos release or as a separate .epk file then the -appropriate package version should be used instead of -current. - - - - -The configure script takes the usual arguments such -as --prefix= to specify where the executables -and support files should be installed. The only other parameter that -some users may wish to specify is the location of a suitable Tcl -installation. By default usbhost will use -the existing Tcl installation in /usr, -as provided by your Linux distribution. An alternative Tcl -installation can be specified using the parameter ---with-tcl=, or alternatively using some -combination of --with-tcl-include, ---with-tcl-lib and ---with-tcl-version. - - - - -One of the host-side executables that gets built, -usbchmod, needs to be installed with suid -root privileges. Although the Linux kernel makes it possible for -applications to perform low-level USB operations such as transmitting -bulk packets, by default access to this functionality is restricted to -programs with superuser privileges. It is undesirable to run a complex -program such as usbhost with such -privileges, especially since the program contains a general-purpose -Tcl interpreter. Therefore when usbhost -starts up and discovers that it does not have sufficient access to the -appropriate entries in /proc/bus/usb, -it spawns an instance of usbchmod to modify -the permissions on these entries. usbchmod -will only do this for a USB device "Red Hat eCos USB -test", so installing this program suid root should not -introduce any security problems. - - - - - -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. - - -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. - - - - - -Writing a Test - -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. - - - -Available Hardware - -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: - - - - bulk_in_endpoints - - 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 { - … - } - } - - - - - bulk_in() - - 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: - - - - min_size - - This field specifies a lower bound on the size of bulk transfers, - and will typically will have a value of 1. - - - 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. - - - - - max_size - - 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. - - - - max_in_padding - - 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. - - - - devtab - - 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)" - } - } - - - - - bulk_out_endpoint - - This is a simple list of the endpoints which can support bulk OUT - transfers. It is analogous to - bulk_in_endpoints. - - - - bulk_out() - - 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. - - - - control() - - 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. - - - - isochronous_in_endpoints and - isochronous_in() - - These variables provide the same information as - bulk_in_endpoints and bulk_in, - but for endpoints that support isochronous IN transfers. - - - - isochronous_out_endpoints and - isochronous_out() - - These variables provide the same information as - bulk_out_endpoints and bulk_out, - but for endpoints that support isochronous OUT transfers. - - - - interrupt_in_endpoints and - interrupt_in() - - These variables provide the same information as - bulk_in_endpoints and bulk_in, - but for endpoints that support interrupt IN transfers. - - - - interrupt_out_endpoints and - interrupt_out() - - These variables provide the same information as - bulk_out_endpoints and bulk_out, - but for endpoints that support interrupt OUT transfers. - - - - - - -Testing Bulk 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: - - - - endpoint - - 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. - - - - direction - - This should be either in or out. - - - - number of transfers - - 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. - - -Data - -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. - - - - 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. - - - - bytefill - - The entire buffer will be filled with a single byte, as per - memset. - - - - intfill - - 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. - - - - byteseq - - 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. - - - - wordseq - - 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, -…. - - - -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. - - - -I/O Mechanism - -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. - - - -Transmit Size - -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. - - - -Receive Size - -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. - - - -Transmit and Receive Delays - -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. - - - - - -Other Types of Transfer - -Support for testing other types of USB traffic such as isochronous -transfers is not yet implemented. - - - -Starting a Test and Collecting Results - -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. - - - -Existing Test Scripts - -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: - - - list.tcl - - 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. - - - verbose.tcl - - 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. - - - - - -Possible Problems - -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. - - - - - - - - - - Index: slave/v2_0/ChangeLog =================================================================== --- slave/v2_0/ChangeLog (revision 174) +++ slave/v2_0/ChangeLog (nonexistent) @@ -1,152 +0,0 @@ -2003-02-25 Jonathan Larmour - - * doc/usbs.sgml: Declare as not to get - correct TOC numbering. - -2003-02-24 Jonathan Larmour - - * cdl/usbs.cdl: Update doc links. - - * doc/usbs.sgml: Comment out DOCTYPE for now to allow building - with standard doc build. - -2003-02-12 Bart Veer - - * host/Makefile.in, host/configure: - Regenerate after toplevel acinclude.m4 update - -2002-09-23 Bart Veer - - * host/configure.in: - Only build if the required Linux kernel support is present. - -2002-09-21 Bart Veer - - * host/usbhost.c: - Avoid const compatibility problems with Tcl 8.4 - -2002-01-23 Bart Veer - - * host/Makefile.am, host/Makefile.in, host/acinclude.m4, - host/aclocal.m4, host/configure, host/configure.in, - host/usbhost.c, host/usbhost.tcl, host/verbose.tcl - Host-side support for USB testing - - * tests/usbtarget.c, tests/common.c, tests/protocol.h: - New files containing the target-side testing support and - support files. - - * cdl/usbs.cdl: - Add a configuration option to build the target-side testing - support. - - * doc/usbs.sgml, doc/*.html: - Document the testing support. Regenerate html. - -2001-09-14 Bart Veer - - * doc/usbs.sgml, doc/*.html: - Fix the example strings in the enumeration data. - Regenerate html. - - * include/usbs.h: - Update the USB testing data structure - - * src/usbs.c (usbs_handle_standard_control): - Fix an assertion for the special case of a USB configuration that - defines no endpoints. - -2001-08-06 Bart Veer - - * include/usbs.h: - Define additional data structures required for USB testing. - -2001-06-19 Bart Veer - - * src/usbs.c, include/usbs.h (usbs_devtab_cread): - read operations should not take a const buffer - -2001-02-02 Bart Veer - - * cdl/usbs.cdl: - Add doc property to point at the HTML - - * doc/usbs.sgml, *.html: - Incorporate changes from docs department, regenerate HTML - -2001-01-25 Bart Veer - - * src/usbs.c: - * include/usbs.h: - Only declare the devtab support functions if the I/O package is - present, since that provides required data types. - - * cdl/usbs.cdl: - devtab support should be enabled by default iff the I/O package is - present. - -2001-01-22 Bart Veer - - * doc/usbs.sgml, doc/makefile: - Added documentation - -2001-01-16 Bart Veer - - * include/usbs.h: - * src/usbs.c: - Update the start() and poll() functions to match the documentation. - -2000-12-15 Bart Veer - - * src/usbs.c: - Fix missing return statements. - -2000-11-28 Bart Veer - - * cdl/usbs.cdl - * include/usbs.h: - * usbs.c - Update interface to USB device drivers - -2000-11-22 Bart Veer - - * include/usbs.h: Fix nested #include protection - -2000-11-21 Bart Veer - - * First check-in of eCos USB support. - -//=========================================================================== -//####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#### -//=========================================================================== Index: slave/v2_0/src/usbs.c =================================================================== --- slave/v2_0/src/usbs.c (revision 174) +++ slave/v2_0/src/usbs.c (nonexistent) @@ -1,713 +0,0 @@ -//========================================================================== -// -// usbs.c -// -// Generic USB slave-side support -// -//========================================================================== -//####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#### -// -// Author(s): bartv -// Contributors: bartv -// Date: 2000-10-04 -// -//####DESCRIPTIONEND#### -// -//========================================================================== - -#include -#include -#include -#include -#include -#include -#include - -// ---------------------------------------------------------------------------- -// Devtab entry support. This code can be compiled with no overheads as -// long as the necessary support package is in place. -#ifdef CYGPKG_IO -# include -# include -// ---------------------------------------------------------------------------- -// read()/write() functions applied to USB endpoints. These just -// indirect via the usbs_endpoint structures and wait for the -// callback to happen. - -typedef struct usbs_callback_data { - bool completed; - int result; - cyg_drv_mutex_t lock; - cyg_drv_cond_t signal; -} usbs_callback_data; - -static void -usbs_devtab_callback(void* arg, int result) -{ - usbs_callback_data* callback_data = (usbs_callback_data*) arg; - callback_data->result = result; - callback_data->completed = true; - cyg_drv_cond_signal(&(callback_data->signal)); -} - -Cyg_ErrNo -usbs_devtab_cwrite(cyg_io_handle_t handle, const void* buf, cyg_uint32* size) -{ - usbs_callback_data wait; - cyg_devtab_entry_t* devtab_entry; - usbs_tx_endpoint* endpoint; - int result = ENOERR; - - CYG_REPORT_FUNCTION(); - - wait.completed = 0; - cyg_drv_mutex_init(&wait.lock); - cyg_drv_cond_init(&wait.signal, &wait.lock); - - devtab_entry = (cyg_devtab_entry_t*) handle; - CYG_CHECK_DATA_PTR( devtab_entry, "A valid endpoint must be supplied"); - endpoint = (usbs_tx_endpoint*) devtab_entry->priv; - - CYG_CHECK_DATA_PTR( endpoint, "The handle must correspond to a USB endpoint"); - CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The endpoint must have a start_tx function"); - - endpoint->buffer = (unsigned char*) buf; - endpoint->buffer_size = (int) *size; - endpoint->complete_fn = &usbs_devtab_callback; - endpoint->complete_data = (void*) &wait; - (*endpoint->start_tx_fn)(endpoint); - - cyg_drv_mutex_lock(&wait.lock); - while (!wait.completed) { - cyg_drv_cond_wait(&wait.signal); - } - cyg_drv_mutex_unlock(&wait.lock); - if (wait.result < 0) { - result = wait.result; - } else { - *size = wait.result; - } - - cyg_drv_cond_destroy(&wait.signal); - cyg_drv_mutex_destroy(&wait.lock); - - CYG_REPORT_RETURN(); - return result; -} - -Cyg_ErrNo -usbs_devtab_cread(cyg_io_handle_t handle, void* buf, cyg_uint32* size) -{ - usbs_callback_data wait; - cyg_devtab_entry_t* devtab_entry; - usbs_rx_endpoint* endpoint; - int result = ENOERR; - - CYG_REPORT_FUNCTION(); - - wait.completed = 0; - cyg_drv_mutex_init(&wait.lock); - cyg_drv_cond_init(&wait.signal, &wait.lock); - - devtab_entry = (cyg_devtab_entry_t*) handle; - CYG_CHECK_DATA_PTR( devtab_entry, "A valid endpoint must be supplied"); - endpoint = (usbs_rx_endpoint*) devtab_entry->priv; - - CYG_CHECK_DATA_PTR( endpoint, "The handle must correspond to a USB endpoint"); - CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The endpoint must have a start_rx function"); - - endpoint->buffer = (unsigned char*) buf; - endpoint->buffer_size = (int) *size; - endpoint->complete_fn = &usbs_devtab_callback; - endpoint->complete_data = (void*) &wait; - (*endpoint->start_rx_fn)(endpoint); - cyg_drv_mutex_lock(&wait.lock); - while (!wait.completed) { - cyg_drv_cond_wait(&wait.signal); - } - cyg_drv_mutex_unlock(&wait.lock); - if (wait.result < 0) { - result = wait.result; - } else { - *size = wait.result; - } - - cyg_drv_cond_destroy(&wait.signal); - cyg_drv_mutex_destroy(&wait.lock); - - CYG_REPORT_RETURN(); - return result; -} - -// ---------------------------------------------------------------------------- -// More devtab functions, this time related to ioctl() style operations. -Cyg_ErrNo -usbs_devtab_get_config(cyg_io_handle_t handle, cyg_uint32 code, void* buf, cyg_uint32* size) -{ - return -EINVAL; -} - -Cyg_ErrNo -usbs_devtab_set_config(cyg_io_handle_t handle, cyg_uint32 code, const void* buf, cyg_uint32* size) -{ - return -EINVAL; -} - -#endif // CYGPKG_IO - -// ---------------------------------------------------------------------------- -// USB-specific functions that are useful for applications/packages which -// do not want to use the devtab interface. These may get called in DSR -// context. - -void -usbs_start_rx(usbs_rx_endpoint* endpoint) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The USB endpoint must support receive operations"); - (*endpoint->start_rx_fn)(endpoint); -} - -void -usbs_start_rx_buffer(usbs_rx_endpoint* endpoint, - unsigned char* buf, int size, - void (*callback_fn)(void *, int), void* callback_arg) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - CYG_CHECK_FUNC_PTR( endpoint->start_rx_fn, "The USB endpoint must support receive operations"); - - endpoint->buffer = buf; - endpoint->buffer_size = size; - endpoint->complete_fn = callback_fn; - endpoint->complete_data = callback_arg; - (*endpoint->start_rx_fn)(endpoint); -} - -void -usbs_start_tx(usbs_tx_endpoint* endpoint) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The USB endpoint must support receive operations"); - (*endpoint->start_tx_fn)(endpoint); -} - -void -usbs_start_tx_buffer(usbs_tx_endpoint* endpoint, - const unsigned char* buf, int size, - void (*callback_fn)(void*, int), void *callback_arg) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - CYG_CHECK_FUNC_PTR( endpoint->start_tx_fn, "The USB endpoint must support receive operations"); - - endpoint->buffer = buf; - endpoint->buffer_size = size; - endpoint->complete_fn = callback_fn; - endpoint->complete_data = callback_arg; - (*endpoint->start_tx_fn)(endpoint); -} - -void -usbs_start(usbs_control_endpoint* endpoint) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - CYG_CHECK_FUNC_PTR( endpoint->start_fn, "The USB endpoint should have a start function"); - - (*endpoint->start_fn)(endpoint); -} - -cyg_bool -usbs_rx_endpoint_halted(usbs_rx_endpoint* endpoint) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - return endpoint->halted; -} - -cyg_bool -usbs_tx_endpoint_halted(usbs_tx_endpoint* endpoint) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - return endpoint->halted; -} - -void -usbs_set_rx_endpoint_halted(usbs_rx_endpoint* endpoint, cyg_bool halted) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - CYG_CHECK_FUNC_PTR( endpoint->set_halted_fn, "The USB endpoint should have a set-halted function"); - (*endpoint->set_halted_fn)(endpoint, halted); -} - -void -usbs_set_tx_endpoint_halted(usbs_tx_endpoint* endpoint, cyg_bool halted) -{ - CYG_CHECK_DATA_PTR( endpoint, "A valid USB endpoint must be supplied"); - CYG_CHECK_FUNC_PTR( endpoint->set_halted_fn, "The USB endpoint should have a set-halted function"); - (*endpoint->set_halted_fn)(endpoint, halted); -} - -void -usbs_start_rx_endpoint_wait(usbs_rx_endpoint* endpoint, void (*callback_fn)(void*, int), void* callback_data) -{ - endpoint->buffer = (unsigned char*) 0; - endpoint->buffer_size = 0; - endpoint->complete_fn = callback_fn; - endpoint->complete_data = callback_data; - (*endpoint->start_rx_fn)(endpoint); -} - -void -usbs_start_tx_endpoint_wait(usbs_tx_endpoint* endpoint, void (*callback_fn)(void*, int), void* callback_data) -{ - endpoint->buffer = (unsigned char*) 0; - endpoint->buffer_size = 0; - endpoint->complete_fn = callback_fn; - endpoint->complete_data = callback_data; - (*endpoint->start_tx_fn)(endpoint); -} - - -// ---------------------------------------------------------------------------- -// Handling of standard control messages. This will be invoked by -// a USB device driver, usually at DSR level, to process any control -// messages that cannot be handled by the hardware itself and that -// have also not been handled by the application-specific handler -// (if any). -// -// Because this function can run at DSR level performance is important. -// -// The various standard control messages are affected as follows: -// -// clear-feature: nothing can be done here about device requests to -// disable remote-wakeup or about endpoint halt requests. It appears -// to be legal to clear no features on an interface. -// -// get-configuration: if the device is not configured a single byte 0 -// should be returned. Otherwise this code assumes only one configuration -// is supported and its id can be extracted from the enumeration data. -// For more complicated devices get-configuration has to be handled -// at a higher-level. -// -// get-descriptor: this is the big one. It is used to obtain -// the enumeration data. An auxiliary refill function is needed. -// -// get-interface: this can be used to identify the current variant -// for a given interface within a configuration. For simple devices -// there will be only interface, 0. For anything more complicated -// higher level code will have to take care of the request. -// -// get-status. Much the same as clear-feature. -// -// set-address. Must be handled at the device driver level. -// -// set-configuration: a value of 0 is used to deconfigure the device, -// which can be handled here. Otherwise this code assumes that only -// a single configuration is supported and enables that. For anything -// more complicated higher-level code has to handle this request. -// -// set-descriptor: used to update the enumeration data. This is not -// supported here, although higher-level code can choose to do so. -// -// set-feature. See clear-feature and get-status. -// -// set-interface. Variant interfaces are not supported by the -// base code so this request has to be handled at a higher level. -// -// synch-frame. This is only relevant for isochronous transfers -// which are not yet supported, and anyway it is not clear what -// could be done about these requests here. - -// This refill function handles GET_DESCRIPTOR requests for a -// configuration. For details of the control_buffer usage see -// the relevant code in the main callback. -static void -usbs_configuration_descriptor_refill(usbs_control_endpoint* endpoint) -{ - usb_devreq* req = (usb_devreq*) endpoint->control_buffer; - int length = (req->length_hi << 8) | req->length_lo; - int sent = (req->index_hi << 8) | req->index_lo; - int current_interface = req->type; - int last_interface = req->request; - int current_endpoint = req->value_lo; - int last_endpoint = req->value_hi; - cyg_bool done = false; - - if (current_endpoint == last_endpoint) { - // The next transfer should be a single interface - unless we have already finished. - if (current_interface == last_interface) { - done = true; - } else { - endpoint->buffer = (unsigned char*) &(endpoint->enumeration_data->interfaces[current_interface]); - if (USB_INTERFACE_DESCRIPTOR_LENGTH >= (length - sent)) { - endpoint->buffer_size = length - sent; - done = true; - } else { - endpoint->buffer_size = USB_INTERFACE_DESCRIPTOR_LENGTH; - sent += USB_INTERFACE_DESCRIPTOR_LENGTH; - // Note that an interface with zero endpoints is ok. We'll just move - // to the next interface in the next call. - last_endpoint = current_endpoint + - endpoint->enumeration_data->interfaces[current_interface].number_endpoints; - current_interface++; - } - } - } else { - // The next transfer should be a single endpoint. The - // endpoints are actually contiguous array elements - // but may not be packed, so they have to be transferred - // one at a time. - endpoint->buffer = (unsigned char*) &(endpoint->enumeration_data->endpoints[current_endpoint]); - if ((sent + USB_ENDPOINT_DESCRIPTOR_LENGTH) >= length) { - endpoint->buffer_size = length - sent; - done = true; - } else { - endpoint->buffer_size = USB_ENDPOINT_DESCRIPTOR_LENGTH; - current_endpoint ++; - } - } - - if (done) { - endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; - } else { - req->type = (unsigned char) current_interface; - req->value_lo = (unsigned char) current_endpoint; - req->value_hi = (unsigned char) last_endpoint; - req->index_hi = (unsigned char) (sent >> 8); - req->index_lo = (unsigned char) (sent & 0x00FF); - } -} - -usbs_control_return -usbs_handle_standard_control(usbs_control_endpoint* endpoint) -{ - usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN; - usb_devreq* req = (usb_devreq*) endpoint->control_buffer; - int length; - int direction; - int recipient; - - length = (req->length_hi << 8) | req->length_lo; - direction = req->type & USB_DEVREQ_DIRECTION_MASK; - recipient = req->type & USB_DEVREQ_RECIPIENT_MASK; - - if (USB_DEVREQ_CLEAR_FEATURE == req->request) { - - if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) { - // The host should expect no data back, the device must - // be configured, and there are no defined features to clear. - if ((0 == length) && - (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) && - (0 == req->value_lo)) { - - int interface_id = req->index_lo; - CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \ - "Higher level code should have handled this request"); - - if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) { - result = USBS_CONTROL_RETURN_HANDLED; - } else { - result = USBS_CONTROL_RETURN_STALL; - } - - } else { - result = USBS_CONTROL_RETURN_STALL; - } - } - - } else if (USB_DEVREQ_GET_CONFIGURATION == req->request) { - - // Return a single byte 0 if the device is not currently - // configured. Otherwise assume a single configuration - // in the enumeration data and return its id. - if ((1 == length) && (USB_DEVREQ_DIRECTION_IN == direction)) { - - if (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) { - CYG_ASSERT( 1 == endpoint->enumeration_data->device.number_configurations, \ - "Higher level code should have handled this request"); - endpoint->control_buffer[0] = endpoint->enumeration_data->configurations[0].configuration_id; - } else { - endpoint->control_buffer[0] = 0; - } - endpoint->buffer = endpoint->control_buffer; - endpoint->buffer_size = 1; - endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; - endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; - result = USBS_CONTROL_RETURN_HANDLED; - - } else { - result = USBS_CONTROL_RETURN_STALL; - } - - } else if (USB_DEVREQ_GET_DESCRIPTOR == req->request) { - - // The descriptor type is in value_hi. The descriptor index - // is in value_lo. - // The hsot must expect at least one byte of data. - if ((0 == length) || (USB_DEVREQ_DIRECTION_IN != direction)) { - - result = USBS_CONTROL_RETURN_STALL; - - } else if (USB_DEVREQ_DESCRIPTOR_TYPE_DEVICE == req->value_hi) { - - // The device descriptor is easy, it is a single field in the - // enumeration data. - endpoint->buffer = (unsigned char*) &(endpoint->enumeration_data->device); - endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; - endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; - if (length < USB_DEVICE_DESCRIPTOR_LENGTH) { - endpoint->buffer_size = length; - } else { - endpoint->buffer_size = USB_DEVICE_DESCRIPTOR_LENGTH; - } - result = USBS_CONTROL_RETURN_HANDLED; - - } else if (USB_DEVREQ_DESCRIPTOR_TYPE_CONFIGURATION == req->value_hi) { - - // This is where things get messy. We need to supply the - // specified configuration data, followed by some number of - // interfaces and endpoints. Plus there are length limits - // to consider. First check that the specified index is valid. - if (req->value_lo >= endpoint->enumeration_data->device.number_configurations) { - result = USBS_CONTROL_RETURN_STALL; - } else { - // No such luck. OK, supplying the initial block is easy. - endpoint->buffer = (unsigned char*) &(endpoint->enumeration_data->configurations[req->value_lo]); - endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; - - // How much data was actually requested. If only the - // configuration itself is of interest then there is - // no need to worry about the rest. - if (length <= USB_CONFIGURATION_DESCRIPTOR_LENGTH) { - endpoint->buffer_size = length; - endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; - } else { - int i, j; - int start_interface; - int start_endpoint; - endpoint->buffer_size = USB_CONFIGURATION_DESCRIPTOR_LENGTH; - endpoint->fill_buffer_fn = &usbs_configuration_descriptor_refill; - - // The descriptor refill_fn needs to know what next to transfer. - // The desired interfaces and endpoints will be contiguous so - // we need to keep track of the following: - // 1) the current interface index being transferred. - // 2) the last interface that should be transferred. - // 3) the current endpoint index that should be transferred. - // 4) the last endpoint index. This marks interface/endpoint transitions. - // 5) how much has been transferred to date. - // This information can be held in the control_buffer, - // with the length field being preserved. - start_interface = 0; - start_endpoint = 0; - // For all configurations up to the desired one. - for (i = 0; i < req->value_lo; i++) { - int config_interfaces = endpoint->enumeration_data->configurations[i].number_interfaces; - - // For all interfaces in this configuration. - for (j = 0; j < config_interfaces; j++) { - // Add the number of endpoints in this interface to the current count. - CYG_ASSERT( (j + start_interface) < endpoint->enumeration_data->total_number_interfaces, \ - "Valid interface count in enumeration data"); - start_endpoint += endpoint->enumeration_data->interfaces[j + start_interface].number_endpoints; - } - // And update the index for the starting interface. - start_interface += config_interfaces; - } - CYG_ASSERT( start_interface < endpoint->enumeration_data->total_number_interfaces, \ - "Valid interface count in enumeration data"); - CYG_ASSERT( ((0 == endpoint->enumeration_data->total_number_endpoints) && (0 == start_endpoint)) || \ - (start_endpoint < endpoint->enumeration_data->total_number_endpoints), \ - "Valid endpoint count in enumeration data"); - - req->type = (unsigned char) start_interface; - req->request = (unsigned char) (start_interface + - endpoint->enumeration_data->configurations[req->value_lo].number_interfaces - ); - req->value_lo = (unsigned char) start_endpoint; - req->value_hi = (unsigned char) start_endpoint; - req->index_lo = USB_CONFIGURATION_DESCRIPTOR_LENGTH; - req->index_hi = 0; - } - result = USBS_CONTROL_RETURN_HANDLED; - } - - - } else if (USB_DEVREQ_DESCRIPTOR_TYPE_STRING == req->value_hi) { - - // As long as the index is valid, the rest is easy since - // the strings are just held in a simple array. - // NOTE: if multiple languages have to be supported - // then things get more difficult. - if (req->value_lo >= endpoint->enumeration_data->total_number_strings) { - result = USBS_CONTROL_RETURN_STALL; - } else { - endpoint->buffer = (unsigned char*) endpoint->enumeration_data->strings[req->value_lo]; - endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; - endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; - - if (length < endpoint->buffer[0]) { - endpoint->buffer_size = length; - } else { - endpoint->buffer_size = endpoint->buffer[0]; - } - result = USBS_CONTROL_RETURN_HANDLED; - } - - } else { - result = USBS_CONTROL_RETURN_STALL; - } - - } else if (USB_DEVREQ_GET_INTERFACE == req->request) { - - if ((1 != length) || - (USB_DEVREQ_DIRECTION_IN != direction) || - (USBS_STATE_CONFIGURED != (endpoint->state & USBS_STATE_MASK))) { - - result = USBS_CONTROL_RETURN_STALL; - - } else { - int interface_id; - - CYG_ASSERT( (1 == endpoint->enumeration_data->device.number_configurations) && \ - (1 == endpoint->enumeration_data->total_number_interfaces), \ - "Higher level code should have handled this request"); - - interface_id = (req->index_hi << 8) | req->index_lo; - if (interface_id != endpoint->enumeration_data->interfaces[0].interface_id) { - result = USBS_CONTROL_RETURN_STALL; - } else { - endpoint->control_buffer[0] = endpoint->enumeration_data->interfaces[0].alternate_setting; - endpoint->buffer = endpoint->control_buffer; - endpoint->buffer_size = 1; - endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; - endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; - result = USBS_CONTROL_RETURN_HANDLED; - } - } - - } else if (USB_DEVREQ_GET_STATUS == req->request) { - - if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) { - // The host should expect two bytes back, the device must - // be configured, the interface number must be valid. - // The host should expect no data back, the device must - // be configured, and there are no defined features to clear. - if ((2 == length) && - (USB_DEVREQ_DIRECTION_IN == direction) && - (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK))) { - - int interface_id = req->index_lo; - CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \ - "Higher level code should have handled this request"); - - if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) { - - // The request is legit, but there are no defined features for an interface... - endpoint->control_buffer[0] = 0; - endpoint->control_buffer[1] = 0; - endpoint->buffer = endpoint->control_buffer; - endpoint->buffer_size = 2; - endpoint->fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0; - endpoint->complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, cyg_bool)) 0; - result = USBS_CONTROL_RETURN_HANDLED; - - } else { - result = USBS_CONTROL_RETURN_STALL; - } - } else { - result = USBS_CONTROL_RETURN_STALL; - } - } - - } else if (USB_DEVREQ_SET_CONFIGURATION == req->request) { - - // Changing to configuration 0 means a state change from - // configured to addressed. Changing to anything else means a - // state change to configured. Both involve invoking the - // state change callback. If there are multiple configurations - // to choose from then this request has to be handled at - // a higher level. - int old_state = endpoint->state; - if (0 == req->value_lo) { - endpoint->state = USBS_STATE_ADDRESSED; - if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != endpoint->state_change_fn) { - (*endpoint->state_change_fn)(endpoint, endpoint->state_change_data, - USBS_STATE_CHANGE_DECONFIGURED, old_state); - } - result = USBS_CONTROL_RETURN_HANDLED; - - } else { - CYG_ASSERT(1 == endpoint->enumeration_data->device.number_configurations, \ - "Higher level code should have handled this request"); - if (req->value_lo == endpoint->enumeration_data->configurations[0].configuration_id) { - endpoint->state = USBS_STATE_CONFIGURED; - if ((void (*)(usbs_control_endpoint*, void*, usbs_state_change, int))0 != endpoint->state_change_fn) { - (*endpoint->state_change_fn)(endpoint, endpoint->state_change_data, - USBS_STATE_CHANGE_CONFIGURED, old_state); - } - result = USBS_CONTROL_RETURN_HANDLED; - } else { - result = USBS_CONTROL_RETURN_STALL; - } - } - - } else if (USB_DEVREQ_SET_FEATURE == req->request) { - - if (USB_DEVREQ_RECIPIENT_INTERFACE == recipient) { - // The host should expect no data back, the device must - // be configured, and there are no defined features to clear. - if ((0 == length) && - (USBS_STATE_CONFIGURED == (endpoint->state & USBS_STATE_MASK)) && - (0 == req->value_lo)) { - - int interface_id = req->index_lo; - CYG_ASSERT( 1 == endpoint->enumeration_data->total_number_interfaces, \ - "Higher level code should have handled this request"); - - if (interface_id == endpoint->enumeration_data->interfaces[0].interface_id) { - result = USBS_CONTROL_RETURN_HANDLED; - } else { - result = USBS_CONTROL_RETURN_STALL; - } - - } else { - result = USBS_CONTROL_RETURN_STALL; - } - } - - } - - return result; -} Index: slave/v2_0/host/configure =================================================================== --- slave/v2_0/host/configure (revision 174) +++ slave/v2_0/host/configure (nonexistent) @@ -1,2233 +0,0 @@ -#! /bin/sh - -# Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf version 2.13 -# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. - -# Defaults: -ac_help= -ac_default_prefix=/usr/local -# Any additions from configure.in: -ac_help="$ac_help - --enable-maintainer-mode enable make rules and dependencies not useful - (and sometimes confusing) to the casual installer" -ac_help="$ac_help - --enable-debug do a debug rather than a release build" -ac_help="$ac_help - --enable-ansi do an ANSI rather than a unicode build" -ac_help="$ac_help - --with-tcl= location of Tcl header and libraries" -ac_help="$ac_help - --with-tcl-version= version of Tcl to be used" -ac_help="$ac_help - --with-tcl-header= location of Tcl header" -ac_help="$ac_help - --with-tcl-lib= location of Tcl libraries" - -# Initialize some variables set by options. -# The variables have the same names as the options, with -# dashes changed to underlines. -build=NONE -cache_file=./config.cache -exec_prefix=NONE -host=NONE -no_create= -nonopt=NONE -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -target=NONE -verbose= -x_includes=NONE -x_libraries=NONE -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datadir='${prefix}/share' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -libdir='${exec_prefix}/lib' -includedir='${prefix}/include' -oldincludedir='/usr/include' -infodir='${prefix}/info' -mandir='${prefix}/man' - -# Initialize some other variables. -subdirs= -MFLAGS= MAKEFLAGS= -SHELL=${CONFIG_SHELL-/bin/sh} -# Maximum number of lines to put in a shell here document. -ac_max_here_lines=12 - -ac_prev= -for ac_option -do - - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval "$ac_prev=\$ac_option" - ac_prev= - continue - fi - - case "$ac_option" in - -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; - *) ac_optarg= ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case "$ac_option" in - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir="$ac_optarg" ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build="$ac_optarg" ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file="$ac_optarg" ;; - - -datadir | --datadir | --datadi | --datad | --data | --dat | --da) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ - | --da=*) - datadir="$ac_optarg" ;; - - -disable-* | --disable-*) - ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then - { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } - fi - ac_feature=`echo $ac_feature| sed 's/-/_/g'` - eval "enable_${ac_feature}=no" ;; - - -enable-* | --enable-*) - ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then - { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } - fi - ac_feature=`echo $ac_feature| sed 's/-/_/g'` - case "$ac_option" in - *=*) ;; - *) ac_optarg=yes ;; - esac - eval "enable_${ac_feature}='$ac_optarg'" ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix="$ac_optarg" ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he) - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat << EOF -Usage: configure [options] [host] -Options: [defaults in brackets after descriptions] -Configuration: - --cache-file=FILE cache test results in FILE - --help print this message - --no-create do not create output files - --quiet, --silent do not print \`checking...' messages - --version print the version of autoconf that created configure -Directory and file names: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [same as prefix] - --bindir=DIR user executables in DIR [EPREFIX/bin] - --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] - --libexecdir=DIR program executables in DIR [EPREFIX/libexec] - --datadir=DIR read-only architecture-independent data in DIR - [PREFIX/share] - --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data in DIR - [PREFIX/com] - --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] - --libdir=DIR object code libraries in DIR [EPREFIX/lib] - --includedir=DIR C header files in DIR [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] - --infodir=DIR info documentation in DIR [PREFIX/info] - --mandir=DIR man documentation in DIR [PREFIX/man] - --srcdir=DIR find the sources in DIR [configure dir or ..] - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM - run sed PROGRAM on installed program names -EOF - cat << EOF -Host type: - --build=BUILD configure for building on BUILD [BUILD=HOST] - --host=HOST configure for HOST [guessed] - --target=TARGET configure for TARGET [TARGET=HOST] -Features and packages: - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --x-includes=DIR X include files are in DIR - --x-libraries=DIR X library files are in DIR -EOF - if test -n "$ac_help"; then - echo "--enable and --with options recognized:$ac_help" - fi - exit 0 ;; - - -host | --host | --hos | --ho) - ac_prev=host ;; - -host=* | --host=* | --hos=* | --ho=*) - host="$ac_optarg" ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir="$ac_optarg" ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir="$ac_optarg" ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir="$ac_optarg" ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir="$ac_optarg" ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst \ - | --locals | --local | --loca | --loc | --lo) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* \ - | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) - localstatedir="$ac_optarg" ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir="$ac_optarg" ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir="$ac_optarg" ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix="$ac_optarg" ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix="$ac_optarg" ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix="$ac_optarg" ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name="$ac_optarg" ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir="$ac_optarg" ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir="$ac_optarg" ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site="$ac_optarg" ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir="$ac_optarg" ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir="$ac_optarg" ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target="$ac_optarg" ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers) - echo "configure generated by autoconf version 2.13" - exit 0 ;; - - -with-* | --with-*) - ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then - { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } - fi - ac_package=`echo $ac_package| sed 's/-/_/g'` - case "$ac_option" in - *=*) ;; - *) ac_optarg=yes ;; - esac - eval "with_${ac_package}='$ac_optarg'" ;; - - -without-* | --without-*) - ac_package=`echo $ac_option|sed -e 's/-*without-//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then - { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } - fi - ac_package=`echo $ac_package| sed 's/-/_/g'` - eval "with_${ac_package}=no" ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes="$ac_optarg" ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries="$ac_optarg" ;; - - -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } - ;; - - *) - if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then - echo "configure: warning: $ac_option: invalid host type" 1>&2 - fi - if test "x$nonopt" != xNONE; then - { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } - fi - nonopt="$ac_option" - ;; - - esac -done - -if test -n "$ac_prev"; then - { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } -fi - -trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 - -# File descriptor usage: -# 0 standard input -# 1 file creation -# 2 errors and warnings -# 3 some systems may open it to /dev/tty -# 4 used on the Kubota Titan -# 6 checking for... messages and results -# 5 compiler messages saved in config.log -if test "$silent" = yes; then - exec 6>/dev/null -else - exec 6>&1 -fi -exec 5>./config.log - -echo "\ -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. -" 1>&5 - -# Strip out --no-create and --no-recursion so they do not pile up. -# Also quote any args containing shell metacharacters. -ac_configure_args= -for ac_arg -do - case "$ac_arg" in - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c) ;; - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) - ac_configure_args="$ac_configure_args '$ac_arg'" ;; - *) ac_configure_args="$ac_configure_args $ac_arg" ;; - esac -done - -# NLS nuisances. -# Only set these to C if already set. These must not be set unconditionally -# because not all systems understand e.g. LANG=C (notably SCO). -# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! -# Non-C LC_CTYPE values break the ctype check. -if test "${LANG+set}" = set; then LANG=C; export LANG; fi -if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi -if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi -if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -rf conftest* confdefs.h -# AIX cpp loses on an empty file, so make sure it contains at least a newline. -echo > confdefs.h - -# A filename unique to this package, relative to the directory that -# configure is in, which we can look for to find out if srcdir is correct. -ac_unique_file=usbhost.c - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then its parent. - ac_prog=$0 - ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` - test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. - srcdir=$ac_confdir - if test ! -r $srcdir/$ac_unique_file; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r $srcdir/$ac_unique_file; then - if test "$ac_srcdir_defaulted" = yes; then - { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } - else - { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } - fi -fi -srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` - -# Prefer explicitly selected file to automatically selected ones. -if test -z "$CONFIG_SITE"; then - if test "x$prefix" != xNONE; then - CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" - else - CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" - fi -fi -for ac_site_file in $CONFIG_SITE; do - if test -r "$ac_site_file"; then - echo "loading site script $ac_site_file" - . "$ac_site_file" - fi -done - -if test -r "$cache_file"; then - echo "loading cache $cache_file" - . $cache_file -else - echo "creating cache $cache_file" - > $cache_file -fi - -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -ac_exeext= -ac_objext=o -if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then - # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. - if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then - ac_n= ac_c=' -' ac_t=' ' - else - ac_n=-n ac_c= ac_t= - fi -else - ac_n= ac_c='\c' ac_t= -fi - - - -ac_aux_dir= -for ac_dir in ../../../../../../acsupport $srcdir/../../../../../../acsupport; do - if test -f $ac_dir/install-sh; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f $ac_dir/install.sh; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - fi -done -if test -z "$ac_aux_dir"; then - { echo "configure: error: can not find install-sh or install.sh in ../../../../../../acsupport $srcdir/../../../../../../acsupport" 1>&2; exit 1; } -fi -ac_config_guess=$ac_aux_dir/config.guess -ac_config_sub=$ac_aux_dir/config.sub -ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. - - - - echo $ac_n "checking that a separate build tree is being used""... $ac_c" 1>&6 -echo "configure:563: checking that a separate build tree is being used" >&5 - ecos_cwd=`/bin/pwd` - if test "${srcdir}" = "." ; then - srcdir=${ecos_cwd} - fi - if test "${ecos_cwd}" = "${srcdir}" ; then - echo "$ac_t""no" 1>&6 - { echo "configure: error: This configure script should not be run inside the source tree. Instead please use a separate build tree" 1>&2; exit 1; } - else - echo "$ac_t""yes" 1>&6 - fi - - -# Make sure we can run config.sub. -if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : -else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } -fi - -echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:582: checking host system type" >&5 - -host_alias=$host -case "$host_alias" in -NONE) - case $nonopt in - NONE) - if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : - else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } - fi ;; - *) host_alias=$nonopt ;; - esac ;; -esac - -host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` -host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` -host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` -host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` -echo "$ac_t""$host" 1>&6 - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# ./install, which can be erroneously created by make from ./install.sh. -echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:614: checking for a BSD compatible install" >&5 -if test -z "$INSTALL"; then -if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" - for ac_dir in $PATH; do - # Account for people who put trailing slashes in PATH elements. - case "$ac_dir/" in - /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - if test -f $ac_dir/$ac_prog; then - if test $ac_prog = install && - grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - else - ac_cv_path_install="$ac_dir/$ac_prog -c" - break 2 - fi - fi - done - ;; - esac - done - IFS="$ac_save_IFS" - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL="$ac_cv_path_install" - else - # As a last resort, use the slow shell script. We don't cache a - # path for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the path is relative. - INSTALL="$ac_install_sh" - fi -fi -echo "$ac_t""$INSTALL" 1>&6 - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 -echo "configure:667: checking whether build environment is sane" >&5 -# Just in case -sleep 1 -echo timestamp > conftestfile -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t $srcdir/configure conftestfile` - fi - if test "$*" != "X $srcdir/configure conftestfile" \ - && test "$*" != "X conftestfile $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - { echo "configure: error: ls -t appears to fail. Make sure there is not a broken -alias in your environment" 1>&2; exit 1; } - fi - - test "$2" = conftestfile - ) -then - # Ok. - : -else - { echo "configure: error: newly created file is older than distributed files! -Check your system clock" 1>&2; exit 1; } -fi -rm -f conftest* -echo "$ac_t""yes" 1>&6 -if test "$program_transform_name" = s,x,x,; then - program_transform_name= -else - # Double any \ or $. echo might interpret backslashes. - cat <<\EOF_SED > conftestsed -s,\\,\\\\,g; s,\$,$$,g -EOF_SED - program_transform_name="`echo $program_transform_name|sed -f conftestsed`" - rm -f conftestsed -fi -test "$program_prefix" != NONE && - program_transform_name="s,^,${program_prefix},; $program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" - -# sed with no file args requires a program. -test "$program_transform_name" = "" && program_transform_name="s,x,x," - -echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:724: checking whether ${MAKE-make} sets \${MAKE}" >&5 -set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftestmake <<\EOF -all: - @echo 'ac_maketemp="${MAKE}"' -EOF -# GNU make sometimes prints "make[1]: Entering...", which would confuse us. -eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` -if test -n "$ac_maketemp"; then - eval ac_cv_prog_make_${ac_make}_set=yes -else - eval ac_cv_prog_make_${ac_make}_set=no -fi -rm -f conftestmake -fi -if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then - echo "$ac_t""yes" 1>&6 - SET_MAKE= -else - echo "$ac_t""no" 1>&6 - SET_MAKE="MAKE=${MAKE-make}" -fi - - -PACKAGE=usbhost - -VERSION=0.1 - -if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then - { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } -fi - - - -missing_dir=`cd $ac_aux_dir && pwd` -echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 -echo "configure:763: checking for working aclocal" >&5 -# Run test in a subshell; some versions of sh will print an error if -# an executable is not found, even if stderr is redirected. -# Redirect stdin to placate older versions of autoconf. Sigh. -if (aclocal --version) < /dev/null > /dev/null 2>&1; then - ACLOCAL=aclocal - echo "$ac_t""found" 1>&6 -else - ACLOCAL="$missing_dir/missing aclocal" - echo "$ac_t""missing" 1>&6 -fi - -echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 -echo "configure:776: checking for working autoconf" >&5 -# Run test in a subshell; some versions of sh will print an error if -# an executable is not found, even if stderr is redirected. -# Redirect stdin to placate older versions of autoconf. Sigh. -if (autoconf --version) < /dev/null > /dev/null 2>&1; then - AUTOCONF=autoconf - echo "$ac_t""found" 1>&6 -else - AUTOCONF="$missing_dir/missing autoconf" - echo "$ac_t""missing" 1>&6 -fi - -echo $ac_n "checking for working automake""... $ac_c" 1>&6 -echo "configure:789: checking for working automake" >&5 -# Run test in a subshell; some versions of sh will print an error if -# an executable is not found, even if stderr is redirected. -# Redirect stdin to placate older versions of autoconf. Sigh. -if (automake --version) < /dev/null > /dev/null 2>&1; then - AUTOMAKE=automake - echo "$ac_t""found" 1>&6 -else - AUTOMAKE="$missing_dir/missing automake" - echo "$ac_t""missing" 1>&6 -fi - -echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 -echo "configure:802: checking for working autoheader" >&5 -# Run test in a subshell; some versions of sh will print an error if -# an executable is not found, even if stderr is redirected. -# Redirect stdin to placate older versions of autoconf. Sigh. -if (autoheader --version) < /dev/null > /dev/null 2>&1; then - AUTOHEADER=autoheader - echo "$ac_t""found" 1>&6 -else - AUTOHEADER="$missing_dir/missing autoheader" - echo "$ac_t""missing" 1>&6 -fi - -echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 -echo "configure:815: checking for working makeinfo" >&5 -# Run test in a subshell; some versions of sh will print an error if -# an executable is not found, even if stderr is redirected. -# Redirect stdin to placate older versions of autoconf. Sigh. -if (makeinfo --version) < /dev/null > /dev/null 2>&1; then - MAKEINFO=makeinfo - echo "$ac_t""found" 1>&6 -else - MAKEINFO="$missing_dir/missing makeinfo" - echo "$ac_t""missing" 1>&6 -fi - - -echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 -echo "configure:829: checking whether to enable maintainer-specific portions of Makefiles" >&5 - # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. -if test "${enable_maintainer_mode+set}" = set; then - enableval="$enable_maintainer_mode" - USE_MAINTAINER_MODE=$enableval -else - USE_MAINTAINER_MODE=no -fi - - echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6 - - -if test $USE_MAINTAINER_MODE = yes; then - MAINTAINER_MODE_TRUE= - MAINTAINER_MODE_FALSE='#' -else - MAINTAINER_MODE_TRUE='#' - MAINTAINER_MODE_FALSE= -fi - MAINT=$MAINTAINER_MODE_TRUE - - - -case "${host}" in - *-*-linux-gnu* ) SUPPORTED="yes";; - * ) SUPPORTED="no" -esac - -if test "${SUPPORTED}" = "no" ; then - echo "configure: warning: USB testing is only supported on Linux hosts" 1>&2 -else - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:863: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_CC="gcc" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:893: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_prog_rejected=no - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - break - fi - done - IFS="$ac_save_ifs" -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# -gt 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - set dummy "$ac_dir/$ac_word" "$@" - shift - ac_cv_prog_CC="$@" - fi -fi -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - - if test -z "$CC"; then - case "`uname -s`" in - *win32* | *WIN32*) - # Extract the first word of "cl", so it can be a program name with args. -set dummy cl; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:944: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_CC="cl" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - ;; - esac - fi - test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } -fi - -echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:976: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 - -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -cat > conftest.$ac_ext << EOF - -#line 987 "configure" -#include "confdefs.h" - -main(){return(0);} -EOF -if { (eval echo configure:992: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - ac_cv_prog_cc_works=yes - # If we can't run a trivial program, we are probably using a cross compiler. - if (./conftest; exit) 2>/dev/null; then - ac_cv_prog_cc_cross=no - else - ac_cv_prog_cc_cross=yes - fi -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_cv_prog_cc_works=no -fi -rm -fr conftest* -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 -if test $ac_cv_prog_cc_works = no; then - { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } -fi -echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:1018: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 -echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 -cross_compiling=$ac_cv_prog_cc_cross - -echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1023: checking whether we are using GNU C" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then - ac_cv_prog_gcc=yes -else - ac_cv_prog_gcc=no -fi -fi - -echo "$ac_t""$ac_cv_prog_gcc" 1>&6 - -if test $ac_cv_prog_gcc = yes; then - GCC=yes -else - GCC= -fi - -ac_test_CFLAGS="${CFLAGS+set}" -ac_save_CFLAGS="$CFLAGS" -CFLAGS= -echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:1051: checking whether ${CC-cc} accepts -g" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - echo 'void f(){}' > conftest.c -if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then - ac_cv_prog_cc_g=yes -else - ac_cv_prog_cc_g=no -fi -rm -f conftest* - -fi - -echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 -if test "$ac_test_CFLAGS" = set; then - CFLAGS="$ac_save_CFLAGS" -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi - - for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl -do -# Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1087: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_CXX="$ac_prog" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -CXX="$ac_cv_prog_CXX" -if test -n "$CXX"; then - echo "$ac_t""$CXX" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -test -n "$CXX" && break -done -test -n "$CXX" || CXX="gcc" - - -echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:1119: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 - -ac_ext=C -# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cxx_cross - -cat > conftest.$ac_ext << EOF - -#line 1130 "configure" -#include "confdefs.h" - -int main(){return(0);} -EOF -if { (eval echo configure:1135: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - ac_cv_prog_cxx_works=yes - # If we can't run a trivial program, we are probably using a cross compiler. - if (./conftest; exit) 2>/dev/null; then - ac_cv_prog_cxx_cross=no - else - ac_cv_prog_cxx_cross=yes - fi -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_cv_prog_cxx_works=no -fi -rm -fr conftest* -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 -if test $ac_cv_prog_cxx_works = no; then - { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } -fi -echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:1161: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 -echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 -cross_compiling=$ac_cv_prog_cxx_cross - -echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 -echo "configure:1166: checking whether we are using GNU C++" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then - ac_cv_prog_gxx=yes -else - ac_cv_prog_gxx=no -fi -fi - -echo "$ac_t""$ac_cv_prog_gxx" 1>&6 - -if test $ac_cv_prog_gxx = yes; then - GXX=yes -else - GXX= -fi - -ac_test_CXXFLAGS="${CXXFLAGS+set}" -ac_save_CXXFLAGS="$CXXFLAGS" -CXXFLAGS= -echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 -echo "configure:1194: checking whether ${CXX-g++} accepts -g" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - echo 'void f(){}' > conftest.cc -if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then - ac_cv_prog_cxx_g=yes -else - ac_cv_prog_cxx_g=no -fi -rm -f conftest* - -fi - -echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS="$ac_save_CXXFLAGS" -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi - -for ac_declaration in \ - ''\ - '#include ' \ - 'extern "C" void std::exit (int) throw (); using std::exit;' \ - 'extern "C" void std::exit (int); using std::exit;' \ - 'extern "C" void exit (int) throw ();' \ - 'extern "C" void exit (int);' \ - 'void exit (int);' -do - cat > conftest.$ac_ext < -$ac_declaration -int main() { -exit (42); -; return 0; } -EOF -if { (eval echo configure:1243: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - : -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - continue -fi -rm -f conftest* - cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - break -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 -fi -rm -f conftest* -done -if test -n "$ac_declaration"; then - echo '#ifdef __cplusplus' >>confdefs.h - echo $ac_declaration >>confdefs.h - echo '#endif' >>confdefs.h -fi - - - echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:1277: checking whether ln -s works" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - rm -f conftestdata -if ln -s X conftestdata 2>/dev/null -then - rm -f conftestdata - ac_cv_prog_LN_S="ln -s" -else - ac_cv_prog_LN_S=ln -fi -fi -LN_S="$ac_cv_prog_LN_S" -if test "$ac_cv_prog_LN_S" = "ln -s"; then - echo "$ac_t""yes" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - - echo $ac_n "checking for object suffix""... $ac_c" 1>&6 -echo "configure:1298: checking for object suffix" >&5 -if eval "test \"`echo '$''{'ac_cv_objext'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - rm -f conftest* -echo 'int i = 1;' > conftest.$ac_ext -if { (eval echo configure:1304: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - for ac_file in conftest.*; do - case $ac_file in - *.c) ;; - *) ac_cv_objext=`echo $ac_file | sed -e s/conftest.//` ;; - esac - done -else - { echo "configure: error: installation or configuration problem; compiler does not work" 1>&2; exit 1; } -fi -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_objext" 1>&6 -OBJEXT=$ac_cv_objext -ac_objext=$ac_cv_objext - - echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:1322: checking for Cygwin environment" >&5 -if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_cygwin=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_cygwin=no -fi -rm -f conftest* -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_cygwin" 1>&6 -CYGWIN= -test "$ac_cv_cygwin" = yes && CYGWIN=yes -echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 -echo "configure:1355: checking for mingw32 environment" >&5 -if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_mingw32=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_mingw32=no -fi -rm -f conftest* -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_mingw32" 1>&6 -MINGW32= -test "$ac_cv_mingw32" = yes && MINGW32=yes - - -echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:1386: checking for executable suffix" >&5 -if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$CYGWIN" = yes || test "$MINGW32" = yes; then - ac_cv_exeext=.exe -else - rm -f conftest* - echo 'int main () { return 0; }' > conftest.$ac_ext - ac_cv_exeext= - if { (eval echo configure:1396: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then - for file in conftest.*; do - case $file in - *.c | *.o | *.obj) ;; - *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;; - esac - done - else - { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; } - fi - rm -f conftest* - test x"${ac_cv_exeext}" = x && ac_cv_exeext=no -fi -fi - -EXEEXT="" -test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext} -echo "$ac_t""${ac_cv_exeext}" 1>&6 -ac_exeext=$EXEEXT - - - ecos_CFLAGS="" - ecos_CXXFLAGS="" - ecos_LDADD="" - ecos_INCLUDES="" - ecos_LIBS="" - - - - - - - - - - - - echo $ac_n "checking "for Visual C++"""... $ac_c" 1>&6 -echo "configure:1434: checking "for Visual C++"" >&5 - MSVC="no"; - if test "${CC}" = "cl" ; then - MSVC="yes" - CXX="cl" - MSVC_SRCDIR=${srcdir} - - - - if test "${MSVC}" = "yes" ; then - MSVC_SRCDIR=`cygpath -w ${MSVC_SRCDIR} | tr \\\\\\\\ /` - fi - - - ecos_INCLUDES="${ecos_INCLUDES} \"-I${MSVC_SRCDIR}\"" - ecos_LDADD="-link" - ecos_LIBS="advapi32.lib" - fi - - -if test "${MSVC}" = "yes"; then - MSVC_TRUE= - MSVC_FALSE='#' -else - MSVC_TRUE='#' - MSVC_FALSE= -fi - if test "${MSVC}" = "yes" ; then - echo "$ac_t""unfortunately yes" 1>&6 - else - echo "$ac_t""no" 1>&6 - fi - - - - - - - - echo $ac_n "checking "the default compiler flags"""... $ac_c" 1>&6 -echo "configure:1474: checking "the default compiler flags"" >&5 - - ecosflags_enable_debug="no" - # Check whether --enable-debug or --disable-debug was given. -if test "${enable_debug+set}" = set; then - enableval="$enable_debug" - case "${enableval}" in - yes) ecosflags_enable_debug="yes" ;; - *) ecosflags_enable_debug="no" ;; - esac -fi - - - ecosflags_enable_ansi="no" - if test "${MSVC}" = "yes" ; then - # Check whether --enable-ansi or --disable-ansi was given. -if test "${enable_ansi+set}" = set; then - enableval="$enable_ansi" - case "${enableval}" in - yes) ecosflags_enable_ansi="yes" ;; - *) ecosflags_enable_ansi="no" ;; - esac -fi - - fi - - if test "${GCC}" = "yes" ; then - ecos_CFLAGS="${ecos_CFLAGS} -pipe -Wall -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs" - ecos_CXXFLAGS="${ecos_CXXFLAGS} -pipe -Wall -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Woverloaded-virtual" - elif test "${MSVC}" = "yes" ; then - ecos_CFLAGS="${ecos_CFLAGS} -nologo -W3" - ecos_CXXFLAGS="${ecos_CXXFLAGS} -nologo -W3 -GR -GX" - else - { echo "configure: error: "default flags for ${CC} are not known"" 1>&2; exit 1; } - fi - - if test "${ecosflags_enable_debug}" = "yes" ; then - if test "${GCC}" = "yes" ; then - ecos_CFLAGS="${ecos_CFLAGS} -g -O0" - ecos_CXXFLAGS="${ecos_CXXFLAGS} -g -O0" - elif test "${MSVC}" = "yes" ; then - ecos_CFLAGS="${ecos_CFLAGS} -MDd -Zi" - ecos_CXXFLAGS="${ecos_CXXFLAGS} -MDd -Zi" - fi - else - if test "${GCC}" = "yes" ; then - ecos_CFLAGS="${ecos_CFLAGS} -O0" - ecos_CXXFLAGS="${ecos_CXXFLAGS} -O0" - elif test "${MSVC}" = "yes" ; then - ecos_CFLAGS="${ecos_CFLAGS} -MD -O2" - ecos_CXXFLAGS="${ecos_CXXFLAGS} -MD -O2" - fi - fi - - CFLAGS="${ac_save_CFLAGS}" - CXXFLAGS="${ac_save_CXXFLAGS}" - - echo "$ac_t""done" 1>&6 - - - - package_dir=`cd ${srcdir} && /bin/pwd` - PACKAGE_VERSION=`dirname ${package_dir}` - PACKAGE_VERSION=`basename ${PACKAGE_VERSION}` - - package_dir=`dirname ${package_dir}` - package_dir=`dirname ${package_dir}` - - possibles="${package_dir}/.. ${package_dir}/../.. ${package_dir}/../../.. ${package_dir}/../../../.." - possibles="${possibles} ${package_dir}/../../../../.. ${package_dir}/../../../../../.." - - repository_root="" - for i in ${possibles}; do - if test -d "$i/"acsupport""; then - repository_root=$i - break - fi - done - - if test "${repository_root}" = "" ; then - { echo "configure: error: Failed to identify this package's position within the eCos repository" 1>&2; exit 1; } - fi - ECOS_REPOSITORY=`cd "${repository_root}/packages/pkgconf/.." && /bin/pwd` - - PACKAGE_DIR=`echo ${package_dir} | sed -e "s:${ECOS_REPOSITORY}/::"` - - PACKAGE_INSTALL="${PACKAGE_DIR}/${PACKAGE_VERSION}" - - - - - - - - - - - - - ecos_tk_libs="" - ecos_tk_libdir="" - - echo $ac_n "checking for Tcl installation""... $ac_c" 1>&6 -echo "configure:1577: checking for Tcl installation" >&5 - # Check whether --with-tcl or --without-tcl was given. -if test "${with_tcl+set}" = set; then - withval="$with_tcl" - : -fi - - # Check whether --with-tcl-version or --without-tcl-version was given. -if test "${with_tcl_version+set}" = set; then - withval="$with_tcl_version" - : -fi - - - if test "${MSVC}" = "yes" ; then - # Check whether --with-tcl-header or --without-tcl-header was given. -if test "${with_tcl_header+set}" = set; then - withval="$with_tcl_header" - : -fi - - # Check whether --with-tcl-lib or --without-tcl-lib was given. -if test "${with_tcl_lib+set}" = set; then - withval="$with_tcl_lib" - : -fi - - ecos_tcl_incdir="" - ecos_tcl_libdir="" - if test "${with_tcl_version+set}" != set ; then - { echo "configure: error: You must specify a Tcl version using --with-tcl-version=" 1>&2; exit 1; } - fi - if test "${with_tcl_header+set}" = set ; then - ecos_tcl_incdir=${with_tcl_header} - elif test "${with_tcl+set}" = set ; then - ecos_tcl_incdir="${with_tcl}/include" - else - { echo "configure: error: You must specify a Tcl installation with either --with-tcl= or --with-tcl-header=" 1>&2; exit 1; } - fi - if test "${with_tcl_lib+set}" = set; then - ecos_tcl_libdir=${with_tcl_lib} - elif test "${with_tcl+set}" = set; then - ecos_tcl_libdir="${with_tcl}/lib" - else - { echo "configure: error: You must specify a Tcl installation with either --with-tcl= or --with-tcl-lib=" 1>&2; exit 1; } - fi - - if test \! -r "${ecos_tcl_incdir}/tcl.h" ; then - { echo "configure: error: unable to locate Tcl header file tcl.h" 1>&2; exit 1; } - fi - - - - - if test "${MSVC}" = "yes" ; then - ecos_tcl_incdir=`cygpath -w ${ecos_tcl_incdir} | tr \\\\\\\\ /` - fi - - - - - if test "${MSVC}" = "yes" ; then - ecos_tcl_libdir=`cygpath -w ${ecos_tcl_libdir} | tr \\\\\\\\ /` - fi - - ecos_INCLUDES="${ecos_INCLUDES} \"-I${ecos_tcl_incdir}\"" - ecos_LIBS="${ecos_LIBS} tcl${with_tcl_version}.lib" - ecos_LDADD="${ecos_LDADD} \"-libpath=${ecos_tcl_libdir}\"" - - ecos_tk_libs="" - - else - possibles="" - if test "${with_tcl+set}" = set ; then - possibles="${with_tcl}/lib" - if test "${with_tcl_version+set}" = set ; then - possibles="${possibles} ${with_tcl}/lib/tcl${with_tcl_version}" - fi - fi - possibles="${possibles} ${prefix}/lib" - if test "${with_tcl_version+set}" = set ; then - possibles="${possibles} ${prefix}/lib/tcl${with_tcl_version}" - fi - possibles="${possibles} /usr/lib" - if test "${with_tcl_version+set}" = set ; then - possibles="${possibles} /usr/lib/tcl${with_tcl_version}" - fi - - tclconfig="" - for i in ${possibles}; do - if test -r "$i/"tclConfig.sh""; then - tclconfig=$i - break - fi - done - - if test \! -r "${tclconfig}/tclConfig.sh" ; then - { echo "configure: error: unable to locate Tcl configuration file tclConfig.sh" 1>&2; exit 1; } - else - . ${tclconfig}/tclConfig.sh - - if test -z "${TCL_INC_DIR}" ; then - ecos_tcl_incdir="${TCL_PREFIX}/include" - else - ecos_tcl_incdir="${TCL_INC_DIR}" - fi - if test \! -r "${ecos_tcl_incdir}/tcl.h" ; then - { echo "configure: error: unable to locate Tcl header file tcl.h" 1>&2; exit 1; } - else - if test "${ecos_tcl_incdir}" != "/usr/include" ; then - ecos_INCLUDES="${ecos_INCLUDES} -I${ecos_tcl_incdir}" - fi - fi - - if test -z "${TCL_LIB_SPEC}" -a "${with_tcl_version+set}" = set ; then - - libtcl="" - for i in ${possibles}; do - if test -r "$i/"libtcl${with_tcl_version}.a""; then - libtcl=$i - break - fi - done - - if test -r "${libtcl}/libtcl${with_tcl_version}.a" ; then - TCL_LIB_SPEC="-L${libtcl} -ltcl${with_tcl_version}" - fi - fi - if test -z "${TCL_LIB_SPEC}" ; then - - libtcl="" - for i in ${possibles}; do - if test -r "$i/"libtcl.a""; then - libtcl=$i - break - fi - done - - if test -r "${libtcl}/libtcl.a" ; then - TCL_LIB_SPEC="-L${libtcl} -ltcl" - fi - fi - if test -z "${TCL_LIB_SPEC}" ; then - { echo "configure: error: ${tclconfig}/tclConfig.sh does not define TCL_LIB_SPEC" 1>&2; exit 1; } - fi - ecos_LIBS="${ecos_LIBS} ${TCL_LIB_SPEC}" - - possibles=`echo ${possibles} | sed -e 's,tcl,tk,g'` - - tkconfig="" - for i in ${possibles}; do - if test -r "$i/"tkConfig.sh""; then - tkconfig=$i - break - fi - done - - if test \! -r "${tkconfig}/tkConfig.sh" ; then - { echo "configure: error: unable to locate Tk config file tkConfig.sh" 1>&2; exit 1; } - else - . ${tkconfig}/tkConfig.sh - if test -z "${TK_INC_DIR}" ; then - if test "${TK_PREFIX}" = "/usr" ; then - ecos_tk_includes="${TK_XINCLUDES}" - else - ecos_tk_includes="-I${TK_PREFIX}/include ${TK_XINCLUDES}" - fi - else - ecos_tk_includes="-I${TK_INC_DIR} ${TK_XINCLUDES}" - fi - - if test -z "${TK_LIB_SPEC}" -a "${with_tcl_version+set}" = set ; then - - libtk="" - for i in ${possibles}; do - if test -r "$i/"libtk${with_tcl_version}.a""; then - libtk=$i - break - fi - done - - if test -r "${libtk}/libtk${with_tcl_version}.a" ; then - TK_LIB_SPEC="-L${libtk} -ltk${with_tcl_version}" - fi - fi - if test -z "${TK_LIB_SPEC}" ; then - - libtk="" - for i in ${possibles}; do - if test -r "$i/"libtk.a""; then - libtk=$i - break - fi - done - - if test -r "${libtk}/libtk.a" ; then - TK_LIB_SPEC="-L${libtk} -ltk" - fi - fi - if test -z "${TK_LIB_SPEC}" ; then - { echo "configure: error: ${tkconfig}/tkConfig.sh does not define TK_LIB_SPEC" 1>&2; exit 1; } - fi - ecos_tk_libs="${TK_LIB_SPEC} ${TK_LIBS}" - fi - fi - fi - - echo "$ac_t""-I${ecos_tcl_incdir} ${TCL_LIB_SPEC}" 1>&6 - - - - if test "${TK_MAJOR_VERSION}" = "8" ; then - if test ${TK_MINOR_VERSION} -lt 2 ; then - echo "configure: warning: Version 8.2 or greater of Tcl/Tk is required" 1>&2 - SUPPORTED="no" - fi - fi - if test "${SUPPORTED}" = "yes" ; then - echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:1796: checking how to run the C preprocessor" >&5 -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then -if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - # This must be in double quotes, not single quotes, because CPP may get - # substituted into the Makefile and "${CC-cc}" will confuse make. - CPP="${CC-cc} -E" - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. - cat > conftest.$ac_ext < -Syntax Error -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1817: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - CPP="${CC-cc} -E -traditional-cpp" - cat > conftest.$ac_ext < -Syntax Error -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1834: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - CPP="${CC-cc} -nologo -E" - cat > conftest.$ac_ext < -Syntax Error -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1851: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - CPP=/lib/cpp -fi -rm -f conftest* -fi -rm -f conftest* -fi -rm -f conftest* - ac_cv_prog_CPP="$CPP" -fi - CPP="$ac_cv_prog_CPP" -else - ac_cv_prog_CPP="$CPP" -fi -echo "$ac_t""$CPP" 1>&6 - -for ac_hdr in "linux/usb.h" "linux/usbdevice_fs.h" -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1879: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1889: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <&6 -SUPPORTED="no" -fi -done - - if test "${SUPPORTED}" = "no" ; then - echo "configure: warning: Required Linux kernel functionality does not appear to be available" 1>&2 - fi - fi -fi - -if test "${SUPPORTED}" = "no" ; then - echo "configure: warning: The USB testing support cannot be built on this platform." 1>&2 -fi - - - -if test "${SUPPORTED}" = "yes"; then - SUPPORTED_TRUE= - SUPPORTED_FALSE='#' -else - SUPPORTED_TRUE='#' - SUPPORTED_FALSE= -fi - - -trap '' 1 2 15 -cat > confcache <<\EOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs. It is not useful on other systems. -# If it contains results you don't want to keep, you may remove or edit it. -# -# By default, configure uses ./config.cache as the cache file, -# creating it if it does not exist already. You can give configure -# the --cache-file=FILE option to use a different cache file; that is -# what configure does when it calls configure scripts in -# subdirectories, so they share the cache. -# Giving --cache-file=/dev/null disables caching, for debugging configure. -# config.status only pays attention to the cache file if you give it the -# --recheck option to rerun configure. -# -EOF -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, don't put newlines in cache variables' values. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -(set) 2>&1 | - case `(ac_space=' '; set | grep ac_space) 2>&1` in - *ac_space=\ *) - # `set' does not quote correctly, so add quotes (double-quote substitution - # turns \\\\ into \\, and sed turns \\ into \). - sed -n \ - -e "s/'/'\\\\''/g" \ - -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" - ;; - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' - ;; - esac >> confcache -if cmp -s $cache_file confcache; then - : -else - if test -w $cache_file; then - echo "updating cache $cache_file" - cat confcache > $cache_file - else - echo "not updating unwritable cache $cache_file" - fi -fi -rm -f confcache - -trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -# Any assignment to VPATH causes Sun make to only execute -# the first set of double-colon rules, so remove it if not needed. -# If there is a colon in the path, we need to keep it. -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' -fi - -trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 - -# Transform confdefs.h into DEFS. -# Protect against shell expansion while executing Makefile rules. -# Protect against Makefile macro expansion. -cat > conftest.defs <<\EOF -s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g -s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g -s%\[%\\&%g -s%\]%\\&%g -s%\$%$$%g -EOF -DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` -rm -f conftest.defs - - -# Without the "./", some shells look in PATH for config.status. -: ${CONFIG_STATUS=./config.status} - -echo creating $CONFIG_STATUS -rm -f $CONFIG_STATUS -cat > $CONFIG_STATUS </dev/null | sed 1q`: -# -# $0 $ac_configure_args -# -# Compiler output produced by configure, useful for debugging -# configure, is in ./config.log if it exists. - -ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" -for ac_option -do - case "\$ac_option" in - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" - exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; - -version | --version | --versio | --versi | --vers | --ver | --ve | --v) - echo "$CONFIG_STATUS generated by autoconf version 2.13" - exit 0 ;; - -help | --help | --hel | --he | --h) - echo "\$ac_cs_usage"; exit 0 ;; - *) echo "\$ac_cs_usage"; exit 1 ;; - esac -done - -ac_given_srcdir=$srcdir -ac_given_INSTALL="$INSTALL" - -trap 'rm -fr `echo "Makefile:Makefile.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 -EOF -cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF -$ac_vpsub -$extrasub -s%@SHELL@%$SHELL%g -s%@CFLAGS@%$CFLAGS%g -s%@CPPFLAGS@%$CPPFLAGS%g -s%@CXXFLAGS@%$CXXFLAGS%g -s%@FFLAGS@%$FFLAGS%g -s%@DEFS@%$DEFS%g -s%@LDFLAGS@%$LDFLAGS%g -s%@LIBS@%$LIBS%g -s%@exec_prefix@%$exec_prefix%g -s%@prefix@%$prefix%g -s%@program_transform_name@%$program_transform_name%g -s%@bindir@%$bindir%g -s%@sbindir@%$sbindir%g -s%@libexecdir@%$libexecdir%g -s%@datadir@%$datadir%g -s%@sysconfdir@%$sysconfdir%g -s%@sharedstatedir@%$sharedstatedir%g -s%@localstatedir@%$localstatedir%g -s%@libdir@%$libdir%g -s%@includedir@%$includedir%g -s%@oldincludedir@%$oldincludedir%g -s%@infodir@%$infodir%g -s%@mandir@%$mandir%g -s%@host@%$host%g -s%@host_alias@%$host_alias%g -s%@host_cpu@%$host_cpu%g -s%@host_vendor@%$host_vendor%g -s%@host_os@%$host_os%g -s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g -s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g -s%@INSTALL_DATA@%$INSTALL_DATA%g -s%@PACKAGE@%$PACKAGE%g -s%@VERSION@%$VERSION%g -s%@ACLOCAL@%$ACLOCAL%g -s%@AUTOCONF@%$AUTOCONF%g -s%@AUTOMAKE@%$AUTOMAKE%g -s%@AUTOHEADER@%$AUTOHEADER%g -s%@MAKEINFO@%$MAKEINFO%g -s%@SET_MAKE@%$SET_MAKE%g -s%@MAINTAINER_MODE_TRUE@%$MAINTAINER_MODE_TRUE%g -s%@MAINTAINER_MODE_FALSE@%$MAINTAINER_MODE_FALSE%g -s%@MAINT@%$MAINT%g -s%@CC@%$CC%g -s%@CXX@%$CXX%g -s%@LN_S@%$LN_S%g -s%@OBJEXT@%$OBJEXT%g -s%@EXEEXT@%$EXEEXT%g -s%@ecos_CFLAGS@%$ecos_CFLAGS%g -s%@ecos_CXXFLAGS@%$ecos_CXXFLAGS%g -s%@ecos_LDADD@%$ecos_LDADD%g -s%@ecos_INCLUDES@%$ecos_INCLUDES%g -s%@ecos_LIBS@%$ecos_LIBS%g -s%@MSVC_SRCDIR@%$MSVC_SRCDIR%g -s%@MSVC_TRUE@%$MSVC_TRUE%g -s%@MSVC_FALSE@%$MSVC_FALSE%g -s%@ECOS_REPOSITORY@%$ECOS_REPOSITORY%g -s%@PACKAGE_DIR@%$PACKAGE_DIR%g -s%@PACKAGE_VERSION@%$PACKAGE_VERSION%g -s%@PACKAGE_INSTALL@%$PACKAGE_INSTALL%g -s%@ecos_tk_includes@%$ecos_tk_includes%g -s%@ecos_tk_libs@%$ecos_tk_libs%g -s%@CPP@%$CPP%g -s%@SUPPORTED_TRUE@%$SUPPORTED_TRUE%g -s%@SUPPORTED_FALSE@%$SUPPORTED_FALSE%g - -CEOF -EOF - -cat >> $CONFIG_STATUS <<\EOF - -# Split the substitutions into bite-sized pieces for seds with -# small command number limits, like on Digital OSF/1 and HP-UX. -ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. -ac_file=1 # Number of current file. -ac_beg=1 # First line for current file. -ac_end=$ac_max_sed_cmds # Line after last line for current file. -ac_more_lines=: -ac_sed_cmds="" -while $ac_more_lines; do - if test $ac_beg -gt 1; then - sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file - else - sed "${ac_end}q" conftest.subs > conftest.s$ac_file - fi - if test ! -s conftest.s$ac_file; then - ac_more_lines=false - rm -f conftest.s$ac_file - else - if test -z "$ac_sed_cmds"; then - ac_sed_cmds="sed -f conftest.s$ac_file" - else - ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" - fi - ac_file=`expr $ac_file + 1` - ac_beg=$ac_end - ac_end=`expr $ac_end + $ac_max_sed_cmds` - fi -done -if test -z "$ac_sed_cmds"; then - ac_sed_cmds=cat -fi -EOF - -cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF -for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then - # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". - case "$ac_file" in - *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` - ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - *) ac_file_in="${ac_file}.in" ;; - esac - - # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. - - # Remove last slash and all that follows it. Not all systems have dirname. - ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` - if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then - # The file is in a subdirectory. - test ! -d "$ac_dir" && mkdir "$ac_dir" - ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" - # A "../" for each directory in $ac_dir_suffix. - ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` - else - ac_dir_suffix= ac_dots= - fi - - case "$ac_given_srcdir" in - .) srcdir=. - if test -z "$ac_dots"; then top_srcdir=. - else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; - /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; - *) # Relative path. - srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" - top_srcdir="$ac_dots$ac_given_srcdir" ;; - esac - - case "$ac_given_INSTALL" in - [/$]*) INSTALL="$ac_given_INSTALL" ;; - *) INSTALL="$ac_dots$ac_given_INSTALL" ;; - esac - - echo creating "$ac_file" - rm -f "$ac_file" - configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." - case "$ac_file" in - *Makefile*) ac_comsub="1i\\ -# $configure_input" ;; - *) ac_comsub= ;; - esac - - ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` - sed -e "$ac_comsub -s%@configure_input@%$configure_input%g -s%@srcdir@%$srcdir%g -s%@top_srcdir@%$top_srcdir%g -s%@INSTALL@%$INSTALL%g -" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file -fi; done -rm -f conftest.s* - -EOF -cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF - -exit 0 -EOF -chmod +x $CONFIG_STATUS -rm -fr confdefs* $ac_clean_files -test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 - Index: slave/v2_0/host/Makefile.in =================================================================== --- slave/v2_0/host/Makefile.in (revision 174) +++ slave/v2_0/host/Makefile.in (nonexistent) @@ -1,462 +0,0 @@ -# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am - -# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -#####ECOSGPLCOPYRIGHTBEGIN#### -#####ECOSGPLCOPYRIGHTEND#### -#######DESCRIPTIONBEGIN#### -######DESCRIPTIONEND#### - - -SHELL = @SHELL@ - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -bindir = @bindir@ -sbindir = @sbindir@ -libexecdir = @libexecdir@ -datadir = @datadir@ -sysconfdir = @sysconfdir@ -sharedstatedir = @sharedstatedir@ -localstatedir = @localstatedir@ -libdir = @libdir@ -infodir = @infodir@ -mandir = @mandir@ -includedir = @includedir@ -oldincludedir = /usr/include - -DESTDIR = - -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ - -top_builddir = . - -ACLOCAL = @ACLOCAL@ -AUTOCONF = @AUTOCONF@ -AUTOMAKE = @AUTOMAKE@ -AUTOHEADER = @AUTOHEADER@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -transform = @program_transform_name@ - -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -host_alias = @host_alias@ -host_triplet = @host@ -CC = @CC@ -CXX = @CXX@ -ECOS_REPOSITORY = @ECOS_REPOSITORY@ -EXEEXT = @EXEEXT@ -LN_S = @LN_S@ -MAINT = @MAINT@ -MAKEINFO = @MAKEINFO@ -MSVC_SRCDIR = @MSVC_SRCDIR@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_DIR = @PACKAGE_DIR@ -PACKAGE_INSTALL = @PACKAGE_INSTALL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -VERSION = @VERSION@ -ecos_CFLAGS = @ecos_CFLAGS@ -ecos_CXXFLAGS = @ecos_CXXFLAGS@ -ecos_INCLUDES = @ecos_INCLUDES@ -ecos_LDADD = @ecos_LDADD@ -ecos_LIBS = @ecos_LIBS@ -ecos_infra_incdir = @ecos_infra_incdir@ -ecos_infra_libdir = @ecos_infra_libdir@ -ecos_libcdl_incdir = @ecos_libcdl_incdir@ -ecos_libcdl_libdir = @ecos_libcdl_libdir@ -ecos_tk_includes = @ecos_tk_includes@ -ecos_tk_libs = @ecos_tk_libs@ - -AUTOMAKE_OPTIONS = 1.3 foreign - -@SUPPORTED_TRUE@AM_CFLAGS = @SUPPORTED_TRUE@@ecos_CFLAGS@ -DUSBHOST_VERSION=\"@VERSION@\" -DPKGVERSION=\"@PACKAGE_VERSION@\" -DUSBAUXDIR=\"$(libexecdir)/ecos/@PACKAGE_INSTALL@\" -@SUPPORTED_TRUE@AM_CXXFLAGS = @SUPPORTED_TRUE@@ecos_CXXFLAGS@ -@SUPPORTED_TRUE@INCLUDES = @SUPPORTED_TRUE@@ecos_INCLUDES@ -@SUPPORTED_TRUE@LIBS = @SUPPORTED_TRUE@@ecos_LIBS@ @ecos_LDADD@ - -@SUPPORTED_TRUE@noinst_PROGRAMS = @SUPPORTED_TRUE@usbhost -@SUPPORTED_TRUE@usbhost_SOURCES = @SUPPORTED_TRUE@usbhost.c -@SUPPORTED_TRUE@usbhost_DEPENDENCIES = @SUPPORTED_TRUE@../tests/protocol.h ../tests/common.c -@SUPPORTED_TRUE@usbhost_LDADD = @SUPPORTED_TRUE@-lpthread - -@SUPPORTED_TRUE@usbauxdir = @SUPPORTED_TRUE@$(libexecdir)/ecos/@PACKAGE_INSTALL@ -@SUPPORTED_TRUE@usbaux_PROGRAMS = @SUPPORTED_TRUE@usbchmod -@SUPPORTED_TRUE@usbaux_DATA = @SUPPORTED_TRUE@usbhost.tcl list.tcl verbose.tcl -@SUPPORTED_TRUE@usbchmod_SOURCES = @SUPPORTED_TRUE@usbchmod.c -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -mkinstalldirs = $(SHELL) $(top_srcdir)/../../../../../../acsupport/mkinstalldirs -CONFIG_CLEAN_FILES = -@SUPPORTED_TRUE@noinst_PROGRAMS = usbhost$(EXEEXT) -@SUPPORTED_TRUE@usbaux_PROGRAMS = usbchmod$(EXEEXT) -PROGRAMS = $(noinst_PROGRAMS) $(usbaux_PROGRAMS) - - -DEFS = @DEFS@ -I. -I$(srcdir) -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ -@SUPPORTED_TRUE@usbhost_OBJECTS = usbhost.$(OBJEXT) -usbhost_LDFLAGS = -@SUPPORTED_TRUE@usbchmod_OBJECTS = usbchmod.$(OBJEXT) -usbchmod_LDADD = $(LDADD) -usbchmod_DEPENDENCIES = -usbchmod_LDFLAGS = -CFLAGS = @CFLAGS@ -COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ -DATA = $(usbaux_DATA) - -DIST_COMMON = Makefile.am Makefile.in acinclude.m4 aclocal.m4 configure \ -configure.in - - -DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) - -TAR = gtar -GZIP_ENV = --best -DEP_FILES = .deps/usbchmod.P .deps/usbhost.P -SOURCES = $(usbhost_SOURCES) $(usbchmod_SOURCES) -OBJECTS = $(usbhost_OBJECTS) $(usbchmod_OBJECTS) - -all: all-redirect -.SUFFIXES: -.SUFFIXES: .S .c .o .obj .s -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile - -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) - cd $(top_builddir) \ - && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status - -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4 - cd $(srcdir) && $(ACLOCAL) - -config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck -$(srcdir)/configure: @MAINTAINER_MODE_TRUE@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) - cd $(srcdir) && $(AUTOCONF) - -mostlyclean-noinstPROGRAMS: - -clean-noinstPROGRAMS: - -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) - -distclean-noinstPROGRAMS: - -maintainer-clean-noinstPROGRAMS: - -mostlyclean-usbauxPROGRAMS: - -clean-usbauxPROGRAMS: - -test -z "$(usbaux_PROGRAMS)" || rm -f $(usbaux_PROGRAMS) - -distclean-usbauxPROGRAMS: - -maintainer-clean-usbauxPROGRAMS: - -install-usbauxPROGRAMS: $(usbaux_PROGRAMS) - @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(usbauxdir) - @list='$(usbaux_PROGRAMS)'; for p in $$list; do \ - if test -f $$p; then \ - echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(usbauxdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ - $(INSTALL_PROGRAM) $$p $(DESTDIR)$(usbauxdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ - else :; fi; \ - done - -uninstall-usbauxPROGRAMS: - @$(NORMAL_UNINSTALL) - list='$(usbaux_PROGRAMS)'; for p in $$list; do \ - rm -f $(DESTDIR)$(usbauxdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ - done - -# FIXME: We should only use cygpath when building on Windows, -# and only if it is available. -.c.obj: - $(COMPILE) -c `cygpath -w $<` - -.s.o: - $(COMPILE) -c $< - -.S.o: - $(COMPILE) -c $< - -mostlyclean-compile: - -rm -f *.o core *.core - -rm -f *.$(OBJEXT) - -clean-compile: - -distclean-compile: - -rm -f *.tab.c - -maintainer-clean-compile: - -usbhost$(EXEEXT): $(usbhost_OBJECTS) $(usbhost_DEPENDENCIES) - @rm -f usbhost$(EXEEXT) - $(LINK) $(usbhost_LDFLAGS) $(usbhost_OBJECTS) $(usbhost_LDADD) $(LIBS) - -usbchmod$(EXEEXT): $(usbchmod_OBJECTS) $(usbchmod_DEPENDENCIES) - @rm -f usbchmod$(EXEEXT) - $(LINK) $(usbchmod_LDFLAGS) $(usbchmod_OBJECTS) $(usbchmod_LDADD) $(LIBS) - -install-usbauxDATA: $(usbaux_DATA) - @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(usbauxdir) - @list='$(usbaux_DATA)'; for p in $$list; do \ - if test -f $(srcdir)/$$p; then \ - echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(usbauxdir)/$$p"; \ - $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(usbauxdir)/$$p; \ - else if test -f $$p; then \ - echo " $(INSTALL_DATA) $$p $(DESTDIR)$(usbauxdir)/$$p"; \ - $(INSTALL_DATA) $$p $(DESTDIR)$(usbauxdir)/$$p; \ - fi; fi; \ - done - -uninstall-usbauxDATA: - @$(NORMAL_UNINSTALL) - list='$(usbaux_DATA)'; for p in $$list; do \ - rm -f $(DESTDIR)$(usbauxdir)/$$p; \ - done - -tags: TAGS - -ID: $(HEADERS) $(SOURCES) $(LISP) - list='$(SOURCES) $(HEADERS)'; \ - unique=`for i in $$list; do echo $$i; done | \ - awk ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - here=`pwd` && cd $(srcdir) \ - && mkid -f$$here/ID $$unique $(LISP) - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS)'; \ - unique=`for i in $$list; do echo $$i; done | \ - awk ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ - || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) - -mostlyclean-tags: - -clean-tags: - -distclean-tags: - -rm -f TAGS ID - -maintainer-clean-tags: - -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - -rm -rf $(distdir) - GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz - mkdir $(distdir)/=build - mkdir $(distdir)/=inst - dc_install_base=`cd $(distdir)/=inst && pwd`; \ - cd $(distdir)/=build \ - && ../configure --srcdir=.. --prefix=$$dc_install_base \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) dist - -rm -rf $(distdir) - @banner="$(distdir).tar.gz is ready for distribution"; \ - dashes=`echo "$$banner" | sed s/./=/g`; \ - echo "$$dashes"; \ - echo "$$banner"; \ - echo "$$dashes" -dist: distdir - -chmod -R a+r $(distdir) - GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) - -rm -rf $(distdir) -dist-all: distdir - -chmod -R a+r $(distdir) - GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) - -rm -rf $(distdir) -distdir: $(DISTFILES) - -rm -rf $(distdir) - mkdir $(distdir) - -chmod 777 $(distdir) - here=`cd $(top_builddir) && pwd`; \ - top_distdir=`cd $(distdir) && pwd`; \ - distdir=`cd $(distdir) && pwd`; \ - cd $(top_srcdir) \ - && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign Makefile - @for file in $(DISTFILES); do \ - d=$(srcdir); \ - if test -d $$d/$$file; then \ - cp -pr $$d/$$file $(distdir)/$$file; \ - else \ - test -f $(distdir)/$$file \ - || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ - || cp -p $$d/$$file $(distdir)/$$file || :; \ - fi; \ - done - -DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) - --include $(DEP_FILES) - -mostlyclean-depend: - -clean-depend: - -distclean-depend: - -rm -rf .deps - -maintainer-clean-depend: - -%.o: %.c - @echo '$(COMPILE) -c $<'; \ - $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< - @-cp .deps/$(*F).pp .deps/$(*F).P; \ - tr ' ' '\012' < .deps/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*F).P; \ - rm .deps/$(*F).pp - -%.lo: %.c - @echo '$(LTCOMPILE) -c $<'; \ - $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< - @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ - < .deps/$(*F).pp > .deps/$(*F).P; \ - tr ' ' '\012' < .deps/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*F).P; \ - rm -f .deps/$(*F).pp -info-am: -info: info-am -dvi-am: -dvi: dvi-am -check-am: all-am -check: check-am -installcheck-am: -installcheck: installcheck-am -install-exec-am: - @$(NORMAL_INSTALL) - $(MAKE) $(AM_MAKEFLAGS) install-exec-hook -install-exec: install-exec-am - -install-data-am: install-usbauxPROGRAMS install-usbauxDATA - @$(NORMAL_INSTALL) - $(MAKE) $(AM_MAKEFLAGS) install-data-hook -install-data: install-data-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -install: install-am -uninstall-am: uninstall-usbauxPROGRAMS uninstall-usbauxDATA -uninstall: uninstall-am -all-am: Makefile $(PROGRAMS) $(DATA) -all-redirect: all-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install -installdirs: - $(mkinstalldirs) $(DESTDIR)$(usbauxdir) $(DESTDIR)$(usbauxdir) - - -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -rm -f Makefile $(CONFIG_CLEAN_FILES) - -rm -f config.cache config.log stamp-h stamp-h[0-9]* - -maintainer-clean-generic: -mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-usbauxPROGRAMS \ - mostlyclean-compile mostlyclean-tags mostlyclean-depend \ - mostlyclean-generic - -mostlyclean: mostlyclean-am - -clean-am: clean-noinstPROGRAMS clean-usbauxPROGRAMS clean-compile \ - clean-tags clean-depend clean-generic mostlyclean-am - -clean: clean-am - -distclean-am: distclean-noinstPROGRAMS distclean-usbauxPROGRAMS \ - distclean-compile distclean-tags distclean-depend \ - distclean-generic clean-am - -distclean: distclean-am - -rm -f config.status - -maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ - maintainer-clean-usbauxPROGRAMS \ - maintainer-clean-compile maintainer-clean-tags \ - maintainer-clean-depend maintainer-clean-generic \ - distclean-am - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - -maintainer-clean: maintainer-clean-am - -rm -f config.status - -.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ -clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ -mostlyclean-usbauxPROGRAMS distclean-usbauxPROGRAMS \ -clean-usbauxPROGRAMS maintainer-clean-usbauxPROGRAMS \ -uninstall-usbauxPROGRAMS install-usbauxPROGRAMS mostlyclean-compile \ -distclean-compile clean-compile maintainer-clean-compile \ -uninstall-usbauxDATA install-usbauxDATA tags mostlyclean-tags \ -distclean-tags clean-tags maintainer-clean-tags distdir \ -mostlyclean-depend distclean-depend clean-depend \ -maintainer-clean-depend info-am info dvi-am dvi check check-am \ -installcheck-am installcheck install-exec-am install-exec \ -install-data-am install-data install-am install uninstall-am uninstall \ -all-redirect all-am all installdirs mostlyclean-generic \ -distclean-generic clean-generic maintainer-clean-generic clean \ -mostlyclean distclean maintainer-clean - - -@SUPPORTED_TRUE@install-exec-hook: -@SUPPORTED_TRUE@ $(INSTALL_PROGRAM) usbhost $(bindir)/usbhost_@PACKAGE_VERSION@ -@SUPPORTED_TRUE@ rm -f $(bindir)/usbhost -@SUPPORTED_TRUE@ $(LN_S) $(bindir)/usbhost_@PACKAGE_VERSION@ $(bindir)/usbhost - -@SUPPORTED_TRUE@install-data-hook: -@SUPPORTED_TRUE@ chown root $(usbauxdir)/usbchmod -@SUPPORTED_TRUE@ chmod u+s $(usbauxdir)/usbchmod - -@SUPPORTED_FALSE@install-exec-hook: -@SUPPORTED_FALSE@ echo Nothing to be done for this platform - -@SUPPORTED_FALSE@install-data-hook: -@SUPPORTED_FALSE@ echo Nothing to be done for this platform - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: Index: slave/v2_0/host/usbchmod.c =================================================================== --- slave/v2_0/host/usbchmod.c (revision 174) +++ slave/v2_0/host/usbchmod.c (nonexistent) @@ -1,180 +0,0 @@ -//================================================================= -// -// usb_chmod.c -// -// A utility to manipulate /proc/bus/usb access rights -// -//========================================================================== -//####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#### -// -// The Linux kernel allows raw access to USB devices via /proc/bus/usb. -// However, such access requires root privileges: this makes perfect -// sense for typical USB devices, but gets in the way of eCos USB -// testing. This utility runs suid and can be used to change the access -// rights to a specific and validated USB device. -// -// Author(s): bartv -// Date: 2001-07-18 -//####DESCRIPTIONEND#### -//========================================================================== - -#include -#include -#include -#include -#include -#include - -// Note: this code is duplicated in usbhost.c. Any changes here -// should be propagated. For now the routine is too small to warrant -// a separate source file. -#define USB_ROOT "/proc/bus/usb/" -#define PRODUCT_STRING "Red Hat eCos USB test" - -static int -usb_scan_devices(int* bus, int* dev) -{ - FILE* devs_file = fopen(USB_ROOT "devices", "r"); - int current_bus = -1; - int current_dev = -1; - int ch; - - if (NULL == devs_file) { - fprintf(stderr, "Error: unable to access " USB_ROOT "devices\n"); - return 0; - } - ch = getc(devs_file); - while (EOF != ch) { - if ('T' == ch) { - if (2 !=fscanf(devs_file, ": Bus=%d %*[^D\n]Dev#=%d", ¤t_bus, ¤t_dev)) { - current_bus = -1; - current_dev = -1; - } - } else if ('S' == ch) { - int start = 0, end = 0; - if (EOF != fscanf(devs_file, ": Product=%n" PRODUCT_STRING "%n", &start, &end)) { - if (start < end) { - *bus = current_bus; - *dev = current_dev; - break; - } - } - } - // Move to the end of the current line. - do { - ch = getc(devs_file); - } while ((EOF != ch) && ('\n' != ch)); - if (EOF != ch) { - ch = getc(devs_file); - } - } - - fclose(devs_file); - if ((-1 != *bus) && (-1 != *dev)) { - return 1; - } - fprintf(stderr, "Error: failed to find a USB device \"" PRODUCT_STRING "\"\n"); - return 0; -} - -int -main(int argc, char** argv) -{ - int bus, dev; - int actual_bus, actual_dev; - char devname[_POSIX_PATH_MAX]; - long strtol_tmp1; - char* strtol_tmp2; - - if (3 != argc) { - fprintf(stderr, "usb_chmod: wrong number of arguments\n"); - fprintf(stderr, " : usage, usb_chmod \n"); - exit(EXIT_FAILURE); - } - if (('\0' == argv[1][0]) || ('\0' == argv[2][0])) { - fprintf(stderr, "usb_chmod: invalid arguments\n"); - exit(EXIT_FAILURE); - } - - strtol_tmp1 = strtol(argv[1], &strtol_tmp2, 10); - if ('\0' != *strtol_tmp2) { - fprintf(stderr, "usbchmod: invalid first argument, not a number\n"); - exit(EXIT_FAILURE); - } - if (strtol_tmp1 > INT_MAX) { - fprintf(stderr, "usbchmod: invalid first argument, number too large\n"); - exit(EXIT_FAILURE); - } - bus = (int) strtol_tmp1; - - strtol_tmp1 = strtol(argv[2], &strtol_tmp2, 10); - if ('\0' != *strtol_tmp2) { - fprintf(stderr, "usbchmod: invalid second argument, not a number\n"); - exit(EXIT_FAILURE); - } - if (strtol_tmp1 > INT_MAX) { - fprintf(stderr, "usbchmod: invalid second argument, number too large\n"); - exit(EXIT_FAILURE); - } - dev = (int) strtol_tmp1; - - if (!usb_scan_devices(&actual_bus, &actual_dev)) { - fprintf(stderr, "usb_chmod: failed to find eCos USB test application\n"); - exit(EXIT_FAILURE); - } - if ((bus != actual_bus) || (dev != actual_dev)) { - fprintf(stderr, "usbchmod: mismatch between specified and actual USB identifiers.\n"); - fprintf(stderr, " : eCos test application is at %03d/%03d, not %03d/%03d\n", - actual_bus, actual_dev, bus, dev); - exit(EXIT_FAILURE); - } - - if (_POSIX_PATH_MAX == snprintf(devname, _POSIX_PATH_MAX, "/proc/bus/usb/" "%03d/%03d", actual_bus, actual_dev)) { - fprintf(stderr, "usbchmod: internal error, buffer overflow\n"); - exit(EXIT_FAILURE); - } - - if (0 != chmod(devname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) { - int old_errno = errno; - fprintf(stderr, "usbchmod: failed to modify access rights on %s\n", devname); - if ((old_errno >= 0) && (old_errno < sys_nerr)) { - fprintf(stderr, " : %s\n", sys_errlist[old_errno]); - } - exit(EXIT_FAILURE); - } - - return EXIT_SUCCESS; -} Index: slave/v2_0/host/acinclude.m4 =================================================================== --- slave/v2_0/host/acinclude.m4 (revision 174) +++ slave/v2_0/host/acinclude.m4 (nonexistent) @@ -1,54 +0,0 @@ -dnl Process this file with aclocal to get an aclocal.m4 file. Then -dnl process that with autoconf. -dnl ==================================================================== -dnl -dnl acinclude.m4 -dnl -dnl ==================================================================== -dnl ####ECOSGPLCOPYRIGHTBEGIN#### -dnl ------------------------------------------- -dnl This file is part of eCos, the Embedded Configurable Operating System. -dnl Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -dnl -dnl eCos is free software; you can redistribute it and/or modify it under -dnl the terms of the GNU General Public License as published by the Free -dnl Software Foundation; either version 2 or (at your option) any later version. -dnl -dnl eCos is distributed in the hope that it will be useful, but WITHOUT ANY -dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or -dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -dnl for more details. -dnl -dnl You should have received a copy of the GNU General Public License along -dnl with eCos; if not, write to the Free Software Foundation, Inc., -dnl 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -dnl -dnl As a special exception, if other files instantiate templates or use macros -dnl or inline functions from this file, or you compile this file and link it -dnl with other works to produce a work based on this file, this file does not -dnl by itself cause the resulting work to be covered by the GNU General Public -dnl License. However the source code for this file must still be made available -dnl in accordance with section (3) of the GNU General Public License. -dnl -dnl This exception does not invalidate any other reasons why a work based on -dnl this file might be covered by the GNU General Public License. -dnl -dnl Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -dnl at http://sources.redhat.com/ecos/ecos-license/ -dnl ------------------------------------------- -dnl ####ECOSGPLCOPYRIGHTEND#### -dnl ==================================================================== -dnl#####DESCRIPTIONBEGIN#### -dnl -dnl Author(s): bartv -dnl Contact(s): bartv -dnl Date: 2002/01/10 -dnl Version: 0.01 -dnl -dnl####DESCRIPTIONEND#### -dnl ==================================================================== - -dnl Access shared macros. -dnl AM_CONDITIONAL needs to be mentioned here or else aclocal does not -dnl incorporate the macro into aclocal.m4 -sinclude(../../../../../../acsupport/acinclude.m4) Index: slave/v2_0/host/configure.in =================================================================== --- slave/v2_0/host/configure.in (revision 174) +++ slave/v2_0/host/configure.in (nonexistent) @@ -1,115 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -dnl ==================================================================== -dnl -dnl configure.in -dnl -dnl configure script for eCos USB host-side support -dnl -dnl ==================================================================== -dnl ####ECOSGPLCOPYRIGHTBEGIN#### -dnl ------------------------------------------- -dnl This file is part of eCos, the Embedded Configurable Operating System. -dnl Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -dnl -dnl eCos is free software; you can redistribute it and/or modify it under -dnl the terms of the GNU General Public License as published by the Free -dnl Software Foundation; either version 2 or (at your option) any later version. -dnl -dnl eCos is distributed in the hope that it will be useful, but WITHOUT ANY -dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or -dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -dnl for more details. -dnl -dnl You should have received a copy of the GNU General Public License along -dnl with eCos; if not, write to the Free Software Foundation, Inc., -dnl 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -dnl -dnl As a special exception, if other files instantiate templates or use macros -dnl or inline functions from this file, or you compile this file and link it -dnl with other works to produce a work based on this file, this file does not -dnl by itself cause the resulting work to be covered by the GNU General Public -dnl License. However the source code for this file must still be made available -dnl in accordance with section (3) of the GNU General Public License. -dnl -dnl This exception does not invalidate any other reasons why a work based on -dnl this file might be covered by the GNU General Public License. -dnl -dnl Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -dnl at http://sources.redhat.com/ecos/ecos-license/ -dnl ------------------------------------------- -dnl ####ECOSGPLCOPYRIGHTEND#### -dnl ==================================================================== -dnl#####DESCRIPTIONBEGIN#### -dnl -dnl Author(s): bartv -dnl Contact(s): bartv -dnl Date: 2002/01/10 -dnl Version: 0.01 -dnl -dnl####DESCRIPTIONEND#### -dnl ==================================================================== - - -AC_INIT(usbhost.c) - -dnl Pick up the support files from the top-level acsupport directory. -AC_CONFIG_AUX_DIR(../../../../../../acsupport) - -ECOS_CHECK_BUILD_ne_SRC -AC_CANONICAL_HOST -AM_INIT_AUTOMAKE(usbhost,0.1,0) -AM_MAINTAINER_MODE - -dnl The current version of the USB testing support depends on -dnl functionality provided only by Linux platforms, and has only been -dnl tested on x86 machines, so a test is appropriate here. However -dnl it is not a good idea for the configure script to report an error: -dnl that would prevent any top-level configury working for other -dnl platforms. Instead an automake conditional is used to suppress adding -dnl targets to the build. -case "${host}" in - *-*-linux-gnu* ) SUPPORTED="yes";; - * ) SUPPORTED="no" -esac - -if test "${SUPPORTED}" = "no" ; then - AC_MSG_WARN([USB testing is only supported on Linux hosts]) -else - AC_PROG_CC - AC_PROG_CXX - AC_PROG_LN_S - AC_OBJEXT - AC_EXEEXT - ECOS_PROG_MSVC - ECOS_PROG_STANDARD_COMPILER_FLAGS - ECOS_PACKAGE_DIRS - - ECOS_PATH_TCL - dnl Check that the version of tcl is sufficiently recent. - dnl e.g. "end" only became a valid index for the - dnl string commands after 8.1 - if test "${TK_MAJOR_VERSION}" = "8" ; then - if test ${TK_MINOR_VERSION} -lt 2 ; then - AC_MSG_WARN([Version 8.2 or greater of Tcl/Tk is required]) - SUPPORTED="no" - fi - fi - if test "${SUPPORTED}" = "yes" ; then - AC_CHECK_HEADERS("linux/usb.h" "linux/usbdevice_fs.h",,SUPPORTED="no") - if test "${SUPPORTED}" = "no" ; then - AC_MSG_WARN([Required Linux kernel functionality does not appear to be available]) - fi - fi -fi - -if test "${SUPPORTED}" = "no" ; then - AC_MSG_WARN([The USB testing support cannot be built on this platform.]) -fi - -AM_CONDITIONAL(SUPPORTED, test "${SUPPORTED}" = "yes") - -dnl There is no real need for a config.h file at this time, since the code -dnl is specific to Linux. This may change in future. -dnl AM_CONFIG_HEADER(config.h:config.h.in) - -AC_OUTPUT(Makefile:Makefile.in) Index: slave/v2_0/host/verbose.tcl =================================================================== --- slave/v2_0/host/verbose.tcl (revision 174) +++ slave/v2_0/host/verbose.tcl (nonexistent) @@ -1,71 +0,0 @@ -# {{{ Banner - -#=============================================================================== -# -# verbose.tcl -# -# Support for USB testing -# -#=============================================================================== -#####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#### -# -# Author(s): bartv -# Date: 2002-01-16 -# Purpose: Set the target-side verbosity level -# -#####DESCRIPTIONEND#### -#=============================================================================== -# - -# }}} - -if { 1 == $argc } { - puts "The desired verbosity level must be specified on the command line." - puts "This should be a small integer. A value of 0 suppresses run-time" - puts "logging within the target." - exit 1 -} -set level [lindex $argv 0] - -if { ![string is integer -strict $level ] } { - puts "Invalid verbosity level \"$level\"" - puts "This should be a small integer. A value of 0 suppresses run-time" - puts "logging within the target." - exit 1 -} - -usbtest::target_verbose $level - Index: slave/v2_0/host/usbhost.c =================================================================== --- slave/v2_0/host/usbhost.c (revision 174) +++ slave/v2_0/host/usbhost.c (nonexistent) @@ -1,1898 +0,0 @@ -/*{{{ Banner */ - -//================================================================= -// -// host.c -// -// USB testing - host-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#### -// -// Author(s): bartv -// Date: 2001-07-04 -//####DESCRIPTIONEND#### -//========================================================================== - -// The overall architecture is as follows. -// -// The target hardware runs a special application which provides a -// particular type of USB application, "Red Hat eCos USB testing". -// This will not be recognised by any device driver, so the Linux -// kernel will pretty much ignore the device (other host OS's are not -// considered at this time). -// -// This program is the only supported way to interact with that service. -// It acts as an extended Tcl interpreter, providing a number of new -// Tcl commands for interacting with the target. All test cases can -// then be written as Tcl scripts which invoke a series of these commands. -// These Tcl commands operate essentially though the LINUX usb devfs -// service which allows ordinary application code to perform USB operations -// via ioctl()'s. - -/*}}}*/ -/*{{{ #include's */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// Avoid compatibility problems with Tcl 8.4 vs. earlier -#define USE_NON_CONST -#include -#include -#include -#include "../tests/protocol.h" - -/*}}}*/ - -/*{{{ Statics */ - -// ---------------------------------------------------------------------------- -// Statics. - -// Has the current batch of tests actually terminated? 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; - -// The next local thread to be allocated for testing. This variable can also -// be used to find out how many threads are involved in the current test. -// This counter should always be reset to 0 at the end of every test run. -static int local_thread_count = 0; - -// A similar counter for remote threads. -static int remote_thread_count = 0; - -// A file handle for manipulating the USB device at a low level -static int usb_master_fd = -1; - -/*}}}*/ -/*{{{ Logging */ - -// ---------------------------------------------------------------------------- -// The user can provide one or more -V/--verbose arguments to increase -// the amount of output generated. - -static int verbose = 0; - -#define VERBOSE(_level_, _format_, _args_...) \ - do { \ - if (verbose >= _level_) { \ - printf(_format_, ## _args_); \ - } \ - } while (0); - -/*}}}*/ -/*{{{ Low-level USB access */ - -// ---------------------------------------------------------------------------- -// Low-level access to a USB device. -// -// The various ioctl() calls require a file handle which corresponds to one -// of the /proc/bus/usb// entries. is a bus number, -// typically 001 or 001, and is a device number on that bus, -// e.g. 003. Figuring out and requires scanning -// /proc/bus/usb/devices, which is a somewhat complicated text file. -// -// This is all somewhat vulnerable to incompatible changes in the -// Linux kernel, specifically the implementation of the /proc/bus/usb. -// An alternative approach would be to write a new Linux device driver -// and interact with that, but that approach is vulnerable to any -// internal kernel API changes affecting USB device drivers. - -// How to access USB devices from userland -#define USB_ROOT "/proc/bus/usb/" - -// How to identify the eCos test case -#define PRODUCT_STRING "Red Hat eCos USB test" - -// Scan through /proc/bus/usb/devices looking for an entry that -// matches what we are after, specifically a line -// S: Product=Red Hat eCos USB testcase -// The required information can then be obtained from the previous -// line: -// T: Bus= ... Dev#= ... -// -// Of course the T: line is going to come first, so it is necessary -// to keep track of the current bus and device numbers. -// -// Note: this code is duplicated in usbchmod.c. Any changes here -// should be propagated. For now the routine is too small to warrant -// a separate source file. - -static int -usb_scan_devices(int* bus, int* dev) -{ - FILE* devs_file; - int current_bus = -1; - int current_dev = -1; - int ch; - - *bus = -1; - *dev = -1; - - VERBOSE(1, "Searching " USB_ROOT "devices for the eCos USB test code\n"); - - devs_file = fopen(USB_ROOT "devices", "r"); - if (NULL == devs_file) { - fprintf(stderr, "usbhost: error, unable to access " USB_ROOT "devices\n"); - return 0; - } - ch = getc(devs_file); - while (EOF != ch) { - if ('T' == ch) { - if (2 !=fscanf(devs_file, ": Bus=%d %*[^D\n]Dev#=%d", ¤t_bus, ¤t_dev)) { - current_bus = -1; - current_dev = -1; - } - } else if ('S' == ch) { - int start = 0, end = 0; - if (EOF != fscanf(devs_file, ": Product=%n" PRODUCT_STRING "%n", &start, &end)) { - if (start < end) { - *bus = current_bus; - *dev = current_dev; - break; - } - } - } - // Move to the end of the current line. - do { - ch = getc(devs_file); - } while ((EOF != ch) && ('\n' != ch)); - if (EOF != ch) { - ch = getc(devs_file); - } - } - - fclose(devs_file); - if ((-1 != *bus) && (-1 != *dev)) { - VERBOSE(1, "Found eCos USB test code on bus %d, device %d\n", *bus, *dev); - return 1; - } - fprintf(stderr, "usbhost: error, failed to find a USB device \"" PRODUCT_STRING "\"\n"); - return 0; -} - -// Actually open the USB device, allowing subsequent ioctl() operations. -// -// Typically /proc/bus/usb/... will not allow ordinary applications -// to perform ioctl()'s. Instead root privileges are required. To work -// around this there is a little utility usbchmod, installed suid, -// which can be used to get access to the raw device. -static int -usb_open_device(void) -{ - char devname[_POSIX_PATH_MAX]; - static int bus = -1; - static int dev = -1; - int result; - - if ((-1 == bus) || (-1 == dev)) { - if (!usb_scan_devices(&bus, &dev)) { - return -1; - } - } - - if (_POSIX_PATH_MAX == snprintf(devname, _POSIX_PATH_MAX, USB_ROOT "%03d/%03d", bus, dev)) { - fprintf(stderr, "usbhost: internal error, buffer overflow\n"); - exit(EXIT_FAILURE); - } - - VERBOSE(1, "Attempting to access USB target via %s\n", devname); - - result = open(devname, O_RDWR); - if (-1 == result) { - // Check for access right problems. If so, try to work around them - // by invoking usbchmod. Always look for this in the install tree, - // since it is only that version which is likely to have been - // chown'ed and chmod'ed to be suid root. - if (EACCES == errno) { - char command_name[_POSIX_PATH_MAX]; - - VERBOSE(1, "Insufficient access to USB target, running usbchmod\n"); - if (_POSIX_PATH_MAX == snprintf(command_name, _POSIX_PATH_MAX, "%s/usbchmod %d %d", USBAUXDIR, bus, dev)) { - fprintf(stderr, "usbhost: internal error, buffer overflow\n"); - exit(EXIT_FAILURE); - } - (void) system(command_name); - result = open(devname, O_RDWR); - } - } - if (-1 == result) { - fprintf(stderr, "usbhost: error, failed to open \"%s\", errno %d\n", devname, errno); - } - - VERBOSE(1, "USB device now accessible via file descriptor %d\n", result); - - // Also perform a set-configuration call, to avoid warnings from - // the Linux kernel. Target-side testing is always configuration 1 - // because only a single configuration is supported. - (void) ioctl(result, USBDEVFS_SETCONFIGURATION, 1); - return result; -} - -// Exchange a control message with the host. The return value should -// be 0, or a small positive number indicating the actual number of -// bytes received which may be less than requested. -// -// There appear to be problems with some hosts, manifesting itself as -// an inability to send control messages that involve additional data -// from host->target. These problems are not yet well-understood. For -// now the workaround is to send multiple packets, each with up to -// four bytes encoded in the index and length fields. -static int -usb_control_message(int fd, int request_type, int request, int value, int index, int length, void* data) -{ - struct usbdevfs_ctrltransfer transfer; - int result = 0; - - VERBOSE(3, "usb_control_message, request %02x, len %d\n", request, length); - - if (length > USBTEST_MAX_CONTROL_DATA) { - fprintf(stderr, "usbhost: internal error, control message involves too much data.\n"); - exit(EXIT_FAILURE); - } - -#if 1 - // Workaround - send additional data in the index and length fields. - if ((length > 0) && (USB_DIR_OUT == (USB_ENDPOINT_DIR_MASK & request_type))) { - int i; - unsigned char* buf = (unsigned char*) data; - - for (i = 0; i < length; i+= 4) { - int this_len = length - 1; - int ioctl_result; - - transfer.requesttype = USB_TYPE_CLASS | USB_RECIP_DEVICE; - if (this_len > 4) { - this_len = 4; - } - switch (this_len) { - case 1: transfer.request = USBTEST_CONTROL_DATA1; break; - case 2: transfer.request = USBTEST_CONTROL_DATA2; break; - case 3: transfer.request = USBTEST_CONTROL_DATA3; break; - case 4: transfer.request = USBTEST_CONTROL_DATA4; break; - default: - fprintf(stderr, "usbhost: internal error, confusion about transfer length.\n"); - exit(EXIT_FAILURE); - } - transfer.value = (buf[i] << 8) | buf[i+1]; // Possible read beyond end of buffer, - transfer.index = (buf[i+2] << 8) | buf[i+3]; // but not worth worrying about. - transfer.length = 0; - transfer.timeout = 10 * 1000; // ten seconds, the target should always accept data faster than this. - transfer.data = NULL; - - // This is too strict, deciding what to do about errors should be - // handled by higher-level code. However it will do for now. - ioctl_result = ioctl(fd, USBDEVFS_CONTROL, &transfer); - if (0 != ioctl_result) { - fprintf(stderr, "usbhost: error, failed to send control message (data) to target.\n"); - exit(EXIT_FAILURE); - } - } - // There is no more data to be transferred. - length = 0; - } -#endif - transfer.requesttype = request_type; - transfer.request = request; - transfer.value = value; - transfer.index = index; - transfer.length = length; - transfer.timeout = 10000; - transfer.data = data; - - result = ioctl(fd, USBDEVFS_CONTROL, &transfer); - return result; -} - -// A variant of the above which can be called when the target should always respond -// correctly. This can be used for class control messages. -static int -usb_reliable_control_message(int fd, int request_type, int request, int value, int index, int length, void* data) -{ - int result = usb_control_message(fd, request_type, request, value, index, length, data); - if (-1 == result) { - fprintf(stderr, "usbhost: error, failed to send control message %02x to target.\n", request); - fprintf(stderr, " : errno %d (%s)\n", errno, strerror(errno)); - exit(EXIT_FAILURE); - } - return result; -} - - -// Either send or receive a single bulk message. The top bit of the endpoint -// number indicates the direction. -static int -usb_bulk_message(int fd, int endpoint, unsigned char* buffer, int length) -{ - struct usbdevfs_bulktransfer transfer; - int result; - - transfer.ep = endpoint; - transfer.len = length; - transfer.timeout = 60 * 60 * 1000; - // An hour. These operations should not time out because that - // leaves the system in a confused state. Instead there is - // higher-level recovery code that should ensure the operation - // really does complete, and the return value here is used - // by the calling code to determine whether the operation - // was successful or whether there was an error and the recovery - // code was invoked. - transfer.data = buffer; - errno = 0; - result = ioctl(fd, USBDEVFS_BULK, &transfer); - return result; -} - - -// Synchronise with the target. This can be used after the host has sent a request that -// may take a bit of time, e.g. it may involve waking up a thread. The host will send -// synch requests at regular intervals, until the target is ready. -// -// The limit argument can be used to avoid locking up. -1 means loop forever, otherwise -// it means that many iterations of 100ms apiece. -static int -usb_sync(int fd, int limit) -{ - unsigned char buf[1]; - struct timespec delay; - int loops = 0; - int result = 0; - - VERBOSE(2, "Synchronizing with target\n"); - - while (1) { - buf[0] = 0; - usb_reliable_control_message(fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_SYNCH, 0, 0, 1, buf); - if (buf[0]) { - result = 1; - break; - } else { - if ((-1 != limit) && (++loops > limit)) { - break; - } else { - VERBOSE(3, "Not yet synchronized, sleeping\n"); - delay.tv_sec = 0; - delay.tv_nsec = 100000000; // 100 ms - nanosleep(&delay, NULL); - } - } - } - VERBOSE(2, "%s\n", result ? "Synchronized" : "Not synchronized"); - return result; -} - -// Abort the target. Things seem to be completely messed up and there is no easy -// way to restore sanity to both target and host. -static void -usb_abort(int fd) -{ - VERBOSE(2, "Target-side abort operation invoked\n"); - usb_reliable_control_message(fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_ABORT, 0, 0, 0, (void*)0); -} - -/*}}}*/ -/*{{{ Initialise endpoints */ - -// ---------------------------------------------------------------------------- -// On power-up some endpoints may not be in a sensible state. For example, -// with the SA11x0 the hardware may start accepting bulk OUT transfers -// before the target-side software has started a receive operation, -// so if the host sends a bulk packet before the target is ready then -// things get messy. This is especially troublesome if the target-side -// attempts any diagnostic output because of verbosity. -// -// This code loops through the various endpoints and makes sure that -// they are all in a reasonable state, before any real tests get run -// That means known hardware flaws do not show up as test failures, -// but of course they are still documented and application software -// will have to do the right thing. - -static void -usb_initialise_control_endpoint(int min_size, int max_size) -{ - // At this time there are no known problems on any hardware - // that would need to be addressed -} - -static void -usb_initialise_isochronous_in_endpoint(int number, int min_size, int max_size) -{ - // At this time there are no known problems on any hardware - // that would need to be addressed -} - -static void -usb_initialise_isochronous_out_endpoint(int number, int min_size, int max_size) -{ - // At this time there are no known problems on any hardware - // that would need to be addressed -} - -static void -usb_initialise_bulk_in_endpoint(int number, int min_size, int max_size, int padding) -{ - // At this time there are no known problems on any hardware - // that would need to be addressed -} - -static void -usb_initialise_bulk_out_endpoint(int number, int min_size, int max_size) -{ - char buf[1]; - - // On the SA1110 the hardware comes up with a bogus default value, - // causing the hardware to accept packets before the software has - // set up DMA or in any way prepared for incoming data. This is - // a problem. It is worked around by making the target receive - // a single packet, sending that packet, and then performing a - // sync. - VERBOSE(2, "Performing bulk OUT initialization on endpoint %d\n", number); - - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, - USBTEST_INIT_BULK_OUT, number, 0, 0, (void*) 0); - usb_bulk_message(usb_master_fd, number, buf, 1); - usb_sync(usb_master_fd, 10); -} - -static void -usb_initialise_interrupt_in_endpoint(int number, int min_size, int max_size) -{ - // At this time there are no known problems on any hardware - // that would need to be addressed -} - -static void -usb_initialise_interrupt_out_endpoint(int number, int min_size, int max_size) -{ - // At this time there are no known problems on any hardware - // that would need to be addressed -} - -/*}}}*/ -/*{{{ Host/target common code */ - -#define HOST -#include "../tests/common.c" - -/*}}}*/ -/*{{{ The test cases themselves */ - -/*{{{ UsbTest definition */ - -// ---------------------------------------------------------------------------- -// All the data associated with a single test. - -typedef struct UsbTest { - - // A "unique" identifier to make verbose output easier to understand. - int id; - // Which file descriptor should be used to access USB. - int fd; - - // 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; - - int result_pass; - char result_message[USBTEST_MAX_MESSAGE]; - 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'; -} - -/*}}}*/ -/*{{{ bulk OUT */ - -static void -run_test_bulk_out(UsbTest* test) -{ - unsigned char* buf = test->buffer; - int i; - - VERBOSE(1, "Starting test %d, bulk OUT on endpoint %d\n", test->id, test->test_params.bulk.endpoint); - - for (i = 0; i < test->test_params.bulk.number_packets; i++) { - int transferred; - int packet_size = test->test_params.bulk.tx_size; - - test->recovery.endpoint = test->test_params.bulk.endpoint; - test->recovery.protocol = USB_ENDPOINT_XFER_BULK; - test->recovery.size = packet_size; - - usbtest_fill_buffer(&(test->test_params.bulk.data), buf, packet_size); - if (verbose < 3) { - VERBOSE(2, "Bulk OUT test %d: iteration %d, packet size %d\n", test->id, i, packet_size); - } else { - // Output the first 32 bytes of data as well. - char msg[256]; - int index; - int j; - index = snprintf(msg, 255, "Bulk OUT test %d: iteration %d, packet size %d\n Data %s:", - test->id, i, packet_size, - (usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : ""); - - for (j = 0; ((j + 3) < packet_size) && (j < 32); j+= 4) { - index += snprintf(msg+index, 255-index, " %02x%02x%02x%02x", - buf[j], buf[j+1], buf[j+2], buf[j+3]); - } - if (j < 32) { - index += snprintf(msg+index, 255-index, " "); - for ( ; j < packet_size; j++) { - index += snprintf(msg+index, 255-index, "%02x", buf[j]); - } - - } - VERBOSE(3, "%s\n", msg); - } - - transferred = usb_bulk_message(test->fd, test->test_params.bulk.endpoint, buf, packet_size); - - // Has this test run been aborted for some reason? - if (current_tests_terminated) { - VERBOSE(2, "Bulk OUT test %d: iteration %d, termination detected\n", test->id, i); - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, bulk OUT transfer on endpoint %d: aborted after %d iterations\n", - test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, i); - return; - } - - // If an error occurred, abort this run. - if (-1 == transferred) { - char errno_buf[USBTEST_MAX_MESSAGE]; - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, bulk OUT transfer on endpoint %d : host ioctl() system call failed\n errno %d (%s)", - test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, errno, - strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE)); - VERBOSE(2, "Bulk OUT test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message); - break; - } - - if (0 != test->test_params.bulk.tx_delay) { - struct timespec delay; - - VERBOSE(2, "Bulk OUT test %d: iteration %d, sleeping for %d nanoseconds\n", test->id, \ - i, test->test_params.bulk.tx_delay); - // Note that nanosleep() can return early due to incoming signals, - // with the unelapsed time returned in a second argument. This - // allows for a retry loop. In practice this does not seem - // worthwhile, the delays are approximate anyway. - delay.tv_sec = test->test_params.bulk.tx_delay / 1000000000; - delay.tv_nsec = test->test_params.bulk.tx_delay % 1000000000; - nanosleep(&delay, NULL); - } - - // Now move on to the next transfer - USBTEST_BULK_NEXT(test->test_params.bulk); - } - - // If all the packets have been transferred this test has passed. - if (i >= test->test_params.bulk.number_packets) { - test->result_pass = 1; - } - - VERBOSE(1, "Test %d bulk OUT on endpoint %d, result %d\n", test->id, test->test_params.bulk.endpoint, test->result_pass); -} - -/*}}}*/ -/*{{{ bulk IN */ - -static void -run_test_bulk_in(UsbTest* test) -{ - unsigned char* buf = test->buffer; - int i; - - VERBOSE(1, "Starting test %d bulk IN on endpoint %d\n", test->id, test->test_params.bulk.endpoint); - - for (i = 0; i < test->test_params.bulk.number_packets; i++) { - int transferred; - int tx_size = test->test_params.bulk.tx_size; - int rx_size = test->test_params.bulk.rx_size; - int size_plus_padding; - - VERBOSE(2, "Bulk IN test %d: iteration %d, rx size %d, tx size %d\n", test->id, i, rx_size, tx_size); - - if (rx_size < tx_size) { - rx_size = tx_size; - VERBOSE(2, "Bulk IN test %d: iteration %d, packet size reset to %d to match tx size\n", - test->id, i, rx_size); - } - test->recovery.endpoint = test->test_params.bulk.endpoint; - test->recovery.protocol = USB_ENDPOINT_XFER_BULK; - test->recovery.size = rx_size; - - // Make sure there is no old data lying around - if (usbtestdata_none != test->test_params.bulk.data.format) { - memset(buf, 0, rx_size); - } - - // And do the actual transfer. - size_plus_padding = rx_size; - if (size_plus_padding < (tx_size + test->test_params.bulk.rx_padding)) { - size_plus_padding += test->test_params.bulk.rx_padding; - } - do { - transferred = usb_bulk_message(test->fd, test->test_params.bulk.endpoint, buf, size_plus_padding); - } while (0 == transferred); - - // Has this test run been aborted for some reason? - if (current_tests_terminated) { - VERBOSE(2, "Bulk IN test %d: iteration %d, termination detected\n", test->id, i); - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, bulk IN transfer on endpoint %d: aborted after %d iterations\n", - test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, i); - return; - } - - // If an error occurred, abort this run. - if (-1 == transferred) { - char errno_buf[USBTEST_MAX_MESSAGE]; - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, bulk IN transfer on endpoint %d : host ioctl() system call failed\n errno %d (%s)", - test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, errno, - strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE)); - VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message); - break; - } - - // Did the target send the expected amount of data? - if (transferred < tx_size) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, bulk IN transfer on endpoint %d : the target only sent %d bytes when %d were expected", - test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, transferred, tx_size); - VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message); - break; - } - - if (verbose >= 3) { - // Output the first 32 bytes of data - char msg[256]; - int index; - int j; - index = snprintf(msg, 255, "Bulk IN test %d: iteration %d, transferred %d\n Data %s:", - test->id, i, transferred, - (usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : ""); - - for (j = 0; ((j + 3) < transferred) && (j < 32); j+= 4) { - index += snprintf(msg+index, 255-index, " %02x%02x%02x%02x", - buf[j], buf[j+1], buf[j+2], buf[j+3]); - } - if (j < 32) { - index += snprintf(msg+index, 255-index, " "); - for ( ; j < transferred; j++) { - index += snprintf(msg+index, 255-index, "%02x", buf[j]); - } - - } - VERBOSE(3, "%s\n", msg); - } - - // Is the data correct? - if (!usbtest_check_buffer(&(test->test_params.bulk.data), buf, tx_size)) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, bulk IN transfer on endpoint %d : mismatch between received and expected data", - test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK); - VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message); - break; - } - - if (0 != test->test_params.bulk.rx_delay) { - struct timespec delay; - - VERBOSE(2, "Bulk IN test %d: iteration %d, sleeping for %d nanoseconds\n", test->id, \ - i, test->test_params.bulk.tx_delay); - // Note that nanosleep() can return early due to incoming signals, - // with the unelapsed time returned in a second argument. This - // allows for a retry loop. In practice this does not seem - // worthwhile, the delays are approximate anyway. - delay.tv_sec = test->test_params.bulk.rx_delay / 1000000000; - delay.tv_nsec = test->test_params.bulk.rx_delay % 1000000000; - nanosleep(&delay, NULL); - } - - USBTEST_BULK_NEXT(test->test_params.bulk); - } - - - // If all the packets have been transferred this test has passed. - if (i >= test->test_params.bulk.number_packets) { - test->result_pass = 1; - } - - VERBOSE(1, "Test %d bulk IN on endpoint %d, result %d\n", test->id, test->test_params.bulk.endpoint, test->result_pass); -} - -/*}}}*/ -/*{{{ control IN */ - -// Receive appropriate packets via the control endpoint. This is somewhat -// different from bulk transfers. It is implemented using reserved control -// messages. -// -// Note: it is not entirely clear that this test is safe. There will be -// concurrent control traffic to detect test termination and the like, -// and these control messages may interfere with each other. It is not -// entirely clear how the Linux kernel handles concurrent control -// operations. - -static void -run_test_control_in(UsbTest* test) -{ - unsigned char* buf = test->buffer; - int packet_size; - int i; - - packet_size = test->test_params.control_in.packet_size_initial; - for (i = 0; i < test->test_params.control_in.number_packets; i++) { - int transferred; - - test->recovery.endpoint = 0; - test->recovery.protocol = USB_ENDPOINT_XFER_CONTROL; - test->recovery.size = packet_size; - - // Make sure there is no old data lying around - if (usbtestdata_none != test->test_params.control_in.data.format) { - memset(buf, 0, packet_size); - } - - // And do the actual transfer. - transferred = usb_control_message(test->fd, USB_TYPE_RESERVED | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_RESERVED_CONTROL_IN, - 0, 0, packet_size, buf); - - // Has this test run been aborted for some reason? - if (current_tests_terminated) { - return; - } - - // If an error occurred, abort this run. - if (-1 == transferred) { - char errno_buf[USBTEST_MAX_MESSAGE]; - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, control IN transfer: host ioctl() system call failed\n errno %d (%s)", - errno, strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE)); - break; - } - - // Did the target send the expected amount of data? - if (transferred < packet_size) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, control IN transfer: the target only sent %d bytes when %d were expected", - transferred, packet_size); - break; - } - - // Is the data correct? - if (!usbtest_check_buffer(&(test->test_params.control_in.data), buf, packet_size)) { - test->result_pass = 0; - snprintf(test->result_message, USBTEST_MAX_MESSAGE, - "Host, control IN transfer: mismatch between received and expected data"); - break; - } - - USBTEST_CONTROL_NEXT_PACKET_SIZE(packet_size, test->test_params.control_in); - } - - // If all the packets have been transferred this test has passed. - if (i >= test->test_params.control_in.number_packets) { - test->result_pass = 1; - } -} - -/*}}}*/ - -// FIXME: add more tests - -/*{{{ run_test() */ - -// This utility is invoked from a thread in the thread pool whenever there is -// work to be done. It simply dispatches to the appropriate handler. -static void -run_test(UsbTest* test) -{ - switch (test->which_test) { - case usbtest_bulk_out: run_test_bulk_out(test); break; - case usbtest_bulk_in: run_test_bulk_in(test); break; - case usbtest_control_in: run_test_control_in(test); break; - default: - fprintf(stderr, "usbhost: internal error, attempt to execute an unknown test.\n"); - exit(EXIT_FAILURE); - } -} - -/*}}}*/ - -/*}}}*/ -/*{{{ The thread pool */ - -// ---------------------------------------------------------------------------- -// A pool of threads and buffers which do the real work. The number of possible -// concurrent tests is defined in protocol.h. Each one requires a separate -// thread, transfer buffer, semaphore, and some state information. -// -// Although the application is multi-threaded, in practice there is little -// need for synchronization. Tests will only be started while the pool threads -// are idle. When the pool threads are running the main thread will be waiting -// for them all to finish, with a bit of polling to detect error conditions. -// The pool threads do not share any data, apart from the file descriptor for -// the USB device. - -typedef struct PoolEntry { - pthread_t thread; - sem_t wakeup; - int running; - UsbTest test; -} PoolEntry; - -static PoolEntry pool[USBTEST_MAX_CONCURRENT_TESTS]; - -// This is the entry point for every thread in the pool. It just loops forever, -// waiting until it is supposed to run a test. These threads never actually -// exit, instead there should be a call to exit() somewhere. -static void* -pool_function(void* arg) -{ - PoolEntry* pool_entry = (PoolEntry*) arg; - for ( ; ; ) { - sem_wait(&(pool_entry->wakeup)); - run_test(&(pool_entry->test)); - pool_entry->running = 0; - } - - return NULL; -} - -// Initialize all threads in the pool. -static void -pool_initialize(void) -{ - int i; - for (i = 0; i < USBTEST_MAX_CONCURRENT_TESTS; i++) { - pool[i].running = 0; - pool[i].test.fd = dup(usb_master_fd); - if (0 != sem_init(&(pool[i].wakeup), 0, 0)) { - fprintf(stderr, "usbhost: internal error, failed to initialize all semaphores.\n"); - exit(EXIT_FAILURE); - } - if (0 != pthread_create(&(pool[i].thread), NULL, &pool_function, (void*) &(pool[i]))) { - fprintf(stderr, "usbhost: internal error, failed to start all threads.\n"); - exit(EXIT_FAILURE); - } - } -} - -// Allocate a single entry in the thread pool. -static UsbTest* -pool_allocate(void) -{ - UsbTest* result = (UsbTest*) 0; - - if (local_thread_count == USBTEST_MAX_CONCURRENT_TESTS) { - fprintf(stderr, "usbhost: internal error, thread resource exhausted.\n"); - exit(EXIT_FAILURE); - } - - result = &(pool[local_thread_count].test); - local_thread_count++; - reset_usbtest(result); - return result; -} - -// Start all the threads that are supposed to be running tests. -static void -pool_start(void) -{ - int i; - for (i = 0; i < local_thread_count; i++) { - pool[i].running = 1; - sem_post(&(pool[i].wakeup)); - } -} - -/*}}}*/ -/*{{{ Tcl routines */ - -// ---------------------------------------------------------------------------- -// Tcl routines to provide access to the USB device from inside Tcl -// scripts, plus some general utilities. These routines deal mostly -// with preparing a test run. The actual work is done in C: the -// ioctl() operations are not readily accessible from Tcl, and -// operations like filling in buffers and calculating checksums are -// cpu-intensive. - -/*{{{ pass/fail/abort */ - -// ---------------------------------------------------------------------------- -// Some simple routines accessible from Tcl to get the target to report pass/fail or -// to make the target abort. - -static int -tcl_target_pass(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv) -{ - if (2 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_pass \"", TCL_STATIC); - return TCL_ERROR; - } - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PASS, 0, 0, strlen(argv[1]) + 1, argv[1]); - usb_sync(usb_master_fd, -1); - return TCL_OK; -} - -static int -tcl_target_fail(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv) -{ - if (2 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_fail \"", TCL_STATIC); - return TCL_ERROR; - } - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_FAIL, 0, 0, strlen(argv[1]) + 1, argv[1]); - usb_sync(usb_master_fd, -1); - return TCL_OK; -} - -// The next three routines cause the target to exit, so a usb_sync() is inappropriate. -static int -tcl_target_pass_exit(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv) -{ - if (2 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_pass_exit \"", TCL_STATIC); - return TCL_ERROR; - } - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PASS_EXIT, 0, 0, - strlen(argv[1]) + 1, argv[1]); - return TCL_OK; -} - - -static int -tcl_target_fail_exit(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv) -{ - if (2 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_fail_exit \"", TCL_STATIC); - return TCL_ERROR; - } - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_FAIL_EXIT, 0, 0, - strlen(argv[1]) + 1, argv[1]); - return TCL_OK; -} - -static int -tcl_target_abort(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv __attribute__ ((unused)) ) -{ - if (1 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_abort\"", TCL_STATIC); - return TCL_ERROR; - } - usb_abort(usb_master_fd); - return TCL_OK; -} - -/*}}}*/ -/*{{{ start bulk test */ - -// ---------------------------------------------------------------------------- -// Start a bulk test. The real Tcl interface to this functionality is -// implemented in Tcl: it takes care of figuring out sensible default -// arguments, validating the data, etc. All that this code does is -// allocate a thread and fill in the appropriate data, plus request -// the target-side to do the same thing. - -static int -tcl_test_bulk(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv) -{ - int i; - int tmp; - UsbTest* test; - unsigned char request[USBTEST_MAX_CONTROL_DATA]; - int request_index; - - // The data consists of 28 numbers for UsbTest_Bulk itself, and - // another 10 numbers for the test data definition. - if (39 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_test_bulk \"", TCL_STATIC); - return TCL_ERROR; - } - for (i = 1; i < 39; i++) { - int discard; - if (TCL_OK != Tcl_GetInt(interp, argv[i], &discard)) { - Tcl_SetResult(interp, "invalid argument: all arguments should be numbers", TCL_STATIC); - return TCL_ERROR; - } - } - - test = pool_allocate(); - Tcl_GetInt(interp, argv[1], &(test->test_params.bulk.number_packets)); - Tcl_GetInt(interp, argv[2], &(test->test_params.bulk.endpoint)); - test->which_test = (USB_DIR_IN == (test->test_params.bulk.endpoint & USB_ENDPOINT_DIR_MASK)) - ? usbtest_bulk_in : usbtest_bulk_out; - Tcl_GetInt(interp, argv[ 3], &(test->test_params.bulk.tx_size)); - Tcl_GetInt(interp, argv[ 4], &(test->test_params.bulk.tx_size_min)); - Tcl_GetInt(interp, argv[ 5], &(test->test_params.bulk.tx_size_max)); - Tcl_GetInt(interp, argv[ 6], &(test->test_params.bulk.tx_size_multiplier)); - Tcl_GetInt(interp, argv[ 7], &(test->test_params.bulk.tx_size_divisor)); - Tcl_GetInt(interp, argv[ 8], &(test->test_params.bulk.tx_size_increment)); - Tcl_GetInt(interp, argv[ 9], &(test->test_params.bulk.rx_size)); - Tcl_GetInt(interp, argv[10], &(test->test_params.bulk.rx_size_min)); - Tcl_GetInt(interp, argv[11], &(test->test_params.bulk.rx_size_max)); - Tcl_GetInt(interp, argv[12], &(test->test_params.bulk.rx_size_multiplier)); - Tcl_GetInt(interp, argv[13], &(test->test_params.bulk.rx_size_divisor)); - Tcl_GetInt(interp, argv[14], &(test->test_params.bulk.rx_size_increment)); - Tcl_GetInt(interp, argv[15], &(test->test_params.bulk.rx_padding)); - Tcl_GetInt(interp, argv[16], &(test->test_params.bulk.tx_delay)); - Tcl_GetInt(interp, argv[17], &(test->test_params.bulk.tx_delay_min)); - Tcl_GetInt(interp, argv[18], &(test->test_params.bulk.tx_delay_max)); - Tcl_GetInt(interp, argv[19], &(test->test_params.bulk.tx_delay_multiplier)); - Tcl_GetInt(interp, argv[20], &(test->test_params.bulk.tx_delay_divisor)); - Tcl_GetInt(interp, argv[21], &(test->test_params.bulk.tx_delay_increment)); - Tcl_GetInt(interp, argv[22], &(test->test_params.bulk.rx_delay)); - Tcl_GetInt(interp, argv[23], &(test->test_params.bulk.rx_delay_min)); - Tcl_GetInt(interp, argv[24], &(test->test_params.bulk.rx_delay_max)); - Tcl_GetInt(interp, argv[25], &(test->test_params.bulk.rx_delay_multiplier)); - Tcl_GetInt(interp, argv[26], &(test->test_params.bulk.rx_delay_divisor)); - Tcl_GetInt(interp, argv[27], &(test->test_params.bulk.rx_delay_increment)); - Tcl_GetInt(interp, argv[28], &tmp); - test->test_params.bulk.io_mechanism = (usb_io_mechanism) tmp; - Tcl_GetInt(interp, argv[29], &tmp); - test->test_params.bulk.data.format = (usbtestdata) tmp; - Tcl_GetInt(interp, argv[30], &(test->test_params.bulk.data.seed)); - Tcl_GetInt(interp, argv[31], &(test->test_params.bulk.data.multiplier)); - Tcl_GetInt(interp, argv[32], &(test->test_params.bulk.data.increment)); - Tcl_GetInt(interp, argv[33], &(test->test_params.bulk.data.transfer_seed_multiplier)); - Tcl_GetInt(interp, argv[34], &(test->test_params.bulk.data.transfer_seed_increment)); - Tcl_GetInt(interp, argv[35], &(test->test_params.bulk.data.transfer_multiplier_multiplier)); - Tcl_GetInt(interp, argv[36], &(test->test_params.bulk.data.transfer_multiplier_increment)); - Tcl_GetInt(interp, argv[37], &(test->test_params.bulk.data.transfer_increment_multiplier)); - Tcl_GetInt(interp, argv[38], &(test->test_params.bulk.data.transfer_increment_increment)); - - VERBOSE(3, "Preparing USB bulk test on endpoint %d, direction %s, for %d packets\n", \ - test->test_params.bulk.endpoint, \ - (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" : ""); - 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" : "", \ - 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); - - - // That is all the data converted from Tcl to C, and a local thread is set up to handle this - // request. Also set up a thread on the target. - request_index = 0; - pack_usbtest_bulk(&(test->test_params.bulk), request, &request_index); - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_TEST_BULK, 0, 0, request_index, request); - remote_thread_count++; - - return TCL_OK; -} - -/*}}}*/ -/*{{{ start control-in test */ - -// ---------------------------------------------------------------------------- -// Start a control-in test. The real Tcl interface to this -// functionality is implemented in Tcl: it takes care of figuring out -// sensible default arguments, validating the data, etc. All that this -// code does is allocate a thread and fill in the appropriate data, -// plus request the target-side to do the same thing. - -static int -tcl_test_control_in(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv) -{ - int i; - int tmp; - UsbTest* test; - unsigned char request[USBTEST_MAX_CONTROL_DATA]; - int request_index; - - // The data consists of 6 numbers for UsbTest_ControlIn itself, and - // another 10 numbers for the test data definition. - if (17 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_test_control_in \"", TCL_STATIC); - return TCL_ERROR; - } - for (i = 1; i < 17; i++) { - int discard; - if (TCL_OK != Tcl_GetInt(interp, argv[i], &discard)) { - Tcl_SetResult(interp, "invalid argument: all arguments should be numbers", TCL_STATIC); - return TCL_ERROR; - } - } - - test = pool_allocate(); - test->which_test = usbtest_control_in; - Tcl_GetInt(interp, argv[1], &(test->test_params.control_in.number_packets)); - Tcl_GetInt(interp, argv[2], &(test->test_params.control_in.packet_size_initial)); - Tcl_GetInt(interp, argv[3], &(test->test_params.control_in.packet_size_min)); - Tcl_GetInt(interp, argv[4], &(test->test_params.control_in.packet_size_max)); - Tcl_GetInt(interp, argv[5], &(test->test_params.control_in.packet_size_multiplier)); - Tcl_GetInt(interp, argv[6], &(test->test_params.control_in.packet_size_increment)); - Tcl_GetInt(interp, argv[7], &tmp); - test->test_params.bulk.data.format = (usbtestdata) tmp; - Tcl_GetInt(interp, argv[ 8], &(test->test_params.control_in.data.seed)); - Tcl_GetInt(interp, argv[ 9], &(test->test_params.control_in.data.multiplier)); - Tcl_GetInt(interp, argv[10], &(test->test_params.control_in.data.increment)); - Tcl_GetInt(interp, argv[11], &(test->test_params.control_in.data.transfer_seed_multiplier)); - Tcl_GetInt(interp, argv[12], &(test->test_params.control_in.data.transfer_seed_increment)); - Tcl_GetInt(interp, argv[13], &(test->test_params.control_in.data.transfer_multiplier_multiplier)); - Tcl_GetInt(interp, argv[14], &(test->test_params.control_in.data.transfer_multiplier_increment)); - Tcl_GetInt(interp, argv[15], &(test->test_params.control_in.data.transfer_increment_multiplier)); - Tcl_GetInt(interp, argv[16], &(test->test_params.control_in.data.transfer_increment_increment)); - - // That is all the data converted from Tcl to C, and a local thread is set up to handle this - // request. Also set up a thread on the target. - request_index = 0; - pack_usbtest_control_in(&(test->test_params.control_in), request, &request_index); - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_TEST_CONTROL_IN, 0, 0, - request_index, request); - remote_thread_count++; - - return TCL_OK; -} - -/*}}}*/ -/*{{{ Cancel the current batch of tests */ - -static int -tcl_cancel(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv __attribute__ ((unused)) ) -{ - if (1 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::cancel\"", TCL_STATIC); - return TCL_ERROR; - } - - // Send the request on to the target. - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_CANCEL, 0, 0, 0, (void*)0); - - // Now cancel all the local tests. This can be done by resetting the counter - // of allocated threads: no actual work will have been started yet. - local_thread_count = 0; - - // And synchronise with the target - if (!usb_sync(usb_master_fd, 30)) { - fprintf(stderr, "usbhost: error, target has failed to process test cancel request.\n"); - exit(EXIT_FAILURE); - - } - remote_thread_count = 0; - - return TCL_OK; -} - -/*}}}*/ -/*{{{ Run a batch of tests */ - -// ---------------------------------------------------------------------------- -// This code does an awful lot of the hard work. Start with various utilities. - -// Has the current batch finished as far as the local threads are concerned? -static int -local_batch_finished(void) -{ - int result = 1; - int i; - - for (i = 0; i < local_thread_count; i++) { - if (pool[i].running) { - result = 0; - break; - } - } - return result; -} - -// Has the current batch finished as far as remote threads are concerned? -static int -remote_batch_finished(void) -{ - char buf[1]; - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_FINISHED, - 0, 0, 1, (void*) buf); - return buf[0]; -} - -// Perform recovery for a thread on the target. This involves asking the -// target for recovery information, then performing an appropriate -// action. If no data is returned then no recovery is needed for this thread. -static void -recover_remote(int index) -{ - unsigned char buffer[USBTEST_MAX_CONTROL_DATA]; - int buffer_index; - UsbTest_Recovery recovery; - int i; - - if (0 != usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, - USBTEST_GET_RECOVERY, 0, index, 12, buffer)) { - // There is work to be done - buffer_index = 0; - unpack_usbtest_recovery(&recovery, buffer, &buffer_index); - - // We have an endpoint, a protocol, and a size. - if (0 == recovery.endpoint) { - // The target just needs a dummy reserved control message - usb_reliable_control_message(usb_master_fd, USB_TYPE_RESERVED | USB_RECIP_DEVICE, USBTEST_RESERVED_CONTROL_IN, - 0, 0, 0, (void*) 0); - } else if (USB_ENDPOINT_XFER_BULK == recovery.protocol) { - // Either we need to send some data to the target, or we need to accept some data. - static unsigned char recovery_buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA]; - - struct usbdevfs_bulktransfer transfer; - transfer.ep = recovery.endpoint; - transfer.timeout = 2000; // Two seconds. Should be plenty, even for a large bulk transfer. - transfer.data = recovery_buffer; - if (USB_DIR_IN == (recovery.endpoint & USB_ENDPOINT_DIR_MASK)) { - transfer.len = recovery.size; - } else { - transfer.len = 1; - } - errno = 0; - i = ioctl(usb_master_fd, USBDEVFS_BULK, &transfer); - } - - // There is no recovery support yet for other protocols. - } -} - -// Perform recovery for a local thread. This involves extracting the -// recovery information from the local thread and asking the target -// to take appropriate action. -static void -recover_local(int index) -{ - unsigned char buffer[USBTEST_MAX_CONTROL_DATA]; - int buffer_index; - - if (pool[index].running) { - buffer_index = 0; - pack_usbtest_recovery(&(pool[index].test.recovery), buffer, &buffer_index); - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PERFORM_RECOVERY, - 0, 0, buffer_index, (void*) buffer); - } -} - -// All done, time for a clean-up on both target and host. The latter -// is achieved simply by resetting the thread pool, which actually -// just means resetting the counter since all the threads are blocked -// waiting for the next batch. -static void -run_done(void) -{ - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_BATCH_DONE, 0, 0, 0, (void*) NULL); - local_thread_count = 0; - remote_thread_count = 0; -} - -// The main routine, as invoked from Tcl. This takes a single -// argument, a timeout in seconds. -static int -tcl_run(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv __attribute__ ((unused)) ) -{ - struct timespec delay; - int timeout; - time_t start; - time_t now; - int i, j; - unsigned char result_buf[USBTEST_MAX_CONTROL_DATA]; - int all_ok; - - if (2 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_run \"", TCL_STATIC); - return TCL_ERROR; - } - if (TCL_OK != Tcl_GetInt(interp, argv[1], &timeout)) { - Tcl_SetResult(interp, "invalid argument: timeout should be numeric", TCL_STATIC); - return TCL_ERROR; - } - - VERBOSE(2, "Starting a testrun, timeout %d seconds\n", timeout); - - // Start the tests running on the target. The target USB hardware - // will not actually do anything except in response to packets - // from the host, so it is better to start the target before the - // local threads. - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_START, 0, 0, 0, (void*) 0); - - // Now the local threads can get going. - current_tests_terminated = 0; - pool_start(); - - // Now leave the various testing threads to do their thing until - // either side believes that the batch has finished, or until the - // timeout expires. Note that if one side decides that the batch - // has finished but the other disagrees, that in itself indicates - // a test failure of sorts. - // - // There is a question of polling frequency. Once a second avoids - // excessive polling traffic on the USB bus, and should not impose - // intolerable delays for short-duration tests. - start = time(NULL); - do { - VERBOSE(3, "The tests are running, waiting for termination\n"); - delay.tv_sec = 1; - delay.tv_nsec = 0; - nanosleep(&delay, NULL); - now = time(NULL); - } while (((start + timeout) > now) && !local_batch_finished() && !remote_batch_finished()); - - VERBOSE(2, "Termination detected, time elapsed %ld\n", (long) now - start); - - // If either side believes that testing is not complete, things - // get messy. Start by setting the terminated flag. Any tests that - // are actually still running happily but have not finished within - // the timeout should detect this and stop. - if (!local_batch_finished() || !remote_batch_finished()) { - VERBOSE(2, "Testing is not yet complete, setting TERMINATED flag\n"); - current_tests_terminated = 1; - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_SET_TERMINATED, 0, 0, 0, (void*) 0); - // And another delay, to give threads a chance to detect the - // flag's update - delay.tv_sec = 1; - delay.tv_nsec = 0; - nanosleep(&delay, NULL); - } - - // If there is still are unfinished threads, recovery action - // is needed. It is not clear whether it is better to unlock - // the local threads first, or the remote threads. For now the - // latter approach is taken. - if (!remote_batch_finished()) { - int i; - VERBOSE(2, "Remote threads still running, performing remote recovery\n"); - for (i = 0; i < remote_thread_count; i++) { - recover_remote(i); - } - // Allow the recovery actions to take effect - delay.tv_sec = 1; - delay.tv_nsec = 0; - nanosleep(&delay, NULL); - } - - if (!local_batch_finished()) { - int i; - VERBOSE(2, "Local threads still running, performing local recovery\n"); - for (i = 0; i < local_thread_count; i++) { - recover_local(i); - } - // Allow the recovery actions to take effect - delay.tv_sec = 1; - delay.tv_nsec = 0; - nanosleep(&delay, NULL); - } - - // One last check to make sure that everything is finished. If not, - // testing has broken down and it is necessary to abort. - if (!local_batch_finished() || !remote_batch_finished()) { - VERBOSE(2, "Giving local and remote threads another chance to finish.\n"); - // Allow the recovery actions to take effect - delay.tv_sec = 5; - delay.tv_nsec = 0; - nanosleep(&delay, NULL); - if (!local_batch_finished() || !remote_batch_finished()) { - // OK, normality has not been restored. - // It would be nice to get hold of and display any error messages. - usb_abort(usb_master_fd); - fprintf(stderr, "Fatal error: the host test program and the remote target are out of synch.\n"); - fprintf(stderr, " recovery has been attempted, without success.\n"); - fprintf(stderr, " USB testing cannot continue.\n"); - exit(EXIT_FAILURE); - } - } - - VERBOSE(2, "Local and remote threads are in synch, collecting results.\n"); - - // The world is in a coherent state. Time to collect the results. - // The return value of this function is a simple boolean. More - // detailed results will be held in a Tcl variable as a list of - // messages. It is desirable to keep both local and remote results - // in order. - for (i = 0; i < ((local_thread_count < remote_thread_count) ? local_thread_count : remote_thread_count); i++) { - if (!pool[i].test.result_pass) { - Tcl_SetVar(interp, "usbtest::results", pool[i].test.result_message, - all_ok ? (TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT) : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT)); - all_ok = 0; - } - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_GET_RESULT, - 0, i, USBTEST_MAX_CONTROL_DATA, (void*) result_buf); - if (!result_buf[0]) { - Tcl_SetVar(interp, "usbtest::results", &(result_buf[1]), - all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT)); - all_ok = 0; - } - } - for (j = i; j < local_thread_count; j++) { - if (!pool[j].test.result_pass) { - Tcl_SetVar(interp, "usbtest::results", pool[j].test.result_message, - all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT)); - all_ok = 0; - } - } - for (j = i; j < remote_thread_count; j++) { - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_GET_RESULT, - 0, i, USBTEST_MAX_CONTROL_DATA, (void*) result_buf); - if (!result_buf[0]) { - Tcl_SetVar(interp, "usbtest::results", &(result_buf[1]), - all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT)); - all_ok = 0; - } - } - VERBOSE(2, "Overall test result %d\n", all_ok); - - Tcl_SetResult(interp, all_ok ? "1" : "0", TCL_STATIC); - - run_done(); - - return TCL_OK; -} - -/*}}}*/ -/*{{{ Set verbosity */ - -// ---------------------------------------------------------------------------- -// Allow Tcl scripts to control verbosity levels for both host and target -static int -tcl_host_verbose(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv) -{ - int level; - - if (2 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::host_verbose \"", TCL_STATIC); - return TCL_ERROR; - } - if (TCL_OK != Tcl_GetInt(interp, argv[1], &level)) { - Tcl_SetResult(interp, "invalid argument: verbosity level should be numeric", TCL_STATIC); - return TCL_ERROR; - } - - verbose = level; - return TCL_OK; -} - -static int -tcl_target_verbose(ClientData clientData __attribute__ ((unused)), - Tcl_Interp* interp, - int argc, - char** argv) -{ - int level; - - if (2 != argc) { - Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_verbose \"", TCL_STATIC); - return TCL_ERROR; - } - if (TCL_OK != Tcl_GetInt(interp, argv[1], &level)) { - Tcl_SetResult(interp, "invalid argument: verbosity level should be numeric", TCL_STATIC); - return TCL_ERROR; - } - - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_VERBOSE, level, 0, 0, NULL); - usb_sync(usb_master_fd, -1); - - return TCL_OK; -} - -/*}}}*/ - -/*}}}*/ -/*{{{ AppInit() */ - -// ---------------------------------------------------------------------------- -// Application-specific initialization. We have a bare Tcl interpreter ready -// to start executing scripts that define various test cases. However some -// additional functions will have to be added to the interpreter, plus -// information about the various endpoints. - -static int -usbhost_appinit(Tcl_Interp* interp) -{ - unsigned char buf[USBTEST_MAX_CONTROL_DATA]; - int number_of_endpoints; - int i; - char* location; - - // Start by creating a usbtest namespace, for use by the various functions - // and variables. - if (TCL_OK != Tcl_Eval(interp, - "namespace eval usbtest {\n" - " variable number_of_endpoints 0\n" - " array set endpoint [list]\n" - "}\n")) { - fprintf(stderr, "usbhost: internal error, failed to create Tcl usbtest:: namespace\n"); - fprintf(stderr, " Please check Tcl version (8.0b1 or later required).\n"); - exit(EXIT_FAILURE); - } - - // Add some information about the install path so that the - // main Tcl script can find and execute test scripts. - location = getenv("USBHOSTDIR"); - if (NULL == location) { - location = USBAUXDIR; - } - Tcl_SetVar(interp, "usbtest::USBAUXDIR", location, TCL_GLOBAL_ONLY); - - // Also set the verbosity level correctly - Tcl_SetVar2Ex(interp, "usbtest::verbose", NULL, Tcl_NewIntObj(verbose), TCL_GLOBAL_ONLY); - - // Next we need to know the number of endpoints, and for each - // endpoint we want additional information such as type. The - // results are placed in a Tcl array. - usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_ENDPOINT_COUNT, - 0, 0, 1, buf); - number_of_endpoints = buf[0]; - Tcl_SetVar2Ex(interp, "usbtest::endpoint_count", NULL, Tcl_NewIntObj(number_of_endpoints), TCL_GLOBAL_ONLY); - - for (i = 0; i < number_of_endpoints; i++) { - char varname[256]; - int result; - int endpoint_min_size; - int endpoint_max_size; - int index; - - memset(buf, 0, USBTEST_MAX_CONTROL_DATA); - result = usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, - USBTEST_ENDPOINT_DETAILS, 0, i, USBTEST_MAX_CONTROL_DATA, buf); - if (result < 13) { - fprintf(stderr, "usbhost: error, received insufficient endpoint data back from the target.\n"); - exit(EXIT_FAILURE); - } - - // See protocol.h for the encoding used. - sprintf(varname, "usbtest::endpoint_data(%d,type)", i); - switch(buf[0]) { - case USB_ENDPOINT_XFER_CONTROL : Tcl_SetVar(interp, varname, "control", TCL_GLOBAL_ONLY); break; - case USB_ENDPOINT_XFER_ISOC : Tcl_SetVar(interp, varname, "isochronous", TCL_GLOBAL_ONLY); break; - case USB_ENDPOINT_XFER_BULK : Tcl_SetVar(interp, varname, "bulk", TCL_GLOBAL_ONLY); break; - case USB_ENDPOINT_XFER_INT : Tcl_SetVar(interp, varname, "interrupt", TCL_GLOBAL_ONLY); break; - } - - sprintf(varname, "usbtest::endpoint_data(%d,number)", i); - Tcl_SetVar2Ex(interp, varname, NULL, Tcl_NewIntObj((int) buf[1]), TCL_GLOBAL_ONLY); - - sprintf(varname, "usbtest::endpoint_data(%d,direction)", i); - if (USB_DIR_OUT == buf[2]) { - Tcl_SetVar(interp, varname, "out", TCL_GLOBAL_ONLY); - } else { - Tcl_SetVar(interp, varname, "in", TCL_GLOBAL_ONLY); - } - - sprintf(varname, "usbtest::endpoint_data(%d,max_in_padding)", i); - Tcl_SetVar2Ex(interp, varname, NULL, Tcl_NewIntObj((int) buf[3]), TCL_GLOBAL_ONLY); - - sprintf(varname, "usbtest::endpoint_data(%d,min_size)", i); - index = 4; - endpoint_min_size = unpack_int(buf, &index); - Tcl_SetVar2Ex(interp, varname, NULL, Tcl_NewIntObj(endpoint_min_size), TCL_GLOBAL_ONLY); - - sprintf(varname, "usbtest::endpoint_data(%d,max_size)", i); - endpoint_max_size = unpack_int(buf, &index); - if (USB_ENDPOINT_XFER_CONTROL == buf[0]) { - if (endpoint_max_size > USBTEST_MAX_CONTROL_DATA) { - endpoint_max_size = USBTEST_MAX_CONTROL_DATA; - } - } else { - if ((-1 == endpoint_max_size) || (endpoint_max_size > USBTEST_MAX_BULK_DATA)) { - endpoint_max_size = USBTEST_MAX_BULK_DATA; - } - } - Tcl_SetVar2Ex(interp, varname, NULL, Tcl_NewIntObj(endpoint_max_size), TCL_GLOBAL_ONLY); - - sprintf(varname, "usbtest::endpoint_data(%d,devtab)", i); - Tcl_SetVar(interp, varname, (char*) &(buf[12]), TCL_GLOBAL_ONLY); - - // Perform any additional endpoint-specific initialization to make - // sure host and target can actually communicate via this endpoint. - switch(buf[0]) { - case USB_ENDPOINT_XFER_CONTROL : - { - usb_initialise_control_endpoint(endpoint_min_size, endpoint_max_size); - break; - } - case USB_ENDPOINT_XFER_ISOC : - { - if (USB_DIR_OUT == buf[2]) { - usb_initialise_isochronous_out_endpoint(buf[1], endpoint_min_size, endpoint_max_size); - } else { - usb_initialise_isochronous_in_endpoint(buf[1], endpoint_min_size, endpoint_max_size); - } - break; - } - case USB_ENDPOINT_XFER_BULK : - { - if (USB_DIR_OUT == buf[2]) { - usb_initialise_bulk_out_endpoint(buf[1], endpoint_min_size, endpoint_max_size); - } else { - usb_initialise_bulk_in_endpoint(buf[1], endpoint_min_size, endpoint_max_size, buf[3]); - } - - break; - } - case USB_ENDPOINT_XFER_INT : - { - if (USB_DIR_OUT == buf[2]) { - usb_initialise_interrupt_out_endpoint(buf[1], endpoint_min_size, endpoint_max_size); - } else { - usb_initialise_interrupt_in_endpoint(buf[1], endpoint_min_size, endpoint_max_size); - } - break; - } - } - } - - // Register appropriate commands with the Tcl interpreter - Tcl_CreateCommand(interp, "usbtest::target_pass", &tcl_target_pass, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::target_pass_exit", &tcl_target_pass_exit, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::target_fail", &tcl_target_fail, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::target_fail_exit", &tcl_target_fail_exit, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::target_abort", &tcl_target_abort, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::_test_bulk", &tcl_test_bulk, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::_test_control_in", &tcl_test_control_in, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::_cancel", &tcl_cancel, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::_run", &tcl_run, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::host_verbose", &tcl_host_verbose, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "usbtest::target_verbose", &tcl_target_verbose, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL); - - return TCL_OK; -} - -/*}}}*/ -/*{{{ main() */ - -// ---------------------------------------------------------------------------- -// System start-up. After argument processing this code checks that -// there is a suitable USB target attached - if not then there is no -// point in proceeding. Otherwise further initialization is performed -// and then control is passed to a Tcl interpreter. - -static void -usage(void) -{ - printf("usbhost: usage, usbhost [-V|--verbose] [-v|--version] [-h|--help] [args]\n"); - printf(" -V, --verbose Make the host-side output additional information\n"); - printf(" during test runs. This argument can be repeated to\n"); - printf(" increase verbosity.\n"); - printf(" -v, --version Output version information for usbhost.\n"); - printf(" -h, --help Output this help information.\n"); - printf(" The name of a USB test case, for example list.tcl\n"); - printf(" [args] Optional additional arguments for the testcase.\n"); - exit(0); -} - -static void -version(void) -{ - printf("usbhost: version %s\n", USBHOST_VERSION); - printf(" : built from USB slave package version %s\n", PKGVERSION); - printf(" : support files installed in %s\n", USBAUXDIR); - exit(0); -} - -int -main(int argc, char** argv) -{ - char* interpreter = argv[0]; - char** new_argv; - char path[_POSIX_PATH_MAX]; - char* location; - int i; - - // Argument processing - for (i = 1; i < argc; i++) { - if ((0 == strcmp("-h", argv[i])) || (0 == strcmp("-H", argv[i])) || (0 == strcmp("--help", argv[i]))) { - usage(); - } - if ((0 == strcmp("-v", argv[i])) || (0 == strcmp("--version", argv[i]))) { - version(); - } - if ((0 == strcmp("-V", argv[i])) || (0 == strcmp("--verbose", argv[i]))) { - verbose++; - continue; - } - - // The first unrecognised argument should correspond to the test script. - break; - } - argc = (argc - i) + 1; - argv = (argv + i) - 1; - - if (1 == argc) { - fprintf(stderr, "usbhost: at least one test script must be specified on the command line.\n"); - exit(EXIT_FAILURE); - } - - usb_master_fd = usb_open_device(); - if (-1 == usb_master_fd) { - return EXIT_FAILURE; - } - - // There is a valid USB target. Initialize the pool of threads etc. - pool_initialize(); - - // Now start a Tcl interpreter. Tcl_Main() will interpret the - // first argument as the name of a Tcl script to execute, - // i.e. usbhost.tcl. This can be found in the install tree, - // but during development it is inconvenient to run - // "make install" every time the Tcl script is edited so an - // environment variable can be used to override the location. - new_argv = malloc((argc + 2) * sizeof(char*)); - if (NULL == new_argv) { - fprintf(stderr, "usbhost: internal error, out of memory.\n"); - exit(EXIT_FAILURE); - } - new_argv[0] = interpreter; - - location = getenv("USBHOSTDIR"); - if (NULL == location) { - location = USBAUXDIR; - } - snprintf(path, _POSIX_PATH_MAX, "%s/usbhost.tcl", location); - if (0 != access(path, R_OK)) { - fprintf(stderr, "usbhost: cannot find or access required Tcl script\n"); - fprintf(stderr, " : %s\n", path); - exit(EXIT_FAILURE); - } - new_argv[1] = path; - - for (i = 1; i < argc; i++) { - new_argv[i+1] = argv[i]; - } - new_argv[i+1] = NULL; - - Tcl_Main(i+1, new_argv, &usbhost_appinit); - - return EXIT_SUCCESS; -} - -/*}}}*/ Index: slave/v2_0/host/usbhost.tcl =================================================================== --- slave/v2_0/host/usbhost.tcl (revision 174) +++ slave/v2_0/host/usbhost.tcl (nonexistent) @@ -1,531 +0,0 @@ -# {{{ Banner - -#=============================================================================== -# -# usbhost.tcl -# -# Support for USB testing -# -#=============================================================================== -#####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#### -# -# Author(s): bartv -# Date: 2001-07-04 -# Purpose: To provide higher-level utility commands for performing -# USB testing, and to iterate through the various test scripts -# specified on the command line. -# -#####DESCRIPTIONEND#### -#=============================================================================== -# - -# }}} - -# {{{ Endpoint data - -# Given the raw endpoint data provided by the C code, turn -# it something more usable from inside Tcl scripts. -namespace eval usbtest { - array set control {} - - variable bulk_in_endpoints [list] - array set bulk_in {} - variable bulk_out_endpoints [list] - array set bulk_out {} - - variable isochronous_in_endpoints [list] - array set isochronous_in {} - variable isochronous_out_endpoints [list] - array set isochronous_out {} - - variable interrupt_in_endpoints [list] - array set interrupt_in {} - variable interrupt_out_endpoints [list] - array set interrupt_out {} - - for { set i 0 } { $i < $usbtest::endpoint_count } { incr i } { - switch -- $usbtest::endpoint_data($i,type) { - "control" { - set usbtest::control(min_size) $usbtest::endpoint_data($i,min_size) - set usbtest::control(max_size) $usbtest::endpoint_data($i,max_size) - } - - "bulk" { - set number $usbtest::endpoint_data($i,number) - if { "in" == $usbtest::endpoint_data($i,direction) } { - lappend usbtest::bulk_in_endpoints $number - set usbtest::bulk_in($number,min_size) $usbtest::endpoint_data($i,min_size) - set usbtest::bulk_in($number,max_size) $usbtest::endpoint_data($i,max_size) - set usbtest::bulk_in($number,max_in_padding) $usbtest::endpoint_data($i,max_in_padding) - set usbtest::bulk_in($number,devtab) $usbtest::endpoint_data($i,devtab) - } else { - lappend usbtest::bulk_out_endpoints $number - set usbtest::bulk_out($number,min_size) $usbtest::endpoint_data($i,min_size) - set usbtest::bulk_out($number,max_size) $usbtest::endpoint_data($i,max_size) - set usbtest::bulk_out($number,devtab) $usbtest::endpoint_data($i,devtab) - } - } - - "isochronous" { - set number $usbtest::endpoint_data($i,number) - if { "in" == $usbtest::endpoint_data($i,direction) } { - lappend usbtest::isochronous_in_endpoints $number - set usbtest::isochronous_in($number,min_size) $usbtest::endpoint_data($i,min_size) - set usbtest::isochronous_in($number,max_size) $usbtest::endpoint_data($i,max_size) - set usbtest::isochronous_in($number,devtab) $usbtest::endpoint_data($i,devtab) - } else { - lappend usbtest::isochronous_out_endpoints $number - set usbtest::isochronous_out($number,min_size) $usbtest::endpoint_data($i,min_size) - set usbtest::isochronous_out($number,max_size) $usbtest::endpoint_data($i,max_size) - set usbtest::isochronous_out($number,devtab) $usbtest::endpoint_data($i,devtab) - } - } - - "interrupt" { - set number $usbtest::endpoint_data($i,number) - if { "in" == $usbtest::endpoint_data($i,direction) } { - lappend usbtest::interrupt_in_endpoints $number - set usbtest::interrupt_in($number,min_size) $usbtest::endpoint_data($i,min_size) - set usbtest::interrupt_in($number,max_size) $usbtest::endpoint_data($i,max_size) - set usbtest::interrupt_in($number,devtab) $usbtest::endpoint_data($i,devtab) - } else { - lappend usbtest::interrupt_out_endpoints $number - set usbtest::interrupt_out($number,min_size) $usbtest::endpoint_data($i,min_size) - set usbtest::interrupt_out($number,max_size) $usbtest::endpoint_data($i,max_size) - set usbtest::interrupt_out($number,devtab) $usbtest::endpoint_data($i,devtab) - } - } - - default { - puts stderr "Internal error: invalid endpoint type $usbtest::endpoint_data($i,type)" - exit 1 - } - } - } -} - -# }}} -# {{{ Constants - -# The C code expects to receive certain data as simple numbers, -# corresponding to #define's in common.c and elsewhere. Strictly -# speaking it would be better to pass strings to the C code and -# have it do the translation, thus ensuring that these constants -# exist in only one place. - -namespace eval usbtest { - - variable _USB_DIR_IN 0x0080 - variable _DATA_NONE 0 - variable _DATA_BYTE_FILL 1 - variable _DATA_WORD_FILL 2 - variable _DATA_BYTE_GEN 3 - variable _DATA_WORD_GEN 4 - variable _IO_MECHANISM_USB 1 - variable _IO_MECHANISM_DEV 2 -} - -# It is also desirable to have some constants corresponding -# to common random number generators. -namespace eval usbtest { - variable MULTIPLIER 1103515245 - variable INCREMENT 12345 -} - -# }}} -# {{{ Argument processing - -# ---------------------------------------------------------------------------- -# Given a list of arguments of the form "xyzzy=123" or "xyzzy 123", and -# an array arguments containing entries such as arguments(xyzzy) and -# already filled in with default values, update the array using the -# actual arguments -namespace eval usbtest { - - proc process_arguments { list array_ref } { - upvar $array_ref array - array set defined_args [list] - - set listlen [llength $list] - for { set index 0 } { $index < $listlen } { incr index } { - set arg [lindex $list $index] - set found 0 - foreach name [array names array] { - set len [string length $name] - if { [string equal -length $len $name $arg] } { - # Partial match found. - if { [string equal $name $arg] } { - # Exact match found, The value must be the next arg. - if { [info exists defined_args($name)] } { - error "Argument $name should be specified only once" - } - incr index - if { $index >= $listlen } { - error "Missing value after argument $name" - } - set array($name) [lindex $list $index] - set found 1 - break - } - - # Not an exact match. Try looking for x=y - incr len - if { [string equal -length $len "$name=" $arg] } { - if { [info exists defined_args($name)] } { - error "Argument $name should be specified only once" - } - set array($name) [string range $arg $len end] - set found 1 - break - } - } - } - if { ! $found } { - error "Invalid argument $arg" - } - } - } -} - -# }}} -# {{{ Starting and ending tests - -# This section deals with starting tests, or cleaning up when the -# tests cannot actually proceed. Also there is some validation, -# for example to make sure that no endpoint number is used for -# multiple tests. - -namespace eval usbtest { - variable results - variable _tests_submitted 0 - variable _control_endpoint_in_use 0 - variable _in_endpoints_in_use [list] - variable _out_endpoints_in_use [list] - - proc reset { } { - if { 0 != $usbtest::_tests_submitted } { - usbtest::_cancel - set usbtest::_tests_submitted 0 - - } - set usbtest::_in_endpoints_in_use [list] - set usbtest::_out_endpoints_in_use [list] - } - - proc use_endpoint { endpoint direction } { - if { 0 == $endpoint } { - if { $usbtest::_control_endpoint_in_use } { - error "Attempt to run multiple tests on the control endpoint" - } - set usbtest::_control_endpoint_in_use 1 - } else { - switch -- $direction { - "in" { - if { -1 != [lsearch -exact $usbtest::_in_endpoints_in_use $endpoint] } { - error "Attempt to run multiple IN tests on endpoint $endpoint" - } - lappend usbtest::_in_endpoints_in_use $endpoint - } - - "out" { - if { -1 != [lsearch -exact $usbtest::_out_endpoints_in_use $endpoint] } { - error "Attempt to run multiple OUT tests on endpoint $endpoint" - } - lappend usbtest::_out_endpoints_in_use $endpoint - } - - default { - error "Invalid direction passed to usbtest::use_endpoint" - } - } - } - } - - proc test_submitted { } { - incr usbtest::_tests_submitted - } - - proc start { timeout } { - set result 0 - if { 0 == $usbtest::_tests_submitted } { - error "Attempt to start tests when no tests are scheduled to run." - } elseif { ! [string is integer -strict $timeout] } { - error "Invalid timeout specified, it should be a simple number." - } else { - set usbtest::results [list] - set result [usbtest::_run $timeout] - set usbtest::_tests_submitted 0 - set usbtest::_control_endpoint_in_use 0 - array unset _in_endpoints_in_use - array unset _out_endpoints_in_use - } - return $result - } -} - -# }}} -# {{{ Bulk tests - -# Prepare to run a bulk test. -# -# This test requires rather a lot of parameters, many of which -# will have sensible defaults. - -namespace eval usbtest { - - proc bulktest { endpoint direction number_packets args } { - - - # Parameters to be passed to the C code. Most are - # held in an array indexed by the option name, - # facilitating command-line parsing. - set arguments(format) "none" - set arguments(data1) 0 - set arguments(data*) 1 - set arguments(data+) 0 - set arguments(data1*) 1 - set arguments(data1+) 0 - set arguments(data**) 1 - set arguments(data*+) 0 - set arguments(data+*) 1 - set arguments(data++) 0 - set arguments(mechanism) "usb" - set arguments(txsize1) 32 - set arguments(txsize>=) 0 - set arguments(txsize<=) -1 - set arguments(txsize*) 1 - set arguments(txsize/) 1 - set arguments(txsize+) 0 - set arguments(rxsize1) 0 - set arguments(rxsize>=) 0 - set arguments(rxsize<=) -1 - set arguments(rxsize*) 1 - set arguments(rxsize/) 1 - set arguments(rxsize+) 0 - set arguments(txdelay1) 0 - set arguments(txdelay>=) 0 - set arguments(txdelay<=) 1000000000 - set arguments(txdelay*) 1 - set arguments(txdelay/) 1 - set arguments(txdelay+) 0 - set arguments(rxdelay1) 0 - set arguments(rxdelay>=) 0 - set arguments(rxdelay<=) 1000000000 - set arguments(rxdelay*) 1 - set arguments(rxdelay/) 1 - set arguments(rxdelay+) 0 - - set endpoint_param "" - - # Target limits - set target_min_size 0 - set target_max_size 0 - set target_padding 0 - set target_devtab "" - - # Start by validating the endpoint and direction arguments. - # Also check that the specified endpoint is not yet in use. - if { ![string is integer -strict $endpoint] } { - error "Invalid endpoint argument \"$endpoint\": should be a number" - } - if { ($endpoint < 1) || ($endpoint > 15) } { - error "Invalid bulk endpoint argument \"$endpoint\": should be between 1 and 15" - } - switch -- $direction { - "in" - - "In" - - "IN" { - set direction "in" - if { -1 == [lsearch -exact $usbtest::bulk_in_endpoints $endpoint] } { - error "Invalid bulk endpoint argument \"$endpoint\": the target does not list that as a bulk IN endpoint" - } - set target_min_size $usbtest::bulk_in($endpoint,min_size) - set target_max_size $usbtest::bulk_in($endpoint,max_size) - set target_padding $usbtest::bulk_in($endpoint,max_in_padding) - set target_devtab $usbtest::bulk_in($endpoint,devtab); - set endpoint_param [expr $endpoint | $usbtest::_USB_DIR_IN] - } - - "out" - - "Out" - - "OUT" { - set direction "out" - if { -1 == [lsearch -exact $usbtest::bulk_out_endpoints $endpoint] } { - error "Invalid bulk endpoint argument \"$endpoint\": the target does not list that as a bulk OUT endpoint" - } - set target_min_size $usbtest::bulk_out($endpoint,min_size) - set target_max_size $usbtest::bulk_out($endpoint,max_size) - set target_devtab $usbtest::bulk_out($endpoint,devtab); - set target_padding 0; # Not applicable - set endpoint_param $endpoint - } - - default { - error "Invalid direction argument \"$direction\": should be \"in\" or \"out\"" - } - } - - # Now parse any remaining arguments - usbtest::process_arguments $args arguments - - # Convert two of the arguments from strings to numbers, for the - # convenience of the C code - switch -- $arguments(format) { - "none" { set arguments(format) $usbtest::_DATA_NONE } - "bytefill" { set arguments(format) $usbtest::_DATA_BYTE_FILL } - "wordfill" { set arguments(format) $usbtest::_DATA_WORD_FILL } - "byteseq" { set arguments(format) $usbtest::_DATA_BYTE_GEN } - "wordseq" { set arguments(format) $usbtest::_DATA_WORD_GEN } - - default { - error "Invalid data format argument \"$arguments(data)\"\n \ - Should be \"none\", \"bytefill\", \"wordfill\", \"byteseq\" or \"wordseq\"" - } - } - switch -- $arguments(mechanism) { - "usb" { set arguments(mechanism) $usbtest::_IO_MECHANISM_USB } - "devtab" { set arguments(mechanism) $usbtest::_IO_MECHANISM_DEV } - - default { - error "Invalid mechanism argument \"$arguments(mechanism)\"\n \ - Should be \"usb\" or \"devtab\"" - } - } - - puts "validating fields" - # Validate the remaining fields - foreach field [list data1 data* data+ data1* data1+ data** data*+ data+* data++ \ - txsize1 txsize>= txsize<= txsize* txsize/ txsize+ \ - rxsize1 rxsize>= rxsize<= rxsize* rxsize/ rxsize+ \ - txdelay1 txdelay>= txdelay<= txdelay* txdelay/ txdelay+ \ - rxdelay1 rxdelay>= rxdelay<= rxdelay* rxdelay/ rxdelay+] { - if { ![string is integer -strict $arguments($field)] } { - error "Invalid value \"$arguments($field)\" for argument $field, should be an integer." - } - } - - if { $arguments(txsize>=) < $target_min_size } { - set arguments(txsize>=) $target_min_size - } - if { (-1 == $arguments(txsize<=) ) || ($arguments(txsize<=) > $target_max_size) } { - set arguments(txsize<=) $target_max_size - } - if { $arguments(rxsize<=) == -1 } { - set arguments(rxsize<=) $target_max_size - } - if { $arguments(txsize1) < $arguments(txsize>=) } { - set arguments(txsize1) $arguments(txsize>=) - } - # Make sure the endpoint is not already in use - usbtest::use_endpoint $endpoint $direction - - puts "Submitting test" - # Now submit the test. This is handled by C code. - usbtest::_test_bulk \ - $number_packets \ - $endpoint_param \ - $arguments(txsize1) \ - $arguments(txsize>=) \ - $arguments(txsize<=) \ - $arguments(txsize*) \ - $arguments(txsize/) \ - $arguments(txsize+) \ - $arguments(rxsize1) \ - $arguments(rxsize>=) \ - $arguments(rxsize<=) \ - $arguments(rxsize*) \ - $arguments(rxsize/) \ - $arguments(rxsize+) \ - $target_padding \ - $arguments(txdelay1) \ - $arguments(txdelay>=) \ - $arguments(txdelay<=) \ - $arguments(txdelay*) \ - $arguments(txdelay/) \ - $arguments(txdelay+) \ - $arguments(rxdelay1) \ - $arguments(rxdelay>=) \ - $arguments(rxdelay<=) \ - $arguments(rxdelay*) \ - $arguments(rxdelay/) \ - $arguments(rxdelay+) \ - $arguments(mechanism) \ - $arguments(format) \ - $arguments(data1) \ - $arguments(data*) \ - $arguments(data+) \ - $arguments(data1*) \ - $arguments(data1+) \ - $arguments(data**) \ - $arguments(data*+) \ - $arguments(data+*) \ - $arguments(data++) - - test_submitted - } -} - -# }}} -# {{{ Execute the specified test script - -# Interpret the arguments as a test script plus auxiliary data. -set script [lindex $::argv 0] -set ::argv [lrange $::argv 1 end] - -set result [catch { - set path [file join [pwd] $script] - if { ![file exists $path] } { - set path "$path.tcl" - if { ![file exists $path] } { - set path [file join $usbtest::USBAUXDIR $script] - if { ![file exists $path] } { - set path "$path.tcl" - if { ![file exists $path] } { - error "Error: unknown test script $script" - } - } - } - } - - source $path - -} message] - -if { 0 != $result } { - puts $message -} - -# }}} Index: slave/v2_0/host/Makefile.am =================================================================== --- slave/v2_0/host/Makefile.am (revision 174) +++ slave/v2_0/host/Makefile.am (nonexistent) @@ -1,114 +0,0 @@ -## Process this file with automake to produce Makefile.in -## ===================================================================== -## -## Makefile.am -## -## Build support for the eCos USB host-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#### -## -## Author(s): bartv -## Contact(s): bartv -## Date: 2002/01/10 -## Version: 0.01 -## -######DESCRIPTIONEND#### -## ===================================================================== - -AUTOMAKE_OPTIONS = 1.3 foreign - -## Only some platforms are supported. Having the configure script throw -## an error when attempting to configure on an unsupported platform -## would be a mistake, since that would prevent any configury from -## the toplevel on unsupported platforms. Instead an automake conditional -## is used, leading to null makefiles on unsupported platforms. - -if SUPPORTED - -AM_CFLAGS = @ecos_CFLAGS@ -DUSBHOST_VERSION=\"@VERSION@\" -DPKGVERSION=\"@PACKAGE_VERSION@\" -DUSBAUXDIR=\"$(libexecdir)/ecos/@PACKAGE_INSTALL@\" -AM_CXXFLAGS = @ecos_CXXFLAGS@ -INCLUDES = @ecos_INCLUDES@ -LIBS = @ecos_LIBS@ @ecos_LDADD@ - -## The USB testing support consists of two programs, usbhost and -## usbchmod, and a number of Tcl scripts. usbhost is executable by the -## user so it should get installed in bindir, appropriately prefixed -## and with a symbolic link installed as per e.g. tclsh (it is known -## that this code is Linux-specific so the use of symbolic links is -## not a problem). usbchmod is not directly executable so it should -## get installed in or below libexec. The Tcl scripts are architecture -## independent so should probably be installed below $(datadir), but -## for now putting them in the same directory as usbchmod will do -## fine. - -noinst_PROGRAMS = usbhost -usbhost_SOURCES = usbhost.c -usbhost_DEPENDENCIES = ../tests/protocol.h ../tests/common.c -usbhost_LDADD = -lpthread - -usbauxdir = $(libexecdir)/ecos/@PACKAGE_INSTALL@ -usbaux_PROGRAMS = usbchmod -usbaux_DATA = usbhost.tcl list.tcl verbose.tcl -usbchmod_SOURCES = usbchmod.c - -## Two special operations are required during installation. -## 1) usbhost needs to be installed suitably versioned, e.g. as -## usbhost_current, and with a symbolic link from usbhost to -## the new executable. -## 2) usbchmod needs to be suid root -install-exec-hook: - $(INSTALL_PROGRAM) usbhost $(bindir)/usbhost_@PACKAGE_VERSION@ - rm -f $(bindir)/usbhost - $(LN_S) $(bindir)/usbhost_@PACKAGE_VERSION@ $(bindir)/usbhost - -install-data-hook: - chown root $(usbauxdir)/usbchmod - chmod u+s $(usbauxdir)/usbchmod - -else - -## When automake scans for hooks it does not take conditionals fully -## into account. If the conditional is not satisfied the generated -## makefile will still try to invoke the hook, so dummy hooks are needed. -install-exec-hook: - echo Nothing to be done for this platform - -install-data-hook: - echo Nothing to be done for this platform - -endif Index: slave/v2_0/host/list.tcl =================================================================== --- slave/v2_0/host/list.tcl (revision 174) +++ slave/v2_0/host/list.tcl (nonexistent) @@ -1,130 +0,0 @@ -# {{{ Banner - -#=============================================================================== -# -# list.tcl -# -# Support for USB testing -# -#=============================================================================== -#####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#### -# -# Author(s): bartv -# Date: 2001-08-21 -# Purpose: Provide details of the available endpoints -# -#####DESCRIPTIONEND#### -#=============================================================================== -# - -# }}} - -puts "Control endpoint: valid packet sizes are $usbtest::control(min_size) to $usbtest::control(max_size)" - -if { 0 != [llength $usbtest::bulk_in_endpoints] } { - puts "Bulk IN endpoints: $usbtest::bulk_in_endpoints" - foreach ep $usbtest::bulk_in_endpoints { - puts [format " %2d: packet sizes %d to %d, padding %d" $ep \ - $usbtest::bulk_in($ep,min_size) $usbtest::bulk_in($ep,max_size) $usbtest::bulk_in($ep,max_in_padding)] - if { "" == $usbtest::bulk_in($ep,devtab) } { - puts " no devtab entry" - } else { - puts " devtab entry $usbtest::bulk_in($ep,devtab)" - } - } -} -if { 0 != [llength $usbtest::bulk_out_endpoints] } { - puts "Bulk OUT endpoints: $usbtest::bulk_out_endpoints" - foreach ep $usbtest::bulk_out_endpoints { - puts [format " %2d: packet sizes %d to %d" $ep \ - $usbtest::bulk_out($ep,min_size) $usbtest::bulk_out($ep,max_size)] - if { "" == $usbtest::bulk_out($ep,devtab) } { - puts " no devtab entry" - } else { - puts " devtab entry $usbtest::bulk_out($ep,devtab)" - } - } -} - -if { 0 != [llength $usbtest::isochronous_in_endpoints] } { - puts "Isochronous IN endpoints: $usbtest::isochronous_in_endpoints" - foreach ep $usbtest::isochronous_in_endpoints { - puts [format " %2d: packet sizes %d to %d" $ep \ - $usbtest::isochronous_in($ep,min_size) $usbtest::isochronous_in($ep,max_size)] - if { "" == $usbtest::isochronous_in($ep,devtab) } { - puts " no devtab entry" - } else { - puts " devtab entry $usbtest::isochronous_in($ep,devtab)" - } - } -} -if { 0 != [llength $usbtest::isochronous_out_endpoints] } { - puts "Isochronous OUT endpoints: $usbtest::isochronous_out_endpoints" - foreach ep $usbtest::isochronous_out_endpoints { - puts [format " %2d: packet sizes %d to %d" $ep \ - $usbtest::isochronous_out($ep,min_size) $usbtest::isochronous_out($ep,max_size)] - if { "" == $usbtest::isochronous_out($ep,devtab) } { - puts " no devtab entry" - } else { - puts " devtab entry $usbtest::isochronous_out($ep,devtab)" - } - } -} - -if { 0 != [llength $usbtest::interrupt_in_endpoints] } { - puts "Interrupt IN endpoints: $usbtest::interrupt_in_endpoints" - foreach ep $usbtest::interrupt_in_endpoints { - puts [format " %2d: packet sizes %d to %d" $ep \ - $usbtest::interrupt_in($ep,min_size) $usbtest::interrupt_in($ep,max_size)] - if { "" == $usbtest::interrupt_in($ep,devtab) } { - puts " no devtab entry" - } else { - puts " devtab entry $usbtest::interrupt_in($ep,devtab)" - } - } -} -if { 0 != [llength $usbtest::interrupt_out_endpoints] } { - puts "Interrupt OUT endpoints: $usbtest::interrupt_out_endpoints" - foreach ep $usbtest::interrupt_out_endpoints { - puts [format " %2d: packet sizes %d to %d" $ep \ - $usbtest::interrupt_out($ep,min_size) $usbtest::interrupt_out($ep,max_size)] - if { "" == $usbtest::interrupt_out($ep,devtab) } { - puts " no devtab entry" - } else { - puts " devtab entry $usbtest::interrupt_out($ep,devtab)" - } - } -} Index: slave/v2_0/host/aclocal.m4 =================================================================== --- slave/v2_0/host/aclocal.m4 (revision 174) +++ slave/v2_0/host/aclocal.m4 (nonexistent) @@ -1,192 +0,0 @@ -dnl aclocal.m4 generated automatically by aclocal 1.4-p5 - -dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl This program is distributed in the hope that it will be useful, -dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without -dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A -dnl PARTICULAR PURPOSE. - -dnl Process this file with aclocal to get an aclocal.m4 file. Then -dnl process that with autoconf. -dnl ==================================================================== -dnl -dnl acinclude.m4 -dnl -dnl ==================================================================== -dnl ####ECOSGPLCOPYRIGHTBEGIN#### -dnl ------------------------------------------- -dnl This file is part of eCos, the Embedded Configurable Operating System. -dnl Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -dnl -dnl eCos is free software; you can redistribute it and/or modify it under -dnl the terms of the GNU General Public License as published by the Free -dnl Software Foundation; either version 2 or (at your option) any later version. -dnl -dnl eCos is distributed in the hope that it will be useful, but WITHOUT ANY -dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or -dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -dnl for more details. -dnl -dnl You should have received a copy of the GNU General Public License along -dnl with eCos; if not, write to the Free Software Foundation, Inc., -dnl 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -dnl -dnl As a special exception, if other files instantiate templates or use macros -dnl or inline functions from this file, or you compile this file and link it -dnl with other works to produce a work based on this file, this file does not -dnl by itself cause the resulting work to be covered by the GNU General Public -dnl License. However the source code for this file must still be made available -dnl in accordance with section (3) of the GNU General Public License. -dnl -dnl This exception does not invalidate any other reasons why a work based on -dnl this file might be covered by the GNU General Public License. -dnl -dnl Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -dnl at http://sources.redhat.com/ecos/ecos-license/ -dnl ------------------------------------------- -dnl ####ECOSGPLCOPYRIGHTEND#### -dnl ==================================================================== -dnl#####DESCRIPTIONBEGIN#### -dnl -dnl Author(s): bartv -dnl Contact(s): bartv -dnl Date: 2002/01/10 -dnl Version: 0.01 -dnl -dnl####DESCRIPTIONEND#### -dnl ==================================================================== - -dnl Access shared macros. -dnl AM_CONDITIONAL needs to be mentioned here or else aclocal does not -dnl incorporate the macro into aclocal.m4 -sinclude(../../../../../../acsupport/acinclude.m4) - -# Define a conditional. - -AC_DEFUN([AM_CONDITIONAL], -[AC_SUBST($1_TRUE) -AC_SUBST($1_FALSE) -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi]) - -# Do all the work for Automake. This macro actually does too much -- -# some checks are only needed if your package does certain things. -# But this isn't really a big deal. - -# serial 1 - -dnl Usage: -dnl AM_INIT_AUTOMAKE(package,version, [no-define]) - -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_REQUIRE([AC_PROG_INSTALL]) -PACKAGE=[$1] -AC_SUBST(PACKAGE) -VERSION=[$2] -AC_SUBST(VERSION) -dnl test to see if srcdir already configured -if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) -fi -ifelse([$3],, -AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) -AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) -AC_REQUIRE([AM_SANITY_CHECK]) -AC_REQUIRE([AC_ARG_PROGRAM]) -dnl FIXME This is truly gross. -missing_dir=`cd $ac_aux_dir && pwd` -AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) -AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) -AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) -AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) -AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) -AC_REQUIRE([AC_PROG_MAKE_SET])]) - -# -# Check to make sure that the build environment is sane. -# - -AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) -# Just in case -sleep 1 -echo timestamp > conftestfile -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` - if test "[$]*" = "X"; then - # -L didn't work. - set X `ls -t $srcdir/configure conftestfile` - fi - if test "[$]*" != "X $srcdir/configure conftestfile" \ - && test "[$]*" != "X conftestfile $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken -alias in your environment]) - fi - - test "[$]2" = conftestfile - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi -rm -f conftest* -AC_MSG_RESULT(yes)]) - -dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) -dnl The program must properly implement --version. -AC_DEFUN([AM_MISSING_PROG], -[AC_MSG_CHECKING(for working $2) -# Run test in a subshell; some versions of sh will print an error if -# an executable is not found, even if stderr is redirected. -# Redirect stdin to placate older versions of autoconf. Sigh. -if ($2 --version) < /dev/null > /dev/null 2>&1; then - $1=$2 - AC_MSG_RESULT(found) -else - $1="$3/missing $2" - AC_MSG_RESULT(missing) -fi -AC_SUBST($1)]) - -# Add --enable-maintainer-mode option to configure. -# From Jim Meyering - -# serial 1 - -AC_DEFUN([AM_MAINTAINER_MODE], -[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) - dnl maintainer-mode is disabled by default - AC_ARG_ENABLE(maintainer-mode, -[ --enable-maintainer-mode enable make rules and dependencies not useful - (and sometimes confusing) to the casual installer], - USE_MAINTAINER_MODE=$enableval, - USE_MAINTAINER_MODE=no) - AC_MSG_RESULT($USE_MAINTAINER_MODE) - AM_CONDITIONAL(MAINTAINER_MODE, test $USE_MAINTAINER_MODE = yes) - MAINT=$MAINTAINER_MODE_TRUE - AC_SUBST(MAINT)dnl -] -) -

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.