Mercurial > flash_v2
changeset 213:3a5832bf0564
Merge from eCos master repository on 2002-05-31-16:13:14-BST
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/Makefile.am @@ -0,0 +1,103 @@ +## 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_NAME@_@PACKAGE_VERSION@\" +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_NAME@_@PACKAGE_VERSION@ +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 + +endif
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/Makefile.in @@ -0,0 +1,483 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 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#### +## ------------------------------------------- +## 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#### +######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@ +EXEEXT = @EXEEXT@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MSVC_SRCDIR = @MSVC_SRCDIR@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_NAME = @PACKAGE_NAME@ +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_libs = @ecos_tk_libs@ + +AUTOMAKE_OPTIONS = 1.3 foreign + +@SUPPORTED_TRUE@AM_CFLAGS = @ecos_CFLAGS@ -DUSBHOST_VERSION=\"@VERSION@\" -DPKGVERSION=\"@PACKAGE_VERSION@\" -DUSBAUXDIR=\"$(libexecdir)/ecos/@PACKAGE_NAME@_@PACKAGE_VERSION@\" +@SUPPORTED_TRUE@AM_CXXFLAGS = @ecos_CXXFLAGS@ +@SUPPORTED_TRUE@INCLUDES = @ecos_INCLUDES@ +@SUPPORTED_TRUE@LIBS = @ecos_LIBS@ @ecos_LDADD@ + +@SUPPORTED_TRUE@noinst_PROGRAMS = usbhost +@SUPPORTED_TRUE@usbhost_SOURCES = usbhost.c +@SUPPORTED_TRUE@usbhost_DEPENDENCIES = ../tests/protocol.h ../tests/common.c +@SUPPORTED_TRUE@usbhost_LDADD = -lpthread + +@SUPPORTED_TRUE@usbauxdir = $(libexecdir)/ecos/@PACKAGE_NAME@_@PACKAGE_VERSION@ +@SUPPORTED_TRUE@usbaux_PROGRAMS = usbchmod +@SUPPORTED_TRUE@usbaux_DATA = usbhost.tcl list.tcl verbose.tcl +@SUPPORTED_TRUE@usbchmod_SOURCES = 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 + +# 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:
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/acinclude.m4 @@ -0,0 +1,54 @@ +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)
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/aclocal.m4 @@ -0,0 +1,192 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 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 +] +) +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/configure @@ -0,0 +1,1967 @@ +#! /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-version=<vsn> version of Tcl to be used" +ac_help="$ac_help + --with-tcl-header=<path> location of Tcl header" +ac_help="$ac_help + --with-tcl-lib=<path> location of Tcl libraries" +ac_help="$ac_help + --with-tcl=<path> location of Tcl header and 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}" = "yes"; then + SUPPORTED_TRUE= + SUPPORTED_FALSE='#' +else + SUPPORTED_TRUE='#' + SUPPORTED_FALSE= +fi + +if test "${SUPPORTED}" = "yes" ; then + # 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:870: 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:900: 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:951: 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:983: 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 994 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:999: \"$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:1025: 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:1030: 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 <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1039: \"$ac_try\") 1>&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:1058: 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:1094: 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:1126: 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 1137 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:1142: \"$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:1168: 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:1173: 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 <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1182: \"$ac_try\") 1>&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:1201: 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 + + echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:1233: 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:1254: 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:1260: \"$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:1278: 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 <<EOF +#line 1283 "configure" +#include "confdefs.h" + +int main() { + +#ifndef __CYGWIN__ +#define __CYGWIN__ __CYGWIN32__ +#endif +return __CYGWIN__; +; return 0; } +EOF +if { (eval echo configure:1294: \"$ac_compile\") 1>&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:1311: 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 <<EOF +#line 1316 "configure" +#include "confdefs.h" + +int main() { +return __MINGW32__; +; return 0; } +EOF +if { (eval echo configure:1323: \"$ac_compile\") 1>&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:1342: 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:1352: \"$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:1390: checking "for Visual C++"" >&5 + MSVC="no"; + if test "${CC}" = "cl" ; then + MSVC="yes" + CXX="cl" + + + + 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:1429: 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 + + + + + + + + ecos_tcl_version="" + ecos_tcl_incdir="" + ecos_tcl_libdir="" + ecos_tk_libs="" + + + echo $ac_n "checking for Tcl version""... $ac_c" 1>&6 +echo "configure:1501: checking for Tcl version" >&5 + # Check whether --with-tcl-version or --without-tcl-version was given. +if test "${with_tcl_version+set}" = set; then + withval="$with_tcl_version" + + ecos_tcl_version=${with_tcl_version} + +else + + if test "${MSVC}" = "yes" ; then + ecos_tcl_version=80 + elif test "${ac_cv_cygwin}" = "yes" ; then + ecos_tcl_version=80 + else + ecos_tcl_version="" + fi + +fi + + echo "$ac_t""${ecos_tcl_version}" 1>&6 + + echo $ac_n "checking for Tcl installation""... $ac_c" 1>&6 +echo "configure:1523: checking for Tcl installation" >&5 + + # 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 + + # Check whether --with-tcl or --without-tcl was given. +if test "${with_tcl+set}" = set; then + withval="$with_tcl" + : +fi + + + + if test "${MSVC}" = "yes" ; then + + 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=<path> or --with-tcl-header=<path>" 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 + ecos_msvc_tcl_incdir="${ecos_tcl_incdir}" + + + + if test "${MSVC}" = "yes" ; then + ecos_msvc_tcl_incdir=`cygpath -w ${ecos_msvc_tcl_incdir} | tr \\\\\\\\ /` + fi + + ecos_INCLUDES="${ecos_INCLUDES} \"-I${ecos_msvc_tcl_incdir}\"" + + 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=<path> or --with-tcl-lib=<path>" 1>&2; exit 1; } + fi + + + + if test "${MSVC}" = "yes" ; then + ecos_tcl_libdir=`cygpath -w ${ecos_tcl_libdir} | tr \\\\\\\\ /` + fi + + ecos_LIBS="${ecos_LIBS} tcl${ecos_tcl_version}.lib" + ecos_LDADD="${ecos_LDADD} \"-libpath=${ecos_tcl_libdir}\"" + + ecos_tk_libs="" + + else + possibles="${with_tcl_header} ${with_tcl}/include ${prefix}/include /usr/include/tcl${ecos_tcl_version} /usr/include" + + ecos_tcl_incdir="" + for i in ${possibles}; do + if test -r "$i/"tcl.h""; then + ecos_tcl_incdir=$i + break + fi + done + + 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 + possibles="${with_tcl_lib} ${with_tcl}/lib ${libdir} ${prefix}/lib /usr/lib/tcl$${ecos_tcl_version} /usr/lib" + + ecos_tcl_libdir="" + for i in ${possibles}; do + if test -r "$i/"tclConfig.sh""; then + ecos_tcl_libdir=$i + break + fi + done + + if test \! -r "${ecos_tcl_libdir}/tclConfig.sh" ; then + { echo "configure: error: unable to locate Tcl config file tclConfig.sh" 1>&2; exit 1; } + else + . ${ecos_tcl_libdir}/tclConfig.sh + ecos_LIBS="${ecos_LIBS} -ltcl${ecos_tcl_version} ${TCL_LIBS}" + fi + + if test \! -r "${ecos_tcl_libdir}/tkConfig.sh" ; then + { echo "configure: error: unable to locate Tk config file tkConfig.sh" 1>&2; exit 1; } + else + . ${ecos_tcl_libdir}/tkConfig.sh + ecos_tk_libs="-ltk${ecos_tcl_version} ${TK_LIBS}" + for lib in ${TCL_LIBS} ; do + ecos_tk_libs=`echo ${ecos_tk_libs} | sed -e "s!${lib}!!"` + done + fi + fi + + echo "$ac_t""-I${ecos_tcl_incdir} -L${ecos_tcl_libdir}" 1>&6 + + + + if test "${TK_MAJOR_VERSION}" = "8" ; then + if test ${TK_MINOR_VERSION} -lt 2 ; then + { echo "configure: error: The USB testing support requires at least version 8.2 of Tcl/Tk" 1>&2; exit 1; } + fi + fi + + + 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}/../../../.. ${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 + repository_root=`cd "${repository_root}/packages" && /bin/pwd` + package_dir=`echo ${package_dir} | sed -e "s:${repository_root}/::"` + + PACKAGE_NAME=`echo ${package_dir} | sed -e "s:/:_:g"` + + + +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 <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/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 <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > 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%@SUPPORTED_TRUE@%$SUPPORTED_TRUE%g +s%@SUPPORTED_FALSE@%$SUPPORTED_FALSE%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_tk_libs@%$ecos_tk_libs%g +s%@PACKAGE_VERSION@%$PACKAGE_VERSION%g +s%@PACKAGE_NAME@%$PACKAGE_NAME%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 <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile:Makefile.in"} +EOF +cat >> $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 <<EOF + +EOF +cat >> $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 +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/configure.in @@ -0,0 +1,101 @@ +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 +AM_CONDITIONAL(SUPPORTED, test "${SUPPORTED}" = "yes") + +if test "${SUPPORTED}" = "yes" ; then + AC_PROG_CC + AC_PROG_CXX + AC_PROG_LN_S + AC_OBJEXT + AC_EXEEXT + ECOS_PROG_MSVC + ECOS_PROG_STANDARD_COMPILER_FLAGS + + 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_ERROR([The USB testing support requires at least version 8.2 of Tcl/Tk]) + fi + fi + ECOS_PACKAGE_NAME_AND_VERSION +fi + +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)
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/list.tcl @@ -0,0 +1,130 @@ +# {{{ 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)" + } + } +}
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/usbchmod.c @@ -0,0 +1,180 @@ +//================================================================= +// +// 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 <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +// 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 <bus> <dev>\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; +}
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/usbhost.c @@ -0,0 +1,1896 @@ +/*{{{ 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <time.h> +#include <pthread.h> +#include <semaphore.h> +#include <tcl.h> +#include <linux/usb.h> +#include <linux/usbdevice_fs.h> +#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/<abc>/<def> entries. <abc> is a bus number, +// typically 001 or 001, and <def> is a device number on that bus, +// e.g. 003. Figuring out <abc> and <def> 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=<abc> ... Dev#= <def> ... +// +// 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 <message>\"", 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 <message>\"", 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 <message>\"", 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 <message>\"", 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 <message>\"", 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" : "<invalid>"); + VERBOSE(3, " Data format %s, data1 %d, data* %d, data+ %d, data1* %d, data1+ %d, data** %d, data*+ %d, data+* %d, data++ %d\n",\ + (usbtestdata_none == test->test_params.bulk.data.format) ? "none" : \ + (usbtestdata_bytefill == test->test_params.bulk.data.format) ? "bytefill" : \ + (usbtestdata_wordfill == test->test_params.bulk.data.format) ? "wordfill" : \ + (usbtestdata_byteseq == test->test_params.bulk.data.format) ? "byteseq" : \ + (usbtestdata_wordseq == test->test_params.bulk.data.format) ? "wordseq" : "<invalid>", \ + test->test_params.bulk.data.seed, \ + test->test_params.bulk.data.multiplier, \ + test->test_params.bulk.data.increment, \ + test->test_params.bulk.data.transfer_seed_multiplier, \ + test->test_params.bulk.data.transfer_seed_increment, \ + test->test_params.bulk.data.transfer_multiplier_multiplier, \ + test->test_params.bulk.data.transfer_multiplier_increment, \ + test->test_params.bulk.data.transfer_increment_multiplier, \ + test->test_params.bulk.data.transfer_increment_increment); + VERBOSE(3, " txsize1 %d, txsize>= %d, txsize<= %d, txsize* %d, txsize/ %d, txsize+ %d\n", \ + test->test_params.bulk.tx_size, test->test_params.bulk.tx_size_min, \ + test->test_params.bulk.tx_size_max, test->test_params.bulk.tx_size_multiplier, \ + test->test_params.bulk.tx_size_divisor, test->test_params.bulk.tx_size_increment); + VERBOSE(3, " rxsize1 %d, rxsize>= %d, rxsize<= %d, rxsize* %d, rxsize/ %d, rxsize+ %d\n", \ + test->test_params.bulk.rx_size, test->test_params.bulk.rx_size_min, \ + test->test_params.bulk.rx_size_max, test->test_params.bulk.rx_size_multiplier, \ + test->test_params.bulk.rx_size_divisor, test->test_params.bulk.rx_size_increment); + VERBOSE(3, " txdelay1 %d, txdelay>= %d, txdelay<= %d, txdelay* %d, txdelay/ %d, txdelay+ %d\n", \ + test->test_params.bulk.tx_delay, test->test_params.bulk.tx_delay_min, \ + test->test_params.bulk.tx_delay_max, test->test_params.bulk.tx_delay_multiplier, \ + test->test_params.bulk.tx_delay_divisor, test->test_params.bulk.tx_delay_increment); + VERBOSE(3, " rxdelay1 %d, rxdelay>= %d, rxdelay<= %d, rxdelay* %d, rxdelay/ %d, rxdelay+ %d\n", \ + test->test_params.bulk.rx_delay, test->test_params.bulk.rx_delay_min, \ + test->test_params.bulk.rx_delay_max, test->test_params.bulk.rx_delay_multiplier, \ + test->test_params.bulk.rx_delay_divisor, test->test_params.bulk.rx_delay_increment); + + + // 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 <message>\"", 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 <timeout>\"", 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 <level>\"", 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 <level>\"", 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] <test> [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(" <test> 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; +} + +/*}}}*/
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/usbhost.tcl @@ -0,0 +1,531 @@ +# {{{ 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 +} + +# }}}
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/host/verbose.tcl @@ -0,0 +1,71 @@ +# {{{ 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 +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/tests/common.c @@ -0,0 +1,681 @@ +/*{{{ 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; +} + +/*}}}*/
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/tests/protocol.h @@ -0,0 +1,194 @@ +//================================================================= +// +// 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 +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/slave/current/tests/usbtarget.c @@ -0,0 +1,1848 @@ +/*{{{ Banner */ + +/*================================================================= +// +// target.c +// +// USB testing - target-side +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// This program performs appropriate USB initialization and initializes +// itself as a specific type of USB peripheral, Red Hat eCos testing. +// There is no actual host-side device driver for this, instead there is +// a test application which performs ioctl's on /proc/bus/usb/... and +// makes appropriate functionality available to a Tcl script. +// +// Author(s): bartv +// Date: 2001-07-04 +//####DESCRIPTIONEND#### +//========================================================================== +*/ + +/*}}}*/ +/*{{{ #include's */ + +#include <stdio.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> +#include <cyg/kernel/kapi.h> +#include <cyg/hal/hal_arch.h> +#include <cyg/io/io.h> +#include <cyg/io/usb/usbs.h> +#include <cyg/infra/testcase.h> +#include "protocol.h" + +/*}}}*/ + +/*{{{ Statics */ + +// ---------------------------------------------------------------------------- +// Statics. + +// The number of endpoints supported by the device driver. +static int number_endpoints = 0; + +// The control 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" : "<invalid>"); + VERBOSE(3, " Data format %s, data1 %d, data* %d, data+ %d, data1* %d, data1+ %d, data** %d, data*+ %d, data+* %d, data++ %d\n",\ + (usbtestdata_none == test->test_params.bulk.data.format) ? "none" : \ + (usbtestdata_bytefill == test->test_params.bulk.data.format) ? "bytefill" : \ + (usbtestdata_wordfill == test->test_params.bulk.data.format) ? "wordfill" : \ + (usbtestdata_byteseq == test->test_params.bulk.data.format) ? "byteseq" : \ + (usbtestdata_wordseq == test->test_params.bulk.data.format) ? "wordseq" : "<invalid>", \ + test->test_params.bulk.data.seed, \ + test->test_params.bulk.data.multiplier, \ + test->test_params.bulk.data.increment, \ + test->test_params.bulk.data.transfer_seed_multiplier, \ + test->test_params.bulk.data.transfer_seed_increment, \ + test->test_params.bulk.data.transfer_multiplier_multiplier, \ + test->test_params.bulk.data.transfer_multiplier_increment, \ + test->test_params.bulk.data.transfer_increment_multiplier, \ + test->test_params.bulk.data.transfer_increment_increment); + VERBOSE(3, " txsize1 %d, txsize>= %d, txsize<= %d, txsize* %d, txsize/ %d, txsize+ %d\n", \ + test->test_params.bulk.tx_size, test->test_params.bulk.tx_size_min, \ + test->test_params.bulk.tx_size_max, test->test_params.bulk.tx_size_multiplier, \ + test->test_params.bulk.tx_size_divisor, test->test_params.bulk.tx_size_increment); + VERBOSE(3, " rxsize1 %d, rxsize>= %d, rxsize<= %d, rxsize* %d, rxsize/ %d, rxsize+ %d\n", \ + test->test_params.bulk.rx_size, test->test_params.bulk.rx_size_min, \ + test->test_params.bulk.rx_size_max, test->test_params.bulk.rx_size_multiplier, \ + test->test_params.bulk.rx_size_divisor, test->test_params.bulk.rx_size_increment); + VERBOSE(3, " txdelay1 %d, txdelay>= %d, txdelay<= %d, txdelay* %d, txdelay/ %d, txdelay+ %d\n", \ + test->test_params.bulk.tx_delay, test->test_params.bulk.tx_delay_min, \ + test->test_params.bulk.tx_delay_max, test->test_params.bulk.tx_delay_multiplier, \ + test->test_params.bulk.tx_delay_divisor, test->test_params.bulk.tx_delay_increment); + VERBOSE(3, " rxdelay1 %d, rxdelay>= %d, rxdelay<= %d, rxdelay* %d, rxdelay/ %d, rxdelay+ %d\n", \ + test->test_params.bulk.rx_delay, test->test_params.bulk.rx_delay_min, \ + test->test_params.bulk.rx_delay_max, test->test_params.bulk.rx_delay_multiplier, \ + test->test_params.bulk.rx_delay_divisor, test->test_params.bulk.rx_delay_increment); + + return USBS_CONTROL_RETURN_HANDLED; +} + +/*}}}*/ +/*{{{ run_test_bulk_out() */ + +// The same callback can be used for IN and OUT transfers. Note that +// starting the next transfer is left to the thread, it is not done +// at DSR level. +static void +run_test_bulk_in_out_callback(void* callback_arg, int transferred) +{ + UsbTest* test = (UsbTest*) callback_arg; + test->transferred = transferred; + cyg_semaphore_post(&(test->sem)); +} + +// OUT transfers, i.e. the host will be sending some number of +// packets. The I/O can happen in a number of different ways, e.g. via +// the low-level USB API or via devtab routines. +static void +run_test_bulk_out(UsbTest* test) +{ + unsigned char* buf; + int endpoint_number = test->test_params.bulk.endpoint & ~USB_DEVREQ_DIRECTION_MASK; + int ep_index; + usbs_rx_endpoint* endpoint = 0; + cyg_io_handle_t io_handle = (cyg_io_handle_t)0; + int alignment; + int transferred; + int i; + + VERBOSE(1, "Starting test %d, bulk out on endpoint %d\n", test->id, endpoint_number); + + ep_index = lookup_endpoint(endpoint_number, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT, USB_ENDPOINT_DESCRIPTOR_ATTR_BULK); + if (ep_index == -1) { + test->result_pass = 0; + snprintf(test->result_message, USBTEST_MAX_MESSAGE, + "Target, bulk OUT transfer on endpoint %d: no such bulk endpoint", endpoint_number); + return; + } + endpoint = (usbs_rx_endpoint*) usbs_testing_endpoints[ep_index].endpoint; + alignment = usbs_testing_endpoints[ep_index].alignment; + if (0 != alignment) { + buf = (unsigned char*) ((((cyg_uint32)test->buffer) + alignment - 1) & ~(alignment - 1)); + } else { + buf = test->buffer; + } + + 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; + } +} + +/*}}}*/
--- a/packages/redboot/current/ChangeLog +++ b/packages/redboot/current/ChangeLog @@ -1,3 +1,8 @@ +2002-05-31 Jesper Skov <jskov@redhat.com> + + * doc/redboot_installing.sgml: Updated the remaining installation + instructions (well, the top mode details anyway). + 2002-05-29 Jesper Skov <jskov@redhat.com> * doc/redboot_cmds.sgml: Changed format of fis commands.
--- a/packages/redboot/current/doc/redboot_installing.sgml +++ b/packages/redboot/current/doc/redboot_installing.sgml @@ -4584,13 +4584,34 @@ description of the associated modes.</pa and testing</secondary></indexterm><indexterm><primary>installing and testing </primary><secondary>Analogue & Micro PowerPC 860T</secondary></indexterm>RedBoot uses the SMC1 serial port. The default serial port settings are 38400,8,N,1. -Ethernet is also supported using the RJ-45 connector. </para> -<para>Management of onboard flash is also supported. -A single RedBoot configuration is supported: <itemizedlist> -<listitem><para>RedBoot running from RAM using an image copied from the flash boot sector (ROMRAM mode). +Ethernet is also supported using the RJ-45 connector. Management of +onboard flash is also supported.</para> + +<para>The following RedBoot configurations are supported: + + <informaltable frame="all"> + <tgroup cols="4" colsep="1" rowsep="1" align="left"> + <thead> + <row> + <entry>Configuration</entry> + <entry>Mode</entry> + <entry>Description</entry> + <entry>File</entry> + </row> + </thead> + <tbody> + <row> + <entry>ROMRAM</entry> + <entry>[ROMRAM]</entry> + <entry>RedBoot running from RAM, but contained in the + board's flash boot sector.</entry> + <entry>redboot_ROMRAM.ecm</entry> + </row> +</tbody> +</tgroup> +</informaltable> </para> -</listitem> -</itemizedlist></para> + </sect2> <sect2> <title>Initial Installation Method </title> @@ -4639,19 +4660,45 @@ and testing</secondary></indexterm><inde </primary><secondary>Motorola PowerPC MBX</secondary></indexterm>RedBoot uses the SMC1/COM1 serial port. The default serial port settings are 38400,8,N,1. Ethernet is also supported using the 10-base T connector. </para> -<para>Management of onboard flash is also supported. Two basic RedBoot configurations -are supported: <itemizedlist> -<listitem><para>RedBoot running from RAM with RedBoot in the flash boot sector. +<para>Management of onboard flash is also supported.</para> + +<para>The following RedBoot configurations are supported: + + <informaltable frame="all"> + <tgroup cols="4" colsep="1" rowsep="1" align="left"> + <thead> + <row> + <entry>Configuration</entry> + <entry>Mode</entry> + <entry>Description</entry> + <entry>File</entry> + </row> + </thead> + <tbody> + <row> + <entry>ROM</entry> + <entry>[ROM]</entry> + <entry>RedBoot running from the board's flash boot + sector.</entry> + <entry>redboot_ROM.ecm</entry> + </row> + <row> + <entry>RAM</entry> + <entry>[RAM]</entry> + <entry>RedBoot running from RAM with RedBoot in the + flash boot sector.</entry> + <entry>redboot_RAM.ecm</entry> + </row> +</tbody> +</tgroup> +</informaltable> </para> -</listitem> -<listitem><para>RedBoot running from the board's flash boot sector. </para> -</listitem> -</itemizedlist></para> + </sect2> <sect2> <title>Initial Installation Method </title> <para>Device programmer is used to program the XU1 socketed flash part (AM29F040B) -with the ROM version of RedBoot. - Use the on-board EPPC-Bug monitor to update +with the ROM mode image of RedBoot. Use the on-board EPPC-Bug monitor to update RedBoot. </para> <para>This assumes that you have EPPC-Bug in the on-board flash. This can be determined by setting up the board according to the following instructions @@ -4666,33 +4713,27 @@ 8N1. </para> </orderedlist> <para>If it is available, program the flash by following these steps: </para> <orderedlist> -<listitem><para>Prepare EPPC-Bug for download: <screen>EPPC-Bug>lo 0 +<listitem><para>Prepare EPPC-Bug for download: <screen>EPPC-Bug><userinput>lo 0</userinput> </screen>At this point the monitor is ready for input. It will not return the prompt until the file has been downloaded. </para> </listitem> <listitem><para>Use the terminal emulator's ASCII download feature (or a simple -clipboard copy/paste operation) to download the redboot.ppcbug file.</para> -<para>Note that on Linux, Minicom's ASCII download feature seems to be broken. -A workaround is to load the file into emacs (or another editor) and copy the +clipboard copy/paste operation) to download the +<filename>redboot.ppcbug</filename> file.</para> +<para>Note that on Linux, <application>Minicom</application>'s ASCII +download feature seems to be broken. A workaround is to load the file +into <application>emacs</application> (or another editor) and copy the full contents to the clipboard. Then press the mouse paste-button (usually -the middle one) over the Minicom window. </para> +the middle one) over the <application>Minicom</application> window. </para> </listitem> <listitem><para>Program the flash with the downloaded data: <screen> -EPPC-Bug>pflash 40000 60000 fc000000</screen></para> +EPPC-Bug><userinput>pflash 40000 60000 fc000000</userinput></screen></para> </listitem> <listitem><para>Switch off the power, and change jumper 4 to 1-2. Turn on the power again. The board should now boot using the newly programmed RedBoot. </para> </listitem> </orderedlist> -<para>To install RedBoot on a target that already has eCos GDB stubs, download -the RAM version of RedBoot and run it. Initialize the flash image directory: <screen> -RedBoot> fi init</screen>Then download the ROM version of RedBoot -and program it into flash: -<screen> -RedBoot> <userinput>load redboot_ROM.srec -b 0x80100000</userinput> -RedBoot> <userinput>fi cr RedBoot -f 0xFE000000 -b 0x00040000 -l 0x20000</userinput> -</screen></para> </sect2> <sect2> <title>Special RedBoot Commands </title> @@ -4743,14 +4784,40 @@ description of the associated modes.</pa and testing</secondary></indexterm><indexterm><primary>installing and testing </primary><secondary>Hitachi SH EDK7708</secondary></indexterm>RedBoot uses the serial port. The default serial port settings are 38400,8,N,1.</para> -<para>Management of onboard flash is also supported. Two basic RedBoot configurations -are supported: <itemizedlist> -<listitem><para>RedBoot running from RAM with RedBoot in the flash boot sector. +<para>Management of onboard flash is also supported.</para> + +<para>The following RedBoot configurations are supported: + + <informaltable frame="all"> + <tgroup cols="4" colsep="1" rowsep="1" align="left"> + <thead> + <row> + <entry>Configuration</entry> + <entry>Mode</entry> + <entry>Description</entry> + <entry>File</entry> + </row> + </thead> + <tbody> + <row> + <entry>ROM</entry> + <entry>[ROM]</entry> + <entry>RedBoot running from the board's flash boot + sector.</entry> + <entry>redboot_ROM.ecm</entry> + </row> + <row> + <entry>RAM</entry> + <entry>[RAM]</entry> + <entry>RedBoot running from RAM with RedBoot in the + flash boot sector.</entry> + <entry>redboot_RAM.ecm</entry> + </row> +</tbody> +</tgroup> +</informaltable> </para> -</listitem> -<listitem><para>RedBoot running from the board's flash boot sector. </para> -</listitem> -</itemizedlist></para> + </sect2> <sect2> <title>Initial Installation Method </title> @@ -4802,14 +4869,40 @@ for instructions for the MS7729SE01 and <para>RedBoot uses the COM1 and COM2 serial ports. The default serial port settings are 38400,8,N,1. Ethernet is also supported using the 10-base T connector. </para> -<para>Management of onboard flash is also supported. Two basic RedBoot configurations -are supported: <itemizedlist> -<listitem><para>RedBoot running from RAM with RedBoot in the flash boot sector. +<para>Management of onboard flash is also supported.</para> + +<para>The following RedBoot configurations are supported: + + <informaltable frame="all"> + <tgroup cols="4" colsep="1" rowsep="1" align="left"> + <thead> + <row> + <entry>Configuration</entry> + <entry>Mode</entry> + <entry>Description</entry> + <entry>File</entry> + </row> + </thead> + <tbody> + <row> + <entry>ROM</entry> + <entry>[ROM]</entry> + <entry>RedBoot running from the board's flash boot + sector.</entry> + <entry>redboot_ROM.ecm</entry> + </row> + <row> + <entry>RAM</entry> + <entry>[RAM]</entry> + <entry>RedBoot running from RAM with RedBoot in the + flash boot sector.</entry> + <entry>redboot_RAM.ecm</entry> + </row> +</tbody> +</tgroup> +</informaltable> </para> -</listitem> -<listitem><para>RedBoot running from the board's flash boot sector. </para> -</listitem> -</itemizedlist></para> + </sect2> <sect2> <title>Initial Installation Method </title> @@ -4822,13 +4915,14 @@ which allows for initial programming of <listitem><para>Connect a serial cable to CN1 (SCI) and power up the board.</para> </listitem> <listitem><para>After the boot monitor banner, invoke the flash -download/program command:<screen>Ready >fl</screen></para> +download/program command:<screen>Ready ><userinput>fl</userinput></screen></para> </listitem> <listitem><para>The monitor should now ask for input: <screen>Flash ROM data copy to RAM Please Send A S-format Record</screen>At this point copy the RedBoot ROM SREC file to the serial port:<screen> -$ cat redboot_SE7709RP_ROM.eprom.srec > /dev/ttyS0</screen>Eventually you +$ <userinput>cat redboot_SE7709RP_ROM.eprom.srec > /dev/ttyS0</userinput></screen> +Eventually you should see something like<screen>Start Addrs = A1000000 End Addrs = A1xxxxxx Transfer complete</screen> from the monitor. @@ -4940,28 +5034,59 @@ and testing</secondary></indexterm><inde the COM1 and COM2 serial ports (and the debug port on the motherboard). The default serial port settings are 38400,8,N,1. -Ethernet is also supported using a D-Link DFE-530TX PCI plugin card.</para> -<para>Management of onboard flash is also supported. Two basic RedBoot configurations -are supported: <itemizedlist> -<listitem><para>RedBoot running from RAM with RedBoot in the flash boot sector. +Ethernet is also supported using a D-Link DFE-530TX PCI plugin +card. Management of onboard flash is also supported. </para> + +<para>The following RedBoot configurations are supported: + + <informaltable frame="all"> + <tgroup cols="4" colsep="1" rowsep="1" align="left"> + <thead> + <row> + <entry>Configuration</entry> + <entry>Mode</entry> + <entry>Description</entry> + <entry>File</entry> + </row> + </thead> + <tbody> + <row> + <entry>ROM</entry> + <entry>[ROM]</entry> + <entry>RedBoot running from the board's flash boot + sector.</entry> + <entry>redboot_ROM.ecm</entry> + </row> + <row> + <entry>RAM</entry> + <entry>[RAM]</entry> + <entry>RedBoot running from RAM with RedBoot in the + flash boot sector.</entry> + <entry>redboot_RAM.ecm</entry> + </row> +</tbody> +</tgroup> +</informaltable> </para> -</listitem> -<listitem><para>RedBoot running from the board's flash boot sector. </para> -</listitem> -</itemizedlist></para> + + </sect2> <sect2> <title>Initial Installation Method </title> -<para>A copy of the ROM startup version of RedBoot must be programmed -into the two EPROMs. Two files with a split version of the ROM image is -provided: it is also possible to recreate these from the redboot.bin -file, but requires the split_word.c program in -hal/sh/hs7729pci/<replaceable>VERSION</replaceable>/misc to be built -and executed with the redboot.bin filename as sole argument.</para> - -<para>After doing this it is advised that another ROM version of -RedBoot is programmed into the flash, and that copy be used for -booting the board. This allows for software programmed updates of +<para>A ROM mode RedBoot image must be programmed +into the two EPROMs. Two files with a split version of the ROM mode +image is +provided: it is also possible to recreate these from the +<filename>redboot.bin</filename> +file, but requires the <application>split_word.c</application> program in +<filename +class="directory">hal/sh/hs7729pci/<replaceable>VERSION</replaceable>/misc</filename> +to be built and executed with the <filename>redboot.bin</filename> +filename as sole argument.</para> + +<para>After doing this it is advised that another ROM mode image of +RedBoot is programmed into the on-board flash, and that copy be used +for booting the board. This allows for software programmed updates of RedBoot instead of having to reprogram the EPROMs.</para> <orderedlist> @@ -4972,8 +5097,9 @@ go in socket M1 and the .hi image in soc <listitem><para>Set switch SW1-6 to ON [boot from EPROM]</para> </listitem> <listitem><para>Follow the instructions under Flash management for -updating the flash copy of RedBoot, but use -<screen>-f 0x80400000</screen> due to setting of +updating the flash copy of RedBoot, but force the flash destination +address with +<screen><userinput>-f 0x80400000</userinput></screen> due to setting of the SW1-6 switch.</para> </listitem> <listitem><para>Set switch SW1-6 to OFF [boot from flash] and reboot the board. You @@ -5085,15 +5211,41 @@ for instructions for the MS7709SE01 vari <para>RedBoot uses the COM1 and COM2 serial ports. The default serial port settings are 38400,8,N,1. -Ethernet is also supported using the 10-base T connector. </para> -<para>Management of onboard flash is also supported. Two basic RedBoot configurations -are supported: <itemizedlist> -<listitem><para>RedBoot running from RAM with RedBoot in the flash boot sector. +Ethernet is also supported using the 10-base T connector. Management +of onboard flash is also supported.</para> + +<para>The following RedBoot configurations are supported: + + <informaltable frame="all"> + <tgroup cols="4" colsep="1" rowsep="1" align="left"> + <thead> + <row> + <entry>Configuration</entry> + <entry>Mode</entry> + <entry>Description</entry> + <entry>File</entry> + </row> + </thead> + <tbody> + <row> + <entry>ROM</entry> + <entry>[ROM]</entry> + <entry>RedBoot running from the board's flash boot + sector.</entry> + <entry>redboot_ROM.ecm</entry> + </row> + <row> + <entry>RAM</entry> + <entry>[RAM]</entry> + <entry>RedBoot running from RAM with RedBoot in the + flash boot sector.</entry> + <entry>redboot_RAM.ecm</entry> + </row> +</tbody> +</tgroup> +</informaltable> </para> -</listitem> -<listitem><para>RedBoot running from the board's flash boot sector. </para> -</listitem> -</itemizedlist></para> + </sect2> <sect2> <title>Initial Installation Method </title> @@ -5106,13 +5258,14 @@ which allows for initial programming of <listitem><para>Connect a serial cable to COM2 and power up the board.</para> </listitem> <listitem><para>After the boot monitor banner, invoke the flash -download/program command:<screen>Ready >fl</screen></para> +download/program command:<screen>Ready ><userinput>fl</userinput></screen></para> </listitem> <listitem><para>The monitor should now ask for input: <screen>Flash ROM data copy to RAM Please Send A S-format Record</screen>At this point copy the RedBoot ROM SREC file to the serial port:<screen> -$ cat redboot_ROM.eprom.srec > /dev/ttyS0</screen>Eventually you +$ <userinput>cat redboot_ROM.eprom.srec > /dev/ttyS0</userinput></screen> +Eventually you should see something like<screen>Start Addrs = A1000000 End Addrs = A1xxxxxx Transfer complete</screen> from the monitor. @@ -5218,15 +5371,41 @@ description of the associated modes.</pa and testing</secondary></indexterm><indexterm><primary>installing and testing </primary><secondary>Hitachi SH SE7751</secondary></indexterm>RedBoot uses the COM1 serial port. The default serial port settings are 38400,8,N,1. -Ethernet is also supported using the 10-base T connector. </para> -<para>Management of onboard flash is also supported. Two basic RedBoot configurations -are supported: <itemizedlist> -<listitem><para>RedBoot running from RAM with RedBoot in the flash boot sector. +Ethernet is also supported using the 10-base T connector. Management +of onboard flash is also supported.</para> + +<para>The following RedBoot configurations are supported: + + <informaltable frame="all"> + <tgroup cols="4" colsep="1" rowsep="1" align="left"> + <thead> + <row> + <entry>Configuration</entry> + <entry>Mode</entry> + <entry>Description</entry> + <entry>File</entry> + </row> + </thead> + <tbody> + <row> + <entry>ROM</entry> + <entry>[ROM]</entry> + <entry>RedBoot running from the board's flash boot + sector.</entry> + <entry>redboot_ROM.ecm</entry> + </row> + <row> + <entry>RAM</entry> + <entry>[RAM]</entry> + <entry>RedBoot running from RAM with RedBoot in the + flash boot sector.</entry> + <entry>redboot_RAM.ecm</entry> + </row> +</tbody> +</tgroup> +</informaltable> </para> -</listitem> -<listitem><para>RedBoot running from the board's flash boot sector. </para> -</listitem> -</itemizedlist></para> + </sect2> <sect2> <title>Initial Installation Method </title> @@ -5239,13 +5418,14 @@ which allows for initial programming of <listitem><para>Connect a serial cable to COM1 and power up the board.</para> </listitem> <listitem><para>After the boot monitor banner, invoke the flash -download/program command:<screen>Ready >fl</screen></para> +download/program command:<screen>Ready ><userinput>fl</userinput></screen></para> </listitem> <listitem><para>The monitor should now ask for input: <screen>Flash ROM data copy to RAM Please Send A S-format Record</screen>At this point copy the RedBoot ROM SREC file to the serial port:<screen> -$ cat redboot_ROM.eprom.srec > /dev/ttyS0</screen>Eventually you +$ <userinput>cat redboot_ROM.eprom.srec > /dev/ttyS0</userinput></screen> +Eventually you should see something like<screen>Start Addrs = A1000000 End Addrs = A1xxxxxx Transfer complete</screen> from the monitor.
