From 2f4546f3926e7cf4a156fdc8c081a6fcfecf0b17 Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Wed, 22 Aug 2012 20:21:43 +0000 Subject: Imported from /home/lorry/working-area/delta_mtdev/mtdev-1.1.3.tar.gz. --- src/Makefile.am | 27 +++ src/Makefile.in | 622 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/caps.c | 232 +++++++++++++++++++++ src/common.h | 147 +++++++++++++ src/core.c | 426 +++++++++++++++++++++++++++++++++++++ src/evbuf.h | 59 ++++++ src/iobuf.c | 87 ++++++++ src/iobuf.h | 42 ++++ src/match.c | 390 ++++++++++++++++++++++++++++++++++ src/match.h | 51 +++++ src/match_four.c | 129 ++++++++++++ src/state.h | 88 ++++++++ 12 files changed, 2300 insertions(+) create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/caps.c create mode 100644 src/common.h create mode 100644 src/core.c create mode 100644 src/evbuf.h create mode 100644 src/iobuf.c create mode 100644 src/iobuf.h create mode 100644 src/match.c create mode 100644 src/match.h create mode 100644 src/match_four.c create mode 100644 src/state.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..16d388c --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,27 @@ +lib_LTLIBRARIES = libmtdev.la + +libmtdev_la_LDFLAGS = -version-info @LIB_VERSION@ + +libmtdev_la_SOURCES = \ + $(top_srcdir)/include/mtdev-mapping.h \ + $(top_srcdir)/include/mtdev-plumbing.h \ + common.h \ + evbuf.h \ + iobuf.h \ + match.h \ + state.h \ + caps.c \ + core.c \ + iobuf.c \ + match.c \ + match_four.c + +AM_CFLAGS = $(CWARNFLAGS) #-DMTDEV_NO_LEGACY_ABI + +INCLUDES = -I$(top_srcdir)/include/ + +libmtdevincludedir = $(includedir) +libmtdevinclude_HEADERS = \ + $(top_srcdir)/include/mtdev-mapping.h \ + $(top_srcdir)/include/mtdev-plumbing.h \ + $(top_srcdir)/include/mtdev.h diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..8016f98 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,622 @@ +# Makefile.in generated by automake 1.12.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2012 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. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = $(libmtdevinclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/config-aux/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" \ + "$(DESTDIR)$(libmtdevincludedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libmtdev_la_LIBADD = +am_libmtdev_la_OBJECTS = caps.lo core.lo iobuf.lo match.lo \ + match_four.lo +libmtdev_la_OBJECTS = $(am_libmtdev_la_OBJECTS) +libmtdev_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libmtdev_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libmtdev_la_SOURCES) +DIST_SOURCES = $(libmtdev_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(libmtdevinclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION = @LIB_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +lib_LTLIBRARIES = libmtdev.la +libmtdev_la_LDFLAGS = -version-info @LIB_VERSION@ +libmtdev_la_SOURCES = \ + $(top_srcdir)/include/mtdev-mapping.h \ + $(top_srcdir)/include/mtdev-plumbing.h \ + common.h \ + evbuf.h \ + iobuf.h \ + match.h \ + state.h \ + caps.c \ + core.c \ + iobuf.c \ + match.c \ + match_four.c + +AM_CFLAGS = $(CWARNFLAGS) #-DMTDEV_NO_LEGACY_ABI +INCLUDES = -I$(top_srcdir)/include/ +libmtdevincludedir = $(includedir) +libmtdevinclude_HEADERS = \ + $(top_srcdir)/include/mtdev-mapping.h \ + $(top_srcdir)/include/mtdev-plumbing.h \ + $(top_srcdir)/include/mtdev.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +libmtdev.la: $(libmtdev_la_OBJECTS) $(libmtdev_la_DEPENDENCIES) $(EXTRA_libmtdev_la_DEPENDENCIES) + $(libmtdev_la_LINK) -rpath $(libdir) $(libmtdev_la_OBJECTS) $(libmtdev_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/caps.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iobuf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/match.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/match_four.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-libmtdevincludeHEADERS: $(libmtdevinclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(libmtdevinclude_HEADERS)'; test -n "$(libmtdevincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(libmtdevincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libmtdevincludedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libmtdevincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(libmtdevincludedir)" || exit $$?; \ + done + +uninstall-libmtdevincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(libmtdevinclude_HEADERS)'; test -n "$(libmtdevincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(libmtdevincludedir)'; $(am__uninstall_files_from_dir) + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +cscopelist: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libmtdevincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-libmtdevincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES \ + uninstall-libmtdevincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool cscopelist ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-libmtdevincludeHEADERS \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-libLTLIBRARIES \ + uninstall-libmtdevincludeHEADERS + + +# 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/src/caps.c b/src/caps.c new file mode 100644 index 0000000..45c185c --- /dev/null +++ b/src/caps.c @@ -0,0 +1,232 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#include "state.h" + +static const int SN_COORD = 250; /* coordinate signal-to-noise ratio */ +static const int SN_WIDTH = 100; /* width signal-to-noise ratio */ +static const int SN_ORIENT = 10; /* orientation signal-to-noise ratio */ + +static const int bits_per_long = 8 * sizeof(long); + +static inline int nlongs(int nbit) +{ + return (nbit + bits_per_long - 1) / bits_per_long; +} + +static inline int getbit(const unsigned long *map, int key) +{ + return (map[key / bits_per_long] >> (key % bits_per_long)) & 0x01; +} + +static int getabs(struct input_absinfo *abs, int key, int fd) +{ + int rc; + SYSCALL(rc = ioctl(fd, EVIOCGABS(key), abs)); + return rc >= 0; +} + +static struct input_absinfo *get_info(struct mtdev *dev, int code) +{ + int ix; + + if (code == ABS_MT_SLOT) + return &dev->slot; + if (!mtdev_is_absmt(code)) + return NULL; + + ix = mtdev_abs2mt(code); + if (ix < 11) + return &dev->abs[ix]; + else + return &dev->state->ext_abs[ix - 11]; +} + +static void set_info(struct mtdev *dev, int code, + const unsigned long *bits, int fd) +{ + int has = getbit(bits, code) && getabs(get_info(dev, code), code, fd); + mtdev_set_mt_event(dev, code, has); +} + +static void default_fuzz(struct mtdev *dev, int code, int sn) +{ + struct input_absinfo *abs = get_info(dev, code); + if (!mtdev_has_mt_event(dev, code) || abs->fuzz) + return; + abs->fuzz = (abs->maximum - abs->minimum) / sn; +} + +int mtdev_set_slots(struct mtdev *dev, int fd) +{ + struct { unsigned code; int values[DIM_FINGER]; } req; + struct mtdev_state *state = dev->state; + int rc, i, s, nslot; + + nslot = mtdev_get_abs_maximum(dev, ABS_MT_SLOT) + 1; + + for (i = 0; i < MT_ABS_SIZE; i++) { + req.code = mtdev_mt2abs(i); + if (!mtdev_has_mt_event(dev, req.code)) + continue; + SYSCALL(rc = ioctl(fd, EVIOCGMTSLOTS(sizeof(req)), &req)); + if (rc < 0) + return rc; + for (s = 0; s < DIM_FINGER && s < nslot; s++) + set_sval(&state->data[s], i, req.values[s]); + } + + return 0; +} + +int mtdev_configure(struct mtdev *dev, int fd) +{ + unsigned long absbits[nlongs(ABS_MAX)]; + int rc, i; + + SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); + if (rc < 0) + return rc; + + set_info(dev, ABS_MT_SLOT, absbits, fd); + for (i = 0; i < MT_ABS_SIZE; i++) + set_info(dev, mtdev_mt2abs(i), absbits, fd); + + dev->has_mtdata = mtdev_has_mt_event(dev, ABS_MT_POSITION_X) && + mtdev_has_mt_event(dev, ABS_MT_POSITION_Y); + + if (!mtdev_has_mt_event(dev, ABS_MT_POSITION_X)) + getabs(get_info(dev, ABS_MT_POSITION_X), ABS_X, fd); + if (!mtdev_has_mt_event(dev, ABS_MT_POSITION_Y)) + getabs(get_info(dev, ABS_MT_POSITION_Y), ABS_Y, fd); + if (!mtdev_has_mt_event(dev, ABS_MT_PRESSURE)) + getabs(get_info(dev, ABS_MT_PRESSURE), ABS_PRESSURE, fd); + + if (!mtdev_has_mt_event(dev, ABS_MT_TRACKING_ID)) { + mtdev_set_abs_minimum(dev, ABS_MT_TRACKING_ID, MT_ID_MIN); + mtdev_set_abs_maximum(dev, ABS_MT_TRACKING_ID, MT_ID_MAX); + } + + default_fuzz(dev, ABS_MT_POSITION_X, SN_COORD); + default_fuzz(dev, ABS_MT_POSITION_Y, SN_COORD); + default_fuzz(dev, ABS_MT_TOUCH_MAJOR, SN_WIDTH); + default_fuzz(dev, ABS_MT_TOUCH_MINOR, SN_WIDTH); + default_fuzz(dev, ABS_MT_WIDTH_MAJOR, SN_WIDTH); + default_fuzz(dev, ABS_MT_WIDTH_MINOR, SN_WIDTH); + default_fuzz(dev, ABS_MT_ORIENTATION, SN_ORIENT); + + if (dev->has_slot) + mtdev_set_slots(dev, fd); + + return 0; +} + +int mtdev_has_mt_event(const struct mtdev *dev, int code) +{ + int ix; + + if (code == ABS_MT_SLOT) + return dev->has_slot; + if (!mtdev_is_absmt(code)) + return 0; + + ix = mtdev_abs2mt(code); + if (ix < 11) + return dev->has_abs[ix]; + else + return dev->state->has_ext_abs[ix - 11]; +} + +int mtdev_get_abs_minimum(const struct mtdev *dev, int code) +{ + const struct input_absinfo *abs = get_info((struct mtdev *)dev, code); + return abs ? abs->minimum : 0; +} + +int mtdev_get_abs_maximum(const struct mtdev *dev, int code) +{ + const struct input_absinfo *abs = get_info((struct mtdev *)dev, code); + return abs ? abs->maximum : 0; +} + +int mtdev_get_abs_fuzz(const struct mtdev *dev, int code) +{ + const struct input_absinfo *abs = get_info((struct mtdev *)dev, code); + return abs ? abs->fuzz : 0; +} + +int mtdev_get_abs_resolution(const struct mtdev *dev, int code) +{ + const struct input_absinfo *abs = get_info((struct mtdev *)dev, code); + return abs ? abs->resolution : 0; +} + +void mtdev_set_abs_minimum(struct mtdev *dev, int code, int value) +{ + struct input_absinfo *abs = get_info(dev, code); + if (abs) + abs->minimum = value; +} + +void mtdev_set_mt_event(struct mtdev *dev, int code, int value) +{ + int ix; + + if (code == ABS_MT_SLOT) + dev->has_slot = value; + if (!mtdev_is_absmt(code)) + return; + + ix = mtdev_abs2mt(code); + if (ix < 11) + dev->has_abs[ix] = value; + else + dev->state->has_ext_abs[ix - 11] = value; +} + +void mtdev_set_abs_maximum(struct mtdev *dev, int code, int value) +{ + struct input_absinfo *abs = get_info(dev, code); + if (abs) + abs->maximum = value; +} + +void mtdev_set_abs_fuzz(struct mtdev *dev, int code, int value) +{ + struct input_absinfo *abs = get_info(dev, code); + if (abs) + abs->fuzz = value; +} + +void mtdev_set_abs_resolution(struct mtdev *dev, int code, int value) +{ + struct input_absinfo *abs = get_info(dev, code); + if (abs) + abs->resolution = value; +} + diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..2ec8eb8 --- /dev/null +++ b/src/common.h @@ -0,0 +1,147 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#ifndef COMMON_H +#define COMMON_H + +#define MTDEV_NO_LEGACY_API + +#include +#include +#include +#include +#include + +#define DIM_FINGER 32 +#define DIM2_FINGER (DIM_FINGER * DIM_FINGER) + +/* event buffer size (must be a power of two) */ +#define DIM_EVENTS 512 + +/* all bit masks have this type */ +typedef unsigned int bitmask_t; + +#define BITMASK(x) (1U << (x)) +#define BITONES(x) (BITMASK(x) - 1U) +#define GETBIT(m, x) (((m) >> (x)) & 1U) +#define SETBIT(m, x) (m |= BITMASK(x)) +#define CLEARBIT(m, x) (m &= ~BITMASK(x)) +#define MODBIT(m, x, b) ((b) ? SETBIT(m, x) : CLEARBIT(m, x)) + +static inline int maxval(int x, int y) { return x > y ? x : y; } +static inline int minval(int x, int y) { return x < y ? x : y; } + +static inline int clamp15(int x) +{ + return x < -32767 ? -32767 : x > 32767 ? 32767 : x; +} + +/* absolute scale is assumed to fit in 15 bits */ +static inline int dist2(int dx, int dy) +{ + dx = clamp15(dx); + dy = clamp15(dy); + return dx * dx + dy * dy; +} + +/* Count number of bits (Sean Eron Andersson's Bit Hacks) */ +static inline int bitcount(unsigned v) +{ + v -= ((v>>1) & 0x55555555); + v = (v&0x33333333) + ((v>>2) & 0x33333333); + return (((v + (v>>4)) & 0xF0F0F0F) * 0x1010101) >> 24; +} + +/* Return index of first bit [0-31], -1 on zero */ +#define firstbit(v) (__builtin_ffs(v) - 1) + +/* boost-style foreach bit */ +#define foreach_bit(i, m) \ + for (i = firstbit(m); i >= 0; i = firstbit((m) & (~0U << (i + 1)))) + +/* robust system ioctl calls */ +#define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) + +/** + * struct mtdev - represents an input MT device + * @has_mtdata: true if the device has MT capabilities + * @has_slot: true if the device sends MT slots + * @slot: slot event properties + * @abs: ABS_MT event properties + * @state: internal mtdev parsing state + * + * The mtdev structure represents a kernel MT device type B, emitting + * MT slot events. The events put into mtdev may be from any MT + * device, specifically type A without contact tracking, type A with + * contact tracking, or type B with contact tracking. See the kernel + * documentation for further details. + * + */ +struct mtdev { + int has_mtdata; + int has_slot; + int has_abs[11]; + struct input_absinfo slot; + struct input_absinfo abs[11]; + struct mtdev_state *state; +}; + +#define MT_ABS_SIZE 12 + +static const unsigned int mtdev_map_abs2mt[ABS_CNT] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0009, 0x000a, 0x000b, 0x000c, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const unsigned int mtdev_map_mt2abs[MT_ABS_SIZE] = { + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, +}; + +static inline int mtdev_is_absmt(unsigned int code) +{ + return mtdev_map_abs2mt[code]; +} + +static inline unsigned int mtdev_abs2mt(unsigned int code) +{ + return mtdev_map_abs2mt[code] - 1; +} + +static inline unsigned int mtdev_mt2abs(unsigned int mtcode) +{ + return mtdev_map_mt2abs[mtcode]; +} + +#endif diff --git a/src/core.c b/src/core.c new file mode 100644 index 0000000..87ef420 --- /dev/null +++ b/src/core.c @@ -0,0 +1,426 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#include "state.h" +#include "iobuf.h" +#include "evbuf.h" +#include "match.h" + +static inline int istouch(const struct mtdev_slot *data, + const struct mtdev *dev) +{ + return data->touch_major || + !mtdev_has_mt_event(dev, ABS_MT_TOUCH_MAJOR); +} + +static inline int isfilled(unsigned int mask) +{ + return GETBIT(mask, mtdev_abs2mt(ABS_MT_POSITION_X)) && + GETBIT(mask, mtdev_abs2mt(ABS_MT_POSITION_Y)); +} + +/* Response-augmented EWMA filter, courtesy of Vojtech Pavlik */ +static int defuzz(int value, int old_val, int fuzz) +{ + if (fuzz) { + if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2) + return old_val; + + if (value > old_val - fuzz && value < old_val + fuzz) + return (old_val * 3 + value) / 4; + + if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2) + return (old_val + value) / 2; + } + + return value; +} + +/* + * solve - solve contact matching problem + * @state: mtdev state + * @dev: device capabilities + * @sid: array of current tracking ids + * @sx: array of current position x + * @sy: array of current position y + * @sn: number of current contacts + * @nid: array of new or matched tracking ids, to be filled + * @nx: array of new position x + * @ny: array of new position y + * @nn: number of new contacts + * @touch: which of the new contacts to fill + */ +static void solve(struct mtdev_state *state, const struct mtdev *dev, + const int *sid, const int *sx, const int *sy, int sn, + int *nid, const int *nx, const int *ny, int nn, + bitmask_t touch) +{ + int A[DIM2_FINGER], *row; + int n2s[DIM_FINGER]; + int id, i, j; + + /* setup distance matrix for contact matching */ + for (j = 0; j < sn; j++) { + row = A + nn * j; + for (i = 0; i < nn; i++) + row[i] = dist2(nx[i] - sx[j], ny[i] - sy[j]); + } + + mtdev_match(n2s, A, nn, sn); + + /* update matched contacts and create new ones */ + foreach_bit(i, touch) { + j = n2s[i]; + id = j >= 0 ? sid[j] : MT_ID_NULL; + if (id == MT_ID_NULL) + id = state->lastid++ & MT_ID_MAX; + nid[i] = id; + } +} + +/* + * assign_tracking_id - assign tracking ids to all contacts + * @state: mtdev state + * @dev: device capabilities + * @data: array of all present contacts, to be filled + * @prop: array of all set contacts properties + * @size: number of contacts in array + * @touch: which of the contacts are actual touches + */ +static void assign_tracking_id(struct mtdev_state *state, + const struct mtdev *dev, + struct mtdev_slot *data, bitmask_t *prop, + int size, bitmask_t touch) +{ + int sid[DIM_FINGER], sx[DIM_FINGER], sy[DIM_FINGER], sn = 0; + int nid[DIM_FINGER], nx[DIM_FINGER], ny[DIM_FINGER], i; + foreach_bit(i, state->used) { + sid[sn] = state->data[i].tracking_id; + sx[sn] = state->data[i].position_x; + sy[sn] = state->data[i].position_y; + sn++; + } + for (i = 0; i < size; i++) { + nx[i] = data[i].position_x; + ny[i] = data[i].position_y; + } + solve(state, dev, sid, sx, sy, sn, nid, nx, ny, size, touch); + for (i = 0; i < size; i++) { + data[i].tracking_id = GETBIT(touch, i) ? nid[i] : MT_ID_NULL; + SETBIT(prop[i], mtdev_abs2mt(ABS_MT_TRACKING_ID)); + } +} + +/* + * process_typeA - consume MT events and update mtdev state + * @state: mtdev state + * @data: array of all present contacts, to be filled + * @prop: array of all set contacts properties, to be filled + * + * This function is called when a SYN_REPORT is seen, right before + * that event is pushed to the queue. + * + * Returns -1 if the packet is not MT related and should not affect + * the current mtdev state. + */ +static int process_typeA(struct mtdev_state *state, + struct mtdev_slot *data, bitmask_t *prop) +{ + struct input_event ev; + int consumed, mtcode; + int mtcnt = 0, size = 0; + prop[size] = 0; + while (!evbuf_empty(&state->inbuf)) { + evbuf_get(&state->inbuf, &ev); + consumed = 0; + switch (ev.type) { + case EV_SYN: + switch (ev.code) { + case SYN_MT_REPORT: + if (size < DIM_FINGER && isfilled(prop[size])) + size++; + if (size < DIM_FINGER) + prop[size] = 0; + mtcnt++; + consumed = 1; + break; + } + break; + case EV_KEY: + switch (ev.code) { + case BTN_TOUCH: + mtcnt++; + break; + } + break; + case EV_ABS: + if (size < DIM_FINGER && mtdev_is_absmt(ev.code)) { + mtcode = mtdev_abs2mt(ev.code); + set_sval(&data[size], mtcode, ev.value); + SETBIT(prop[size], mtcode); + mtcnt++; + consumed = 1; + } + break; + } + if (!consumed) + evbuf_put(&state->outbuf, &ev); + } + return mtcnt ? size : -1; +} + +/* + * process_typeB - propagate events without parsing + * @state: mtdev state + * + * This function is called when a SYN_REPORT is seen, right before + * that event is pushed to the queue. + */ +static void process_typeB(struct mtdev_state *state) +{ + struct input_event ev; + while (!evbuf_empty(&state->inbuf)) { + evbuf_get(&state->inbuf, &ev); + evbuf_put(&state->outbuf, &ev); + } +} + +/* + * filter_data - apply input filtering on new incoming data + * @state: mtdev state + * @dev: device capabilities + * @data: the incoming data to filter + * @prop: the properties to filter + * @slot: the slot the data refers to + */ +static void filter_data(const struct mtdev_state *state, + const struct mtdev *dev, + struct mtdev_slot *data, bitmask_t prop, + int slot) +{ + int i; + foreach_bit(i, prop) { + int fuzz = mtdev_get_abs_fuzz(dev, mtdev_mt2abs(i)); + int oldval = get_sval(&state->data[slot], i); + int value = get_sval(data, i); + set_sval(data, i, defuzz(value, oldval, fuzz)); + } +} + +/* + * push_slot_changes - propagate state changes + * @state: mtdev state + * @data: the incoming data to propagate + * @prop: the properties to propagate + * @slot: the slot the data refers to + * @syn: reference to the SYN_REPORT event + */ +static void push_slot_changes(struct mtdev_state *state, + const struct mtdev_slot *data, bitmask_t prop, + int slot, const struct input_event *syn) +{ + struct input_event ev; + int i, count = 0; + foreach_bit(i, prop) + if (get_sval(&state->data[slot], i) != get_sval(data, i)) + count++; + if (!count) + return; + ev.time = syn->time; + ev.type = EV_ABS; + ev.code = ABS_MT_SLOT; + ev.value = slot; + if (state->slot != ev.value) { + evbuf_put(&state->outbuf, &ev); + state->slot = ev.value; + } + foreach_bit(i, prop) { + ev.code = mtdev_mt2abs(i); + ev.value = get_sval(data, i); + if (get_sval(&state->data[slot], i) != ev.value) { + evbuf_put(&state->outbuf, &ev); + set_sval(&state->data[slot], i, ev.value); + } + } +} + +/* + * apply_typeA_changes - parse and propagate state changes + * @state: mtdev state + * @dev: device capabilities + * @data: array of data to apply + * @prop: array of properties to apply + * @size: number of contacts in array + * @syn: reference to the SYN_REPORT event + */ +static void apply_typeA_changes(struct mtdev_state *state, + const struct mtdev *dev, + struct mtdev_slot *data, const bitmask_t *prop, + int size, const struct input_event *syn) +{ + bitmask_t unused = ~state->used; + bitmask_t used = 0; + int i, slot, id; + for (i = 0; i < size; i++) { + id = data[i].tracking_id; + foreach_bit(slot, state->used) { + if (state->data[slot].tracking_id != id) + continue; + filter_data(state, dev, &data[i], prop[i], slot); + push_slot_changes(state, &data[i], prop[i], slot, syn); + SETBIT(used, slot); + id = MT_ID_NULL; + break; + } + if (id != MT_ID_NULL) { + slot = firstbit(unused); + push_slot_changes(state, &data[i], prop[i], slot, syn); + SETBIT(used, slot); + CLEARBIT(unused, slot); + } + } + + /* clear unused slots and update slot usage */ + foreach_bit(slot, state->used & ~used) { + struct mtdev_slot tdata = state->data[slot]; + bitmask_t tprop = BITMASK(mtdev_abs2mt(ABS_MT_TRACKING_ID)); + tdata.tracking_id = MT_ID_NULL; + push_slot_changes(state, &tdata, tprop, slot, syn); + } + state->used = used; +} + +/* + * convert_A_to_B - propagate a type A packet as a type B packet + * @state: mtdev state + * @dev: device capabilities + * @syn: reference to the SYN_REPORT event + */ +static void convert_A_to_B(struct mtdev_state *state, + const struct mtdev *dev, + const struct input_event *syn) +{ + struct mtdev_slot data[DIM_FINGER]; + bitmask_t prop[DIM_FINGER]; + int size = process_typeA(state, data, prop); + if (size < 0) + return; + if (!mtdev_has_mt_event(dev, ABS_MT_TRACKING_ID)) { + bitmask_t touch = 0; + int i; + for (i = 0; i < size; i++) + MODBIT(touch, i, istouch(&data[i], dev)); + assign_tracking_id(state, dev, data, prop, size, touch); + } + apply_typeA_changes(state, dev, data, prop, size, syn); +} + +struct mtdev *mtdev_new(void) +{ + return calloc(1, sizeof(struct mtdev)); +} + +int mtdev_init(struct mtdev *dev) +{ + int i; + memset(dev, 0, sizeof(struct mtdev)); + dev->state = calloc(1, sizeof(struct mtdev_state)); + if (!dev->state) + return -ENOMEM; + for (i = 0; i < DIM_FINGER; i++) + dev->state->data[i].tracking_id = MT_ID_NULL; + return 0; +} + +int mtdev_open(struct mtdev *dev, int fd) +{ + int ret = -EINVAL; + + if (!dev || fd < 0) + goto error; + ret = mtdev_init(dev); + if (ret) + goto error; + ret = mtdev_configure(dev, fd); + if (ret) + goto error; + return 0; + + error: + mtdev_close(dev); + return ret; +} + +struct mtdev *mtdev_new_open(int fd) +{ + struct mtdev *dev; + + dev = mtdev_new(); + if (!dev) + return NULL; + if (!mtdev_open(dev, fd)) + return dev; + + mtdev_delete(dev); + return NULL; +} + +void mtdev_put_event(struct mtdev *dev, const struct input_event *ev) +{ + struct mtdev_state *state = dev->state; + if (ev->type == EV_SYN && ev->code == SYN_REPORT) { + bitmask_t head = state->outbuf.head; + if (mtdev_has_mt_event(dev, ABS_MT_SLOT)) + process_typeB(state); + else + convert_A_to_B(state, dev, ev); + if (state->outbuf.head != head) + evbuf_put(&state->outbuf, ev); + } else { + evbuf_put(&state->inbuf, ev); + } +} + +void mtdev_close_delete(struct mtdev *dev) +{ + mtdev_close(dev); + mtdev_delete(dev); +} + +void mtdev_close(struct mtdev *dev) +{ + if (dev) { + free(dev->state); + memset(dev, 0, sizeof(struct mtdev)); + } +} + +void mtdev_delete(struct mtdev *dev) +{ + free(dev); +} diff --git a/src/evbuf.h b/src/evbuf.h new file mode 100644 index 0000000..17ea4e7 --- /dev/null +++ b/src/evbuf.h @@ -0,0 +1,59 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#ifndef MTDEV_EVBUF_H +#define MTDEV_EVBUF_H + +#include "common.h" + +struct mtdev_evbuf { + int head; + int tail; + struct input_event buffer[DIM_EVENTS]; +}; + +static inline int evbuf_empty(const struct mtdev_evbuf *evbuf) +{ + return evbuf->head == evbuf->tail; +} + +static inline void evbuf_put(struct mtdev_evbuf *evbuf, + const struct input_event *ev) +{ + evbuf->buffer[evbuf->head++] = *ev; + evbuf->head &= DIM_EVENTS - 1; +} + +static inline void evbuf_get(struct mtdev_evbuf *evbuf, + struct input_event *ev) +{ + *ev = evbuf->buffer[evbuf->tail++]; + evbuf->tail &= DIM_EVENTS - 1; +} + +#endif diff --git a/src/iobuf.c b/src/iobuf.c new file mode 100644 index 0000000..61ec9c1 --- /dev/null +++ b/src/iobuf.c @@ -0,0 +1,87 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#include "iobuf.h" +#include "state.h" +#include +#include + +int mtdev_idle(struct mtdev *dev, int fd, int ms) +{ + struct mtdev_iobuf *buf = &dev->state->iobuf; + struct pollfd fds = { fd, POLLIN, 0 }; + return buf->head == buf->tail && poll(&fds, 1, ms) <= 0; +} + +int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev) +{ + struct mtdev_iobuf *buf = &dev->state->iobuf; + int n = buf->head - buf->tail; + if (n < EVENT_SIZE) { + if (buf->tail && n > 0) + memmove(buf->data, buf->data + buf->tail, n); + buf->head = n; + buf->tail = 0; + SYSCALL(n = read(fd, buf->data + buf->head, + DIM_BUFFER - buf->head)); + if (n <= 0) + return n; + buf->head += n; + } + if (buf->head - buf->tail < EVENT_SIZE) + return 0; + memcpy(ev, buf->data + buf->tail, EVENT_SIZE); + buf->tail += EVENT_SIZE; + return 1; +} + +int mtdev_empty(struct mtdev *dev) +{ + return evbuf_empty(&dev->state->outbuf); +} + +void mtdev_get_event(struct mtdev *dev, struct input_event* ev) +{ + evbuf_get(&dev->state->outbuf, ev); +} + +int mtdev_get(struct mtdev *dev, int fd, struct input_event* ev, int ev_max) +{ + struct input_event kev; + int ret, count = 0; + while (count < ev_max) { + while (mtdev_empty(dev)) { + ret = mtdev_fetch_event(dev, fd, &kev); + if (ret <= 0) + return count > 0 ? count : ret; + mtdev_put_event(dev, &kev); + } + mtdev_get_event(dev, &ev[count++]); + } + return count; +} diff --git a/src/iobuf.h b/src/iobuf.h new file mode 100644 index 0000000..09c26c4 --- /dev/null +++ b/src/iobuf.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#ifndef MTDEV_IOBUF_H +#define MTDEV_IOBUF_H + +#include "common.h" + +#define EVENT_SIZE sizeof(struct input_event) +#define DIM_BUFFER (DIM_EVENTS * EVENT_SIZE) + +struct mtdev_iobuf { + int head, tail; + char data[DIM_BUFFER]; +}; + +#endif diff --git a/src/match.c b/src/match.c new file mode 100644 index 0000000..4247e5a --- /dev/null +++ b/src/match.c @@ -0,0 +1,390 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#include "match.h" +#include +#include + +/** + * Bitmap implementation of the hungarian algorithm (MIT license) + * + * Copyright (C) 2008 Henrik Rydberg + * + * Based on code released by Markus Buehren (2004) (BSD license) + * + * Copyright (C) 2004, Markus Buehren. All rights reserved. + */ + +typedef unsigned col_t[1]; +typedef unsigned mat_t[DIM_FINGER]; + +#define GET1(m, x) ((m[0] >> (x)) & 1U) +#define SET1(m, x) (m[0] |= (1U << (x))) +#define CLEAR1(m, x) (m[0] &= ~(1U << (x))) + +#define GET2(m, row, col) ((m[col] >> (row)) & 1U) +#define SET2(m, row, col) (m[col] |= (1U << (row))) +#define CLEAR2(m, row, col) (m[col] &= ~(1U << (row))) + +/********************************************************/ + +static void buildixvector(int *ix, mat_t mstar, int nrows, int ncols) +{ + int row, col; + for (row = 0; row < nrows; row++) { + for (col = 0; col < ncols; col++) { + if (GET2(mstar, row, col)) { + ix[row] = col; + break; + } + } + } +} + + +/********************************************************/ + +static void step2a(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin); +static void step2b(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin); +static void step3(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin); +static void step4(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin, int row, int col); +static void step5(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin); + +static void ixoptimal(int *ix, int *mdist, int nrows, int ncols) +{ + int *mdistTemp, *mdistEnd, *columnEnd, value, minValue; + int dmin, row, col; + col_t ccol, crow; + mat_t mstar, mprime, nmstar; + + memset(ccol, 0, sizeof(col_t)); + memset(crow, 0, sizeof(col_t)); + memset(mstar, 0, sizeof(mat_t)); + memset(mprime, 0, sizeof(mat_t)); + memset(nmstar, 0, sizeof(mat_t)); + + /* initialization */ + for (row = 0; row < nrows; row++) + ix[row] = -1; + + mdistEnd = mdist + nrows * ncols; + + /* preliminary steps */ + if (nrows <= ncols) { + dmin = nrows; + + for (row = 0; row < nrows; row++) { + /* find the smallest element in the row */ + mdistTemp = mdist + row; + minValue = *mdistTemp; + mdistTemp += nrows; + while (mdistTemp < mdistEnd) { + value = *mdistTemp; + if (value < minValue) + minValue = value; + mdistTemp += nrows; + } + + /* subtract the smallest element from each element + of the row */ + mdistTemp = mdist + row; + while (mdistTemp < mdistEnd) { + *mdistTemp -= minValue; + mdistTemp += nrows; + } + } + + /* Steps 1 and 2a */ + for (row = 0; row < nrows; row++) { + for (col = 0; col < ncols; col++) { + if (mdist[row + nrows * col] != 0) + continue; + if (GET1(ccol, col)) + continue; + SET2(mstar, row, col); + SET1(ccol, col); + break; + } + } + } else { + dmin = ncols; + + for (col = 0; col < ncols; col++) { + /* find the smallest element in the column */ + mdistTemp = mdist + nrows*col; + columnEnd = mdistTemp + nrows; + + minValue = *mdistTemp++; + while (mdistTemp < columnEnd) { + value = *mdistTemp++; + if (value < minValue) + minValue = value; + } + + /* subtract the smallest element from each element + of the column */ + mdistTemp = mdist + nrows*col; + while (mdistTemp < columnEnd) + *mdistTemp++ -= minValue; + } + + /* Steps 1 and 2a */ + for (col = 0; col < ncols; col++) { + for (row = 0; row < nrows; row++) { + if (mdist[row + nrows * col] != 0) + continue; + if (GET1(crow, row)) + continue; + SET2(mstar, row, col); + SET1(ccol, col); + SET1(crow, row); + break; + } + } + memset(crow, 0, sizeof(col_t)); + } + + /* move to step 2b */ + step2b(ix, mdist, mstar, nmstar, + mprime, ccol, crow, nrows, ncols, + dmin); +} + +/********************************************************/ +static void step2a(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin) +{ + int col, row; + + /* cover every column containing a starred zero */ + for (col = 0; col < ncols; col++) { + for (row = 0; row < nrows; row++) { + if (!GET2(mstar, row, col)) + continue; + SET1(ccol, col); + break; + } + } + + /* move to step 3 */ + step2b(ix, mdist, mstar, nmstar, + mprime, ccol, crow, nrows, ncols, + dmin); +} + +/********************************************************/ +static void step2b(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin) +{ + int col, ncc; + + /* count covered columns */ + ncc = 0; + for (col = 0; col < ncols; col++) + if (GET1(ccol, col)) + ncc++; + + if (ncc == dmin) { + /* algorithm finished */ + buildixvector(ix, mstar, nrows, ncols); + } else { + /* move to step 3 */ + step3(ix, mdist, mstar, nmstar, + mprime, ccol, crow, nrows, ncols, + dmin); + } + +} + +/********************************************************/ +static void step3(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin) +{ + int zerosFound; + int row, col, cstar; + + zerosFound = 1; + while (zerosFound) { + zerosFound = 0; + for (col = 0; col < ncols; col++) { + if (GET1(ccol, col)) + continue; + for (row = 0; row < nrows; row++) { + if (mdist[row + nrows * col] != 0) + continue; + if (GET1(crow, row)) + continue; + + /* prime zero */ + SET2(mprime, row, col); + + /* find starred zero in current row */ + for (cstar = 0; cstar < ncols; cstar++) + if (GET2(mstar, row, cstar)) + break; + + if (cstar == ncols) { /* no starred zero */ + /* move to step 4 */ + step4(ix, mdist, mstar, nmstar, + mprime, ccol, crow, nrows, ncols, + dmin, row, col); + return; + } else { + SET1(crow, row); + CLEAR1(ccol, cstar); + zerosFound = 1; + break; + } + } + } + } + + /* move to step 5 */ + step5(ix, mdist, mstar, nmstar, + mprime, ccol, crow, nrows, ncols, + dmin); +} + +/********************************************************/ +static void step4(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin, int row, int col) +{ + int rstar, cstar, primeRow, primeCol; + + /* generate temporary copy of mstar */ + memcpy(nmstar, mstar, sizeof(mat_t)); + + /* star current zero */ + SET2(nmstar, row, col); + + /* find starred zero in current column */ + cstar = col; + for (rstar = 0; rstar < nrows; rstar++) + if (GET2(mstar, rstar, cstar)) + break; + + while (rstar < nrows) { + /* unstar the starred zero */ + CLEAR2(nmstar, rstar, cstar); + + /* find primed zero in current row */ + primeRow = rstar; + for (primeCol = 0; primeCol < ncols; primeCol++) + if (GET2(mprime, primeRow, primeCol)) + break; + + /* star the primed zero */ + SET2(nmstar, primeRow, primeCol); + + /* find starred zero in current column */ + cstar = primeCol; + for (rstar = 0; rstar < nrows; rstar++) + if (GET2(mstar, rstar, cstar)) + break; + } + + /* use temporary copy as new mstar */ + /* delete all primes, uncover all rows */ + memcpy(mstar, nmstar, sizeof(mat_t)); + memset(mprime, 0, sizeof(mat_t)); + memset(crow, 0, sizeof(col_t)); + + /* move to step 2a */ + step2a(ix, mdist, mstar, nmstar, + mprime, ccol, crow, nrows, ncols, + dmin); +} + +/********************************************************/ +static void step5(int *ix, int *mdist, mat_t mstar, mat_t nmstar, + mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, + int dmin) +{ + int h = 0, value; + int row, col, found = 0; + + /* find smallest uncovered element h */ + for (row = 0; row < nrows; row++) { + if (GET1(crow, row)) + continue; + for (col = 0; col < ncols; col++) { + if (GET1(ccol, col)) + continue; + value = mdist[row + nrows * col]; + if (!found || value < h) { + h = value; + found = 1; + } + } + } + + /* where to go if nothing uncovered? */ + if (!found) + return; + + /* add h to each covered row */ + for (row = 0; row < nrows; row++) { + if (!GET1(crow, row)) + continue; + for (col = 0; col < ncols; col++) + mdist[row + nrows * col] += h; + } + + /* subtract h from each uncovered column */ + for (col = 0; col < ncols; col++) { + if (GET1(ccol, col)) + continue; + for (row = 0; row < nrows; row++) + mdist[row + nrows * col] -= h; + } + + /* move to step 3 */ + step3(ix, mdist, mstar, nmstar, + mprime, ccol, crow, nrows, ncols, + dmin); +} + +void mtdev_match(int ix[DIM_FINGER], int A[DIM2_FINGER], int nrow, int ncol) +{ + ixoptimal(ix, A, nrow, ncol); +} + diff --git a/src/match.h b/src/match.h new file mode 100644 index 0000000..efba6f5 --- /dev/null +++ b/src/match.h @@ -0,0 +1,51 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#ifndef MATCHER_H +#define MATCHER_H + +/** + * Special implementation of the hungarian algorithm. + * The maximum number of fingers matches a uint32. + * Bitmasks are used extensively. + */ + +#include "common.h" + +void mtdev_match(int index[DIM_FINGER], int A[DIM2_FINGER], + int nrow, int ncol); + +struct trk_coord { + int x; + int y; +}; + +const unsigned char *mtdev_match_four(const struct trk_coord *old, int nslot, + const struct trk_coord *pos, int npos); + +#endif diff --git a/src/match_four.c b/src/match_four.c new file mode 100644 index 0000000..c7d2cd3 --- /dev/null +++ b/src/match_four.c @@ -0,0 +1,129 @@ +#include "match.h" +#include + +typedef unsigned char u8; +typedef unsigned int u32; + +/* generated by mtdev-kernel - do not edit */ +static const u8 match_data[] = { + 0, 0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 1, 2, 1, 1, 0, 2, 2, 1, 2, 0, 0, 0, + 1, 2, 3, 1, 1, 0, 2, 3, 2, 1, 2, 0, 3, 3, 1, 2, + 3, 0, 0, 0, 1, 1, 1, 2, 1, 0, 0, 3, 0, 1, 1, 3, + 1, 0, 2, 2, 3, 1, 2, 0, 0, 4, 0, 1, 2, 2, 4, 2, + 1, 0, 0, 5, 0, 2, 1, 1, 5, 2, 0, 1, 1, 4, 1, 0, + 2, 3, 2, 4, 1, 2, 0, 3, 3, 4, 1, 2, 3, 0, 0, 5, + 0, 1, 2, 3, 2, 5, 2, 1, 0, 3, 3, 5, 2, 1, 3, 0, + 0, 6, 0, 2, 1, 3, 1, 6, 2, 0, 1, 3, 3, 6, 2, 3, + 1, 0, 0, 7, 0, 2, 3, 1, 1, 7, 2, 0, 3, 1, 2, 7, + 2, 3, 0, 1, 0, 0, 1, 1, 2, 2, 1, 2, 1, 0, 0, 3, + 0, 1, 1, 4, 2, 0, 3, 4, 2, 1, 0, 5, 0, 2, 2, 5, + 1, 2, 2, 4, 6, 2, 1, 0, 1, 5, 6, 2, 0, 1, 2, 3, + 7, 1, 2, 0, 0, 5, 7, 0, 2, 1, 1, 3, 8, 1, 0, 2, + 0, 4, 8, 0, 1, 2, 2, 5, 8, 2, 1, 0, 3, 3, 5, 8, + 2, 1, 3, 0, 1, 6, 8, 2, 0, 1, 3, 3, 6, 8, 2, 3, + 1, 0, 1, 7, 8, 2, 0, 3, 1, 2, 7, 8, 2, 3, 0, 1, + 2, 4, 9, 1, 2, 0, 3, 3, 4, 9, 1, 2, 3, 0, 0, 6, + 9, 0, 2, 1, 3, 3, 6, 9, 3, 2, 1, 0, 0, 7, 9, 0, + 2, 3, 1, 2, 7, 9, 3, 2, 0, 1, 1, 4, 10, 1, 0, 2, + 3, 3, 4, 10, 1, 3, 2, 0, 0, 5, 10, 0, 1, 2, 3, 3, + 5, 10, 3, 1, 2, 0, 0, 7, 10, 0, 3, 2, 1, 1, 7, 10, + 3, 0, 2, 1, 1, 4, 11, 1, 0, 3, 2, 2, 4, 11, 1, 3, + 0, 2, 0, 5, 11, 0, 1, 3, 2, 2, 5, 11, 3, 1, 0, 2, + 0, 6, 11, 0, 3, 1, 2, 1, 6, 11, 3, 0, 1, 2, 0, 0, + 1, 1, 2, 2, 3, 3, 1, 2, 1, 0, 0, 3, 0, 1, 1, 4, + 2, 0, 3, 4, 2, 1, 0, 5, 0, 2, 2, 5, 1, 2, 1, 6, + 3, 0, 3, 6, 3, 1, 5, 6, 3, 2, 0, 7, 0, 3, 2, 7, + 1, 3, 4, 7, 2, 3, 2, 4, 6, 2, 1, 0, 1, 5, 6, 2, + 0, 1, 2, 3, 7, 1, 2, 0, 0, 5, 7, 0, 2, 1, 1, 3, + 8, 1, 0, 2, 0, 4, 8, 0, 1, 2, 2, 4, 9, 3, 1, 0, + 1, 5, 9, 3, 0, 1, 2, 7, 9, 3, 2, 0, 5, 7, 9, 3, + 2, 1, 1, 8, 9, 3, 0, 2, 4, 8, 9, 3, 1, 2, 2, 3, + 10, 1, 3, 0, 0, 5, 10, 0, 3, 1, 2, 6, 10, 2, 3, 0, + 5, 6, 10, 2, 3, 1, 0, 8, 10, 0, 3, 2, 3, 8, 10, 1, + 3, 2, 1, 3, 11, 1, 0, 3, 0, 4, 11, 0, 1, 3, 1, 6, + 11, 2, 0, 3, 4, 6, 11, 2, 1, 3, 0, 7, 11, 0, 2, 3, + 3, 7, 11, 1, 2, 3, 3, 6, 9, 12, 3, 2, 1, 0, 2, 7, + 9, 12, 3, 2, 0, 1, 3, 5, 10, 12, 3, 1, 2, 0, 1, 7, + 10, 12, 3, 0, 2, 1, 2, 5, 11, 12, 3, 1, 0, 2, 1, 6, + 11, 12, 3, 0, 1, 2, 3, 6, 8, 13, 2, 3, 1, 0, 2, 7, + 8, 13, 2, 3, 0, 1, 3, 4, 10, 13, 1, 3, 2, 0, 0, 7, + 10, 13, 0, 3, 2, 1, 2, 4, 11, 13, 1, 3, 0, 2, 0, 6, + 11, 13, 0, 3, 1, 2, 3, 5, 8, 14, 2, 1, 3, 0, 1, 7, + 8, 14, 2, 0, 3, 1, 3, 4, 9, 14, 1, 2, 3, 0, 0, 7, + 9, 14, 0, 2, 3, 1, 1, 4, 11, 14, 1, 0, 3, 2, 0, 5, + 11, 14, 0, 1, 3, 2, 2, 5, 8, 15, 2, 1, 0, 3, 1, 6, + 8, 15, 2, 0, 1, 3, 2, 4, 9, 15, 1, 2, 0, 3, 0, 6, + 9, 15, 0, 2, 1, 3, 1, 4, 10, 15, 1, 0, 2, 3, 0, 5, + 10, 15, 0, 1, 2, 3, +}; + +/* generated by mtdev-kernel - do not edit */ +static const int match_index[][5] = { + { 0, 0, 1, 3, 6 }, + { 10, 10, 12, 18, 30 }, + { 50, 50, 54, 62, 92 }, + { 164, 164, 170, 194, 230 }, + { 398, 398, 406, 454, 598 }, + { 790 } +}; + +static void set_dist(u32 *dist, + const struct trk_coord *b1, const struct trk_coord *e1, + const struct trk_coord *b2, const struct trk_coord *e2) +{ + const struct trk_coord *p, *q; + + for (p = b1; p != e1; p++) + for (q = b2; q != e2; q++) + *dist++ = abs(q->x - p->x) + abs(q->y - p->y); +} + +const u8 *mtdev_match_four(const struct trk_coord *old, int nslot, + const struct trk_coord *pos, int npos) +{ + u32 d[16], obj, t; + const u8 *p, *b, *e; + const int *at; + + set_dist(d, old, old + nslot, pos, pos + npos); + + at = &match_index[nslot][npos]; + b = &match_data[at[0]]; + e = &match_data[at[1]]; + + obj = UINT_MAX, p = b; + + switch (minval(nslot, npos)) { + case 1: + for (; b != e; b += npos) { + t = d[*b++]; + if (t < obj) + obj = t, p = b; + } + break; + case 2: + for (; b != e; b += npos) { + t = d[*b++], t += d[*b++]; + if (t < obj) + obj = t, p = b; + } + break; + case 3: + for (; b != e; b += npos) { + t = d[*b++], t += d[*b++], t += d[*b++]; + if (t < obj) + obj = t, p = b; + } + break; + case 4: + for (; b != e; b += npos) { + t = d[*b++], t += d[*b++], t += d[*b++], t += d[*b++]; + if (t < obj) + obj = t, p = b; + } + break; + } + + return p; +} diff --git a/src/state.h b/src/state.h new file mode 100644 index 0000000..256858a --- /dev/null +++ b/src/state.h @@ -0,0 +1,88 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#ifndef MTDEV_STATE_H +#define MTDEV_STATE_H + +#include "iobuf.h" +#include "evbuf.h" + +/* + * struct mtdev_slot - represents the state of an input MT slot + * @abs: current values of ABS_MT axes for this slot + */ +struct mtdev_slot { + int touch_major; + int touch_minor; + int width_major; + int width_minor; + int orientation; + int position_x; + int position_y; + int tool_type; + int blob_id; + int tracking_id; + int pressure; + int distance; +}; + +static inline int get_sval(const struct mtdev_slot *slot, int ix) +{ + return (&slot->touch_major)[ix]; +} + +static inline void set_sval(struct mtdev_slot *slot, int ix, int value) +{ + (&slot->touch_major)[ix] = value; +} + +/* + * struct mtdev_state - MT slot parsing + * @inbuf: input event buffer + * @outbuf: output event buffer + * @data: array of scratch slot data + * @used: bitmask of currently used slots + * @slot: slot currently being modified + * @lastid: last used tracking id + */ +struct mtdev_state { + + int has_ext_abs[MT_ABS_SIZE - 11]; + struct input_absinfo ext_abs[MT_ABS_SIZE - 11]; + + struct mtdev_iobuf iobuf; + struct mtdev_evbuf inbuf; + struct mtdev_evbuf outbuf; + struct mtdev_slot data[DIM_FINGER]; + + bitmask_t used; + bitmask_t slot; + bitmask_t lastid; +}; + +#endif -- cgit v1.2.1