From 5f3f6bfc3626a4332fd849da1c87316f7360d56c Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Fri, 22 Sep 2006 23:33:23 +0100 Subject: [PATCH 1/1] tclusb: initial version listing devices and support opening a device Signed-off-by: Pat Thoyts --- Makefile.in | 437 ++++++++++++++++++++++++++++++++++++++++++++++++ aclocal.m4 | 9 + configure.in | 187 +++++++++++++++++++++ pkgIndex.tcl.in | 1 + tclusb.c | 242 +++++++++++++++++++++++++++ 5 files changed, 876 insertions(+) create mode 100644 Makefile.in create mode 100644 aclocal.m4 create mode 100644 configure.in create mode 100644 pkgIndex.tcl.in create mode 100644 tclusb.c diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..788c1cf --- /dev/null +++ b/Makefile.in @@ -0,0 +1,437 @@ +# Makefile.in -- +# +# This file is a Makefile for Sample TEA Extension. If it has the name +# "Makefile.in" then it is a template for a Makefile; to generate the +# actual Makefile, run "./configure", which is a configuration script +# generated by the "autoconf" program (constructs like "@foo@" will get +# replaced in the actual Makefile. +# +# Copyright (c) 1999 Scriptics Corporation. +# Copyright (c) 2002-2005 ActiveState Corporation. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: Makefile.in,v 1.61 2006/07/20 07:42:37 das Exp $ + +#======================================================================== +# Add additional lines to handle any additional AC_SUBST cases that +# have been added in a customized configure script. +#======================================================================== + +#SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ + +#======================================================================== +# Nothing of the variables below this line should need to be changed. +# Please check the TARGETS section below to make sure the make targets +# are correct. +#======================================================================== + +#======================================================================== +# The names of the source files is defined in the configure script. +# The object files are used for linking into the final library. +# This will be used when a dist target is added to the Makefile. +# It is not important to specify the directory, as long as it is the +# $(srcdir) or in the generic, win or unix subdirectory. +#======================================================================== + +PKG_SOURCES = @PKG_SOURCES@ +PKG_OBJECTS = @PKG_OBJECTS@ + +PKG_STUB_SOURCES = @PKG_STUB_SOURCES@ +PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@ + +#======================================================================== +# PKG_TCL_SOURCES identifies Tcl runtime files that are associated with +# this package that need to be installed, if any. +#======================================================================== + +PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ + +#======================================================================== +# This is a list of public header files to be installed, if any. +#======================================================================== + +PKG_HEADERS = @PKG_HEADERS@ + +#======================================================================== +# "PKG_LIB_FILE" refers to the library (dynamic or static as per +# configuration options) composed of the named objects. +#======================================================================== + +PKG_LIB_FILE = @PKG_LIB_FILE@ +PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ + +lib_BINARIES = $(PKG_LIB_FILE) +BINARIES = $(lib_BINARIES) + +SHELL = @SHELL@ + +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +libdir = @libdir@ +datadir = @datadir@ +mandir = @mandir@ +includedir = @includedir@ + +DESTDIR = + +PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) +pkgdatadir = $(datadir)/$(PKG_DIR) +pkglibdir = $(libdir)/$(PKG_DIR) +pkgincludedir = $(includedir)/$(PKG_DIR) + +top_builddir = . + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ + +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +CC = @CC@ +CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ +CFLAGS_WARNING = @CFLAGS_WARNING@ +CLEANFILES = @CLEANFILES@ +EXEEXT = @EXEEXT@ +LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ +MAKE_LIB = @MAKE_LIB@ +MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ +MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ +MAKE_STUB_LIB = @MAKE_STUB_LIB@ +OBJEXT = @OBJEXT@ +RANLIB = @RANLIB@ +RANLIB_STUB = @RANLIB_STUB@ +SHLIB_CFLAGS = @SHLIB_CFLAGS@ +SHLIB_LD = @SHLIB_LD@ +SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ +STLIB_LD = @STLIB_LD@ +#TCL_DEFS = @TCL_DEFS@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +#TK_BIN_DIR = @TK_BIN_DIR@ +#TK_SRC_DIR = @TK_SRC_DIR@ + +# Not used, but retained for reference of what libs Tcl required +#TCL_LIBS = @TCL_LIBS@ + +#======================================================================== +# TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our +# package without installing. The other environment variables allow us +# to test against an uninstalled Tcl. Add special env vars that you +# require for testing here (like TCLX_LIBRARY). +#======================================================================== + +EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) +#EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) +TCLLIBPATH = $(top_builddir) +TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ + @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ + PATH="$(EXTRA_PATH):$(PATH)" \ + TCLLIBPATH="$(TCLLIBPATH)" +# TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` + +TCLSH_PROG = @TCLSH_PROG@ +TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) + +#WISH_PROG = @WISH_PROG@ +#WISH = $(TCLSH_ENV) $(WISH_PROG) + + +SHARED_BUILD = @SHARED_BUILD@ + +INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ +#INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ + +PKG_CFLAGS = @PKG_CFLAGS@ + +# TCL_DEFS is not strictly need here, but if you remove it, then you +# must make sure that configure.in checks for the necessary components +# that your library may use. TCL_DEFS can actually be a problem if +# you do not compile with a similar machine setup as the Tcl core was +# compiled with. +#DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) +DEFS = @DEFS@ $(PKG_CFLAGS) + +CONFIG_CLEAN_FILES = Makefile + +CPPFLAGS = @CPPFLAGS@ +LIBS = @PKG_LIBS@ @LIBS@ +AR = @AR@ +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) + +#======================================================================== +# Start of user-definable TARGETS section +#======================================================================== + +#======================================================================== +# TEA TARGETS. Please note that the "libraries:" target refers to platform +# independent files, and the "binaries:" target inclues executable programs and +# platform-dependent libraries. Modify these targets so that they install +# the various pieces of your package. The make and install rules +# for the BINARIES that you specified above have already been done. +#======================================================================== + +all: binaries libraries doc + +#======================================================================== +# The binaries target builds executable programs, Windows .dll's, unix +# shared/static libraries, and any other platform-dependent files. +# The list of targets to build for "binaries:" is specified at the top +# of the Makefile, in the "BINARIES" variable. +#======================================================================== + +binaries: $(BINARIES) + +libraries: + + +#======================================================================== +# Your doc target should differentiate from doc builds (by the developer) +# and doc installs (see install-doc), which just install the docs on the +# end user machine when building from source. +#======================================================================== + +doc: + @echo "If you have documentation to create, place the commands to" + @echo "build the docs in the 'doc:' target. For example:" + @echo " xml2nroff sample.xml > sample.n" + @echo " xml2html sample.xml > sample.html" + +install: all install-binaries install-libraries install-doc + +install-binaries: binaries install-lib-binaries install-bin-binaries + +#======================================================================== +# This rule installs platform-independent files, such as header files. +# The list=...; for p in $$list handles the empty list case x-platform. +#======================================================================== + +install-libraries: libraries + @mkdir -p $(DESTDIR)$(includedir) + @echo "Installing header files in $(DESTDIR)$(includedir)" + @list='$(PKG_HEADERS)'; for i in $$list; do \ + echo "Installing $(srcdir)/$$i" ; \ + $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ + done; + +#======================================================================== +# Install documentation. Unix manpages should go in the $(mandir) +# directory. +#======================================================================== + +install-doc: doc + @mkdir -p $(DESTDIR)$(mandir)/mann + @echo "Installing documentation in $(DESTDIR)$(mandir)" + @list='$(srcdir)/doc/*.n'; for i in $$list; do \ + echo "Installing $$i"; \ + rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ + done + +test: binaries libraries + $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) + +shell: binaries libraries + @$(TCLSH) $(SCRIPT) + +gdb: + $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) + +depend: + +#======================================================================== +# $(PKG_LIB_FILE) should be listed as part of the BINARIES variable +# mentioned above. That will ensure that this target is built when you +# run "make binaries". +# +# The $(PKG_OBJECTS) objects are created and linked into the final +# library. In most cases these object files will correspond to the +# source files above. +#======================================================================== + +$(PKG_LIB_FILE): $(PKG_OBJECTS) + -rm -f $(PKG_LIB_FILE) + ${MAKE_LIB} + $(RANLIB) $(PKG_LIB_FILE) + +$(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) + -rm -f $(PKG_STUB_LIB_FILE) + ${MAKE_STUB_LIB} + $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) + +#======================================================================== +# We need to enumerate the list of .c to .o lines here. +# +# In the following lines, $(srcdir) refers to the toplevel directory +# containing your extension. If your sources are in a subdirectory, +# you will have to modify the paths to reflect this: +# +# sample.$(OBJEXT): $(srcdir)/generic/sample.c +# $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ +# +# Setting the VPATH variable to a list of paths will cause the makefile +# to look into these paths when resolving .c to .obj dependencies. +# As necessary, add $(srcdir):$(srcdir)/compat:.... +#======================================================================== + +VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win + +.c.@OBJEXT@: + $(COMPILE) -c `@CYGPATH@ $<` -o $@ + +#======================================================================== +# Distribution creation +# You may need to tweak this target to make it work correctly. +#======================================================================== + +#COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar +COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) +DIST_ROOT = /tmp/dist +DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) + +dist-clean: + rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* + +dist: dist-clean + mkdir -p $(DIST_DIR) + cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \ + $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ + $(DIST_DIR)/ + chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 + chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in + + for i in $(srcdir)/*.[ch]; do \ + if [ -f $$i ]; then \ + cp -p $$i $(DIST_DIR)/ ; \ + fi; \ + done; + + mkdir $(DIST_DIR)/tclconfig + cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ + $(DIST_DIR)/tclconfig/ + chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 + chmod +x $(DIST_DIR)/tclconfig/install-sh + + list='demos doc generic library mac tests unix win'; \ + for p in $$list; do \ + if test -d $(srcdir)/$$p ; then \ + mkdir $(DIST_DIR)/$$p; \ + cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ + fi; \ + done + + (cd $(DIST_ROOT); $(COMPRESS);) + +#======================================================================== +# End of user-definable section +#======================================================================== + +#======================================================================== +# Don't modify the file to clean here. Instead, set the "CLEANFILES" +# variable in configure.in +#======================================================================== + +clean: + -test -z "$(BINARIES)" || rm -f $(BINARIES) + -rm -f *.$(OBJEXT) core *.core + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean: clean + -rm -f *.tab.c + -rm -f $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log config.status + +#======================================================================== +# Install binary object libraries. On Windows this includes both .dll and +# .lib files. Because the .lib files are not explicitly listed anywhere, +# we need to deduce their existence from the .dll file of the same name. +# Library files go into the lib directory. +# In addition, this will generate the pkgIndex.tcl +# file in the install location (assuming it can find a usable tclsh shell) +# +# You should not have to modify this target. +#======================================================================== + +install-lib-binaries: binaries + @mkdir -p $(DESTDIR)$(pkglibdir) + @list='$(lib_BINARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ + stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ + if test "x$$stub" = "xstub"; then \ + echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ + $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ + else \ + echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ + $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ + fi; \ + ext=`echo $$p|sed -e "s/.*\.//"`; \ + if test "x$$ext" = "xdll"; then \ + lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ + if test -f $$lib; then \ + echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ + $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ + fi; \ + fi; \ + fi; \ + done + @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + destp=`basename $$p`; \ + echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ + $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ + fi; \ + done + @if test "x$(SHARED_BUILD)" = "x1"; then \ + echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \ + $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ + fi + +#======================================================================== +# Install binary executables (e.g. .exe files and dependent .dll files) +# This is for files that must go in the bin directory (located next to +# wish and tclsh), like dependent .dll files on Windows. +# +# You should not have to modify this target, except to define bin_BINARIES +# above if necessary. +#======================================================================== + +install-bin-binaries: binaries + @mkdir -p $(DESTDIR)$(bindir) + @list='$(bin_BINARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ + fi; \ + done + +.SUFFIXES: .c .$(OBJEXT) + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +uninstall-binaries: + list='$(lib_BINARIES)'; for p in $$list; do \ + rm -f $(DESTDIR)$(pkglibdir)/$$p; \ + done + list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ + p=`basename $$p`; \ + rm -f $(DESTDIR)$(pkglibdir)/$$p; \ + done + list='$(bin_BINARIES)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/$$p; \ + done + +.PHONY: all binaries clean depend distclean doc install libraries test + +# 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: diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..0b05739 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,9 @@ +# +# Include the TEA standard macro set +# + +builtin(include,tclconfig/tcl.m4) + +# +# Add here whatever m4 macros you want to define for your package +# diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..b2a872a --- /dev/null +++ b/configure.in @@ -0,0 +1,187 @@ +#!/bin/bash -norc +dnl This file is an input file used by the GNU "autoconf" program to +dnl generate the file "configure", which is run during Tcl installation +dnl to configure the system for the local environment. +# +# RCS: @(#) $Id: configure.in,v 1.46 2006/01/23 19:18:55 hobbs Exp $ + +#----------------------------------------------------------------------- +# Sample configure.in for Tcl Extensions. The only places you should +# need to modify this file are marked by the string __CHANGE__ +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# __CHANGE__ +# Set your package name and version numbers here. +# +# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION +# set as provided. These will also be added as -D defs in your Makefile +# so you can encode the package version directly into the source files. +#----------------------------------------------------------------------- + +AC_INIT([tclusb], [0.1]) + +#-------------------------------------------------------------------- +# Call TEA_INIT as the first TEA_ macro to set up initial vars. +# This will define a ${TEA_PLATFORM} variable == "unix" or "windows" +# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. +#-------------------------------------------------------------------- + +TEA_INIT([3.5]) + +AC_CONFIG_AUX_DIR(tclconfig) + +#-------------------------------------------------------------------- +# Load the tclConfig.sh file +#-------------------------------------------------------------------- + +TEA_PATH_TCLCONFIG +TEA_LOAD_TCLCONFIG + +#-------------------------------------------------------------------- +# Load the tkConfig.sh file if necessary (Tk extension) +#-------------------------------------------------------------------- + +#TEA_PATH_TKCONFIG +#TEA_LOAD_TKCONFIG + +#----------------------------------------------------------------------- +# Handle the --prefix=... option by defaulting to what Tcl gave. +# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. +#----------------------------------------------------------------------- + +TEA_PREFIX + +#----------------------------------------------------------------------- +# Standard compiler checks. +# This sets up CC by using the CC env var, or looks for gcc otherwise. +# This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create +# the basic setup necessary to compile executables. +#----------------------------------------------------------------------- + +TEA_SETUP_COMPILER + +#----------------------------------------------------------------------- +# __CHANGE__ +# Specify the C source files to compile in TEA_ADD_SOURCES, +# public headers that need to be installed in TEA_ADD_HEADERS, +# stub library C source files to compile in TEA_ADD_STUB_SOURCES, +# and runtime Tcl library files in TEA_ADD_TCL_SOURCES. +# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS +# and PKG_TCL_SOURCES. +#----------------------------------------------------------------------- + +TEA_ADD_SOURCES([tclusb.c]) +TEA_ADD_HEADERS([]) +TEA_ADD_INCLUDES([]) +TEA_ADD_LIBS([-lusb]) +TEA_ADD_CFLAGS([]) +TEA_ADD_STUB_SOURCES([]) +TEA_ADD_TCL_SOURCES([]) + +#-------------------------------------------------------------------- +# __CHANGE__ +# A few miscellaneous platform-specific items: +# +# Define a special symbol for Windows (BUILD_sample in this case) so +# that we create the export library with the dll. +# +# Windows creates a few extra files that need to be cleaned up. +# You can add more files to clean if your extension creates any extra +# files. +# +# TEA_ADD_* any platform specific compiler/build info here. +#-------------------------------------------------------------------- + +if test "${TEA_PLATFORM}" = "windows" ; then + AC_DEFINE(BUILD_sample, 1, [Build windows export dll]) + CLEANFILES="pkgIndex.tcl *.lib *.dll *.exp *.ilk *.pdb vc*.pch" + #TEA_ADD_SOURCES([win/winFile.c]) + #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) +else + CLEANFILES="pkgIndex.tcl" + #TEA_ADD_SOURCES([unix/unixFile.c]) + #TEA_ADD_LIBS([-lsuperfly]) +fi +AC_SUBST(CLEANFILES) + +#-------------------------------------------------------------------- +# __CHANGE__ +# Choose which headers you need. Extension authors should try very +# hard to only rely on the Tcl public header files. Internal headers +# contain private data structures and are subject to change without +# notice. +# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG +#-------------------------------------------------------------------- + +TEA_PUBLIC_TCL_HEADERS +#TEA_PRIVATE_TCL_HEADERS + +#TEA_PUBLIC_TK_HEADERS +#TEA_PRIVATE_TK_HEADERS +#TEA_PATH_X + +#-------------------------------------------------------------------- +# Check whether --enable-threads or --disable-threads was given. +# This auto-enables if Tcl was compiled threaded. +#-------------------------------------------------------------------- + +TEA_ENABLE_THREADS + +#-------------------------------------------------------------------- +# The statement below defines a collection of symbols related to +# building as a shared library instead of a static library. +#-------------------------------------------------------------------- + +TEA_ENABLE_SHARED + +#-------------------------------------------------------------------- +# This macro figures out what flags to use with the compiler/linker +# when building shared/static debug/optimized objects. This information +# can be taken from the tclConfig.sh file, but this figures it all out. +#-------------------------------------------------------------------- + +TEA_CONFIG_CFLAGS + +#-------------------------------------------------------------------- +# Set the default compiler switches based on the --enable-symbols option. +#-------------------------------------------------------------------- + +TEA_ENABLE_SYMBOLS + +#-------------------------------------------------------------------- +# Everyone should be linking against the Tcl stub library. If you +# can't for some reason, remove this definition. If you aren't using +# stubs, you also need to modify the SHLIB_LD_LIBS setting below to +# link against the non-stubbed Tcl library. Add Tk too if necessary. +#-------------------------------------------------------------------- + +AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) +#AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) + +#-------------------------------------------------------------------- +# This macro generates a line to use when building a library. It +# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, +# and TEA_LOAD_TCLCONFIG macros above. +#-------------------------------------------------------------------- + +TEA_MAKE_LIB + +#-------------------------------------------------------------------- +# Determine the name of the tclsh and/or wish executables in the +# Tcl and Tk build directories or the location they were installed +# into. These paths are used to support running test cases only, +# the Makefile should not be making use of these paths to generate +# a pkgIndex.tcl file or anything else at extension build time. +#-------------------------------------------------------------------- + +TEA_PROG_TCLSH +#TEA_PROG_WISH + +#-------------------------------------------------------------------- +# Finally, substitute all of the various values into the Makefile. +# You may alternatively have a special pkgIndex.tcl.in or other files +# which require substituting th AC variables in. Include these here. +#-------------------------------------------------------------------- + +AC_OUTPUT([Makefile pkgIndex.tcl]) diff --git a/pkgIndex.tcl.in b/pkgIndex.tcl.in new file mode 100644 index 0000000..cc105a1 --- /dev/null +++ b/pkgIndex.tcl.in @@ -0,0 +1 @@ +package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ [list load [file join $dir @PKG_LIB_FILE@]] \ No newline at end of file diff --git a/tclusb.c b/tclusb.c new file mode 100644 index 0000000..c0f8ce9 --- /dev/null +++ b/tclusb.c @@ -0,0 +1,242 @@ +/* + * usb find_device vid pid + * usb devices + * $device select_configuration $config + * $device open + * $device close + */ + +#include +#include +#include + +int DLLEXPORT Usb_Init(Tcl_Interp *interp); +static Tcl_ObjCmdProc UsbEnsembleCmd; +static Tcl_ObjCmdProc UsbDeviceEnsembleCmd; +static Tcl_ObjCmdProc UsbDevicesCmd; +static Tcl_ObjCmdProc UsbGetDeviceCmd; +static Tcl_ObjCmdProc UsbSetConfigurationCmd; +static Tcl_ObjCmdProc UsbClaimInterfaceCmd; +static Tcl_CmdDeleteProc UsbDeviceCleanup; + +struct Ensemble { + const char *name; + Tcl_ObjCmdProc *command; + struct Ensemble *ensemble; +}; + +struct Ensemble UsbEnsemble[] = { + { "devices", UsbDevicesCmd, NULL }, + { "get_device", UsbGetDeviceCmd, NULL}, + { NULL, NULL, NULL }, +}; + +struct Ensemble UsbDeviceEnsemble[] = { + { "set_configuration", UsbSetConfigurationCmd, NULL }, + { "claim_interface", UsbClaimInterfaceCmd, NULL }, + { NULL, NULL, NULL } +}; + +typedef struct Device { + struct usb_device *dev; + struct usb_dev_handle *handle; +} Device; + +int +UsbEnsembleCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct Ensemble *ensemble = UsbEnsemble; + int optPtr = 1, index = 0; + + while (optPtr < objc) { + if (Tcl_GetIndexFromObjStruct(interp, objv[optPtr], ensemble, + sizeof(ensemble[0]), + "command", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + if (ensemble[index].command) { + return ensemble[index].command(clientData, interp, objc, objv); + } + ensemble = ensemble[index].ensemble; + ++optPtr; + } + Tcl_WrongNumArgs(interp, optPtr, objv, "subcommand ?arg arg...?"); + return TCL_ERROR; +} + +int +UsbDeviceEnsembleCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct Ensemble *ensemble = UsbDeviceEnsemble; + int optPtr = 1, index = 0; + + while (optPtr < objc) { + if (Tcl_GetIndexFromObjStruct(interp, objv[optPtr], ensemble, + sizeof(ensemble[0]), + "command", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + if (ensemble[index].command) { + return ensemble[index].command(clientData, interp, objc, objv); + } + ensemble = ensemble[index].ensemble; + ++optPtr; + } + Tcl_WrongNumArgs(interp, optPtr, objv, "subcommand ?arg arg...?"); + return TCL_ERROR; +} + +int +UsbDevicesCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct usb_bus *bus = NULL; + Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); + + usb_find_devices(); + for (bus = usb_get_busses(); bus; bus = bus->next) { + struct usb_device *dev = NULL; + for (dev = bus->devices; dev != NULL; dev = dev->next) { + Tcl_Obj *elt[10], *deviceObj; + int n = 0; + elt[n++] = Tcl_NewStringObj("devnum", -1); + elt[n++] = Tcl_NewIntObj(dev->devnum); + elt[n++] = Tcl_NewStringObj("bDeviceClass", -1); + elt[n++] = Tcl_NewIntObj(dev->descriptor.bDeviceClass); + elt[n++] = Tcl_NewStringObj("idVendor", -1); + elt[n++] = Tcl_NewIntObj(dev->descriptor.idVendor); + elt[n++] = Tcl_NewStringObj("idProduct", -1); + elt[n++] = Tcl_NewIntObj(dev->descriptor.idProduct); + elt[n++] = Tcl_NewStringObj("path", -1); + elt[n] = Tcl_NewStringObj(bus->dirname, -1); + Tcl_AppendStringsToObj(elt[n++], "/", dev->filename, NULL); + deviceObj = Tcl_NewListObj(n, elt); + if (Tcl_ListObjAppendElement(interp, listObj, deviceObj) != TCL_OK) + return TCL_ERROR; + } + } + Tcl_SetObjResult(interp, listObj); + return TCL_OK; +} + +void +UsbDeviceCleanup(ClientData clientData) +{ + Device *devicePtr = (Device *)clientData; + usb_close(devicePtr->handle); + ckfree((char *)devicePtr); +} + +int +UsbGetDeviceCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + int num_parts = 0; + const char **path_parts; + char name[14]; + struct usb_device *dev = NULL; + struct usb_bus *bus = NULL; + Device *devicePtr = NULL; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "path"); + return TCL_ERROR; + } + + Tcl_SplitPath(Tcl_GetString(objv[2]), &num_parts, &path_parts); + if (num_parts != 2) { + Tcl_SetResult(interp, "error: path must be nnn/iii", TCL_STATIC); + return TCL_ERROR; + } + + for (bus = usb_get_busses(); bus; bus = bus->next) { + if (strcmp(bus->dirname, path_parts[0]) == 0) + break; + } + if (bus == NULL) { + Tcl_SetResult(interp, "error: bus index invalid", TCL_STATIC); + return TCL_ERROR; + } + + for (dev = bus->devices; dev; dev = dev->next) { + if (strcmp(dev->filename, path_parts[1]) == 0) + break; + } + if (dev == NULL) { + Tcl_SetResult(interp, "error: device index invalid", TCL_STATIC); + return TCL_ERROR; + } + + snprintf(name, sizeof(name) - 1, "usb%04x%04x", + dev->descriptor.idVendor, dev->descriptor.idProduct); + name[sizeof(name)-1] = 0; + + devicePtr = (Device *)ckalloc(sizeof(Device)); + devicePtr->dev = dev; + devicePtr->handle = usb_open(dev); + + Tcl_CreateObjCommand(interp, name, UsbDeviceEnsembleCmd, + devicePtr, UsbDeviceCleanup); + Tcl_SetObjResult(interp, Tcl_NewStringObj(name, -1)); + return TCL_OK; +} + +int +UsbSetConfigurationCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + Device *devicePtr = (Device *)clientData; + int r = TCL_OK, num = 0; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "num"); + return TCL_ERROR; + } + r = Tcl_GetIntFromObj(interp, objv[2], &num); + if (r == TCL_OK) { + int u = usb_set_configuration(devicePtr->handle, num); + Tcl_SetObjResult(interp, Tcl_NewIntObj(u)); + } + return r; +} + +int +UsbClaimInterfaceCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + Device *devicePtr = (Device *)clientData; + int r = TCL_OK, num = 0; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "num"); + return TCL_ERROR; + } + r = Tcl_GetIntFromObj(interp, objv[2], &num); + if (r == TCL_OK) { + int u = usb_set_configuration(devicePtr->handle, num); + Tcl_SetObjResult(interp, Tcl_NewIntObj(u)); + } + return r; +} + +#define TCL_VERSION_WRONG "8.0" + +int DLLEXPORT +Tclusb_Init(Tcl_Interp *interp) +{ +#ifdef USE_TCL_STUBS + if (Tcl_InitStubs(interp, TCL_VERSION_WRONG, 0) == NULL) { + return TCL_ERROR; + } +#endif + + usb_init(); + usb_find_busses(); + usb_find_devices(); + + Tcl_CreateObjCommand(interp, "usb", UsbEnsembleCmd, NULL, NULL); + Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_VERSION); + return TCL_OK; +} -- 2.23.0