Repository: xmake-io/xmake Branch: dev Commit: 84634aa837ef Files: 4126 Total size: 13.7 MB Directory structure: gitextract_jls52xg_/ ├── .clang-format ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── alpine.yml │ ├── archlinux.yml │ ├── cosmocc.yml │ ├── dragonflybsd.yml │ ├── fedora.yml │ ├── freebsd.yml │ ├── haiku.yml │ ├── issue-translator.yml │ ├── linux.yml │ ├── linux_arm64.yml │ ├── linux_luajit.yml │ ├── macos.yml │ ├── macos_arm64.yml │ ├── msys2_mingw.yml │ ├── netbsd.yml │ ├── openbsd.yml │ ├── solaris.yml │ ├── windows.yml │ └── windows_luajit.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── NOTICE.md ├── README.md ├── README_zh.md ├── configure ├── core/ │ ├── src/ │ │ ├── cli/ │ │ │ ├── xmake.c │ │ │ ├── xmake.lua │ │ │ ├── xmake.rc │ │ │ └── xmake.sh │ │ ├── lua/ │ │ │ ├── xmake.lua │ │ │ └── xmake.sh │ │ ├── lua-cjson/ │ │ │ ├── xmake.lua │ │ │ └── xmake.sh │ │ ├── luajit/ │ │ │ ├── xmake.lua │ │ │ └── xmake.sh │ │ ├── lz4/ │ │ │ ├── xmake.lua │ │ │ └── xmake.sh │ │ ├── pdcurses/ │ │ │ └── xmake.lua │ │ ├── sv/ │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── xmake.lua │ │ │ └── xmake.sh │ │ ├── tbox/ │ │ │ ├── inc/ │ │ │ │ ├── bsd/ │ │ │ │ │ └── tbox.config.h │ │ │ │ ├── cygwin/ │ │ │ │ │ └── tbox.config.h │ │ │ │ ├── haiku/ │ │ │ │ │ └── tbox.config.h │ │ │ │ ├── iphoneos/ │ │ │ │ │ └── tbox.config.h │ │ │ │ ├── linux/ │ │ │ │ │ └── tbox.config.h │ │ │ │ ├── macosx/ │ │ │ │ │ └── tbox.config.h │ │ │ │ ├── mingw/ │ │ │ │ │ └── tbox.config.h │ │ │ │ ├── msys/ │ │ │ │ │ └── tbox.config.h │ │ │ │ └── solaris/ │ │ │ │ └── tbox.config.h │ │ │ ├── xmake.lua │ │ │ └── xmake.sh │ │ ├── xmake/ │ │ │ ├── base64/ │ │ │ │ ├── decode.c │ │ │ │ ├── encode.c │ │ │ │ └── prefix.h │ │ │ ├── binutils/ │ │ │ │ ├── ar/ │ │ │ │ │ ├── extractlib.c │ │ │ │ │ ├── prefix.h │ │ │ │ │ └── readsyms.c │ │ │ │ ├── bin2c.c │ │ │ │ ├── coff/ │ │ │ │ │ ├── bin2coff.c │ │ │ │ │ ├── deplibs.c │ │ │ │ │ ├── prefix.h │ │ │ │ │ └── readsyms.c │ │ │ │ ├── deplibs.c │ │ │ │ ├── elf/ │ │ │ │ │ ├── bin2elf.c │ │ │ │ │ ├── deplibs.c │ │ │ │ │ ├── prefix.h │ │ │ │ │ ├── readsyms.c │ │ │ │ │ └── rpath.c │ │ │ │ ├── extractlib.c │ │ │ │ ├── format.c │ │ │ │ ├── macho/ │ │ │ │ │ ├── bin2macho.c │ │ │ │ │ ├── deplibs.c │ │ │ │ │ ├── prefix.h │ │ │ │ │ ├── readsyms.c │ │ │ │ │ └── rpath.c │ │ │ │ ├── mslib/ │ │ │ │ │ ├── extractlib.c │ │ │ │ │ ├── prefix.h │ │ │ │ │ └── readsyms.c │ │ │ │ ├── prefix.h │ │ │ │ ├── readsyms.c │ │ │ │ ├── rpath.c │ │ │ │ └── wasm/ │ │ │ │ ├── prefix.h │ │ │ │ └── readsyms.c │ │ │ ├── bloom_filter/ │ │ │ │ ├── bloom_filter_clear.c │ │ │ │ ├── bloom_filter_close.c │ │ │ │ ├── bloom_filter_data.c │ │ │ │ ├── bloom_filter_data_set.c │ │ │ │ ├── bloom_filter_get.c │ │ │ │ ├── bloom_filter_open.c │ │ │ │ ├── bloom_filter_set.c │ │ │ │ ├── bloom_filter_size.c │ │ │ │ └── prefix.h │ │ │ ├── config.h │ │ │ ├── curses/ │ │ │ │ ├── curses.c │ │ │ │ └── prefix.h │ │ │ ├── engine.c │ │ │ ├── engine.h │ │ │ ├── engine_pool.c │ │ │ ├── engine_pool.h │ │ │ ├── fwatcher/ │ │ │ │ ├── add.c │ │ │ │ ├── close.c │ │ │ │ ├── open.c │ │ │ │ ├── prefix.h │ │ │ │ ├── remove.c │ │ │ │ └── wait.c │ │ │ ├── hash/ │ │ │ │ ├── md5.c │ │ │ │ ├── prefix.h │ │ │ │ ├── rand128.c │ │ │ │ ├── rand32.c │ │ │ │ ├── rand64.c │ │ │ │ ├── sha.c │ │ │ │ ├── uuid4.c │ │ │ │ └── xxhash.c │ │ │ ├── io/ │ │ │ │ ├── file_close.c │ │ │ │ ├── file_convert.c │ │ │ │ ├── file_flush.c │ │ │ │ ├── file_isatty.c │ │ │ │ ├── file_open.c │ │ │ │ ├── file_rawfd.c │ │ │ │ ├── file_read.c │ │ │ │ ├── file_readable.c │ │ │ │ ├── file_seek.c │ │ │ │ ├── file_size.c │ │ │ │ ├── file_write.c │ │ │ │ ├── filelock_close.c │ │ │ │ ├── filelock_lock.c │ │ │ │ ├── filelock_open.c │ │ │ │ ├── filelock_trylock.c │ │ │ │ ├── filelock_unlock.c │ │ │ │ ├── iscygpty.c │ │ │ │ ├── pipe_close.c │ │ │ │ ├── pipe_connect.c │ │ │ │ ├── pipe_open.c │ │ │ │ ├── pipe_openpair.c │ │ │ │ ├── pipe_read.c │ │ │ │ ├── pipe_wait.c │ │ │ │ ├── pipe_write.c │ │ │ │ ├── poller.c │ │ │ │ ├── poller.h │ │ │ │ ├── poller_insert.c │ │ │ │ ├── poller_modify.c │ │ │ │ ├── poller_remove.c │ │ │ │ ├── poller_spank.c │ │ │ │ ├── poller_support.c │ │ │ │ ├── poller_wait.c │ │ │ │ ├── prefix.h │ │ │ │ ├── socket_accept.c │ │ │ │ ├── socket_bind.c │ │ │ │ ├── socket_close.c │ │ │ │ ├── socket_connect.c │ │ │ │ ├── socket_ctrl.c │ │ │ │ ├── socket_kill.c │ │ │ │ ├── socket_listen.c │ │ │ │ ├── socket_open.c │ │ │ │ ├── socket_peeraddr.c │ │ │ │ ├── socket_rawfd.c │ │ │ │ ├── socket_recv.c │ │ │ │ ├── socket_recvfrom.c │ │ │ │ ├── socket_send.c │ │ │ │ ├── socket_sendfile.c │ │ │ │ ├── socket_sendto.c │ │ │ │ ├── socket_wait.c │ │ │ │ └── stdfile.c │ │ │ ├── libc/ │ │ │ │ ├── byteof.c │ │ │ │ ├── dataptr.c │ │ │ │ ├── free.c │ │ │ │ ├── malloc.c │ │ │ │ ├── memcpy.c │ │ │ │ ├── memmov.c │ │ │ │ ├── memset.c │ │ │ │ ├── prefix.h │ │ │ │ ├── setbyte.c │ │ │ │ └── strndup.c │ │ │ ├── lz4/ │ │ │ │ ├── block_compress.c │ │ │ │ ├── block_decompress.c │ │ │ │ ├── compress.c │ │ │ │ ├── compress_file.c │ │ │ │ ├── compress_stream_close.c │ │ │ │ ├── compress_stream_open.c │ │ │ │ ├── compress_stream_read.c │ │ │ │ ├── compress_stream_write.c │ │ │ │ ├── decompress.c │ │ │ │ ├── decompress_file.c │ │ │ │ ├── decompress_stream_close.c │ │ │ │ ├── decompress_stream_open.c │ │ │ │ ├── decompress_stream_read.c │ │ │ │ ├── decompress_stream_write.c │ │ │ │ └── prefix.h │ │ │ ├── os/ │ │ │ │ ├── access.c │ │ │ │ ├── args.c │ │ │ │ ├── argv.c │ │ │ │ ├── chdir.c │ │ │ │ ├── cpdir.c │ │ │ │ ├── cpfile.c │ │ │ │ ├── cpuinfo.c │ │ │ │ ├── curdir.c │ │ │ │ ├── emptydir.c │ │ │ │ ├── exists.c │ │ │ │ ├── filesize.c │ │ │ │ ├── find.c │ │ │ │ ├── fscase.c │ │ │ │ ├── getenv.c │ │ │ │ ├── getenvs.c │ │ │ │ ├── getown.c │ │ │ │ ├── getpid.c │ │ │ │ ├── getwinsize.c │ │ │ │ ├── gid.c │ │ │ │ ├── isdir.c │ │ │ │ ├── isfile.c │ │ │ │ ├── islink.c │ │ │ │ ├── link.c │ │ │ │ ├── mclock.c │ │ │ │ ├── meminfo.c │ │ │ │ ├── mkdir.c │ │ │ │ ├── mtime.c │ │ │ │ ├── prefix.h │ │ │ │ ├── processes.c │ │ │ │ ├── readlink.c │ │ │ │ ├── rename.c │ │ │ │ ├── rmdir.c │ │ │ │ ├── rmfile.c │ │ │ │ ├── setenv.c │ │ │ │ ├── signal.c │ │ │ │ ├── sleep.c │ │ │ │ ├── strerror.c │ │ │ │ ├── syserror.c │ │ │ │ ├── tmpdir.c │ │ │ │ ├── touch.c │ │ │ │ └── uid.c │ │ │ ├── package/ │ │ │ │ ├── loadxmi.c │ │ │ │ └── prefix.h │ │ │ ├── path/ │ │ │ │ ├── absolute.c │ │ │ │ ├── directory.c │ │ │ │ ├── is_absolute.c │ │ │ │ ├── prefix.h │ │ │ │ ├── relative.c │ │ │ │ └── translate.c │ │ │ ├── prefix/ │ │ │ │ ├── config.h │ │ │ │ ├── prefix.h │ │ │ │ └── version.h │ │ │ ├── prefix.h │ │ │ ├── process/ │ │ │ │ ├── close.c │ │ │ │ ├── kill.c │ │ │ │ ├── open.c │ │ │ │ ├── openv.c │ │ │ │ ├── prefix.h │ │ │ │ └── wait.c │ │ │ ├── readline/ │ │ │ │ ├── add_history.c │ │ │ │ ├── clear_history.c │ │ │ │ ├── history_list.c │ │ │ │ ├── prefix.h │ │ │ │ └── readline.c │ │ │ ├── sandbox/ │ │ │ │ ├── interactive.c │ │ │ │ └── prefix.h │ │ │ ├── semver/ │ │ │ │ ├── compare.c │ │ │ │ ├── parse.c │ │ │ │ ├── prefix.h │ │ │ │ ├── satisfies.c │ │ │ │ ├── select.c │ │ │ │ └── semver.c │ │ │ ├── string/ │ │ │ │ ├── convert.c │ │ │ │ ├── endswith.c │ │ │ │ ├── lastof.c │ │ │ │ ├── lower.c │ │ │ │ ├── prefix.h │ │ │ │ ├── split.c │ │ │ │ ├── startswith.c │ │ │ │ ├── trim.c │ │ │ │ └── upper.c │ │ │ ├── thread/ │ │ │ │ ├── event_exit.c │ │ │ │ ├── event_incref.c │ │ │ │ ├── event_init.c │ │ │ │ ├── event_post.c │ │ │ │ ├── event_wait.c │ │ │ │ ├── mutex_exit.c │ │ │ │ ├── mutex_incref.c │ │ │ │ ├── mutex_init.c │ │ │ │ ├── mutex_lock.c │ │ │ │ ├── mutex_trylock.c │ │ │ │ ├── mutex_unlock.c │ │ │ │ ├── prefix.h │ │ │ │ ├── queue_clear.c │ │ │ │ ├── queue_exit.c │ │ │ │ ├── queue_incref.c │ │ │ │ ├── queue_init.c │ │ │ │ ├── queue_pop.c │ │ │ │ ├── queue_push.c │ │ │ │ ├── queue_size.c │ │ │ │ ├── semaphore_exit.c │ │ │ │ ├── semaphore_incref.c │ │ │ │ ├── semaphore_init.c │ │ │ │ ├── semaphore_post.c │ │ │ │ ├── semaphore_wait.c │ │ │ │ ├── sharedata_clear.c │ │ │ │ ├── sharedata_exit.c │ │ │ │ ├── sharedata_get.c │ │ │ │ ├── sharedata_incref.c │ │ │ │ ├── sharedata_init.c │ │ │ │ ├── sharedata_set.c │ │ │ │ ├── thread_exit.c │ │ │ │ ├── thread_init.c │ │ │ │ ├── thread_resume.c │ │ │ │ ├── thread_suspend.c │ │ │ │ └── thread_wait.c │ │ │ ├── tty/ │ │ │ │ ├── prefix.h │ │ │ │ ├── session_id.c │ │ │ │ └── term_mode.c │ │ │ ├── utf8/ │ │ │ │ ├── byte.c │ │ │ │ ├── char.c │ │ │ │ ├── codepoint.c │ │ │ │ ├── codes.c │ │ │ │ ├── find.c │ │ │ │ ├── lastof.c │ │ │ │ ├── len.c │ │ │ │ ├── offset.c │ │ │ │ ├── prefix.h │ │ │ │ ├── reverse.c │ │ │ │ ├── sub.c │ │ │ │ ├── utf8.c │ │ │ │ ├── utf8.h │ │ │ │ └── width.c │ │ │ ├── utils/ │ │ │ │ ├── charset.c │ │ │ │ ├── charset.h │ │ │ │ └── prefix.h │ │ │ ├── winos/ │ │ │ │ ├── ansi.c │ │ │ │ ├── ansi.h │ │ │ │ ├── file_signature.c │ │ │ │ ├── logical_drives.c │ │ │ │ ├── prefix.h │ │ │ │ ├── registry_keys.c │ │ │ │ ├── registry_query.c │ │ │ │ ├── registry_values.c │ │ │ │ ├── set_error_mode.c │ │ │ │ └── short_path.c │ │ │ ├── xmake.c │ │ │ ├── xmake.config.h.in │ │ │ ├── xmake.h │ │ │ ├── xmake.lua │ │ │ └── xmake.sh │ │ └── xxhash/ │ │ └── xxhash/ │ │ ├── LICENSE │ │ └── xxhash.h │ ├── xmake.lua │ ├── xmake.sh │ └── xpack.lua ├── scripts/ │ ├── debian/ │ │ ├── README.Debian │ │ ├── README.source │ │ ├── changelog │ │ ├── compat │ │ ├── control │ │ ├── copyright │ │ ├── init.d.ex │ │ ├── manpage.1.ex │ │ ├── manpage.sgml.ex │ │ ├── manpage.xml.ex │ │ ├── menu.ex │ │ ├── postinst.ex │ │ ├── postrm.ex │ │ ├── preinst.ex │ │ ├── prerm.ex │ │ ├── rules │ │ ├── source/ │ │ │ └── format │ │ ├── watch.ex │ │ ├── xmake-docs.docs │ │ ├── xmake.cron.d.ex │ │ ├── xmake.default.ex │ │ └── xmake.doc-base.EX │ ├── get.ps1 │ ├── get.sh │ ├── makeppa │ ├── man/ │ │ ├── xmake.1 │ │ └── xrepo.1 │ ├── msys/ │ │ ├── xmake.cmd │ │ ├── xmake.ps1 │ │ └── xmake.sh │ ├── rpmbuild/ │ │ ├── 0001-use-static-libsv-and-tbox.patch │ │ └── xmake.spec │ ├── srcenv.bat │ ├── srcenv.profile │ ├── srcenv.ps1 │ ├── xrepo.bat │ ├── xrepo.ps1 │ └── xrepo.sh ├── tests/ │ ├── actions/ │ │ ├── config/ │ │ │ ├── .gitignore │ │ │ └── test.lua │ │ ├── install/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ ├── foo.cpp │ │ │ │ ├── foo.h │ │ │ │ ├── foo.txt │ │ │ │ └── main.cpp │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── package/ │ │ │ └── localpkg/ │ │ │ ├── bar/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── libfoo/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── add.cpp │ │ │ │ │ ├── add.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ ├── sub.cpp │ │ │ │ │ └── sub.h │ │ │ │ └── xmake.lua │ │ │ └── test.lua │ │ └── test/ │ │ ├── .gitignore │ │ ├── outputs/ │ │ │ ├── fail_hello_xmake.txt │ │ │ └── pass_hello_foo.txt │ │ ├── src/ │ │ │ ├── compile_1.cpp │ │ │ ├── compile_2.cpp │ │ │ ├── run_timeout.cpp │ │ │ ├── test_1.cpp │ │ │ ├── test_2.cpp │ │ │ ├── test_3.cpp │ │ │ ├── test_4.cpp │ │ │ ├── test_5.cpp │ │ │ ├── test_6.cpp │ │ │ ├── test_7.cpp │ │ │ ├── test_8.cpp │ │ │ └── test_9.cpp │ │ ├── test.lua │ │ ├── tests/ │ │ │ ├── stub_1.cpp │ │ │ ├── stub_2.cpp │ │ │ ├── stub_n1.cpp │ │ │ └── stub_n2.cpp │ │ └── xmake.lua │ ├── apis/ │ │ ├── add_allowedxxx/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── add_configfiles/ │ │ │ ├── config.h.in │ │ │ ├── config2.h.in │ │ │ ├── hello.man │ │ │ ├── main.c │ │ │ ├── main2.c │ │ │ ├── test.c.in │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── add_defines/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── add_deps/ │ │ │ ├── inc1/ │ │ │ │ └── stub.h │ │ │ ├── inc2/ │ │ │ │ └── stub.h │ │ │ ├── inc3/ │ │ │ │ └── stub.h │ │ │ ├── inc4/ │ │ │ │ └── stub.h │ │ │ ├── src/ │ │ │ │ ├── interface.c │ │ │ │ ├── interface.h │ │ │ │ └── main.c │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── add_imports/ │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── add_xxx/ │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── check_xxx/ │ │ │ ├── config.h.in │ │ │ ├── foo.c │ │ │ ├── main.c │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── clone_target/ │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── custom_scopeapis/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── custom_toolchain/ │ │ │ ├── src/ │ │ │ │ ├── foo.cpp │ │ │ │ ├── foo.h │ │ │ │ └── test.cpp │ │ │ ├── xmake/ │ │ │ │ ├── modules/ │ │ │ │ │ ├── core/ │ │ │ │ │ │ └── tools/ │ │ │ │ │ │ ├── ar6x.lua │ │ │ │ │ │ ├── cl6x/ │ │ │ │ │ │ │ ├── has_flags.lua │ │ │ │ │ │ │ └── parse_deps.lua │ │ │ │ │ │ └── cl6x.lua │ │ │ │ │ └── detect/ │ │ │ │ │ └── tools/ │ │ │ │ │ ├── find_ar6x.lua │ │ │ │ │ └── find_cl6x.lua │ │ │ │ └── toolchains/ │ │ │ │ └── my-c6000/ │ │ │ │ └── xmake.lua │ │ │ └── xmake.lua │ │ ├── namespace/ │ │ │ ├── basic/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── includes/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── xmake.lua │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── inner/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── nested/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── option/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── package/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── root/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── rule/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── task/ │ │ │ │ ├── .gitignore │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ └── toolchain/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ ├── bar.cpp │ │ │ │ ├── bar.h │ │ │ │ ├── foo.cpp │ │ │ │ ├── foo.h │ │ │ │ └── main.cpp │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── rules/ │ │ │ ├── src/ │ │ │ │ ├── empty.stub │ │ │ │ ├── index.md │ │ │ │ ├── main.c │ │ │ │ ├── main2.c │ │ │ │ ├── man/ │ │ │ │ │ ├── man1.in │ │ │ │ │ ├── man2.in │ │ │ │ │ └── man3.in │ │ │ │ └── test.c.in │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── rules_inject_deps/ │ │ │ ├── src/ │ │ │ │ ├── main.cpp │ │ │ │ └── main.cpp2 │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── rules_order/ │ │ │ ├── src/ │ │ │ │ ├── main.c │ │ │ │ ├── test.man │ │ │ │ └── test.md │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── rules_override_cxx/ │ │ │ ├── src/ │ │ │ │ ├── main.xx │ │ │ │ └── test.cc │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── set_toolchains/ │ │ │ ├── src/ │ │ │ │ ├── foo.cpp │ │ │ │ ├── foo.h │ │ │ │ └── test.cpp │ │ │ └── xmake.lua │ │ ├── target_get_from/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ ├── foo.cpp │ │ │ │ ├── foo.h │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ └── xxx_script/ │ │ ├── test.lua │ │ └── xmake.lua │ ├── benchmarks/ │ │ ├── async/ │ │ │ └── runjobs.lua │ │ ├── build_targets/ │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── meson.build │ │ │ ├── src/ │ │ │ │ ├── test_1.cpp │ │ │ │ ├── test_10.cpp │ │ │ │ ├── test_11.cpp │ │ │ │ ├── test_12.cpp │ │ │ │ ├── test_13.cpp │ │ │ │ ├── test_14.cpp │ │ │ │ ├── test_15.cpp │ │ │ │ ├── test_16.cpp │ │ │ │ ├── test_17.cpp │ │ │ │ ├── test_18.cpp │ │ │ │ ├── test_19.cpp │ │ │ │ ├── test_2.cpp │ │ │ │ ├── test_20.cpp │ │ │ │ ├── test_21.cpp │ │ │ │ ├── test_22.cpp │ │ │ │ ├── test_23.cpp │ │ │ │ ├── test_24.cpp │ │ │ │ ├── test_25.cpp │ │ │ │ ├── test_26.cpp │ │ │ │ ├── test_27.cpp │ │ │ │ ├── test_28.cpp │ │ │ │ ├── test_29.cpp │ │ │ │ ├── test_3.cpp │ │ │ │ ├── test_30.cpp │ │ │ │ ├── test_4.cpp │ │ │ │ ├── test_5.cpp │ │ │ │ ├── test_6.cpp │ │ │ │ ├── test_7.cpp │ │ │ │ ├── test_8.cpp │ │ │ │ └── test_9.cpp │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── config_targets/ │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── meson.build │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ └── hash.lua │ ├── cli/ │ │ ├── test.lua │ │ └── utils/ │ │ └── test.lua │ ├── modules/ │ │ ├── async/ │ │ │ ├── run_callback.lua │ │ │ ├── run_jobgraph.lua │ │ │ └── run_jobpool.lua │ │ ├── binutils/ │ │ │ └── test.lua │ │ ├── bloom_filter/ │ │ │ └── test.lua │ │ ├── bytes/ │ │ │ └── test.lua │ │ ├── cache/ │ │ │ └── test.lua │ │ ├── compress/ │ │ │ └── test.lua │ │ ├── devel/ │ │ │ └── git/ │ │ │ └── test.lua │ │ ├── fwatcher/ │ │ │ ├── on_created.lua │ │ │ ├── on_deleted.lua │ │ │ ├── on_modified.lua │ │ │ ├── sched_watchdir.lua │ │ │ ├── watchdir.lua │ │ │ └── watchdirs.lua │ │ ├── graph/ │ │ │ └── test.lua │ │ ├── hash/ │ │ │ └── test.lua │ │ ├── hashset/ │ │ │ └── test.lua │ │ ├── heap/ │ │ │ └── test.lua │ │ ├── hello/ │ │ │ └── test.lua │ │ ├── io/ │ │ │ ├── files/ │ │ │ │ ├── .gitattributes │ │ │ │ ├── utf16be-lf-eleof │ │ │ │ ├── utf16le-crlf-neleof │ │ │ │ ├── utf8-crlf-neleof │ │ │ │ ├── utf8-longline-eleof │ │ │ │ ├── utf8-longline-neleof │ │ │ │ └── utf8bom-lf-eleof │ │ │ └── test.lua │ │ ├── jobgraph/ │ │ │ └── test.lua │ │ ├── json/ │ │ │ └── test.lua │ │ ├── lib/ │ │ │ └── detect/ │ │ │ └── test.lua │ │ ├── list/ │ │ │ └── test.lua │ │ ├── math/ │ │ │ └── test.lua │ │ ├── os/ │ │ │ ├── async_copy.lua │ │ │ ├── async_scheduler.lua │ │ │ ├── cpuinfo.lua │ │ │ ├── meminfo.lua │ │ │ └── test.lua │ │ ├── path/ │ │ │ └── test.lua │ │ ├── pipe/ │ │ │ ├── echo_client.lua │ │ │ ├── echo_server.lua │ │ │ ├── pipe_pair.lua │ │ │ ├── sched_echo_client.lua │ │ │ ├── sched_echo_server.lua │ │ │ └── sched_pipe_pair.lua │ │ ├── private/ │ │ │ └── select_script/ │ │ │ └── test.lua │ │ ├── process/ │ │ │ ├── process_autoexit.lua │ │ │ ├── process_killed.lua │ │ │ ├── sched_process.lua │ │ │ ├── sched_process_pipe.lua │ │ │ └── test.lua │ │ ├── queue/ │ │ │ └── test.lua │ │ ├── scheduler/ │ │ │ ├── semaphore.lua │ │ │ ├── sleep.lua │ │ │ ├── spinner.lua │ │ │ ├── test.lua │ │ │ └── yield.lua │ │ ├── semver/ │ │ │ └── test.lua │ │ ├── signal/ │ │ │ └── sigint.lua │ │ ├── socket/ │ │ │ ├── sched_tcp/ │ │ │ │ ├── echo_client.lua │ │ │ │ ├── echo_server.lua │ │ │ │ ├── file_client.lua │ │ │ │ └── file_server.lua │ │ │ ├── sched_udp/ │ │ │ │ ├── echo_client.lua │ │ │ │ └── echo_server.lua │ │ │ ├── tcp/ │ │ │ │ ├── echo_client.lua │ │ │ │ ├── echo_server.lua │ │ │ │ ├── file_client.lua │ │ │ │ └── file_server.lua │ │ │ ├── udp/ │ │ │ │ ├── echo_client.lua │ │ │ │ └── echo_server.lua │ │ │ └── unix_tcp/ │ │ │ ├── echo_client.lua │ │ │ ├── echo_server.lua │ │ │ ├── file_client.lua │ │ │ └── file_server.lua │ │ ├── stdin/ │ │ │ └── test.lua │ │ ├── string/ │ │ │ ├── lastof_perf.lua │ │ │ ├── serialize/ │ │ │ │ └── test.lua │ │ │ ├── split_perf.lua │ │ │ └── test.lua │ │ ├── table/ │ │ │ └── test.lua │ │ ├── thread/ │ │ │ ├── coroutine.lua │ │ │ ├── event.lua │ │ │ ├── mutex.lua │ │ │ ├── queue.lua │ │ │ ├── semaphore.lua │ │ │ ├── sharedata.lua │ │ │ └── sleep.lua │ │ ├── tty/ │ │ │ ├── cursor_control.lua │ │ │ ├── live_dashboard.lua │ │ │ ├── quick_example.lua │ │ │ └── test.lua │ │ ├── utf8/ │ │ │ └── test.lua │ │ └── xml/ │ │ └── test.lua │ ├── plugins/ │ │ ├── create/ │ │ │ └── test.lua │ │ ├── macro/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── pack/ │ │ │ ├── console/ │ │ │ │ ├── .gitignore │ │ │ │ ├── LICENSE.md │ │ │ │ ├── include/ │ │ │ │ │ ├── foo/ │ │ │ │ │ │ └── foo.h │ │ │ │ │ └── test.h │ │ │ │ ├── src/ │ │ │ │ │ ├── assets/ │ │ │ │ │ │ ├── file1.txt │ │ │ │ │ │ └── file2.txt │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── xmake.rc │ │ │ │ └── xmake.lua │ │ │ ├── macapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── AppDelegate.h │ │ │ │ │ ├── AppDelegate.m │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── ViewController.h │ │ │ │ │ ├── ViewController.m │ │ │ │ │ └── main.m │ │ │ │ └── xmake.lua │ │ │ └── qtapp/ │ │ │ ├── src/ │ │ │ │ ├── main.cpp │ │ │ │ ├── mainwindow.cpp │ │ │ │ ├── mainwindow.h │ │ │ │ └── mainwindow.ui │ │ │ └── xmake.lua │ │ └── project/ │ │ └── test.lua │ ├── projects/ │ │ ├── android/ │ │ │ └── native_app/ │ │ │ ├── lvgl_basic/ │ │ │ │ ├── android/ │ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ │ ├── debug.jks │ │ │ │ │ └── res/ │ │ │ │ │ └── values/ │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── lvgl_particles/ │ │ │ │ ├── android/ │ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ │ ├── debug.jks │ │ │ │ │ └── res/ │ │ │ │ │ └── values/ │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── raylib_basic/ │ │ │ │ ├── android/ │ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ │ ├── debug.jks │ │ │ │ │ └── res/ │ │ │ │ │ └── values/ │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── raylib_custom_glue/ │ │ │ │ ├── android/ │ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ │ ├── debug.jks │ │ │ │ │ └── res/ │ │ │ │ │ └── values/ │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── src/ │ │ │ │ │ ├── android_native_app_glue.c │ │ │ │ │ ├── android_native_app_glue.h │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ └── raylib_particles/ │ │ │ ├── android/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── debug.jks │ │ │ │ └── res/ │ │ │ │ └── values/ │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── asm/ │ │ │ ├── fasm/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.S │ │ │ │ └── xmake.lua │ │ │ ├── gas/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.S │ │ │ │ └── xmake.lua │ │ │ ├── masm32/ │ │ │ │ ├── src/ │ │ │ │ │ ├── generic.asm │ │ │ │ │ └── rsrc.rc │ │ │ │ └── xmake.lua │ │ │ ├── nasm/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.S │ │ │ │ └── xmake.lua │ │ │ └── yasm/ │ │ │ ├── src/ │ │ │ │ ├── main.S │ │ │ │ ├── main_elf.S │ │ │ │ └── stub.c │ │ │ └── xmake.lua │ │ ├── c/ │ │ │ ├── Unicode 测试/ │ │ │ │ ├── test.lua │ │ │ │ ├── xmake.lua │ │ │ │ ├── 头文件✨/ │ │ │ │ │ └── 标头🎟.h │ │ │ │ └── 源文件🎆/ │ │ │ │ ├── 中文.c │ │ │ │ └── 😘.c │ │ │ ├── asn1c/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.c │ │ │ │ │ └── rectangle.asn1 │ │ │ │ └── xmake.lua │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── cosmocc/ │ │ │ │ ├── console/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.c │ │ │ │ │ └── xmake.lua │ │ │ │ └── static_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── embeddirs/ │ │ │ │ ├── .gitignore │ │ │ │ ├── assets/ │ │ │ │ │ └── message.txt │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── headeronly/ │ │ │ │ ├── src/ │ │ │ │ │ └── foo.h │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── library_with_cmakelists/ │ │ │ │ ├── .gitignore │ │ │ │ ├── foo/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ └── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ └── foo.h │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── linker_scripts/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ ├── foo.def │ │ │ │ │ ├── main.c │ │ │ │ │ └── main.lds │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── llvm_compiler_rt/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── precompiled_header/ │ │ │ │ ├── src/ │ │ │ │ │ ├── header.h │ │ │ │ │ ├── main.c │ │ │ │ │ ├── test.c │ │ │ │ │ ├── test.cpp │ │ │ │ │ ├── test2.c │ │ │ │ │ ├── test3.c │ │ │ │ │ ├── test4.c │ │ │ │ │ ├── test5.c │ │ │ │ │ ├── test6.c │ │ │ │ │ ├── test7.c │ │ │ │ │ └── test8.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── protobuf/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.c │ │ │ │ │ ├── subdir/ │ │ │ │ │ │ └── test2.proto │ │ │ │ │ └── test.proto │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── shared_library_export_all/ │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── foo.c │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── shared_library_export_list/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ ├── foo.export.txt │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── static library with spaces/ │ │ │ │ ├── i n c/ │ │ │ │ │ ├── interface.h │ │ │ │ │ └── stdafx.h │ │ │ │ ├── s r c/ │ │ │ │ │ ├── interface.c │ │ │ │ │ └── test.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── static_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ └── unity_build/ │ │ │ ├── src/ │ │ │ │ ├── bar/ │ │ │ │ │ ├── test4.c │ │ │ │ │ └── test5.c │ │ │ │ ├── foo/ │ │ │ │ │ ├── test1.c │ │ │ │ │ └── test2.c │ │ │ │ ├── header.h │ │ │ │ ├── main.c │ │ │ │ ├── test.cpp │ │ │ │ ├── test2.c │ │ │ │ ├── test6.c │ │ │ │ ├── test7.c │ │ │ │ └── test8.c │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── c++/ │ │ │ ├── capnproto/ │ │ │ │ ├── proto/ │ │ │ │ │ └── message.capnp │ │ │ │ ├── src/ │ │ │ │ │ └── main.cc │ │ │ │ └── xmake.lua │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── console_zig_cxx/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── doctest/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ └── main.cpp │ │ │ │ ├── tests/ │ │ │ │ │ ├── test_1.cpp │ │ │ │ │ └── test_2.cpp │ │ │ │ └── xmake.lua │ │ │ ├── linkorders/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── manifest/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── main.manifest │ │ │ │ └── xmake.lua │ │ │ ├── modules/ │ │ │ │ ├── add_move_remove_module/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── foo.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── aliased_headerunit/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── foo/ │ │ │ │ │ │ │ └── hello.mpp │ │ │ │ │ │ ├── header.hpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── circular_dependency/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── hello2.mpp │ │ │ │ │ │ ├── hello3.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── class/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── hello_impl.cpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── class_cmake/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── hello_impl.cpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── cpp_with_moduledeps/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── mod.cpp │ │ │ │ │ │ └── mod.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── culling/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── hello.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── culling2/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── hello.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── culling3/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── hello.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── dependence/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── hello_impl.cpp │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── mod.mpp │ │ │ │ │ │ └── mod_impl.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── dependence2/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ ├── cat.mpp │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ └── zoo.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── dependency_flag_update/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── dependency_flag_update2/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ ├── foobar.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── duplicate_name_detection/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── headerunits_person/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── Person.mpp │ │ │ │ │ │ └── test.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── hello/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── hello with spaces/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── hello_mpp/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ └── main.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── hello_with_pch/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ └── test.h │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── hide_dependency_flags/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ ├── cat.mpp │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ └── zoo.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── ifdef_module/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── impl_unit/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── hello_impl.cpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── include-dirs/ │ │ │ │ │ ├── include/ │ │ │ │ │ │ └── foo.h │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── inline_and_template/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ ├── foo_impl.cpp │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ └── say.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── install_with_false_default/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── internal_partition/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── hello_internal.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── moduleonly/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── mod.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── moduleonly_private_dep/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── modA.mpp │ │ │ │ │ │ ├── modB.cpp │ │ │ │ │ │ └── modB.mpp │ │ │ │ │ └── xmake.lua │ │ │ │ ├── multiple_runtimes/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── namespace/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── hello_impl.cpp │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── mod.mpp │ │ │ │ │ │ └── mod_impl.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── namespace2/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ ├── hello_impl.cpp │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── mod.mpp │ │ │ │ │ │ └── mod_impl.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── packages/ │ │ │ │ │ ├── my-repo/ │ │ │ │ │ │ └── packages/ │ │ │ │ │ │ ├── b/ │ │ │ │ │ │ │ ├── bar/ │ │ │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ │ │ │ ├── include/ │ │ │ │ │ │ │ │ │ │ └── a.hpp │ │ │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ │ └── bar2/ │ │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ └── f/ │ │ │ │ │ │ └── foo/ │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── packages-subtarget/ │ │ │ │ │ ├── my-repo/ │ │ │ │ │ │ └── packages/ │ │ │ │ │ │ ├── b/ │ │ │ │ │ │ │ ├── bar/ │ │ │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ │ │ │ ├── include/ │ │ │ │ │ │ │ │ │ │ └── a.hpp │ │ │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ │ └── bar2/ │ │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ └── f/ │ │ │ │ │ │ └── foo/ │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ └── mod.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── partitions/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── math.math1.mpp │ │ │ │ │ │ ├── math.math2.mpp │ │ │ │ │ │ └── math.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── partitions_implunit/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ ├── foo_impl.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── partitions_implunit2/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ ├── foo_impl.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── phony/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── phony2/ │ │ │ │ │ ├── include/ │ │ │ │ │ │ └── foo.h │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── private_module/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── dep1.mpp │ │ │ │ │ │ ├── dep2.mpp │ │ │ │ │ │ ├── use.cpp │ │ │ │ │ │ └── use.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── staticlib/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── mod.cpp │ │ │ │ │ │ └── mod.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── staticlib2/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── stdmodules/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── my_module.cpp │ │ │ │ │ │ └── my_module.mpp │ │ │ │ │ ├── test/ │ │ │ │ │ │ └── test.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── stdmodules_cpp_only/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── stdmodules_deps/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── bar.mpp │ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ │ ├── foo.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── stdmodules_multiple_targets/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── my_module.cpp │ │ │ │ │ │ └── my_module.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── stl_headerunit/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── stl_headerunit_cpp_only/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── submodules/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── math.math1.mpp │ │ │ │ │ │ ├── math.math2.mpp │ │ │ │ │ │ └── math.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── submodules2/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ ├── main_module.mpp │ │ │ │ │ │ ├── module1.cpp │ │ │ │ │ │ ├── module1.mpp │ │ │ │ │ │ ├── module2.cpp │ │ │ │ │ │ └── module2.mpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── test_base.lua │ │ │ │ ├── test_cmake.lua │ │ │ │ ├── test_culling.lua │ │ │ │ ├── test_dependency_scanner.lua │ │ │ │ ├── test_duplicate_modules.lua │ │ │ │ ├── test_headerunits.lua │ │ │ │ ├── test_partitions.lua │ │ │ │ ├── test_stdmodules.lua │ │ │ │ ├── test_xmake_test.lua │ │ │ │ ├── test_xmake_test_stdmodules.lua │ │ │ │ ├── user_headerunit/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── header.hpp │ │ │ │ │ │ ├── hello.mpp │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── user_headerunit2/ │ │ │ │ │ ├── a/ │ │ │ │ │ │ ├── a.mpp │ │ │ │ │ │ ├── c.hpp │ │ │ │ │ │ ├── d.hpp │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ ├── b/ │ │ │ │ │ │ ├── b.mpp │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── xmake_tests1/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── foo.cppm │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── xmake_tests2/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── foo.cppm │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── xmake_tests3/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── foo.cppm │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ └── xmake_tests4/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── work.mpp │ │ │ │ ├── test/ │ │ │ │ │ └── test.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── package_linkgroups/ │ │ │ │ ├── 3rd/ │ │ │ │ │ ├── dpdk/ │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ ├── add.cc │ │ │ │ │ │ │ └── add.h │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ └── spdk/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── mul.cc │ │ │ │ │ │ └── mul.h │ │ │ │ │ └── xmake.lua │ │ │ │ ├── src/ │ │ │ │ │ └── main.cc │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── precompiled_header/ │ │ │ │ ├── src/ │ │ │ │ │ ├── header.h │ │ │ │ │ ├── header2.h │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── test.c │ │ │ │ │ ├── test.cpp │ │ │ │ │ ├── test2.cpp │ │ │ │ │ ├── test4.cpp │ │ │ │ │ ├── test5.cpp │ │ │ │ │ ├── test6.cpp │ │ │ │ │ ├── test7.cpp │ │ │ │ │ └── test8.cpp │ │ │ │ ├── test.lua │ │ │ │ ├── test3.cpp │ │ │ │ └── xmake.lua │ │ │ ├── precompiled_header_multiple_targets/ │ │ │ │ ├── src/ │ │ │ │ │ ├── common.h │ │ │ │ │ ├── consumer.cpp │ │ │ │ │ ├── lib1.cpp │ │ │ │ │ ├── lib1_pch.h │ │ │ │ │ ├── lib2.cpp │ │ │ │ │ ├── lib2_pch.h │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── pch_test.inc │ │ │ │ │ ├── pch_test.inl │ │ │ │ │ ├── pch_test.ipp │ │ │ │ │ ├── pch_test.tcc │ │ │ │ │ ├── pch_test.tpl │ │ │ │ │ ├── simple.cpp │ │ │ │ │ ├── test_inc.cpp │ │ │ │ │ ├── test_inl.cpp │ │ │ │ │ ├── test_ipp.cpp │ │ │ │ │ ├── test_tcc.cpp │ │ │ │ │ ├── test_tpl.cpp │ │ │ │ │ ├── tool.cpp │ │ │ │ │ └── tool_pch.h │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── protobuf/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── subdir/ │ │ │ │ │ │ └── test2.proto │ │ │ │ │ └── test.proto │ │ │ │ └── xmake.lua │ │ │ ├── protobuf_grpc_cpp_plugin/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── subdir/ │ │ │ │ │ │ └── test2.proto │ │ │ │ │ └── test.proto │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── shared_library_export_all/ │ │ │ │ ├── src/ │ │ │ │ │ ├── bar.cpp │ │ │ │ │ ├── bar.h │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── shared_library_with_soname/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── snippet_runtimes/ │ │ │ │ ├── my-repo/ │ │ │ │ │ └── packages/ │ │ │ │ │ └── b/ │ │ │ │ │ └── bar/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── include/ │ │ │ │ │ │ │ └── bar.hpp │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ └── bar.cpp │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── static_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── test(brackets)/ │ │ │ │ ├── .gitignore │ │ │ │ ├── inc(brackets)/ │ │ │ │ │ └── test.h │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ └── unity_build/ │ │ │ ├── src/ │ │ │ │ ├── bar/ │ │ │ │ │ ├── test4.cpp │ │ │ │ │ ├── test5.cpp │ │ │ │ │ └── test6.cpp │ │ │ │ ├── foo/ │ │ │ │ │ ├── test.cpp │ │ │ │ │ └── test2.cpp │ │ │ │ ├── header.h │ │ │ │ ├── header2.h │ │ │ │ ├── main.cpp │ │ │ │ ├── test.c │ │ │ │ ├── test7.cpp │ │ │ │ └── test8.cpp │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── cppfront/ │ │ │ └── console/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ ├── main.cpp2 │ │ │ │ └── println.h2 │ │ │ └── xmake.lua │ │ ├── csharp/ │ │ │ ├── console/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── Program.cs │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── console_with_runtime_json/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── Program.cs │ │ │ │ │ └── runtime.json │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── multiple_library/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── libalpha/ │ │ │ │ │ │ └── Alpha.cs │ │ │ │ │ ├── libbeta/ │ │ │ │ │ │ └── Beta.cs │ │ │ │ │ └── sample/ │ │ │ │ │ └── Program.cs │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── nuget_package/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── Program.cs │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── pinvoke/ │ │ │ │ ├── src/ │ │ │ │ │ ├── app/ │ │ │ │ │ │ └── Program.cs │ │ │ │ │ └── native/ │ │ │ │ │ └── mathlib.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── app/ │ │ │ │ │ │ └── Program.cs │ │ │ │ │ └── lib/ │ │ │ │ │ └── Greeter.cs │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ └── web_project/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ └── Program.cs │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── cuda/ │ │ │ ├── console/ │ │ │ │ ├── inc/ │ │ │ │ │ ├── cuda_drvapi_dynlink.c │ │ │ │ │ ├── drvapi_error_string.h │ │ │ │ │ ├── dynlink/ │ │ │ │ │ │ ├── cuda_drvapi_dynlink.h │ │ │ │ │ │ ├── cuda_drvapi_dynlink_cuda.h │ │ │ │ │ │ ├── cuda_drvapi_dynlink_d3d.h │ │ │ │ │ │ └── cuda_drvapi_dynlink_gl.h │ │ │ │ │ ├── dynlink_d3d10.h │ │ │ │ │ ├── dynlink_d3d11.h │ │ │ │ │ ├── exception.h │ │ │ │ │ ├── helper_cuda.h │ │ │ │ │ ├── helper_cuda_drvapi.h │ │ │ │ │ ├── helper_cuda_gl.h │ │ │ │ │ ├── helper_cusolver.h │ │ │ │ │ ├── helper_functions.h │ │ │ │ │ ├── helper_gl.h │ │ │ │ │ ├── helper_image.h │ │ │ │ │ ├── helper_math.h │ │ │ │ │ ├── helper_string.h │ │ │ │ │ ├── helper_timer.h │ │ │ │ │ ├── multithreading.h │ │ │ │ │ ├── nvMath.h │ │ │ │ │ ├── nvMatrix.h │ │ │ │ │ ├── nvQuaternion.h │ │ │ │ │ ├── nvShaderUtils.h │ │ │ │ │ ├── nvVector.h │ │ │ │ │ ├── nvrtc_helper.h │ │ │ │ │ ├── param.h │ │ │ │ │ ├── paramgl.h │ │ │ │ │ ├── rendercheck_d3d10.h │ │ │ │ │ ├── rendercheck_d3d11.h │ │ │ │ │ ├── rendercheck_d3d9.h │ │ │ │ │ ├── rendercheck_gl.h │ │ │ │ │ ├── rendercheck_gles.h │ │ │ │ │ └── timer.h │ │ │ │ ├── src/ │ │ │ │ │ └── main.cu │ │ │ │ └── xmake.lua │ │ │ ├── console_2/ │ │ │ │ ├── inc/ │ │ │ │ │ └── lib.cuh │ │ │ │ ├── src/ │ │ │ │ │ ├── lib.cu │ │ │ │ │ └── main.cu │ │ │ │ └── xmake.lua │ │ │ ├── shared/ │ │ │ │ ├── inc/ │ │ │ │ │ └── lib.cuh │ │ │ │ ├── src/ │ │ │ │ │ ├── lib.cu │ │ │ │ │ └── main.cu │ │ │ │ └── xmake.lua │ │ │ └── static/ │ │ │ ├── inc/ │ │ │ │ └── lib.cuh │ │ │ ├── src/ │ │ │ │ ├── lib.cu │ │ │ │ └── main.cu │ │ │ └── xmake.lua │ │ ├── dlang/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.d │ │ │ │ └── xmake.lua │ │ │ ├── console_with_pkgs/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.d │ │ │ │ └── xmake.lua │ │ │ ├── dub_package/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.d │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── interfaces.d │ │ │ │ │ └── main.d │ │ │ │ └── xmake.lua │ │ │ └── static_library/ │ │ │ ├── src/ │ │ │ │ ├── interfaces.d │ │ │ │ └── main.d │ │ │ └── xmake.lua │ │ ├── embed/ │ │ │ ├── c51/ │ │ │ │ └── hello/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── gnu-rm/ │ │ │ │ └── hello/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo/ │ │ │ │ │ │ └── foo.c │ │ │ │ │ ├── gcc_arm.ld │ │ │ │ │ ├── lib/ │ │ │ │ │ │ └── cmsis/ │ │ │ │ │ │ ├── ARMCM3.h │ │ │ │ │ │ ├── cmsis_compiler.h │ │ │ │ │ │ ├── cmsis_gcc.h │ │ │ │ │ │ ├── cmsis_version.h │ │ │ │ │ │ ├── core_cm3.h │ │ │ │ │ │ ├── mpu_armv7.h │ │ │ │ │ │ └── system_ARMCM3.h │ │ │ │ │ ├── main.c │ │ │ │ │ ├── startup_ARMCM3.S │ │ │ │ │ └── system_ARMCM3.c │ │ │ │ └── xmake.lua │ │ │ ├── iverilog/ │ │ │ │ ├── hello/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.v │ │ │ │ │ └── xmake.lua │ │ │ │ └── hello_vcd/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.v │ │ │ │ └── xmake.lua │ │ │ ├── mdk/ │ │ │ │ └── hello/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo/ │ │ │ │ │ │ └── foo.c │ │ │ │ │ ├── lib/ │ │ │ │ │ │ └── cmsis/ │ │ │ │ │ │ ├── ARMCM3.h │ │ │ │ │ │ ├── cmsis_armcc.h │ │ │ │ │ │ ├── cmsis_armclang.h │ │ │ │ │ │ ├── cmsis_compiler.h │ │ │ │ │ │ ├── cmsis_version.h │ │ │ │ │ │ ├── core_cm3.h │ │ │ │ │ │ ├── mpu_armv7.h │ │ │ │ │ │ └── system_ARMCM3.h │ │ │ │ │ ├── main.c │ │ │ │ │ ├── startup_ARMCM3.s │ │ │ │ │ └── system_ARMCM3.c │ │ │ │ └── xmake.lua │ │ │ └── verilator/ │ │ │ ├── hello/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.v │ │ │ │ │ └── sim_main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── hello_vcd/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.v │ │ │ │ │ └── sim_main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── shared/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.v │ │ │ │ │ └── sim_main.cpp │ │ │ │ └── xmake.lua │ │ │ └── static/ │ │ │ ├── src/ │ │ │ │ ├── main.v │ │ │ │ └── sim_main.cpp │ │ │ └── xmake.lua │ │ ├── fortran/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.f90 │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.f90 │ │ │ │ │ └── test.f90 │ │ │ │ └── xmake.lua │ │ │ └── static_library/ │ │ │ ├── src/ │ │ │ │ ├── main.f90 │ │ │ │ └── test.f90 │ │ │ └── xmake.lua │ │ ├── go/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.go │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ └── static_library/ │ │ │ ├── src/ │ │ │ │ ├── main.go │ │ │ │ ├── module/ │ │ │ │ │ ├── add.go │ │ │ │ │ └── sub.go │ │ │ │ └── test.go │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── hybrid/ │ │ │ └── static_library/ │ │ │ ├── src/ │ │ │ │ ├── main.cpp │ │ │ │ ├── main2.cpp │ │ │ │ ├── test.h │ │ │ │ ├── test1.c │ │ │ │ ├── test2.m │ │ │ │ ├── test3.mm │ │ │ │ ├── test4.cpp │ │ │ │ └── test5.d │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── kotlin-native/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.kt │ │ │ │ └── xmake.lua │ │ │ ├── package/ │ │ │ │ ├── cli-parser/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.kt │ │ │ │ │ └── xmake.lua │ │ │ │ └── json/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.kt │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.kt │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ └── static_library/ │ │ │ ├── src/ │ │ │ │ ├── foo.kt │ │ │ │ └── main.c │ │ │ └── xmake.lua │ │ ├── lex_yacc/ │ │ │ ├── src/ │ │ │ │ ├── calc.l │ │ │ │ ├── calc.y │ │ │ │ └── test.c │ │ │ └── xmake.lua │ │ ├── linux/ │ │ │ ├── bpf/ │ │ │ │ └── minimal/ │ │ │ │ ├── src/ │ │ │ │ │ ├── minimal.bpf.c │ │ │ │ │ └── minimal.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ └── driver/ │ │ │ ├── hello/ │ │ │ │ ├── src/ │ │ │ │ │ ├── add.c │ │ │ │ │ ├── add.h │ │ │ │ │ └── hello.c │ │ │ │ └── xmake.lua │ │ │ ├── hello_custom/ │ │ │ │ ├── src/ │ │ │ │ │ ├── add.c │ │ │ │ │ ├── add.h │ │ │ │ │ └── hello.c │ │ │ │ └── xmake.lua │ │ │ └── hello_makefile/ │ │ │ └── src/ │ │ │ ├── add.c │ │ │ ├── add.h │ │ │ └── hello.c │ │ ├── nim/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main │ │ │ │ │ └── main.nim │ │ │ │ └── xmake.lua │ │ │ ├── console_with_c/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ └── main.nim │ │ │ │ └── xmake.lua │ │ │ ├── link_library/ │ │ │ │ ├── headers/ │ │ │ │ │ └── test_header.h │ │ │ │ ├── inc/ │ │ │ │ │ └── test.h │ │ │ │ ├── maindll.nim │ │ │ │ ├── mainlib.nim │ │ │ │ ├── shared.nim │ │ │ │ ├── static.nim │ │ │ │ └── xmake.lua │ │ │ ├── native_package/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.nim │ │ │ │ └── xmake.lua │ │ │ ├── nimble_package/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.nim │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.nim │ │ │ │ │ └── main.nim │ │ │ │ └── xmake.lua │ │ │ └── static_library/ │ │ │ ├── src/ │ │ │ │ ├── foo.nim │ │ │ │ └── main.nim │ │ │ └── xmake.lua │ │ ├── objc/ │ │ │ ├── bundle/ │ │ │ │ ├── src/ │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── test.h │ │ │ │ │ └── test.m │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.m │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── framework/ │ │ │ │ ├── src/ │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── main.m │ │ │ │ │ ├── test.h │ │ │ │ │ └── test.m │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── iosapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── AppDelegate.h │ │ │ │ │ ├── AppDelegate.m │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── SceneDelegate.h │ │ │ │ │ ├── SceneDelegate.m │ │ │ │ │ ├── ViewController.h │ │ │ │ │ ├── ViewController.m │ │ │ │ │ └── main.m │ │ │ │ └── xmake.lua │ │ │ ├── iosapp_with_framework/ │ │ │ │ ├── src/ │ │ │ │ │ ├── app/ │ │ │ │ │ │ ├── AppDelegate.h │ │ │ │ │ │ ├── AppDelegate.m │ │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ │ ├── Info.plist │ │ │ │ │ │ ├── SceneDelegate.h │ │ │ │ │ │ ├── SceneDelegate.m │ │ │ │ │ │ ├── ViewController.h │ │ │ │ │ │ ├── ViewController.m │ │ │ │ │ │ └── main.m │ │ │ │ │ └── framework/ │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── test.h │ │ │ │ │ └── test.m │ │ │ │ └── xmake.lua │ │ │ ├── macapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── AppDelegate.h │ │ │ │ │ ├── AppDelegate.m │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── ViewController.h │ │ │ │ │ ├── ViewController.m │ │ │ │ │ ├── main.m │ │ │ │ │ └── test.entitlements │ │ │ │ └── xmake.lua │ │ │ ├── macapp_with_framework/ │ │ │ │ ├── src/ │ │ │ │ │ ├── app/ │ │ │ │ │ │ ├── AppDelegate.h │ │ │ │ │ │ ├── AppDelegate.m │ │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ │ ├── Info.plist │ │ │ │ │ │ ├── ViewController.h │ │ │ │ │ │ ├── ViewController.m │ │ │ │ │ │ └── main.m │ │ │ │ │ └── framework/ │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── test.h │ │ │ │ │ └── test.m │ │ │ │ └── xmake.lua │ │ │ ├── macapp_with_shared/ │ │ │ │ ├── src/ │ │ │ │ │ ├── AppDelegate.h │ │ │ │ │ ├── AppDelegate.m │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── ViewController.h │ │ │ │ │ ├── ViewController.m │ │ │ │ │ ├── main.m │ │ │ │ │ ├── test.c │ │ │ │ │ ├── test.entitlements │ │ │ │ │ └── test.h │ │ │ │ └── xmake.lua │ │ │ ├── metal_app/ │ │ │ │ ├── .gitignore │ │ │ │ ├── Application/ │ │ │ │ │ ├── AAPLAppDelegate.h │ │ │ │ │ ├── AAPLAppDelegate.m │ │ │ │ │ ├── AAPLViewController.h │ │ │ │ │ ├── AAPLViewController.m │ │ │ │ │ ├── iOS/ │ │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ │ └── Info.plist │ │ │ │ │ ├── macOS/ │ │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ │ └── Info.plist │ │ │ │ │ ├── main.m │ │ │ │ │ └── tvOS/ │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ └── Info.plist │ │ │ │ ├── Configuration/ │ │ │ │ │ └── SampleCode.xcconfig │ │ │ │ ├── HelloTriangle.xcodeproj/ │ │ │ │ │ ├── .xcodesamplecode.plist │ │ │ │ │ ├── project.pbxproj │ │ │ │ │ └── project.xcworkspace/ │ │ │ │ │ └── xcshareddata/ │ │ │ │ │ └── WorkspaceSettings.xcsettings │ │ │ │ ├── LICENSE/ │ │ │ │ │ └── LICENSE.txt │ │ │ │ ├── README.md │ │ │ │ ├── Renderer/ │ │ │ │ │ ├── AAPLRenderer.h │ │ │ │ │ ├── AAPLRenderer.m │ │ │ │ │ ├── AAPLShaderTypes.h │ │ │ │ │ └── AAPLShaders.metal │ │ │ │ └── xmake.lua │ │ │ └── modulemap/ │ │ │ ├── src/ │ │ │ │ ├── hello.h │ │ │ │ ├── hello.m │ │ │ │ ├── main.m │ │ │ │ └── module.modulemap │ │ │ └── xmake.lua │ │ ├── objc++/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.mm │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── modulemap/ │ │ │ │ ├── src/ │ │ │ │ │ ├── hello.h │ │ │ │ │ ├── hello.m │ │ │ │ │ ├── main.mm │ │ │ │ │ └── module.modulemap │ │ │ │ └── xmake.lua │ │ │ └── precompiled_header/ │ │ │ ├── src/ │ │ │ │ ├── header.h │ │ │ │ ├── header2.h │ │ │ │ ├── main.mm │ │ │ │ ├── test.c │ │ │ │ ├── test.mm │ │ │ │ ├── test2.mm │ │ │ │ ├── test4.mm │ │ │ │ ├── test5.mm │ │ │ │ ├── test6.mm │ │ │ │ ├── test7.mm │ │ │ │ └── test8.mm │ │ │ ├── test.lua │ │ │ ├── test3.mm │ │ │ └── xmake.lua │ │ ├── openmp/ │ │ │ ├── hello/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ └── loop/ │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── other/ │ │ │ ├── autogen/ │ │ │ │ ├── autogen_binary_module/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── modules/ │ │ │ │ │ │ └── autogen/ │ │ │ │ │ │ └── foo/ │ │ │ │ │ │ ├── .gitignore │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ └── main.cpp │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── data.in │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── autogen_code/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── autogen_codedep/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── autogen.cpp │ │ │ │ │ │ ├── data.in │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ └── autogen_shared_module/ │ │ │ │ ├── .gitignore │ │ │ │ ├── modules/ │ │ │ │ │ └── autogen/ │ │ │ │ │ └── foo/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.cpp │ │ │ │ │ └── xmake.lua │ │ │ │ ├── src/ │ │ │ │ │ ├── data.in │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── bin2c/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── bin2obj/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── build_deps/ │ │ │ │ ├── src/ │ │ │ │ │ ├── dep1.c │ │ │ │ │ ├── dep2.c │ │ │ │ │ ├── dep3.c │ │ │ │ │ ├── dep4.c │ │ │ │ │ ├── dep5.c │ │ │ │ │ ├── interface.h │ │ │ │ │ ├── test1.c │ │ │ │ │ ├── test2.c │ │ │ │ │ └── test3.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── glsl2spv_bin2c/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.c │ │ │ │ │ ├── test.frag │ │ │ │ │ └── test.vert │ │ │ │ └── xmake.lua │ │ │ ├── glsl2spv_bin2obj/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.c │ │ │ │ │ ├── test.frag │ │ │ │ │ └── test.vert │ │ │ │ └── xmake.lua │ │ │ ├── group/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── hlsl2spv_bin2c/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.c │ │ │ │ │ ├── test.ps.hlsl │ │ │ │ │ └── test.vs.hlsl │ │ │ │ └── xmake.lua │ │ │ ├── hlsl2spv_bin2obj/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.c │ │ │ │ │ ├── test.ps.hlsl │ │ │ │ │ └── test.vs.hlsl │ │ │ │ └── xmake.lua │ │ │ ├── ispc/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── test.ispc │ │ │ │ └── xmake.lua │ │ │ ├── merge_archive/ │ │ │ │ ├── src/ │ │ │ │ │ ├── add.c │ │ │ │ │ ├── mul.c │ │ │ │ │ └── sub.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── merge_archive2/ │ │ │ │ ├── src/ │ │ │ │ │ ├── add.c │ │ │ │ │ ├── main.c │ │ │ │ │ ├── mul.c │ │ │ │ │ ├── sub.c │ │ │ │ │ └── subdir/ │ │ │ │ │ ├── add.c │ │ │ │ │ └── sub.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── merge_object/ │ │ │ │ ├── src/ │ │ │ │ │ ├── interface.c │ │ │ │ │ ├── interface.h │ │ │ │ │ └── test.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── multiplats_vs/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── test.asm │ │ │ │ │ └── test.rc │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── multiplats_xcode/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── native_module/ │ │ │ │ ├── cjson/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── modules/ │ │ │ │ │ │ └── lua/ │ │ │ │ │ │ └── cjson/ │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ └── cjson.c │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.cpp │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ └── hello/ │ │ │ │ ├── .gitignore │ │ │ │ ├── modules/ │ │ │ │ │ ├── binary/ │ │ │ │ │ │ └── bar/ │ │ │ │ │ │ ├── .gitignore │ │ │ │ │ │ ├── src/ │ │ │ │ │ │ │ ├── add.cpp │ │ │ │ │ │ │ └── sub.cpp │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ └── shared/ │ │ │ │ │ └── foo/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── foo.c │ │ │ │ │ └── xmake.lua │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── object_only/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.cpp │ │ │ │ │ ├── foo.h │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── parallel_build/ │ │ │ │ ├── 1.cpp │ │ │ │ ├── 2.cpp │ │ │ │ └── xmake.lua │ │ │ └── parse_headerdeps/ │ │ │ ├── .gitignore │ │ │ ├── common/ │ │ │ │ └── test1.hpp │ │ │ └── src/ │ │ │ ├── test1.cpp │ │ │ └── xmake.lua │ │ ├── package/ │ │ │ ├── basic/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.c │ │ │ │ │ └── test.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── brew/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── cmake/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── compatibility/ │ │ │ │ ├── deps_with_version/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ └── main.c │ │ │ │ │ ├── test.lua │ │ │ │ │ └── xmake.lua │ │ │ │ └── sync_requires_to_deps/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── components/ │ │ │ │ ├── src/ │ │ │ │ │ ├── graphics.cpp │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── network.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── conan/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── depconfigs/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── inherit_base/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── llvm_dev/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── multiconfig/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── multiplat/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── nuget/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── package_rule/ │ │ │ │ ├── repo/ │ │ │ │ │ └── packages/ │ │ │ │ │ └── f/ │ │ │ │ │ └── foo/ │ │ │ │ │ ├── rules/ │ │ │ │ │ │ └── markdown.lua │ │ │ │ │ └── xmake.lua │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── test.md │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── requires_lock/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── rootconfigs/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── schemes/ │ │ │ │ ├── port/ │ │ │ │ │ └── xmake.lua │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── toolchain_gnu_rm/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── toolchain_llvm/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── toolchain_llvm_mingw/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── toolchain_msvc/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── toolchain_muslcc/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── toolchain_tinycc/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ ├── toolchain_zig/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.zig │ │ │ │ └── xmake.lua │ │ │ ├── vcpkg/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── vcpkg_dependency/ │ │ │ │ ├── .gitignore │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ └── vcpkg_manifest/ │ │ │ ├── .gitignore │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── pascal/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.pas │ │ │ │ └── xmake.lua │ │ │ ├── console_with_c/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ └── main.pas │ │ │ │ └── xmake.lua │ │ │ └── shared/ │ │ │ ├── src/ │ │ │ │ ├── foo.pas │ │ │ │ └── main.pas │ │ │ └── xmake.lua │ │ ├── policy/ │ │ │ └── compile_commands/ │ │ │ ├── src/ │ │ │ │ └── main.c │ │ │ └── xmake.lua │ │ ├── python/ │ │ │ ├── cython/ │ │ │ │ └── example/ │ │ │ │ ├── src/ │ │ │ │ │ └── example.py │ │ │ │ └── xmake.lua │ │ │ └── pybind/ │ │ │ ├── example/ │ │ │ │ ├── src/ │ │ │ │ │ └── example.cpp │ │ │ │ └── xmake.lua │ │ │ └── example_with_soabi/ │ │ │ ├── src/ │ │ │ │ └── example.cpp │ │ │ └── xmake.lua │ │ ├── qt/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── console_static/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── quickapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── main.qml │ │ │ │ │ └── qml.qrc │ │ │ │ └── xmake.lua │ │ │ ├── quickapp_static/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── main.qml │ │ │ │ │ └── qml.qrc │ │ │ │ └── xmake.lua │ │ │ ├── quickplugin/ │ │ │ │ ├── src/ │ │ │ │ │ ├── Foo.cpp │ │ │ │ │ ├── Foo.h │ │ │ │ │ ├── Plugin.cpp │ │ │ │ │ └── Plugin.h │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── demo.cpp │ │ │ │ │ ├── demo.h │ │ │ │ │ └── demo_global.h │ │ │ │ └── xmake.lua │ │ │ ├── static_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── demo.cpp │ │ │ │ │ └── demo.h │ │ │ │ └── xmake.lua │ │ │ ├── widgetapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── mainwindow.cpp │ │ │ │ │ ├── mainwindow.h │ │ │ │ │ └── mainwindow.ui │ │ │ │ └── xmake.lua │ │ │ ├── widgetapp_private_slot/ │ │ │ │ ├── main.cpp │ │ │ │ ├── mainwindow.cpp │ │ │ │ ├── mainwindow.h │ │ │ │ ├── mainwindow.ui │ │ │ │ └── xmake.lua │ │ │ ├── widgetapp_private_slot2/ │ │ │ │ ├── main.cpp │ │ │ │ ├── mainwindow.cpp │ │ │ │ ├── mainwindow.h │ │ │ │ ├── mainwindow.ui │ │ │ │ └── xmake.lua │ │ │ ├── widgetapp_static/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── mainwindow.cpp │ │ │ │ │ ├── mainwindow.h │ │ │ │ │ └── mainwindow.ui │ │ │ │ └── xmake.lua │ │ │ ├── with_private/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── mainwindow.cpp │ │ │ │ │ ├── mainwindow.h │ │ │ │ │ └── mainwindow.ui │ │ │ │ └── xmake.lua │ │ │ └── with_ts/ │ │ │ ├── src/ │ │ │ │ ├── demo_zh_CN.ts │ │ │ │ ├── demo_zh_TW.ts │ │ │ │ ├── main.cpp │ │ │ │ ├── mainwindow.cpp │ │ │ │ ├── mainwindow.h │ │ │ │ └── mainwindow.ui │ │ │ └── xmake.lua │ │ ├── rust/ │ │ │ ├── cargo_deps/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.rs │ │ │ │ └── xmake.lua │ │ │ ├── cargo_deps_cross_build/ │ │ │ │ ├── Cargo.toml │ │ │ │ ├── src/ │ │ │ │ │ └── main.rs │ │ │ │ └── xmake.lua │ │ │ ├── cargo_deps_with_toml/ │ │ │ │ ├── Cargo.toml │ │ │ │ ├── src/ │ │ │ │ │ └── main.rs │ │ │ │ └── xmake.lua │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.rs │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── cxx_call_rust_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── bridge.rsx │ │ │ │ │ ├── foo.rs │ │ │ │ │ └── main.cc │ │ │ │ └── xmake.lua │ │ │ ├── rust_call_cxx_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.cc │ │ │ │ │ └── main.rs │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── shared_library/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.rs │ │ │ │ │ └── main.rs │ │ │ │ └── xmake.lua │ │ │ └── static_library/ │ │ │ ├── src/ │ │ │ │ ├── foo.rs │ │ │ │ └── main.rs │ │ │ ├── test.lua │ │ │ └── xmake.lua │ │ ├── swift/ │ │ │ ├── bidirectional_cxx_interop_lib/ │ │ │ │ ├── include/ │ │ │ │ │ └── fibonacci/ │ │ │ │ │ ├── fibonacci.h │ │ │ │ │ └── module.modulemap │ │ │ │ ├── lib/ │ │ │ │ │ ├── fibonacci.cpp │ │ │ │ │ └── fibonacci.swift │ │ │ │ ├── src/ │ │ │ │ │ ├── fibonacci.cpp │ │ │ │ │ └── fibonacci.swift │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.swift │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── cross_modules/ │ │ │ │ ├── src/ │ │ │ │ │ ├── A.swift │ │ │ │ │ └── main.swift │ │ │ │ └── xmake.lua │ │ │ ├── cxx_interop/ │ │ │ │ ├── lib/ │ │ │ │ │ └── fibonacci/ │ │ │ │ │ └── fibonacci.swift │ │ │ │ ├── src/ │ │ │ │ │ └── fibonacci.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── cxx_interop_lib/ │ │ │ │ ├── lib/ │ │ │ │ │ └── fibonacci/ │ │ │ │ │ └── fibonacci.swift │ │ │ │ ├── src/ │ │ │ │ │ └── fibonacci.cpp │ │ │ │ ├── test.lua │ │ │ │ └── xmake.lua │ │ │ ├── iosapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── AppDelegate.swift │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── SceneDelegate.swift │ │ │ │ │ └── ViewController.swift │ │ │ │ └── xmake.lua │ │ │ ├── macapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── AppDelegate.swift │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── ViewController.swift │ │ │ │ │ └── test.entitlements │ │ │ │ └── xmake.lua │ │ │ └── modulemap/ │ │ │ ├── src/ │ │ │ │ ├── hello.cpp │ │ │ │ ├── hello.h │ │ │ │ ├── main.swift │ │ │ │ └── module.modulemap │ │ │ └── xmake.lua │ │ ├── swig/ │ │ │ ├── auto_include/ │ │ │ │ ├── src/ │ │ │ │ │ ├── example.cpp │ │ │ │ │ └── example.i │ │ │ │ └── xmake.lua │ │ │ ├── java_c/ │ │ │ │ ├── src/ │ │ │ │ │ ├── example.c │ │ │ │ │ ├── example.i │ │ │ │ │ ├── example2.i │ │ │ │ │ └── test.h │ │ │ │ └── xmake.lua │ │ │ ├── lua_c/ │ │ │ │ ├── src/ │ │ │ │ │ ├── example.c │ │ │ │ │ └── example.i │ │ │ │ └── xmake.lua │ │ │ ├── python_c/ │ │ │ │ ├── src/ │ │ │ │ │ ├── example.c │ │ │ │ │ └── example.i │ │ │ │ └── xmake.lua │ │ │ ├── python_c_with_soabi/ │ │ │ │ ├── src/ │ │ │ │ │ ├── example.c │ │ │ │ │ └── example.i │ │ │ │ └── xmake.lua │ │ │ └── python_cpp/ │ │ │ ├── src/ │ │ │ │ ├── example.cpp │ │ │ │ └── example.i │ │ │ └── xmake.lua │ │ ├── vala/ │ │ │ ├── gtk+3/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.vala │ │ │ │ └── xmake.lua │ │ │ ├── includec/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.vala │ │ │ │ │ ├── printer.c │ │ │ │ │ └── printer.vala │ │ │ │ └── xmake.lua │ │ │ ├── lua/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.vala │ │ │ │ └── xmake.lua │ │ │ ├── sharedlib/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.vala │ │ │ │ │ └── mymath.vala │ │ │ │ └── xmake.lua │ │ │ ├── sqlite3/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.vala │ │ │ │ └── xmake.lua │ │ │ └── staticlib/ │ │ │ ├── src/ │ │ │ │ ├── main.vala │ │ │ │ └── mymath.vala │ │ │ └── xmake.lua │ │ ├── windows/ │ │ │ ├── driver/ │ │ │ │ ├── kmdf/ │ │ │ │ │ ├── ioctl/ │ │ │ │ │ │ ├── driver/ │ │ │ │ │ │ │ ├── nonpnp.c │ │ │ │ │ │ │ ├── nonpnp.h │ │ │ │ │ │ │ ├── nonpnp.rc │ │ │ │ │ │ │ └── trace.h │ │ │ │ │ │ ├── exe/ │ │ │ │ │ │ │ ├── install.c │ │ │ │ │ │ │ ├── nonpnp.inf │ │ │ │ │ │ │ └── testapp.c │ │ │ │ │ │ ├── localwpp.ini │ │ │ │ │ │ ├── public.h │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ └── serial/ │ │ │ │ │ ├── error.c │ │ │ │ │ ├── flush.c │ │ │ │ │ ├── immediat.c │ │ │ │ │ ├── initunlo.c │ │ │ │ │ ├── ioctl.c │ │ │ │ │ ├── isr.c │ │ │ │ │ ├── log.c │ │ │ │ │ ├── log.h │ │ │ │ │ ├── modmflow.c │ │ │ │ │ ├── openclos.c │ │ │ │ │ ├── pnp.c │ │ │ │ │ ├── power.c │ │ │ │ │ ├── precomp.h │ │ │ │ │ ├── precompsrc.c │ │ │ │ │ ├── purge.c │ │ │ │ │ ├── qsfile.c │ │ │ │ │ ├── read.c │ │ │ │ │ ├── registry.c │ │ │ │ │ ├── serial.h │ │ │ │ │ ├── serial.inx │ │ │ │ │ ├── serial.rc │ │ │ │ │ ├── serialp.h │ │ │ │ │ ├── serlog.mc │ │ │ │ │ ├── trace.h │ │ │ │ │ ├── utils.c │ │ │ │ │ ├── waitmask.c │ │ │ │ │ ├── wmi.c │ │ │ │ │ ├── write.c │ │ │ │ │ └── xmake.lua │ │ │ │ ├── umdf/ │ │ │ │ │ ├── echo/ │ │ │ │ │ │ ├── driver/ │ │ │ │ │ │ │ ├── device.c │ │ │ │ │ │ │ ├── device.h │ │ │ │ │ │ │ ├── driver.c │ │ │ │ │ │ │ ├── driver.h │ │ │ │ │ │ │ ├── echoum.inx │ │ │ │ │ │ │ ├── queue.c │ │ │ │ │ │ │ └── queue.h │ │ │ │ │ │ ├── exe/ │ │ │ │ │ │ │ ├── echoapp.cpp │ │ │ │ │ │ │ └── public.h │ │ │ │ │ │ └── xmake.lua │ │ │ │ │ └── skeleton/ │ │ │ │ │ ├── Skeleton.rc │ │ │ │ │ ├── UMDFSkeleton_OSR.inx │ │ │ │ │ ├── UMDFSkeleton_Root.inx │ │ │ │ │ ├── comsup.cpp │ │ │ │ │ ├── comsup.h │ │ │ │ │ ├── device.cpp │ │ │ │ │ ├── device.h │ │ │ │ │ ├── dllsup.cpp │ │ │ │ │ ├── driver.cpp │ │ │ │ │ ├── driver.h │ │ │ │ │ ├── exports.def │ │ │ │ │ ├── internal.h │ │ │ │ │ └── xmake.lua │ │ │ │ └── wdm/ │ │ │ │ ├── msdsm/ │ │ │ │ │ ├── SampleDSM.inf │ │ │ │ │ ├── dsmmain.c │ │ │ │ │ ├── dsmtrace.mof │ │ │ │ │ ├── intrface.c │ │ │ │ │ ├── msdsm.h │ │ │ │ │ ├── msdsm.mof │ │ │ │ │ ├── msdsm.rc │ │ │ │ │ ├── msdsmdsm.mof │ │ │ │ │ ├── precomp.h │ │ │ │ │ ├── precompsrc.c │ │ │ │ │ ├── prototypes.h │ │ │ │ │ ├── trace.h │ │ │ │ │ ├── utils.c │ │ │ │ │ ├── wmi.c │ │ │ │ │ └── xmake.lua │ │ │ │ └── perfcounters/ │ │ │ │ ├── kcs.c │ │ │ │ ├── kcs.h │ │ │ │ ├── kcs.man │ │ │ │ ├── kcs.rc │ │ │ │ └── xmake.lua │ │ │ ├── idl/ │ │ │ │ ├── test_norpc/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── lockowner.idl │ │ │ │ │ │ └── test_iid.c │ │ │ │ │ └── xmake.lua │ │ │ │ ├── test_norpc_proxy/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── lockowner.idl │ │ │ │ │ │ └── test_iid.c │ │ │ │ │ └── xmake.lua │ │ │ │ ├── test_rpc/ │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── example.idl │ │ │ │ │ │ └── test_iid.c │ │ │ │ │ └── xmake.lua │ │ │ │ └── test_rpc_noserver/ │ │ │ │ ├── src/ │ │ │ │ │ ├── example.idl │ │ │ │ │ └── test_iid.c │ │ │ │ └── xmake.lua │ │ │ ├── windows_links/ │ │ │ │ ├── src/ │ │ │ │ │ ├── foo.c │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ └── winsdk/ │ │ │ ├── usbview/ │ │ │ │ ├── app.config │ │ │ │ ├── codeanalysis.h │ │ │ │ ├── debug.c │ │ │ │ ├── devnode.c │ │ │ │ ├── dispaud.c │ │ │ │ ├── display.c │ │ │ │ ├── dispvid.c │ │ │ │ ├── enum.c │ │ │ │ ├── h264.c │ │ │ │ ├── h264.h │ │ │ │ ├── langidlist.h │ │ │ │ ├── resource.h │ │ │ │ ├── split.cur │ │ │ │ ├── usbdesc.h │ │ │ │ ├── usbschema.hpp │ │ │ │ ├── usbviddesc.h │ │ │ │ ├── uvcdesc.h │ │ │ │ ├── uvcview.c │ │ │ │ ├── uvcview.h │ │ │ │ ├── uvcview.rc │ │ │ │ ├── vndrlist.h │ │ │ │ ├── xmake.lua │ │ │ │ ├── xmlhelper.cpp │ │ │ │ └── xmlhelper.h │ │ │ └── windemo/ │ │ │ ├── main.cpp │ │ │ ├── resource.h │ │ │ ├── stdafx.cpp │ │ │ ├── stdafx.h │ │ │ ├── targetver.h │ │ │ ├── test │ │ │ ├── test.h │ │ │ ├── test.rc │ │ │ └── xmake.lua │ │ ├── xmake_cli/ │ │ │ ├── hello/ │ │ │ │ ├── src/ │ │ │ │ │ ├── lni/ │ │ │ │ │ │ └── main.c │ │ │ │ │ └── lua/ │ │ │ │ │ └── main.lua │ │ │ │ └── xmake.lua │ │ │ ├── ide_integration/ │ │ │ │ ├── assets/ │ │ │ │ │ ├── targetpath.lua │ │ │ │ │ └── targets.lua │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ └── xmake/ │ │ │ ├── src/ │ │ │ │ ├── main.c │ │ │ │ └── xmake.rc │ │ │ └── xmake.lua │ │ └── zig/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.zig │ │ │ └── xmake.lua │ │ ├── console_c_call_zig/ │ │ │ ├── src/ │ │ │ │ ├── main.c │ │ │ │ └── test.zig │ │ │ └── xmake.lua │ │ ├── shared_library/ │ │ │ ├── src/ │ │ │ │ ├── main.zig │ │ │ │ └── test.zig │ │ │ └── xmake.lua │ │ └── static_library/ │ │ ├── src/ │ │ │ ├── main.zig │ │ │ └── test.zig │ │ └── xmake.lua │ ├── run.lua │ ├── runner.lua │ ├── test/ │ │ └── test.lua │ ├── test_utils/ │ │ ├── check.lua │ │ ├── context.lua │ │ ├── print_error.lua │ │ ├── test_assert.lua │ │ ├── test_build.lua │ │ └── test_skip.lua │ └── ui/ │ ├── desktop.lua │ ├── dialog.lua │ ├── events.lua │ ├── inputdialog.lua │ ├── mconfdialog.lua │ ├── utf8dialog.lua │ └── window.lua └── xmake/ ├── actions/ │ ├── build/ │ │ ├── build.lua │ │ ├── build_files.lua │ │ ├── check.lua │ │ ├── cleaner.lua │ │ ├── deprecated/ │ │ │ ├── build.lua │ │ │ ├── build_files.lua │ │ │ └── kinds/ │ │ │ ├── binary.lua │ │ │ ├── moduleonly.lua │ │ │ ├── object.lua │ │ │ ├── rule_groups.lua │ │ │ ├── shared.lua │ │ │ └── static.lua │ │ ├── main.lua │ │ └── xmake.lua │ ├── clean/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── config/ │ │ ├── configfiles.lua │ │ ├── main.lua │ │ ├── menuconf.lua │ │ ├── scangen.lua │ │ └── xmake.lua │ ├── create/ │ │ ├── main.lua │ │ ├── template.lua │ │ └── xmake.lua │ ├── global/ │ │ ├── main.lua │ │ ├── menuconf.lua │ │ └── xmake.lua │ ├── install/ │ │ ├── install.lua │ │ ├── install_admin.lua │ │ ├── main.lua │ │ └── xmake.lua │ ├── package/ │ │ ├── local/ │ │ │ └── main.lua │ │ ├── main.lua │ │ ├── oldpkg/ │ │ │ └── main.lua │ │ ├── remote/ │ │ │ └── main.lua │ │ └── xmake.lua │ ├── require/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── run/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── service/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── test/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── uninstall/ │ │ ├── main.lua │ │ ├── uninstall.lua │ │ ├── uninstall_admin.lua │ │ └── xmake.lua │ └── update/ │ ├── main.lua │ └── xmake.lua ├── core/ │ ├── _xmake_main.lua │ ├── base/ │ │ ├── base64.lua │ │ ├── binutils.lua │ │ ├── bit.lua │ │ ├── bloom_filter.lua │ │ ├── bytes.lua │ │ ├── cli.lua │ │ ├── colors.lua │ │ ├── compat/ │ │ │ ├── bit.lua │ │ │ └── env.lua │ │ ├── coroutine.lua │ │ ├── cpu.lua │ │ ├── debugger.lua │ │ ├── deprecated.lua │ │ ├── dump.lua │ │ ├── emoji.lua │ │ ├── filter.lua │ │ ├── fwatcher.lua │ │ ├── global.lua │ │ ├── graph.lua │ │ ├── hash.lua │ │ ├── hashset.lua │ │ ├── heap.lua │ │ ├── interpreter.lua │ │ ├── io.lua │ │ ├── json.lua │ │ ├── libc.lua │ │ ├── linuxos.lua │ │ ├── list.lua │ │ ├── log.lua │ │ ├── macos.lua │ │ ├── math.lua │ │ ├── memory.lua │ │ ├── object.lua │ │ ├── option.lua │ │ ├── os.lua │ │ ├── path.lua │ │ ├── pipe.lua │ │ ├── poller.lua │ │ ├── private/ │ │ │ ├── async_task.lua │ │ │ ├── instance_deps.lua │ │ │ ├── is_cross.lua │ │ │ ├── match_copyfiles.lua │ │ │ ├── pipe_event.lua │ │ │ └── select_script.lua │ │ ├── privilege.lua │ │ ├── process.lua │ │ ├── profiler.lua │ │ ├── queue.lua │ │ ├── scheduler.lua │ │ ├── scopeinfo.lua │ │ ├── semver.lua │ │ ├── serialize.lua │ │ ├── signal.lua │ │ ├── singleton.lua │ │ ├── socket.lua │ │ ├── string.lua │ │ ├── table.lua │ │ ├── task.lua │ │ ├── text.lua │ │ ├── thread.lua │ │ ├── timer.lua │ │ ├── todisplay.lua │ │ ├── tty.lua │ │ ├── utf8.lua │ │ ├── utils.lua │ │ ├── winos.lua │ │ ├── xmake.lua │ │ └── xml.lua │ ├── cache/ │ │ ├── detectcache.lua │ │ ├── global_detectcache.lua │ │ ├── globalcache.lua │ │ ├── localcache.lua │ │ └── memcache.lua │ ├── compress/ │ │ └── lz4.lua │ ├── language/ │ │ ├── language.lua │ │ └── menu.lua │ ├── main.lua │ ├── package/ │ │ ├── component.lua │ │ ├── package.lua │ │ ├── repository.lua │ │ └── scheme.lua │ ├── platform/ │ │ ├── environment.lua │ │ ├── menu.lua │ │ └── platform.lua │ ├── project/ │ │ ├── cache.lua │ │ ├── config.lua │ │ ├── deprecated/ │ │ │ └── project.lua │ │ ├── option.lua │ │ ├── package.lua │ │ ├── policy.lua │ │ ├── project.lua │ │ ├── rule.lua │ │ └── target.lua │ ├── sandbox/ │ │ ├── modules/ │ │ │ ├── assert.lua │ │ │ ├── catch.lua │ │ │ ├── coroutine.lua │ │ │ ├── cprint.lua │ │ │ ├── cprintf.lua │ │ │ ├── debug.lua │ │ │ ├── dprint.lua │ │ │ ├── dprintf.lua │ │ │ ├── finally.lua │ │ │ ├── find_package.lua │ │ │ ├── find_packages.lua │ │ │ ├── format.lua │ │ │ ├── get_config.lua │ │ │ ├── has_config.lua │ │ │ ├── has_package.lua │ │ │ ├── hash.lua │ │ │ ├── import/ │ │ │ │ ├── core/ │ │ │ │ │ ├── base/ │ │ │ │ │ │ ├── base64.lua │ │ │ │ │ │ ├── binutils.lua │ │ │ │ │ │ ├── bit.lua │ │ │ │ │ │ ├── bloom_filter.lua │ │ │ │ │ │ ├── bytes.lua │ │ │ │ │ │ ├── cli.lua │ │ │ │ │ │ ├── colors.lua │ │ │ │ │ │ ├── cpu.lua │ │ │ │ │ │ ├── dlist.lua │ │ │ │ │ │ ├── filter.lua │ │ │ │ │ │ ├── fwatcher.lua │ │ │ │ │ │ ├── global.lua │ │ │ │ │ │ ├── graph.lua │ │ │ │ │ │ ├── hashset.lua │ │ │ │ │ │ ├── heap.lua │ │ │ │ │ │ ├── interpreter.lua │ │ │ │ │ │ ├── json.lua │ │ │ │ │ │ ├── libc.lua │ │ │ │ │ │ ├── list.lua │ │ │ │ │ │ ├── memory.lua │ │ │ │ │ │ ├── object.lua │ │ │ │ │ │ ├── option.lua │ │ │ │ │ │ ├── pipe.lua │ │ │ │ │ │ ├── privilege.lua │ │ │ │ │ │ ├── process.lua │ │ │ │ │ │ ├── profiler.lua │ │ │ │ │ │ ├── queue.lua │ │ │ │ │ │ ├── scheduler.lua │ │ │ │ │ │ ├── semver.lua │ │ │ │ │ │ ├── signal.lua │ │ │ │ │ │ ├── singleton.lua │ │ │ │ │ │ ├── socket.lua │ │ │ │ │ │ ├── task.lua │ │ │ │ │ │ ├── text.lua │ │ │ │ │ │ ├── thread.lua │ │ │ │ │ │ ├── tty.lua │ │ │ │ │ │ └── xml.lua │ │ │ │ │ ├── cache/ │ │ │ │ │ │ ├── detectcache.lua │ │ │ │ │ │ ├── global_detectcache.lua │ │ │ │ │ │ ├── globalcache.lua │ │ │ │ │ │ ├── localcache.lua │ │ │ │ │ │ └── memcache.lua │ │ │ │ │ ├── compress/ │ │ │ │ │ │ └── lz4.lua │ │ │ │ │ ├── language/ │ │ │ │ │ │ ├── language.lua │ │ │ │ │ │ └── menu.lua │ │ │ │ │ ├── package/ │ │ │ │ │ │ ├── package.lua │ │ │ │ │ │ └── repository.lua │ │ │ │ │ ├── platform/ │ │ │ │ │ │ ├── menu.lua │ │ │ │ │ │ └── platform.lua │ │ │ │ │ ├── project/ │ │ │ │ │ │ ├── config.lua │ │ │ │ │ │ ├── menu.lua │ │ │ │ │ │ ├── option.lua │ │ │ │ │ │ ├── policy.lua │ │ │ │ │ │ ├── project.lua │ │ │ │ │ │ ├── rule.lua │ │ │ │ │ │ ├── target.lua │ │ │ │ │ │ └── task.lua │ │ │ │ │ ├── sandbox/ │ │ │ │ │ │ ├── module.lua │ │ │ │ │ │ └── sandbox.lua │ │ │ │ │ ├── theme/ │ │ │ │ │ │ └── theme.lua │ │ │ │ │ ├── tool/ │ │ │ │ │ │ ├── compiler.lua │ │ │ │ │ │ ├── linker.lua │ │ │ │ │ │ └── toolchain.lua │ │ │ │ │ └── ui/ │ │ │ │ │ ├── action.lua │ │ │ │ │ ├── application.lua │ │ │ │ │ ├── border.lua │ │ │ │ │ ├── boxdialog.lua │ │ │ │ │ ├── button.lua │ │ │ │ │ ├── canvas.lua │ │ │ │ │ ├── choicebox.lua │ │ │ │ │ ├── choicedialog.lua │ │ │ │ │ ├── curses.lua │ │ │ │ │ ├── desktop.lua │ │ │ │ │ ├── dialog.lua │ │ │ │ │ ├── event.lua │ │ │ │ │ ├── inputdialog.lua │ │ │ │ │ ├── label.lua │ │ │ │ │ ├── log.lua │ │ │ │ │ ├── mconfdialog.lua │ │ │ │ │ ├── menubar.lua │ │ │ │ │ ├── menuconf.lua │ │ │ │ │ ├── object.lua │ │ │ │ │ ├── panel.lua │ │ │ │ │ ├── point.lua │ │ │ │ │ ├── program.lua │ │ │ │ │ ├── rect.lua │ │ │ │ │ ├── statusbar.lua │ │ │ │ │ ├── textarea.lua │ │ │ │ │ ├── textdialog.lua │ │ │ │ │ ├── textedit.lua │ │ │ │ │ ├── view.lua │ │ │ │ │ └── window.lua │ │ │ │ ├── lib/ │ │ │ │ │ ├── detect/ │ │ │ │ │ │ ├── find_directory.lua │ │ │ │ │ │ ├── find_file.lua │ │ │ │ │ │ ├── find_library.lua │ │ │ │ │ │ ├── find_path.lua │ │ │ │ │ │ ├── find_program.lua │ │ │ │ │ │ └── find_programver.lua │ │ │ │ │ ├── lni.lua │ │ │ │ │ ├── lua/ │ │ │ │ │ │ └── package.lua │ │ │ │ │ └── luajit/ │ │ │ │ │ ├── bcsave.lua │ │ │ │ │ ├── bit.lua │ │ │ │ │ ├── ffi.lua │ │ │ │ │ └── jit.lua │ │ │ │ └── private/ │ │ │ │ └── core/ │ │ │ │ └── base/ │ │ │ │ ├── is_cross.lua │ │ │ │ ├── match_copyfiles.lua │ │ │ │ └── select_script.lua │ │ │ ├── import.lua │ │ │ ├── inherit.lua │ │ │ ├── interpreter/ │ │ │ │ ├── format.lua │ │ │ │ ├── getenv.lua │ │ │ │ ├── hash.lua │ │ │ │ ├── ipairs.lua │ │ │ │ ├── is_host.lua │ │ │ │ ├── is_subhost.lua │ │ │ │ ├── linuxos.lua │ │ │ │ ├── macos.lua │ │ │ │ ├── math.lua │ │ │ │ ├── os.lua │ │ │ │ ├── pairs.lua │ │ │ │ ├── path.lua │ │ │ │ ├── print.lua │ │ │ │ ├── printf.lua │ │ │ │ ├── string.lua │ │ │ │ ├── table.lua │ │ │ │ ├── tonumber.lua │ │ │ │ ├── tostring.lua │ │ │ │ ├── type.lua │ │ │ │ ├── unpack.lua │ │ │ │ ├── utf8.lua │ │ │ │ ├── winos.lua │ │ │ │ └── xmake.lua │ │ │ ├── io.lua │ │ │ ├── ipairs.lua │ │ │ ├── irpairs.lua │ │ │ ├── is_arch.lua │ │ │ ├── is_config.lua │ │ │ ├── is_host.lua │ │ │ ├── is_mode.lua │ │ │ ├── is_plat.lua │ │ │ ├── is_subhost.lua │ │ │ ├── linuxos.lua │ │ │ ├── macos.lua │ │ │ ├── math.lua │ │ │ ├── os.lua │ │ │ ├── pairs.lua │ │ │ ├── path.lua │ │ │ ├── print.lua │ │ │ ├── printf.lua │ │ │ ├── raise.lua │ │ │ ├── string.lua │ │ │ ├── table.lua │ │ │ ├── todisplay.lua │ │ │ ├── tonumber.lua │ │ │ ├── tostring.lua │ │ │ ├── try.lua │ │ │ ├── type.lua │ │ │ ├── unpack.lua │ │ │ ├── utf8.lua │ │ │ ├── utils.lua │ │ │ ├── val.lua │ │ │ ├── vformat.lua │ │ │ ├── vprint.lua │ │ │ ├── vprintf.lua │ │ │ ├── winos.lua │ │ │ ├── wprint.lua │ │ │ └── xmake.lua │ │ └── sandbox.lua │ ├── theme/ │ │ └── theme.lua │ ├── tool/ │ │ ├── builder.lua │ │ ├── compiler.lua │ │ ├── linker.lua │ │ ├── tool.lua │ │ └── toolchain.lua │ └── ui/ │ ├── action.lua │ ├── application.lua │ ├── border.lua │ ├── boxdialog.lua │ ├── button.lua │ ├── canvas.lua │ ├── choicebox.lua │ ├── choicedialog.lua │ ├── curses.lua │ ├── desktop.lua │ ├── dialog.lua │ ├── event.lua │ ├── inputdialog.lua │ ├── label.lua │ ├── log.lua │ ├── mconfdialog.lua │ ├── menubar.lua │ ├── menuconf.lua │ ├── object.lua │ ├── panel.lua │ ├── point.lua │ ├── program.lua │ ├── rect.lua │ ├── scrollbar.lua │ ├── statusbar.lua │ ├── textarea.lua │ ├── textdialog.lua │ ├── textedit.lua │ ├── view.lua │ └── window.lua ├── includes/ │ ├── check/ │ │ ├── check_bigendian.lua │ │ ├── check_cflags.lua │ │ ├── check_cfuncs.lua │ │ ├── check_cincludes.lua │ │ ├── check_csnippets.lua │ │ ├── check_ctypes.lua │ │ ├── check_cxxflags.lua │ │ ├── check_cxxfuncs.lua │ │ ├── check_cxxincludes.lua │ │ ├── check_cxxsnippets.lua │ │ ├── check_cxxtypes.lua │ │ ├── check_features.lua │ │ ├── check_links.lua │ │ ├── check_macros.lua │ │ ├── check_sizeof.lua │ │ ├── check_syslinks.lua │ │ └── xmake.lua │ ├── qt/ │ │ ├── qt_add_static_plugins.lua │ │ └── xmake.lua │ ├── xpack/ │ │ └── xmake.lua │ └── xrepo/ │ └── xmake.lua ├── languages/ │ ├── asm/ │ │ ├── load.lua │ │ └── xmake.lua │ ├── c/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── c++/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── csharp/ │ │ ├── load.lua │ │ └── xmake.lua │ ├── cuda/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── dlang/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── fortran/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── golang/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── kotlin/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── msrc/ │ │ ├── load.lua │ │ └── xmake.lua │ ├── nim/ │ │ ├── load.lua │ │ └── xmake.lua │ ├── objc++/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── pascal/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── rust/ │ │ ├── check_main.lua │ │ ├── load.lua │ │ └── xmake.lua │ ├── swift/ │ │ ├── load.lua │ │ └── xmake.lua │ └── zig/ │ ├── check_main.lua │ ├── load.lua │ └── xmake.lua ├── modules/ │ ├── async/ │ │ ├── jobgraph.lua │ │ └── runjobs.lua │ ├── cli/ │ │ ├── amalgamate.lua │ │ ├── archive.lua │ │ ├── binutils/ │ │ │ ├── bin2c.lua │ │ │ └── bin2obj.lua │ │ ├── bisect.lua │ │ ├── extract.lua │ │ └── iconv.lua │ ├── core/ │ │ ├── base/ │ │ │ └── license.lua │ │ ├── project/ │ │ │ └── depend.lua │ │ └── tools/ │ │ ├── ar/ │ │ │ └── has_flags.lua │ │ ├── ar.lua │ │ ├── ar2000.lua │ │ ├── ar6x.lua │ │ ├── armar.lua │ │ ├── armasm.lua │ │ ├── armasm64_msvc/ │ │ │ └── has_flags.lua │ │ ├── armasm64_msvc.lua │ │ ├── armasm_msvc/ │ │ │ └── has_flags.lua │ │ ├── armasm_msvc.lua │ │ ├── armcc/ │ │ │ └── parse_deps.lua │ │ ├── armcc.lua │ │ ├── armclang/ │ │ │ └── has_flags.lua │ │ ├── armclang.lua │ │ ├── armlink.lua │ │ ├── bl51.lua │ │ ├── c51.lua │ │ ├── cc.lua │ │ ├── circle/ │ │ │ └── has_flags.lua │ │ ├── circle.lua │ │ ├── cl/ │ │ │ ├── cfeatures.lua │ │ │ ├── cxxfeatures.lua │ │ │ ├── features.lua │ │ │ ├── has_flags.lua │ │ │ ├── parse_deps.lua │ │ │ ├── parse_deps_json.lua │ │ │ └── parse_include.lua │ │ ├── cl.lua │ │ ├── cl2000/ │ │ │ ├── has_flags.lua │ │ │ └── parse_deps.lua │ │ ├── cl2000.lua │ │ ├── cl6x/ │ │ │ ├── has_flags.lua │ │ │ └── parse_deps.lua │ │ ├── cl6x.lua │ │ ├── cl_json/ │ │ │ └── parse_deps.lua │ │ ├── clang/ │ │ │ ├── cfeatures.lua │ │ │ ├── cxxfeatures.lua │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── clang.lua │ │ ├── clang_cl/ │ │ │ └── has_flags.lua │ │ ├── clang_cl.lua │ │ ├── clangxx/ │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── clangxx.lua │ │ ├── cosmoar.lua │ │ ├── cosmocc/ │ │ │ └── has_flags.lua │ │ ├── cosmocc.lua │ │ ├── cosmocxx/ │ │ │ └── has_flags.lua │ │ ├── cosmocxx.lua │ │ ├── cparser.lua │ │ ├── cxx.lua │ │ ├── dmd/ │ │ │ └── has_flags.lua │ │ ├── dmd.lua │ │ ├── dotnet/ │ │ │ └── has_flags.lua │ │ ├── dotnet.lua │ │ ├── dpcpp/ │ │ │ ├── cfeatures.lua │ │ │ ├── cxxfeatures.lua │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── dpcpp.lua │ │ ├── emar.lua │ │ ├── emcc/ │ │ │ └── has_flags.lua │ │ ├── emcc.lua │ │ ├── emxx/ │ │ │ └── has_flags.lua │ │ ├── emxx.lua │ │ ├── fasm.lua │ │ ├── flang/ │ │ │ └── has_flags.lua │ │ ├── flang.lua │ │ ├── fpc/ │ │ │ └── has_flags.lua │ │ ├── fpc.lua │ │ ├── gcc/ │ │ │ ├── cfeatures.lua │ │ │ ├── cxxfeatures.lua │ │ │ ├── features.lua │ │ │ ├── has_flags.lua │ │ │ └── parse_deps.lua │ │ ├── gcc.lua │ │ ├── gcc_ar.lua │ │ ├── gccgo/ │ │ │ └── has_flags.lua │ │ ├── gccgo.lua │ │ ├── gdc/ │ │ │ └── has_flags.lua │ │ ├── gdc.lua │ │ ├── gfortran/ │ │ │ └── has_flags.lua │ │ ├── gfortran.lua │ │ ├── go/ │ │ │ └── has_flags.lua │ │ ├── go.lua │ │ ├── gxx/ │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── gxx.lua │ │ ├── iarchive.lua │ │ ├── icc/ │ │ │ └── has_flags.lua │ │ ├── icc.lua │ │ ├── iccarm/ │ │ │ └── has_flags.lua │ │ ├── iccarm.lua │ │ ├── icl/ │ │ │ └── has_flags.lua │ │ ├── icl.lua │ │ ├── icpc/ │ │ │ └── has_flags.lua │ │ ├── icpc.lua │ │ ├── icpx/ │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── icpx.lua │ │ ├── icx/ │ │ │ ├── cfeatures.lua │ │ │ ├── cxxfeatures.lua │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── icx.lua │ │ ├── ifort/ │ │ │ └── has_flags.lua │ │ ├── ifort.lua │ │ ├── ifx/ │ │ │ └── has_flags.lua │ │ ├── ifx.lua │ │ ├── ilinkarm.lua │ │ ├── kotlinc_native/ │ │ │ └── has_flags.lua │ │ ├── kotlinc_native.lua │ │ ├── ld.lua │ │ ├── ld64_lld.lua │ │ ├── ld_lld.lua │ │ ├── ldc2/ │ │ │ └── has_flags.lua │ │ ├── ldc2.lua │ │ ├── link/ │ │ │ └── has_flags.lua │ │ ├── link.lua │ │ ├── lld_link.lua │ │ ├── llvm_ar.lua │ │ ├── llvm_rc.lua │ │ ├── ml/ │ │ │ └── has_flags.lua │ │ ├── ml.lua │ │ ├── ml64/ │ │ │ └── has_flags.lua │ │ ├── ml64.lua │ │ ├── mold.lua │ │ ├── nasm.lua │ │ ├── nim/ │ │ │ └── has_flags.lua │ │ ├── nim.lua │ │ ├── nvc/ │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── nvc.lua │ │ ├── nvcc/ │ │ │ └── has_flags.lua │ │ ├── nvcc.lua │ │ ├── nvcxx/ │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── nvcxx.lua │ │ ├── nvfortran/ │ │ │ └── has_flags.lua │ │ ├── nvfortran.lua │ │ ├── rc/ │ │ │ ├── has_flags.lua │ │ │ └── parse_deps.lua │ │ ├── rc.lua │ │ ├── rustc/ │ │ │ ├── has_flags.lua │ │ │ └── target_triple.lua │ │ ├── rustc.lua │ │ ├── sdar.lua │ │ ├── sdasstm8.lua │ │ ├── sdcc/ │ │ │ └── has_flags.lua │ │ ├── sdcc.lua │ │ ├── swift_frontend/ │ │ │ └── has_flags.lua │ │ ├── swift_frontend.lua │ │ ├── swiftc/ │ │ │ └── has_flags.lua │ │ ├── swiftc.lua │ │ ├── tcc/ │ │ │ └── has_flags.lua │ │ ├── tcc.lua │ │ ├── windres.lua │ │ ├── yasm.lua │ │ ├── zig/ │ │ │ └── has_flags.lua │ │ ├── zig.lua │ │ ├── zig_cc/ │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ ├── zig_cc.lua │ │ ├── zig_cxx/ │ │ │ ├── features.lua │ │ │ └── has_flags.lua │ │ └── zig_cxx.lua │ ├── detect/ │ │ ├── packages/ │ │ │ ├── find_libxml2.lua │ │ │ ├── find_mbedtls.lua │ │ │ ├── find_mkl.lua │ │ │ ├── find_mysql.lua │ │ │ ├── find_nvtx.lua │ │ │ ├── find_openssl.lua │ │ │ ├── find_pcre.lua │ │ │ ├── find_pcre2.lua │ │ │ ├── find_tbb.lua │ │ │ ├── find_vulkansdk.lua │ │ │ └── find_zlib.lua │ │ ├── sdks/ │ │ │ ├── find_android_sdk.lua │ │ │ ├── find_c51.lua │ │ │ ├── find_cross_toolchain.lua │ │ │ ├── find_cuda.lua │ │ │ ├── find_dia_sdk.lua │ │ │ ├── find_dotnet.lua │ │ │ ├── find_emsdk.lua │ │ │ ├── find_hdk.lua │ │ │ ├── find_iarsdk.lua │ │ │ ├── find_iccenv.lua │ │ │ ├── find_icxenv.lua │ │ │ ├── find_ifortenv.lua │ │ │ ├── find_ifxenv.lua │ │ │ ├── find_masm32.lua │ │ │ ├── find_matlab.lua │ │ │ ├── find_matlab_runtime.lua │ │ │ ├── find_mdk.lua │ │ │ ├── find_mingw.lua │ │ │ ├── find_ndk.lua │ │ │ ├── find_qt.lua │ │ │ ├── find_sdasstm8.lua │ │ │ ├── find_vcpkgdir.lua │ │ │ ├── find_vstudio.lua │ │ │ ├── find_vulkansdk.lua │ │ │ ├── find_wasisdk.lua │ │ │ ├── find_wdk.lua │ │ │ ├── find_xcode.lua │ │ │ └── matlab.lua │ │ └── tools/ │ │ ├── find_7z.lua │ │ ├── find_appimagetool.lua │ │ ├── find_apt.lua │ │ ├── find_aqt.lua │ │ ├── find_ar.lua │ │ ├── find_ar2000.lua │ │ ├── find_ar6x.lua │ │ ├── find_armar.lua │ │ ├── find_armasm.lua │ │ ├── find_armasm64_msvc.lua │ │ ├── find_armasm_msvc.lua │ │ ├── find_armcc.lua │ │ ├── find_armclang.lua │ │ ├── find_armlink.lua │ │ ├── find_asm6x.lua │ │ ├── find_asn1c.lua │ │ ├── find_bash.lua │ │ ├── find_bazel.lua │ │ ├── find_bison.lua │ │ ├── find_bl51.lua │ │ ├── find_brew.lua │ │ ├── find_bzip2.lua │ │ ├── find_c51.lua │ │ ├── find_cargo.lua │ │ ├── find_cc.lua │ │ ├── find_ccache.lua │ │ ├── find_circle.lua │ │ ├── find_cl.lua │ │ ├── find_cl2000.lua │ │ ├── find_cl6x.lua │ │ ├── find_clang.lua │ │ ├── find_clang_cl.lua │ │ ├── find_clang_format.lua │ │ ├── find_clang_scan_deps.lua │ │ ├── find_clang_tidy.lua │ │ ├── find_clangxx.lua │ │ ├── find_clib.lua │ │ ├── find_cmake.lua │ │ ├── find_codesign.lua │ │ ├── find_conan.lua │ │ ├── find_conda.lua │ │ ├── find_cosmoar.lua │ │ ├── find_cosmocc.lua │ │ ├── find_cosmocxx.lua │ │ ├── find_cparser.lua │ │ ├── find_cpp.lua │ │ ├── find_cudagdb.lua │ │ ├── find_cudamemcheck.lua │ │ ├── find_curl.lua │ │ ├── find_cxx.lua │ │ ├── find_cxxbridge.lua │ │ ├── find_debuild.lua │ │ ├── find_devenv.lua │ │ ├── find_dmd.lua │ │ ├── find_dotnet.lua │ │ ├── find_doxygen.lua │ │ ├── find_dpcpp.lua │ │ ├── find_dsymutil.lua │ │ ├── find_dub.lua │ │ ├── find_dumpbin.lua │ │ ├── find_dxc.lua │ │ ├── find_emar.lua │ │ ├── find_emcc.lua │ │ ├── find_emrun.lua │ │ ├── find_emxx.lua │ │ ├── find_fasm.lua │ │ ├── find_flang.lua │ │ ├── find_flex.lua │ │ ├── find_fpc.lua │ │ ├── find_gcc.lua │ │ ├── find_gcc_ar.lua │ │ ├── find_gccgo.lua │ │ ├── find_gdb.lua │ │ ├── find_gdc.lua │ │ ├── find_gfortran.lua │ │ ├── find_git.lua │ │ ├── find_glslangValidator.lua │ │ ├── find_glslc.lua │ │ ├── find_gn.lua │ │ ├── find_go.lua │ │ ├── find_gxx.lua │ │ ├── find_gzip.lua │ │ ├── find_hdiutil.lua │ │ ├── find_iarchive.lua │ │ ├── find_iasmarm.lua │ │ ├── find_icc.lua │ │ ├── find_iccarm.lua │ │ ├── find_icl.lua │ │ ├── find_icpc.lua │ │ ├── find_icpx.lua │ │ ├── find_icx.lua │ │ ├── find_ideviceinstaller.lua │ │ ├── find_ifort.lua │ │ ├── find_ifx.lua │ │ ├── find_ilinkarm.lua │ │ ├── find_iverilog.lua │ │ ├── find_java.lua │ │ ├── find_jom.lua │ │ ├── find_kotlinc_native.lua │ │ ├── find_ld.lua │ │ ├── find_ld64_lld.lua │ │ ├── find_ld_lld.lua │ │ ├── find_ldc2.lua │ │ ├── find_lex.lua │ │ ├── find_lib.lua │ │ ├── find_link.lua │ │ ├── find_lipo.lua │ │ ├── find_lld_link.lua │ │ ├── find_lldb.lua │ │ ├── find_llvm_ar.lua │ │ ├── find_llvm_as.lua │ │ ├── find_llvm_dlltool.lua │ │ ├── find_llvm_rc.lua │ │ ├── find_lua.lua │ │ ├── find_luajit.lua │ │ ├── find_make.lua │ │ ├── find_meson.lua │ │ ├── find_metal.lua │ │ ├── find_metallib.lua │ │ ├── find_midl.lua │ │ ├── find_ml.lua │ │ ├── find_ml64.lua │ │ ├── find_mold.lua │ │ ├── find_msbuild.lua │ │ ├── find_nasm.lua │ │ ├── find_nim.lua │ │ ├── find_nimble.lua │ │ ├── find_ninja.lua │ │ ├── find_nix.lua │ │ ├── find_nmake.lua │ │ ├── find_nmap.lua │ │ ├── find_nnd.lua │ │ ├── find_nvc.lua │ │ ├── find_nvcc.lua │ │ ├── find_nvcxx.lua │ │ ├── find_nvfortran.lua │ │ ├── find_objcopy.lua │ │ ├── find_oh51.lua │ │ ├── find_ollydbg.lua │ │ ├── find_pacman.lua │ │ ├── find_patch.lua │ │ ├── find_perl.lua │ │ ├── find_ping.lua │ │ ├── find_pkg_config.lua │ │ ├── find_pkgconf.lua │ │ ├── find_powershell.lua │ │ ├── find_pwsh.lua │ │ ├── find_python.lua │ │ ├── find_python2.lua │ │ ├── find_python3.lua │ │ ├── find_qmake.lua │ │ ├── find_raddbg.lua │ │ ├── find_ranlib.lua │ │ ├── find_rc.lua │ │ ├── find_renderdoc.lua │ │ ├── find_rpm.lua │ │ ├── find_rustc.lua │ │ ├── find_scons.lua │ │ ├── find_sdar.lua │ │ ├── find_sdcc.lua │ │ ├── find_strip.lua │ │ ├── find_sudo.lua │ │ ├── find_swift_frontend.lua │ │ ├── find_swiftc.lua │ │ ├── find_swig.lua │ │ ├── find_tar.lua │ │ ├── find_tcc.lua │ │ ├── find_tclsh.lua │ │ ├── find_unzip.lua │ │ ├── find_valac.lua │ │ ├── find_vcpkg.lua │ │ ├── find_verilator.lua │ │ ├── find_vsjitdebugger.lua │ │ ├── find_vswhere.lua │ │ ├── find_vvp.lua │ │ ├── find_wasm_ld.lua │ │ ├── find_wget.lua │ │ ├── find_where.lua │ │ ├── find_windbg.lua │ │ ├── find_windres.lua │ │ ├── find_wine.lua │ │ ├── find_x64dbg.lua │ │ ├── find_xrepo.lua │ │ ├── find_xz.lua │ │ ├── find_yacc.lua │ │ ├── find_yasm.lua │ │ ├── find_yum.lua │ │ ├── find_zig.lua │ │ ├── find_zig_cc.lua │ │ ├── find_zig_cxx.lua │ │ ├── find_zip.lua │ │ ├── find_zstd.lua │ │ └── find_zypper.lua │ ├── devel/ │ │ ├── debugger/ │ │ │ └── run.lua │ │ └── git/ │ │ ├── apply.lua │ │ ├── asgiturl.lua │ │ ├── branch.lua │ │ ├── branches.lua │ │ ├── checkout.lua │ │ ├── checkurl.lua │ │ ├── clean.lua │ │ ├── clone.lua │ │ ├── init.lua │ │ ├── lastcommit.lua │ │ ├── ls_remote.lua │ │ ├── pull.lua │ │ ├── push.lua │ │ ├── refs.lua │ │ ├── remote.lua │ │ ├── reset.lua │ │ ├── submodule/ │ │ │ ├── clean.lua │ │ │ ├── reset.lua │ │ │ └── update.lua │ │ ├── support.lua │ │ └── tags.lua │ ├── lib/ │ │ └── detect/ │ │ ├── check_bigendian.lua │ │ ├── check_csnippets.lua │ │ ├── check_cxsnippets.lua │ │ ├── check_cxxsnippets.lua │ │ ├── check_fcsnippets.lua │ │ ├── check_importfiles.lua │ │ ├── check_msnippets.lua │ │ ├── check_mxxsnippets.lua │ │ ├── check_sizeof.lua │ │ ├── features.lua │ │ ├── find_cudadevices.lua │ │ ├── find_package.lua │ │ ├── find_tool.lua │ │ ├── find_toolname.lua │ │ ├── has_cfuncs.lua │ │ ├── has_cincludes.lua │ │ ├── has_ctypes.lua │ │ ├── has_cxxfuncs.lua │ │ ├── has_cxxincludes.lua │ │ ├── has_cxxtypes.lua │ │ ├── has_features.lua │ │ ├── has_flags.lua │ │ └── pkgconfig.lua │ ├── net/ │ │ ├── fasturl.lua │ │ ├── http/ │ │ │ └── download.lua │ │ ├── ping.lua │ │ └── proxy.lua │ ├── os/ │ │ └── winver.lua │ ├── package/ │ │ ├── manager/ │ │ │ ├── apt/ │ │ │ │ ├── find_package.lua │ │ │ │ ├── install_package.lua │ │ │ │ └── search_package.lua │ │ │ ├── brew/ │ │ │ │ ├── find_package.lua │ │ │ │ └── install_package.lua │ │ │ ├── cargo/ │ │ │ │ ├── configurations.lua │ │ │ │ ├── find_package.lua │ │ │ │ └── install_package.lua │ │ │ ├── clib/ │ │ │ │ ├── configurations.lua │ │ │ │ ├── find_package.lua │ │ │ │ └── install_package.lua │ │ │ ├── cmake/ │ │ │ │ ├── configurations.lua │ │ │ │ └── find_package.lua │ │ │ ├── conan/ │ │ │ │ ├── configurations.lua │ │ │ │ ├── find_package.lua │ │ │ │ ├── install_package.lua │ │ │ │ ├── search_package.lua │ │ │ │ ├── v1/ │ │ │ │ │ └── install_package.lua │ │ │ │ └── v2/ │ │ │ │ └── install_package.lua │ │ │ ├── conda/ │ │ │ │ ├── find_package.lua │ │ │ │ ├── install_package.lua │ │ │ │ └── search_package.lua │ │ │ ├── dub/ │ │ │ │ ├── find_package.lua │ │ │ │ └── install_package.lua │ │ │ ├── find_package.lua │ │ │ ├── install_package.lua │ │ │ ├── kotlin-native/ │ │ │ │ ├── configurations.lua │ │ │ │ ├── find_package.lua │ │ │ │ └── install_package.lua │ │ │ ├── nimble/ │ │ │ │ ├── find_package.lua │ │ │ │ └── install_package.lua │ │ │ ├── nix/ │ │ │ │ ├── find_package.lua │ │ │ │ ├── install_package.lua │ │ │ │ └── search_package.lua │ │ │ ├── nuget/ │ │ │ │ ├── find_package.lua │ │ │ │ └── install_package.lua │ │ │ ├── pacman/ │ │ │ │ ├── configurations.lua │ │ │ │ ├── find_package.lua │ │ │ │ ├── get_package_name.lua │ │ │ │ └── install_package.lua │ │ │ ├── pkgconfig/ │ │ │ │ └── find_package.lua │ │ │ ├── portage/ │ │ │ │ ├── find_package.lua │ │ │ │ └── install_package.lua │ │ │ ├── system/ │ │ │ │ └── find_package.lua │ │ │ ├── vcpkg/ │ │ │ │ ├── configurations.lua │ │ │ │ ├── find_package.lua │ │ │ │ ├── install_package.lua │ │ │ │ ├── search_package.lua │ │ │ │ └── utils.lua │ │ │ ├── xmake/ │ │ │ │ ├── find_package.lua │ │ │ │ └── search_package.lua │ │ │ ├── yum/ │ │ │ │ └── install_package.lua │ │ │ └── zypper/ │ │ │ ├── find_package.lua │ │ │ ├── install_package.lua │ │ │ └── search_package.lua │ │ └── tools/ │ │ ├── autoconf.lua │ │ ├── bazel.lua │ │ ├── cmake.lua │ │ ├── gn.lua │ │ ├── jom.lua │ │ ├── make.lua │ │ ├── meson.lua │ │ ├── msbuild.lua │ │ ├── ninja.lua │ │ ├── nmake.lua │ │ ├── scons.lua │ │ └── xmake.lua │ ├── private/ │ │ ├── action/ │ │ │ ├── clean/ │ │ │ │ └── remove_files.lua │ │ │ ├── require/ │ │ │ │ ├── check.lua │ │ │ │ ├── clean.lua │ │ │ │ ├── download.lua │ │ │ │ ├── export.lua │ │ │ │ ├── fetch.lua │ │ │ │ ├── impl/ │ │ │ │ │ ├── actions/ │ │ │ │ │ │ ├── check.lua │ │ │ │ │ │ ├── download.lua │ │ │ │ │ │ ├── download_resources.lua │ │ │ │ │ │ ├── install.lua │ │ │ │ │ │ ├── patch_sources.lua │ │ │ │ │ │ └── test.lua │ │ │ │ │ ├── check_api.lua │ │ │ │ │ ├── download_packages.lua │ │ │ │ │ ├── environment.lua │ │ │ │ │ ├── export_packages.lua │ │ │ │ │ ├── import_packages.lua │ │ │ │ │ ├── install_packages.lua │ │ │ │ │ ├── lock_packages.lua │ │ │ │ │ ├── package.lua │ │ │ │ │ ├── packagenv.lua │ │ │ │ │ ├── register_packages.lua │ │ │ │ │ ├── remove_packages.lua │ │ │ │ │ ├── repository.lua │ │ │ │ │ ├── search_packages.lua │ │ │ │ │ ├── uninstall_packages.lua │ │ │ │ │ └── utils/ │ │ │ │ │ ├── filter.lua │ │ │ │ │ ├── get_requires.lua │ │ │ │ │ ├── requirekey.lua │ │ │ │ │ └── url_filename.lua │ │ │ │ ├── import.lua │ │ │ │ ├── info.lua │ │ │ │ ├── install.lua │ │ │ │ ├── list.lua │ │ │ │ ├── register.lua │ │ │ │ ├── scan.lua │ │ │ │ ├── search.lua │ │ │ │ └── uninstall.lua │ │ │ ├── run/ │ │ │ │ └── runenvs.lua │ │ │ ├── trybuild/ │ │ │ │ ├── autoconf.lua │ │ │ │ ├── bazel.lua │ │ │ │ ├── cmake.lua │ │ │ │ ├── make.lua │ │ │ │ ├── meson.lua │ │ │ │ ├── msbuild.lua │ │ │ │ ├── ndkbuild.lua │ │ │ │ ├── ninja.lua │ │ │ │ ├── scons.lua │ │ │ │ ├── xcodebuild.lua │ │ │ │ └── xrepo.lua │ │ │ ├── update/ │ │ │ │ └── fetch_version.lua │ │ │ └── utils.lua │ │ ├── async/ │ │ │ ├── buildjobs.lua │ │ │ ├── jobpool.lua │ │ │ └── runjobs.lua │ │ ├── cache/ │ │ │ └── build_cache.lua │ │ ├── check/ │ │ │ ├── checker.lua │ │ │ ├── checkers/ │ │ │ │ ├── api/ │ │ │ │ │ ├── api_checker.lua │ │ │ │ │ ├── package/ │ │ │ │ │ │ ├── kind.lua │ │ │ │ │ │ └── versionfiles.lua │ │ │ │ │ └── target/ │ │ │ │ │ ├── asflags.lua │ │ │ │ │ ├── cflags.lua │ │ │ │ │ ├── configfiles.lua │ │ │ │ │ ├── cxflags.lua │ │ │ │ │ ├── cxxflags.lua │ │ │ │ │ ├── encodings.lua │ │ │ │ │ ├── exceptions.lua │ │ │ │ │ ├── files.lua │ │ │ │ │ ├── fpmodels.lua │ │ │ │ │ ├── frameworkdirs.lua │ │ │ │ │ ├── headerfiles.lua │ │ │ │ │ ├── includedirs.lua │ │ │ │ │ ├── installfiles.lua │ │ │ │ │ ├── kind.lua │ │ │ │ │ ├── languages.lua │ │ │ │ │ ├── ldflags.lua │ │ │ │ │ ├── license.lua │ │ │ │ │ ├── linkdirs.lua │ │ │ │ │ ├── optimize.lua │ │ │ │ │ ├── packages.lua │ │ │ │ │ ├── shflags.lua │ │ │ │ │ ├── strip.lua │ │ │ │ │ ├── symbols.lua │ │ │ │ │ ├── vectorexts.lua │ │ │ │ │ ├── version.lua │ │ │ │ │ └── warnings.lua │ │ │ │ ├── clang/ │ │ │ │ │ └── tidy.lua │ │ │ │ ├── cuda/ │ │ │ │ │ └── devlink.lua │ │ │ │ └── syntax.lua │ │ │ └── show.lua │ │ ├── detect/ │ │ │ ├── check_targetname.lua │ │ │ ├── find_cudatool.lua │ │ │ ├── find_platform.lua │ │ │ └── find_similar_targetnames.lua │ │ ├── service/ │ │ │ ├── add_user.lua │ │ │ ├── clean_files.lua │ │ │ ├── client.lua │ │ │ ├── client_config.lua │ │ │ ├── connect_service.lua │ │ │ ├── disconnect_service.lua │ │ │ ├── distcc_build/ │ │ │ │ ├── client.lua │ │ │ │ ├── client_session.lua │ │ │ │ ├── server.lua │ │ │ │ └── server_session.lua │ │ │ ├── gen_token.lua │ │ │ ├── message.lua │ │ │ ├── pull_files.lua │ │ │ ├── reconnect_service.lua │ │ │ ├── remote_build/ │ │ │ │ ├── action.lua │ │ │ │ ├── client.lua │ │ │ │ ├── filesync.lua │ │ │ │ ├── server.lua │ │ │ │ └── server_session.lua │ │ │ ├── remote_cache/ │ │ │ │ ├── client.lua │ │ │ │ ├── server.lua │ │ │ │ └── server_session.lua │ │ │ ├── restart_service.lua │ │ │ ├── rm_user.lua │ │ │ ├── server.lua │ │ │ ├── server_config.lua │ │ │ ├── service.lua │ │ │ ├── show_logs.lua │ │ │ ├── show_status.lua │ │ │ ├── start_service.lua │ │ │ ├── stop_service.lua │ │ │ ├── stream.lua │ │ │ └── sync_files.lua │ │ ├── tools/ │ │ │ ├── ccache.lua │ │ │ ├── codesign.lua │ │ │ ├── go/ │ │ │ │ └── goenv.lua │ │ │ ├── rust/ │ │ │ │ └── check_target.lua │ │ │ └── vstool.lua │ │ ├── utils/ │ │ │ ├── batchcmds.lua │ │ │ ├── bcsave.lua │ │ │ ├── complete.lua │ │ │ ├── complete_helper.lua │ │ │ ├── completer.lua │ │ │ ├── executable_path.lua │ │ │ ├── package.lua │ │ │ ├── rule.lua │ │ │ ├── statistics.lua │ │ │ ├── target.lua │ │ │ ├── toolchain.lua │ │ │ ├── trim_trailing_spaces.lua │ │ │ └── upgrade_vsproj.lua │ │ └── xrepo/ │ │ ├── action/ │ │ │ ├── add-repo.lua │ │ │ ├── clean.lua │ │ │ ├── download.lua │ │ │ ├── env.lua │ │ │ ├── export.lua │ │ │ ├── fetch.lua │ │ │ ├── import.lua │ │ │ ├── info.lua │ │ │ ├── install.lua │ │ │ ├── list-repo.lua │ │ │ ├── remove.lua │ │ │ ├── rm-repo.lua │ │ │ ├── scan.lua │ │ │ ├── search.lua │ │ │ └── update-repo.lua │ │ ├── complete.lua │ │ ├── main.lua │ │ └── quick_search/ │ │ ├── cache.lua │ │ └── completion.lua │ ├── privilege/ │ │ └── sudo.lua │ ├── target/ │ │ └── action/ │ │ ├── clean/ │ │ │ └── main.lua │ │ ├── install/ │ │ │ ├── cmake_importfiles.lua │ │ │ ├── main.lua │ │ │ └── pkgconfig_importfiles.lua │ │ └── uninstall/ │ │ └── main.lua │ ├── ui/ │ │ └── app/ │ │ ├── showfile.lua │ │ └── version.lua │ └── utils/ │ ├── archive/ │ │ ├── archive.lua │ │ ├── archive_xmz.lua │ │ ├── extension.lua │ │ ├── extract.lua │ │ ├── extract_xmz.lua │ │ └── merge_staticlib.lua │ ├── binary/ │ │ ├── bin2c.lua │ │ ├── bin2obj.lua │ │ ├── deplibs.lua │ │ ├── extractlib.lua │ │ ├── readsyms.lua │ │ └── rpath.lua │ ├── ci/ │ │ ├── is_running.lua │ │ └── packageskey.lua │ ├── ipa/ │ │ ├── install.lua │ │ ├── package.lua │ │ └── resign.lua │ ├── platform/ │ │ └── gnu2mslib.lua │ ├── progress.lua │ ├── run_script.lua │ ├── waiting_indicator.lua │ └── wdk/ │ └── testcert.lua ├── platforms/ │ ├── android/ │ │ └── xmake.lua │ ├── appletvos/ │ │ └── xmake.lua │ ├── applexros/ │ │ └── xmake.lua │ ├── bsd/ │ │ └── xmake.lua │ ├── cross/ │ │ └── xmake.lua │ ├── cygwin/ │ │ └── xmake.lua │ ├── haiku/ │ │ └── xmake.lua │ ├── harmony/ │ │ └── xmake.lua │ ├── iphoneos/ │ │ └── xmake.lua │ ├── linux/ │ │ └── xmake.lua │ ├── macosx/ │ │ └── xmake.lua │ ├── mingw/ │ │ └── xmake.lua │ ├── msys/ │ │ └── xmake.lua │ ├── solaris/ │ │ └── xmake.lua │ ├── wasm/ │ │ └── xmake.lua │ ├── watchos/ │ │ └── xmake.lua │ └── windows/ │ └── xmake.lua ├── plugins/ │ ├── check/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── doxygen/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── format/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── lua/ │ │ ├── main.lua │ │ ├── scripts/ │ │ │ ├── cat.lua │ │ │ ├── cp.lua │ │ │ ├── echo.lua │ │ │ ├── lipo.lua │ │ │ ├── mkdir.lua │ │ │ ├── mv.lua │ │ │ ├── rm.lua │ │ │ ├── rmdir.lua │ │ │ └── time.lua │ │ └── xmake.lua │ ├── macro/ │ │ ├── macros/ │ │ │ └── package.lua │ │ ├── main.lua │ │ └── xmake.lua │ ├── pack/ │ │ ├── appimage/ │ │ │ └── main.lua │ │ ├── archive.lua │ │ ├── batchcmds.lua │ │ ├── deb/ │ │ │ └── main.lua │ │ ├── dmg/ │ │ │ └── main.lua │ │ ├── filter.lua │ │ ├── main.lua │ │ ├── nsis/ │ │ │ └── main.lua │ │ ├── rpm/ │ │ │ └── main.lua │ │ ├── runself/ │ │ │ └── main.lua │ │ ├── srctargz/ │ │ │ └── main.lua │ │ ├── srctarxz/ │ │ │ └── main.lua │ │ ├── srczip/ │ │ │ └── main.lua │ │ ├── srpm/ │ │ │ └── main.lua │ │ ├── targz/ │ │ │ └── main.lua │ │ ├── tarxz/ │ │ │ └── main.lua │ │ ├── wix/ │ │ │ └── main.lua │ │ ├── xmake.lua │ │ ├── xpack.lua │ │ ├── xpack_component.lua │ │ └── zip/ │ │ └── main.lua │ ├── plugin/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── project/ │ │ ├── clang/ │ │ │ ├── compile_commands.lua │ │ │ └── compile_flags.lua │ │ ├── cmake/ │ │ │ └── cmakelists.lua │ │ ├── main.lua │ │ ├── make/ │ │ │ ├── makefile.lua │ │ │ └── xmakefile.lua │ │ ├── ninja/ │ │ │ └── build_ninja.lua │ │ ├── utils/ │ │ │ └── target_cmds.lua │ │ ├── vstudio/ │ │ │ ├── impl/ │ │ │ │ ├── vs200x.lua │ │ │ │ ├── vs200x_solution.lua │ │ │ │ ├── vs200x_vcproj.lua │ │ │ │ ├── vs201x.lua │ │ │ │ ├── vs201x_solution.lua │ │ │ │ ├── vs201x_vcxproj.lua │ │ │ │ ├── vs201x_vcxproj_filters.lua │ │ │ │ ├── vsfile.lua │ │ │ │ ├── vsinfo.lua │ │ │ │ └── vsutils.lua │ │ │ └── vs.lua │ │ ├── vsxmake/ │ │ │ ├── getinfo.lua │ │ │ ├── render.lua │ │ │ └── vsxmake.lua │ │ ├── xcode/ │ │ │ ├── get_xcode_info.lua │ │ │ ├── pbxproj.lua │ │ │ └── xcodeproj.lua │ │ └── xmake.lua │ ├── repo/ │ │ ├── main.lua │ │ └── xmake.lua │ ├── show/ │ │ ├── info/ │ │ │ ├── basic.lua │ │ │ └── target.lua │ │ ├── list.lua │ │ ├── lists/ │ │ │ ├── apis.lua │ │ │ ├── architectures.lua │ │ │ ├── buildmodes.lua │ │ │ ├── envs.lua │ │ │ ├── packages.lua │ │ │ ├── platforms.lua │ │ │ ├── policies.lua │ │ │ ├── rules.lua │ │ │ ├── targets.lua │ │ │ ├── themes.lua │ │ │ └── toolchains.lua │ │ ├── main.lua │ │ ├── showlist.lua │ │ └── xmake.lua │ └── watch/ │ ├── main.lua │ └── xmake.lua ├── repository/ │ ├── packages/ │ │ ├── 7/ │ │ │ └── 7z/ │ │ │ ├── patches/ │ │ │ │ └── 21.02/ │ │ │ │ └── backport-21.03-fix-for-GCC-10.patch │ │ │ └── xmake.lua │ │ └── g/ │ │ └── git/ │ │ └── xmake.lua │ └── templates/ │ ├── c/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.c │ │ │ └── xmake.lua │ │ ├── module/ │ │ │ ├── binary/ │ │ │ │ ├── .gitignore │ │ │ │ ├── modules/ │ │ │ │ │ └── binary/ │ │ │ │ │ └── bar/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── add.c │ │ │ │ │ │ └── sub.c │ │ │ │ │ └── xmake.lua │ │ │ │ ├── src/ │ │ │ │ │ └── main.c │ │ │ │ └── xmake.lua │ │ │ └── shared/ │ │ │ ├── .gitignore │ │ │ ├── modules/ │ │ │ │ └── shared/ │ │ │ │ └── foo/ │ │ │ │ ├── src/ │ │ │ │ │ └── foo.c │ │ │ │ └── xmake.lua │ │ │ ├── src/ │ │ │ │ └── main.c │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── foo.c │ │ │ │ ├── foo.h │ │ │ │ └── main.c │ │ │ └── xmake.lua │ │ ├── static/ │ │ │ ├── src/ │ │ │ │ ├── foo.c │ │ │ │ ├── foo.h │ │ │ │ └── main.c │ │ │ └── xmake.lua │ │ └── xmake/ │ │ └── cli/ │ │ ├── src/ │ │ │ ├── lni/ │ │ │ │ └── main.c │ │ │ └── lua/ │ │ │ └── main.lua │ │ └── xmake.lua │ ├── c++/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── module/ │ │ │ ├── binary/ │ │ │ │ ├── .gitignore │ │ │ │ ├── modules/ │ │ │ │ │ └── binary/ │ │ │ │ │ └── bar/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── add.cpp │ │ │ │ │ │ └── sub.cpp │ │ │ │ │ └── xmake.lua │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ └── shared/ │ │ │ ├── .gitignore │ │ │ ├── modules/ │ │ │ │ └── shared/ │ │ │ │ └── foo/ │ │ │ │ ├── src/ │ │ │ │ │ └── foo.cpp │ │ │ │ └── xmake.lua │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── qt/ │ │ │ ├── console/ │ │ │ │ ├── src/ │ │ │ │ │ └── main.cpp │ │ │ │ └── xmake.lua │ │ │ ├── quickapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── main.qml │ │ │ │ │ └── qml.qrc │ │ │ │ └── xmake.lua │ │ │ ├── quickapp_static/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── main.qml │ │ │ │ │ └── qml.qrc │ │ │ │ └── xmake.lua │ │ │ ├── shared/ │ │ │ │ ├── src/ │ │ │ │ │ ├── demo.cpp │ │ │ │ │ ├── demo.h │ │ │ │ │ └── demo_global.h │ │ │ │ └── xmake.lua │ │ │ ├── static/ │ │ │ │ ├── src/ │ │ │ │ │ ├── demo.cpp │ │ │ │ │ └── demo.h │ │ │ │ └── xmake.lua │ │ │ ├── widgetapp/ │ │ │ │ ├── src/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ ├── mainwindow.cpp │ │ │ │ │ ├── mainwindow.h │ │ │ │ │ └── mainwindow.ui │ │ │ │ └── xmake.lua │ │ │ └── widgetapp_static/ │ │ │ ├── src/ │ │ │ │ ├── main.cpp │ │ │ │ ├── mainwindow.cpp │ │ │ │ ├── mainwindow.h │ │ │ │ └── mainwindow.ui │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── foo.cpp │ │ │ │ ├── foo.h │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── static/ │ │ │ ├── src/ │ │ │ │ ├── foo.cpp │ │ │ │ ├── foo.h │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ ├── wxwidgets/ │ │ │ ├── src/ │ │ │ │ └── main.cpp │ │ │ └── xmake.lua │ │ └── xmake/ │ │ └── cli/ │ │ ├── src/ │ │ │ ├── lni/ │ │ │ │ └── main.cpp │ │ │ └── lua/ │ │ │ └── main.lua │ │ └── xmake.lua │ ├── csharp/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── Program.cs │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── foo.cs │ │ │ │ └── main.cs │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── src/ │ │ │ ├── foo.cs │ │ │ └── main.cs │ │ └── xmake.lua │ ├── cuda/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.cu │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── inc/ │ │ │ │ └── lib.cuh │ │ │ ├── src/ │ │ │ │ └── lib.cu │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── inc/ │ │ │ └── lib.cuh │ │ ├── src/ │ │ │ └── lib.cu │ │ └── xmake.lua │ ├── dlang/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.d │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── interfaces.d │ │ │ │ └── main.d │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── src/ │ │ │ ├── interfaces.d │ │ │ └── main.d │ │ └── xmake.lua │ ├── fortran/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.f90 │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── main.f90 │ │ │ │ └── test.f90 │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── src/ │ │ │ ├── main.f90 │ │ │ └── test.f90 │ │ └── xmake.lua │ ├── go/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.go │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── src/ │ │ │ ├── main.go │ │ │ ├── module/ │ │ │ │ ├── add.go │ │ │ │ └── sub.go │ │ │ └── test.go │ │ └── xmake.lua │ ├── kotlin/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.kt │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── foo.kt │ │ │ │ └── main.c │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── src/ │ │ │ ├── foo.kt │ │ │ └── main.c │ │ └── xmake.lua │ ├── nim/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.nim │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── foo.nim │ │ │ │ └── main.nim │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── src/ │ │ │ ├── foo.nim │ │ │ └── main.nim │ │ └── xmake.lua │ ├── objc/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.m │ │ │ └── xmake.lua │ │ └── xcode/ │ │ ├── bundle/ │ │ │ ├── src/ │ │ │ │ ├── Info.plist │ │ │ │ ├── test.h │ │ │ │ └── test.m │ │ │ └── xmake.lua │ │ ├── framework/ │ │ │ ├── src/ │ │ │ │ ├── Info.plist │ │ │ │ ├── test.h │ │ │ │ └── test.m │ │ │ └── xmake.lua │ │ ├── iosapp/ │ │ │ ├── src/ │ │ │ │ ├── AppDelegate.h │ │ │ │ ├── AppDelegate.m │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Base.lproj/ │ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ │ └── Main.storyboard │ │ │ │ ├── Info.plist │ │ │ │ ├── SceneDelegate.h │ │ │ │ ├── SceneDelegate.m │ │ │ │ ├── ViewController.h │ │ │ │ ├── ViewController.m │ │ │ │ └── main.m │ │ │ └── xmake.lua │ │ ├── iosapp_with_framework/ │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ ├── AppDelegate.h │ │ │ │ │ ├── AppDelegate.m │ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ │ │ └── Main.storyboard │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── SceneDelegate.h │ │ │ │ │ ├── SceneDelegate.m │ │ │ │ │ ├── ViewController.h │ │ │ │ │ ├── ViewController.m │ │ │ │ │ └── main.m │ │ │ │ └── framework/ │ │ │ │ ├── Info.plist │ │ │ │ ├── test.h │ │ │ │ └── test.m │ │ │ └── xmake.lua │ │ ├── macapp/ │ │ │ ├── src/ │ │ │ │ ├── AppDelegate.h │ │ │ │ ├── AppDelegate.m │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Base.lproj/ │ │ │ │ │ └── Main.storyboard │ │ │ │ ├── Info.plist │ │ │ │ ├── ViewController.h │ │ │ │ ├── ViewController.m │ │ │ │ ├── main.m │ │ │ │ └── test.entitlements │ │ │ └── xmake.lua │ │ └── macapp_with_framework/ │ │ ├── src/ │ │ │ ├── app/ │ │ │ │ ├── AppDelegate.h │ │ │ │ ├── AppDelegate.m │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Base.lproj/ │ │ │ │ │ └── Main.storyboard │ │ │ │ ├── Info.plist │ │ │ │ ├── ViewController.h │ │ │ │ ├── ViewController.m │ │ │ │ ├── main.m │ │ │ │ └── test.entitlements │ │ │ └── framework/ │ │ │ ├── Info.plist │ │ │ ├── test.h │ │ │ └── test.m │ │ └── xmake.lua │ ├── objc++/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.mm │ │ │ └── xmake.lua │ │ └── xcode/ │ │ ├── bundle/ │ │ │ ├── src/ │ │ │ │ ├── Info.plist │ │ │ │ ├── test.h │ │ │ │ └── test.mm │ │ │ └── xmake.lua │ │ └── framework/ │ │ ├── src/ │ │ │ ├── Info.plist │ │ │ ├── test.h │ │ │ └── test.mm │ │ └── xmake.lua │ ├── pascal/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.pas │ │ │ └── xmake.lua │ │ └── shared/ │ │ ├── src/ │ │ │ ├── foo.pas │ │ │ └── main.pas │ │ └── xmake.lua │ ├── rust/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.rs │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── foo.rs │ │ │ │ └── main.rs │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── src/ │ │ │ ├── foo.rs │ │ │ └── main.rs │ │ └── xmake.lua │ ├── swift/ │ │ └── console/ │ │ ├── src/ │ │ │ └── main.swift │ │ └── xmake.lua │ ├── vala/ │ │ ├── console/ │ │ │ ├── src/ │ │ │ │ └── main.vala │ │ │ └── xmake.lua │ │ ├── shared/ │ │ │ ├── src/ │ │ │ │ ├── main.vala │ │ │ │ └── mymath.vala │ │ │ └── xmake.lua │ │ └── static/ │ │ ├── src/ │ │ │ ├── main.vala │ │ │ └── mymath.vala │ │ └── xmake.lua │ └── zig/ │ ├── console/ │ │ ├── src/ │ │ │ └── main.zig │ │ └── xmake.lua │ ├── shared/ │ │ ├── src/ │ │ │ ├── main.zig │ │ │ └── test.zig │ │ └── xmake.lua │ └── static/ │ ├── src/ │ │ ├── main.zig │ │ └── test.zig │ └── xmake.lua ├── rules/ │ ├── asm/ │ │ └── xmake.lua │ ├── asn1c/ │ │ └── xmake.lua │ ├── c++/ │ │ ├── config/ │ │ │ ├── basic.lua │ │ │ ├── dynamic_debugging.lua │ │ │ ├── main.lua │ │ │ ├── optimization.lua │ │ │ ├── runtime.lua │ │ │ └── sanitizer.lua │ │ ├── modules/ │ │ │ ├── builder.lua │ │ │ ├── clang/ │ │ │ │ ├── builder.lua │ │ │ │ ├── scanner.lua │ │ │ │ └── support.lua │ │ │ ├── config.lua │ │ │ ├── gcc/ │ │ │ │ ├── builder.lua │ │ │ │ ├── scanner.lua │ │ │ │ └── support.lua │ │ │ ├── install.lua │ │ │ ├── mapper.lua │ │ │ ├── msvc/ │ │ │ │ ├── builder.lua │ │ │ │ ├── scanner.lua │ │ │ │ └── support.lua │ │ │ ├── scanner.lua │ │ │ ├── stlheaders.lua │ │ │ ├── support.lua │ │ │ └── xmake.lua │ │ ├── openmp/ │ │ │ ├── load.lua │ │ │ └── xmake.lua │ │ ├── precompiled_header/ │ │ │ └── xmake.lua │ │ ├── unity_build/ │ │ │ ├── unity_build.lua │ │ │ └── xmake.lua │ │ └── xmake.lua │ ├── c51/ │ │ └── xmake.lua │ ├── capnproto/ │ │ ├── capnp.lua │ │ └── xmake.lua │ ├── cppfront/ │ │ └── xmake.lua │ ├── csharp/ │ │ ├── build.lua │ │ ├── config.lua │ │ ├── generator/ │ │ │ ├── csproj.lua │ │ │ ├── itemgroups.lua │ │ │ └── properties.lua │ │ ├── install.lua │ │ ├── installcmd.lua │ │ └── xmake.lua │ ├── cuda/ │ │ ├── devlink/ │ │ │ ├── devlink.lua │ │ │ └── xmake.lua │ │ ├── env/ │ │ │ └── xmake.lua │ │ ├── gencodes/ │ │ │ └── xmake.lua │ │ └── xmake.lua │ ├── dlang/ │ │ ├── build_optimization/ │ │ │ ├── config.lua │ │ │ └── xmake.lua │ │ └── xmake.lua │ ├── fortran/ │ │ └── xmake.lua │ ├── gnu-rm/ │ │ └── xmake.lua │ ├── go/ │ │ └── xmake.lua │ ├── iverilog/ │ │ └── xmake.lua │ ├── kotlin-native/ │ │ └── xmake.lua │ ├── lex_yacc/ │ │ ├── lex/ │ │ │ └── xmake.lua │ │ └── yacc/ │ │ └── xmake.lua │ ├── linker/ │ │ ├── link_scripts/ │ │ │ └── xmake.lua │ │ ├── soname/ │ │ │ └── xmake.lua │ │ ├── version_scripts/ │ │ │ └── xmake.lua │ │ └── xmake.lua │ ├── lua/ │ │ ├── module/ │ │ │ └── xmake.lua │ │ └── native-objects/ │ │ └── xmake.lua │ ├── luarocks/ │ │ └── module/ │ │ └── xmake.lua │ ├── mdk/ │ │ └── xmake.lua │ ├── mode/ │ │ └── xmake.lua │ ├── module/ │ │ └── xmake.lua │ ├── nim/ │ │ └── xmake.lua │ ├── nodejs/ │ │ └── module/ │ │ └── xmake.lua │ ├── objc++/ │ │ ├── config/ │ │ │ ├── basic.lua │ │ │ └── main.lua │ │ ├── precompiled_header/ │ │ │ └── xmake.lua │ │ └── xmake.lua │ ├── pascal/ │ │ └── xmake.lua │ ├── platform/ │ │ ├── android/ │ │ │ ├── install.lua │ │ │ ├── load.lua │ │ │ ├── package.lua │ │ │ ├── run.lua │ │ │ ├── uninstall.lua │ │ │ └── xmake.lua │ │ ├── linux/ │ │ │ ├── bpf/ │ │ │ │ └── xmake.lua │ │ │ ├── driver/ │ │ │ │ └── xmake.lua │ │ │ └── module/ │ │ │ ├── driver_modules.lua │ │ │ └── xmake.lua │ │ ├── wasm/ │ │ │ ├── installfiles/ │ │ │ │ └── xmake.lua │ │ │ └── preloadfiles/ │ │ │ └── xmake.lua │ │ ├── windows/ │ │ │ ├── def/ │ │ │ │ └── xmake.lua │ │ │ ├── idl/ │ │ │ │ ├── idl.lua │ │ │ │ └── xmake.lua │ │ │ ├── manifest/ │ │ │ │ └── xmake.lua │ │ │ └── subsystem/ │ │ │ └── xmake.lua │ │ └── xmake.lua │ ├── plugin/ │ │ ├── compile_commands/ │ │ │ └── xmake.lua │ │ └── vsxmake/ │ │ └── xmake.lua │ ├── protobuf/ │ │ ├── proto.lua │ │ └── xmake.lua │ ├── python/ │ │ ├── cython/ │ │ │ └── xmake.lua │ │ ├── library/ │ │ │ └── xmake.lua │ │ └── module/ │ │ └── xmake.lua │ ├── qt/ │ │ ├── build_qt_wasm_app.lua │ │ ├── config_static.lua │ │ ├── deploy/ │ │ │ ├── android.lua │ │ │ └── macosx.lua │ │ ├── env/ │ │ │ └── xmake.lua │ │ ├── install/ │ │ │ ├── android.lua │ │ │ ├── mingw.lua │ │ │ ├── windeployqt.lua │ │ │ └── windows.lua │ │ ├── installcmd.lua │ │ ├── load.lua │ │ ├── moc/ │ │ │ └── xmake.lua │ │ ├── qmltyperegistrar/ │ │ │ └── xmake.lua │ │ ├── qrc/ │ │ │ └── xmake.lua │ │ ├── ts/ │ │ │ └── xmake.lua │ │ ├── ui/ │ │ │ └── xmake.lua │ │ ├── uninstallcmd.lua │ │ └── xmake.lua │ ├── rust/ │ │ └── xmake.lua │ ├── swift/ │ │ ├── config/ │ │ │ ├── basic.lua │ │ │ └── main.lua │ │ └── xmake.lua │ ├── swig/ │ │ ├── build_module_file.lua │ │ └── xmake.lua │ ├── utils/ │ │ ├── bin2c/ │ │ │ ├── utils.lua │ │ │ └── xmake.lua │ │ ├── bin2obj/ │ │ │ ├── utils.lua │ │ │ └── xmake.lua │ │ ├── compiler_runtime/ │ │ │ └── xmake.lua │ │ ├── glsl2spv/ │ │ │ └── xmake.lua │ │ ├── hlsl2spv/ │ │ │ └── xmake.lua │ │ ├── inherit_links/ │ │ │ ├── inherit_links.lua │ │ │ └── xmake.lua │ │ ├── install_importfiles/ │ │ │ └── xmake.lua │ │ ├── ispc/ │ │ │ └── xmake.lua │ │ ├── merge_archive/ │ │ │ └── xmake.lua │ │ ├── merge_object/ │ │ │ └── xmake.lua │ │ └── symbols/ │ │ ├── export_all/ │ │ │ ├── export_all.lua │ │ │ └── xmake.lua │ │ ├── export_list/ │ │ │ └── xmake.lua │ │ └── extract/ │ │ └── xmake.lua │ ├── vala/ │ │ └── xmake.lua │ ├── verilator/ │ │ ├── verilator.lua │ │ └── xmake.lua │ ├── wdk/ │ │ ├── env/ │ │ │ ├── load.lua │ │ │ └── xmake.lua │ │ ├── inf/ │ │ │ └── xmake.lua │ │ ├── load.lua │ │ ├── man/ │ │ │ └── xmake.lua │ │ ├── mc/ │ │ │ └── xmake.lua │ │ ├── mof/ │ │ │ └── xmake.lua │ │ ├── package/ │ │ │ └── xmake.lua │ │ ├── sign/ │ │ │ ├── sign.lua │ │ │ └── xmake.lua │ │ ├── tracewpp/ │ │ │ └── xmake.lua │ │ └── xmake.lua │ ├── winsdk/ │ │ ├── dotnet/ │ │ │ └── xmake.lua │ │ ├── mfc/ │ │ │ ├── env/ │ │ │ │ └── xmake.lua │ │ │ ├── mfc.lua │ │ │ └── xmake.lua │ │ └── xmake.lua │ ├── xcode/ │ │ ├── application/ │ │ │ ├── build.lua │ │ │ ├── install.lua │ │ │ ├── installcmd.lua │ │ │ ├── load.lua │ │ │ ├── package.lua │ │ │ ├── run.lua │ │ │ ├── uninstall.lua │ │ │ └── xmake.lua │ │ ├── bundle/ │ │ │ └── xmake.lua │ │ ├── framework/ │ │ │ └── xmake.lua │ │ ├── info_plist/ │ │ │ └── xmake.lua │ │ ├── metal/ │ │ │ └── xmake.lua │ │ ├── storyboard/ │ │ │ └── xmake.lua │ │ └── xcassets/ │ │ └── xmake.lua │ ├── xmake_cli/ │ │ └── xmake.lua │ └── zig/ │ └── xmake.lua ├── scripts/ │ ├── PkgInfo │ ├── cmake_importfiles/ │ │ ├── xxxConfig.cmake │ │ ├── xxxConfigVersion.cmake │ │ ├── xxxTargets-debug.cmake │ │ ├── xxxTargets-release.cmake │ │ └── xxxTargets.cmake │ ├── completions/ │ │ ├── register-completions.bash │ │ ├── register-completions.fish │ │ └── register-completions.zsh │ ├── conan/ │ │ └── extensions/ │ │ └── generators/ │ │ └── xmake_generator.py │ ├── download.ps1 │ ├── faq.lua │ ├── find_cudadevices.cpp │ ├── gas-preprocessor.pl │ ├── gitignore │ ├── module/ │ │ ├── luawrap/ │ │ │ ├── lauxlib.h │ │ │ ├── lua.h │ │ │ └── luaconf.h │ │ └── xmi.h │ ├── patches/ │ │ └── libtool/ │ │ ├── 2.4.3.patch │ │ ├── 2.4.4.patch │ │ ├── 2.4.7.patch │ │ ├── 2.5.0.patch │ │ └── 2.6.0.patch │ ├── profile-unix.fish │ ├── profile-unix.sh │ ├── profile-win.ps1 │ ├── run.vbs │ ├── unzip.ps1 │ ├── update-script.bat │ ├── update-script.sh │ ├── virtualenvs/ │ │ └── register-virtualenvs.sh │ ├── vsxmake/ │ │ └── vsproj/ │ │ ├── Xmake.Defaults.props │ │ ├── Xmake.props │ │ ├── Xmake.targets │ │ ├── Xmake.xml │ │ └── templates/ │ │ ├── Xmake.Custom.items │ │ ├── Xmake.Custom.items.filters │ │ ├── Xmake.Custom.props │ │ ├── Xmake.Custom.targets │ │ ├── sln/ │ │ │ ├── ProjConfig(target,mode,arch) │ │ │ ├── Project(target) │ │ │ ├── ProjectGroup(group) │ │ │ ├── ProjectGroupConfig(group_dep) │ │ │ ├── SlnConfig(mode,arch) │ │ │ └── vsxmake.sln │ │ ├── vcxproj/ │ │ │ ├── #target#.vcxproj │ │ │ ├── File.c(filec) │ │ │ ├── File.cu(filecu) │ │ │ ├── File.cxx(filecxx) │ │ │ ├── File.mpp(filempp) │ │ │ ├── File.obj(fileobj) │ │ │ ├── File.qrc(fileqrc) │ │ │ ├── File.rc(filerc) │ │ │ ├── File.ts(filets) │ │ │ ├── File.ui(fileui) │ │ │ ├── Include.c(incc) │ │ │ ├── Include.natvis(incnatvis) │ │ │ ├── ProjectConfiguration(mode,arch) │ │ │ ├── ProjectRef(dep) │ │ │ ├── XmakeConfig(mode,arch) │ │ │ └── XmakePath(mode,arch) │ │ └── vcxproj.filters/ │ │ ├── #target#.vcxproj.filters │ │ ├── File.c(filec) │ │ ├── File.cu(filecu) │ │ ├── File.cxx(filecxx) │ │ ├── File.mpp(filempp) │ │ ├── File.obj(fileobj) │ │ ├── File.qrc(fileqrc) │ │ ├── File.rc(filerc) │ │ ├── File.ts(filets) │ │ ├── File.ui(fileui) │ │ ├── Filter(dir) │ │ ├── Include.c(incc) │ │ └── Include.natvis(incnatvis) │ ├── xpack/ │ │ ├── deb/ │ │ │ └── debian/ │ │ │ ├── README.Debian │ │ │ ├── changelog │ │ │ ├── control │ │ │ ├── copyright │ │ │ ├── rules │ │ │ └── source/ │ │ │ └── format │ │ ├── nsis/ │ │ │ └── makensis.nsi │ │ ├── runself/ │ │ │ ├── makeself.lsm │ │ │ └── setup.sh │ │ ├── srpm/ │ │ │ └── srpm.spec │ │ └── wix/ │ │ └── msi.wxs │ ├── xrepo/ │ │ └── envs/ │ │ ├── depot_tools.lua │ │ ├── devel.lua │ │ ├── llvm-mingw.lua │ │ ├── llvm.lua │ │ ├── mingw-w64.lua │ │ ├── msvc.lua │ │ ├── msys2-mingw32.lua │ │ ├── msys2-mingw64.lua │ │ ├── msys2.lua │ │ ├── python2.lua │ │ └── python3.lua │ └── xrepo-hook.psm1 ├── themes/ │ ├── dark/ │ │ └── xmake.lua │ ├── default/ │ │ └── xmake.lua │ ├── emoji/ │ │ └── xmake.lua │ ├── light/ │ │ └── xmake.lua │ ├── ninja/ │ │ └── xmake.lua │ ├── plain/ │ │ └── xmake.lua │ ├── powershell/ │ │ └── xmake.lua │ └── soong/ │ └── xmake.lua └── toolchains/ ├── armcc/ │ └── xmake.lua ├── armclang/ │ └── xmake.lua ├── c51/ │ └── xmake.lua ├── circle/ │ └── xmake.lua ├── clang/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── clang-12/ │ └── xmake.lua ├── clang-13/ │ └── xmake.lua ├── clang-14/ │ └── xmake.lua ├── clang-15/ │ └── xmake.lua ├── clang-16/ │ └── xmake.lua ├── clang-17/ │ └── xmake.lua ├── clang-18/ │ └── xmake.lua ├── clang-19/ │ └── xmake.lua ├── clang-20/ │ └── xmake.lua ├── clang-21/ │ └── xmake.lua ├── clang-cl/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── cosmocc/ │ ├── check.lua │ └── xmake.lua ├── cross/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── cuda/ │ └── xmake.lua ├── dlang/ │ ├── check.lua │ └── xmake.lua ├── dmd/ │ └── xmake.lua ├── dotnet/ │ └── xmake.lua ├── dpcpp/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── emcc/ │ └── xmake.lua ├── envs/ │ └── xmake.lua ├── fasm/ │ └── xmake.lua ├── flang/ │ └── xmake.lua ├── fpc/ │ └── xmake.lua ├── gcc/ │ └── xmake.lua ├── gcc-10/ │ └── xmake.lua ├── gcc-11/ │ └── xmake.lua ├── gcc-12/ │ └── xmake.lua ├── gcc-13/ │ └── xmake.lua ├── gcc-14/ │ └── xmake.lua ├── gcc-15/ │ └── xmake.lua ├── gcc-4.8/ │ └── xmake.lua ├── gcc-4.9/ │ └── xmake.lua ├── gcc-8/ │ └── xmake.lua ├── gcc-9/ │ └── xmake.lua ├── gdc/ │ ├── check.lua │ └── xmake.lua ├── gfortran/ │ └── xmake.lua ├── gnu-rm/ │ └── xmake.lua ├── go/ │ └── xmake.lua ├── hdk/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── iararm/ │ └── xmake.lua ├── icc/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── icx/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── ifort/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── ifx/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── iverilog/ │ └── xmake.lua ├── kotlin-native/ │ └── xmake.lua ├── ldc/ │ ├── check.lua │ └── xmake.lua ├── llvm/ │ ├── check.lua │ └── xmake.lua ├── masm32/ │ └── xmake.lua ├── mingw/ │ ├── check.lua │ └── xmake.lua ├── msvc/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── muslcc/ │ └── xmake.lua ├── nasm/ │ └── xmake.lua ├── ndk/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── nim/ │ └── xmake.lua ├── rust/ │ └── xmake.lua ├── sdcc/ │ ├── check.lua │ └── xmake.lua ├── swift/ │ └── xmake.lua ├── ti-c2000/ │ └── xmake.lua ├── ti-c6000/ │ └── xmake.lua ├── tinycc/ │ └── xmake.lua ├── verilator/ │ └── xmake.lua ├── wasi/ │ └── xmake.lua ├── xcode/ │ ├── check.lua │ ├── load.lua │ └── xmake.lua ├── yasm/ │ └── xmake.lua ├── zig/ │ └── xmake.lua └── zigcc/ └── xmake.lua ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ --- Language: Cpp BasedOnStyle: LLVM DisableFormat: false # Indentation IndentWidth: 4 ContinuationIndentWidth: 4 TabWidth: 4 UseTab: Never # Braces BreakBeforeBraces: Attach BraceWrapping: AfterControlStatement: false AfterFunction: false AfterEnum: false AfterClass: false AfterStruct: false AfterUnion: false BeforeElse: false BeforeCatch: false BeforeLambdaBody: false # Alignment AlignAfterOpenBracket: Align AlignTrailingComments: true AlignConsecutiveAssignments: None AlignConsecutiveBitFields: None AlignConsecutiveDeclarations: None AlignConsecutiveMacros: None # Spacing SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpacesBeforeTrailingComments: 1 # Column limit ColumnLimit: 120 # Short constructs AllowShortBlocksOnASingleLine: Never AllowShortCaseLabelsOnASingleLine: false AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false # Line breaking AlwaysBreakAfterReturnType: None BreakBeforeBinaryOperators: None BreakBeforeTernaryOperators: true # Functions IndentWrappedFunctionNames: false MaxEmptyLinesToKeep: 1 # Includes IncludeBlocks: Preserve SortIncludes: Never # Initializers AllowAllConstructorInitializersOnNextLine: true ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 Cpp11BracedListStyle: false BinPackArguments: false BinPackParameters: false # Preprocessor/Macros IndentPPDirectives: None # Misc KeepEmptyLinesAtTheStartOfBlocks: false ReflowComments: false SeparateDefinitionBlocks: Leave # Penalties PenaltyBreakAssignment: 100 PenaltyBreakBeforeFirstCallParameter: 100 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 1000 PenaltyBreakTemplateDeclaration: 1000 --- Language: ObjC BasedOnStyle: LLVM DisableFormat: true ================================================ FILE: .gitattributes ================================================ *.mpp linguist-language=C++ *.cppm linguist-language=C++ *.ixx linguist-language=C++ ================================================ FILE: .github/workflows/alpine.yml ================================================ name: Alpine on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 20%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.ALPINE_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' container: alpine:latest runs-on: ubuntu-latest concurrency: # Prevent concurrent runs of the same workflow group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Alpine cancel-in-progress: true steps: - name: Prepare build tools run: | uname -a apk --no-cache add grep linux-headers bash curl git unzip build-base tar 7zip perl - uses: actions/checkout@v2 with: submodules: true - name: prepare local xmake run: | cp -rf . ../xmake-source - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: local#../xmake-source - name: Tests env: XMAKE_ROOT: y run: | xmake lua -v -D tests/run.lua xrepo --version ================================================ FILE: .github/workflows/archlinux.yml ================================================ name: Archlinux on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 20%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.ARCHLINUX_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' container: archlinux:base-devel runs-on: ubuntu-latest concurrency: # Prevent concurrent runs of the same workflow group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Archlinux cancel-in-progress: true steps: - name: Prepare build tools run: | pacman -Syu --noconfirm --needed openssl pacman -Sy --noconfirm --needed glibc git base-devel perl make unzip pacman -Sy --noconfirm --needed mesa gcc-fortran glu git config --global --add safe.directory /__w/xmake/xmake - uses: actions/checkout@v2 with: submodules: true - name: prepare local xmake run: | cp -rf . ../xmake-source - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: local#../xmake-source - name: Tests env: XMAKE_ROOT: y run: | xmake lua -v -D tests/run.lua xrepo --version ================================================ FILE: .github/workflows/cosmocc.yml ================================================ name: Cosmocc on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 50%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.5'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.COSMOCC_RUN_PROBABILITY || '0.5' }} build: #needs: check #if: needs.check.outputs.should-run == 'true' strategy: matrix: os: [ubuntu-latest, macos-15-intel] arch: [x86_64] runs-on: ${{ matrix.os }} concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Cosmocc-${{ matrix.os }}-${{ matrix.arch }} cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - uses: little-core-labs/get-git-tag@v3.0.2 id: tagName - name: Prepare local xmake run: cp -rf . ../xmake-source - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: local#../xmake-source - uses: bjia56/setup-cosmocc@main with: version: "4.0.2" - name: Build run: | cd core xmake f -p linux --cosmocc=y --embed=y -y -cvD xmake -v cd .. - name: Prepare (Linux) if: matrix.os == 'ubuntu-latest' run: | sudo apt update sudo apt install -y ruby ruby-dev rubygems build-essential llvm libc++-dev sudo apt install -y libgl1-mesa-dev libglu1-mesa-dev clang --version # In the tests, cmake tries to use make from the cosmopolitan toolchain and fails, so uninstall it - name: Remove cosmocc if: startsWith(matrix.os, 'macos') run: | INSTALL_DIR="${{runner.temp}}/cosmocc-4.0.2" echo "Removing cosmocc from PATH" echo "::remove-path::${INSTALL_DIR}/bin" rm -r "${INSTALL_DIR}" - name: Tests run: | ls -l core/build/ cmake --version core/build/xmake --version core/build/xmake lua -v -D tests/run.lua - name: Artifact if: matrix.os == 'ubuntu-latest' uses: actions/upload-artifact@v4 with: name: xmake-bundle.cosmocc path: core/build/xmake - name: Publish bundle binary if: github.event.action == 'published' && matrix.os == 'ubuntu-latest' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: core/build/xmake asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.cosmocc asset_content_type: application/zip ================================================ FILE: .github/workflows/dragonflybsd.yml ================================================ name: DragonflyBSD on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 20%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.DRAGONFLYBSD_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' runs-on: ubuntu-latest concurrency: # Prevent concurrent runs of the same workflow group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-DragonflyBSD cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - name: Tests uses: vmactions/dragonflybsd-vm@v1 with: usesh: true mem: 4096 copyback: false prepare: | pkg install -y git curl unzip gmake llvm libc++ gsed bash perl5 run: | ./configure gmake -j4 gmake install export XMAKE_ROOT=y xrepo --version xmake l os.meminfo xmake lua -v -D tests/run.lua ================================================ FILE: .github/workflows/fedora.yml ================================================ name: Fedora on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 20%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.FEDORA_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' container: fedora:latest runs-on: ubuntu-latest concurrency: # Prevent concurrent runs of the same workflow group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Fedora cancel-in-progress: true steps: - name: Prepare build tools run: | uname -a dnf -y install @development-tools @rpm-development-tools dnf -y install mesa-libGL-devel mesa-libGLU-devel dnf -y install copr-cli make gcc-c++ dnf -y install perl dnf -y upgrade git - uses: actions/checkout@v2 with: submodules: true - name: Prepare local xmake run: | cp -rf . ../xmake-source - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: local#../xmake-source - name: Tests env: XMAKE_ROOT: y run: | xmake lua -v -D tests/run.lua xrepo --version ================================================ FILE: .github/workflows/freebsd.yml ================================================ name: FreeBSD on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 50%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.5'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.FREEBSD_RUN_PROBABILITY || '0.5' }} build: needs: check if: needs.check.outputs.should-run == 'true' runs-on: ubuntu-latest concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-FreeBSD cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - name: Tests uses: vmactions/freebsd-vm@v1 with: usesh: true mem: 4096 copyback: false prepare: pkg install -y git curl unzip gmake llvm gsed bash perl5 run: | ./configure gmake -j4 gmake install export XMAKE_ROOT=y xrepo --version xmake l os.meminfo xmake lua -v -D tests/run.lua ================================================ FILE: .github/workflows/haiku.yml ================================================ name: Haiku on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; } const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.HAIKU_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' runs-on: ubuntu-latest concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Haiku cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - name: Tests uses: vmactions/haiku-vm@v1 with: usesh: true mem: 4096 copyback: false prepare: | pkgman install -y git curl unzip make bash perl run: | ./configure --prefix=`pwd`/dist make -j2 make install export XMAKE_ROOT=y export PATH=`pwd`/dist/bin:$PATH xrepo --version xmake lua -v -D tests/run.lua ================================================ FILE: .github/workflows/issue-translator.yml ================================================ name: 'issue-translator' on: issue_comment: types: [created] issues: types: [opened] jobs: build: runs-on: ubuntu-latest steps: - uses: usthe/issues-translate-action@v2.7 with: IS_MODIFY_TITLE: false CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. ================================================ FILE: .github/workflows/linux.yml ================================================ name: Linux on: pull_request: push: release: types: [published] jobs: build: runs-on: ubuntu-latest concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Linux cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - name: prepare local xmake run: cp -rf . ../xmake-source - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: local#../xmake-source - uses: dlang-community/setup-dlang@v1 with: compiler: dmd-latest - uses: little-core-labs/get-git-tag@v3.0.2 id: tagName - name: Prepare run: | sudo apt update sudo apt install -y ruby ruby-dev rubygems build-essential llvm libc++-dev sudo apt install -y libgl1-mesa-dev libglu1-mesa-dev clang --version xrepo install -y zig - name: Tests run: | xmake lua -v -D tests/run.lua xrepo --version - name: Artifact run: | cd core xrepo env -b zig xmake f --embed=y --toolchain=zig --cross=x86_64-linux-musl -c xmake mkdir ../artifacts cp build/xmake ../artifacts/xmake-bundle cd .. - uses: actions/upload-artifact@v4 with: name: xmake-bundle.linux.x86_64 path: artifacts/xmake-bundle - name: Publish if: github.event.action == 'published' env: PPA_GPG_PRIKEY_2C0C68C9: ${{ secrets.PPA_GPG_PRIKEY_2C0C68C9 }} run: | # upload ubuntu/ppa sudo apt install -y dh-make rng-tools devscripts lintian echo "$PPA_GPG_PRIKEY_2C0C68C9" > ppa_gpg.key gpg --import ppa_gpg.key scripts/makeppa questing # 25.10 scripts/makeppa plucky # 25.04 scripts/makeppa noble # 24.04 scripts/makeppa mantic # 23.10 scripts/makeppa lunar # 23.04 scripts/makeppa kinetic # 22.10 scripts/makeppa jammy # 22.04 scripts/makeppa focal # 20.04 scripts/makeppa bionic # 18.04 scripts/makeppa xenial # 16.04 scripts/makeppa trusty # 14.04 - name: Publish bundle binary if: github.event.action == 'published' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/xmake-bundle asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.linux.x86_64 asset_content_type: application/zip ================================================ FILE: .github/workflows/linux_arm64.yml ================================================ name: Linux (Arm64) on: pull_request: push: release: types: [published] jobs: build: runs-on: ubuntu-24.04-arm concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Ubuntu-Arm64 cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - name: prepare local xmake run: cp -rf . ../xmake-source - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: local#../xmake-source - name: Prepare run: | sudo apt update sudo apt install -y unzip build-essential llvm libc++-dev - name: Tests run: | xmake lua -v -D tests/run.lua xrepo --version ================================================ FILE: .github/workflows/linux_luajit.yml ================================================ name: Linux (Luajit) on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 20%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.LINUX_LUAJIT_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' runs-on: ubuntu-latest concurrency: # Prevent concurrent runs of the same workflow group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Linux-Luajit cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - uses: dlang-community/setup-dlang@v1 with: compiler: dmd-latest - uses: little-core-labs/get-git-tag@v3.0.2 id: tagName - name: Installation run: | ./configure --runtime=luajit make -j`nproc` ./scripts/get.sh __local__ __install_only__ source ~/.xmake/profile xmake --version - name: Prepare run: | sudo apt update sudo apt install -y build-essential llvm libc++-dev sudo apt install -y libgl1-mesa-dev libglu1-mesa-dev - name: Tests run: | xmake lua -v -D tests/run.lua xrepo --version ================================================ FILE: .github/workflows/macos.yml ================================================ name: macOS (x86_64) on: pull_request: push: release: types: [published] jobs: build: strategy: matrix: os: [macos-15-intel] arch: [x86_64] runs-on: ${{ matrix.os }} concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-macOS-${{ matrix.arch }} cancel-in-progress: true steps: - uses: actions/checkout@v2 with: # WyriHaximus/github-action-get-previous-tag@master need it fetch-depth: 0 submodules: true - name: Prepare local xmake run: cp -rf . ../xmake-source - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: local#../xmake-source - uses: little-core-labs/get-git-tag@v3.0.2 id: tagName - name: Tests run: | xmake lua -v -D tests/run.lua xrepo --version - name: Artifact run: | brew install gnu-tar cd core xmake pack -y --autobuild=n --basename=xmake -o ../artifacts xmakesrc xmake f --embed=y -c xmake cp build/xmake ../artifacts/xmake-bundle cd .. - uses: actions/upload-artifact@v4 with: name: xmake-latest.gz.run path: artifacts/xmake.gz.run - uses: actions/upload-artifact@v4 with: name: xmake-latest.tar.gz path: artifacts/xmake.tar.gz - uses: actions/upload-artifact@v4 with: name: xmake-latest.zip path: artifacts/xmake.zip - uses: actions/upload-artifact@v4 with: name: xmake-bundle.macos.x86_64 path: artifacts/xmake-bundle # upload artifacts to latest release - name: Get Previous tag id: previoustag uses: WyriHaximus/github-action-get-previous-tag@master - name: Upload artifacts to lastest release if: github.ref == 'refs/heads/master' uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: artifacts/xmake.zip asset_name: xmake-master.zip tag: ${{ steps.previoustag.outputs.tag }} overwrite: true - name: Upload artifacts to lastest release if: github.ref == 'refs/heads/master' uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: artifacts/xmake.tar.gz asset_name: xmake-master.tar.gz tag: ${{ steps.previoustag.outputs.tag }} overwrite: true - name: Publish gz runfile if: github.event.action == 'published' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/xmake.gz.run asset_name: xmake-${{ steps.tagName.outputs.tag }}.gz.run asset_content_type: application/zip - name: Publish gz archive if: github.event.action == 'published' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/xmake.tar.gz asset_name: xmake-${{ steps.tagName.outputs.tag }}.tar.gz asset_content_type: application/zip - name: Publish zip archive if: github.event.action == 'published' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/xmake.zip asset_name: xmake-${{ steps.tagName.outputs.tag }}.zip asset_content_type: application/zip - name: Publish bundle binary if: github.event.action == 'published' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/xmake-bundle asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.macos.x86_64 asset_content_type: application/zip ================================================ FILE: .github/workflows/macos_arm64.yml ================================================ name: macOS (arm64) on: pull_request: push: release: types: [published] jobs: build: strategy: matrix: os: [macos-latest] arch: [arm64] runs-on: ${{ matrix.os }} concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-macOS-${{ matrix.arch }} cancel-in-progress: true steps: - uses: actions/checkout@v2 with: # WyriHaximus/github-action-get-previous-tag@master need it fetch-depth: 0 submodules: true - name: Prepare local xmake run: cp -rf . ../xmake-source - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: local#../xmake-source - uses: little-core-labs/get-git-tag@v3.0.2 id: tagName - name: Tests run: | xmake lua -v -D tests/run.lua xrepo --version - name: Artifact run: | cd core xmake f --embed=y -c xmake mkdir ../artifacts cp build/xmake ../artifacts/xmake-bundle cd .. - uses: actions/upload-artifact@v4 with: name: xmake-bundle.macos.arm64 path: artifacts/xmake-bundle - name: Publish bundle binary if: github.event.action == 'published' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/xmake-bundle asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.macos.arm64 asset_content_type: application/zip ================================================ FILE: .github/workflows/msys2_mingw.yml ================================================ name: MSYS2 (MingW) on: push: pull_request: jobs: build: runs-on: windows-latest concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-MSYS2_MINGW-${{ matrix.arch }} cancel-in-progress: true strategy: fail-fast: false matrix: include: [ { msystem: MINGW64, arch: x86_64, prefix: /mingw64 }, { msystem: MINGW32, arch: i686, prefix: /mingw32 } ] steps: - uses: actions/checkout@v2 with: path: temp submodules: true - uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.msystem }} install: git base-devel unzip mingw-w64-${{ matrix.arch }}-toolchain update: true - name: Move Checkout run: | Copy-Item -Path ".\temp" -Destination "C:\_" -Recurse - name: Build shell: msys2 {0} run: | cd /C/_ ./configure --prefix=${{ matrix.prefix }} make make install xmake --version - name: Tests shell: msys2 {0} run: | cd /C/_ xmake lua -v -D tests/run.lua xrepo --version ================================================ FILE: .github/workflows/netbsd.yml ================================================ name: NetBSD on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 20%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.NETBSD_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' runs-on: ubuntu-latest concurrency: # Prevent concurrent runs of the same workflow group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-NetBSD cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - name: Tests uses: vmactions/netbsd-vm@v1 with: usesh: true mem: 4096 copyback: false prepare: | /usr/sbin/pkg_add -u curl git unzip gmake llvm libcxx gsed bash perl ln -sf /usr/pkg/bin/gmake /usr/pkg/bin/make run: | ./configure gmake -j4 gmake install export XMAKE_ROOT=y xrepo --version xmake l os.meminfo xmake lua -v -D tests/run.lua ================================================ FILE: .github/workflows/openbsd.yml ================================================ name: OpenBSD on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 20%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.OPENBSD_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' runs-on: ubuntu-latest concurrency: # Prevent concurrent runs of the same workflow group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-OpenBSD cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - name: Tests uses: vmactions/openbsd-vm@v1 with: usesh: true mem: 4096 copyback: false prepare: | pkg_add curl git unzip gmake llvm libc++ gsed bash perl ln -sf /usr/local/bin/gmake /usr/local/bin/make run: | ./configure gmake -j4 gmake install export XMAKE_ROOT=y xrepo --version xmake l os.meminfo xmake lua -v -D tests/run.lua ================================================ FILE: .github/workflows/solaris.yml ================================================ name: Solaris on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 50%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.5'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.SOLARIS_RUN_PROBABILITY || '0.5' }} build: needs: check if: needs.check.outputs.should-run == 'true' runs-on: ubuntu-latest concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Solaris cancel-in-progress: true steps: - uses: actions/checkout@v2 with: submodules: true - name: Tests uses: vmactions/solaris-vm@v1 with: usesh: true prepare: | # Try OpenCSW first (for older Solaris) if command -v pkgutil >/dev/null 2>&1; then pkgutil -U || true pkgutil -y -i socat git gmake bash gcc4g++ 2>/dev/null || pkgutil -y -i socat git gmake bash gcc5g++ 2>/dev/null || true fi # Try IPS (for newer Solaris) if command -v pkg >/dev/null 2>&1; then pkg install --accept developer/gcc developer/build/gnu-make developer/versioning/git || true fi run: | cd $GITHUB_WORKSPACE bash ./configure gmake -j4 gmake install export XMAKE_ROOT=y xrepo --version xmake l os.meminfo xmake lua -v -D tests/run.lua ================================================ FILE: .github/workflows/windows.yml ================================================ name: Windows on: pull_request: push: release: types: [published] jobs: build: strategy: matrix: os: [windows-2022, windows-2025] arch: [x64, x86, arm64] runs-on: ${{ matrix.os }} concurrency: group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-${{ matrix.os }}-${{ matrix.arch }}-Windows cancel-in-progress: true steps: - uses: actions/checkout@v2 with: # WyriHaximus/github-action-get-previous-tag@master need it fetch-depth: 0 submodules: true - uses: xmake-io/github-action-setup-xmake@v1 with: # this is not supported, use dev branch instead # xmake-version: local# xmake-version: branch@dev - uses: dlang-community/setup-dlang@v1 with: compiler: dmd-latest - uses: little-core-labs/get-git-tag@v3.0.2 id: tagName # Force xmake to a specific folder (for cache) - name: Set xmake package cache path run: echo "XMAKE_PKG_CACHEDIR=$(pwd)/xmake-cache" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append # Cache xmake dependencies - name: Retrieve xmake cache for packages uses: actions/cache@v3 with: path: xmake-cache key: ${{ matrix.os }}-${{ matrix.arch }} - name: Set release arch name run: | if ("${{ matrix.arch }}" -eq "x64") { Write-Output "RELEASE_NAME=win64" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append } elseif ("${{ matrix.arch }}" -eq "arm64") { Write-Output "RELEASE_NAME=arm64" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append } else { Write-Output "RELEASE_NAME=win32" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append } - name: Build run: | cd core xmake f -vD -a ${{ matrix.arch }} --embed=y -c xmake xmake l os.cp build/xmake.exe ../artifacts/${{env.RELEASE_NAME}}/xmake-bundle.exe xmake f -vD -a ${{ matrix.arch }} -c xmake -vD cd .. - name: Artifact run: | cd core xrepo update-repo xmake pack -vD -y --formats=nsis,zip --autobuild=n -o ../artifacts/${{env.RELEASE_NAME}} --basename=xmake xmake (Get-FileHash ../artifacts/${{env.RELEASE_NAME}}/xmake.zip -Algorithm SHA256).Hash.ToLower() + " *xmake.zip`n" | Out-File ./shafile -Encoding ASCII -NoNewLine -Append Copy-Item shafile ../artifacts/${{env.RELEASE_NAME}} cd .. - name: Tests if: matrix.arch != 'arm64' run: | Copy-Item ./core/build/xmake.exe ./xmake Copy-Item ./scripts/xrepo.bat ./xmake Copy-Item ./scripts/xrepo.ps1 ./xmake $Env:XMAKE_MAIN_REPO = "https://github.com/xmake-io/xmake-repo.git" $Env:XMAKE_PROGRAM_DIR = $(Resolve-Path ./xmake) Set-Item -Path Env:Path -Value ($Env:XMAKE_PROGRAM_DIR + ";" + $Env:Path) xrepo --version xmake show xmake lua -v -D tests/run.lua # upload artifacts - name: Upload artifacts (exe) if: matrix.os == 'windows-2025' uses: actions/upload-artifact@v4 with: name: xmake-latest.${{env.RELEASE_NAME}}.exe path: artifacts/${{env.RELEASE_NAME}}/xmake.exe - name: Upload artifacts (zip) if: matrix.os == 'windows-2025' uses: actions/upload-artifact@v4 with: name: xmake-latest.${{ env.RELEASE_NAME }}.zip path: artifacts/${{env.RELEASE_NAME}}/xmake.zip - name: Upload artifacts (sha256) if: matrix.os == 'windows-2025' uses: actions/upload-artifact@v4 with: name: xmake-latest.${{ env.RELEASE_NAME }}.sha256 path: artifacts/${{env.RELEASE_NAME}}/shafile - name: Upload artifacts (bundle) if: matrix.os == 'windows-2025' uses: actions/upload-artifact@v4 with: name: xmake-bundle-latest.${{env.RELEASE_NAME}}.exe path: artifacts/${{env.RELEASE_NAME}}/xmake-bundle.exe # upload artifacts to latest release - name: Inject slug/short variables uses: rlespinasse/github-slug-action@v3.x - name: Get Previous tag id: previoustag uses: WyriHaximus/github-action-get-previous-tag@master - name: Upload artifacts to lastest release if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev') && matrix.os == 'windows-2025' uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: artifacts/${{env.RELEASE_NAME}}/xmake.exe asset_name: xmake-${{ env.GITHUB_REF_SLUG }}.${{ env.RELEASE_NAME }}.exe tag: ${{ steps.previoustag.outputs.tag }} overwrite: true - name: Upload artifacts to lastest release if: github.ref == 'refs/heads/master' && matrix.os == 'windows-2025' uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: artifacts/${{env.RELEASE_NAME}}/xmake.zip asset_name: xmake-${{ env.GITHUB_REF_SLUG }}.${{ env.RELEASE_NAME }}.zip tag: ${{ steps.previoustag.outputs.tag }} overwrite: true # publish release - name: Publish if: github.event.action == 'published' && matrix.os == 'windows-2025' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/${{env.RELEASE_NAME}}/xmake.exe asset_name: xmake-${{ steps.tagName.outputs.tag }}.${{ env.RELEASE_NAME }}.exe asset_content_type: application/zip - name: Publish if: github.event.action == 'published' && matrix.os == 'windows-2025' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/${{env.RELEASE_NAME}}/xmake.zip asset_name: xmake-${{ steps.tagName.outputs.tag }}.${{ env.RELEASE_NAME }}.zip asset_content_type: application/zip - name: Publish if: github.event.action == 'published' && matrix.os == 'windows-2025' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/${{env.RELEASE_NAME}}/shafile asset_name: xmake-${{ steps.tagName.outputs.tag }}.${{ env.RELEASE_NAME }}.sha256 asset_content_type: application/zip - name: Publish if: github.event.action == 'published' && matrix.os == 'windows-2025' uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: artifacts/${{env.RELEASE_NAME}}/xmake-bundle.exe asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.${{ env.RELEASE_NAME }}.exe asset_content_type: application/zip ================================================ FILE: .github/workflows/windows_luajit.yml ================================================ name: Windows (Luajit) on: pull_request: push: release: types: [published] jobs: check: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - name: Random execution check id: check uses: actions/github-script@v7 with: script: | const fs = require('fs'); const outputFile = process.env.GITHUB_OUTPUT; // Always run for release events if (context.eventName === 'release') { fs.appendFileSync(outputFile, `should-run=true\n`); core.info('Release event detected. Will run tests.'); return; } // Execution probability (default 20%, can be overridden via env) const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2'); // Generate deterministic "random" number based on commit SHA, run ID, and current time // Adding time ensures better randomness while keeping same commit/run consistent const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency const seed = context.sha + context.runId + timeSeed; let hash = 0; for (let i = 0; i < seed.length; i++) { const char = seed.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash | 0; // Convert to 32-bit integer } // Normalize to 0-1 range const random = Math.abs(hash) / 2147483647; const shouldRun = random < probability; // Use environment file instead of deprecated set-output fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`); if (shouldRun) { core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`); } else { core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`); } env: RUN_PROBABILITY: ${{ vars.WINDOWS_LUAJIT_RUN_PROBABILITY || '0.2' }} build: needs: check if: needs.check.outputs.should-run == 'true' strategy: matrix: os: [windows-2022, windows-2025] arch: [x64, x86] runs-on: ${{ matrix.os }} concurrency: # Prevent concurrent runs of the same workflow group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-${{ matrix.os }}-${{ matrix.arch }}-Windows-Luajit cancel-in-progress: true steps: - uses: actions/checkout@v2 with: # WyriHaximus/github-action-get-previous-tag@master need it fetch-depth: 0 submodules: true - uses: xmake-io/github-action-setup-xmake@v1 with: # this is not supported, use dev branch instead # xmake-version: local# xmake-version: branch@dev - uses: dlang-community/setup-dlang@v1 with: compiler: dmd-latest - uses: little-core-labs/get-git-tag@v3.0.2 id: tagName - name: Set release arch name run: | if ("${{ matrix.arch }}" -eq "x64") { Write-Output "RELEASE_NAME=win64" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append } elseif ("${{ matrix.arch }}" -eq "arm64") { Write-Output "RELEASE_NAME=arm64" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append } else { Write-Output "RELEASE_NAME=win32" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append } - name: Build run: | cd core xmake f -vD -a ${{ matrix.arch }} --runtime=luajit xmake -vD cd .. - name: Artifact run: | cd core xrepo update-repo xmake pack -vD -y --formats=nsis,zip --autobuild=n -o ../artifacts/${{env.RELEASE_NAME}} --basename=xmake xmake (Get-FileHash ../artifacts/${{env.RELEASE_NAME}}/xmake.zip -Algorithm SHA256).Hash.ToLower() + " *xmake.zip`n" | Out-File ./shafile -Encoding ASCII -NoNewLine -Append Copy-Item shafile ../artifacts/${{env.RELEASE_NAME}} cd .. - name: Tests run: | Copy-Item ./core/build/xmake.exe ./xmake Copy-Item ./scripts/xrepo.bat ./xmake Copy-Item ./scripts/xrepo.ps1 ./xmake $Env:XMAKE_PROGRAM_DIR = $(Resolve-Path ./xmake) Set-Item -Path Env:Path -Value ($Env:XMAKE_PROGRAM_DIR + ";" + $Env:Path) xrepo --version xmake show xmake lua -v -D tests/run.lua # upload artifacts - name: Upload artifacts (exe) if: matrix.os == 'windows-2022' uses: actions/upload-artifact@v4 with: name: xmake-latest.${{env.RELEASE_NAME}}.exe path: artifacts/${{env.RELEASE_NAME}}/xmake.exe - name: Upload artifacts (zip) if: matrix.os == 'windows-2022' uses: actions/upload-artifact@v4 with: name: xmake-latest.${{ env.RELEASE_NAME }}.zip path: artifacts/${{env.RELEASE_NAME}}/xmake.zip - name: Upload artifacts (sha256) if: matrix.os == 'windows-2022' uses: actions/upload-artifact@v4 with: name: xmake-latest.${{ env.RELEASE_NAME }}.sha256 path: artifacts/${{env.RELEASE_NAME}}/shafile ================================================ FILE: .gitignore ================================================ # MacOS Cache .DS_Store # Xmake cache .xmake/ build/ makefile Makefile build.ninja # gcc cache gcm.cache # for VS Code .vscode/ # for vim *.swp *.swo tags !tags/ # Ignore packaging files winenv/ *.exe *.zip *.gz *.bz2 *.xz *.7z *.run # for compiler compile_commands.json .cache/ # Makefile generation /core/xmake.config.h /core/.config.mak /core/**/*.o /core/**/*.b /core/**/*.a /core/**/*.obj /core/**/*.lib /core/**/*.exe # for fortran /tests/**/*.mod !/xmake/actions/build/ # for linux driver *.o *.ko *.mod .*.cmd *.mod.c Module.symvers modules.order # ai .claude ================================================ FILE: .gitmodules ================================================ [submodule "core/src/tbox/tbox"] path = core/src/tbox/tbox url = ../../tboox/tbox.git [submodule "core/src/luajit/luajit"] path = core/src/luajit/luajit url = ../../xmake-io/xmake-core-luajit.git [submodule "core/src/sv/sv"] path = core/src/sv/sv url = ../../xmake-io/xmake-core-sv.git [submodule "core/src/pdcurses/pdcurses"] path = core/src/pdcurses/pdcurses url = ../../xmake-io/xmake-core-pdcurses.git [submodule "core/src/lua-cjson/lua-cjson"] path = core/src/lua-cjson/lua-cjson url = ../../xmake-io/xmake-core-lua-cjson.git [submodule "core/src/lua/lua"] path = core/src/lua/lua url = ../../xmake-io/xmake-core-lua.git [submodule "core/src/lz4/lz4"] path = core/src/lz4/lz4 url = ../../xmake-io/xmake-core-lz4.git ================================================ FILE: CHANGELOG.md ================================================ # Changelog ([中文](#中文)) ## master (unreleased) ### New features * [#7398](https://github.com/xmake-io/xmake/pull/7398): Add C# language and dotnet toolchain support * [#7410](https://github.com/xmake-io/xmake/pull/7410): Add C# and C/C++ interop support via P/Invoke * [#7360](https://github.com/xmake-io/xmake/pull/7360): Support custom templates * [#7367](https://github.com/xmake-io/xmake/pull/7367): Add `xmake create --list` and remote template distribution * [#7313](https://github.com/xmake-io/xmake/pull/7313): Add `build.release.strip` policy * [#7333](https://github.com/xmake-io/xmake/pull/7333): Add `winos.file_signature` function * [#7336](https://github.com/xmake-io/xmake/pull/7336): Add support for running wasi target * [#7346](https://github.com/xmake-io/xmake/pull/7346): Add nnd debugger support * [#7366](https://github.com/xmake-io/xmake/pull/7366): Add tarxz pack format ### Changes * [#7309](https://github.com/xmake-io/xmake/pull/7309): Keep package source * [#7310](https://github.com/xmake-io/xmake/pull/7310): Improve check tips * [#7311](https://github.com/xmake-io/xmake/pull/7311): Improve Xcode toolchain * [#7312](https://github.com/xmake-io/xmake/pull/7312): Improve binutils to support wasm * [#7320](https://github.com/xmake-io/xmake/pull/7320): Add haiku ci * [#7329](https://github.com/xmake-io/xmake/pull/7329): Improve qt deploy for macapp * [#7349](https://github.com/xmake-io/xmake/pull/7349): Strip embed-dir on clang/gcc for C++ modules * [#7368](https://github.com/xmake-io/xmake/pull/7368): Move templates to repository * [#7383](https://github.com/xmake-io/xmake/pull/7383): Split zig toolchain to zig/zigcc * [#7384](https://github.com/xmake-io/xmake/pull/7384): Improve find_hdk * [#7387](https://github.com/xmake-io/xmake/pull/7387): Show target name in progress * [#7391](https://github.com/xmake-io/xmake/pull/7391): Improve to find package with vcpkg features * [#7392](https://github.com/xmake-io/xmake/pull/7392): Fix zig for shared libraries * [#7396](https://github.com/xmake-io/xmake/pull/7396): Improve vcpkg * [#7399](https://github.com/xmake-io/xmake/pull/7399): Extend formatting to C++ modules * [#7409](https://github.com/xmake-io/xmake/pull/7409): Improve ldc on windows ### Bugs fixed * [#7299](https://github.com/xmake-io/xmake/pull/7299): Fix dependency handling for vcpkg * [#7316](https://github.com/xmake-io/xmake/pull/7316): Fix components typo * [#7318](https://github.com/xmake-io/xmake/pull/7318): Update tbox to fix tolower/toupper * [#7339](https://github.com/xmake-io/xmake/pull/7339): Update tbox to fix start process on win7 * [#7344](https://github.com/xmake-io/xmake/pull/7344): Fix swig jar package module * [#7345](https://github.com/xmake-io/xmake/pull/7345): Fix check clang info * [#7341](https://github.com/xmake-io/xmake/pull/7341): Fix WASM QT 6.9 * [#7356](https://github.com/xmake-io/xmake/pull/7356): Fix issue #7354 * [#7371](https://github.com/xmake-io/xmake/pull/7371): Fix test verbose output * [#7386](https://github.com/xmake-io/xmake/pull/7386): Fix install script incompatibility with coreutils 9.10 * [#7393](https://github.com/xmake-io/xmake/pull/7393): Fix build target validation ## v3.0.7 ### New features * [#7178](https://github.com/xmake-io/xmake/pull/7178): Switch Verilator build file parsing from cmake to json format * [#7186](https://github.com/xmake-io/xmake/pull/7186): Add alpine ci * [#7187](https://github.com/xmake-io/xmake/pull/7187): Add suffix support for CUDA architecture * [#7190](https://github.com/xmake-io/xmake/pull/7190): Nix Package Manager: Add Semantic Versioning and Improve Version Selection * [#7189](https://github.com/xmake-io/xmake/pull/7189): Add package schemes * [#7208](https://github.com/xmake-io/xmake/pull/7208): Support dynamic mkspec selection for Qt SDK * [#7219](https://github.com/xmake-io/xmake/pull/7219): Add cli.iconv module * [#7235](https://github.com/xmake-io/xmake/pull/7235): Add string case conversion functions: lower and upper * [#7246](https://github.com/xmake-io/xmake/pull/7246): Add utf8 module * [#7268](https://github.com/xmake-io/xmake/pull/7268): Add dependency file generation for Nim source files * [#7269](https://github.com/xmake-io/xmake/pull/7269): Add target architecture validation for cross-compilation in zig toolchain * [#7274](https://github.com/xmake-io/xmake/pull/7274): Add os.access function for file access checking * [#7284](https://github.com/xmake-io/xmake/pull/7284): Add `--stdin` * [#7293](https://github.com/xmake-io/xmake/pull/7293): Add support for running wasm target in browser * [#7300](https://github.com/xmake-io/xmake/pull/7300): Add libdir,includedir,bindir support for install/uninstall * [#7295](https://github.com/xmake-io/xmake/pull/7295): Support test output files ### Changes * [#7203](https://github.com/xmake-io/xmake/pull/7203): Improve mingw toolchain * [#7206](https://github.com/xmake-io/xmake/pull/7206): WDK: Add shared directory to KMDF include path * [#7214](https://github.com/xmake-io/xmake/pull/7214): Improve warnings output * [#7216](https://github.com/xmake-io/xmake/pull/7216): Improve requirelock * [#7223](https://github.com/xmake-io/xmake/pull/7223): Improve NuGet library file matching with score-based selection * [#7226](https://github.com/xmake-io/xmake/pull/7226): Improve to find clang-tidy * [#7232](https://github.com/xmake-io/xmake/pull/7232): Improve linker.link_scripts * [#7237](https://github.com/xmake-io/xmake/pull/7237): Update tbox to support case * [#7240](https://github.com/xmake-io/xmake/pull/7240): Improve verilator flags * [#7258](https://github.com/xmake-io/xmake/pull/7258): Improve qt xpack * [#7262](https://github.com/xmake-io/xmake/pull/7262): Improve pch concurrently to other targets * [#7260](https://github.com/xmake-io/xmake/pull/7260): Improve fpc * [#7270](https://github.com/xmake-io/xmake/pull/7270): Improve to select scheme version * [#7272](https://github.com/xmake-io/xmake/pull/7272): Enhance Nim support for shared libraries and rpath handling * [#7273](https://github.com/xmake-io/xmake/pull/7273): Improve io.read and io.readfile * [#7267](https://github.com/xmake-io/xmake/pull/7267): Enhance shell detection for Linux by checking parent process * [#7278](https://github.com/xmake-io/xmake/pull/7278): Improve os.isexec * [#7283](https://github.com/xmake-io/xmake/pull/7283): Enhance compile_commands support and add test cases * [#7285](https://github.com/xmake-io/xmake/pull/7285): Improve Windows shell detection for cmd/powershell * [#7286](https://github.com/xmake-io/xmake/pull/7286): Check long env values when detecting vs * [#7280](https://github.com/xmake-io/xmake/pull/7280): Add target flags only for cross-compilation * [#7290](https://github.com/xmake-io/xmake/pull/7290): Improve vcvars * [#7302](https://github.com/xmake-io/xmake/pull/7302): Improve run process errors * [#7306](https://github.com/xmake-io/xmake/pull/7306): Improve remote build with multi-host configuration and `--host` option * [#7298](https://github.com/xmake-io/xmake/pull/7298): Add initial implementation for Windows DLL foo/main example ### Bugs fixed * [#7210](https://github.com/xmake-io/xmake/pull/7210): Fix package version * [#7213](https://github.com/xmake-io/xmake/pull/7213): Fix installdir of imporfiles * [#7231](https://github.com/xmake-io/xmake/pull/7231): Fix get flag in module support * [#7245](https://github.com/xmake-io/xmake/pull/7245): Fix to select scheme version * [#7259](https://github.com/xmake-io/xmake/pull/7259): Fix export c++ function symbols * [#7266](https://github.com/xmake-io/xmake/pull/7266): Fix pch header extension * [#7282](https://github.com/xmake-io/xmake/pull/7282): find_cuda: revert breaking change * [#7294](https://github.com/xmake-io/xmake/pull/7294): Fix package toolchain * [#7296](https://github.com/xmake-io/xmake/pull/7296): Fix find emsdk * [#7202](https://github.com/xmake-io/xmake/pull/7202): Fix getfenv ## v3.0.6 ### New features * [#7141](https://github.com/xmake-io/xmake/pull/7141): Support disabling native app glue for Android * [#7139](https://github.com/xmake-io/xmake/pull/7139): Add Android native app build support * [#7127](https://github.com/xmake-io/xmake/pull/7127): Add deplibs support in binutils * [#7120](https://github.com/xmake-io/xmake/pull/7120): Add extractlib support in binutils * [#7106](https://github.com/xmake-io/xmake/pull/7106): Add `/std:c++23preview` support for MSVC * [#7105](https://github.com/xmake-io/xmake/pull/7105): Add `bin2obj` support for glsl/hlsl2spv * [#7103](https://github.com/xmake-io/xmake/pull/7103): Add `bin2obj` rule (faster than `bin2c`) * [#7096](https://github.com/xmake-io/xmake/pull/7096): Add Flang toolchain support * [#7094](https://github.com/xmake-io/xmake/pull/7094): Add `xmake check syntax` support * [#7091](https://github.com/xmake-io/xmake/pull/7091): Add dynamic debugging support for MSVC * [#7083](https://github.com/xmake-io/xmake/pull/7083): Add support for CUDA 11~13 * [#7071](https://github.com/xmake-io/xmake/pull/7071): Add Qt pack support * [#7064](https://github.com/xmake-io/xmake/pull/7064): Add AppImage xpack format for Linux application packaging * [#7062](https://github.com/xmake-io/xmake/pull/7062): Add dmg xpack format for macOS application packaging ### Changes * [#7149](https://github.com/xmake-io/xmake/pull/7149): Improve binutils to optimize rpath parsing * [#7148](https://github.com/xmake-io/xmake/pull/7148): Update Zig examples * [#7145](https://github.com/xmake-io/xmake/pull/7145): Improve Clang/LLVM runtime support * [#7136](https://github.com/xmake-io/xmake/pull/7136): Improve clang-cl depfiles generation * [#7135](https://github.com/xmake-io/xmake/pull/7135): Improve `xrepo env` to add session ID * [#7155](https://github.com/xmake-io/xmake/pull/7155): Refactor Windows ASan for clang-cl (runtime linking, linker flags, PATH/CMAKE_LINKER_TYPE setup, toolchain streamlining) * [#7109](https://github.com/xmake-io/xmake/pull/7109): Improve binutils to read symbols from binary file * [#7102](https://github.com/xmake-io/xmake/pull/7102): Improve bin2c rule * [#7098](https://github.com/xmake-io/xmake/pull/7098): Refactor and improve Golang support * [#7095](https://github.com/xmake-io/xmake/pull/7095): Mark target/package/toolchain:memcache as public * [#7093](https://github.com/xmake-io/xmake/pull/7093): Improve mirror repo URL * [#7088](https://github.com/xmake-io/xmake/pull/7088): Improve C++/ObjC rules * [#7087](https://github.com/xmake-io/xmake/pull/7087): Add type constraint for policy `package.download.http_headers` * [#7069](https://github.com/xmake-io/xmake/pull/7069): Save Qt rules for LLVM toolchain * [#7061](https://github.com/xmake-io/xmake/pull/7061): Update CI configuration * [#7039](https://github.com/xmake-io/xmake/pull/7039): Update macOS CI ### Bugs fixed * [#7132](https://github.com/xmake-io/xmake/pull/7132): Fix clang-cl toolchain with ASan * [#7125](https://github.com/xmake-io/xmake/pull/7125): Fix cosmocc CI * [#7124](https://github.com/xmake-io/xmake/pull/7124): Fix default MSVC runtime for Clang toolchain * [#7112](https://github.com/xmake-io/xmake/pull/7112): Fix change directory on Windows * [#7104](https://github.com/xmake-io/xmake/pull/7104): Fix prepare for project generators * [#7092](https://github.com/xmake-io/xmake/pull/7092): Fix Solaris build * [#7086](https://github.com/xmake-io/xmake/pull/7086): Fix targetdir in Qt QML rule * [#7085](https://github.com/xmake-io/xmake/pull/7085): Fix CMake flags for Clang toolchain * [#7084](https://github.com/xmake-io/xmake/pull/7084): Fix pacman find_package * [#7082](https://github.com/xmake-io/xmake/pull/7082): Fix checking Clang CUDA flags * [#7081](https://github.com/xmake-io/xmake/pull/7081): Fix `get_headerunit_key` * [#7074](https://github.com/xmake-io/xmake/pull/7074): Fix libc++ cannot find std module * [#7067](https://github.com/xmake-io/xmake/pull/7067): Fix get_stdmodules with cross toolchain ## v3.0.5 ### New features * [#7055](https://github.com/xmake-io/xmake/pull/7055): Add Solaris platform support (i386, x86_64) * [#7054](https://github.com/xmake-io/xmake/pull/7054): Add support for additional BSD systems (NetBSD, OpenBSD, DragonflyBSD) * [#6929](https://github.com/xmake-io/xmake/pull/6929): Add support for GCC 15 toolchain * [#6967](https://github.com/xmake-io/xmake/pull/6967): Add Swift interop support for C++ and Objective-C * [#6964](https://github.com/xmake-io/xmake/pull/6964): Support specifying CUDA SDK version via cuda_sdkver * [#6963](https://github.com/xmake-io/xmake/pull/6963): Add libtool patch support for cross compilation * [#6974](https://github.com/xmake-io/xmake/pull/6974): Support multi-row refresh for progress output * [#7024](https://github.com/xmake-io/xmake/pull/7024): Add JSON output format for `xmake show -t target` * [#7025](https://github.com/xmake-io/xmake/pull/7025): Add XML module with parsing and encoding support * [#6989](https://github.com/xmake-io/xmake/pull/6989): Add async support for os APIs ### Changes * [#6924](https://github.com/xmake-io/xmake/pull/6924): Improve toolchain configuration with add_toolchains("name[configs]") syntax * [#6935](https://github.com/xmake-io/xmake/pull/6935): Refactor toolchain: separate gcc/clang registration from definition * [#6942](https://github.com/xmake-io/xmake/pull/6942): Improve file reading performance * [#6946](https://github.com/xmake-io/xmake/pull/6946): Add LLD linker support for Clang toolchain * [#6970](https://github.com/xmake-io/xmake/pull/6970): Improve TTY handling and output * [#6977](https://github.com/xmake-io/xmake/pull/6977): Refactor Xcode toolchain and integrate it into LLVM toolchain for Apple devices * [#6987](https://github.com/xmake-io/xmake/pull/6987): Add Ghostty terminal detection support * [#7003](https://github.com/xmake-io/xmake/pull/7003): Limit build environment retrieval in package configurations * [#7008](https://github.com/xmake-io/xmake/pull/7008): Format code style * [#7004](https://github.com/xmake-io/xmake/pull/7004): Skip rebuilding packages and std modules when using -r flag * [#7019](https://github.com/xmake-io/xmake/pull/7019): Improve xmake.sh/configure script and add Ninja generator support * [#7023](https://github.com/xmake-io/xmake/pull/7023): Update Qt TypeScript rule * [#7022](https://github.com/xmake-io/xmake/pull/7022): Make zig-cc toolchain inherit from clang * [#7027](https://github.com/xmake-io/xmake/pull/7027): Improve graph module performance * [#7031](https://github.com/xmake-io/xmake/pull/7031): Improve require parsing * [#7032](https://github.com/xmake-io/xmake/pull/7032): Improve symbol extraction * [#6952](https://github.com/xmake-io/xmake/pull/6952): Add realtime output support for tests * [#6998](https://github.com/xmake-io/xmake/pull/6998): Update tbox library for process/argv support * [#7037](https://github.com/xmake-io/xmake/pull/7037): Improve xmake format * [#7038](https://github.com/xmake-io/xmake/pull/7038): Improve clang-tidy output handling ### Bugs fixed * [#6926](https://github.com/xmake-io/xmake/pull/6926): Fix loading Unicode main script path on Windows * [#6931](https://github.com/xmake-io/xmake/pull/6931): Fix C++ modules: fallback to system-wide clang-scan-deps when toolchain version is not installed * [#6937](https://github.com/xmake-io/xmake/pull/6937): Fix target jobs handling * [#6954](https://github.com/xmake-io/xmake/pull/6954): Fix modules support for vsxmake/vs generators * [#6955](https://github.com/xmake-io/xmake/pull/6955): Fix build number sorting in packages * [#6956](https://github.com/xmake-io/xmake/pull/6956): Fix build failure when using zigcc linker that doesn't support depfile * [#6959](https://github.com/xmake-io/xmake/pull/6959): Fix using zigcc with autotools for dynamic linking * [#6983](https://github.com/xmake-io/xmake/pull/6983): Fix modules: strip sanitizer flags for module reuse * [#6984](https://github.com/xmake-io/xmake/pull/6984): Fix libdir path in installed CMake import files * [#6993](https://github.com/xmake-io/xmake/pull/6993): Fix xmake test modules * [#6992](https://github.com/xmake-io/xmake/pull/6992): Fix modules: add all supported platforms for clang get_cpp_library_name * [#6999](https://github.com/xmake-io/xmake/pull/6999): Fix rootdir handling * [#7002](https://github.com/xmake-io/xmake/pull/7002): Fix asn1c: include generated output as system headers * [#6996](https://github.com/xmake-io/xmake/pull/6996): Fix Nimble find_package to use latest package list format * [#7012](https://github.com/xmake-io/xmake/pull/7012): Fix sparse checkout handling * [#7013](https://github.com/xmake-io/xmake/pull/7013): Fix removing dependencies when packaging * [#7017](https://github.com/xmake-io/xmake/pull/7017): Fix lock_packages typo * [#7016](https://github.com/xmake-io/xmake/pull/7016): Fix project default configuration in vsxmake * [#7018](https://github.com/xmake-io/xmake/pull/7018): Fix build order: only disable when dependency linking inheritance is disabled * [#7035](https://github.com/xmake-io/xmake/pull/7035): Fix process redirection issues by updating tbox ## v3.0.4 ### New features * [#6864](https://github.com/xmake-io/xmake/pull/6864): Add default file filter for `format` task * [#6843](https://github.com/xmake-io/xmake/pull/6843): Improve clang-tidy support * [#6861](https://github.com/xmake-io/xmake/pull/6861): Rewrite of Nix Package Manager Support * [#6850](https://github.com/xmake-io/xmake/pull/6850): Add package api checking * [#6874](https://github.com/xmake-io/xmake/pull/6874): Add scriptdir to project packages * [#6876](https://github.com/xmake-io/xmake/pull/6876): Add versionfiles checker * [#6884](https://github.com/xmake-io/xmake/pull/6884): Add msystem support on msys2 * [#6891](https://github.com/xmake-io/xmake/pull/6891): Add coroutine semaphore * [#6894](https://github.com/xmake-io/xmake/pull/6894): Add llvm-nm for clang toolchain * [#6918](https://github.com/xmake-io/xmake/pull/6918): Add copy_if_different in os.cp ### Changes * [#6846](https://github.com/xmake-io/xmake/pull/6846): Improve cmake default flags * [#6849](https://github.com/xmake-io/xmake/pull/6849): Improve jobgraph * [#6859](https://github.com/xmake-io/xmake/pull/6859): Improve to check target flags * [#6858](https://github.com/xmake-io/xmake/pull/6858): Modify config flags order * [#6854](https://github.com/xmake-io/xmake/pull/6854): Improve os.curdir/os.cd * [#6866](https://github.com/xmake-io/xmake/pull/6866): Improve os.getenvs * [#6867](https://github.com/xmake-io/xmake/pull/6867): Make sure generic options are always inserted * [#6870](https://github.com/xmake-io/xmake/pull/6870): chore(vcpkg): bump default baseline hash of vcpkg * [#6880](https://github.com/xmake-io/xmake/pull/6880): Update cmake_importfiles.lua * [#6872](https://github.com/xmake-io/xmake/pull/6872): Improve hash * [#6886](https://github.com/xmake-io/xmake/pull/6886): Decrease jobs count in jobgraph * [#6890](https://github.com/xmake-io/xmake/pull/6890): Update cmake_importfiles.lua * [#6892](https://github.com/xmake-io/xmake/pull/6892): Improve runjobs to reduce the time spent on coroutine scheduling * [#6896](https://github.com/xmake-io/xmake/pull/6896): Add hash test * [#6904](https://github.com/xmake-io/xmake/pull/6904): Improve clang to support for msvc envs * [#6915](https://github.com/xmake-io/xmake/pull/6915): Improve to export def rules for binary ### Bugs fixed * [#6844](https://github.com/xmake-io/xmake/pull/6844): Fix version in auto-generated .pc. * [#6851](https://github.com/xmake-io/xmake/pull/6851): Fix finding clang-scan-deps * [#6857](https://github.com/xmake-io/xmake/pull/6857): Fix rc compiler with cmake in cross-compilation * [#6809](https://github.com/xmake-io/xmake/pull/6809): fix(C++ modules) fix stdmodule priority * [#6882](https://github.com/xmake-io/xmake/pull/6882): Fix: write package manifest.pathenvs in deterministic order * [#6888](https://github.com/xmake-io/xmake/pull/6888): Fix clang toolchain package * [#6889](https://github.com/xmake-io/xmake/pull/6889): Fix os.getenvs compat * [#6900](https://github.com/xmake-io/xmake/pull/6900): package.tools.xmake: fix policies not being passed * [#6901](https://github.com/xmake-io/xmake/pull/6901): package download: don't get submodules if disabled * [#6907](https://github.com/xmake-io/xmake/pull/6907): package download: don't get submodules if disabled (branch version) ## v3.0.3 ### New features * [#6778](https://github.com/xmake-io/xmake/pull/6778): Add build.linker.output * [#6779](https://github.com/xmake-io/xmake/pull/6779): Add #embed and embedirs support * [#6787](https://github.com/xmake-io/xmake/pull/6787): Support for vs2026 * [#6785](https://github.com/xmake-io/xmake/pull/6785): Support clang and llvm for wdk rules * [#6791](https://github.com/xmake-io/xmake/pull/6791): Add Nix Package Manager Support * [#6800](https://github.com/xmake-io/xmake/pull/6800): Support nushell for xrepo env * [#6796](https://github.com/xmake-io/xmake/pull/6796): Enable support of incomplete wdk ### Changes * [#6765](https://github.com/xmake-io/xmake/pull/6765): Improve bin2c to use native thread * [#6771](https://github.com/xmake-io/xmake/pull/6771): Fix find gcc/gxx cache * [#6777](https://github.com/xmake-io/xmake/pull/6777): Fix executable path for cmake * [#6783](https://github.com/xmake-io/xmake/pull/6783): Fix build.c++.modules.std policy * [#6744](https://github.com/xmake-io/xmake/pull/6744): Use a file for requires flags when --verbose or --diagnosis is supplied * [#6780](https://github.com/xmake-io/xmake/pull/6780): Add benchmarks and optimize config/build targets * [#6784](https://github.com/xmake-io/xmake/pull/6784): Continue to optimize building targets speed * [#6793](https://github.com/xmake-io/xmake/pull/6793): Use musl to avoid glibc's version issue * [#6788](https://github.com/xmake-io/xmake/pull/6788): Improve incremental build clang * [#6811](https://github.com/xmake-io/xmake/pull/6811): Improve clang-tidy * [#6810](https://github.com/xmake-io/xmake/pull/6810): Improve the default flags for cmake * [#6801](https://github.com/xmake-io/xmake/pull/6801): Change compilers priority for gcc and clang * [#6819](https://github.com/xmake-io/xmake/pull/6819): Improve show target * [#6817](https://github.com/xmake-io/xmake/pull/6817): Improve build targets speed * [#6822](https://github.com/xmake-io/xmake/pull/6822): Prioritize envs over repo cache * [#6824](https://github.com/xmake-io/xmake/pull/6824): Improve has_flags * [#6832](https://github.com/xmake-io/xmake/pull/6832): Optimize codesign ### Bugs fixed * [#6808](https://github.com/xmake-io/xmake/pull/6808): Fix xrepo env * [#6821](https://github.com/xmake-io/xmake/pull/6821): Clean undefined vsvers * [#6818](https://github.com/xmake-io/xmake/pull/6818): Fix Nix Package Detection in nix-shell Environment * [#6798](https://github.com/xmake-io/xmake/pull/6798): Add external to the strippeable_flags for msvc ## v3.0.2 ### New features * [#6755](https://github.com/xmake-io/xmake/issues/6755): Add native thread support * [#6641](https://github.com/xmake-io/xmake/pull/6641): Add pkgenvs to target/config * [#6644](https://github.com/xmake-io/xmake/pull/6644): Support .def file with clang * [#6695](https://github.com/xmake-io/xmake/pull/6695): Add /uselocaltime to inf2cat args * [#6709](https://github.com/xmake-io/xmake/pull/6709): Support for wasm64 * [#6737](https://github.com/xmake-io/xmake/pull/6737): Add python stub file extension to cython rule ### Changes * [#6651](https://github.com/xmake-io/xmake/pull/6651): Improve depfiles * [#6656](https://github.com/xmake-io/xmake/pull/6656): Make build tools support passing in `opt.targets` * [#6688](https://github.com/xmake-io/xmake/pull/6688): Improve to install targets * [#6692](https://github.com/xmake-io/xmake/pull/6692): Improve protobuf test * [#6714](https://github.com/xmake-io/xmake/pull/6714): Improve tests for c++ modules * [#6719](https://github.com/xmake-io/xmake/pull/6719): Improve comax for config * [#6725](https://github.com/xmake-io/xmake/pull/6725): Improve target:extrafiles ### Bugs fixed * [#6648](https://github.com/xmake-io/xmake/pull/6648): Fix(qt.qmltyperegistrar): Collect metatypes info * [#6661](https://github.com/xmake-io/xmake/pull/6661): Fix prolonged blocking in _ping_via_wget by setting "--tries=1" * [#6665](https://github.com/xmake-io/xmake/pull/6665): Fix cmake/mingw * [#6674](https://github.com/xmake-io/xmake/pull/6674): Attempt to fix linkgroups in package * [#6686](https://github.com/xmake-io/xmake/pull/6686): Fix compiler cache * [#6698](https://github.com/xmake-io/xmake/pull/6698): Fix(c++ modules) handle empty modules * [#6699](https://github.com/xmake-io/xmake/pull/6699): Fix(c++ modules) fix xmake not updating module mapper when module file is removed * [#6706](https://github.com/xmake-io/xmake/pull/6706): Fix find_cudadevices for CUDA 13 * [#6707](https://github.com/xmake-io/xmake/pull/6707): Fix(c++ modules) fix sourcebatch caching * [#6712](https://github.com/xmake-io/xmake/pull/6712): Fix(c++ modules) fix disabled target getting configured for module compilation * [#6713](https://github.com/xmake-io/xmake/pull/6713): Fix(c++ modules) fix non .cpp file stealed from c++.build sourcebatch * [#6715](https://github.com/xmake-io/xmake/pull/6715): Fix(c++ modules) fix public culled module incorrectly emiting a warning * [#6718](https://github.com/xmake-io/xmake/pull/6718): Ignore pch flags * [#6732](https://github.com/xmake-io/xmake/pull/6732): Fix: android ndk rust link-args * [#6735](https://github.com/xmake-io/xmake/pull/6735): Fix(qt.qmltyperegistrar): Extend dependencies for rebuild * [#6738](https://github.com/xmake-io/xmake/pull/6738): Fix protobuf for target deps * [#6741](https://github.com/xmake-io/xmake/pull/6741): Fix vsxmake options * [#6747](https://github.com/xmake-io/xmake/pull/6747): meminfo.c: no vmstat.compressor_page_count on < 10.7 ## v3.0.1 ### New features * [#4810](https://github.com/xmake-io/xmake/issues/4810): Add Native XCode project generator plugin ### Bugs fixed * [#6592](https://github.com/xmake-io/xmake/pull/6592): Fix objects only links * [#6586](https://github.com/xmake-io/xmake/issues/6586): Fix build.fence policy * [#6600](https://github.com/xmake-io/xmake/issues/6600): Fix compile_commands generator for c++modules * [#6621](https://github.com/xmake-io/xmake/issues/6621): Fix android build for ndk r17c * [#6635](https://github.com/xmake-io/xmake/discussions/6635): Fix batchcmds for qt/moc ## v3.0.0 ### New features * [#5926](https://github.com/xmake-io/xmake/issues/5926): Add MIDL support * [#6414](https://github.com/xmake-io/xmake/pull/6414): Add platform.windows.subsystem rule * [#5527](https://github.com/xmake-io/xmake/issues/5527): Switch to 3.0 policies ### Changes * [#6202](https://github.com/xmake-io/xmake/issues/6202): Improve rule API and build dependency order * [#5624](https://github.com/xmake-io/xmake/discussions/5624): Enable auto build when calling xmake run by default * [#5526](https://github.com/xmake-io/xmake/discussions/5526): Use MD/MDd runtimes for msvc by default * [#5545](https://github.com/xmake-io/xmake/discussions/5545): Use ninja generator for cmake package by default * [#6355](https://github.com/xmake-io/xmake/pull/6355): Support customizing implib path of MinGW/MSVC * [#6373](https://github.com/xmake-io/xmake/pull/6373): Improve c++ modules support * [#6376](https://github.com/xmake-io/xmake/issues/6476): Improve vsxmake generators for namespaces * [#6209](https://github.com/xmake-io/xmake/pull/6209): Add build jobgraph support * [#6361](https://github.com/xmake-io/xmake/pull/6361): Rename buildir to builddir ## v2.9.9 ### New features * [#6137](https://github.com/xmake-io/xmake/issues/6137): IDE integration * [#6138](https://github.com/xmake-io/xmake/issues/6138): Use libxmake to build binary with xmake lua apis * [#6154](https://github.com/xmake-io/xmake/issues/6154): Add kotlin language and kotlin-native compiler and packages support * [#6279](https://github.com/xmake-io/xmake/pull/6279): Add msvc midl support ### Changes * [#6182](https://github.com/xmake-io/xmake/pull/6182): Support msstl modules for clang * [#6281](https://github.com/xmake-io/xmake/pull/6281): Support Verilator target build to shared library * [#6270](https://github.com/xmake-io/xmake/pull/6270): Improve conan generator * [#6243](https://github.com/xmake-io/xmake/pull/6243): Improve llvm toolchain to support for cross platform * Support for CMake 4.0 ### Bugs fixed * [#6292](https://github.com/xmake-io/xmake/issues/6292): Fix namespace issue ## v2.9.8 ### New features * [#5994](https://github.com/xmake-io/xmake/issues/5994): Profile process performance * [#5995](https://github.com/xmake-io/xmake/pull/5995): Add profile support for vs generator * [#5949](https://github.com/xmake-io/xmake/pull/5949): Add rule nodejs.module * [#3380](https://github.com/xmake-io/xmake/issues/3380): Add namespace support * [#5945](https://github.com/xmake-io/xmake/issues/5945): Check pkgconfig/cmake importfiles for package * [#6054](https://github.com/xmake-io/xmake/issues/6054): Add xmake bundle for linux * [#6071](https://github.com/xmake-io/xmake/issues/6071): Improve to download package for git url, support for sparse-checkout * [#5163](https://github.com/xmake-io/xmake/issues/5163): Support TI-CGT C2000/C6000 compiler * [#5344](https://github.com/xmake-io/xmake/issues/5344): Support IAR ARM C/C++ compiler * [#5554](https://github.com/xmake-io/xmake/issues/5554): Add custom unknown toolchains support ### Changes * [#6056](https://github.com/xmake-io/xmake/pull/6056): Build and release xmake/arm64 on windows. * [#6097](https://github.com/xmake-io/xmake/pull/6097): Add qt_host Option to Enable Cross-Platform Qt Builds Using Host SDK Tools * [#6120](https://github.com/xmake-io/xmake/issues/6120): Add custom preprocessor for configfiles * [#6088](https://github.com/xmake-io/xmake/issues/6088): Improve configfiles to generate export macro ### Bugs fixed * [#272](https://github.com/tboox/tbox/issues/272): Fix xmake stuck when readfile always return zero for msvc + /O1 * [#6089](https://github.com/tboox/tbox/issues/6089): Fix depend.is_changed for cuda ## v2.9.7 ### New features * [#5813](https://github.com/xmake-io/xmake/pull/5813): Add `before_config` and `after_config` for rule * [#5848](https://github.com/xmake-io/xmake/issues/5848): Support custom MSVC build tools, e.g. PortableBuildTools and msvc-wine * [#5880](https://github.com/xmake-io/xmake/pull/5880): Use msvc package to build project * [#5884](https://github.com/xmake-io/xmake/issues/5884): Add installtips for package * [#5894](https://github.com/xmake-io/xmake/issues/5894): Add package.merge_staticlibs policy to merge package libs * [#5948](https://github.com/xmake-io/xmake/pull/5948): Add `lua.native-object` rule * [#5911](https://github.com/xmake-io/xmake/issues/5911): Support for nuget packages ### Changes * [#5817](https://github.com/xmake-io/xmake/pull/5817): Improve default pic for packages * [#5869](https://github.com/xmake-io/xmake/pull/5869): Add libstdc++ standard library modules support for gcc * [#5923](https://github.com/xmake-io/xmake/pull/5923): Solve the package version and configs conflict ### Bugs fixed * [#5856](https://github.com/xmake-io/xmake/issues/5856): Fix compile c++modules for clang * [#5858](https://github.com/xmake-io/xmake/issues/5858): Fix the precompiled header for gcc ## v2.9.6 ### New features * [#5527](https://github.com/xmake-io/xmake/issues/5527): Add `set_policy("compatibility.version", "3.0")` to preview v3.0 features. * [#5649](https://github.com/xmake-io/xmake/pull/5649): Add `package.check_fcsnippets` ### Changes * [#5631](https://github.com/xmake-io/xmake/pull/5631): Add `as_needed` for `add_linkgroups` * [#5702](https://github.com/xmake-io/xmake/issues/5702): Improve hash module * [#5688](https://github.com/xmake-io/xmake/pull/5688): Improve hashset module * [#5711](https://github.com/xmake-io/xmake/issues/5711): Support to parse include deps for sdcc * [#5727](https://github.com/xmake-io/xmake/issues/5727): Improve configs for add_requires * [#5762](https://github.com/xmake-io/xmake/pull/5762): Improve bin2c speed ### Bugs fixed * [#5645](https://github.com/xmake-io/xmake/issues/5645): Fix `xmake watch` for linux * [#5686](https://github.com/xmake-io/xmake/pull/5686): Fix module scanning ## v2.9.5 ### New features * [#5462](https://github.com/xmake-io/xmake/pull/5462): Add `xmake l cli.bisect` * [#5488](https://github.com/xmake-io/xmake/pull/5488): Support for using cosmocc to build xmake binary * [#5491](https://github.com/xmake-io/xmake/pull/5491): Provide single xmake binary with embeded lua files * [#5580](https://github.com/xmake-io/xmake/issues/5580): Add `@builtin/xrepo` to add envs for `xrepo env shell` ### Changes * [#5507](https://github.com/xmake-io/xmake/issues/5507): Use treeless to improve git.clone * [#5536](https://github.com/xmake-io/xmake/pull/5536): Add jar generate in swig mode * [#5573](https://github.com/xmake-io/xmake/issues/5573): Improve vsxmake generator performance * [#5601](https://github.com/xmake-io/xmake/issues/5601): Improve utils.symbols.export_all rule to filter sourcefile path ### Bugs fixed * [#4750](https://github.com/xmake-io/xmake/issues/4750): Fix compile_commands generator for `xmake tests` * [#5465](https://github.com/xmake-io/xmake/pull/5465): Fix lock package requires * [#4760](https://github.com/xmake-io/xmake/issues/4760): Fix distcc client issue ## v2.9.4 ### New features * [#5278](https://github.com/xmake-io/xmake/issues/5278): Add `build.intermediate_directory` policy to disable and custom intermediate directory * [#5313](https://github.com/xmake-io/xmake/issues/5313): Add windows arm/arm64ec support * [#5296](https://github.com/xmake-io/xmake/issues/5296): Add Intel LLVM Fortran Compiler support * [#5384](https://github.com/xmake-io/xmake/issues/5384): Add `add_bindirs` for package ### Changes * [#5280](https://github.com/xmake-io/xmake/issues/5280): Add missing C++20 Modules file extension * [#5251](https://github.com/xmake-io/xmake/issues/5251): Update 7z/curl for windows installer * [#5286](https://github.com/xmake-io/xmake/issues/5286): Improve json to parse hex string * [#5302](https://github.com/xmake-io/xmake/pull/5302): Improve Vala support * [#5335](https://github.com/xmake-io/xmake/pull/5335): Improve `xmake install` and `xpack`, Add `set_prefixdir` api for target * [#5387](https://github.com/xmake-io/xmake/pull/5387): Improve `xmake test` * [#5376](https://github.com/xmake-io/xmake/pull/5376): Improve module objectfiles handling and moduleonly package ### Bugs Fixed * [#5288](https://github.com/xmake-io/xmake/issues/5288): Fix `xmake test` for unity build * [#5270](https://github.com/xmake-io/xmake/issues/5270): Fix pch/include for gcc/clang * [#5276](https://github.com/xmake-io/xmake/issues/5276): Fix find vc6 * [#5259](https://github.com/xmake-io/xmake/issues/5259): Fix the failure of the command line completion function ## v2.9.3 ### New features * [#4637](https://github.com/xmake-io/xmake/issues/4637): Add mix generator for xpack * [#5107](https://github.com/xmake-io/xmake/issues/5107): Add deb generator for xpack * [#5148](https://github.com/xmake-io/xmake/issues/5148): Add on_source in package ### Changes * [#5156](https://github.com/xmake-io/xmake/issues/5156): Improve to install cargo packages for rust ### Bugs fixed * [#5176](https://github.com/xmake-io/xmake/pull/5176): Fix VS toolset v144 ## v2.9.2 ### New features * [#5005](https://github.com/xmake-io/xmake/pull/5005): Show all apis * [#5003](https://github.com/xmake-io/xmake/issues/5003): Add build.fence policy * [#5060](https://github.com/xmake-io/xmake/issues/5060): Support Verilator target build to static library * [#5074](https://github.com/xmake-io/xmake/pull/5074): Add `xrepo download` command to download package source * [#5086](https://github.com/xmake-io/xmake/issues/5986): Add check support for package * [#5103](https://github.com/xmake-io/xmake/pull/5103): Add qt ts files building * [#5104](https://github.com/xmake-io/xmake/pull/5104): Call where in find_program ### Changes * [#5077](https://github.com/xmake-io/xmake/issues/5077): Use x64 host compiler for msvc when building x86 target * [#5109](https://github.com/xmake-io/xmake/issues/5109): Support runpath/rpath for add_rpathdirs * [#5132](https://github.com/xmake-io/xmake/pull/5132): Improve ifort/icc/icx support on windows ### Bugs Fixed * [#5059](https://github.com/xmake-io/xmake/issues/5059): Fix load huge targets stuck * [#5029](https://github.com/xmake-io/xmake/issues/5029): Fix crash on termux ## v2.9.1 ### New features * [#4874](https://github.com/xmake-io/xmake/pull/4874): Add Harmony SDK support * [#4889](https://github.com/xmake-io/xmake/issues/4889): Add signal module to register signal handler in lua * [#4925](https://github.com/xmake-io/xmake/issues/4925): Add native modules support * [#4938](https://github.com/xmake-io/xmake/issues/4938): Support for cppfront/h2 ### Changes * Improve packages to support for clang-cl * [#4893](https://github.com/xmake-io/xmake/issues/4893): Improve rc includes deps * [#4928](https://github.com/xmake-io/xmake/issues/4928): Improve to build and link speed * [#4931](https://github.com/xmake-io/xmake/pull/4931): Update pdcurses * [#4973](https://github.com/xmake-io/xmake/issues/4973): Improve to select script ### Bugs fixed * [#4882](https://github.com/xmake-io/xmake/issues/4882): Fix install deps with --group * [#4877](https://github.com/xmake-io/xmake/issues/4877): Fix compile error for xpack with unity build * [#4887](https://github.com/xmake-io/xmake/issues/4887): Fix object deps ## v2.8.9 ### New features * [#4843](https://github.com/xmake-io/xmake/issues/4843): Endianness/Byte-order detection on build machine ### Changes * [#4798](https://github.com/xmake-io/xmake/issues/4798): Improve wasi sdk detect * [#4772](https://github.com/xmake-io/xmake/issues/4772): Improve tools.cmake to support vs2022 preview (v144) * [#4813](https://github.com/xmake-io/xmake/issues/4813): Add gb2312 encoding * [#4864](https://github.com/xmake-io/xmake/issues/4864): Improve to extract symbols for gdb * [#4831](https://github.com/xmake-io/xmake/issues/4831): Allow target:fileconfig() for headerfiles * [#4846](https://github.com/xmake-io/xmake/issues/4846): Improve to show progress ### Bugs Fixed * Fix select_script match pattern * [#4763](https://github.com/xmake-io/xmake/issues/4763): Fix {force = true} * [#4807](https://github.com/xmake-io/xmake/issues/4807): Fix nimble::find_package * [#4857](https://github.com/xmake-io/xmake/issues/4857): Fix parse basic options ## v2.8.8 ### Changes * Add `package:check_sizeof()` ### Bugs Fixed * [#4774](https://github.com/xmake-io/xmake/issues/4774): Fix android symbol strip * [#4769](https://github.com/xmake-io/xmake/issues/4769): Fix cross toolchain and format * [#4776](https://github.com/xmake-io/xmake/issues/4776): Fix soname for linux * [#4638](https://github.com/xmake-io/xmake/issues/4638): Fix vsxmake with --menu config ## v2.8.7 ### New features * [#4544](https://github.com/xmake-io/xmake/issues/4544): Support to wait process timeout for `xmake test` * [#4606](https://github.com/xmake-io/xmake/pull/4606): Add `add_versionfiles` api in package * [#4709](https://github.com/xmake-io/xmake/issues/4709): Add cosmocc toolchain support * [#4715](https://github.com/xmake-io/xmake/issues/4715): Add is_cross() api in description scope * [#4747](https://github.com/xmake-io/xmake/issues/4747): Add `build.always_update_configfiles` policy ### Changes * [#4575](https://github.com/xmake-io/xmake/issues/4575): Check invalid scope name * Add more loong64 support * Improve dlang/dmd support for frameworks * [#4571](https://github.com/xmake-io/xmake/issues/4571): Improve `xmake test` output * [#4609](https://github.com/xmake-io/xmake/issues/4609): Improve to detect vs build tool envirnoments * [#4614](https://github.com/xmake-io/xmake/issues/4614): Support android ndk 26b * [#4473](https://github.com/xmake-io/xmake/issues/4473): Enable warning output by default * [#4477](https://github.com/xmake-io/xmake/issues/4477): Improve runtimes to support libc++/libstdc++ * [#4657](https://github.com/xmake-io/xmake/issues/4657): Improve to select script pattern * [#4673](https://github.com/xmake-io/xmake/pull/4673): Refactor modules support * [#4746](https://github.com/xmake-io/xmake/pull/4746): Add native modules support for cmake generator ### Bugs Fixed * [#4596](https://github.com/xmake-io/xmake/issues/4596): Fix remote build cache * [#4689](https://github.com/xmake-io/xmake/issues/4689): Fix deps inherit ## v2.8.6 ### New features * Add `network.mode` policy * [#1433](https://github.com/xmake-io/xmake/issues/1433): Add `xmake pack` command to generate NSIS/zip/tar.gz/rpm/srpm/runself packages like cmake/cpack * [#4435](https://github.com/xmake-io/xmake/issues/4435): Support batchsize for UnityBuild in Group Mode * [#4485](https://github.com/xmake-io/xmake/pull/4485): Support package.install_locally * Support NetBSD ### Changes * [#4484](https://github.com/xmake-io/xmake/pull/4484): Improve swig rule * Improve Haiku support ### Bugs fixed * [#4372](https://github.com/xmake-io/xmake/issues/4372): Fix protobuf rules * [#4439](https://github.com/xmake-io/xmake/issues/4439): Fix asn1c rules ## v2.8.5 ### New features * [#1452](https://github.com/xmake-io/xmake/issues/1452): Improve link mechanism and order * [#1438](https://github.com/xmake-io/xmake/issues/1438): Support code amalgamation * [#3381](https://github.com/xmake-io/xmake/issues/3381): Add `xmake test` support * [#4276](https://github.com/xmake-io/xmake/issues/4276): Support custom scope api * [#4286](https://github.com/xmake-io/xmake/pull/4286): Add Apple XROS support * [#4345](https://github.com/xmake-io/xmake/issues/4345): Support check sizeof * [#4369](https://github.com/xmake-io/xmake/pull/4369): Add windows.manifest.uac policy ### Changes * [#4284](https://github.com/xmake-io/xmake/issues/4284): Improve builtin includes ### Bugs fixed * [#4256](https://github.com/xmake-io/xmake/issues/4256): Fix intellisense for vsxmake/c++modules ## v2.8.3 ### New features * [#4122](https://github.com/xmake-io/xmake/issues/4122): Support Lua Debugger (EmmyLua) * [#4132](https://github.com/xmake-io/xmake/pull/4132): Support cppfront * [#4147](https://github.com/xmake-io/xmake/issues/4147): Add hlsl2spv rule * [#4226](https://github.com/xmake-io/xmake/issues/4226): Support sanitizers for package and policy * Add lib.lua.package module * Add `run.autobuild` policy * Add global policies `xmake g --policies=` ### Changes * [#4119](https://github.com/xmake-io/xmake/issues/4119): Improve to support emcc toolchain and emscripten package * [#4154](https://github.com/xmake-io/xmake/issues/4154): Add `xmake -r --shallow target` to rebuild target without deps * Add global ccache storage directory * [#4137](https://github.com/xmake-io/xmake/issues/4137): Support Qt6 for Wasm * [#4173](https://github.com/xmake-io/xmake/issues/4173): Add recheck argument to on_config * [#4200](https://github.com/xmake-io/xmake/pull/4200): Improve remote build to support debugging xmake source code. * [#4209](https://github.com/xmake-io/xmake/issues/4209): Add extra and pedantic warnings ### Bugs fixed * [#4110](https://github.com/xmake-io/xmake/issues/4110): Fix extrafiles * [#4115](https://github.com/xmake-io/xmake/issues/4115): Fix compile_commands generator for clangd * [#4199](https://github.com/xmake-io/xmake/pull/4199): Fix compile_commands generator for c++ modules * Fix os.mv fail on window * [#4214](https://github.com/xmake-io/xmake/issues/4214): Fix rust workspace build error ## v2.8.2 ### New features * [#4002](https://github.com/xmake-io/xmake/issues/4002): Add soname and version support * [#1613](https://github.com/xmake-io/xmake/issues/1613): Add avx512 and sse4.2 for add_vectorexts * [#2471](https://github.com/xmake-io/xmake/issues/2471): Add set_encodings to set source/target encodings * [#4071](https://github.com/xmake-io/xmake/pull/4071): Support the stm8 assembler on the sdcc toolchain. * [#4101](https://github.com/xmake-io/xmake/issues/4101): Add force includes for c/c++ * [#2384](https://github.com/xmake-io/xmake/issues/2384): Add extrafiles for vs/vsxmake generator ### Changes * [#3960](https://github.com/xmake-io/xmake/issues/3960): Improve msys2/crt64 support * [#4032](https://github.com/xmake-io/xmake/pull/4032): Remove some old deprecated apis * Improve to upgrade vcproj files in tools.msbuild * Support add_requires("xmake::xxx") package * [#4049](https://github.com/xmake-io/xmake/issues/4049): Improve rust to support cross-compilation * Improve clang modules support ### Bugs fixed * Fix exit all child processes on macOS/Linux ## v2.8.1 ### New features * [#3821](https://github.com/xmake-io/xmake/pull/3821): Add longpath option for windows installer * [#3828](https://github.com/xmake-io/xmake/pull/3828): Add support for zypper package manager * [#3871](https://github.com/xmake-io/xmake/issues/3871): Improve tools.msbuild to support for upgrading vsproj * [#3148](https://github.com/xmake-io/xmake/issues/3148): Support grpc for protobuf * [#3889](https://github.com/xmake-io/xmake/issues/3889): Support to add library path for add_links * [#3912](https://github.com/orgs/xmake-io/issues/3912): Add set_pmxxheader to support objc precompiled header * add_links support library file path ### Changes * [#3752](https://github.com/xmake-io/xmake/issues/3752): Improve os.getenvs for windows * [#3371](https://github.com/xmake-io/xmake/issues/3371): Improve tools.cmake to support ninja generator for wasm * [#3777](https://github.com/xmake-io/xmake/issues/3777): Improve to find package from pkg-config * [#3815](https://github.com/xmake-io/xmake/pull/3815): Improve tools.xmake to pass toolchains for windows * [#3857](https://github.com/xmake-io/xmake/issues/3857): Improve to generate compile_commands.json * [#3892](https://github.com/xmake-io/xmake/issues/3892): Improve to search packages from description * [#3916](https://github.com/xmake-io/xmake/issues/3916): Improve to build swift program, support for multiple modules * Update lua runtime to 5.4.6 ### Bugs fixed * [#3755](https://github.com/xmake-io/xmake/pull/3755): Fix find_tool from xmake/packages * [#3787](https://github.com/xmake-io/xmake/issues/3787): Fix packages from conan 2.x * [#3839](https://github.com/orgs/xmake-io/discussions/3839): Fix vs_runtime for conan 2.x ## v2.7.9 ### New features * [#3613](https://github.com/xmake-io/xmake/issues/3613): Add `wasm.preloadfiles` configuration for wasm * [#3703](https://github.com/xmake-io/xmake/pull/3703): Support for conan >=2.0.5 ### Changes * [#3669](https://github.com/xmake-io/xmake/issues/3669): Improve cmake generator to support add_cxflags with the given tool * [#3679](https://github.com/xmake-io/xmake/issues/3679): Improve `xrepo clean` * [#3662](https://github.com/xmake-io/xmake/issues/3662): Improve cmake/make generator for lex/yacc project * [#3697](https://github.com/xmake-io/xmake/issues/3662): Improve trybuild/cmake * [#3730](https://github.com/xmake-io/xmake/issues/3730): Improve c++modules package installation ### Bugs fixed * [#3596](https://github.com/xmake-io/xmake/issues/3596): Fix check_cxxfuncs and check_cxxsnippets * [#3603](https://github.com/xmake-io/xmake/issues/3603): Fix `xmake update` * [#3614](https://github.com/xmake-io/xmake/issues/3614): Fix qt envirnoment when running target * [#3628](https://github.com/xmake-io/xmake/issues/3628): Fix msys2/mingw setenv and os.exec issue * Fix setenv for msys/mingw ## v2.7.8 ### New features * [#3518](https://github.com/xmake-io/xmake/issues/3518): Profile compile and link performance * [#3522](https://github.com/xmake-io/xmake/issues/3522): Add has_cflags, has_xxx for target * [#3537](https://github.com/xmake-io/xmake/issues/3537): Add --fix for clang.tidy checker ### Changes * [#3433](https://github.com/xmake-io/xmake/issues/3433): Improve to build Qt project on msys2/mingw64 and wasm * [#3419](https://github.com/xmake-io/xmake/issues/3419): Support fish shell envirnoment * [#3455](https://github.com/xmake-io/xmake/issues/3455): Dlang incremental build support * [#3498](https://github.com/xmake-io/xmake/issues/3498): Improve to bind package virtual envirnoments * [#3504](https://github.com/xmake-io/xmake/pull/3504): Add swig java support * [#3508](https://github.com/xmake-io/xmake/issues/3508): Improve trybuild/cmake to support for switching toolchain * disable build cache for msvc, because msvc's preprocessor is too slow. ### Bugs fixed * [#3436](https://github.com/xmake-io/xmake/issues/3436): Fix complete and menuconf * [#3463](https://github.com/xmake-io/xmake/issues/3463): Fix c++modules cache issue * [#3545](https://github.com/xmake-io/xmake/issues/3545): Fix parsedeps for armcc ## v2.7.7 ### New features * Add Haiku support * [#3326](https://github.com/xmake-io/xmake/issues/3326): Add `xmake check` to check project code (clang-tidy) and configuration * [#3332](https://github.com/xmake-io/xmake/pull/3332): add custom http headers when downloading packages ### Changes * [#3318](https://github.com/xmake-io/xmake/pull/3318): Improve dlang toolchains * [#2591](https://github.com/xmake-io/xmake/issues/2591): Improve target analysis * [#3342](https://github.com/xmake-io/xmake/issues/3342): Improve to configure working and build directories * [#3373](https://github.com/xmake-io/xmake/issues/3373): Improve std modules support for clang-17 * Improve to strip/optimization for dmd/ldc2 ### Bugs fixed * [#3317](https://github.com/xmake-io/xmake/pull/3317): Fix languages for qt project. * [#3321](https://github.com/xmake-io/xmake/issues/3321): Fix dependfile when generating configiles * [#3296](https://github.com/xmake-io/xmake/issues/3296): Fix build error on macOS arm64 ## v2.7.6 ### New features * [#3228](https://github.com/xmake-io/xmake/pull/3228): Add support of importing modules from packages * [#3257](https://github.com/xmake-io/xmake/issues/3257): Add support for iverilog and verilator * Support for xp and vc6.0 * [#3214](https://github.com/xmake-io/xmake/pull/3214): Completion on xrepo install packages ### Changes * [#3255](https://github.com/xmake-io/xmake/pull/3225): Improve clang libc++ module support * Support for compiling xmake using mingw * Improve compatibility issues with xmake running on win xp * Add pure lua json implementation instead of lua-cjson if the external dependencies are enabled ### Bugs fixed * [#3229](https://github.com/xmake-io/xmake/issues/3229): Fix find rc.exe for vs2015 * [#3271](https://github.com/xmake-io/xmake/issues/3271): Fix macro defines with spaces * [#3273](https://github.com/xmake-io/xmake/issues/3273): Fix nim link error * [#3286](https://github.com/xmake-io/xmake/issues/3286): Fix compile_commands for clangd ## v2.7.5 ### New features * [#3201](https://github.com/xmake-io/xmake/pull/3201): Add completer and xrepo complete * [#3233](https://github.com/xmake-io/xmake/issues/3233): Add MASM32 sdk toolchain ### Changes * [#3216](https://github.com/xmake-io/xmake/pull/3216): Add intel one api toolkits detection * [#3020](https://github.com/xmake-io/xmake/issues/3020): Add `--lsp=clangd` to improve to generate compile_commands.json * [#3215](https://github.com/xmake-io/xmake/issues/3215): Add includedirs and defines to c51 * [#3251](https://github.com/xmake-io/xmake/issues/3251): Improve to build zig and c program ### Bugs fixed * [#3203](https://github.com/xmake-io/xmake/issues/3203): Fix compile_commands * [#3222](https://github.com/xmake-io/xmake/issues/3222): Fix precompiled headers in ObjC * [#3240](https://github.com/xmake-io/xmake/pull/3240): Fix target run with single arguments * [#3238](https://github.com/xmake-io/xmake/pull/3238): Fix clang module mapper ## v2.7.4 ### New features * [#3049](https://github.com/xmake-io/xmake/pull/3049): Add `xmake format` plugin * Add `plugin.compile_commands.autoupdate` rule * [#3172](https://github.com/xmake-io/xmake/pull/3172): Add xmake.sh * [#3168](https://github.com/xmake-io/xmake/pull/3168): add support of C++23 standard modules on msvc ### Changes * [#3056](https://github.com/xmake-io/xmake/issues/3056): Improve zig support * [#3060](https://github.com/xmake-io/xmake/issues/3060): Improve to detect msys2 for clang toolchains envirnoment * [#3071](https://github.com/xmake-io/xmake/issues/3071): Support rc for llvm/clang toolchain * [#3122](https://github.com/xmake-io/xmake/pull/3122): Generate dependencies of preprocessed modules to avoid importing #ifdef import * [#3125](https://github.com/xmake-io/xmake/pull/3125): Compile private C++20 modules * [#3133](https://github.com/xmake-io/xmake/pull/3133): Add support of internal partitions * [#3146](https://github.com/xmake-io/xmake/issues/3146): Add default components for packages * [#3192](https://github.com/xmake-io/xmake/issues/3192): JSON output for auto complete ### Bugs fixed * Fix requires-lock bug * [#3065](https://github.com/xmake-io/xmake/issues/3065): Fix missing package dependences * [#3082](https://github.com/xmake-io/xmake/issues/3082): Fix build.ninja generator * [#3092](https://github.com/xmake-io/xmake/issues/3092): Fix xrepo add-repo error handing * [#3013](https://github.com/xmake-io/xmake/issues/3013): Fix and support windows UNC path * [#2902](https://github.com/xmake-io/xmake/issues/2902): Fix file not access by another process occupied * [#3074](https://github.com/xmake-io/xmake/issues/3074): Fix CMakelists generator * [#3141](https://github.com/xmake-io/xmake/pull/3141): Fix import order on GCC and force it on clang and msvc #3141 * Fix tools/xmake package build directory * [#3159](https://github.com/xmake-io/xmake/issues/3159): Fix compile_commands for CLion ## v2.7.3 ### New features * A new optional configuration syntax. It is LSP friendly, automatically calls target_end() to achieve scope isolation. * [#2944](https://github.com/xmake-io/xmake/issues/2944): Add `gnu-rm.binary` and `gnu-rm.static` rules and tests for embed project * [#2636](https://github.com/xmake-io/xmake/issues/2636): Support package components * Support armasm/armasm64 for msvc * [#3023](https://github.com/xmake-io/xmake/pull/3023): Add support for debugging with renderdoc * [#3022](https://github.com/xmake-io/xmake/issues/3022): Add flags for specific compilers and linkers * [#3025](https://github.com/xmake-io/xmake/pull/3025): C++ exception enabled/disabled switch method * [#3017](https://github.com/xmake-io/xmake/pull/3017): Support ispc compiler ### Changes * [#2925](https://github.com/xmake-io/xmake/issues/2925): Improve doxygen plugin * [#2948](https://github.com/xmake-io/xmake/issues/2948): Support OpenBSD * Add `xmake g --insecure-ssl=y` option to disable ssl certificate when downloading packages * [#2971](https://github.com/xmake-io/xmake/pull/2971): Stabilize vs and vsxmake project generation * [#3000](https://github.com/xmake-io/xmake/issues/3000): Incremental compilation support for modules * [#3016](https://github.com/xmake-io/xmake/pull/3016): Improve clang/msvc to better support std modules ### Bugs fixed * [#2949](https://github.com/xmake-io/xmake/issues/2949): Fix vs group * [#2952](https://github.com/xmake-io/xmake/issues/2952): Fix armlink for long args * [#2954](https://github.com/xmake-io/xmake/issues/2954): Fix c++ module partitions path issue * [#3033](https://github.com/xmake-io/xmake/issues/3033): Detect circular modules dependency ## v2.7.2 ### New features * [#2140](https://github.com/xmake-io/xmake/issues/2140): Support Windows Arm64 * [#2719](https://github.com/xmake-io/xmake/issues/2719): Add `package.librarydeps.strict_compatibility` to strict compatibility for package linkdeps * [#2810](https://github.com/xmake-io/xmake/pull/2810): Support os.execv to run shell script file * [#2817](https://github.com/xmake-io/xmake/pull/2817): Improve rule to support dependence order * [#2824](https://github.com/xmake-io/xmake/pull/2824): Pass cross-file to meson.install and trybuild * [#2856](https://github.com/xmake-io/xmake/pull/2856): Improve to debug package using the debug source directory * [#2859](https://github.com/xmake-io/xmake/issues/2859): Improve trybuild to build 3rd source library using xmake-repo scripts * [#2879](https://github.com/xmake-io/xmake/issues/2879): Support for dynamic creation and injection of rules and targets in script scope * [#2374](https://github.com/xmake-io/xmake/issues/2374): Allow xmake package to embed rules and scripts * Add clang-cl toolchain ### Changes * [#2745](https://github.com/xmake-io/xmake/pull/2745): Improve os.cp to support symlink * [#2773](https://github.com/xmake-io/xmake/pull/2773): Improve vcpkg packages to support freebsd * [#2778](https://github.com/xmake-io/xmake/pull/2778): Improve Improve xrepo.env for target * [#2783](https://github.com/xmake-io/xmake/issues/2783): Add digest algorithm option for wdk signtool * [#2787](https://github.com/xmake-io/xmake/pull/2787): Improve json to support empty array * [#2782](https://github.com/xmake-io/xmake/pull/2782): Improve to find matlab and runtime * [#2793](https://github.com/xmake-io/xmake/issues/2793): Improve mconfdialog * [#2804](https://github.com/xmake-io/xmake/issues/2804): Support macOS arm64/x86_64 cross-compilation for installing packages * [#2809](https://github.com/xmake-io/xmake/issues/2809): Improve cl optimization option * Improve trybuild for meson/cmake/autoconf * [#2846](https://github.com/xmake-io/xmake/discussions/2846): Improve to generate config files * [#2866](https://github.com/xmake-io/xmake/issues/2866): Better control over the order of execution of rules ### Bugs fixed * [#2740](https://github.com/xmake-io/xmake/issues/2740): Fix build c++ modules stuck and slower for msvc * [#2875](https://github.com/xmake-io/xmake/issues/2875): Fix build linux driver error * [#2885](https://github.com/xmake-io/xmake/issues/2885): Fix pch not found with msvc/ccache ## v2.7.1 ### New features * [#2555](https://github.com/xmake-io/xmake/issues/2555): Add fwatcher module and `xmake watch` plugin command * Add `xmake service --pull 'build/**' outputdir` to pull the given files in remote server * [#2641](https://github.com/xmake-io/xmake/pull/2641): Improve C++20 modules, support headerunits and project generators * [#2679](https://github.com/xmake-io/xmake/issues/2679): Support Mac Catalyst ### Changes * [#2576](https://github.com/xmake-io/xmake/issues/2576): More flexible package fetching from cmake * [#2577](https://github.com/xmake-io/xmake/issues/2577): Improve add_headerfiles(), add `{install = false}` support * [#2603](https://github.com/xmake-io/xmake/issues/2603): Disable `-fdirectives-only` for ccache by default * [#2580](https://github.com/xmake-io/xmake/issues/2580): Set stdout to line buffering * [#2571](https://github.com/xmake-io/xmake/issues/2571): Improve task scheduling for parallel and distributed compilation based on memory/cpu usage * [#2410](https://github.com/xmake-io/xmake/issues/2410): Improve cmakelists generator * [#2690](https://github.com/xmake-io/xmake/issues/2690): Improve to pass toolchains to packages * [#2686](https://github.com/xmake-io/xmake/issues/2686): Support for incremental compilation and parse header file deps for keil/armcc/armclang * [#2562](https://github.com/xmake-io/xmake/issues/2562): Improve include deps for rc.exe * Improve the default parallel building jobs number ### Bugs fixed * [#2614](https://github.com/xmake-io/xmake/issues/2614): Fix building submodules2 tests for msvc * [#2620](https://github.com/xmake-io/xmake/issues/2620): Fix build cache for incremental compilation * [#2177](https://github.com/xmake-io/xmake/issues/2177): Fix python.library segmentation fault for macosx * [#2708](https://github.com/xmake-io/xmake/issues/2708): Fix link error for mode.coverage rule * Fix rpath for macos/iphoneos frameworks and application ## v2.6.9 ### New features * [#2474](https://github.com/xmake-io/xmake/issues/2474): Add icx and dpcpp toolchains * [#2523](https://github.com/xmake-io/xmake/issues/2523): Improve LTO support * [#2527](https://github.com/xmake-io/xmake/issues/2527): Add set_runargs api ### Changes * Improve tools.cmake to support wasm * [#2491](https://github.com/xmake-io/xmake/issues/2491): Fallback to local compiler/cache from remote if server is unreachable * [#2514](https://github.com/xmake-io/xmake/issues/2514): Disable Unity Build for project generator * [#2473](https://github.com/xmake-io/xmake/issues/2473): Improve apt::find_package to find it from pc files * [#2512](https://github.com/xmake-io/xmake/issues/2512): Improve remote service to support timeout configuration ### Bugs fixed * [#2488](https://github.com/xmake-io/xmake/issues/2488): Fix remote compilation from windows to linux * [#2504](https://github.com/xmake-io/xmake/issues/2504): Fix remote build bug on msys2/cygwin * [#2525](https://github.com/xmake-io/xmake/issues/2525): Fix install package deps and stuck * [#2557](https://github.com/xmake-io/xmake/issues/2557): Fix cmake.find_package links bug * Fix cache-induced path conflicts in preprocessed files ## v2.6.8 ### New features * [#2447](https://github.com/xmake-io/xmake/pull/2447): Add qt.qmlplugin rule and support of qmltypesregistrar * [#2446](https://github.com/xmake-io/xmake/issues/2446): Support target group for `xmake install` * [#2469](https://github.com/xmake-io/xmake/issues/2469): Generate vcpkg-configuration.json ### Changes * Add `preprocessor.linemarkers` policy to disable linemarkers to speed up ccache/distcc * [#2389](https://github.com/xmake-io/xmake/issues/2389): Improve `xmake run` to parallel running of targets * [#2417](https://github.com/xmake-io/xmake/issues/2417): Switch the default value of option/showmenu * [#2440](https://github.com/xmake-io/xmake/pull/2440): Improve package installation error messages * [#2438](https://github.com/xmake-io/xmake/pull/2438): Make sure the solution and project file unchanged by sorting those tables * [#2434](https://github.com/xmake-io/xmake/issues/2434): Improve plugins manager, allow to handle multiples plugin repositories * [#2421](https://github.com/xmake-io/xmake/issues/2421): Improve config option menu * [#2425](https://github.com/xmake-io/xmake/issues/2425): Add `preprocessor.gcc.directives_only` policy * [#2455](https://github.com/xmake-io/xmake/issues/2455): Improve optimize options for emcc * [#2467](https://github.com/xmake-io/xmake/issues/2467): Add compile fallback for msvc/ccache * [#2452](https://github.com/xmake-io/xmake/issues/2452): Add build.warning policy ### Bugs Fixed * [#2435](https://github.com/xmake-io/xmake/pull/2435): fix the search bug when the package name has an extension name. * [#2445](https://github.com/xmake-io/xmake/issues/2445): Fix ccache bug for msvc * [#2452](https://github.com/xmake-io/xmake/issues/2452): Fix warnings output for ccache ## v2.6.7 ### New features * [#2318](https://github.com/xmake-io/xmake/issues/2318): Add `xmake f --policies=` config argument to modify project policies ### Changes * fallback to source code build if the precompiled package is error * [#2387](https://github.com/xmake-io/xmake/issues/2387): Improve pkgconfig and find_package * Add `build.ccache` policy ### Bugs fixed * [#2382](https://github.com/xmake-io/xmake/issues/2382): Fix headeronly package configs * [#2388](https://github.com/xmake-io/xmake/issues/2388): Fix path bug * [#2385](https://github.com/xmake-io/xmake/issues/2385): Fix cmake/find_package * [#2395](https://github.com/xmake-io/xmake/issues/2395): Fix c++modules * Fix find_qt bug ## v2.6.6 ### New features * [#2327](https://github.com/xmake-io/xmake/issues/2327): Support nvc/nvc++/nvfortran in nvidia-hpc-sdk * Add path instance interfaces * [#2344](https://github.com/xmake-io/xmake/pull/2344): Add lz4 compress module * [#2349](https://github.com/xmake-io/xmake/pull/2349): Add keil/c51 project support * [#274](https://github.com/xmake-io/xmake/issues/274): Distributed compilation support * Use builtin local cache instead of ccache ### Changes * [#2309](https://github.com/xmake-io/xmake/issues/2309): Support user authorization for remote compilation * Improve remote compilation to support lz4 compression ### Bugs fixed * Fix lua stack when select package versions ## v2.6.5 ### New features * [#2138](https://github.com/xmake-io/xmake/issues/2138): Support template package * [#2185](https://github.com/xmake-io/xmake/issues/2185): Add `--appledev=simulator` to improve apple simulator support * [#2227](https://github.com/xmake-io/xmake/issues/2227): Improve cargo package with Cargo.toml file * Improve `add_requires` to support git commit as version * [#622](https://github.com/xmake-io/xmake/issues/622): Support remote compilation * [#2282](https://github.com/xmake-io/xmake/issues/2282): Add `add_filegroups` to support file group for vs/vsxmake/cmake generator ### Changes * [#2137](https://github.com/xmake-io/xmake/pull/2137): Improve path module * Reduce 50% xmake binary size on macOS * Improve tools/autoconf,cmake to support toolchain switching. * [#2221](https://github.com/xmake-io/xmake/pull/2221): Improve registry api to support unicode * [#2225](https://github.com/xmake-io/xmake/issues/2225): Support to parse import dependencies for protobuf * [#2265](https://github.com/xmake-io/xmake/issues/2265): Sort CMakeLists.txt * Speed up `os.files` ### Bugs fixed * [#2233](https://github.com/xmake-io/xmake/issues/2233): Fix c++ modules deps ## v2.6.4 ### New features * [#2011](https://github.com/xmake-io/xmake/issues/2011): Support to inherit base package * Support to build and run xmake on sparc, alpha, powerpc, s390x and sh4 * Add on_download for package() * [#2021](https://github.com/xmake-io/xmake/issues/2021): Support Swift for linux and windows * [#2024](https://github.com/xmake-io/xmake/issues/2024): Add asn1c support * [#2031](https://github.com/xmake-io/xmake/issues/2031): Support linker scripts and version scripts for add_files * [#2033](https://github.com/xmake-io/xmake/issues/2033): Catch ctrl-c to get current backtrace for debugging stuck * [#2059](https://github.com/xmake-io/xmake/pull/2059): Add `xmake update --integrate` to integrate for shell * [#2070](https://github.com/xmake-io/xmake/issues/2070): Add built-in xrepo environments * [#2117](https://github.com/xmake-io/xmake/pull/2117): Support to pass toolchains to package for other platforms * [#2121](https://github.com/xmake-io/xmake/issues/2121): Support to export the given symbols list ### Changes * [#2036](https://github.com/xmake-io/xmake/issues/2036): Improve xrepo to install packages from configuration file, e.g. `xrepo install xxx.lua` * [#2039](https://github.com/xmake-io/xmake/issues/2039): Improve filter directory for vs generator * [#2025](https://github.com/xmake-io/xmake/issues/2025): Support phony and headeronly target for vs generator * Improve to find vstudio and codesign speed * [#2077](https://github.com/xmake-io/xmake/issues/2077): Improve vs project generator to support cuda ### Bugs fixed * [#2005](https://github.com/xmake-io/xmake/issues/2005): Fix path.extension * [#2008](https://github.com/xmake-io/xmake/issues/2008): Fix windows manifest * [#2016](https://github.com/xmake-io/xmake/issues/2016): Fix object filename confict for vs project generator ## v2.6.3 ### New features * [#1298](https://github.com/xmake-io/xmake/issues/1928): Support vcpkg manifest mode and select version for package/install * [#1896](https://github.com/xmake-io/xmake/issues/1896): Add `python.library` rule to build pybind modules * [#1939](https://github.com/xmake-io/xmake/issues/1939): Add `remove_files`, `remove_headerfiles` and mark `del_files` as deprecated * Made on_config as the official api for rule/target * Add riscv32/64 support * [#1970](https://github.com/xmake-io/xmake/issues/1970): Add CMake wrapper for Xrepo C and C++ package manager. * Add builtin github mirror pac files, `xmake g --proxy_pac=github_mirror.lua` ### Changes * [#1923](https://github.com/xmake-io/xmake/issues/1923): Improve to build linux driver, support set custom linux-headers path * [#1962](https://github.com/xmake-io/xmake/issues/1962): Improve armclang toolchain to support to build asm * [#1959](https://github.com/xmake-io/xmake/pull/1959): Improve vstudio project generator * [#1969](https://github.com/xmake-io/xmake/issues/1969): Add default option description ### Bugs fixed * [#1875](https://github.com/xmake-io/xmake/issues/1875): Fix deploy android qt apk issue * [#1973](https://github.com/xmake-io/xmake/issues/1973): Fix merge static archive ## v2.6.2 ### New features * [#1902](https://github.com/xmake-io/xmake/issues/1902): Support to build linux kernel driver modules * [#1913](https://github.com/xmake-io/xmake/issues/1913): Build and run targets with given group pattern * [#1982](https://github.com/xmake-io/xmake/pull/1982): Fix build c++20 submodules for clang ### Change * [#1872](https://github.com/xmake-io/xmake/issues/1872): Escape characters for set_configvar * [#1888](https://github.com/xmake-io/xmake/issues/1888): Improve windows installer to avoid remove other files * [#1895](https://github.com/xmake-io/xmake/issues/1895): Improve `plugin.vsxmake.autoupdate` rule * [#1893](https://github.com/xmake-io/xmake/issues/1893): Improve to detect icc and ifort toolchains * [#1905](https://github.com/xmake-io/xmake/pull/1905): Add support of external headers without experimental for msvc * [#1904](https://github.com/xmake-io/xmake/pull/1904): Improve vs201x generator * Add `XMAKE_THEME` envirnoment variable to switch theme * [#1907](https://github.com/xmake-io/xmake/issues/1907): Add `-f/--force` to force to create project in a non-empty directory * [#1917](https://github.com/xmake-io/xmake/pull/1917): Improve to find_package and configurations ### Bugs fixed * [#1885](https://github.com/xmake-io/xmake/issues/1885): Fix package:fetch_linkdeps * [#1903](https://github.com/xmake-io/xmake/issues/1903): Fix package link order ## v2.6.1 ### New features * [#1799](https://github.com/xmake-io/xmake/issues/1799): Support mixed rust & c++ target and cargo dependences * Add `utils.glsl2spv` rules to compile *.vert/*.frag shader files to spirv file and binary c header file ### Changes * Switch to Lua5.4 runtime by default * [#1776](https://github.com/xmake-io/xmake/issues/1776): Improve system::find_package, support to find package from envs * [#1786](https://github.com/xmake-io/xmake/issues/1786): Improve apt:find_package, support to find alias package * [#1819](https://github.com/xmake-io/xmake/issues/1819): Add precompiled header to cmake generator * Improve C++20 module to support std libraries for msvc * [#1792](https://github.com/xmake-io/xmake/issues/1792): Add custom command in vs project generator * [#1835](https://github.com/xmake-io/xmake/issues/1835): Improve MDK program supports and add `set_runtimes("microlib")` * [#1858](https://github.com/xmake-io/xmake/issues/1858): Improve to build c++20 modules with libraries * Add $XMAKE_BINARY_REPO and $XMAKE_MAIN_REPO repositories envs * [#1865](https://github.com/xmake-io/xmake/issues/1865): Improve openmp projects * [#1845](https://github.com/xmake-io/xmake/issues/1845): Install pdb files for static library ### Bugs Fixed * Fix semver to parse build string with zero prefix * [#50](https://github.com/libbpf/libbpf-bootstrap/issues/50): Fix rule and build bpf program errors * [#1610](https://github.com/xmake-io/xmake/issues/1610): Fix `xmake f --menu` not responding in vscode and support ConPTY terminal virtkeys ## v2.5.9 ### New features * [#1736](https://github.com/xmake-io/xmake/issues/1736): Support wasi-sdk toolchain * Support Lua 5.4 runtime * Add gcc-8, gcc-9, gcc-10, gcc-11 toolchains * [#1623](https://github.com/xmake-io/xmake/issues/1632): Support find_package from cmake * [#1747](https://github.com/xmake-io/xmake/issues/1747): Add `set_kind("headeronly")` for target to install files for headeronly library * [#1019](https://github.com/xmake-io/xmake/issues/1019): Support Unity build * [#1438](https://github.com/xmake-io/xmake/issues/1438): Support code amalgamation, `xmake l cli.amalgamate` * [#1765](https://github.com/xmake-io/xmake/issues/1756): Support nim language * [#1762](https://github.com/xmake-io/xmake/issues/1762): Manage and switch the given package envs for `xrepo env` * [#1767](https://github.com/xmake-io/xmake/issues/1767): Support Circle compiler * [#1753](https://github.com/xmake-io/xmake/issues/1753): Support armcc/armclang toolchains for Keil/MDK * [#1774](https://github.com/xmake-io/xmake/issues/1774): Add table.contains api * [#1735](https://github.com/xmake-io/xmake/issues/1735): Add custom command in cmake generator ### Changes * [#1528](https://github.com/xmake-io/xmake/issues/1528): Check c++17/20 features * [#1729](https://github.com/xmake-io/xmake/issues/1729): Improve C++20 modules for clang/gcc/msvc, support inter-module dependency compilation and parallel optimization * [#1779](https://github.com/xmake-io/xmake/issues/1779): Remove builtin `-Gd` for ml.exe/x86 * [#1781](https://github.com/xmake-io/xmake/issues/1781): Improve get.sh installation script to support nixos ## v2.5.8 ### New features * [#388](https://github.com/xmake-io/xmake/issues/388): Pascal Language Support * [#1682](https://github.com/xmake-io/xmake/issues/1682): Add optional lua5.3 backend instead of luajit to provide better compatibility * [#1622](https://github.com/xmake-io/xmake/issues/1622): Support Swig * [#1714](https://github.com/xmake-io/xmake/issues/1714): Support build local embed cmake projects * [#1715](https://github.com/xmake-io/xmake/issues/1715): Support to detect compiler language standards as features and add `check_macros` * Support Loongarch ### Change * [#1618](https://github.com/xmake-io/xmake/issues/1618): Improve vala to support to generate libraries and bindings * Improve Qt rules to support Qt 4.x * Improve `set_symbols("debug")` to generate pdb file for clang on windows * [#1638](https://github.com/xmake-io/xmake/issues/1638): Improve to merge static library * Improve on_load/after_load to support to add target deps dynamically * [#1675](https://github.com/xmake-io/xmake/pull/1675): Rename dynamic and import library suffix for mingw * [#1694](https://github.com/xmake-io/xmake/issues/1694): Support to define a variable without quotes for configuration files * Support Android NDK r23 * Add `c++latest` and `clatest` for `set_languages` * [#1720](https://github.com/xmake-io/xmake/issues/1720): Add `save_scope` and `restore_scope` to fix `check_xxx` apis * [#1726](https://github.com/xmake-io/xmake/issues/1726): Improve compile_commands generator to support nvcc ### Bugs fixed * [#1671](https://github.com/xmake-io/xmake/issues/1671): Fix incorrect absolute path after installing precompiled packages * [#1689](https://github.com/xmake-io/xmake/issues/1689): Fix unicode chars bug for vsxmake ## v2.5.7 ### New features * [#1534](https://github.com/xmake-io/xmake/issues/1534): Support to compile Vala lanuage project * [#1544](https://github.com/xmake-io/xmake/issues/1544): Add utils.bin2c rule to generate header from binary file * [#1547](https://github.com/xmake-io/xmake/issues/1547): Support to run and get output of c/c++ snippets in option * [#1567](https://github.com/xmake-io/xmake/issues/1567): Package "lock file" support to freeze dependencies * [#1597](https://github.com/xmake-io/xmake/issues/1597): Support to compile *.metal files to generate *.metalib and improve xcode.application rule ### Change * [#1540](https://github.com/xmake-io/xmake/issues/1540): Better support for compilation of automatically generated code * [#1578](https://github.com/xmake-io/xmake/issues/1578): Improve add_repositories to support relative path better * [#1582](https://github.com/xmake-io/xmake/issues/1582): Improve installation and os.cp to reserve symlink ### Bugs fixed * [#1531](https://github.com/xmake-io/xmake/issues/1531): Fix error info when loading targets failed ## v2.5.6 ### New features * [#1483](https://github.com/xmake-io/xmake/issues/1483): Add `os.joinenvs()` and improve package tools envirnoments * [#1523](https://github.com/xmake-io/xmake/issues/1523): Add `set_allowedmodes`, `set_allowedplats` and `set_allowedarchs` * [#1523](https://github.com/xmake-io/xmake/issues/1523): Add `set_defaultmode`, `set_defaultplat` and `set_defaultarch` ### Change * Improve vs/vsxmake project generator to support vs2022 * [#1513](https://github.com/xmake-io/xmake/issues/1513): Improve precompiled binary package compatibility on windows/msvc * Improve to find vcpkg root directory on windows * Improve to support Qt6 ### Bugs fixed * [#489](https://github.com/xmake-io/xmake-repo/pull/489): Fix run os.execv with too long envirnoment value on windows ## v2.5.5 ### New features * [#1421](https://github.com/xmake-io/xmake/issues/1421): Add prefix, suffix and extension options for target names * [#1422](https://github.com/xmake-io/xmake/issues/1422): Support search packages from vcpkg, conan * [#1424](https://github.com/xmake-io/xmake/issues/1424): Set binary as default target kind * [#1140](https://github.com/xmake-io/xmake/issues/1140): Add a way to ask xmake to try to download dependencies from a certain package manager * [#1339](https://github.com/xmake-io/xmake/issues/1339): Improve `xmake package` to generate new local/remote packages * Add `appletvos` platform support for AppleTV, `xmake f -p appletvos` * [#1437](https://github.com/xmake-io/xmake/issues/1437): Add headeronly library type for package to ignore `vs_runtime` * [#1351](https://github.com/xmake-io/xmake/issues/1351): Support export/import current configs * [#1454](https://github.com/xmake-io/xmake/issues/1454): Support to download and install precompiled image packages from xmake-mirror ### Change * [#1425](https://github.com/xmake-io/xmake/issues/1425): Improve tools/meson to load msvc envirnoments * [#1442](https://github.com/xmake-io/xmake/issues/1442): Support to clone package resources from git url * [#1389](https://github.com/xmake-io/xmake/issues/1389): Support to add toolchain envs to `xrepo env` * [#1453](https://github.com/xmake-io/xmake/issues/1453): Support to export protobuf includedirs * Support vs2022 ### Bugs fixed * [#1413](https://github.com/xmake-io/xmake/issues/1413): Fix hangs on fetching packages * [#1420](https://github.com/xmake-io/xmake/issues/1420): Fix config and packages cache * [#1445](https://github.com/xmake-io/xmake/issues/1445): Fix WDK driver sign error * [#1465](https://github.com/xmake-io/xmake/issues/1465): Fix missing link directory ## v2.5.4 ### New features * [#1323](https://github.com/xmake-io/xmake/issues/1323): Support find and install package from `apt`, `add_requires("apt::zlib1g-dev")` * [#1337](https://github.com/xmake-io/xmake/issues/1337): Add environment vars to change package directories * [#1338](https://github.com/xmake-io/xmake/issues/1338): Support import and export installed packages * [#1087](https://github.com/xmake-io/xmake/issues/1087): Add `xrepo env shell` and support load envs from `add_requires/xmake.lua` * [#1313](https://github.com/xmake-io/xmake/issues/1313): Support private package for `add_requires/add_deps` * [#1358](https://github.com/xmake-io/xmake/issues/1358): Support to set mirror url to speedup download package * [#1369](https://github.com/xmake-io/xmake/pull/1369): Support arm/arm64 packages for vcpkg, thanks @fallending * [#1405](https://github.com/xmake-io/xmake/pull/1405): Add portage package manager support, thanks @Phate6660 ### Change * Improve `find_package` and add `package:find_package` for xmake package * Remove deprecated `set_config_h` and `set_config_h_prefix` apis * [#1343](https://github.com/xmake-io/xmake/issues/1343): Improve to search local package files * [#1347](https://github.com/xmake-io/xmake/issues/1347): Improve to vs_runtime configs for binary package * [#1353](https://github.com/xmake-io/xmake/issues/1353): Improve del_files() to speedup matching files * [#1349](https://github.com/xmake-io/xmake/issues/1349): Improve `xrepo env shell` to support powershell ### Bugs fixed * [#1380](https://github.com/xmake-io/xmake/issues/1380): Fix add packages errors * [#1381](https://github.com/xmake-io/xmake/issues/1381): Fix add local git source for package * [#1391](https://github.com/xmake-io/xmake/issues/1391): Fix cuda/nvcc toolchain ### v2.5.3 ### New features * [#1259](https://github.com/xmake-io/xmake/issues/1259): Support `add_files("*.def")` to export symbols for windows/dll * [#1267](https://github.com/xmake-io/xmake/issues/1267): add `find_package("nvtx")` * [#1274](https://github.com/xmake-io/xmake/issues/1274): add `platform.linux.bpf` rule to build linux/bpf program * [#1280](https://github.com/xmake-io/xmake/issues/1280): Support fetchonly package to improve find_package * Support to fetch remote ndk toolchain package * [#1268](https://github.com/xmake-io/xmake/issues/1268): Add `utils.install.pkgconfig_importfiles` rule to install `*.pc` import file * [#1268](https://github.com/xmake-io/xmake/issues/1268): Add `utils.install.cmake_importfiles` rule to install `*.cmake` import files * [#348](https://github.com/xmake-io/xmake-repo/pull/348): Add `platform.longpaths` policy to support git longpaths * [#1314](https://github.com/xmake-io/xmake/issues/1314): Support to install and use conda packages * [#1120](https://github.com/xmake-io/xmake/issues/1120): Add `core.base.cpu` module and improve `os.cpuinfo()` * [#1325](https://github.com/xmake-io/xmake/issues/1325): Add builtin git variables for `add_configfiles` ### Change * [#1275](https://github.com/xmake-io/xmake/issues/1275): Support conditionnal targets for vsxmake plugin * [#1290](https://github.com/xmake-io/xmake/pull/1290): Improve android ndk to support >= r22 * [#1311](https://github.com/xmake-io/xmake/issues/1311): Add packages lib folder to PATH for vsxmake project ### Bugs fixed * [#1266](https://github.com/xmake-io/xmake/issues/1266): Fix relative repo path in `add_repositories` * [#1288](https://github.com/xmake-io/xmake/issues/1288): Fix vsxmake generator with option configs ## v2.5.2 ### New features * [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-766481512): Support `zig cc` and `zig c++` as c/c++ compiler * [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-768193083): Support zig cross-compilation * [#1177](https://github.com/xmake-io/xmake/issues/1177): Improve to detect terminal and color codes * [#1216](https://github.com/xmake-io/xmake/issues/1216): Pass custom configuration scripts to xrepo * Add linuxos builtin module to get linux system information * [#1217](https://github.com/xmake-io/xmake/issues/1217): Support to fetch remote toolchain package when building project * [#1123](https://github.com/xmake-io/xmake/issues/1123): Add `rule("utils.symbols.export_all")` to export all symbols for windows/dll * [#1181](https://github.com/xmake-io/xmake/issues/1181): Add `utils.platform.gnu2mslib(mslib, gnulib)` module api to convert mingw/xxx.dll.a to msvc xxx.lib * [#1246](https://github.com/xmake-io/xmake/issues/1246): Improve rules and generators to support commands list * [#1239](https://github.com/xmake-io/xmake/issues/1239): Add `add_extsources` to improve find external packages * [#1241](https://github.com/xmake-io/xmake/issues/1241): Support add .manifest files for windows program * Support to use `xrepo remove --all` to remove all packages * [#1254](https://github.com/xmake-io/xmake/issues/1254): Support to export packages to parent target ### Change * [#1226](https://github.com/xmake-io/xmake/issues/1226): Add missing qt include directories * [#1183](https://github.com/xmake-io/xmake/issues/1183): Improve c++ lanuages to support Qt6 * [#1237](https://github.com/xmake-io/xmake/issues/1237): Add qt.ui files for vsxmake plugin * Improve vs/vsxmake plugins to support precompiled header and intellisense * [#1090](https://github.com/xmake-io/xmake/issues/1090): Simplify integration of custom code generators * [#1065](https://github.com/xmake-io/xmake/issues/1065): Improve protobuf rule to support compile_commands generators * [#1249](https://github.com/xmake-io/xmake/issues/1249): Improve vs/vsxmake generator to support startproject * [#605](https://github.com/xmake-io/xmake/issues/605): Improve to link orders for add_deps/add_packages * Remove deprecated `add_defines_h_if_ok` and `add_defines_h` apis for option ### Bugs fixed * [#1219](https://github.com/xmake-io/xmake/issues/1219): Fix version check and update * [#1235](https://github.com/xmake-io/xmake/issues/1235): Fix include directories with spaces ## v2.5.1 ### New features * [#1035](https://github.com/xmake-io/xmake/issues/1035): The graphics configuration menu fully supports mouse events, and support scroll bar * [#1098](https://github.com/xmake-io/xmake/issues/1098): Support stdin for os.execv * [#1079](https://github.com/xmake-io/xmake/issues/1079): Add autoupdate plugin rule for vsxmake, `add_rules("plugin.vsxmake.autoupdate")` * Add `xmake f --vs_runtime=MT` and `set_runtimes("MT")` to set vs runtime for targets and packages * [#1032](https://github.com/xmake-io/xmake/issues/1032): Support to enum registry keys and values * [#1026](https://github.com/xmake-io/xmake/issues/1026): Support group for vs/vsxmake project * [#1178](https://github.com/xmake-io/xmake/issues/1178): Add `add_requireconfs()` api to rewrite configs of depend packages * [#1043](https://github.com/xmake-io/xmake/issues/1043): Add `luarocks.module` rule for luarocks-build-xmake * [#1190](https://github.com/xmake-io/xmake/issues/1190): Support for Apple Silicon (macOS ARM) * [#1145](https://github.com/xmake-io/xmake/pull/1145): Support Qt deploy for Windows, thanks @SirLynix ### Change * [#1072](https://github.com/xmake-io/xmake/issues/1072): Fix and improve to parse cl deps * Support utf8 for ui modules and `xmake f --menu` * Improve to support zig on macOS * [#1135](https://github.com/xmake-io/xmake/issues/1135): Improve multi-toolchain and multi-platforms for targets * [#1153](https://github.com/xmake-io/xmake/issues/1153): Improve llvm toolchain to support sysroot on macOS * [#1071](https://github.com/xmake-io/xmake/issues/1071): Improve to generate vs/vsxmake project to support for remote packages * Improve vs/vsxmake project plugin to support global `set_arch()` setting * [#1164](https://github.com/xmake-io/xmake/issues/1164): Improve to launch console programs for vsxmake project * [#1179](https://github.com/xmake-io/xmake/issues/1179): Improve llvm toolchain and add isysroot ### Bugs fixed * [#1091](https://github.com/xmake-io/xmake/issues/1091): Fix incorrect ordering of inherited library dependencies * [#1105](https://github.com/xmake-io/xmake/issues/1105): Fix c++ language intellisense for vsxmake * [#1132](https://github.com/xmake-io/xmake/issues/1132): Fix TrimEnd bug for vsxmake * [#1142](https://github.com/xmake-io/xmake/issues/1142): Fix git not found when installing packages * Fix macos.version bug for macOS Big Sur * [#1084](https://github.com/xmake-io/xmake/issues/1084): Fix `add_defines()` bug (contain spaces) * [#1195](https://github.com/xmake-io/xmake/pull/1195): Fix unicode problem for vs and improve find_vstudio/os.exec ## v2.3.9 ### New features * Add new [xrepo](https://github.com/xmake-io/xrepo) command to manage C/C++ packages * Support for installing packages of cross-compilation * Add musl.cc toolchains * [#1009](https://github.com/xmake-io/xmake/issues/1009): Support select and install any version package, e.g. `add_requires("libcurl 7.73.0", {verify = false})` * [#1016](https://github.com/xmake-io/xmake/issues/1016): Add license checking for target/packages * [#1017](https://github.com/xmake-io/xmake/issues/1017): Support external/system include directories `add_sysincludedirs` for package and toolchains * [#1020](https://github.com/xmake-io/xmake/issues/1020): Support to find and install pacman package on archlinux and msys2 * Support mouse for `xmake f --menu` ### Change * [#997](https://github.com/xmake-io/xmake/issues/997): Support to set std lanuages for `xmake project -k cmake` * [#998](https://github.com/xmake-io/xmake/issues/998): Support to install vcpkg packages with windows-static-md * [#996](https://github.com/xmake-io/xmake/issues/996): Improve to find vcpkg directory * [#1008](https://github.com/xmake-io/xmake/issues/1008): Improve cross toolchains * [#1030](https://github.com/xmake-io/xmake/issues/1030): Improve xcode.framework and xcode.application rules * [#1051](https://github.com/xmake-io/xmake/issues/1051): Add `edit` and `embed` to `set_symbols()` only for msvc * [#1062](https://github.com/xmake-io/xmake/issues/1062): Improve `xmake project -k vs` plugin. ## v2.3.8 ### New features * [#955](https://github.com/xmake-io/xmake/issues/955): Add zig project templates * [#956](https://github.com/xmake-io/xmake/issues/956): Add wasm platform and support Qt/Wasm SDK * Upgrade luajit vm and support for runing on mips64 device * [#972](https://github.com/xmake-io/xmake/issues/972): Add `depend.on_changed()` api to simplify adding dependent files * [#981](https://github.com/xmake-io/xmake/issues/981): Add `set_fpmodels()` for math optimization mode * [#980](https://github.com/xmake-io/xmake/issues/980): Support Intel C/C++ and Fortran Compiler * [#986](https://github.com/xmake-io/xmake/issues/986): Support for `c11` and `c17` for MSVC Version 16.8 and Above * [#979](https://github.com/xmake-io/xmake/issues/979): Add Abstraction for OpenMP. `add_rules("c++.openmp")` ### Change * [#958](https://github.com/xmake-io/xmake/issues/958): Improve mingw platform to support llvm-mingw toolchain * Improve `add_requires("zlib~xxx")` to support for installing multi-packages at same time * [#977](https://github.com/xmake-io/xmake/issues/977): Improve find_mingw for windows * [#978](https://github.com/xmake-io/xmake/issues/978): Improve toolchain flags order * Improve Xcode toolchain to support for macOS/arm64 ### Bugs fixed * [#951](https://github.com/xmake-io/xmake/issues/951): Fix emcc support for windows * [#992](https://github.com/xmake-io/xmake/issues/992): Fix filelock bug ## v2.3.7 ### New features * [#2941](https://github.com/microsoft/winget-pkgs/pull/2941): Add support for winget * Add xmake-tinyc installer without msvc compiler for windows * Add tinyc compiler toolchain * Add emcc compiler toolchain (emscripten) to compiling to asm.js and WebAssembly * [#947](https://github.com/xmake-io/xmake/issues/947): Add `xmake g --network=private` to enable the private network ### Change * [#907](https://github.com/xmake-io/xmake/issues/907): Improve to the linker optimization for msvc * Improve to detect qt sdk environment * [#918](https://github.com/xmake-io/xmake/pull/918): Improve to support cuda11 toolchains * Improve Qt support for ubuntu/apt * Improve CMake project generator * [#931](https://github.com/xmake-io/xmake/issues/931): Support to export packages with all dependences * [#930](https://github.com/xmake-io/xmake/issues/930): Support to download package without version list directly * [#927](https://github.com/xmake-io/xmake/issues/927): Support to switch arm/thumb mode for android ndk * Improve trybuild/cmake to support android/mingw/iphoneos/watchos toolchains ### Bugs fixed * [#903](https://github.com/xmake-io/xmake/issues/903): Fix install vcpkg packages fails * [#912](https://github.com/xmake-io/xmake/issues/912): Fix the custom toolchain * [#914](https://github.com/xmake-io/xmake/issues/914): Fix bad light userdata pointer for lua on some aarch64 devices ## v2.3.6 ### New features * Add `xmake project -k xcode` generator (use cmake) * [#870](https://github.com/xmake-io/xmake/issues/870): Support gfortran compiler * [#887](https://github.com/xmake-io/xmake/pull/887): Support zig compiler * [#893](https://github.com/xmake-io/xmake/issues/893): Add json module * [#898](https://github.com/xmake-io/xmake/issues/898): Support cross-compilation for golang * [#275](https://github.com/xmake-io/xmake/issues/275): Support go package manager to install go packages * [#581](https://github.com/xmake-io/xmake/issues/581): Support dub package manager to install dlang packages ### Change * [#868](https://github.com/xmake-io/xmake/issues/868): Support new cl.exe dependency report files, `/sourceDependencies xxx.json` * [#902](https://github.com/xmake-io/xmake/issues/902): Improve to detect cross-compilation toolchain ## v2.3.5 ### New features * Add `xmake show -l envs` to show all builtin envirnoment variables * [#861](https://github.com/xmake-io/xmake/issues/861): Support search local package file to install remote package * [#854](https://github.com/xmake-io/xmake/issues/854): Support global proxy settings for curl, wget and git ### Change * [#828](https://github.com/xmake-io/xmake/issues/828): Support to import sub-directory files for protobuf rules * [#835](https://github.com/xmake-io/xmake/issues/835): Improve mode.minsizerel to add /GL flags for msvc * [#828](https://github.com/xmake-io/xmake/issues/828): Support multi-level directories for protobuf/import * [#838](https://github.com/xmake-io/xmake/issues/838#issuecomment-643570920): Support to override builtin-rules for `add_files("src/*.c", {rules = {"xx", override = true}})` * [#847](https://github.com/xmake-io/xmake/issues/847): Support to parse include deps for rc file * Improve msvc tool chain, remove the dependence of global environment variables * [#857](https://github.com/xmake-io/xmake/pull/857): Improved `set_toolchains()` when cross-compilation is supported, specific target can be switched to host toolchain and compiled at the same time ### Bugs fixed * Fix the progress bug for theme * [#829](https://github.com/xmake-io/xmake/issues/829): Fix invalid sysroot path for macOS * [#832](https://github.com/xmake-io/xmake/issues/832): Fix find_packages bug for the debug mode ## v2.3.4 ### New features * [#630](https://github.com/xmake-io/xmake/issues/630): Support *BSD system, e.g. FreeBSD, .. * Add wprint builtin api to show warnings * [#784](https://github.com/xmake-io/xmake/issues/784): Add `set_policy()` to set and modify some builtin policies * [#780](https://github.com/xmake-io/xmake/issues/780): Add set_toolchains/set_toolsets for target and improve to detect cross-compilation toolchains * [#798](https://github.com/xmake-io/xmake/issues/798): Add `xmake show` plugin to show some builtin configuration values and infos * [#797](https://github.com/xmake-io/xmake/issues/797): Add ninja theme style, e.g. `xmake g --theme=ninja` * [#816](https://github.com/xmake-io/xmake/issues/816): Add mode.releasedbg and mode.minsizerel rules * [#819](https://github.com/xmake-io/xmake/issues/819): Support ansi/vt100 terminal control ### Change * [#771](https://github.com/xmake-io/xmake/issues/771): Check includedirs, linkdirs and frameworkdirs * [#774](https://github.com/xmake-io/xmake/issues/774): Support ltui windows resize for `xmake f --menu` * [#782](https://github.com/xmake-io/xmake/issues/782): Add check flags failed tips for add_cxflags, .. * [#808](https://github.com/xmake-io/xmake/issues/808): Support add_frameworks for cmakelists * [#820](https://github.com/xmake-io/xmake/issues/820): Support independent working/build directory ### Bugs fixed * [#786](https://github.com/xmake-io/xmake/issues/786): Fix check header file deps * [#810](https://github.com/xmake-io/xmake/issues/810): Fix strip debug bug for linux ## v2.3.3 ### New features * [#727](https://github.com/xmake-io/xmake/issues/727): Strip and generate debug symbols file (.so/.dSYM) for android/ios program * [#687](https://github.com/xmake-io/xmake/issues/687): Support to generate objc/bundle program. * [#743](https://github.com/xmake-io/xmake/issues/743): Support to generate objc/framework program. * Support to compile bundle, framework, mac application and ios application, and all some project templates * Support generate ios *.ipa file and codesign * Add xmake.cli rule to develop lua program with xmake core engine ### Change * [#750](https://github.com/xmake-io/xmake/issues/750): Improve qt.widgetapp rule to support private slot * Improve Qt/deploy for android and support Qt 5.14.0 ## v2.3.2 ### New features * Add powershell theme for powershell terminal * Add `xmake --dry-run -v` to dry run building target and only show verbose build command. * [#712](https://github.com/xmake-io/xmake/issues/712): Add sdcc platform and support sdcc compiler ### Change * [#589](https://github.com/xmake-io/xmake/issues/589): Improve and optimize build speed, supports parallel compilation and linking across targets * Improve the ninja/cmake generator * [#728](https://github.com/xmake-io/xmake/issues/728): Improve os.cp to support reserve source directory structure * [#732](https://github.com/xmake-io/xmake/issues/732): Improve find_package to support `homebrew/cmake` pacakges * [#695](https://github.com/xmake-io/xmake/issues/695): Improve android abi ### Bugs fixed * Fix the link errors output issues for msvc * [#718](https://github.com/xmake-io/xmake/issues/718): Fix download cache bug for package * [#722](https://github.com/xmake-io/xmake/issues/722): Fix invalid package deps * [#719](https://github.com/xmake-io/xmake/issues/719): Fix process exit bug * [#720](https://github.com/xmake-io/xmake/issues/720): Fix compile_commands generator ## v2.3.1 ### New features * [#675](https://github.com/xmake-io/xmake/issues/675): Support to compile `*.c` as c++, `add_files("*.c", {sourcekind = "cxx"})`. * [#681](https://github.com/xmake-io/xmake/issues/681): Support compile xmake on msys/cygwin and add msys/cygwin platform * Add socket/pipe io modules and support to schedule socket/process/pipe in coroutine * [#192](https://github.com/xmake-io/xmake/issues/192): Try building project with the third-party buildsystem * Enable color diagnostics output for gcc/clang * [#588](https://github.com/xmake-io/xmake/issues/588): Improve project generator, `xmake project -k ninja`, support for build.ninja ### Change * [#665](https://github.com/xmake-io/xmake/issues/665): Support to parse *nix style command options, thanks [@OpportunityLiu](https://github.com/OpportunityLiu) * [#673](https://github.com/xmake-io/xmake/pull/673): Improve tab complete to support argument values * [#680](https://github.com/xmake-io/xmake/issues/680): Improve get.sh scripts and add download mirrors * Improve process scheduler * [#651](https://github.com/xmake-io/xmake/issues/651): Improve os/io module syserrors tips ### Bugs fixed * Fix incremental compilation for checking the dependent file * Fix log output for parsing xmake-vscode/problem info * [#684](https://github.com/xmake-io/xmake/issues/684): Fix linker errors for android ndk on windows ## v2.2.9 ### New features * [#569](https://github.com/xmake-io/xmake/pull/569): Add c++ modules build rules * Add `xmake project -k xmakefile` generator * [620](https://github.com/xmake-io/xmake/issues/620): Add global `~/.xmakerc.lua` for all projects. * [593](https://github.com/xmake-io/xmake/pull/593): Add `core.base.socket` module. ### Change * [#563](https://github.com/xmake-io/xmake/pull/563): Separate build rules for specific language files from action/build * [#570](https://github.com/xmake-io/xmake/issues/570): Add `qt.widgetapp` and `qt.quickapp` rules * [#576](https://github.com/xmake-io/xmake/issues/576): Uses `set_toolchain` instead of `add_tools` and `set_tools` * Improve `xmake create` action * [#589](https://github.com/xmake-io/xmake/issues/589): Improve the default build jobs number to optimize build speed * [#598](https://github.com/xmake-io/xmake/issues/598): Improve find_package to support .tbd libraries on macOS * [#615](https://github.com/xmake-io/xmake/issues/615): Support to install and use other archs and ios conan packages * [#629](https://github.com/xmake-io/xmake/issues/629): Improve hash.uuid and implement uuid v4 * [#639](https://github.com/xmake-io/xmake/issues/639): Improve to parse argument options to support -jN ### Bugs fixed * [#567](https://github.com/xmake-io/xmake/issues/567): Fix out of memory for serialize * [#566](https://github.com/xmake-io/xmake/issues/566): Fix link order problem with remote packages * [#565](https://github.com/xmake-io/xmake/issues/565): Fix run path for vcpkg packages * [#597](https://github.com/xmake-io/xmake/issues/597): Fix run `xmake require` command too slowly * [#634](https://github.com/xmake-io/xmake/issues/634): Fix mode.coverage rule and check flags ## v2.2.8 ### New features * Add protobuf c/c++ rules * [#468](https://github.com/xmake-io/xmake/pull/468): Add utf-8 support for io module on windows * [#472](https://github.com/xmake-io/xmake/pull/472): Add `xmake project -k vsxmake` plugin to support call xmake from vs/msbuild * [#487](https://github.com/xmake-io/xmake/issues/487): Support to build the selected files for the given target * Add filelock for io * [#513](https://github.com/xmake-io/xmake/issues/513): Support for android/termux * [#517](https://github.com/xmake-io/xmake/issues/517): Add `add_cleanfiles` api for target * [#537](https://github.com/xmake-io/xmake/pull/537): Add `set_runenv` api to override os/envs ### Changes * [#257](https://github.com/xmake-io/xmake/issues/257): Lock the whole project to avoid other process to access. * Attempt to enable /dev/shm for the os.tmpdir * [#542](https://github.com/xmake-io/xmake/pull/542): Improve vs unicode output for link/cl * Improve binary bitcode lua scripts in the program directory ### Bugs fixed * [#549](https://github.com/xmake-io/xmake/issues/549): Fix error caused by the new vsDevCmd.bat of vs2019 ## v2.2.7 ### New features * [#455](https://github.com/xmake-io/xmake/pull/455): support clang as cuda compiler, try `xmake f --cu=clang` * [#440](https://github.com/xmake-io/xmake/issues/440): Add `set_rundir()` and `add_runenvs()` api for target/run * [#443](https://github.com/xmake-io/xmake/pull/443): Add tab completion support * Add `on_link`, `before_link` and `after_link` for rule and target * [#190](https://github.com/xmake-io/xmake/issues/190): Add `add_rules("lex", "yacc")` rules to support lex/yacc projects ### Changes * [#430](https://github.com/xmake-io/xmake/pull/430): Add `add_cugencodes()` api to improve set codegen for cuda * [#432](https://github.com/xmake-io/xmake/pull/432): support deps analyze for cu file (for CUDA 10.1+) * [#437](https://github.com/xmake-io/xmake/issues/437): Support explict git source for xmake update, `xmake update github:xmake-io/xmake#dev` * [#438](https://github.com/xmake-io/xmake/pull/438): Support to only update scripts, `xmake update --scriptonly dev` * [#433](https://github.com/xmake-io/xmake/issues/433): Improve cuda to support device-link * [#442](https://github.com/xmake-io/xmake/issues/442): Improve test library ## v2.2.6 ### New features * [#380](https://github.com/xmake-io/xmake/pull/380): Add support to export compile_flags.txt * [#382](https://github.com/xmake-io/xmake/issues/382): Simplify simple scope settings * [#397](https://github.com/xmake-io/xmake/issues/397): Add clib package manager support * [#404](https://github.com/xmake-io/xmake/issues/404): Support Qt for android and deploy android apk * Add some qt empty project templates, e.g. `widgetapp_qt`, `quickapp_qt_static` and `widgetapp_qt_static` * [#415](https://github.com/xmake-io/xmake/issues/415): Add `--cu-cxx` config arguments to `nvcc/-ccbin` * Add `--ndk_stdcxx=y` and `--ndk_cxxstl=gnustl_static` argument options for android NDK ### Changes * Improve remote package manager * Improve `target:on_xxx` scripts to support to match `android|armv7-a@macosx,linux|x86_64` pattern * Improve loadfile to optimize startup speed, decrease 98% time ### Bugs fixed * [#400](https://github.com/xmake-io/xmake/issues/400): fix c++ languages bug for qt rules ## v2.2.5 ### New features * Add `string.serialize` and `string.deserialize` to serialize and deserialize object, function and others. * Add `xmake g --menu` * [#283](https://github.com/xmake-io/xmake/issues/283): Add `target:installdir()` and `set_installdir()` api for target * [#260](https://github.com/xmake-io/xmake/issues/260): Add `add_platformdirs` api, we can define custom platforms * [#310](https://github.com/xmake-io/xmake/issues/310): Add theme feature * [#318](https://github.com/xmake-io/xmake/issues/318): Add `add_installfiles` api to target * [#339](https://github.com/xmake-io/xmake/issues/339): Improve `add_requires` and `find_package` to integrate the 3rd package manager * [#327](https://github.com/xmake-io/xmake/issues/327): Integrate with Conan package manager * Add the builtin api `find_packages("pcre2", "zlib")` to find multiple packages * [#320](https://github.com/xmake-io/xmake/issues/320): Add template configuration files and replace all variables before building * [#179](https://github.com/xmake-io/xmake/issues/179): Generate CMakelist.txt file for `xmake project` plugin * [#361](https://github.com/xmake-io/xmake/issues/361): Support vs2019 preview * [#368](https://github.com/xmake-io/xmake/issues/368): Support `private, public, interface` to improve dependency inheritance like cmake * [#284](https://github.com/xmake-io/xmake/issues/284): Add passing user configs description for `package()` * [#319](https://github.com/xmake-io/xmake/issues/319): Add `add_headerfiles` to improve to set header files and directories * [#342](https://github.com/xmake-io/xmake/issues/342): Add some builtin help functions for `includes()`, e.g. `check_cfuncs` ### Changes * Improve to switch version and debug mode for the dependent packages * [#264](https://github.com/xmake-io/xmake/issues/264): Support `xmake update dev` on windows * [#293](https://github.com/xmake-io/xmake/issues/293): Add `xmake f/g --mingw=xxx` configuration option and improve to find_mingw * [#301](https://github.com/xmake-io/xmake/issues/301): Improve precompiled header file * [#322](https://github.com/xmake-io/xmake/issues/322): Add `option.add_features`, `option.add_cxxsnippets` and `option.add_csnippets` * Remove some deprecated interfaces of xmake 1.x, e.g. `add_option_xxx` * [#327](https://github.com/xmake-io/xmake/issues/327): Support conan package manager for `lib.detect.find_package` * Improve `lib.detect.find_package` and add builtin `find_packages("zlib 1.x", "openssl", {xxx = ...})` api * Mark `set_modes()` as deprecated, we use `add_rules("mode.debug", "mode.release")` instead of it * [#353](https://github.com/xmake-io/xmake/issues/353): Improve `target:set`, `target:add` and add `target:del` to modify target configuration * [#356](https://github.com/xmake-io/xmake/issues/356): Add `qt_add_static_plugins()` api to support static Qt sdk * [#351](https://github.com/xmake-io/xmake/issues/351): Support yasm for generating vs201x project * Improve the remote package manager. ### Bugs fixed * Fix cannot call `set_optimize()` to set optimization flags when exists `add_rules("mode.release")` * [#289](https://github.com/xmake-io/xmake/issues/289): Fix unarchive gzip file failed on windows * [#296](https://github.com/xmake-io/xmake/issues/296): Fix `option.add_includedirs` for cuda * [#321](https://github.com/xmake-io/xmake/issues/321): Fix find program bug with $PATH envirnoment ## v2.2.3 ### New features * [#233](https://github.com/xmake-io/xmake/issues/233): Support windres for mingw platform * [#239](https://github.com/xmake-io/xmake/issues/239): Add cparser compiler support * Add plugin manager `xmake plugin --help` * Add `add_syslinks` api to add system libraries dependence * Add `xmake l time xmake [--rebuild]` to record compilation time * [#250](https://github.com/xmake-io/xmake/issues/250): Add `xmake f --vs_sdkver=10.0.15063.0` to change windows sdk version * Add `lib.luajit.ffi` and `lib.luajit.jit` extension modules * [#263](https://github.com/xmake-io/xmake/issues/263): Add new target kind: object to only compile object files ### Changes * [#229](https://github.com/xmake-io/xmake/issues/229): Improve to select toolset for vcproj plugin * Improve compilation dependences * Support *.xz for extractor * [#249](https://github.com/xmake-io/xmake/pull/249): revise progress formatting to space-leading three digit percentages * [#247](https://github.com/xmake-io/xmake/pull/247): Add `-D` and `--diagnosis` instead of `--backtrace` * [#259](https://github.com/xmake-io/xmake/issues/259): Improve on_build, on_build_file and on_xxx for target and rule * [#269](https://github.com/xmake-io/xmake/issues/269): Clean up the temporary files at last 30 days * Improve remote package manager * Support to add packages with only header file * Support to modify builtin package links, e.g. `add_packages("xxx", {links = {}})` ### Bugs fixed * Fix state inconsistency after failed outage of installation dependency package ## v2.2.2 ### New features * Support fasm assembler * Add `has_config`, `get_config`, and `is_config` apis * Add `set_config` to set the default configuration * Add `$xmake --try` to try building project using third-party buildsystem * Add `set_enabled(false)` to disable target * [#69](https://github.com/xmake-io/xmake/issues/69): Add remote package management, `add_requires("tbox ~1.6.1")` * [#216](https://github.com/xmake-io/xmake/pull/216): Add windows mfc rules ### Changes * Improve to detect Qt envirnoment and support mingw * Add debug and release rules to the auto-generated xmake.lua * [#178](https://github.com/xmake-io/xmake/issues/178): Modify the shared library name for mingw. * Support case-insensitive path pattern-matching for `add_files()` on windows * Improve to detect Qt sdk directory for `detect.sdks.find_qt` * [#184](https://github.com/xmake-io/xmake/issues/184): Improve `lib.detect.find_package` to support vcpkg * [#208](https://github.com/xmake-io/xmake/issues/208): Improve rpath for shared library * [#225](https://github.com/xmake-io/xmake/issues/225): Improve to detect vs envirnoment ### Bug fixed * [#177](https://github.com/xmake-io/xmake/issues/177): Fix the dependent target link bug * Fix high cpu usage bug and Exit issues for `$ xmake f --menu` * [#197](https://github.com/xmake-io/xmake/issues/197): Fix Chinese path for generating vs201x project * Fix wdk rules bug * [#205](https://github.com/xmake-io/xmake/pull/205): Fix targetdir,objectdir not used in vsproject ## v2.2.1 ### New features * [#158](https://github.com/xmake-io/xmake/issues/158): Support CUDA Toolkit and Compiler * Add `set_tools` and `add_tools` apis to change the toolchains for special target * Add builtin rules: `mode.debug`, `mode.release`, `mode.profile` and `mode.check` * Add `is_mode`, `is_arch` and `is_plat` builtin apis in the custom scripts * Add color256 codes * [#160](https://github.com/xmake-io/xmake/issues/160): Support Qt compilation environment and add `qt.console`, `qt.application` rules * Add some Qt project templates * [#169](https://github.com/xmake-io/xmake/issues/169): Support yasm for linux, macosx and windows * [#159](https://github.com/xmake-io/xmake/issues/159): Support WDK driver compilation environment ### Changes * Add FAQ to the auto-generated xmake.lua * Support android NDK >= r14 * Improve warning flags for swiftc * [#167](https://github.com/xmake-io/xmake/issues/167): Improve custom rules * Improve `os.files` and `os.dirs` api * [#171](https://github.com/xmake-io/xmake/issues/171): Improve build dependence for qt rule * Implement `make clean` for generating makefile plugin ### Bugs fixed * Fix force to add flags bug * [#157](https://github.com/xmake-io/xmake/issues/157): Fix generate pdb file error if it's output directory does not exists * Fix strip all symbols bug for macho target file * [#168](https://github.com/xmake-io/xmake/issues/168): Fix generate vs201x project bug with x86/x64 architectures ## v2.1.9 ### New features * Add `del_files()` api to delete files in the files list * Add `rule()`, `add_rules()` api to implement the custom build rule and improve `add_files("src/*.md", {rule = "markdown"})` * Add `os.filesize()` api * Add `core.ui.xxx` cui components * Add `xmake f --menu` to configure project with a menu configuration interface * Add `set_values` api to `option()` * Support to generate a menu configuration interface from user custom project options * Add source file position to interpreter and search results in menu ### Changes * Improve to configure cross-toolchains, add tool alias to support unknown tool name, e.g. `xmake f --cc=gcc@ccmips.exe` * [#151](https://github.com/xmake-io/xmake/issues/151): Improve to build the share library for the mingw platform * Improve to generate makefile plugin * Improve the checking errors tips * Improve `add_cxflags` .., force to set flags without auto checking: `add_cxflags("-DTEST", {force = true})` * Improve `add_files`, add force block to force to set flags without auto checking: `add_files("src/*.c", {force = {cxflags = "-DTEST"}})` * Improve to search the root project directory * Improve to detect vs environment * Upgrade luajit to 2.1.0-beta3 * Support to run xmake on linux (arm, arm64) * Improve to generate vs201x project plugin ### Bugs fixed * Fix complation dependence * [#151](https://github.com/xmake-io/xmake/issues/151): Fix `os.nuldev()` for gcc on mingw * [#150](https://github.com/xmake-io/xmake/issues/150): Fix the command line string limitation for `ar.exe` * Fix `xmake f --cross` error * Fix `os.cd` to the windows root path bug ## v2.1.8 ### New features * Add `XMAKE_LOGFILE` environment variable to dump the output info to file * Support tinyc compiler ### Changes * Improve support for IDE/editor plugins (e.g. vscode, sublime, intellij-idea) * Add `.gitignore` file when creating new projects * Improve to create template project * Improve to detect toolchains on macosx without xcode * Improve `set_config_header` to support `set_config_header("config", {version = "2.1.8", build = "%Y%m%d%H%M"})` ### Bugs fixed * [#145](https://github.com/xmake-io/xmake/issues/145): Fix the current directory when running target ## v2.1.7 ### New features * Add `add_imports` to bulk import modules for the target, option and package script * Add `xmake -y/--yes` to confirm the user input by default * Add `xmake l package.manager.install xxx` to install software package * Add xmake plugin for vscode editor, [xmake-vscode](https://marketplace.visualstudio.com/items?itemName=tboox.xmake-vscode#overview) * Add `xmake macro ..` to run the last command ### Changes * Support 24bits truecolors for `cprint()` * Support `@loader_path` and `$ORIGIN` for `add_rpathdirs()` * Improve `set_version("x.x.x", {build = "%Y%m%d%H%M"})` and add build version * Move docs directory to xmake-docs repo * Improve install and uninstall actions and support DESTDIR and PREFIX envirnoment variables * Optimize to detect flags * Add `COLORTERM=nocolor` to disable color output * Remove `and_bindings` and `add_rbindings` api * Disable to output colors code to file * Update project templates with tbox * Improve `lib.detect.find_program` interface * Enable colors output for windows cmd * Add `-w|--warning` arguments to enable the warnings output ### Bugs fixed * Fix `set_pcxxheader` bug * [#140](https://github.com/xmake-io/xmake/issues/140): Fix `os.tmpdir()` in fakeroot * [#142](https://github.com/xmake-io/xmake/issues/142): Fix `os.getenv` charset bug on windows * Fix compile error with spaces path * Fix setenv empty value bug ## v2.1.6 ### Changes * Improve `add_files` to configure the compile option of the given files * Inherit links and linkdirs from the dependent targets and options * Improve `target.add_deps` and add inherit config, e.g. `add_deps("test", {inherit = false})` * Remove the binary files of `tbox.pkg` * Use `/Zi` instead of `/ZI` for msvc ### Bugs fixed * Fix target deps * Fix `target:add` and `option:add` bug * Fix compilation and installation bug on archlinux ## v2.1.5 ### New features * [#83](https://github.com/xmake-io/xmake/issues/83): Add `add_csnippet` and `add_cxxsnippet` into `option` for detecting some compiler features. * [#83](https://github.com/xmake-io/xmake/issues/83): Add user extension modules to detect program, libraries and files. * Add `find_program`, `find_file`, `find_library`, `find_tool` and `find_package` module interfaces. * Add `net.*` and `devel.*` extension modules * Add `val()` api to get the value of builtin-variable, e.g. `val("host")`, `val("env PATH")`, `val("shell echo hello")` and `val("reg HKEY_LOCAL_MACHINE\\XX;Value")` * Support to compile the microsoft resource file (.rc) * Add `has_flags`, `features` and `has_features` for detect module interfaces. * Add `option.on_check`, `option.after_check` and `option.before_check` api * Add `target.on_load` api * [#132](https://github.com/xmake-io/xmake/issues/132): Add `add_frameworkdirs` api * Add `lib.detect.has_xxx` and `lib.detect.find_xxx` apis. * Add `add_moduledirs` api * Add `includes` api instead of `add_subdirs` and `add_subfiles` * [#133](https://github.com/xmake-io/xmake/issues/133): Improve the project plugin to generate `compile_commands.json` by run `xmake project -k compile_commands` * Add `set_pcheader` and `set_pcxxheader` to support the precompiled header, support gcc, clang, msvc * Add `xmake f -p cross` platform and support the custom platform ### Changes * [#87](https://github.com/xmake-io/xmake/issues/87): Add includes and links from target deps automatically * Improve `import` to load user extension and global modules * [#93](https://github.com/xmake-io/xmake/pull/93): Improve `xmake lua` to run a single line command * Improve to print gcc error and warning info * Improve `print` interface to dump table * [#111](https://github.com/xmake-io/xmake/issues/111): Add `--root` common option to allow run xmake command as root * [#113](https://github.com/xmake-io/xmake/pull/113): Privilege manage when running as root, store the root privilege and degrade. * Improve `xxx_script` in `xmake.lua` to support pattern match, e.g. `on_build("iphoneos|arm*", function (target) end)` * improve builtin-variables to support to get the value envirnoment and registry * Improve to detect vstudio sdk and cross toolchains envirnoment * [#71](https://github.com/xmake-io/xmake/issues/71): Improve to detect compiler and linker from env vars * Improve the option detection (cache and multi-jobs) and increase 70% speed * [#129](https://github.com/xmake-io/xmake/issues/129): Check link deps and cache the target file * Support `*.asm` source files for vs201x project plugin * Mark `add_bindings` and `add_rbindings` as deprecated * Optimize `xmake rebuild` speed on windows * Move `core.project.task` to `core.base.task` * Move `echo` and `app2ipa` plugins to [xmake-plugins](https://github.com/xmake-io/xmake-plugins) repo. * Add new api `set_config_header("config.h", {prefix = ""})` instead of `set_config_h` and `set_config_h_prefix` ### Bugs fixed * Fix `try-catch-finally` * Fix interpreter bug when parsing multi-level subdirs * [#115](https://github.com/xmake-io/xmake/pull/115): Fix the path problem of the install script `get.sh` * Fix cache bug for import() ## v2.1.4 ### New features * [#68](https://github.com/xmake-io/xmake/issues/68): Add `$(programdir)` and `$(xmake)` builtin variables * add `is_host` api to get current host operating system * [#79](https://github.com/xmake-io/xmake/issues/79): Improve `xmake lua` to run interactive commands, read-eval-print (REPL) ### Changes * Modify option menu color. * [#71](https://github.com/xmake-io/xmake/issues/71): Improve to map optimization flags for cl.exe * [#73](https://github.com/xmake-io/xmake/issues/73): Attempt to get executable path as xmake's program directory * Improve the scope of `xmake.lua` in `add_subdirs` and use independent sub-scope to avoid dirty scope * [#78](https://github.com/xmake-io/xmake/pull/78): Get terminal size in runtime and soft-wrap the help printing * Avoid generate `.xmake` directory if be not in project ### Bugs fixed * [#67](https://github.com/xmake-io/xmake/issues/67): Fix `sudo make install` permission problem * [#70](https://github.com/xmake-io/xmake/issues/70): Fix check android compiler error * Fix temporary file path conflict * Fix `os.host` and `os.arch` interfaces * Fix interpreter bug for loading root api * [#77](https://github.com/xmake-io/xmake/pull/77): fix `cprint` no color reset eol ## v2.1.3 ### New features * [#65](https://github.com/xmake-io/xmake/pull/65): Add `set_default` api for target to modify default build and install behavior * Allows to run `xmake` command in project subdirectories, it will find the project root directory automatically * Add `add_rpathdirs` for target and option ### Changes * [#61](https://github.com/xmake-io/xmake/pull/61): Provide safer `xmake install` and `xmake uninstall` task with administrator permission * Provide `rpm`, `deb` and `osxpkg` install package * [#63](https://github.com/xmake-io/xmake/pull/63): More safer build and install xmake * [#61](https://github.com/xmake-io/xmake/pull/61): Check run command as root * Improve check toolchains and implement delay checking * Add user tips when scanning and generating `xmake.lua` automatically ### Bugs fixed * Fix error tips for checking xmake min version * [#60](https://github.com/xmake-io/xmake/issues/60): Fix self-build for macosx and windows * [#64](https://github.com/xmake-io/xmake/issues/64): Fix compile android `armv8-a` error * [#50](https://github.com/xmake-io/xmake/issues/50): Fix only position independent executables issue for android program ## v2.1.2 ### New features * Add aur package script and support to install xmake from yaourt * Add [set_basename](#http://xmake.io/#/manual?id=targetset_basename) api for target ### Changes * Support vs2017 * Support compile rust for android * Improve vs201x project plugin and support multi-modes compilation. ### Bugs fixed * Fix cannot find android sdk header files * Fix checking option bug * [#57](https://github.com/xmake-io/xmake/issues/57): Fix code files mode to 0644 ## v2.1.1 ### New features * Add `--links`, `--linkdirs` and `--includedirs` configure arguments * Add app2ipa plugin * Add dictionary syntax style for `xmake.lua` * Provide smart scanning and building mode without `xmake.lua` * Add `set_xmakever` api for `xmake.lua` * Add `add_frameworks` api for `objc` and `swift` * Support multi-languages extension and add `golang`, `dlang` and `rust` language * Add optional `target_end`, `option_end`, `task_end` apis for scope * Add `golang`, `dlang` and `rust` project templates ### Changes * Support vs2017 for the project plugin * Improve gcc error and warning tips * Improve lanuage module * Improve print interface, support lua print and format output * Automatically scan project files and generate it for building if xmake.lua not exists * Modify license to Apache License 2.0 * Remove some binary tools * Remove install.bat script and provide nsis install package * Rewrite [documents](http://www.xmake.io/#/home/) using [docute](https://github.com/egoist/docute) * Improve `os.run`, `os.exec`, `os.cp`, `os.mv` and `os.rm` interfaces and support wildcard pattern * Optimize the output info and add `-q|--quiet` option * Improve makefile generator, uses $(XX) variables for tools and flags ### Bugs fixed * [#41](https://github.com/waruqi/xmake/issues/41): Fix checker bug for windows * [#43](https://github.com/waruqi/xmake/issues/43): Avoid generating unnecessary .xmake directory * Add c++ stl search directories for android * Fix compile error for rhel 5.10 * Fix `os.iorun` bug ## v2.0.5 ### New features * Add some interpreter builtin-modules * Support ml64 assembler for windows x64 ### Changes * Improve ipairs and pairs interfaces and support filter * Add filters for generating vs201x project * Remove `core/tools` (msys toolchains) and uses xmake to compile core sources on windows * Remove `xmake/packages` for templates ### Bugs fixed * Fix `-def:xxx.def` flags failed for msvc * Fix ml.exe assembler script * Fix options linking order bug ## v2.0.4 ### New features * Add native shell support for `xmake.lua`. e.g. `add_ldflags("$(shell pkg-config --libs sqlite3)")` * Enable pdb symbol files for windows * Add debugger support on windows (vsjitdebugger, ollydbg, windbg ... ) * Add `getenv` interface for the global scope of `xmake.lua` * Add plugin for generating vstudio project file (vs2002 - vs2015) * Add `set_default` api for option ### Changes * Improve builtin-variable format * Support option for string type ### Bugs fixed * Fix check ld failed without g++ on linux * Fix compile `*.cxx` files failed ## v2.0.3 ### New features * Add check includes dependence automatically * Add print colors * Add debugger support, e.g. `xmake run -d program ...` ### Changes * Improve the interfaces of run shell * Upgrade luajit to v2.0.4 * Improve to generate makefile plugin * Optimizate the multitasking compiling speed ### Bugs fixed * Fix install directory bug * Fix the root directory error for `import` interface * Fix check visual stdio error on windows ## v2.0.2 ### Changes * Change install and uninstall actions * Update templates * Improve to check function ### Bugs fixed * [#7](https://github.com/waruqi/xmake/issues/7): Fix create project bug with '[targetname]' * [#9](https://github.com/waruqi/xmake/issues/9): Support clang with c++11 * Fix api scope leaks bug * Fix path bug for windows * Fix check function bug * Fix check toolchains failed * Fix compile failed for android on windows ## v2.0.1 ### New features * Add task api for running custom tasks * Add plugin expansion and provide some builtin plugins * Add export ide project plugin(e.g. makefile and will support to export other projects for vs, xcode in feature) * Add demo plugin for printing 'hello xmake' * Add make doxygen documents plugin * Add macro script plugin * Add more modules for developing plugin * Add exception using try/catch and simplify grammar for plugin script * Add option bindings * Show progress when building ### Changes * Rewrite interpreter for xmake.lua * More strict syntax detection mechanism * More strict api scope for xmake.lua * Simplify template development * Extend platforms, tools, templates and actions fastly * Simplify api and support import modules * Remove dependence for gnu make/nmake, no longer need makefile * Optimize speed for building and faster x4 than v1.0.4 * Optimize automatic detection * Modify some api name, but be compatible with the old version * Optimize merging static library * Simplify cross compilation using argument `--sdk=xxx` * Simplify boolean option for command line, e.g. `xmake config --xxx=[y|n|yes|no|true|false]` * Merge iphoneos and iphonesimulator platforms * Merge watchos and watchsimulator platformss ### Bugs fixed * [#3](https://github.com/waruqi/xmake/issues/3): ArchLinux compilation failed * [#4](https://github.com/waruqi/xmake/issues/4): Install failed for windows * Fix envirnoment variable bug for windows ## v1.0.4 ### New features * Support windows assembler * Add some project templates * Support swift codes * Add -v argument for outputing more verbose info * Add apple platforms:watchos, watchsimulator * Add architecture x64, amd64, x86_amd64 for windows * Support switch static and share library * Add `-j/--jobs` argument for supporting multi-jobs ### Changes * Improve `add_files` api and support to add `*.o/obj/a/lib` files for merging static library and object files * Optimize installation and remove some binary files ### Bugs fixed * [#1](https://github.com/waruqi/xmake/issues/4): Install failed for win7 * Fix checking toolchains bug * Fix install script bug * Fix install bug for linux x86_64 ## v1.0.3 ### New features * Add `set_runscript` api and support custom action * Add import api and support import modules in xmake.lua, e.g. os, path, utils ... * Add new architecture: arm64-v8a for android ### Bugs fixed * Fix api bug for `set_installscript` * Fix install bug for windows `x86_64` * Fix relative path bug

# 更新日志 ## master (开发中) ### 新特性 * [#7398](https://github.com/xmake-io/xmake/pull/7398): 添加 C# 语言和 dotnet 工具链支持 * [#7410](https://github.com/xmake-io/xmake/pull/7410): 添加 C# 和 C/C++ 通过 P/Invoke 互操作支持 * [#7360](https://github.com/xmake-io/xmake/pull/7360): 支持自定义模板 * [#7367](https://github.com/xmake-io/xmake/pull/7367): 添加 `xmake create --list` 和远程模板分发 * [#7313](https://github.com/xmake-io/xmake/pull/7313): 添加 `build.release.strip` 策略 * [#7333](https://github.com/xmake-io/xmake/pull/7333): 添加 `winos.file_signature` 函数 * [#7336](https://github.com/xmake-io/xmake/pull/7336): 添加运行 wasi 目标支持 * [#7346](https://github.com/xmake-io/xmake/pull/7346): 添加 nnd 调试器支持 * [#7366](https://github.com/xmake-io/xmake/pull/7366): 添加 tarxz 打包格式 ### 改进 * [#7309](https://github.com/xmake-io/xmake/pull/7309): 保持包源信息 * [#7310](https://github.com/xmake-io/xmake/pull/7310): 改进检测提示 * [#7311](https://github.com/xmake-io/xmake/pull/7311): 改进 Xcode 工具链 * [#7312](https://github.com/xmake-io/xmake/pull/7312): 改进 binutils 支持 wasm * [#7320](https://github.com/xmake-io/xmake/pull/7320): 添加 haiku ci * [#7329](https://github.com/xmake-io/xmake/pull/7329): 改进 qt deploy 对 macapp 的支持 * [#7349](https://github.com/xmake-io/xmake/pull/7349): 改进 C++ 模块的 clang/gcc embed-dir 处理 * [#7368](https://github.com/xmake-io/xmake/pull/7368): 迁移模板到仓库 * [#7383](https://github.com/xmake-io/xmake/pull/7383): 拆分 zig 工具链为 zig/zigcc * [#7384](https://github.com/xmake-io/xmake/pull/7384): 改进 find_hdk * [#7387](https://github.com/xmake-io/xmake/pull/7387): 在进度中显示目标名称 * [#7391](https://github.com/xmake-io/xmake/pull/7391): 改进通过 vcpkg features 查找包 * [#7392](https://github.com/xmake-io/xmake/pull/7392): 修复 zig 共享库 * [#7396](https://github.com/xmake-io/xmake/pull/7396): 改进 vcpkg * [#7399](https://github.com/xmake-io/xmake/pull/7399): 扩展格式化到 C++ 模块 * [#7409](https://github.com/xmake-io/xmake/pull/7409): 改进 Windows 上的 ldc ### Bugs 修复 * [#7299](https://github.com/xmake-io/xmake/pull/7299): 修复 vcpkg 依赖处理 * [#7316](https://github.com/xmake-io/xmake/pull/7316): 修复 components 拼写错误 * [#7318](https://github.com/xmake-io/xmake/pull/7318): 更新 tbox 修复 tolower/toupper * [#7339](https://github.com/xmake-io/xmake/pull/7339): 更新 tbox 修复 win7 启动进程问题 * [#7344](https://github.com/xmake-io/xmake/pull/7344): 修复 swig jar 包模块 * [#7345](https://github.com/xmake-io/xmake/pull/7345): 修复检测 clang 信息 * [#7341](https://github.com/xmake-io/xmake/pull/7341): 修复 WASM QT 6.9 * [#7356](https://github.com/xmake-io/xmake/pull/7356): 修复 issue #7354 * [#7371](https://github.com/xmake-io/xmake/pull/7371): 修复测试详细输出 * [#7386](https://github.com/xmake-io/xmake/pull/7386): 修复安装脚本与 coreutils 9.10 的不兼容 * [#7393](https://github.com/xmake-io/xmake/pull/7393): 修复构建目标验证 ## v3.0.7 ### 新特性 * [#7178](https://github.com/xmake-io/xmake/pull/7178): 改进 Verilator 构建文件解析,从 cmake 格式切换到 json 格式 * [#7186](https://github.com/xmake-io/xmake/pull/7186): 添加 Alpine CI 支持 * [#7187](https://github.com/xmake-io/xmake/pull/7187): 为 CUDA 架构添加后缀支持 * [#7190](https://github.com/xmake-io/xmake/pull/7190): Nix 包管理器:添加语义化版本控制并改进版本选择 * [#7189](https://github.com/xmake-io/xmake/pull/7189): 添加包方案(package schemes)支持 * [#7208](https://github.com/xmake-io/xmake/pull/7208): 支持 Qt SDK 动态 mkspec 选择 * [#7219](https://github.com/xmake-io/xmake/pull/7219): 添加 cli.iconv 模块 * [#7235](https://github.com/xmake-io/xmake/pull/7235): 添加字符串大小写转换函数:lower 和 upper * [#7246](https://github.com/xmake-io/xmake/pull/7246): 添加 utf8 模块 * [#7268](https://github.com/xmake-io/xmake/pull/7268): 为 Nim 源文件添加依赖文件生成 * [#7269](https://github.com/xmake-io/xmake/pull/7269): 为 zig 工具链添加交叉编译的目标架构验证 * [#7274](https://github.com/xmake-io/xmake/pull/7274): 添加 os.access 函数用于文件访问检查 * [#7284](https://github.com/xmake-io/xmake/pull/7284): 添加 `--stdin` 支持 * [#7293](https://github.com/xmake-io/xmake/pull/7293): 添加在浏览器中运行 wasm 目标的支持 * [#7300](https://github.com/xmake-io/xmake/pull/7300): 为安装/卸载添加 libdir、includedir、bindir 支持 * [#7295](https://github.com/xmake-io/xmake/pull/7295): 支持测试输出文件 ### 改进 * [#7203](https://github.com/xmake-io/xmake/pull/7203): 改进 MinGW 工具链 * [#7206](https://github.com/xmake-io/xmake/pull/7206): WDK:为 KMDF 包含路径添加共享目录 * [#7214](https://github.com/xmake-io/xmake/pull/7214): 改进警告输出 * [#7216](https://github.com/xmake-io/xmake/pull/7216): 改进依赖锁定(requirelock) * [#7223](https://github.com/xmake-io/xmake/pull/7223): 改进 NuGet 库文件匹配,采用基于分数的选择机制 * [#7226](https://github.com/xmake-io/xmake/pull/7226): 改进 clang-tidy 查找 * [#7232](https://github.com/xmake-io/xmake/pull/7232): 改进链接器脚本配置 * [#7237](https://github.com/xmake-io/xmake/pull/7237): 更新 tbox 库以支持大小写敏感 * [#7240](https://github.com/xmake-io/xmake/pull/7240): 改进 Verilator 标志处理 * [#7258](https://github.com/xmake-io/xmake/pull/7258): 改进 Qt xpack 打包 * [#7262](https://github.com/xmake-io/xmake/pull/7262): 改进预编译头文件(PCH)与其他目标的并发处理 * [#7260](https://github.com/xmake-io/xmake/pull/7260): 改进 Free Pascal 编译器支持 * [#7270](https://github.com/xmake-io/xmake/pull/7270): 改进方案版本选择机制 * [#7272](https://github.com/xmake-io/xmake/pull/7272): 增强 Nim 对共享库和 rpath 处理的支持 * [#7273](https://github.com/xmake-io/xmake/pull/7273): 改进 io.read 和 io.readfile 函数 * [#7267](https://github.com/xmake-io/xmake/pull/7267): 通过检查父进程增强 Linux 的 shell 检测 * [#7278](https://github.com/xmake-io/xmake/pull/7278): 改进 os.isexec 函数 * [#7283](https://github.com/xmake-io/xmake/pull/7283): 增强 compile_commands 支持并添加测试用例 * [#7285](https://github.com/xmake-io/xmake/pull/7285): 改进 Windows 的 cmd/powershell shell 检测 * [#7286](https://github.com/xmake-io/xmake/pull/7286): 检测 VS 时检查长环境变量值 * [#7280](https://github.com/xmake-io/xmake/pull/7280): 仅在交叉编译时添加目标标志 * [#7290](https://github.com/xmake-io/xmake/pull/7290): 改进 vcvars 处理 * [#7302](https://github.com/xmake-io/xmake/pull/7302): 改进运行进程错误处理 * [#7306](https://github.com/xmake-io/xmake/pull/7306): 改进远程构建,支持多主机配置和 `--host` 选项 * [#7298](https://github.com/xmake-io/xmake/pull/7298): 为 Windows DLL 的 foo/main 示例添加初始实现 ### Bugs 修复 * [#7210](https://github.com/xmake-io/xmake/pull/7210): 修复包版本问题 * [#7213](https://github.com/xmake-io/xmake/pull/7213): 修复导入文件的安装目录问题 * [#7231](https://github.com/xmake-io/xmake/pull/7231): 修复模块支持中的标志获取问题 * [#7245](https://github.com/xmake-io/xmake/pull/7245): 修复方案版本选择问题 * [#7259](https://github.com/xmake-io/xmake/pull/7259): 修复 C++ 函数符号导出问题 * [#7266](https://github.com/xmake-io/xmake/pull/7266): 修复预编译头文件扩展名问题 * [#7282](https://github.com/xmake-io/xmake/pull/7282): find_cuda:回滚破坏性变更 * [#7294](https://github.com/xmake-io/xmake/pull/7294): 修复包工具链问题 * [#7296](https://github.com/xmake-io/xmake/pull/7296): 修复 emsdk 查找问题 * [#7202](https://github.com/xmake-io/xmake/pull/7202): 修复 getfenv 函数 ## v3.0.6 ### 新特性 * [#7141](https://github.com/xmake-io/xmake/pull/7141): 支持禁用 Android 原生应用 glue * [#7139](https://github.com/xmake-io/xmake/pull/7139): 添加 Android 原生应用构建支持 * [#7127](https://github.com/xmake-io/xmake/pull/7127): 为 binutils 添加 deplibs 支持 * [#7120](https://github.com/xmake-io/xmake/pull/7120): 为 binutils 添加 extractlib 支持 * [#7106](https://github.com/xmake-io/xmake/pull/7106): 为 MSVC 添加 `/std:c++23preview` 支持 * [#7105](https://github.com/xmake-io/xmake/pull/7105): 为 glsl/hlsl2spv 添加 `bin2obj` 支持 * [#7103](https://github.com/xmake-io/xmake/pull/7103): 添加 `bin2obj` 规则(比 `bin2c` 更快) * [#7096](https://github.com/xmake-io/xmake/pull/7096): 添加 Flang 工具链支持 * [#7094](https://github.com/xmake-io/xmake/pull/7094): 添加 `xmake check syntax` 支持 * [#7091](https://github.com/xmake-io/xmake/pull/7091): 为 MSVC 添加动态调试支持 * [#7083](https://github.com/xmake-io/xmake/pull/7083): 添加对 CUDA 11~13 的支持 * [#7071](https://github.com/xmake-io/xmake/pull/7071): 添加 Qt 打包支持 * [#7064](https://github.com/xmake-io/xmake/pull/7064): 添加 AppImage xpack 格式用于 Linux 应用程序打包 * [#7062](https://github.com/xmake-io/xmake/pull/7062): 添加 dmg xpack 格式用于 macOS 应用程序打包 ### 改进 * [#7149](https://github.com/xmake-io/xmake/pull/7149): 改进 binutils 优化 rpath 解析 * [#7148](https://github.com/xmake-io/xmake/pull/7148): 更新 Zig 示例 * [#7145](https://github.com/xmake-io/xmake/pull/7145): 改进 Clang/LLVM 运行时支持 * [#7136](https://github.com/xmake-io/xmake/pull/7136): 改进 clang-cl 依赖文件生成 * [#7135](https://github.com/xmake-io/xmake/pull/7135): 改进 `xrepo env` 以添加会话 ID * [#7155](https://github.com/xmake-io/xmake/pull/7155): 重构 Windows 上 clang-cl 的 ASan 支持(改进运行库链接、链接器标志、完善 PATH/CMAKE_LINKER_TYPE 配置、精简工具链) * [#7109](https://github.com/xmake-io/xmake/pull/7109): 改进 binutils 以从二进制文件读取符号 * [#7102](https://github.com/xmake-io/xmake/pull/7102): 改进 bin2c 规则 * [#7098](https://github.com/xmake-io/xmake/pull/7098): 重构并改进 Golang 支持 * [#7095](https://github.com/xmake-io/xmake/pull/7095): 将 target/package/toolchain:memcache 标记为公开 * [#7093](https://github.com/xmake-io/xmake/pull/7093): 改进镜像仓库 URL * [#7088](https://github.com/xmake-io/xmake/pull/7088): 改进 C++/ObjC 规则 * [#7087](https://github.com/xmake-io/xmake/pull/7087): 为策略 `package.download.http_headers` 添加类型约束 * [#7069](https://github.com/xmake-io/xmake/pull/7069): 为 LLVM 工具链保存 Qt 规则 * [#7061](https://github.com/xmake-io/xmake/pull/7061): 更新 CI 配置 * [#7039](https://github.com/xmake-io/xmake/pull/7039): 更新 macOS CI ### Bugs 修复 * [#7132](https://github.com/xmake-io/xmake/pull/7132): 修复带有 ASan 的 clang-cl 工具链 * [#7125](https://github.com/xmake-io/xmake/pull/7125): 修复 cosmocc CI * [#7124](https://github.com/xmake-io/xmake/pull/7124): 修复 Clang 工具链的默认 MSVC 运行时 * [#7112](https://github.com/xmake-io/xmake/pull/7112): 修复 Windows 上的目录切换 * [#7104](https://github.com/xmake-io/xmake/pull/7104): 修复项目生成器的准备工作 * [#7092](https://github.com/xmake-io/xmake/pull/7092): 修复 Solaris 构建 * [#7086](https://github.com/xmake-io/xmake/pull/7086): 修复 Qt QML 规则中的 targetdir * [#7085](https://github.com/xmake-io/xmake/pull/7085): 修复 Clang 工具链的 CMake 标志 * [#7084](https://github.com/xmake-io/xmake/pull/7084): 修复 pacman find_package * [#7082](https://github.com/xmake-io/xmake/pull/7082): 修复 Clang CUDA 标志检查 * [#7081](https://github.com/xmake-io/xmake/pull/7081): 修复 `get_headerunit_key` * [#7074](https://github.com/xmake-io/xmake/pull/7074): 修复 libc++ 找不到 std 模块 * [#7067](https://github.com/xmake-io/xmake/pull/7067): 修复交叉编译工具链的 get_stdmodules ## v3.0.5 ### 新特性 * [#7055](https://github.com/xmake-io/xmake/pull/7055): 添加 Solaris 平台支持 (i386, x86_64) * [#7054](https://github.com/xmake-io/xmake/pull/7054): 添加更多 BSD 系统支持 (NetBSD, OpenBSD, DragonflyBSD) * [#6929](https://github.com/xmake-io/xmake/pull/6929): 添加 GCC 15 工具链支持 * [#6967](https://github.com/xmake-io/xmake/pull/6967): 为 C++ 和 Objective-C 添加 Swift 互操作支持 * [#6964](https://github.com/xmake-io/xmake/pull/6964): 支持通过 cuda_sdkver 参数指定 CUDA SDK 版本 * [#6963](https://github.com/xmake-io/xmake/pull/6963): 为交叉编译添加 libtool 补丁支持 * [#6974](https://github.com/xmake-io/xmake/pull/6974): 支持多行刷新进度输出显示 * [#7024](https://github.com/xmake-io/xmake/pull/7024): 为 `xmake show -t target` 命令添加 JSON 格式输出 * [#7025](https://github.com/xmake-io/xmake/pull/7025): 添加 XML 模块,支持解析和编码功能 * [#6989](https://github.com/xmake-io/xmake/pull/6989): 为 os API 添加异步操作支持 ### 改进 * [#6924](https://github.com/xmake-io/xmake/pull/6924): 改进工具链配置,支持 add_toolchains("name[configs]") 语法 * [#6935](https://github.com/xmake-io/xmake/pull/6935): 重构工具链:将 gcc/clang 的注册与定义分离 * [#6942](https://github.com/xmake-io/xmake/pull/6942): 改进文件读取性能 * [#6946](https://github.com/xmake-io/xmake/pull/6946): 为 Clang 工具链添加 LLD 链接器支持 * [#6970](https://github.com/xmake-io/xmake/pull/6970): 改进 TTY 处理和输出显示 * [#6977](https://github.com/xmake-io/xmake/pull/6977): 重构 Xcode 工具链,并将其集成到针对 Apple 设备的 LLVM 工具链中 * [#6987](https://github.com/xmake-io/xmake/pull/6987): 添加 Ghostty 终端检测支持 * [#7003](https://github.com/xmake-io/xmake/pull/7003): 限制在包配置中获取构建环境变量 * [#7008](https://github.com/xmake-io/xmake/pull/7008): 统一代码格式风格 * [#7004](https://github.com/xmake-io/xmake/pull/7004): 使用 -r 标志时跳过重建包和 std 模块 * [#7019](https://github.com/xmake-io/xmake/pull/7019): 改进 xmake.sh/configure 脚本并添加 Ninja 生成器支持 * [#7023](https://github.com/xmake-io/xmake/pull/7023): 更新 Qt TypeScript 规则 * [#7022](https://github.com/xmake-io/xmake/pull/7022): 使 zig-cc 工具链继承自 clang * [#7027](https://github.com/xmake-io/xmake/pull/7027): 改进 graph 模块性能 * [#7031](https://github.com/xmake-io/xmake/pull/7031): 改进 require 解析功能 * [#7032](https://github.com/xmake-io/xmake/pull/7032): 改进符号提取功能 * [#6952](https://github.com/xmake-io/xmake/pull/6952): 为测试添加实时输出支持 * [#6998](https://github.com/xmake-io/xmake/pull/6998): 更新 tbox 库以支持 process/argv * [#7037](https://github.com/xmake-io/xmake/pull/7037): 改进 xmake format 功能 * [#7038](https://github.com/xmake-io/xmake/pull/7038): 改进 clang-tidy 输出处理 ### Bugs 修复 * [#6926](https://github.com/xmake-io/xmake/pull/6926): 修复在 Windows 上加载包含 Unicode 字符的主脚本路径问题 * [#6931](https://github.com/xmake-io/xmake/pull/6931): 修复 C++ 模块:当工具链的 clang-scan-deps 未安装时,自动回退到系统级的 clang-scan-deps * [#6937](https://github.com/xmake-io/xmake/pull/6937): 修复目标任务处理问题 * [#6954](https://github.com/xmake-io/xmake/pull/6954): 修复 vsxmake/vs 生成器的模块支持问题 * [#6955](https://github.com/xmake-io/xmake/pull/6955): 修复包中构建号的排序问题 * [#6956](https://github.com/xmake-io/xmake/pull/6956): 修复使用不支持 depfile 的 zigcc 链接器导致的构建失败 * [#6959](https://github.com/xmake-io/xmake/pull/6959): 修复在动态链接场景下使用 zigcc 与 autotools 的问题 * [#6983](https://github.com/xmake-io/xmake/pull/6983): 修复模块:为模块重用场景去除 sanitizer 标志 * [#6984](https://github.com/xmake-io/xmake/pull/6984): 修复已安装的 CMake 导入文件中的 libdir 路径问题 * [#6993](https://github.com/xmake-io/xmake/pull/6993): 修复 xmake 测试模块相关问题 * [#6992](https://github.com/xmake-io/xmake/pull/6992): 修复模块:为 clang get_cpp_library_name 添加所有支持的平台 * [#6999](https://github.com/xmake-io/xmake/pull/6999): 修复 rootdir 处理问题 * [#7002](https://github.com/xmake-io/xmake/pull/7002): 修复 asn1c:将生成的输出文件作为系统头文件包含 * [#6996](https://github.com/xmake-io/xmake/pull/6996): 修复 Nimble find_package 以使用最新的包列表格式 * [#7012](https://github.com/xmake-io/xmake/pull/7012): 修复稀疏检出处理问题 * [#7013](https://github.com/xmake-io/xmake/pull/7013): 修复打包时移除依赖项的问题 * [#7017](https://github.com/xmake-io/xmake/pull/7017): 修复 lock_packages 的拼写错误 * [#7016](https://github.com/xmake-io/xmake/pull/7016): 修复 vsxmake 中的项目默认配置问题 * [#7018](https://github.com/xmake-io/xmake/pull/7018): 修复构建顺序:仅在禁用依赖链接继承时才禁用构建顺序 * [#7035](https://github.com/xmake-io/xmake/pull/7035): 通过更新 tbox 修复进程重定向问题 ## v3.0.4 ### 新特性 * [#6864](https://github.com/xmake-io/xmake/pull/6864): 为 `format` 任务添加默认文件过滤器 * [#6843](https://github.com/xmake-io/xmake/pull/6843): 改进 clang-tidy 支持 * [#6861](https://github.com/xmake-io/xmake/pull/6861): 重写 Nix 包管理器支持 * [#6850](https://github.com/xmake-io/xmake/pull/6850): 添加包 API 检查 * [#6874](https://github.com/xmake-io/xmake/pull/6874): 为项目包添加 scriptdir * [#6876](https://github.com/xmake-io/xmake/pull/6876): 添加 versionfiles 检查器 * [#6884](https://github.com/xmake-io/xmake/pull/6884): 在 msys2 上添加 msystem 支持 * [#6891](https://github.com/xmake-io/xmake/pull/6891): 添加协程信号量 * [#6894](https://github.com/xmake-io/xmake/pull/6894): 为 clang 工具链添加 llvm-nm * [#6918](https://github.com/xmake-io/xmake/pull/6918): 为 os.cp 添加 copy_if_different 支持 ### 改进 * [#6846](https://github.com/xmake-io/xmake/pull/6846): 改进 cmake 默认标志 * [#6849](https://github.com/xmake-io/xmake/pull/6849): 改进 jobgraph * [#6859](https://github.com/xmake-io/xmake/pull/6859): 改进检查目标标志 * [#6858](https://github.com/xmake-io/xmake/pull/6858): 修改配置标志顺序 * [#6854](https://github.com/xmake-io/xmake/pull/6854): 改进 os.curdir/os.cd * [#6866](https://github.com/xmake-io/xmake/pull/6866): 改进 os.getenvs * [#6867](https://github.com/xmake-io/xmake/pull/6867): 确保通用选项总是被插入 * [#6870](https://github.com/xmake-io/xmake/pull/6870): chore(vcpkg): 提升 vcpkg 的默认 baseline * [#6880](https://github.com/xmake-io/xmake/pull/6880): 更新 cmake_importfiles.lua * [#6872](https://github.com/xmake-io/xmake/pull/6872): 改进哈希 * [#6886](https://github.com/xmake-io/xmake/pull/6886): 减少 jobgraph 中的任务数 * [#6890](https://github.com/xmake-io/xmake/pull/6890): 更新 cmake_importfiles.lua * [#6892](https://github.com/xmake-io/xmake/pull/6892): 改进 runjobs 以减少协程调度所花费的时间 * [#6896](https://github.com/xmake-io/xmake/pull/6896): 添加哈希测试 * [#6904](https://github.com/xmake-io/xmake/pull/6904): 改进 clang 以支持 msvc 环境 * [#6915](https://github.com/xmake-io/xmake/pull/6915): 改进为二进制文件导出 def 规则 ### Bugs 修复 * [#6844](https://github.com/xmake-io/xmake/pull/6844): 修复自动生成的 .pc 文件中的版本 * [#6851](https://github.com/xmake-io/xmake/pull/6851): 修复查找 clang-scan-deps * [#6857](https://github.com/xmake-io/xmake/pull/6857): 修复在交叉编译中使用 cmake 的 rc 编译器 * [#6809](https://github.com/xmake-io/xmake/pull/6809): fix(C++ modules) 修复 stdmodule 优先级 * [#6882](https://github.com/xmake-io/xmake/pull/6882): 修复:以确定性顺序写入包清单 manifest.pathenvs * [#6888](https://github.com/xmake-io/xmake/pull/6888): 修复 clang 工具链包 * [#6889](https://github.com/xmake-io/xmake/pull/6889): 修复 os.getenvs 兼容性 * [#6900](https://github.com/xmake-io/xmake/pull/6900): package.tools.xmake: 修复策略未被传递的问题 * [#6901](https://github.com/xmake-io/xmake/pull/6901): package download: 如果禁用,则不获取子模块 * [#6907](https://github.com/xmake-io/xmake/pull/6907): package download: 如果禁用,则不获取子模块 (分支版本) ## v3.0.3 ### 新特性 * [#6778](https://github.com/xmake-io/xmake/pull/6778): 添加 build.linker.output * [#6779](https://github.com/xmake-io/xmake/pull/6779): 添加 #embed 和 embedirs 支持 * [#6787](https://github.com/xmake-io/xmake/pull/6787): 支持 vs2026 * [#6785](https://github.com/xmake-io/xmake/pull/6785): 为 wdk 规则支持 clang 和 llvm * [#6791](https://github.com/xmake-io/xmake/pull/6791): 添加 Nix 包管理器支持 * [#6800](https://github.com/xmake-io/xmake/pull/6800): 为 xrepo env 支持 nushell * [#6796](https://github.com/xmake-io/xmake/pull/6796): 启用不完整 wdk 的支持 ### 改进 * [#6765](https://github.com/xmake-io/xmake/pull/6765): 改进 bin2c 使用原生线程 * [#6771](https://github.com/xmake-io/xmake/pull/6771): 修复 find gcc/gxx 缓存 * [#6777](https://github.com/xmake-io/xmake/pull/6777): 修复 cmake 的可执行文件路径 * [#6783](https://github.com/xmake-io/xmake/pull/6783): 修复 build.c++.modules.std 策略 * [#6744](https://github.com/xmake-io/xmake/pull/6744): 当提供 --verbose 或 --diagnosis 时使用文件来存储 requires 标志 * [#6780](https://github.com/xmake-io/xmake/pull/6780): 添加基准测试并优化配置/构建目标 * [#6784](https://github.com/xmake-io/xmake/pull/6784): 继续优化构建目标速度 * [#6793](https://github.com/xmake-io/xmake/pull/6793): 使用 musl 避免 glibc 版本问题 * [#6788](https://github.com/xmake-io/xmake/pull/6788): 改进 clang 增量构建 * [#6811](https://github.com/xmake-io/xmake/pull/6811): 改进 clang-tidy * [#6810](https://github.com/xmake-io/xmake/pull/6810): 改进 cmake 的默认标志 * [#6801](https://github.com/xmake-io/xmake/pull/6801): 更改 gcc 和 clang 的编译器优先级 * [#6819](https://github.com/xmake-io/xmake/pull/6819): 改进 show target * [#6817](https://github.com/xmake-io/xmake/pull/6817): 改进构建速度 * [#6822](https://github.com/xmake-io/xmake/pull/6822): 优先使用环境变量而不是仓库缓存 * [#6824](https://github.com/xmake-io/xmake/pull/6824): 改进 has_flags * [#6832](https://github.com/xmake-io/xmake/pull/6832): 优化代码签名 ### Bugs 修复 * [#6808](https://github.com/xmake-io/xmake/pull/6808): 修复 xrepo env * [#6821](https://github.com/xmake-io/xmake/pull/6821): 清理未定义的 vsvers * [#6818](https://github.com/xmake-io/xmake/pull/6818): 修复 nix-shell 环境中的 Nix 包检测 * [#6798](https://github.com/xmake-io/xmake/pull/6798): 为 msvc 的 strippeable_flags 添加 external ## v3.0.2 ### 新特性 * [#6755](https://github.com/xmake-io/xmake/issues/6755): 添加原生线程支持 * [#6641](https://github.com/xmake-io/xmake/pull/6641): 为 `target/config` 添加 `pkgenvs` * [#6644](https://github.com/xmake-io/xmake/pull/6644): 支持使用 clang 编译 .def 文件 * [#6695](https://github.com/xmake-io/xmake/pull/6695): 为 inf2cat 添加 `/uselocaltime` 参数 * [#6709](https://github.com/xmake-io/xmake/pull/6709): 支持 wasm64 架构 * [#6737](https://github.com/xmake-io/xmake/pull/6737): 为 cython 规则添加 python 存根文件扩展 ### 改进 * [#6651](https://github.com/xmake-io/xmake/pull/6651): 改进依赖文件 * [#6656](https://github.com/xmake-io/xmake/pull/6656): 使构建工具支持传入 `opt.targets` * [#6688](https://github.com/xmake-io/xmake/pull/6688): 改进安装目标 * [#6692](https://github.com/xmake-io/xmake/pull/6692): 改进 protobuf 测试 * [#6714](https://github.com/xmake-io/xmake/pull/6714): 改进 C++ 模块测试 * [#6719](https://github.com/xmake-io/xmake/pull/6719): 改进 comax 配置 * [#6725](https://github.com/xmake-io/xmake/pull/6725): 改进 `target:extrafiles` ### Bugs 修复 * [#6648](https://github.com/xmake-io/xmake/pull/6648): 修复(qt.qmltyperegistrar): 收集 metatypes 信息 * [#6661](https://github.com/xmake-io/xmake/pull/6661): 通过设置 "--tries=1" 修复 `_ping_via_wget` 长时间阻塞的问题 * [#6665](https://github.com/xmake-io/xmake/pull/6665): 修复 cmake/mingw * [#6674](https://github.com/xmake-io/xmake/pull/6674): 尝试修复包中的 linkgroups * [#6686](https://github.com/xmake-io/xmake/pull/6686): 修复编译器缓存 * [#6698](https://github.com/xmake-io/xmake/pull/6698): 修复(C++ 模块) 处理空模块 * [#6699](https://github.com/xmake-io/xmake/pull/6699): 修复(C++ 模块) 修复删除模块文件时 xmake 不更新模块映射器的问题 * [#6706](https://github.com/xmake-io/xmake/pull/6706): 修复 CUDA 13 的 `find_cudadevices` * [#6707](https://github.com/xmake-io/xmake/pull/6707): 修复(C++ 模块) 修复 sourcebatch 缓存 * [#6712](https://github.com/xmake-io/xmake/pull/6712): 修复(C++ 模块) 修复禁用的目标被配置用于模块编译的问题 * [#6713](https://github.com/xmake-io/xmake/pull/6713): 修复(C++ 模块) 修复非 .cpp 文件从 `c++.build` sourcebatch 中被窃取的问题 * [#6715](https://github.com/xmake-io/xmake/pull/6715): 修复(C++ 模块) 修复公共剔除模块错误地发出警告的问题 * [#6718](https://github.com/xmake-io/xmake/pull/6718): 忽略 pch 标志 * [#6732](https://github.com/xmake-io/xmake/pull/6732): 修复: android ndk rust link-args * [#6735](https://github.com/xmake-io/xmake/pull/6735): 修复(qt.qmltyperegistrar): 扩展依赖项以进行重建 * [#6738](https://github.com/xmake-io/xmake/pull/6738): 修复 protobuf 的目标依赖 * [#6741](https://github.com/xmake-io/xmake/pull/6741): 修复 vsxmake 选项 * [#6747](https://github.com/xmake-io/xmake/pull/6747): `meminfo.c`: < 10.7 版本上没有 `vmstat.compressor_page_count` ## v3.0.1 ### 新特性 * [#4810](https://github.com/xmake-io/xmake/issues/4810): 添加新的原生 Xcode 工程生成插件 ### Bugs 修复 * [#6592](https://github.com/xmake-io/xmake/pull/6592): 修复 object 目标的链接问题 * [#6586](https://github.com/xmake-io/xmake/issues/6586): 修复 build.fence 策略 * [#6600](https://github.com/xmake-io/xmake/issues/6600): 修复 compile_commands 生成器 * [#6621](https://github.com/xmake-io/xmake/issues/6621): 修复 android ndk r17c 构建失败问题 * [#6635](https://github.com/xmake-io/xmake/discussions/6635): 修复 batchcmds 导致的 qt/moc 增量构建问题 ## v3.0.0 ### 新特性 * [#5926](https://github.com/xmake-io/xmake/issues/5926): 添加 MIDL 支持 * [#6414](https://github.com/xmake-io/xmake/pull/6414): 添加 platform.windows.subsystem 规则 * [#5527](https://github.com/xmake-io/xmake/issues/5527): 切换到 3.0 行为策略 ### 改进 * [#6202](https://github.com/xmake-io/xmake/issues/6202): 改进 rule API 和构建顺序支持,提供统一 jobgraph 调度 * [#5624](https://github.com/xmake-io/xmake/discussions/5624): `xmake run` 运行默认自动构建 * [#5526](https://github.com/xmake-io/xmake/discussions/5526): msvc 默认切换到 MD/MDd 运行时 * [#5545](https://github.com/xmake-io/xmake/discussions/5545): 构建 cmake 包,默认使用 Ninja 生成器 * [#6355](https://github.com/xmake-io/xmake/pull/6355): 支持自定义 implib 路径和访问 * [#6373](https://github.com/xmake-io/xmake/pull/6373): 改进 c++ modules 支持 * [#6376](https://github.com/xmake-io/xmake/issues/6476): 改进 vsxmake 生成器,支持命名空间 * [#6209](https://github.com/xmake-io/xmake/pull/6209): 添加 jobgraph 支持 * [#6361](https://github.com/xmake-io/xmake/pull/6361): 重命名 buildir 到 builddir ## v2.9.9 ### 新特性 * [#6137](https://github.com/xmake-io/xmake/issues/6137): IDE 整合 * [#6138](https://github.com/xmake-io/xmake/issues/6138): 使用 libxmake/xmake APIs 去构建二进制 * [#6154](https://github.com/xmake-io/xmake/issues/6154): 添加 kotlin native 构建支持和包依赖集成支持 * [#6279](https://github.com/xmake-io/xmake/pull/6279): 添加 msvc midl 支持 ### 改进 * [#6182](https://github.com/xmake-io/xmake/pull/6182): 改进 clang/clang-cl 支持 msstl 模块 * [#6281](https://github.com/xmake-io/xmake/pull/6281): 支持 Verilator 动态库 * [#6270](https://github.com/xmake-io/xmake/pull/6270): 改进 conan 生成器 * [#6243](https://github.com/xmake-io/xmake/pull/6243): 改进 llvm 工具链对交叉编译的支持 * 三方包安装支持 CMake 4.0 ### Bugs 修复 * [#6292](https://github.com/xmake-io/xmake/issues/6292): 修复 namespace 问题 ## v2.9.8 ### 新特性 * [#5994](https://github.com/xmake-io/xmake/issues/5994): 分析进程执行性能 * [#5995](https://github.com/xmake-io/xmake/pull/5995): 为 vs generator 添加 profile 支持 * [#5949](https://github.com/xmake-io/xmake/pull/5949): 添加 nodejs.module 规则 * [#3380](https://github.com/xmake-io/xmake/issues/3380): 添加命名空间支持 * [#5945](https://github.com/xmake-io/xmake/issues/5945): 检测 pkgconfig/cmake 导入文件 * [#6054](https://github.com/xmake-io/xmake/issues/6054): 为 linux 添加 xmake bundle 包 * [#6071](https://github.com/xmake-io/xmake/issues/6071): 改进 git 包下载,支持仅仅 clone 指定子目录 * [#5163](https://github.com/xmake-io/xmake/issues/5163): 支持 TI-CGT C2000/C6000 编译器 * [#5344](https://github.com/xmake-io/xmake/issues/5344): 支持 IAR ARM C/C++ 编译器 * [#5554](https://github.com/xmake-io/xmake/issues/5554): 添加自定义未知工具链支持 ### 改进 * [#6056](https://github.com/xmake-io/xmake/pull/6056): 添加 CI 去构建发布 windows arm64 版本。 * [#6097](https://github.com/xmake-io/xmake/pull/6097): 添加 qt_host 支持交叉编译 Qt 项目 * [#6120](https://github.com/xmake-io/xmake/issues/6120): 改进 configfiles 添加自定义预处理支持 * [#6088](https://github.com/xmake-io/xmake/issues/6088): 改进 configfiles 去生成导出宏 ### Bugs 修复 * [#272](https://github.com/tboox/tbox/issues/272): 修复 msvc + /O1 时候,错误的编译器优化导致 xmake 加载卡住 * [#6089](https://github.com/tboox/tbox/issues/6089): 修复 depend.is_changed ## v2.9.7 ### 新特性 * [#5813](https://github.com/xmake-io/xmake/pull/5813): 为 rule 添加 `before_config` 和 `after_config` * [#5848](https://github.com/xmake-io/xmake/issues/5848): 支持自定义 MSVC 构建工具, PortableBuildTools 和 msvc-wine * [#5880](https://github.com/xmake-io/xmake/pull/5880): 支持使用 msvc 包去构建工程 * [#5884](https://github.com/xmake-io/xmake/issues/5884): 为包添加自定义安装提示 * [#5894](https://github.com/xmake-io/xmake/issues/5894): 添加 package.merge_staticlibs 策略去合并包安装的静态库 * [#5948](https://github.com/xmake-io/xmake/pull/5948): 添加 `lua.native-object` 规则 * [#5911](https://github.com/xmake-io/xmake/issues/5911): 支持 nuget 包集成 ### 改进 * [#5817](https://github.com/xmake-io/xmake/pull/5817): 改进安装包的默认 pic 配置 * [#5869](https://github.com/xmake-io/xmake/pull/5869): 为 gcc 添加 libstdc++ 标准库模块的支持 * [#5923](https://github.com/xmake-io/xmake/pull/5923): 解决包依赖链中版本和配置冲突 ### Bugs 修复 * [#5856](https://github.com/xmake-io/xmake/issues/5856): 修复 c++modules 在 clang 下的编译 * [#5858](https://github.com/xmake-io/xmake/issues/5858): 修复 gcc 的头文件预编译问题 ## v2.9.6 ### 新特性 * [#5527](https://github.com/xmake-io/xmake/issues/5527): 添加 `set_policy("compatibility.version", "3.0")` 提前预览体验 3.0 特性 * [#5649](https://github.com/xmake-io/xmake/pull/5649): 添加 `package.check_fcsnippets` ### 改进 * [#5631](https://github.com/xmake-io/xmake/pull/5631): 为 `add_linkgroups` 添加 `as_needed` * [#5702](https://github.com/xmake-io/xmake/issues/5702): 改进 hash 模块 * [#5688](https://github.com/xmake-io/xmake/pull/5688): 改进 hashset * [#5711](https://github.com/xmake-io/xmake/issues/5711): 为 sdcc 支持解析 include 依赖 * [#5727](https://github.com/xmake-io/xmake/issues/5727): 为 add_requires 改进 configs 配置 * [#5762](https://github.com/xmake-io/xmake/pull/5762): 改进 bin2c 速度 ### Bugs 修复 * [#5645](https://github.com/xmake-io/xmake/issues/5645): 修复 `xmake watch` 在 linux 无法监听递归文件问题 * [#5686](https://github.com/xmake-io/xmake/pull/5686): 修复模块扫描 ## v2.9.5 ### 新特性 * [#5462](https://github.com/xmake-io/xmake/pull/5462): 添加 `xmake l cli.bisect` * [#5488](https://github.com/xmake-io/xmake/pull/5488): 支持使用 cosmocc 去构建 xmake 自身二进制 * [#5491](https://github.com/xmake-io/xmake/pull/5491): 支持提供内嵌 lua 文件的单个 xmake 二进制文件 * [#5580](https://github.com/xmake-io/xmake/issues/5580): 添加 `@builtin/xrepo` 辅助模块,为 `xrepo env shell` 实现快速设置环境变量 ### 改进 * [#5507](https://github.com/xmake-io/xmake/issues/5507): 改进 git clone 下载速度 * [#5536](https://github.com/xmake-io/xmake/pull/5536): 在 swig 模式中添加 jar 生成支持 * [#5573](https://github.com/xmake-io/xmake/issues/5573): 改进 vsxmake generator 性能 * [#5601](https://github.com/xmake-io/xmake/issues/5601): 改进 utils.symbols.export_all 规则去过滤源文件路径 ### Bugs 修复 * [#4750](https://github.com/xmake-io/xmake/issues/4750): 修复 compile_commands 生成器,支持 `xmake tests` * [#5465](https://github.com/xmake-io/xmake/pull/5465): 修复 package requires lock * [#4760](https://github.com/xmake-io/xmake/issues/4760): 修复 distcc 分布式编译问题 ## v2.9.4 ### 新特性 * [#5278](https://github.com/xmake-io/xmake/issues/5278): 添加 `build.intermediate_directory` 策略去禁用中间目录生成 * [#5313](https://github.com/xmake-io/xmake/issues/5313): 添加 windows arm/arm64ec 支持 * [#5296](https://github.com/xmake-io/xmake/issues/5296): 添加 Intel LLVM Fortran 编译器支持 * [#5384](https://github.com/xmake-io/xmake/issues/5384): 为包添加 `add_bindirs` 配置支持 ### 改进 * [#5280](https://github.com/xmake-io/xmake/issues/5280): 添加缺失的 C++20 Modules 文件扩展 * [#5251](https://github.com/xmake-io/xmake/issues/5251): 为 windows installer 更新内置的 7z/curl * [#5286](https://github.com/xmake-io/xmake/issues/5286): 改进 json 支持16进制解析 * [#5302](https://github.com/xmake-io/xmake/pull/5302): 改进 Vala 支持 * [#5335](https://github.com/xmake-io/xmake/pull/5335): 改进 `xmake install` 和 `xpack`,添加 `set_prefixdir` 接口 * [#5387](https://github.com/xmake-io/xmake/pull/5387): 改进 `xmake test` * [#5376](https://github.com/xmake-io/xmake/pull/5376): 改进 C++ module 对象列表处理和 moduleonly 包支持 ### Bugs 修复 * [#5288](https://github.com/xmake-io/xmake/issues/5288): 修复 `xmake test` 对 Unity Build 的支持 * [#5270](https://github.com/xmake-io/xmake/issues/5270): 修复 gcc/clang 对 pch 的支持 * [#5276](https://github.com/xmake-io/xmake/issues/5276): 修复查找 vc6 环境 * [#5259](https://github.com/xmake-io/xmake/issues/5259): 修复命令补全失效问题 ## v2.9.3 ### 新特性 * [#4637](https://github.com/xmake-io/xmake/issues/4637): 为 xpack 添加 mix 支持 * [#5107](https://github.com/xmake-io/xmake/issues/5107): 为 xpack 添加 deb 支持 * [#5148](https://github.com/xmake-io/xmake/issues/5148): 为包添加 on_source 配置域 ### 改进 * [#5156](https://github.com/xmake-io/xmake/issues/5156): 改进安装 cargo 包 ### 问题修复 * [#5176](https://github.com/xmake-io/xmake/pull/5176): 修复 VS toolset v144 支持 ## v2.9.2 ### 新特性 * [#5005](https://github.com/xmake-io/xmake/pull/5005): 显示所有 API * [#5003](https://github.com/xmake-io/xmake/issues/5003): 添加 build.fence 策略 * [#5060](https://github.com/xmake-io/xmake/issues/5060): 支持 Verilator 静态库目标构建 * [#5074](https://github.com/xmake-io/xmake/pull/5074): 添加 `xrepo download` 命令去快速下载包源码 * [#5086](https://github.com/xmake-io/xmake/issues/5986): 添加包检测支持 * [#5103](https://github.com/xmake-io/xmake/pull/5103): 添加 qt ts 构建支持 * [#5104](https://github.com/xmake-io/xmake/pull/5104): 改进 find_program,在 windows 上调用 where 改进查找 ### 改进 * [#5077](https://github.com/xmake-io/xmake/issues/5077): 当构建 x86 目标时,使用 x64 的 msvc 编译工具 * [#5109](https://github.com/xmake-io/xmake/issues/5109): 改进 add_rpathdirs 支持 runpath/rpath 切换 * [#5132](https://github.com/xmake-io/xmake/pull/5132): 改进 ifort/icc/icx 在 windows 上的支持 ### Bugs 修复 * [#5059](https://github.com/xmake-io/xmake/issues/5059): 修复加载大量 targets 时候卡住 * [#5029](https://github.com/xmake-io/xmake/issues/5029): 修复在 termux 上崩溃问题 ## v2.9.1 ### 新特性 * [#4874](https://github.com/xmake-io/xmake/pull/4874): 添加鸿蒙 SDK 支持 * [#4889](https://github.com/xmake-io/xmake/issues/4889): 添加 signal 模块 去注册信号处理 * [#4925](https://github.com/xmake-io/xmake/issues/4925): 添加 native 模块支持 * [#4938](https://github.com/xmake-io/xmake/issues/4938): 增加对 cppfront/h2 的支持 ### 改进 * 改进包管理,支持切换 clang-cl * [#4893](https://github.com/xmake-io/xmake/issues/4893): 改进 rc 头文件依赖检测 * [#4928](https://github.com/xmake-io/xmake/issues/4928): 改进构建和链接速度,增量编译时候效果更加明显 * [#4931](https://github.com/xmake-io/xmake/pull/4931): 更新 pdcurses * [#4973](https://github.com/xmake-io/xmake/issues/4973): 改进选择脚本的匹配模式 ### Bugs 修复 * [#4882](https://github.com/xmake-io/xmake/issues/4882): 修复安装组依赖问题 * [#4877](https://github.com/xmake-io/xmake/issues/4877): 修复 xpack 打包时,unit build 编译失败问题 * [#4887](https://github.com/xmake-io/xmake/issues/4887): 修复 object 依赖链接 ## v2.8.9 ### 新特性 * [#4843](https://github.com/xmake-io/xmake/issues/4843): 添加 check_bigendian 接口实现大小端探测 ### 改进 * [#4798](https://github.com/xmake-io/xmake/issues/4798): 改进 wasi sdk 检测 * [#4772](https://github.com/xmake-io/xmake/issues/4772): 改进 tools.cmake 去兼容支持 vs2022 preview (v144) * [#4813](https://github.com/xmake-io/xmake/issues/4813): 添加 gb2312 编码 * [#4864](https://github.com/xmake-io/xmake/issues/4864): 改进抽取符号,支持 gdb 断点调试 * [#4831](https://github.com/xmake-io/xmake/issues/4831): 改进 target:fileconfig() 支持 headerfiles * [#4846](https://github.com/xmake-io/xmake/issues/4846): 改进进度显示,解决顺序错乱问题 ### Bugs 修复 * 修复 select_script 的脚本模式匹配 * [#4763](https://github.com/xmake-io/xmake/issues/4763): 修复 {force = true} * [#4807](https://github.com/xmake-io/xmake/issues/4807): 修复 nimble::find_package * [#4857](https://github.com/xmake-io/xmake/issues/4857): 修复对 -P/-F 等基础选项的解析 ## v2.8.8 ### 改进 * 添加 `package:check_sizeof()` ### Bugs 修复 * [#4774](https://github.com/xmake-io/xmake/issues/4774): 修复 Android NDK r26b 上的 strip 支持 * [#4769](https://github.com/xmake-io/xmake/issues/4769): 修复交叉编译工具链问题 * [#4776](https://github.com/xmake-io/xmake/issues/4776): 修复 soname * [#4638](https://github.com/xmake-io/xmake/issues/4638): 修复 vsxmake generator ## v2.8.7 ### 新特性 * [#4544](https://github.com/xmake-io/xmake/issues/4544): 改进 `xmake test`,支持等待进程超时 * [#4606](https://github.com/xmake-io/xmake/pull/4606): 为 package 添加 `add_versionfiles` 接口 * [#4709](https://github.com/xmake-io/xmake/issues/4709): 添加 cosmocc 工具链支持 * [#4715](https://github.com/xmake-io/xmake/issues/4715): 在描述域添加 is_cross() 接口 * [#4747](https://github.com/xmake-io/xmake/issues/4747): 添加 `build.always_update_configfiles` 策略 ### 改进 * [#4575](https://github.com/xmake-io/xmake/issues/4575): 检测无效的域参数 * 添加更多的 loong64 支持 * 改进 dlang/dmd 对 frameworks 的支持 * [#4571](https://github.com/xmake-io/xmake/issues/4571): 改进 `xmake test` 的输出支持 * [#4609](https://github.com/xmake-io/xmake/issues/4609): 改进探测 vs 构建工具环境 * [#4614](https://github.com/xmake-io/xmake/issues/4614): 改进支持 android ndk 26b * [#4473](https://github.com/xmake-io/xmake/issues/4473): 默认启用警告输出 * [#4477](https://github.com/xmake-io/xmake/issues/4477): 改进 runtimes 去支持 libc++/libstdc++ * [#4657](https://github.com/xmake-io/xmake/issues/4657): 改进脚本的模式匹配 * [#4673](https://github.com/xmake-io/xmake/pull/4673): 重构模块支持 * [#4746](https://github.com/xmake-io/xmake/pull/4746): 为 cmake generator 添加原生 c++ modules 支持 ### Bugs 修复 * [#4596](https://github.com/xmake-io/xmake/issues/4596): 修复远程构建缓存 * [#4689](https://github.com/xmake-io/xmake/issues/4689): 修复目标依赖继承 ## v2.8.6 ### 新特性 * 添加 `network.mode` 策略 * [#1433](https://github.com/xmake-io/xmake/issues/1433): 添加 `xmake pack` 命令去生成 NSIS/zip/tar.gz/rpm/srpm/runself 安装包 * [#4435](https://github.com/xmake-io/xmake/issues/4435): 为 UnityBuild 的组模式增加 batchsize 支持 * [#4485](https://github.com/xmake-io/xmake/pull/4485): 新增 package.install_locally 策略支持 * 新增 NetBSD 支持 ### Changes * [#4484](https://github.com/xmake-io/xmake/pull/4484): 改进 swig 规则 * 改进 Haiku 支持 ### Bugs 修复 * [#4372](https://github.com/xmake-io/xmake/issues/4372): 修复 protobuf 规则 * [#4439](https://github.com/xmake-io/xmake/issues/4439): 修复 asn1c 规则 ## v2.8.5 ### 新特性 * [#1452](https://github.com/xmake-io/xmake/issues/1452): 支持链接顺序调整,链接组 * [#1438](https://github.com/xmake-io/xmake/issues/1438): 支持代码 amalgamation * [#3381](https://github.com/xmake-io/xmake/issues/3381): 添加 `xmake test` 支持 * [#4276](https://github.com/xmake-io/xmake/issues/4276): 支持自定义域 API * [#4286](https://github.com/xmake-io/xmake/pull/4286): 添加 Apple XROS 支持 * [#4345](https://github.com/xmake-io/xmake/issues/4345): 支持检测类型大小 sizeof * [#4369](https://github.com/xmake-io/xmake/pull/4369): 添加 windows.manifest.uac 策略 ### 改进 * [#4284](https://github.com/xmake-io/xmake/issues/4284): 改进内置 includes 模块 ### Bugs 修复 * [#4256](https://github.com/xmake-io/xmake/issues/4256): 为 vsxmake 生成器修复 c++ modules intellisense ## v2.8.3 ### 新特性 * [#4122](https://github.com/xmake-io/xmake/issues/4122): 支持 Lua 调试 (EmmyLua) * [#4132](https://github.com/xmake-io/xmake/pull/4132): 支持 cppfront * [#4147](https://github.com/xmake-io/xmake/issues/4147): 添加 hlsl2spv 规则 * 添加 lib.lua.package 模块 * [#4226](https://github.com/xmake-io/xmake/issues/4226): 新增 asan 相关策略和对包的支持 * 添加 `run.autobuild` 策略开启运行前自动构建 * 添加全局策略 `xmake g --policies=` ### 改进 * [#4119](https://github.com/xmake-io/xmake/issues/4119): 改进支持 emcc 工具链和 emscripten 包的整合 * [#4154](https://github.com/xmake-io/xmake/issues/4154): 添加 `xmake -r --shallow target` 去改进重建目标,避免重建所有依赖目标 * 添加全局 ccache 存储目录 * [#4137](https://github.com/xmake-io/xmake/issues/4137): 改进 Qt,支持 Qt6 for Wasm * [#4173](https://github.com/xmake-io/xmake/issues/4173): 添加 recheck 参数到 on_config * [#4200](https://github.com/xmake-io/xmake/pull/4200): 改进远程构建,支持调试本地 xmake 源码 * [#4209](https://github.com/xmake-io/xmake/issues/4209): 添加 extra 和 pedantic 警告 ### Bugs 修复 * [#4110](https://github.com/xmake-io/xmake/issues/4110): 修复 extrafiles * [#4115](https://github.com/xmake-io/xmake/issues/4115): 修复 compile_commands 生成器 * [#4199](https://github.com/xmake-io/xmake/pull/4199): 修复 compile_commands 生成器对 c++ modules 的支持 * 修复 os.mv 在 windows 上跨驱动盘失败问题 * [#4214](https://github.com/xmake-io/xmake/issues/4214): 修复 rust workspace 构建问题 ## v2.8.2 ### 新特性 * [#4002](https://github.com/xmake-io/xmake/issues/4002): 增加 soname 支持 * [#1613](https://github.com/xmake-io/xmake/issues/1613): 为 add_vectorexts 增加 avx512 和 sse4.2 支持 * [#2471](https://github.com/xmake-io/xmake/issues/2471): 添加 set_encodings API 去设置源文件和目标文件的编码 * [#4071](https://github.com/xmake-io/xmake/pull/4071): 支持 sdcc 的 stm8 汇编器 * [#4101](https://github.com/xmake-io/xmake/issues/4101): 为 c/c++ 添加 force includes * [#2384](https://github.com/xmake-io/xmake/issues/2384): 为 vs/vsxmake 生成器添加 add_extrafiles 接口 ### 改进 * [#3960](https://github.com/xmake-io/xmake/issues/3960): 改进 msys2/crt64 支持 * [#4032](https://github.com/xmake-io/xmake/pull/4032): 移除一些非常老的废弃接口 * 改进 tools.msbuild 升级 vcproj 文件 * 支持 add_requires("xmake::xxx") 包 * [#4049](https://github.com/xmake-io/xmake/issues/4049): 改进 Rust 支持交叉编译 * 改进 clang 下 c++ modules 支持 ### Bugs 修复 * 修复 macOS/Linux 上子子进程无法快速退出问题 ## v2.8.1 ### 新特性 * [#3821](https://github.com/xmake-io/xmake/pull/3821): windows 安装器添加长路径支持选项 * [#3828](https://github.com/xmake-io/xmake/pull/3828): 添加 zypper 包管理器支持 * [#3871](https://github.com/xmake-io/xmake/issues/3871): 改进 tools.msbuild 支持对 vsproj 进行自动升级 * [#3148](https://github.com/xmake-io/xmake/issues/3148): 改进 protobuf 支持 grpc * [#3889](https://github.com/xmake-io/xmake/issues/3889): add_links 支持库路径添加 * [#3912](https://github.com/orgs/xmake-io/issues/3912): 添加 set_pmxxheader 去支持 objc 预编译头 * add_links 支持库文件路径 ### 改进 * [#3752](https://github.com/xmake-io/xmake/issues/3752): 改进 windows 上 os.getenvs 的获取 * [#3371](https://github.com/xmake-io/xmake/issues/3371): 改进 tools.cmake 支持使用 ninja 去构建 wasm 包 * [#3777](https://github.com/xmake-io/xmake/issues/3777): 改进从 pkg-config 中查找包 * [#3815](https://github.com/xmake-io/xmake/pull/3815): 改进 tools.xmake 支持为 windows 平台传递工具链 * [#3857](https://github.com/xmake-io/xmake/issues/3857): 改进生成 compile_commands.json * [#3892](https://github.com/xmake-io/xmake/issues/3892): 改进包搜索,支持从描述中找包 * [#3916](https://github.com/xmake-io/xmake/issues/3916): 改进构建 swift 程序,支持模块间符号调用 * 更新 lua 运行时到 5.4.6 ### Bugs 修复 * [#3755](https://github.com/xmake-io/xmake/pull/3755): 修复 find_tool 从 xmake/packages 中查找程序 * [#3787](https://github.com/xmake-io/xmake/issues/3787): 修复从 conan 2.x 中使用包 * [#3839](https://github.com/orgs/xmake-io/discussions/3839): 修复 conan 2.x 包的 vs_runtime 设置 ## v2.7.9 ### 新特性 * [#3613](https://github.com/xmake-io/xmake/issues/3613): 添加 `wasm.preloadfiles` 扩展配置 * [#3703](https://github.com/xmake-io/xmake/pull/3703): 支持 conan >=2.0.5 ### 改进 * [#3669](https://github.com/xmake-io/xmake/issues/3669): 改进 cmake 生成器支持特定工具的 cxflags * [#3679](https://github.com/xmake-io/xmake/issues/3679): 改进 `xrepo clean` * [#3662](https://github.com/xmake-io/xmake/issues/3662): 改进 cmake/make 生成器去更好的支持 lex/yacc 工程 * [#3697](https://github.com/xmake-io/xmake/issues/3662): 改进 trybuild/cmake * [#3730](https://github.com/xmake-io/xmake/issues/3730): 改进 c++modules 包安装,解决不同目录同名文件分发冲突问题 ### Bugs 修复 * [#3596](https://github.com/xmake-io/xmake/issues/3596): 修复 check_cxxfuncs 和 check_cxxsnippets * [#3603](https://github.com/xmake-io/xmake/issues/3603): 修复 xmake update 的无效 url * [#3614](https://github.com/xmake-io/xmake/issues/3614): 修复 xmake run 对 Qt 环境的加载 * [#3628](https://github.com/xmake-io/xmake/issues/3628): 修复 msys2/mingw 下 os.exec 总是优先查找错误的可执行程序 * 修复 msys/mingw 下环境变量设置问题 ## v2.7.8 ### 新特性 * [#3518](https://github.com/xmake-io/xmake/issues/3518): 分析编译和链接性能 * [#3522](https://github.com/xmake-io/xmake/issues/3522): 为 target 添加 has_cflags, has_xxx 等辅助接口 * [#3537](https://github.com/xmake-io/xmake/issues/3537): 为 clang.tidy 检测器添加 `--fix` 自动修复 ### 改进 * [#3433](https://github.com/xmake-io/xmake/issues/3433): 改进 QT 在 msys2/mingw64 和 wasm 上的构建支持 * [#3419](https://github.com/xmake-io/xmake/issues/3419): 支持 fish shell 环境 * [#3455](https://github.com/xmake-io/xmake/issues/3455): Dlang 增量编译支持 * [#3498](https://github.com/xmake-io/xmake/issues/3498): 改进绑定包虚拟环境 * [#3504](https://github.com/xmake-io/xmake/pull/3504): 添加 swig java 支持 * [#3508](https://github.com/xmake-io/xmake/issues/3508): 改进 trybuild/cmake 去支持工具链切换 * 为 msvc 禁用 build cache 加速,因为 msvc 的预处理器太慢,反而极大影响构建性能。 ### Bugs 修复 * [#3436](https://github.com/xmake-io/xmake/issues/3436): 修复自动补全和 menuconf * [#3463](https://github.com/xmake-io/xmake/issues/3463): 修复 c++modules 缓存问题 * [#3545](https://github.com/xmake-io/xmake/issues/3545): 修复 armcc 的头文件依赖解析 ## v2.7.7 ### 新特性 * 添加 Haiku 支持 * [#3326](https://github.com/xmake-io/xmake/issues/3326): 添加 `xmake check` 去检测工程代码 (clang-tidy) 和 API 参数配置 * [#3332](https://github.com/xmake-io/xmake/pull/3332): 在包中配置添加自定义 http headers ### 改进 * [#3318](https://github.com/xmake-io/xmake/pull/3318): 改进 dlang 工具链 * [#2591](https://github.com/xmake-io/xmake/issues/2591): 改进 target 配置来源分析 * 为 dmd/ldc2 改进 strip/optimization * [#3342](https://github.com/xmake-io/xmake/issues/3342): 改进配置构建目录,支持外置目录构建,保持远吗目录更加干净 * [#3373](https://github.com/xmake-io/xmake/issues/3373): 为 clang-17 改进 std 模块支持 ### Bugs 修复 * [#3317](https://github.com/xmake-io/xmake/pull/3317): 针对 Qt 工程,修复 lanuages 设置 * [#3321](https://github.com/xmake-io/xmake/issues/3321): 修复隔天 configfiles 重新生成导致重编问题 * [#3296](https://github.com/xmake-io/xmake/issues/3296): 修复 macOS arm64 上构建失败 ## v2.7.6 ### 新特性 * [#3228](https://github.com/xmake-io/xmake/pull/3228): C++ modules 的安装发布,以及从包中导入 C++ modules 支持 * [#3257](https://github.com/xmake-io/xmake/issues/3257): 增加对 iverilog 和 verilator 的支持 * 支持 xp 和 vc6.0 * [#3214](https://github.com/xmake-io/xmake/pull/3214): xrepo install 的自动补全支持 ### 改进 * [#3255](https://github.com/xmake-io/xmake/pull/3225): 改进 clang libc++ 模块支持 * 支持使用 mingw 编译 xmake * 改进 xmake 在 win xp 上的兼容性 * 如果外部依赖被启用,切换 json 模块到纯 lua 实现,移除对 lua-cjson 的依赖 ### Bugs 修复 * [#3229](https://github.com/xmake-io/xmake/issues/3229): 修复 vs2015 下找不到 rc.exe 问题 * [#3271](https://github.com/xmake-io/xmake/issues/3271): 修复支持带有空格的宏定义 * [#3273](https://github.com/xmake-io/xmake/issues/3273): 修复 nim 链接错误 * [#3286](https://github.com/xmake-io/xmake/issues/3286): 修复 compile_commands 对 clangd 的支持 ## v2.7.5 ### 新特性 * [#3201](https://github.com/xmake-io/xmake/pull/3201): 为 xrepo 添加命令自动补全 * [#3233](https://github.com/xmake-io/xmake/issues/3233): 添加 MASM32 sdk 工具链 ### 改进 * [#3216](https://github.com/xmake-io/xmake/pull/3216): 改进 intel one api toolkits 探测 * [#3020](https://github.com/xmake-io/xmake/issues/3020): 添加 `--lsp=clangd` 去改进 compile_commands.json 的生成 * [#3215](https://github.com/xmake-io/xmake/issues/3215): 添加 includedirs 和 defines 到 c51 编译器 * [#3251](https://github.com/xmake-io/xmake/issues/3251): 改进 zig and c 混合编译 ### Bugs 修复 * [#3203](https://github.com/xmake-io/xmake/issues/3203): 修复 compile_commands * [#3222](https://github.com/xmake-io/xmake/issues/3222): 修复 objc 的预编译头支持 * [#3240](https://github.com/xmake-io/xmake/pull/3240): 修复 `xmake run` 处理单个参数不正确问题 * [#3238](https://github.com/xmake-io/xmake/pull/3238): 修复 clang 构建 module 时候,并行写入 mapper 冲突问题 ## v2.7.4 ### 新特性 * [#3049](https://github.com/xmake-io/xmake/pull/3049): 添加 `xmake format` 插件 * 添加 `plugin.compile_commands.autoupdate` 规则 * [#3172](https://github.com/xmake-io/xmake/pull/3172): 添加 xmake.sh * [#3168](https://github.com/xmake-io/xmake/pull/3168): 为 msvc 添加 C++23 标准模块支持 ### 改进 * [#3056](https://github.com/xmake-io/xmake/issues/3056): 改进 Zig 支持 * [#3060](https://github.com/xmake-io/xmake/issues/3060): 改进支持 msys2 的环境探测 * [#3071](https://github.com/xmake-io/xmake/issues/3071): 为 llvm/clang 工具链支持 rc 编译 * [#3122](https://github.com/xmake-io/xmake/pull/3122): 改进 c++20 模块依赖图的源码分析,支持预处理 * [#3125](https://github.com/xmake-io/xmake/pull/3125): 增加私有 C++20 模块的编译支持 * [#3133](https://github.com/xmake-io/xmake/pull/3133): 增加 internal partitions 模块支持 * [#3146](https://github.com/xmake-io/xmake/issues/3146): 添加默认包组件支持 * [#3192](https://github.com/xmake-io/xmake/issues/3192): 为 auto complete 增加 json 输出支持 ### Bugs 修复 * 修复 requires-lock 问题 * [#3065](https://github.com/xmake-io/xmake/issues/3065): 修复部分依赖包没有被安装的问题 * [#3082](https://github.com/xmake-io/xmake/issues/3082): 修复 build.ninja 生成器 * [#3092](https://github.com/xmake-io/xmake/issues/3092): 修复 xrepo add-repo 添加失败逻辑 * [#3013](https://github.com/xmake-io/xmake/issues/3013): 修复支持 windows UNC 路径 * [#2902](https://github.com/xmake-io/xmake/issues/2902): 修复文件被其他子进程占用问题 * [#3074](https://github.com/xmake-io/xmake/issues/3074): 修复 CMakelists 生成器链接参数设置不对问题 * [#3141](https://github.com/xmake-io/xmake/pull/3141): 修复 C++ 模块的导入顺序 * 修复 tools/xmake 包安装构建目录 * [#3159](https://github.com/xmake-io/xmake/issues/3159): 为 CLion 修复 compile_commands ## v2.7.3 ### 新特性 * 一种新的可选域配置语法,对 LSP 友好,并且支持域隔离。 * [#2944](https://github.com/xmake-io/xmake/issues/2944): 为嵌入式工程添加 `gnu-rm.binary` 和 `gnu-rm.static` 规则和测试工程 * [#2636](https://github.com/xmake-io/xmake/issues/2636): 支持包组件 * 支持 msvc 的 armasm/armasm64 * [#3023](https://github.com/xmake-io/xmake/pull/3023): 改进 xmake run -d,添加 renderdoc 调试器支持 * [#3022](https://github.com/xmake-io/xmake/issues/3022): 为特定编译器添加 flags * [#3025](https://github.com/xmake-io/xmake/pull/3025): 新增 C++ 异常接口配置 * [#3017](https://github.com/xmake-io/xmake/pull/3017): 支持 ispc 编译器规则 ### 改进 * [#2925](https://github.com/xmake-io/xmake/issues/2925): 改进 doxygen 插件 * [#2948](https://github.com/xmake-io/xmake/issues/2948): 支持 OpenBSD * 添加 `xmake g --insecure-ssl=y` 配置选项去禁用 ssl 证书检测 * [#2971](https://github.com/xmake-io/xmake/pull/2971): 使 vs/vsxmake 工程生成的结果每次保持一致 * [#3000](https://github.com/xmake-io/xmake/issues/3000): 改进 C++ 模块构建支持,实现增量编译支持 * [#3016](https://github.com/xmake-io/xmake/pull/3016): 改进 clang/msvc 去更好地支持 std 模块 ### Bugs 修复 * [#2949](https://github.com/xmake-io/xmake/issues/2949): 修复 vs 分组 * [#2952](https://github.com/xmake-io/xmake/issues/2952): 修复 armlink 处理长命令失败问题 * [#2954](https://github.com/xmake-io/xmake/issues/2954): 修复 c++ module partitions 路径无效问题 * [#3033](https://github.com/xmake-io/xmake/issues/3033): 探测循环模块依赖 ## v2.7.2 ### 新特性 * [#2140](https://github.com/xmake-io/xmake/issues/2140): 支持 Windows Arm64 * [#2719](https://github.com/xmake-io/xmake/issues/2719): 添加 `package.librarydeps.strict_compatibility` 策略严格限制包依赖兼容性 * [#2810](https://github.com/xmake-io/xmake/pull/2810): 支持 os.execv 去执行 shell 脚本文件 * [#2817](https://github.com/xmake-io/xmake/pull/2817): 改进规则支持依赖顺序执行 * [#2824](https://github.com/xmake-io/xmake/pull/2824): 传递 cross-file 交叉编译环境给 meson.install 和 trybuild * [#2856](https://github.com/xmake-io/xmake/pull/2856): xrepo 支持从当前指定源码目录调试程序 * [#2859](https://github.com/xmake-io/xmake/issues/2859): 改进对三方库的 trybuild 构建,利用 xmake-repo 仓库脚本更加智能化地构建三方库 * [#2879](https://github.com/xmake-io/xmake/issues/2879): 更好的动态创建和配置 target 和 rule * [#2374](https://github.com/xmake-io/xmake/issues/2374): 允许 xmake 包中引入自定义规则 * 添加 clang-cl 工具链 ### 改进 * [#2745](https://github.com/xmake-io/xmake/pull/2745): 改进 os.cp 支持符号链接复制 * [#2773](https://github.com/xmake-io/xmake/pull/2773): 改进 vcpkg 包安装,支持 freebsd 平台 * [#2778](https://github.com/xmake-io/xmake/pull/2778): 改进 xrepo.env 支持 target 的运行环境加载 * [#2783](https://github.com/xmake-io/xmake/issues/2783): 添加摘要算法选项到 WDK 的 signtool 签名工具 * [#2787](https://github.com/xmake-io/xmake/pull/2787): 改进 json 支持空数组 * [#2782](https://github.com/xmake-io/xmake/pull/2782): 改进查找 matlib sdk 和运行时 * [#2793](https://github.com/xmake-io/xmake/issues/2793): 改进 mconfdialog 配置操作体验 * [#2804](https://github.com/xmake-io/xmake/issues/2804): 安装依赖包支持 macOS arm64/x86_64 交叉编译 * [#2809](https://github.com/xmake-io/xmake/issues/2809): 改进 msvc 的编译优化选项 * 改进 trybuild 模式,为 meson/autoconf/cmake 提供更好的交叉编译支持 * [#2846](https://github.com/xmake-io/xmake/discussions/2846): 改进对 configfiles 的生成 * [#2866](https://github.com/xmake-io/xmake/issues/2866): 更好地控制 rule 规则执行顺序 ### Bugs 修复 * [#2740](https://github.com/xmake-io/xmake/issues/2740): 修复 msvc 构建 C++ modules 卡死问题 * [#2875](https://github.com/xmake-io/xmake/issues/2875): 修复构建 linux 驱动错误 * [#2885](https://github.com/xmake-io/xmake/issues/2885): 修复 ccache 下,msvc 编译 pch 失败问题 ## v2.7.1 ### 新特性 * [#2555](https://github.com/xmake-io/xmake/issues/2555): 添加 fwatcher 模块和 `xmake watch` 插件命令 * 添加 `xmake service --pull 'build/**' outputdir` 命令去拉取远程构建服务器上的文件 * [#2641](https://github.com/xmake-io/xmake/pull/2641): 改进 C++20 模块, 支持 headerunits 和 project 生成 * [#2679](https://github.com/xmake-io/xmake/issues/2679): 支持 Mac Catalyst 构建 ### 改进 * [#2576](https://github.com/xmake-io/xmake/issues/2576): 改进从 cmake 中查找包,提供更过灵活的可选配置 * [#2577](https://github.com/xmake-io/xmake/issues/2577): 改进 add_headerfiles(),增加 `{install = false}` 支持 * [#2603](https://github.com/xmake-io/xmake/issues/2603): 为 ccache 默认禁用 `-fdirectives-only` * [#2580](https://github.com/xmake-io/xmake/issues/2580): 设置 stdout 到 line 缓冲输出 * [#2571](https://github.com/xmake-io/xmake/issues/2571): 改进分布式编译的调度算法,增加 cpu/memory 状态权重 * [#2410](https://github.com/xmake-io/xmake/issues/2410): 改进 cmakelists 生成 * [#2690](https://github.com/xmake-io/xmake/issues/2690): 改机传递 toolchains 到包 * [#2686](https://github.com/xmake-io/xmake/issues/2686): 改进 armcc/armclang 支持增量编译 * [#2562](https://github.com/xmake-io/xmake/issues/2562): 改进 rc.exe 对引用文件依赖的解析和增量编译支持 * 改进默认的并行构建任务数 ### Bugs 修复 * [#2614](https://github.com/xmake-io/xmake/issues/2614): 为 msvc 修复构建 submodules2 测试工程 * [#2620](https://github.com/xmake-io/xmake/issues/2620): 修复构建缓存导致的增量编译问题 * [#2177](https://github.com/xmake-io/xmake/issues/2177): 修复 python.library 在 macOS 上段错误崩溃 * [#2708](https://github.com/xmake-io/xmake/issues/2708): 修复 mode.coverage 规则的链接错误 * 修复 ios/macOS framework 和 application 的 rpath 加载路径 ## v2.6.9 ### 新特性 * [#2474](https://github.com/xmake-io/xmake/issues/2474): 添加 icx 和 dpcpp 工具链 * [#2523](https://github.com/xmake-io/xmake/issues/2523): 改进对 LTO 的支持 * [#2527](https://github.com/xmake-io/xmake/issues/2527): 添加 set_runargs 接口 ### 改进 * 改进 tools.cmake 支持 wasm 库构建 * [#2491](https://github.com/xmake-io/xmake/issues/2491): 如果服务器不可访问,自动回退到本地编译和缓存 * [#2514](https://github.com/xmake-io/xmake/issues/2514): 为工程生成器禁用 Unity Build * [#2473](https://github.com/xmake-io/xmake/issues/2473): 改进 apt::find_package,支持从 pc 文件中查找 * [#2512](https://github.com/xmake-io/xmake/issues/2512): 改进远程服务支持超时配置 ### Bugs 修复 * [#2488](https://github.com/xmake-io/xmake/issues/2488): 修复从 windows 到 linux 的远程编译路径问题 * [#2504](https://github.com/xmake-io/xmake/issues/2504): 修复在 msys2 上远程编译失败问题 * [#2525](https://github.com/xmake-io/xmake/issues/2525): 修复安装依赖包时候卡死问题 * [#2557](https://github.com/xmake-io/xmake/issues/2557): 修复 cmake.find_package 查找 links 错误 * 修复缓存导致的预处理文件路径冲突问题 ## v2.6.8 ### 新特性 * [#2447](https://github.com/xmake-io/xmake/pull/2447): 添加 qt.qmlplugin 规则和 qmltypesregistrar 支持 * [#2446](https://github.com/xmake-io/xmake/issues/2446): 支持 target 分组安装 * [#2469](https://github.com/xmake-io/xmake/issues/2469): 产生 vcpkg-configuration.json ### 改进 * 添加 `preprocessor.linemarkers` 策略去禁用 linemarkers 去加速 ccache/distcc * [#2389](https://github.com/xmake-io/xmake/issues/2389): 改进 `xmake run` 支持并行运行目标程序 * [#2417](https://github.com/xmake-io/xmake/issues/2417): 切换 option/showmenu 的默认值,默认开启 * [#2440](https://github.com/xmake-io/xmake/pull/2440): 改进安装包的失败错误信息 * [#2438](https://github.com/xmake-io/xmake/pull/2438): 确保生成的 vsxmake 工程不会随机变动 * [#2434](https://github.com/xmake-io/xmake/issues/2434): 改进插件管理器,允许多插件管理 * [#2421](https://github.com/xmake-io/xmake/issues/2421): 改进配置选项菜单 * [#2425](https://github.com/xmake-io/xmake/issues/2425): 添加 `preprocessor.gcc.directives_only` 策略 * [#2455](https://github.com/xmake-io/xmake/issues/2455): 改进 emcc 的优化选项 * [#2467](https://github.com/xmake-io/xmake/issues/2467): 支持回退到原始文件编译,兼容 msvc 预处理器的一些问题 * [#2452](https://github.com/xmake-io/xmake/issues/2452): 添加 build.warning 策略 ### Bugs 修复 * [#2435](https://github.com/xmake-io/xmake/pull/2435): 修复无法搜索带有 `.` 的包名 * [#2445](https://github.com/xmake-io/xmake/issues/2445): 修复 windows 上 ccache 构建失败问题 * [#2452](https://github.com/xmake-io/xmake/issues/2452): 修复 ccache 下,警告无法输出的问题 ## v2.6.7 ### 新特性 * [#2318](https://github.com/xmake-io/xmake/issues/2318): 添加 `xmake f --policies=` 配置参数去修改默认策略 ### 改进 * 如果预编译包构建失败,自动回退到源码包构建 * [#2387](https://github.com/xmake-io/xmake/issues/2387): 改进 pkgconfig 和 find_package * 添加 `build.ccache` 策略,用于在工程中配置编译缓存 ### Bugs 修复 * [#2382](https://github.com/xmake-io/xmake/issues/2382): 修改 headeronly 包配置 * [#2388](https://github.com/xmake-io/xmake/issues/2388): 修复路径问题 * [#2385](https://github.com/xmake-io/xmake/issues/2385): 修复 cmake/find_package * [#2395](https://github.com/xmake-io/xmake/issues/2395): 修复 c++ modules * 修复 find_qt 问题 ## v2.6.6 ### 新特性 * [#2327](https://github.com/xmake-io/xmake/issues/2327): 支持 nvidia-hpc-sdk 工具链中的 nvc/nvc++/nvfortran 编译器 * 添加 path 实例接口 * [#2344](https://github.com/xmake-io/xmake/pull/2344): 添加 lz4 压缩模块 * [#2349](https://github.com/xmake-io/xmake/pull/2349): 添加 keil/c51 工程支持 * [#274](https://github.com/xmake-io/xmake/issues/274): 跨平台分布式编译支持 * 使用内置的本地缓存替代 ccache ### 改进 * [#2309](https://github.com/xmake-io/xmake/issues/2309): 远程编译支持用户授权验证 * 改进远程编译,增加对 lz4 压缩支持 ### Bugs 修复 * 修复选择包版本时候 lua 栈不平衡导致的崩溃问题 ## v2.6.5 ### 新特性 * [#2138](https://github.com/xmake-io/xmake/issues/2138): 支持模板包 * [#2185](https://github.com/xmake-io/xmake/issues/2185): 添加 `--appledev=simulator` 去改进 Apple 模拟器目标编译支持 * [#2227](https://github.com/xmake-io/xmake/issues/2227): 改进 cargo 包,支持指定 Cargo.toml 文件 * 改进 `add_requires` 支持 git command 作为版本 * [#622](https://github.com/xmake-io/xmake/issues/622): 支持远程编译 * [#2282](https://github.com/xmake-io/xmake/issues/2282): 添加 `add_filegroups` 接口为 vs/vsxmake/cmake generator 增加文件组支持 ### 改进 * [#2137](https://github.com/xmake-io/xmake/pull/2137): 改进 path 模块 * macOS 下,减少 50% 的 Xmake 二进制文件大小 * 改进 tools/autoconf,cmake 去更好地支持工具链切换 * [#2221](https://github.com/xmake-io/xmake/pull/2221): 改进注册表 api 去支持 unicode * [#2225](https://github.com/xmake-io/xmake/issues/2225): 增加对 protobuf 的依赖分析和构建支持 * [#2265](https://github.com/xmake-io/xmake/issues/2265): 排序 CMakeLists.txt * 改进 os.files 的文件遍历速度 ### Bugs 修复 * [#2233](https://github.com/xmake-io/xmake/issues/2233): 修复 c++ modules 依赖 ## v2.6.4 ### 新特性 * [#2011](https://github.com/xmake-io/xmake/issues/2011): 支持继承和局部修改官方包,例如对现有的包更换 urls 和 versions * 支持在 sparc, alpha, powerpc, s390x 和 sh4 上编译运行 xmake * 为 package() 添加 on_download 自定义下载 * [#2021](https://github.com/xmake-io/xmake/issues/2021): 支持 Linux/Windows 下构建 Swift 程序 * [#2024](https://github.com/xmake-io/xmake/issues/2024): 添加 asn1c 支持 * [#2031](https://github.com/xmake-io/xmake/issues/2031): 为 add_files 增加 linker scripts 和 version scripts 支持 * [#2033](https://github.com/xmake-io/xmake/issues/2033): 捕获 ctrl-c 去打印当前运行栈,用于调试分析卡死问题 * [#2059](https://github.com/xmake-io/xmake/pull/2059): 添加 `xmake update --integrate` 命令去整合 shell * [#2070](https://github.com/xmake-io/xmake/issues/2070): 添加一些内置的 xrepo env 环境配置 * [#2117](https://github.com/xmake-io/xmake/pull/2117): 支持为任意平台传递工具链到包 * [#2121](https://github.com/xmake-io/xmake/issues/2121): 支持导出指定的符号列表,可用于减少动态库的大小 ### 改进 * [#2036](https://github.com/xmake-io/xmake/issues/2036): 改进 xrepo 支持从配置文件批量安装包,例如:`xrepo install xxx.lua` * [#2039](https://github.com/xmake-io/xmake/issues/2039): 改进 vs generator 的 filter 目录展示 * [#2025](https://github.com/xmake-io/xmake/issues/2025): 支持为 phony 和 headeronly 目标生成 vs 工程 * 优化 vs 和 codesign 的探测速度 * [#2077](https://github.com/xmake-io/xmake/issues/2077): 改进 vs 工程生成器去支持 cuda ### Bugs 修复 * [#2005](https://github.com/xmake-io/xmake/issues/2005): 修复 path.extension * [#2008](https://github.com/xmake-io/xmake/issues/2008): 修复 windows manifest 文件编译 * [#2016](https://github.com/xmake-io/xmake/issues/2016): 修复 vs project generator 里,对象文件名冲突导致的编译失败 ## v2.6.3 ### 新特性 * [#1298](https://github.com/xmake-io/xmake/issues/1928): 支持 vcpkg 清单模式安装包,实现安装包的版本选择 * [#1896](https://github.com/xmake-io/xmake/issues/1896): 添加 `python.library` 规则去构建 pybind 模块,并且支持 soabi * [#1939](https://github.com/xmake-io/xmake/issues/1939): 添加 `remove_files`, `remove_headerfiles` 并且标记 `del_files` 作为废弃接口 * 将 on_config 作为正式的公开接口,用于 target 和 rule * 添加 riscv32/64 支持 * [#1970](https://github.com/xmake-io/xmake/issues/1970): 添加 CMake wrapper 支持在 CMakelists 中去调用 xrepo 集成 C/C++ 包 * 添加内置的 github 镜像加速 pac 代理文件, `xmake g --proxy_pac=github_mirror.lua` ### 改进 * [#1923](https://github.com/xmake-io/xmake/issues/1923): 改进构建 linux 驱动,支持设置自定义 linux-headers 路径 * [#1962](https://github.com/xmake-io/xmake/issues/1962): 改进 armclang 工具链去支持构建 asm * [#1959](https://github.com/xmake-io/xmake/pull/1959): 改进 vstudio 工程生成器 * [#1969](https://github.com/xmake-io/xmake/issues/1969): 添加默认的 option 描述 ### Bugs 修复 * [#1875](https://github.com/xmake-io/xmake/issues/1875): 修复部署生成 Android Qt 程序包失败问题 * [#1973](https://github.com/xmake-io/xmake/issues/1973): 修复合并静态库 * [#1982](https://github.com/xmake-io/xmake/pull/1982): 修复 clang 下对 c++20 子模块的依赖构建 ## v2.6.2 ### 新特性 * [#1902](https://github.com/xmake-io/xmake/issues/1902): 支持构建 linux 内核驱动模块 * [#1913](https://github.com/xmake-io/xmake/issues/1913): 通过 group 模式匹配,指定构建和运行一批目标程序 ### 改进 * [#1872](https://github.com/xmake-io/xmake/issues/1872): 支持转义 set_configvar 中字符串值 * [#1888](https://github.com/xmake-io/xmake/issues/1888): 改进 windows 安装器,避免错误删除其他安装目录下的文件 * [#1895](https://github.com/xmake-io/xmake/issues/1895): 改进 `plugin.vsxmake.autoupdate` 规则 * [#1893](https://github.com/xmake-io/xmake/issues/1893): 改进探测 icc 和 ifort 工具链 * [#1905](https://github.com/xmake-io/xmake/pull/1905): 改进 msvc 对 external 头文件搜索探测支持 * [#1904](https://github.com/xmake-io/xmake/pull/1904): 改进 vs201x 工程生成器 * 添加 `XMAKE_THEME` 环境变量去切换主题配置 * [#1907](https://github.com/xmake-io/xmake/issues/1907): 添加 `-f/--force` 参数使得 `xmake create` 可以在费控目录被强制创建 * [#1917](https://github.com/xmake-io/xmake/pull/1917): 改进 find_package 和配置 ### Bugs 修复 * [#1885](https://github.com/xmake-io/xmake/issues/1885): 修复 package:fetch_linkdeps 链接顺序问题 * [#1903](https://github.com/xmake-io/xmake/issues/1903): 修复包链接顺序 ## v2.6.1 ### 新特性 * [#1799](https://github.com/xmake-io/xmake/issues/1799): 支持混合 Rust 和 C++ 程序,以及集成 Cargo 依赖库 * 添加 `utils.glsl2spv` 规则去编译 *.vert/*.frag shader 文件生成 spirv 文件和二进制 C 头文件 ### 改进 * 默认切换到 Lua5.4 运行时 * [#1776](https://github.com/xmake-io/xmake/issues/1776): 改进 system::find_package,支持从环境变量中查找系统库 * [#1786](https://github.com/xmake-io/xmake/issues/1786): 改进 apt:find_package,支持查找 alias 包 * [#1819](https://github.com/xmake-io/xmake/issues/1819): 添加预编译头到 cmake 生成器 * 改进 C++20 Modules 为 msvc 支持 std 标准库 * [#1792](https://github.com/xmake-io/xmake/issues/1792): 添加自定义命令到 vs 工程生成器 * [#1835](https://github.com/xmake-io/xmake/issues/1835): 改进 MDK 程序构建支持,增加 `set_runtimes("microlib")` * [#1858](https://github.com/xmake-io/xmake/issues/1858): 改进构建 c++20 modules,修复跨 target 构建问题 * 添加 $XMAKE_BINARY_REPO 和 $XMAKE_MAIN_REPO 仓库设置环境变量 * [#1865](https://github.com/xmake-io/xmake/issues/1865): 改进 openmp 工程 * [#1845](https://github.com/xmake-io/xmake/issues/1845): 为静态库安装 pdb 文件 ### Bugs 修复 * 修复语义版本中解析带有 0 前缀的 build 字符串问题 * [#50](https://github.com/libbpf/libbpf-bootstrap/issues/50): 修复 rule 和构建 bpf 程序 bug * [#1610](https://github.com/xmake-io/xmake/issues/1610): 修复 `xmake f --menu` 在 vscode 终端下按键无响应,并且支持 ConPTY 终端虚拟按键 ## v2.5.9 ### 新特性 * [#1736](https://github.com/xmake-io/xmake/issues/1736): 支持 wasi-sdk 工具链 * 支持 Lua 5.4 运行时 * 添加 gcc-8, gcc-9, gcc-10, gcc-11 工具链 * [#1623](https://github.com/xmake-io/xmake/issues/1632): 支持 find_package 从 cmake 查找包 * [#1747](https://github.com/xmake-io/xmake/issues/1747): 添加 `set_kind("headeronly")` 更好的处理 headeronly 库的安装 * [#1019](https://github.com/xmake-io/xmake/issues/1019): 支持 Unity build * [#1438](https://github.com/xmake-io/xmake/issues/1438): 增加 `xmake l cli.amalgamate` 命令支持代码合并 * [#1765](https://github.com/xmake-io/xmake/issues/1756): 支持 nim 语言 * [#1762](https://github.com/xmake-io/xmake/issues/1762): 为 `xrepo env` 管理和切换指定的环境配置 * [#1767](https://github.com/xmake-io/xmake/issues/1767): 支持 Circle 编译器 * [#1753](https://github.com/xmake-io/xmake/issues/1753): 支持 Keil/MDK 的 armcc/armclang 工具链 * [#1774](https://github.com/xmake-io/xmake/issues/1774): 添加 table.contains api * [#1735](https://github.com/xmake-io/xmake/issues/1735): 添加自定义命令到 cmake 生成器 * [#1781](https://github.com/xmake-io/xmake/issues/1781): 改进 get.sh 安装脚本支持 nixos ### 改进 * [#1528](https://github.com/xmake-io/xmake/issues/1528): 检测 c++17/20 特性 * [#1729](https://github.com/xmake-io/xmake/issues/1729): 改进 C++20 modules 对 clang/gcc/msvc 的支持,支持模块间依赖编译和并行优化 * [#1779](https://github.com/xmake-io/xmake/issues/1779): 改进 ml.exe/x86,移除内置的 `-Gd` 选项 ## v2.5.8 ### 新特性 * [#388](https://github.com/xmake-io/xmake/issues/388): Pascal 语言支持,可以使用 fpc 来编译 free pascal * [#1682](https://github.com/xmake-io/xmake/issues/1682): 添加可选的额lua5.3 运行时替代 luajit,提供更好的平台兼容性。 * [#1622](https://github.com/xmake-io/xmake/issues/1622): 支持 Swig * [#1714](https://github.com/xmake-io/xmake/issues/1714): 支持内置 cmake 等第三方项目的混合编译 * [#1715](https://github.com/xmake-io/xmake/issues/1715): 支持探测编译器语言标准特性,并且新增 `check_macros` 检测接口 * xmake 支持在 Loongarch 架构上运行 ### 改进 * [#1618](https://github.com/xmake-io/xmake/issues/1618): 改进 vala 支持构建动态库和静态库程序 * 改进 Qt 规则去支持 Qt 4.x * 改进 `set_symbols("debug")` 支持 clang/windows 生成 pdb 文件 * [#1638](https://github.com/xmake-io/xmake/issues/1638): 改进合并静态库 * 改进 on_load/after_load 去支持动态的添加 target deps * [#1675](https://github.com/xmake-io/xmake/pull/1675): 针对 mingw 平台,重命名动态库和导入库文件名后缀 * [#1694](https://github.com/xmake-io/xmake/issues/1694): 支持在 set_configvar 中定义一个不带引号的字符串变量 * 改进对 Android NDK r23 的支持 * 为 `set_languages` 新增 `c++latest` 和 `clatest` 配置值 * [#1720](https://github.com/xmake-io/xmake/issues/1720): 添加 `save_scope` 和 `restore_scope` 去修复 `check_xxx` 相关接口 * [#1726](https://github.com/xmake-io/xmake/issues/1726): 改进 compile_commands 生成器去支持 nvcc ### Bugs 修复 * [#1671](https://github.com/xmake-io/xmake/issues/1671): 修复安装预编译包后,*.cmake 里面的一些不正确的绝对路径 * [#1689](https://github.com/xmake-io/xmake/issues/1689): 修复 vsxmake 插件的 unicode 字符显示和加载问题 ## v2.5.7 ### 新特性 * [#1534](https://github.com/xmake-io/xmake/issues/1534): 新增对 Vala 语言的支持 * [#1544](https://github.com/xmake-io/xmake/issues/1544): 添加 utils.bin2c 规则去自动从二进制资源文件产生 .h 头文件并引入到 C/C++ 代码中 * [#1547](https://github.com/xmake-io/xmake/issues/1547): option/snippets 支持运行检测模式,并且可以获取输出 * [#1567](https://github.com/xmake-io/xmake/issues/1567): 新增 xmake-requires.lock 包依赖锁定支持 * [#1597](https://github.com/xmake-io/xmake/issues/1597): 支持编译 metal 文件到 metallib,并改进 xcode.application 规则去生成内置的 default.metallib 到 app ### 改进 * [#1540](https://github.com/xmake-io/xmake/issues/1540): 更好更方便地编译自动生成的代码 * [#1578](https://github.com/xmake-io/xmake/issues/1578): 改进 add_repositories 去更好地支持相对路径 * [#1582](https://github.com/xmake-io/xmake/issues/1582): 改进安装和 os.cp 支持符号链接 ### Bugs 修复 * [#1531](https://github.com/xmake-io/xmake/issues/1531): 修复 targets 加载失败的错误信息提示错误 ## v2.5.6 ### 新特性 * [#1483](https://github.com/xmake-io/xmake/issues/1483): 添加 `os.joinenvs()` 和改进包工具环境 * [#1523](https://github.com/xmake-io/xmake/issues/1523): 添加 `set_allowedmodes`, `set_allowedplats` 和 `set_allowedarchs` * [#1523](https://github.com/xmake-io/xmake/issues/1523): 添加 `set_defaultmode`, `set_defaultplat` 和 `set_defaultarch` ### 改进 * 改进 vs/vsxmake 工程插件支持 vs2022 * [#1513](https://github.com/xmake-io/xmake/issues/1513): 改进 windows 预编译包的兼容性问题 * 改进 vcpkg 包在 windows 上的查找 * 改进对 Qt6 的支持 ### Bugs 修复 * [#489](https://github.com/xmake-io/xmake-repo/pull/489): 修复 run os.execv 带有过长环境变量值出现的一些问题 ## v2.5.5 ### 新特性 * [#1421](https://github.com/xmake-io/xmake/issues/1421): 针对 target 目标,增加目标文件名的前缀,后缀和扩展名设置接口。 * [#1422](https://github.com/xmake-io/xmake/issues/1422): 支持从 vcpkg, conan 中搜索包 * [#1424](https://github.com/xmake-io/xmake/issues/1424): 设置 binary 作为默认的 target 目标类型 * [#1140](https://github.com/xmake-io/xmake/issues/1140): 支持安装时候,手动选择从第三包包管理器安装包 * [#1339](https://github.com/xmake-io/xmake/issues/1339): 改进 `xmake package` 去产生新的本地包格式,无缝集成 `add_requires`,并且新增生成远程包支持 * 添加 `appletvos` 编译平台支持, `xmake f -p appletvos` * [#1437](https://github.com/xmake-io/xmake/issues/1437): 为包添加 headeronly 库类型去忽略 `vs_runtime` * [#1351](https://github.com/xmake-io/xmake/issues/1351): 支持导入导出当前配置 * [#1454](https://github.com/xmake-io/xmake/issues/1454): 支持下载安装 windows 预编译包 ### 改进 * [#1425](https://github.com/xmake-io/xmake/issues/1425): 改进 tools/meson 去加载 msvc 环境,并且增加一些内置配置。 * [#1442](https://github.com/xmake-io/xmake/issues/1442): 支持从 git url 去下载包资源文件 * [#1389](https://github.com/xmake-io/xmake/issues/1389): 支持添加工具链环境到 `xrepo env` * [#1453](https://github.com/xmake-io/xmake/issues/1453): 支持 protobuf 规则导出头文件搜索目录 * 新增对 vs2022 的支持 ### Bugs 修复 * [#1413](https://github.com/xmake-io/xmake/issues/1413): 修复查找包过程中出现的挂起卡死问题 * [#1420](https://github.com/xmake-io/xmake/issues/1420): 修复包检测和配置缓存 * [#1445](https://github.com/xmake-io/xmake/issues/1445): 修复 WDK 驱动签名错误 * [#1465](https://github.com/xmake-io/xmake/issues/1465): 修复缺失的链接目录 ## v2.5.4 ### 新特性 * [#1323](https://github.com/xmake-io/xmake/issues/1323): 支持从 apt 查找安装包,`add_requires("apt::zlib1g-dev")` * [#1337](https://github.com/xmake-io/xmake/issues/1337): 添加环境变量去改进包安装和缓存目录 * [#1338](https://github.com/xmake-io/xmake/issues/1338): 支持导入导出已安装的包 * [#1087](https://github.com/xmake-io/xmake/issues/1087): 添加 `xrepo env shell` 并且支持从 `add_requires/xmake.lua` 加载包环境 * [#1313](https://github.com/xmake-io/xmake/issues/1313): 为 `add_requires/add_deps` 添加私有包支持 * [#1358](https://github.com/xmake-io/xmake/issues/1358): 支持设置镜像 url 站点加速包下载 * [#1369](https://github.com/xmake-io/xmake/pull/1369): 为 vcpkg 增加 arm/arm64 包集成支持,感谢 @fallending * [#1405](https://github.com/xmake-io/xmake/pull/1405): 添加 portage 包管理器支持,感谢 @Phate6660 ### 改进 * 改进 `find_package` 并且添加 `package:find_package` 接口在包定义中方便查找包 * 移除废弃的 `set_config_h` 和 `set_config_h_prefix` 接口 * [#1343](https://github.com/xmake-io/xmake/issues/1343): 改进搜索本地包文件 * [#1347](https://github.com/xmake-io/xmake/issues/1347): 针对 binary 包改进 vs_runtime 配置 * [#1353](https://github.com/xmake-io/xmake/issues/1353): 改进 del_files() 去加速匹配文件 * [#1349](https://github.com/xmake-io/xmake/issues/1349): 改进 xrepo env shell 支持,更好的支持 powershell ### Bugs 修复 * [#1380](https://github.com/xmake-io/xmake/issues/1380): 修复 `add_packages()` 失败问题 * [#1381](https://github.com/xmake-io/xmake/issues/1381): 修复添加本地 git 包源问题 * [#1391](https://github.com/xmake-io/xmake/issues/1391): 修复 cuda/nvcc 工具链 ## v2.5.3 ### 新特性 * [#1259](https://github.com/xmake-io/xmake/issues/1259): 支持 `add_files("*.def")` 添加 def 文件去导出 windows/dll 符号 * [#1267](https://github.com/xmake-io/xmake/issues/1267): 添加 `find_package("nvtx")` * [#1274](https://github.com/xmake-io/xmake/issues/1274): 添加 `platform.linux.bpf` 规则去构建 linux/bpf 程序 * [#1280](https://github.com/xmake-io/xmake/issues/1280): 支持 fetchonly 包去扩展改进 find_package * 支持自动拉取远程 ndk 工具链包和集成 * [#1268](https://github.com/xmake-io/xmake/issues/1268): 添加 `utils.install.pkgconfig_importfiles` 规则去安装 `*.pc` 文件 * [#1268](https://github.com/xmake-io/xmake/issues/1268): 添加 `utils.install.cmake_importfiles` 规则去安装 `*.cmake` 导入文件 * [#348](https://github.com/xmake-io/xmake-repo/pull/348): 添加 `platform.longpaths` 策略去支持 git longpaths * [#1314](https://github.com/xmake-io/xmake/issues/1314): 支持安装使用 conda 包 * [#1120](https://github.com/xmake-io/xmake/issues/1120): 添加 `core.base.cpu` 模块并且改进 `os.cpuinfo()` * [#1325](https://github.com/xmake-io/xmake/issues/1325): 为 `add_configfiles` 添加内建的 git 变量 ### 改进 * [#1275](https://github.com/xmake-io/xmake/issues/1275): 改进 vsxmake 生成器,支持条件化编译 targets * [#1290](https://github.com/xmake-io/xmake/pull/1290): 增加对 Android ndk r22 以上版本支持 * [#1311](https://github.com/xmake-io/xmake/issues/1311): 为 vsxmake 工程添加包 dll 路径,确保调试运行加载正常 ### Bugs 修复 * [#1266](https://github.com/xmake-io/xmake/issues/1266): 修复在 `add_repositories` 中的 repo 相对路径 * [#1288](https://github.com/xmake-io/xmake/issues/1288): 修复 vsxmake 插件处理 option 配置问题 ## v2.5.2 ### 新特性 * [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-766481512): 支持 `zig cc` 和 `zig c++` 作为 c/c++ 编译器 * [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-768193083): 支持使用 zig 进行交叉编译 * [#1177](https://github.com/xmake-io/xmake/issues/1177): 改进终端和 color codes 探测 * [#1216](https://github.com/xmake-io/xmake/issues/1216): 传递自定义 includes 脚本给 xrepo * 添加 linuxos 内置模块获取 linux 系统信息 * [#1217](https://github.com/xmake-io/xmake/issues/1217): 支持当编译项目时自动拉取工具链 * [#1123](https://github.com/xmake-io/xmake/issues/1123): 添加 `rule("utils.symbols.export_all")` 自动导出所有 windows/dll 中的符号 * [#1181](https://github.com/xmake-io/xmake/issues/1181): 添加 `utils.platform.gnu2mslib(mslib, gnulib)` 模块接口去转换 mingw/xxx.dll.a 到 msvc xxx.lib * [#1246](https://github.com/xmake-io/xmake/issues/1246): 改进规则支持新的批处理命令去简化自定义规则实现 * [#1239](https://github.com/xmake-io/xmake/issues/1239): 添加 `add_extsources` 去改进外部包的查找 * [#1241](https://github.com/xmake-io/xmake/issues/1241): 支持为 windows 程序添加 .manifest 文件参与链接 * 支持使用 `xrepo remove --all` 命令去移除所有的包,并且支持模式匹配 * [#1254](https://github.com/xmake-io/xmake/issues/1254): 支持导出包配置给父 target,实现包配置的依赖继承 ### 改进 * [#1226](https://github.com/xmake-io/xmake/issues/1226): 添加缺失的 Qt 头文件搜索路径 * [#1183](https://github.com/xmake-io/xmake/issues/1183): 改进 C++ 语言标准,以便支持 Qt6 * [#1237](https://github.com/xmake-io/xmake/issues/1237): 为 vsxmake 插件添加 qt.ui 文件 * 改进 vs/vsxmake 插件去支持预编译头文件和智能提示 * [#1090](https://github.com/xmake-io/xmake/issues/1090): 简化自定义规则 * [#1065](https://github.com/xmake-io/xmake/issues/1065): 改进 protobuf 规则,支持 compile_commands 生成器 * [#1249](https://github.com/xmake-io/xmake/issues/1249): 改进 vs/vsxmake 生成器去支持启动工程设置 * [#605](https://github.com/xmake-io/xmake/issues/605): 改进 add_deps 和 add_packages 直接的导出 links 顺序 * 移除废弃的 `add_defines_h_if_ok` and `add_defines_h` 接口 ### Bugs 修复 * [#1219](https://github.com/xmake-io/xmake/issues/1219): 修复版本检测和更新 * [#1235](https://github.com/xmake-io/xmake/issues/1235): 修复 includes 搜索路径中带有空格编译不过问题 ## v2.5.1 ### 新特性 * [#1035](https://github.com/xmake-io/xmake/issues/1035): 图形配置菜单完整支持鼠标事件,并且新增滚动栏 * [#1098](https://github.com/xmake-io/xmake/issues/1098): 支持传递 stdin 到 os.execv 进行输入重定向 * [#1079](https://github.com/xmake-io/xmake/issues/1079): 为 vsxmake 插件添加工程自动更新插件,`add_rules("plugin.vsxmake.autoupdate")` * 添加 `xmake f --vs_runtime=MT` 和 `set_runtimes("MT")` 去更方便的对 target 和 package 进行设置 * [#1032](https://github.com/xmake-io/xmake/issues/1032): 支持枚举注册表 keys 和 values * [#1026](https://github.com/xmake-io/xmake/issues/1026): 支持对 vs/vsmake 工程增加分组设置 * [#1178](https://github.com/xmake-io/xmake/issues/1178): 添加 `add_requireconfs()` 接口去重写依赖包的配置 * [#1043](https://github.com/xmake-io/xmake/issues/1043): 为 luarocks 模块添加 `luarocks.module` 构建规则 * [#1190](https://github.com/xmake-io/xmake/issues/1190): 添加对 Apple Silicon (macOS ARM) 设备的支持 * [#1145](https://github.com/xmake-io/xmake/pull/1145): 支持在 windows 上安装部署 Qt 程序, 感谢 @SirLynix ### 改进 * [#1072](https://github.com/xmake-io/xmake/issues/1072): 修复并改进 cl 编译器头文件依赖信息 * 针对 ui 模块和 `xmake f --menu` 增加 utf8 支持 * 改进 zig 语言在 macOS 上的支持 * [#1135](https://github.com/xmake-io/xmake/issues/1135): 针对特定 target 改进多平台多工具链同时配置支持 * [#1153](https://github.com/xmake-io/xmake/issues/1153): 改进 llvm 工具链,针对 macos 上编译增加 isysroot 支持 * [#1071](https://github.com/xmake-io/xmake/issues/1071): 改进 vs/vsxmake 生成插件去支持远程依赖包 * 改进 vs/vsxmake 工程生成插件去支持全局的 `set_arch()` 设置 * [#1164](https://github.com/xmake-io/xmake/issues/1164): 改进 vsxmake 插件调试加载 console 程序 * [#1179](https://github.com/xmake-io/xmake/issues/1179): 改进 llvm 工具链,添加 isysroot ### Bugs 修复 * [#1091](https://github.com/xmake-io/xmake/issues/1091): 修复不正确的继承链接依赖 * [#1105](https://github.com/xmake-io/xmake/issues/1105): 修复 vsxmake 插件 c++ 语言标准智能提示错误 * [#1132](https://github.com/xmake-io/xmake/issues/1132): 修复 vsxmake 插件中配置路径被截断问题 * [#1142](https://github.com/xmake-io/xmake/issues/1142): 修复安装包的时候,出现git找不到问题 * 修复在 macOS Big Sur 上 macos.version 问题 * [#1084](https://github.com/xmake-io/xmake/issues/1084): 修复 `add_defines()` 中带有双引号和空格导致无法正确处理宏定义的问题 * [#1195](https://github.com/xmake-io/xmake/pull/1195): 修复 unicode 编码问题,改进 vs 环境查找和进程执行 ## v2.3.9 ### 新特性 * 添加新的 [xrepo](https://github.com/xmake-io/xrepo) 命令去管理安装 C/C++ 包 * 支持安装交叉编译的依赖包 * 新增musl.cc上的工具链支持 * [#1009](https://github.com/xmake-io/xmake/issues/1009): 支持忽略校验去安装任意版本的包,`add_requires("libcurl 7.73.0", {verify = false})` * [#1016](https://github.com/xmake-io/xmake/issues/1016): 针对依赖包增加license兼容性检测 * [#1017](https://github.com/xmake-io/xmake/issues/1017): 支持外部/系统头文件支持 `add_sysincludedirs`,依赖包默认使用`-isystem` * [#1020](https://github.com/xmake-io/xmake/issues/1020): 支持在 archlinux 和 msys2 上查找安装 pacman 包 * 改进 `xmake f --menu` 菜单配置,支持鼠标操作 ### 改进 * [#997](https://github.com/xmake-io/xmake/issues/997): `xmake project -k cmake` 插件增加对 `set_languages` 的支持 * [#998](https://github.com/xmake-io/xmake/issues/998): 支持安装 windows-static-md 类型的 vcpkg 包 * [#996](https://github.com/xmake-io/xmake/issues/996): 改进 vcpkg 目录查找 * [#1008](https://github.com/xmake-io/xmake/issues/1008): 改进交叉编译工具链 * [#1030](https://github.com/xmake-io/xmake/issues/1030): 改进 xcode.framework and xcode.application 规则 * [#1051](https://github.com/xmake-io/xmake/issues/1051): 为 msvc 编译器添加 `edit` 和 `embed` 调试信息格式类型到 `set_symbols()` * [#1062](https://github.com/xmake-io/xmake/issues/1062): 改进 `xmake project -k vs` 插件 ## v2.3.8 ### 新特性 * [#955](https://github.com/xmake-io/xmake/issues/955): 添加 Zig 空工程模板 * [#956](https://github.com/xmake-io/xmake/issues/956): 添加 Wasm 编译平台,并且支持 Qt/Wasm SDK * 升级luajit到v2.1最新分支版本,并且支持mips64上运行xmake * [#972](https://github.com/xmake-io/xmake/issues/972): 添加`depend.on_changed()`去简化依赖文件的处理 * [#981](https://github.com/xmake-io/xmake/issues/981): 添加`set_fpmodels()`去抽象化设置math/float-point编译优化模式 * [#980](https://github.com/xmake-io/xmake/issues/980): 添加对 Intel C/C++ 和 Fortran 编译器的全平台支持 * [#986](https://github.com/xmake-io/xmake/issues/986): 对16.8以上msvc编译器增加 `c11`/`c17` 支持 * [#979](https://github.com/xmake-io/xmake/issues/979): 添加对OpenMP的跨平台抽象配置。`add_rules("c++.openmp")` ### 改进 * [#958](https://github.com/xmake-io/xmake/issues/958): 改进mingw平台,增加对 llvm-mingw 工具链的支持,以及 arm64/arm 架构的支持 * 增加 `add_requires("zlib~xxx")` 模式使得能够支持同时安装带有多种配置的同一个包,作为独立包存在 * [#977](https://github.com/xmake-io/xmake/issues/977): 改进 find_mingw 在 windows 上的探测 * [#978](https://github.com/xmake-io/xmake/issues/978): 改进工具链的flags顺序 * 改进XCode工具链,支持macOS/arm64 ### Bugs 修复 * [#951](https://github.com/xmake-io/xmake/issues/951): 修复 emcc (WebAssembly) 工具链在windows上的支持 * [#992](https://github.com/xmake-io/xmake/issues/992): 修复文件锁偶尔打开失败问题 ## v2.3.7 ### 新特性 * [#2941](https://github.com/microsoft/winget-pkgs/pull/2941): 支持通过 winget 来安装 xmake * 添加 xmake-tinyc 安装包,内置tinyc编译器,支持windows上无msvc环境也可直接编译c代码 * 添加 tinyc 编译工具链 * 添加 emcc (emscripten) 编译工具链去编译 asm.js 和 WebAssembly * [#947](https://github.com/xmake-io/xmake/issues/947): 通过 `xmake g --network=private` 配置设置私有网络模式,避免远程依赖包下载访问外网导致编译失败 ### 改进 * [#907](https://github.com/xmake-io/xmake/issues/907): 改进msvc的链接器优化选项,生成更小的可执行程序 * 改进ubuntu下Qt环境的支持 * [#918](https://github.com/xmake-io/xmake/pull/918): 改进cuda11工具链的支持 * 改进Qt支持,对通过 ubuntu/apt 安装的Qt sdk也进行了探测支持,并且检测效率也优化了下 * 改进 CMake 工程文件生成器 * [#931](https://github.com/xmake-io/xmake/issues/931): 改进导出包,支持导出所有依赖包 * [#930](https://github.com/xmake-io/xmake/issues/930): 如果私有包定义没有版本定义,支持直接尝试下载包 * [#927](https://github.com/xmake-io/xmake/issues/927): 改进android ndk,支持arm/thumb指令模式切换 * 改进 trybuild/cmake 支持 Android/Mingw/iPhoneOS/WatchOS 工具链 ### Bugs 修复 * [#903](https://github.com/xmake-io/xmake/issues/903): 修复vcpkg包安装失败问题 * [#912](https://github.com/xmake-io/xmake/issues/912): 修复自定义工具链 * [#914](https://github.com/xmake-io/xmake/issues/914): 修复部分aarch64设备上运行lua出现bad light userdata pointer问题 ## v2.3.6 ### 新特性 * 添加xcode工程生成器插件,`xmake project -k cmake` (当前采用cmake生成) * [#870](https://github.com/xmake-io/xmake/issues/870): 支持gfortran编译器 * [#887](https://github.com/xmake-io/xmake/pull/887): 支持zig编译器 * [#893](https://github.com/xmake-io/xmake/issues/893): 添加json模块 * [#898](https://github.com/xmake-io/xmake/issues/898): 改进golang项目构建,支持交叉编译 * [#275](https://github.com/xmake-io/xmake/issues/275): 支持go包管理器去集成第三方go依赖包 * [#581](https://github.com/xmake-io/xmake/issues/581): 支持dub包管理器去集成第三方dlang依赖包 ### 改进 * [#868](https://github.com/xmake-io/xmake/issues/868): 支持新的cl.exe的头文件依赖输出文件格式,`/sourceDependencies xxx.json` * [#902](https://github.com/xmake-io/xmake/issues/902): 改进交叉编译工具链 ## v2.3.5 ### 新特性 * 添加`xmake show -l envs`去显示xmake内置的环境变量列表 * [#861](https://github.com/xmake-io/xmake/issues/861): 支持从指定目录搜索本地包去直接安装远程依赖包 * [#854](https://github.com/xmake-io/xmake/issues/854): 针对wget, curl和git支持全局代理设置 ### 改进 * [#828](https://github.com/xmake-io/xmake/issues/828): 针对protobuf规则增加导入子目录proto文件支持 * [#835](https://github.com/xmake-io/xmake/issues/835): 改进mode.minsizerel模式,针对msvc增加/GL支持,进一步优化目标程序大小 * [#828](https://github.com/xmake-io/xmake/issues/828): protobuf规则支持import多级子目录 * [#838](https://github.com/xmake-io/xmake/issues/838#issuecomment-643570920): 支持完全重写内置的构建规则,`add_files("src/*.c", {rules = {"xx", override = true}})` * [#847](https://github.com/xmake-io/xmake/issues/847): 支持rc文件的头文件依赖解析 * 改进msvc工具链,去除全局环境变量的依赖 * [#857](https://github.com/xmake-io/xmake/pull/857): 改进`set_toolchains()`支持交叉编译的时候,特定target可以切换到host工具链同时编译 ### Bugs 修复 * 修复进度字符显示 * [#829](https://github.com/xmake-io/xmake/issues/829): 修复由于macOS大小写不敏感系统导致的sysroot无效路径问题 * [#832](https://github.com/xmake-io/xmake/issues/832): 修复find_packages在debug模式下找不到的问题 ## v2.3.4 ### 新特性 * [#630](https://github.com/xmake-io/xmake/issues/630): 支持*BSD系统,例如:FreeBSD, .. * 添加wprint接口去显示警告信息 * [#784](https://github.com/xmake-io/xmake/issues/784): 添加`set_policy()`去设置修改一些内置的策略,比如:禁用自动flags检测和映射 * [#780](https://github.com/xmake-io/xmake/issues/780): 针对target添加set_toolchains/set_toolsets实现更完善的工具链设置,并且实现platform和toolchains分离 * [#798](https://github.com/xmake-io/xmake/issues/798): 添加`xmake show`插件去显示xmake内置的各种信息 * [#797](https://github.com/xmake-io/xmake/issues/797): 添加ninja主题风格,显示ninja风格的构建进度条,`xmake g --theme=ninja` * [#816](https://github.com/xmake-io/xmake/issues/816): 添加mode.releasedbg和mode.minsizerel编译模式规则 * [#819](https://github.com/xmake-io/xmake/issues/819): 支持ansi/vt100终端字符控制 ### 改进 * [#771](https://github.com/xmake-io/xmake/issues/771): 检测includedirs,linkdirs和frameworkdirs的输入有效性 * [#774](https://github.com/xmake-io/xmake/issues/774): `xmake f --menu`可视化配置菜单支持窗口大小Resize调整 * [#782](https://github.com/xmake-io/xmake/issues/782): 添加add_cxflags等配置flags自动检测失败提示 * [#808](https://github.com/xmake-io/xmake/issues/808): 生成cmakelists插件增加对add_frameworks的支持 * [#820](https://github.com/xmake-io/xmake/issues/820): 支持独立的工作目录和构建目录,保持项目目录完全干净 ### Bugs 修复 * [#786](https://github.com/xmake-io/xmake/issues/786): 修复头文件依赖检测 * [#810](https://github.com/xmake-io/xmake/issues/810): 修复linux下gcc strip debug符号问题 ## v2.3.3 ### 新特性 * [#727](https://github.com/xmake-io/xmake/issues/727): 支持为android, ios程序生成.so/.dSYM符号文件 * [#687](https://github.com/xmake-io/xmake/issues/687): 支持编译生成objc/bundle程序 * [#743](https://github.com/xmake-io/xmake/issues/743): 支持编译生成objc/framework程序 * 支持编译bundle, framework程序,以及mac, ios应用程序,并新增一些工程模板 * 支持对ios应用程序打包生成ipa文件,以及代码签名支持 * 增加一些ipa打包、安装、重签名等辅助工具 * 添加xmake.cli规则来支持开发带有xmake/core引擎的lua扩展程序 ### 改进 * [#750](https://github.com/xmake-io/xmake/issues/750): 改进qt.widgetapp规则,支持qt私有槽 * 改进Qt/android的apk部署,并且支持Qt5.14.0新版本sdk ## v2.3.2 ### 新特性 * 添加powershell色彩主题用于powershell终端下背景色显示 * 添加`xmake --dry-run -v`命令去空运行构建,仅仅为了查看详细的构建命令 * [#712](https://github.com/xmake-io/xmake/issues/712): 添加sdcc平台,并且支持sdcc编译器 ### 改进 * [#589](https://github.com/xmake-io/xmake/issues/589): 改进优化构建速度,支持跨目标间并行编译和link,编译速度和ninja基本持平 * 改进ninja/cmake工程文件生成器插件 * [#728](https://github.com/xmake-io/xmake/issues/728): 改进os.cp支持保留源目录结构层级的递归复制 * [#732](https://github.com/xmake-io/xmake/issues/732): 改进find_package支持查找homebrew/cmake安装的包 * [#695](https://github.com/xmake-io/xmake/issues/695): 改进采用android ndk最新的abi命名 ### Bugs 修复 * 修复windows下link error显示问题 * [#718](https://github.com/xmake-io/xmake/issues/718): 修复依赖包下载在多镜像时一定概率缓存失效问题 * [#722](https://github.com/xmake-io/xmake/issues/722): 修复无效的包依赖导致安装死循环问题 * [#719](https://github.com/xmake-io/xmake/issues/719): 修复windows下主进程收到ctrlc后,.bat子进程没能立即退出的问题 * [#720](https://github.com/xmake-io/xmake/issues/720): 修复compile_commands生成器的路径转义问题 ## v2.3.1 ### 新特性 * [#675](https://github.com/xmake-io/xmake/issues/675): 支持通过设置强制将`*.c`作为c++代码编译, `add_files("*.c", {sourcekind = "cxx"})`。 * [#681](https://github.com/xmake-io/xmake/issues/681): 支持在msys/cygwin上编译xmake,以及添加msys/cygwin编译平台 * 添加socket/pipe模块,并且支持在协程中同时调度process/socket/pipe * [#192](https://github.com/xmake-io/xmake/issues/192): 尝试构建带有第三方构建系统的项目,还支持autotools项目的交叉编译 * 启用gcc/clang的编译错误色彩高亮输出 * [#588](https://github.com/xmake-io/xmake/issues/588): 改进工程生成插件`xmake project -k ninja`,增加对build.ninja生成支持 ### 改进 * [#665](https://github.com/xmake-io/xmake/issues/665): 支持 *nix style 的参数输入,感谢[@OpportunityLiu](https://github.com/OpportunityLiu)的贡献 * [#673](https://github.com/xmake-io/xmake/pull/673): 改进tab命令补全,增加对参数values的补全支持 * [#680](https://github.com/xmake-io/xmake/issues/680): 优化get.sh安装脚本,添加国内镜像源,加速下载 * 改进process调度器 * [#651](https://github.com/xmake-io/xmake/issues/651): 改进os/io模块系统操作错误提示 ### Bugs 修复 * 修复增量编译检测依赖文件的一些问题 * 修复log输出导致xmake-vscode插件解析编译错误信息失败问题 * [#684](https://github.com/xmake-io/xmake/issues/684): 修复windows下android ndk的一些linker错误 ## v2.2.9 ### 新特性 * [#569](https://github.com/xmake-io/xmake/pull/569): 增加对c++模块的实验性支持 * 添加`xmake project -k xmakefile`生成器 * [620](https://github.com/xmake-io/xmake/issues/620): 添加全局`~/.xmakerc.lua`配置文件,对所有本地工程生效. * [593](https://github.com/xmake-io/xmake/pull/593): 添加`core.base.socket`模块,为下一步远程编译和分布式编译做准备。 ### 改进 * [#563](https://github.com/xmake-io/xmake/pull/563): 重构构建逻辑,将特定语言的构建抽离到独立的rules中去 * [#570](https://github.com/xmake-io/xmake/issues/570): 改进Qt构建,将`qt.application`拆分成`qt.widgetapp`和`qt.quickapp`两个构建规则 * [#576](https://github.com/xmake-io/xmake/issues/576): 使用`set_toolchain`替代`add_tools`和`set_tools`,解决老接口使用歧义,提供更加易理解的设置方式 * 改进`xmake create`创建模板工程 * [#589](https://github.com/xmake-io/xmake/issues/589): 改进默认的构建任务数,充分利用cpu core来提速整体编译速度 * [#598](https://github.com/xmake-io/xmake/issues/598): 改进`find_package`支持在macOS上对.tbd系统库文件的查找 * [#615](https://github.com/xmake-io/xmake/issues/615): 支持安装和使用其他arch和ios的conan包 * [#629](https://github.com/xmake-io/xmake/issues/629): 改进hash.uuid并且实现uuid v4 * [#639](https://github.com/xmake-io/xmake/issues/639): 改进参数解析器支持`-jN`风格传参 ### Bugs 修复 * [#567](https://github.com/xmake-io/xmake/issues/567): 修复序列化对象时候出现的内存溢出问题 * [#566](https://github.com/xmake-io/xmake/issues/566): 修复安装远程依赖的链接顺序问题 * [#565](https://github.com/xmake-io/xmake/issues/565): 修复vcpkg包的运行PATH设置问题 * [#597](https://github.com/xmake-io/xmake/issues/597): 修复xmake require安装包时间过长问题 * [#634](https://github.com/xmake-io/xmake/issues/634): 修复mode.coverage构建规则,并且改进flags检测 ## v2.2.8 ### 新特性 * 添加protobuf c/c++构建规则 * [#468](https://github.com/xmake-io/xmake/pull/468): 添加对 Windows 的 UTF-8 支持 * [#472](https://github.com/xmake-io/xmake/pull/472): 添加`xmake project -k vsxmake`去更好的支持vs工程的生成,内部直接调用xmake来编译 * [#487](https://github.com/xmake-io/xmake/issues/487): 通过`xmake --files="src/*.c"`支持指定一批文件进行编译。 * 针对io模块增加文件锁接口 * [#513](https://github.com/xmake-io/xmake/issues/513): 增加对android/termux终端的支持,可在android设备上执行xmake来构建项目 * [#517](https://github.com/xmake-io/xmake/issues/517): 为target增加`add_cleanfiles`接口,实现快速定制化清理文件 * [#537](https://github.com/xmake-io/xmake/pull/537): 添加`set_runenv`接口去覆盖写入系统envs ### 改进 * [#257](https://github.com/xmake-io/xmake/issues/257): 锁定当前正在构建的工程,避免其他xmake进程同时对其操作 * 尝试采用/dev/shm作为os.tmpdir去改善构建过程中临时文件的读写效率 * [#542](https://github.com/xmake-io/xmake/pull/542): 改进vs系列工具链的unicode输出问题 * 对于安装的lua脚本,启用lua字节码存储,减少安装包大小(<2.4M),提高运行加载效率。 ### Bugs 修复 * [#549](https://github.com/xmake-io/xmake/issues/549): 修复新版vs2019下检测环境会卡死的问题 ## v2.2.7 ### 新特性 * [#455](https://github.com/xmake-io/xmake/pull/455): 支持使用 clang 作为 cuda 编译器,`xmake f --cu=clang` * [#440](https://github.com/xmake-io/xmake/issues/440): 为target/run添加`set_rundir()`和`add_runenvs()`接口设置 * [#443](https://github.com/xmake-io/xmake/pull/443): 添加命令行tab自动完成支持 * 为rule/target添加`on_link`,`before_link`和`after_link`阶段自定义脚本支持 * [#190](https://github.com/xmake-io/xmake/issues/190): 添加`add_rules("lex", "yacc")`规则去支持lex/yacc项目 ### 改进 * [#430](https://github.com/xmake-io/xmake/pull/430): 添加`add_cugencodes()`api为cuda改进设置codegen * [#432](https://github.com/xmake-io/xmake/pull/432): 针对cuda编译支持依赖分析检测(仅支持 CUDA 10.1+) * [#437](https://github.com/xmake-io/xmake/issues/437): 支持指定更新源,`xmake update github:xmake-io/xmake#dev` * [#438](https://github.com/xmake-io/xmake/pull/438): 支持仅更新脚本,`xmake update --scriptonly dev` * [#433](https://github.com/xmake-io/xmake/issues/433): 改进cuda构建支持device-link设备代码链接 * [#442](https://github.com/xmake-io/xmake/issues/442): 改进tests测试框架 ## v2.2.6 ### 新特性 * [#380](https://github.com/xmake-io/xmake/pull/380): 添加导出compile_flags.txt * [#382](https://github.com/xmake-io/xmake/issues/382): 简化域设置语法 * [#397](https://github.com/xmake-io/xmake/issues/397): 添加clib包集成支持 * [#404](https://github.com/xmake-io/xmake/issues/404): 增加Qt/Android编译支持,并且支持android apk生成和部署 * 添加一些Qt空工程模板,例如:`widgetapp_qt`, `quickapp_qt_static` and `widgetapp_qt_static` * [#415](https://github.com/xmake-io/xmake/issues/415): 添加`--cu-cxx`配置参数到`nvcc/-ccbin` * 为Android NDK添加`--ndk_stdcxx=y`和`--ndk_cxxstl=gnustl_static`参数选项 ### 改进 * 改进远程依赖包管理,丰富包仓库 * 改进`target:on_xxx`自定义脚本,去支持匹配`android|armv7-a@macosx,linux|x86_64`模式 * 改进loadfile,优化启动速度,windows上启动xmake时间提速98% ### Bugs 修复 * [#400](https://github.com/xmake-io/xmake/issues/400): 修复qt项目c++语言标准设置无效问题 ## v2.2.5 ### 新特性 * 添加`string.serialize`和`string.deserialize`去序列化,反序列化对象,函数以及其他类型 * 添加`xmake g --menu`去图形化配置全局选项 * [#283](https://github.com/xmake-io/xmake/issues/283): 添加`target:installdir()`和`set_installdir()`接口 * [#260](https://github.com/xmake-io/xmake/issues/260): 添加`add_platformdirs`接口,用户现在可以自定义扩展编译平台 * [#310](https://github.com/xmake-io/xmake/issues/310): 新增主题设置支持,用户可随意切换和扩展主题样式 * [#318](https://github.com/xmake-io/xmake/issues/318): 添加`add_installfiles`接口到target去自定义安装文件 * [#339](https://github.com/xmake-io/xmake/issues/339): 改进`add_requires`和`find_package`使其支持对第三方包管理的集成支持 * [#327](https://github.com/xmake-io/xmake/issues/327): 实现对conan包管理的集成支持 * 添加内置API `find_packages("pcre2", "zlib")`去同时查找多个依赖包,不需要通过import导入即可直接调用 * [#320](https://github.com/xmake-io/xmake/issues/320): 添加模板配置文件相关接口,`add_configfiles`和`set_configvar` * [#179](https://github.com/xmake-io/xmake/issues/179): 扩展`xmake project`插件,新增CMakelist.txt生成支持 * [#361](https://github.com/xmake-io/xmake/issues/361): 增加对vs2019 preview的支持 * [#368](https://github.com/xmake-io/xmake/issues/368): 支持`private, public, interface`属性设置去继承target配置 * [#284](https://github.com/xmake-io/xmake/issues/284): 通过`add_configs()`添加和传递用户自定义配置到`package()` * [#319](https://github.com/xmake-io/xmake/issues/319): 添加`add_headerfiles`接口去改进头文件的设置 * [#342](https://github.com/xmake-io/xmake/issues/342): 为`includes()`添加一些内置的辅助函数,例如:`check_cfuncs` ### 改进 * 针对远程依赖包,改进版本和调试模式切换 * [#264](https://github.com/xmake-io/xmake/issues/264): 支持在windows上更新dev/master版本,`xmake update dev` * [#293](https://github.com/xmake-io/xmake/issues/293): 添加`xmake f/g --mingw=xxx` 配置选线,并且改进find_mingw检测 * [#301](https://github.com/xmake-io/xmake/issues/301): 改进编译预处理头文件以及依赖头文件生成,编译速度提升30% * [#322](https://github.com/xmake-io/xmake/issues/322): 添加`option.add_features`, `option.add_cxxsnippets` 和 `option.add_csnippets` * 移除xmake 1.x的一些废弃接口, 例如:`add_option_xxx` * [#327](https://github.com/xmake-io/xmake/issues/327): 改进`lib.detect.find_package`增加对conan包管理器的支持 * 改进`lib.detect.find_package`并且添加内建的`find_packages("zlib 1.x", "openssl", {xxx = ...})`接口 * 标记`set_modes()`作为废弃接口, 我们使用`add_rules("mode.debug", "mode.release")`来替代它 * [#353](https://github.com/xmake-io/xmake/issues/353): 改进`target:set`, `target:add` 并且添加`target:del`去动态修改target配置 * [#356](https://github.com/xmake-io/xmake/issues/356): 添加`qt_add_static_plugins()`接口去支持静态Qt sdk * [#351](https://github.com/xmake-io/xmake/issues/351): 生成vs201x插件增加对yasm的支持 * 重构改进整个远程依赖包管理器,更加快速、稳定、可靠,并提供更多的常用包 ### Bugs 修复 * 修复无法通过 `set_optimize()` 设置优化选项,如果存在`add_rules("mode.release")`的情况下 * [#289](https://github.com/xmake-io/xmake/issues/289): 修复在windows下解压gzip文件失败 * [#296](https://github.com/xmake-io/xmake/issues/296): 修复`option.add_includedirs`对cuda编译不生效 * [#321](https://github.com/xmake-io/xmake/issues/321): 修复PATH环境改动后查找工具不对问题 ## v2.2.3 ### 新特性 * [#233](https://github.com/xmake-io/xmake/issues/233): 对mingw平台增加windres的支持 * [#239](https://github.com/xmake-io/xmake/issues/239): 添加cparser编译器支持 * 添加插件管理器,`xmake plugin --help` * 添加`add_syslinks`接口去设置系统库依赖,分离与`add_links`添加的库依赖之间的链接顺序 * 添加 `xmake l time xmake [--rebuild]` 去记录编译耗时 * [#250](https://github.com/xmake-io/xmake/issues/250): 添加`xmake f --vs_sdkver=10.0.15063.0`去改变windows sdk版本 * 添加`lib.luajit.ffi`和`lib.luajit.jit`扩展模块 * [#263](https://github.com/xmake-io/xmake/issues/263): 添加object目标类型,仅仅用于编译生成object对象文件 * [#269](https://github.com/xmake-io/xmake/issues/269): 每天第一次构建时候后台进程自动清理最近30天的临时文件 ### 改进 * [#229](https://github.com/xmake-io/xmake/issues/229): 改进vs toolset选择已经vcproj工程文件生成 * 改进编译依赖,对源文件列表的改动进行依赖判断 * 支持解压*.xz文件 * [#249](https://github.com/xmake-io/xmake/pull/249): 改进编译进度信息显示格式 * [#247](https://github.com/xmake-io/xmake/pull/247): 添加`-D`和`--diagnosis`去替换`--backtrace`,改进诊断信息显示 * [#259](https://github.com/xmake-io/xmake/issues/259): 改进 on_build, on_build_file 和 on_xxx 等接口 * 改进远程包管理器,更加方便的包依赖配置切换 * 支持only头文件依赖包的安装 * 支持对包内置links的手动调整,`add_packages("xxx", {links = {}})` ### Bugs 修复 * 修复安装依赖包失败中断后的状态不一致性问题 ## v2.2.2 ### 新特性 * 新增fasm汇编器支持 * 添加`has_config`, `get_config`和`is_config`接口去快速判断option和配置值 * 添加`set_config`接口去设置默认配置 * 添加`$xmake --try`去尝试构建工程 * 添加`set_enabled(false)`去显示的禁用target * [#69](https://github.com/xmake-io/xmake/issues/69): 添加远程依赖包管理, `add_requires("tbox ~1.6.1")` * [#216](https://github.com/xmake-io/xmake/pull/216): 添加windows mfc编译规则 ### 改进 * 改进Qt编译编译环境探测,增加对mingw sdk的支持 * 在自动扫描生成的xmake.lua中增加默认debug/release规则 * [#178](https://github.com/xmake-io/xmake/issues/178): 修改mingw平台下的目标名 * 对于`add_files()`在windows上支持大小写不敏感路径模式匹配 * 改进`detect.sdks.find_qt`对于Qt根目录的探测 * [#184](https://github.com/xmake-io/xmake/issues/184): 改进`lib.detect.find_package`支持vcpkg * [#208](https://github.com/xmake-io/xmake/issues/208): 改进rpath对动态库的支持 * [#225](https://github.com/xmake-io/xmake/issues/225): 改进vs环境探测 ### Bugs 修复 * [#177](https://github.com/xmake-io/xmake/issues/177): 修复被依赖的动态库target,如果设置了basename后链接失败问题 * 修复`$ xmake f --menu`中Exit问题以及cpu过高问题 * [#197](https://github.com/xmake-io/xmake/issues/197): 修复生成的vs201x工程文件带有中文路径乱码问题 * 修复WDK规则编译生成的驱动在Win7下运行蓝屏问题 * [#205](https://github.com/xmake-io/xmake/pull/205): 修复vcproj工程生成targetdir, objectdir路径设置不匹配问题 ## v2.2.1 ### 新特性 * [#158](https://github.com/xmake-io/xmake/issues/158): 增加对Cuda编译环境的支持 * 添加`set_tools`和`add_tools`接口为指定target目标设置编译工具链 * 添加内建规则:`mode.debug`, `mode.release`, `mode.profile`和`mode.check` * 添加`is_mode`, `is_arch` 和`is_plat`内置接口到自定义脚本域 * 添加color256代码 * [#160](https://github.com/xmake-io/xmake/issues/160): 增加对Qt SDK编译环境的跨平台支持,并且增加`qt.console`, `qt.application`等规则 * 添加一些Qt工程模板 * [#169](https://github.com/xmake-io/xmake/issues/169): 支持yasm汇编器 * [#159](https://github.com/xmake-io/xmake/issues/159): 增加对WDK驱动编译环境支持 ### 改进 * 添加FAQ到自动生成的xmake.lua文件,方便用户快速上手 * 支持Android NDK >= r14的版本 * 改进swiftc对warning flags的支持 * [#167](https://github.com/xmake-io/xmake/issues/167): 改进自定义规则:`rule()` * 改进`os.files`和`os.dirs`接口,加速文件模式匹配 * [#171](https://github.com/xmake-io/xmake/issues/171): 改进Qt环境的构建依赖 * 在makefile生成插件中实现`make clean` ### Bugs 修复 * 修复无法通过`add_ldflags("xx", "xx", {force = true})`强制设置多个flags的问题 * [#157](https://github.com/xmake-io/xmake/issues/157): 修复pdb符号输出目录不存在情况下编译失败问题 * 修复对macho格式目标strip all符号失效问题 * [#168](https://github.com/xmake-io/xmake/issues/168): 修复生成vs201x工程插件,在x64下失败的问题 ## v2.1.9 ### 新特性 * 添加`del_files()`接口去从已添加的文件列表中移除一些文件 * 添加`rule()`, `add_rules()`接口实现自定义构建规则,并且改进`add_files("src/*.md", {rule = "markdown"})` * 添加`os.filesize()`接口 * 添加`core.ui.xxx`等cui组件模块,实现终端可视化界面,用于实现跟用户进行短暂的交互 * 通过`xmake f --menu`实现可视化菜单交互配置,简化工程的编译配置 * 添加`set_values`接口到option * 改进option,支持根据工程中用户自定义的option,自动生成可视化配置菜单 * 在调用api设置工程配置时以及在配置菜单中添加源文件位置信息 ### 改进 * 改进交叉工具链配置,通过指定工具别名定向到已知的工具链来支持未知编译工具名配置, 例如: `xmake f --cc=gcc@ccmips.exe` * [#151](https://github.com/xmake-io/xmake/issues/151): 改进mingw平台下动态库生成 * 改进生成makefile插件 * 改进检测错误提示 * 改进`add_cxflags`等flags api的设置,添加force参数,来禁用自动检测和映射,强制设置选项:`add_cxflags("-DTEST", {force = true})` * 改进`add_files`的flags设置,添加force域,用于设置不带自动检测和映射的原始flags:`add_files("src/*.c", {force = {cxflags = "-DTEST"}})` * 改进搜索工程根目录策略 * 改进vs环境探测,支持加密文件系统下vs环境的探测 * 升级luajit到最新2.1.0-beta3 * 增加对linux/arm, arm64的支持,可以在arm linux上运行xmake * 改进vs201x工程生成插件,更好的includedirs设置支持 ### Bugs 修复 * 修复依赖修改编译和链接问题 * [#151](https://github.com/xmake-io/xmake/issues/151): 修复`os.nuldev()`在mingw上传入gcc时出现问题 * [#150](https://github.com/xmake-io/xmake/issues/150): 修复windows下ar.exe打包过长obj列表参数,导致失败问题 * 修复`xmake f --cross`无法配置问题 * 修复`os.cd`到windows根路径问题 ## v2.1.8 ### 新特性 * 添加`XMAKE_LOGFILE`环境变量,启用输出到日志文件 * 添加对tinyc编译器的支持 ### 改进 * 改进对IDE和编辑器插件的集成支持,例如:Visual Studio Code, Sublime Text 以及 IntelliJ IDEA * 当生成新工程的时候,自动生成一个`.gitignore`文件,忽略一些xmake的临时文件和目录 * 改进创建模板工程,使用模板名代替模板id作为参数 * 改进macOS编译平台的探测,如果没有安装xcode也能够进行编译构建,如果有编译器的话 * 改进`set_config_header`接口,支持局部版本号设置,优先于全局`set_version`,例如:`set_config_header("config", {version = "2.1.8", build = "%Y%m%d%H%M"})` ### Bugs 修复 * [#145](https://github.com/xmake-io/xmake/issues/145): 修复运行target的当前目录环境 ## v2.1.7 ### 新特性 * 添加`add_imports`去为target,option和package的自定义脚本批量导入模块,简化自定义脚本 * 添加`xmake -y/--yes`去确认用户输入 * 添加`xmake l package.manager.install xxx`模块,进行跨平台一致性安装软件包 * 添加vscode编辑器插件支持,更加方便的使用xmake,[xmake-vscode](https://marketplace.visualstudio.com/items?itemName=tboox.xmake-vscode#overview) * 添加`xmake macro ..`快速运行最近一次命令 ### 改进 * 改进`cprint()`,支持24位真彩色输出 * 对`add_rpathdirs()`增加对`@loader_path`和`$ORIGIN`的内置变量支持,提供可迁移动态库加载 * 改进`set_version("x.x.x", {build = "%Y%m%d%H%M"})` 支持buildversion设置 * 移除docs目录,将其放置到独立xmake-docs仓库中,减少xmake.zip的大小,优化下载安装的效率 * 改进安装和卸载脚本,支持DESTDIR和PREFIX环境变量设置 * 通过缓存优化flags探测,加速编译效率 * 添加`COLORTERM=nocolor`环境变量开关,禁用彩色输出 * 移除`add_rbindings`和`add_bindings`接口 * 禁止在重定向的时候进行彩色输出,避免输出文件中带有色彩代码干扰 * 更新tbox工程模板 * 改进`lib.detect.find_program`模块接口 * 为windows cmd终端增加彩色输出 * 增加`-w|--warning`参数来启用实时警告输出 ### Bugs 修复 * 修复`set_pcxxheader`编译没有继承flags配置问题 * [#140](https://github.com/xmake-io/xmake/issues/140): 修复`os.tmpdir()`在fakeroot下的冲突问题 * [#142](https://github.com/xmake-io/xmake/issues/142): 修复`os.getenv` 在windows上的中文编码问题 * 修复在带有空格路径的情况下,编译错误问题 * 修复setenv空值的崩溃问题 ## v2.1.6 ### 改进 * 改进`add_files`,支持对files粒度进行编译选项的各种配置,更加灵活。 * 从依赖的target和option中继承links和linkdirs。 * 改进`target.add_deps`接口,添加继承配置,允许手动禁止依赖继承,例如:`add_deps("test", {inherit = false})` * 移除`tbox.pkg`二进制依赖,直接集成tbox源码进行编译 ### Bugs 修复 * 修复目标级联依赖问题 * 修复`target:add`和`option:add`问题 * 修复在archlinux上的编译和安装问题 * 修复`/ZI`的兼容性问题,用`/Zi`替代 ## v2.1.5 ### 新特性 * [#83](https://github.com/xmake-io/xmake/issues/83): 添加 `add_csnippet`,`add_cxxsnippet`到`option`来检测一些编译器特性 * [#83](https://github.com/xmake-io/xmake/issues/83): 添加用户扩展模块去探测程序,库文件以及其他主机环境 * 添加`find_program`, `find_file`, `find_library`, `find_tool`和`find_package` 等模块接口 * 添加`net.*`和`devel.*`扩展模块 * 添加`val()`接口去获取内置变量,例如:`val("host")`, `val("env PATH")`, `val("shell echo hello")` and `val("reg HKEY_LOCAL_MACHINE\\XX;Value")` * 增加对微软.rc资源文件的编译支持,当在windows上编译时,可以增加资源文件了 * 增加`has_flags`, `features`和`has_features`等探测模块接口 * 添加`option.on_check`, `option.after_check` 和 `option.before_check` 接口 * 添加`target.on_load`接口 * [#132](https://github.com/xmake-io/xmake/issues/132): 添加`add_frameworkdirs`接口 * 添加`lib.detect.has_xxx`和`lib.detect.find_xxx`接口 * 添加`add_moduledirs`接口在工程中定义和加载扩展模块 * 添加`includes`接口替换`add_subdirs`和`add_subfiles` * [#133](https://github.com/xmake-io/xmake/issues/133): 改进工程插件,通过运行`xmake project -k compile_commands`来导出`compile_commands.json` * 添加`set_pcheader`和`set_pcxxheader`去支持跨编译器预编译头文件,支持`gcc`, `clang`和`msvc` * 添加`xmake f -p cross`平台用于交叉编译,并且支持自定义平台名 ### 改进 * [#87](https://github.com/xmake-io/xmake/issues/87): 为依赖库目标自动添加:`includes` 和 `links` * 改进`import`接口,去加载用户扩展模块 * [#93](https://github.com/xmake-io/xmake/pull/93): 改进 `xmake lua`,支持运行单行命令和模块 * 改进编译错误提示信息输出 * 改进`print`接口去更好些显示table数据 * [#111](https://github.com/xmake-io/xmake/issues/111): 添加`--root`通用选项去临时支持作为root运行 * [#113](https://github.com/xmake-io/xmake/pull/113): 改进权限管理,现在作为root运行也是非常安全的 * 改进`xxx_script`工程描述api,支持多平台模式选择, 例如:`on_build("iphoneos|arm*", function (target) end)` * 改进内置变量,支持环境变量和注册表数据的获取 * 改进vstudio环境和交叉工具链的探测 * [#71](https://github.com/xmake-io/xmake/issues/71): 改进从环境变量中探测链接器和编译器 * 改进option选项检测,通过多任务检测,提升70%的检测速度 * [#129](https://github.com/xmake-io/xmake/issues/129): 检测链接依赖,如果源文件没有改变,就不必重新链接目标文件了 * 在vs201x工程插件中增加对`*.asm`文件的支持 * 标记`add_bindings`和`add_rbindings`为废弃接口 * 优化`xmake rebuild`在windows上的构建速度 * 将`core.project.task`模块迁移至`core.base.task` * 将`echo` 和 `app2ipa` 插件迁移到 [xmake-plugins](https://github.com/xmake-io/xmake-plugins) 仓库 * 添加`set_config_header("config.h", {prefix = ""})` 代替 `set_config_h` 和 `set_config_h_prefix` ### Bugs 修复 * 修复`try-catch-finally` * 修复解释器bug,解决当加载多级子目录时,根域属性设置不对 * [#115](https://github.com/xmake-io/xmake/pull/115): 修复安装脚本`get.sh`的路径问题 * 修复`import()`导入接口的缓存问题 ## v2.1.4 ### 新特性 * [#68](https://github.com/xmake-io/xmake/issues/68): 增加`$(programdir)`和`$(xmake)`内建变量 * 添加`is_host`接口去判断当前的主机环境 * [#79](https://github.com/xmake-io/xmake/issues/79): 增强`xmake lua`,支持交互式解释执行 ### 改进 * 修改菜单选项颜色 * [#71](https://github.com/xmake-io/xmake/issues/71): 针对widows编译器改进优化选项映射 * [#73](https://github.com/xmake-io/xmake/issues/73): 尝试获取可执行文件路径来作为xmake的脚本目录 * 在`add_subdirs`中的子`xmake.lua`中,使用独立子作用域,避免作用域污染导致的干扰问题 * [#78](https://github.com/xmake-io/xmake/pull/78): 美化非全屏终端窗口下的`xmake --help`输出 * 避免产生不必要的`.xmake`目录,如果不在工程中的时候 ### Bugs 修复 * [#67](https://github.com/xmake-io/xmake/issues/67): 修复 `sudo make install` 命令权限问题 * [#70](https://github.com/xmake-io/xmake/issues/70): 修复检测android编译器错误 * 修复临时文件路径冲突问题 * 修复`os.host`, `os.arch`等接口 * 修复根域api加载干扰其他子作用域问题 * [#77](https://github.com/xmake-io/xmake/pull/77): 修复`cprint`色彩打印中断问题 ## v2.1.3 ### 新特性 * [#65](https://github.com/xmake-io/xmake/pull/65): 为target添加`set_default`接口用于修改默认的构建所有targets行为 * 允许在工程子目录执行`xmake`命令进行构建,xmake会自动检测所在的工程根目录 * 添加`add_rpathdirs` api到target和option,支持动态库的自动加载运行 ### 改进 * [#61](https://github.com/xmake-io/xmake/pull/61): 提供更加安全的`xmake install` and `xmake uninstall`任务,更友好的处理root安装问题 * 提供`rpm`, `deb`和`osxpkg`安装包 * [#63](https://github.com/xmake-io/xmake/pull/63): 改进安装脚本,实现更加安全的构建和安装xmake * [#61](https://github.com/xmake-io/xmake/pull/61): 禁止在root权限下运行xmake命令,增强安全性 * 改进工具链检测,通过延迟延迟检测提升整体检测效率 * 当自动扫面生成`xmake.lua`时,添加更友好的用户提示,避免用户无操作 ### Bugs 修复 * 修复版本检测的错误提示信息 * [#60](https://github.com/xmake-io/xmake/issues/60): 修复macosx和windows平台的xmake自举编译 * [#64](https://github.com/xmake-io/xmake/issues/64): 修复构建android `armv8-a`架构失败问题 * [#50](https://github.com/xmake-io/xmake/issues/50): 修复构建android可执行程序,无法运行问题 ## v2.1.2 ### 新特性 * 添加aur打包脚本,并支持用`yaourt`包管理器进行安装。 * 添加[set_basename](#http://xmake.io/#/zh/manual?id=targetset_basename)接口,便于定制化修改生成后的目标文件名 ### 改进 * 支持vs2017编译环境 * 支持编译android版本的rust程序 * 增强vs201x工程生成插件,支持同时多模式、架构编译 ### Bugs 修复 * 修复编译android程序,找不到系统头文件问题 * 修复检测选项行为不正确问题 * [#57](https://github.com/xmake-io/xmake/issues/57): 修复代码文件权限到0644 ## v2.1.1 ### 新特性 * 添加`--links`, `--linkdirs` and `--includedirs` 配置参数 * 添加app2ipa插件 * 为`xmake.lua`工程描述增加dictionay语法风格 * 提供智能扫描编译模式,在无任何`xmake.lua`等工程描述文件的情况下,也能直接快速编译 * 为`xmake.lua`工程描述添加`set_xmakever`接口,更加友好的处理版本兼容性问题 * 为`objc`和`swift`程序添加`add_frameworks`接口 * 更加快速方便的多语言扩展支持,增加`golang`, `dlang`和`rust`程序构建的支持 * 添加`target_end`, `option_end` 和`task_end`等可选api,用于显示结束描述域,进入根域设置,提高可读性 * 添加`golang`, `dlang`和`rust`工程模板 ### 改进 * 工程生成插件支持vs2017 * 改进gcc/clang编译器警告和错误提示 * 重构代码架构,改进多语言支持,更加方便灵活的扩展语言支持 * 改进print接口,同时支持原生lua print以及格式化打印 * 如果xmake.lua不存在,自动扫描工程代码文件,并且生成xmake.lua进行编译 * 修改license,使用更加宽松的Apache License 2.0 * 移除一些二进制工具文件 * 移除install.bat脚本,提供windows nsis安装包支持 * 使用[docute](https://github.com/egoist/docute)重写[文档](http://www.xmake.io/#/zh/),提供更加完善的文档支持 * 增强`os.run`, `os.exec`, `os.cp`, `os.mv` 和 `os.rm` 等接口,支持通配符模式匹配和批量文件操作 * 精简和优化构建输出信息,添加`-q|--quiet`选项实现静默构建 * 改进`makefile`生成插件,抽取编译工具和编译选项到全局变量 ### Bugs 修复 * [#41](https://github.com/waruqi/xmake/issues/41): 修复在windows下自动检测x64失败问题 * [#43](https://github.com/waruqi/xmake/issues/43): 避免创建不必要的.xmake工程缓存目录 * 针对android版本添加c++ stl搜索目录,解决编译c++失败问题 * 修复在rhel 5.10上编译失败问题 * 修复`os.iorun`返回数据不对问题 ## v2.0.5 ### 新特性 * 为解释器作用域增加一些内建模块支持 * 针对windows x64平台,支持ml64汇编器 ### 改进 * 增强ipairs和pairs接口,支持过滤器模式,简化脚本代码 * 为vs201x工程生成增加文件filter * 移除`core/tools`目录以及msys工具链,在windows上使用xmake自编译core源码进行安装,优化xmake源码磁盘空间 * 移除`xmake/packages`,默认模板安装不再内置二进制packages,暂时需要手动放置,以后再做成自动包依赖下载编译 ### Bugs 修复 * 修复msvc的编译选项不支持问题:`-def:xxx.def` * 修复ml.exe汇编器脚本 * 修复选项链接顺序问题 ## v2.0.4 ### 新特性 * 在`xmake.lua`中添加原生shell支持,例如:`add_ldflags("$(shell pkg-config --libs sqlite3)")` * 编译windows目标程序,默认默认启用pdb符号文件 * 在windows上添加调试器支持(vsjitdebugger, ollydbg, windbg ... ) * 添加`getenv`接口到`xmake.lua`的全局作用域中 * 添加生成vstudio工程插件(支持:vs2002 - vs2015) * 为option添加`set_default`接口 ### 改进 * 增强内建变量的处理 * 支持字符串类型的选项option设置 ### Bugs 修复 * 修复在linux下检测ld连接器失败,如果没装g++的话 * 修复`*.cxx`编译失败问题 ## v2.0.3 ### 新特性 * 增加头文件依赖自动检测和增量编译,提高编译速度 * 在终端中进行颜色高亮提示 * 添加调试器支持,`xmake run -d program ...` ### 改进 * 增强运行shell的系列接口 * 更新luajit到v2.0.4版本 * 改进makefile生成插件,移除对xmake的依赖,并且支持`windows/linux/macosx`等大部分pc平台 * 优化多任务编译速度,在windows下编译提升较为明显 ### Bugs 修复 * 修复安装目录错误问题 * 修复`import`根目录错误问题 * 修复在多版本vs同时存在的情况下,检测vs环境失败问题 ## v2.0.2 ### 改进 * 修改安装和卸载的action处理 * 更新工程模板 * 增强函数检测 ### Bugs 修复 * [#7](https://github.com/waruqi/xmake/issues/7): 修复用模板创建工程后,target名不对问题:'[targetname]' * [#9](https://github.com/waruqi/xmake/issues/9): 修复clang不支持c++11的问题 * 修复api作用域泄露问题 * 修复在windows上的一些路径问题 * 修复检测宏函数失败问题 * 修复检测工具链失败问题 * 修复windows上编译android版本失败 ## v2.0.1 ### 新特性 * 增加task任务机制,可运行自定义任务脚本 * 实现plugin扩展机制,可以很方便扩展实现自定义插件,目前已实现的一些内置插件 * 增加project文件导出插件(目前已支持makefile的生成,后续会支持:vs, xcode等工程的生成) * 增加hello xmake插件(插件demo) * 增加doxygen文档生成插件 * 增加自定义宏脚本插件(支持动态宏记录、宏回放、匿名宏、批量导入、导出等功能) * 增加更多的类库用于插件化开发 * 实现异常捕获机制,简化上层调用逻辑 * 增加多个option进行宏绑定,实现配置一个参数,就可以同时对多个配置进行生效 * 增加显示全局构建进度 ### 改进 * 重构整个xmake.lua描述文件的解释器,更加的灵活可扩展 * 更加严格的语法检测机制 * 更加严格的作用域管理,实现沙盒引擎,对xmake.lua中脚本进行沙盒化处理,使得xmake.lua更加的安全 * 简化模板的开发,简单几行描述就可以扩展一个新的自定义工程模板 * 完全模块化platforms、tools、templates、actions,以及通过自注册机制,只需把自定义的脚本放入对应目录,就可实现快速扩展 * 针对所有可扩展脚本所需api进行大量简化,并实现大量类库,通过import机制进行导入使用 * 移除对gnu make/nmake等make工具的依赖,不再需要makefile,实现自己的make算法, * 优化构建速度,支持多任务编译(支持vs编译器)(实测:比v1.0.4提升x4倍的构建性能) * 优化自动检测机制,更加的稳定和准确 * 修改部分工程描述api,增强扩展性,减少一些命名歧义(对低版本向下兼容) * 优化静态库合并:`add_files("*.a")`,修复一些bug * 优化交叉编译,通过`--sdk=xxx`参数实现更加方便智能的进行交叉编译配置,简化mingw平台的编译配置 * 简化命令行配置开关, 支持`xmake config --xxx=[y|n|yes|no|true|false]`等开关值 * 合并iphoneos和iphonesimulator平台,以及watchos和watchsimulator平台,通过arch来区分,使得打包更加方便,能够支持一次性打包iphoneos的所有arch到一个包中 ### Bugs 修复 * [#3](https://github.com/waruqi/xmake/issues/3): 修复ArchLinux 编译失败问题 * [#4](https://github.com/waruqi/xmake/issues/4): 修复windows上安装失败问题 * 修复windows上环境变量设置问题 ## v1.0.4 ### 新特性 * 增加对windows汇编器的支持 * 为xmake create增加一些新的工程模板,支持tbox版本 * 支持swift代码 * 针对-v参数,增加错误输出信息 * 增加apple编译平台:watchos, watchsimulator的编译支持 * 增加对windows: x64, amd64, x86_amd64架构的编译支持 * 实现动态库和静态库的快速切换 * 添加-j/--jobs参数,手动指定是否多任务编译,默认改为单任务编译 ### 改进 * 增强`add_files`接口,支持直接添加`*.o/obj/a/lib`文件,并且支持静态库的合并 * 裁剪xmake的安装过程,移除一些预编译的二进制程序 ### Bugs 修复 * [#1](https://github.com/waruqi/xmake/issues/4): 修复win7上安装失败问题 * 修复和增强工具链检测 * 修复一些安装脚本的bug, 改成外置sudo进行安装 * 修复linux x86_64下安装失败问题 ## v1.0.3 ### 新特性 * 添加set_runscript接口,支持自定义运行脚本扩展 * 添加import接口,使得在xmake.lua中可以导入一些扩展模块,例如:os,path,utils等等,使得脚本更灵活 * 添加android平台arm64-v8a支持 ### Bugs 修复 * 修复set_installscript接口的一些bug * 修复在windows x86_64下,安装失败的问题 * 修复相对路径的一些bug ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [waruqi@gmail.com]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org # Contributor Covenant行为准则 # 参与者公约 ## 我们的保证 为了促进一个开放透明且友好的环境,我们作为贡献者和维护者保证:无论年龄、种族、民族、性别认同和表达(方式)、体型、身体健全与否、经验水平、国籍、个人表现、宗教或性别取向,参与者在我们项目和社区中都免于骚扰。 ## 我们的标准 有助于创造正面环境的行为包括但不限于: * 使用友好和包容性语言 * 尊重不同的观点和经历 * 耐心地接受建设性批评 * 关注对社区最有利的事情 * 友善对待其他社区成员 身为参与者不能接受的行为包括但不限于: * 使用与性有关的言语或是图像,以及不受欢迎的性骚扰 * 捣乱/煽动/造谣的行为或进行侮辱/贬损的评论,人身攻击及政治攻击 * 公开或私下的骚扰 * 未经许可地发布他人的个人资料,例如住址或是电子地址 * 其他可以被合理地认定为不恰当或者违反职业操守的行为 ## 我们的责任 项目维护者有责任为「可接受的行为」标准做出诠释,以及对已发生的不被接受的行为采取恰当且公平的纠正措施。 项目维护者有权利及责任去删除、编辑、拒绝与本行为标准有所违背的评论 (comments)、提交 (commits)、代码、wiki 编辑、问题 (issues) 和其他贡献,以及项目维护者可暂时或永久性的禁止任何他们认为有不适当、威胁、冒犯、有害行为的贡献者。 ## 使用范围 当一个人代表该项目或是其社区时,本行为标准适用于其项目平台和公共平台。 代表项目或是社区的情况,举例来说包括使用官方项目的电子邮件地址、通过官方的社区媒体账号发布或线上或线下事件中担任指定代表。 该项目的呈现方式可由其项目维护者进行进一步的定义及解释。 ## 强制执行 可以通过[waruqi@gmail.com],来联系项目团队来举报滥用、骚扰或其他不被接受的行为。 任何维护团队认为有必要且适合的所有投诉都将进行审查及调查,并做出相对应的回应。项目小组有对事件回报者有保密的义务。具体执行的方针近一步细节可能会单独公布。 没有切实地遵守或是执行本行为标准的项目维护人员,可能会因项目领导人或是其他成员的决定,暂时或是永久地取消其参与资格。 ## 来源 本行为标准改编自[贡献者公约][主页],版本 1.4 可在此观看https://www.contributor-covenant.org/zh-cn/version/1/4/code-of-conduct.html [主页]: https://www.contributor-covenant.org ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing If you discover issues, have ideas for improvements or new features, or want to contribute a new module, please report them to the [issue tracker][1] of the repository or submit a pull request. Please, try to follow these guidelines when you do so. ## Issue reporting * Check that the issue has not already been reported. * Check that the issue has not already been fixed in the latest code (a.k.a. `master`). * Be clear, concise and precise in your description of the problem. * Open an issue with a descriptive title and a summary in grammatically correct, complete sentences. * Include any relevant code to the issue summary. ## Pull requests * Please update your local branch to the latest before submitting a pull request to ensure no merge conflicts. * Use a topic branch to easily amend a pull request later, if necessary. * Write good commit messages. * Please use English for commit messages to standardize the log format. * Use the same coding conventions as the rest of the project. * Ensure your edited codes with four spaces instead of TAB. * Please commit code to `dev` branch and we will merge into `master` branch in future. * If it involves public API changes, please create a corresponding feature request in issues first, then describe the design of the new API in detail. It needs to be approved before you can start creating a PR to add and implement them, rather than directly opening a PR to add or modify new APIs at will. ## Development Guide ### Compiling Source Code 1. Download source code ```bash git clone --recursive https://github.com/xmake-io/xmake.git cd xmake ``` 2. Compile * Linux/macOS ```bash ./configure make ``` * Windows ```bash cd core xmake ``` ### Local Debugging If you want to debug the local xmake source code, you can run the following command to load the local environment. * Linux/macOS ```bash source scripts/srcenv.profile xmake --version ``` * Windows Run `scripts\srcenv.bat` directly. After loading the environment, we can directly modify the Lua script in the source code directory, and then run `xmake` to verify the modification effect in real time, without reinstalling. ### Environment Variables for Debugging * `XMAKE_PROGRAM_DIR`: This environment variable specifies the directory containing Xmake's Lua scripts. By setting this to your local `xmake` source directory (e.g., `path/to/xmake/xmake`), you can force Xmake to use your local scripts. This allows you to test changes to Lua scripts immediately without re-compiling or re-installing. * `XMAKE_PROGRAM_FILE`: This environment variable specifies the path to the `xmake` executable. It ensures that the correct binary is used, which is useful when you have multiple Xmake versions or want to test a locally compiled binary. The `source scripts/srcenv.profile` (or `srcenv.bat`) command automatically sets these variables for you. ### Run Tests Run the tests using the following command (Please ensure the local environment is loaded): ```bash xmake l tests/run.lua [testname] ``` ### Source Code Structure The xmake source code is mainly divided into two parts: the C core and the Lua scripts. * `core/`: The C core implementation, including the Lua runtime, cross-platform abstraction layer, and native API implementation. * `xmake/`: The Lua script implementation, containing the core logic, modules, actions, and platforms. #### Architecture Design Xmake adopts a separation of concern design, where the performance-critical parts are implemented in C, and the build logic is implemented in Lua. * **Sandbox**: User's `xmake.lua` and plugin scripts run in a sandbox environment to ensure safety and isolation. The sandbox API is defined in `xmake/core/sandbox`. * **Core Modules**: The core Lua modules are located in `xmake/core`. * **Actions**: Built-in actions (like `build`, `run`, `install`) are in `xmake/actions`. * **Modules**: Extension modules are in `xmake/modules`. * **Base API**: Utility scripts run in a base lua environment. Base API is in `xmake/core/base`. * **Native API**: The Lua API and Xmake extension API, written in C, are located in `core/src/xmake`. For example, when you call `os.cp()` in `xmake.lua`: `sandbox_os.cp()` (Sandbox) -> `os.cp()` (Base) -> `xm_os_cpdir()` (Native C) -> `tb_directory_copy()` (Tbox) ## Financial contributions If you want to contribute to Xmake but are unable to contribute code due to technical or time constraints, you can also support the further development of the community through [financial contributions](https://xmake.io/about/sponsor). # 贡献代码 如果你发现一些问题,或者想新增或者改进某些新特性,或者想贡献一个新的模块 那么你可以在[issues][1]上提交反馈,或者发起一个提交代码的请求(pull request). ## 问题反馈 * 确认这个问题没有被反馈过 * 确认这个问题最近还没有被修复,请先检查下 `master` 的最新提交 * 请清晰详细地描述你的问题 * 请使用语法正确、完整的句子,开启一个带有描述性标题和摘要的 issue * 如果发现某些代码存在问题,请在issue上引用相关代码 ## 提交代码 * 请先更新你的本地分支到最新,再进行提交代码请求,确保没有合并冲突 * 如果需要,使用 topic 分支以便稍后轻松修改 pull request * 编写友好可读的提交信息 * 请使用与工程代码相同的代码规范 * 确保提交的代码缩进是四个空格,而不是tab * 请提交代码到`dev`分支,如果通过,我们会在特定时间合并到`master`分支上 * 为了规范化提交日志的格式,commit消息,不要用中文,请用英文描述 * 如果涉及公开的 API 改动,请先在 issues 中创建对应的 feature request ,然后详细描述下 新 API 的设计,并且需要经过赞同后,才能开始创建 pr 去添加和实现它们,而不是直接打开 pr 去随意添加修改新的 API ## 开发指南 ### 源码编译 1. 下载源码 ```bash git clone --recursive https://github.com/xmake-io/xmake.git cd xmake ``` 2. 编译 * Linux/macOS ```bash ./configure make ``` * Windows ```bash cd core xmake ``` ### 本地调试 如果想要调试本地 xmake 源码,可以运行以下命令加载本地环境。 * Linux/macOS ```bash source scripts/srcenv.profile xmake --version ``` * Windows 直接运行 `scripts\srcenv.bat`。 加载环境后,我们就可以直接修改源码目录下的 Lua 脚本,然后运行 `xmake` 即可实时验证修改效果,无需重新安装。 ### 调试环境变量 * `XMAKE_PROGRAM_DIR`: 指定 Xmake 的 Lua 脚本目录。将其设置为本地源码中的 `xmake` 目录(例如 `path/to/xmake/xmake`),可以让 Xmake 直接加载本地脚本。这样修改 Lua 脚本后无需重新编译安装即可生效,非常适合调试脚本逻辑。 * `XMAKE_PROGRAM_FILE`: 指定 `xmake` 可执行文件的路径。确保使用指定的二进制文件运行,适用于多版本共存或测试本地编译生成的二进制文件。 `source scripts/srcenv.profile` (或 `srcenv.bat`) 脚本会自动为你设置这些环境变量。 ### 运行测试 使用以下命令运行测试(请确保本地环境已经加载): ```bash xmake l tests/run.lua [testname] ``` ### 源码结构 Xmake 的源码主要分为两部分:C 核心和 Lua 脚本。 * `core/`: C 核心实现,包括 Lua 运行时、跨平台抽象层和原生 API 实现。 * `xmake/`: Lua 脚本实现,包含核心逻辑、模块、操作和平台支持。 #### 架构设计 Xmake 采用关注点分离的设计,性能敏感的部分由 C 实现,而构建逻辑由 Lua 实现。 * **沙盒 (Sandbox)**: 用户的 `xmake.lua` 和插件脚本运行在沙盒环境中,以确保安全性和隔离性。沙盒 API 定义在 `xmake/core/sandbox` 中。 * **核心模块 (Core Modules)**: 核心 Lua 模块位于 `xmake/core`。 * **操作 (Actions)**: 内置操作(如 `build`, `run`, `install`)位于 `xmake/actions`。 * **模块 (Modules)**: 扩展模块位于 `xmake/modules`。 * **基础 API (Base API)**: 工具脚本运行在基础 Lua 环境中。基础 API 位于 `xmake/core/base`。 * **原生 API (Native API)**: 包含 Lua API 和 Xmake 扩展 API,用 C 编写,位于 `core/src/xmake`。 例如,当你在 `xmake.lua` 中调用 `os.cp()` 时: `sandbox_os.cp()` (Sandbox) -> `os.cp()` (Base) -> `xm_os_cpdir()` (Native C) -> `tb_directory_copy()` (Tbox) ## 资金赞助 如果您想要为 Xmake 做贡献,但受限于技术能力或时间无法参与代码开发,也可以通过[资金赞助](https://xmake.io/about/sponsor)来支持社区的进一步发展。 [1]: https://github.com/xmake-io/xmake/issues ================================================ FILE: LICENSE.md ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015-present Xmake Open Source Community Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: NOTICE.md ================================================ A cross-platform build utility based on Lua Copyright 2015-present, The Xmake Open Source Community This product includes software developed by The Xmake Open Source Community (https://xmake.io/). ------------------------------------------------------------------------------- This product depends on 'lua-cjson', The Lua CJSON module provides JSON support for Lua, which can be obtained at: * LICENSE: * core/src/lua-cjson/lua-cjson/LICENSE (MIT License) * HOMEPAGE: * https://www.kyne.com.au/~mark/software/lua-cjson.php This product depends on 'pdcurses', an implementation of X/Open curses for multiple platforms, which can be obtained at: * LICENSE: * Public Domain License * HOMEPAGE: * http://pdcurses.org/ This product depends on 'libsv', Public domain semantic versioning in c, which can be obtained at: * LICENSE: * core/src/sv/sv/UNLICENSE (Public Domain License) * HOMEPAGE: * https://github.com/uael/sv This product depends on 'LuaJIT', a Just-In-Time Compiler for Lua, which can be obtained at: * LICENSE: * core/src/luajit/luajit/COPYRIGHT (MIT License) * HOMEPAGE: * http://luajit.org/ This product depends on 'Lua', The Lua Programming Language, which can be obtained at: * LICENSE: * https://www.lua.org/license.html (MIT License) * HOMEPAGE: * http://lua.org/ This product depends on 'lz4', Extremely Fast Compression algorithm, which can be obtained at: * LICENSE: * https://github.com/lz4/lz4/blob/dev/LICENSE * HOMEPAGE: * https://www.lz4.org/ This product depends on 'xxHash', Extremely fast non-cryptographic hash algorithm, which can be obtained at: * LICENSE: * https://github.com/Cyan4973/xxHash/blob/dev/LICENSE * HOMEPAGE: * https://www.xxhash.com/ This product depends on 'tbox', The Treasure Box Library, which can be obtained at: * LICENSE: * core/src/tbox/tbox/LICENSE.md (Apache License 2.0) * HOMEPAGE: * https://tboox.org/ ================================================ FILE: README.md ================================================

xmake

github-ci github-ci github-ci Github All Releases
license Reddit Telegram QQ Discord Donate
A cross-platform build utility based on Lua
Modern C/C++ build tool: Simple, Fast, Powerful dependency package integration
## Support this project Support this project by [becoming a sponsor](https://xmake.io/about/sponsor.html). Your logo will show up here with a link to your website. 🙏 ## Introduction ([中文](/README_zh.md)) What is Xmake? 1. Xmake is a cross-platform build utility based on the Lua scripting language. 2. Xmake is very lightweight and has no dependencies outside of the standard library. 3. Uses the `xmake.lua` file to maintain project builds with a simple and readable syntax. Xmake can be used to directly build source code (like with Make or Ninja), or it can generate project source files like CMake or Meson. It also has a *built-in* package management system to help users integrate C/C++ dependencies. ``` Xmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache ``` Although less precise, one can still understand Xmake in the following way: ``` Xmake ≈ Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache ``` If you want to know more, please refer to the [Documentation](https://xmake.io/guide/quick-start), [GitHub](https://github.com/xmake-io/xmake) or [Gitee](https://gitee.com/tboox/xmake). You are also welcome to join our [community](https://xmake.io/about/contact). The official Xmake repository can be found at [xmake-io/xmake-repo](https://github.com/xmake-io/xmake-repo). ![](https://github.com/xmake-io/xmake-docs/raw/master/docs/public/assets/img/index/xmake-basic-render.gif) ## Installation ### With cURL ```bash curl -fsSL https://xmake.io/shget.text | bash ``` ### With Wget ```bash wget https://xmake.io/shget.text -O - | bash ``` ### With PowerShell ```sh irm https://xmake.io/psget.text | iex ``` ### Other installation methods If you don't want to use the above scripts to install Xmake, visit the [Installation Guide](https://xmake.io/guide/quick-start.html#installation) for other installation methods (building from source, package managers, etc.). ## Simple Project Description ```lua target("console") set_kind("binary") add_files("src/*.c") ``` Creates a new target `console` of kind `binary`, and adds all the files ending in `.c` in the `src` directory. ## Package dependencies ```lua add_requires("tbox 1.6.*", "zlib", "libpng ~1.6") ``` Adds a requirement of tbox v1.6, zlib (any version), and libpng v1.6. The official xmake package repository exists at: [xmake-repo](https://github.com/xmake-io/xmake-repo)

## Command line interface reference The below assumes you are currently in the project's root directory. ### Build a project ```bash $ xmake ``` ### Run target ```bash $ xmake run console ``` ### Debug target ```bash $ xmake run -d console ``` ### Run test ```bash $ xmake test ``` ### Configure platform ```bash $ xmake f -p [windows|linux|macosx|android|iphoneos ..] -a [x86|arm64 ..] -m [debug|release] $ xmake ``` ### Menu configuration ```bash $ xmake f --menu ```

## Supported platforms * Windows (x86, x64, arm, arm64, arm64ec) * macOS (i386, x86_64, arm64) * Linux (i386, x86_64, arm, arm64, riscv, mips, 390x, sh4 ...) * FreeBSD (i386, x86_64) * NetBSD (i386, x86_64) * OpenBSD (i386, x86_64) * DragonflyBSD (i386, x86_64) * Solaris (i386, x86_64) * Android (x86, x86_64, armeabi, armeabi-v7a, arm64-v8a) * iOS (armv7, armv7s, arm64, i386, x86_64) * WatchOS (armv7k, i386) * AppleTVOS (armv7, arm64, i386, x86_64) * AppleXROS (arm64, x86_64) * MSYS (i386, x86_64) * MinGW (i386, x86_64, arm, arm64) * Cygwin (i386, x86_64) * Wasm (wasm32, wasm64) * Haiku (i386, x86_64) * Harmony (x86_64, armeabi-v7a, arm64-v8a) * Cross (cross-toolchains ..) ## Supported toolchains ```bash $ xmake show -l toolchains xcode Xcode IDE msvc Microsoft Visual C/C++ Compiler clang-cl LLVM Clang C/C++ Compiler compatible with msvc yasm The Yasm Modular Assembler clang A C language family frontend for LLVM go Go Programming Language Compiler dlang D Programming Language Compiler (Auto) dmd D Programming Language Compiler ldc The LLVM-based D Compiler gdc The GNU D Compiler (GDC) gfortran GNU Fortran Programming Language Compiler flang LLVM Fortran Compiler zig Zig Programming Language Compiler zigcc Use zig cc/c++ as C/C++ Compiler sdcc Small Device C Compiler cuda CUDA Toolkit (nvcc, nvc, nvc++, nvfortran) ndk Android NDK rust Rust Programming Language Compiler swift Swift Programming Language Compiler llvm A collection of modular and reusable compiler and toolchain technologies cross Common cross compilation toolchain nasm NASM Assembler gcc GNU Compiler Collection mingw Minimalist GNU for Windows gnu-rm GNU Arm Embedded Toolchain envs Environment variables toolchain fasm Flat Assembler tinycc Tiny C Compiler emcc A toolchain for compiling to asm.js and WebAssembly icc Intel C/C++ Compiler ifort Intel Fortran Compiler ifx Intel LLVM Fortran Compiler muslcc The musl-based cross-compilation toolchain fpc Free Pascal Programming Language Compiler wasi WASI-enabled WebAssembly C/C++ toolchain nim Nim Programming Language Compiler dotnet .NET SDK Toolchain circle A new C++20 compiler armcc ARM Compiler Version 5 of Keil MDK armclang ARM Compiler Version 6 of Keil MDK c51 Keil development tools for the 8051 Microcontroller Architecture icx Intel LLVM C/C++ Compiler dpcpp Intel LLVM C++ Compiler for data parallel programming model based on Khronos SYCL masm32 The MASM32 SDK iverilog Icarus Verilog verilator Verilator open-source SystemVerilog simulator and lint system cosmocc build-once run-anywhere hdk Harmony SDK ti-c2000 TI-CGT C2000 compiler ti-c6000 TI-CGT C6000 compiler iararm IAR ARM C/C++ Compiler kotlin-native Kotlin Native Programming Language Compiler ``` ## Supported languages * C and C++ * Objective-C and Objective-C++ * Swift * Assembly * Golang * Rust * Dlang * Fortran * Cuda * Zig * Vala * Pascal * Nim * Verilog * FASM * NASM * YASM * MASM32 * Cppfront * Kotlin * C# ## Features Xmake exhibits: * Simple yet flexible configuration grammar. * Quick, dependency-free installation. * Easy compilation for most all supported platforms. * Supports cross-compilation with intelligent analysis of cross toolchain information. * Extremely fast parallel compilation support. * Supports C++ modules (new in C++20). * Supports cross-platform C/C++ dependencies with built-in package manager. * Multi-language compilation support including mixed-language projects. * Rich plug-in support with various project generators (ex. Visual Studio/Makefiles/CMake/`compile_commands.json`) * REPL interactive execution support * Incremental compilation support with automatic analysis of header files * Built-in toolchain management * A large number of expansion modules * Remote compilation support * Distributed compilation support * Local and remote build cache support ## Supported Project Types Xmake supports the below types of projects: * Static libraries * Shared libraries * Console/CLI applications * CUDA programs * Qt applications * WDK drivers (umdf/kmdf/wdm) * WinSDK applications * MFC applications * Darwin applications (with metal support) * Frameworks and bundles (in Darwin) * SWIG modules (Lua, Python, ...) * LuaRocks modules * Protobuf programs * Lex/Yacc programs * Linux kernel modules ## Package management ### Download and build Xmake can automatically fetch and install dependencies!

### Supported package repositories * Official package repository [xmake-repo](https://github.com/xmake-io/xmake-repo) (tbox >1.6.1) * Official package manager [Xrepo](https://github.com/xmake-io/xrepo) * [User-built repositories](https://xmake.io/guide/package-management/using-official-packages.html#using-self-built-private-package-repository) * Conan (conan::openssl/1.1.1g) * Conda (conda::libpng 1.3.67) * Vcpkg (vcpkg:ffmpeg) * Homebrew/Linuxbrew (brew::pcre2/libpcre2-8) * Pacman on archlinux/msys2 (pacman::libcurl) * Apt on ubuntu/debian (apt::zlib1g-dev) * Clib (clib::clibs/bytes@0.0.4) * Dub (dub::log 0.4.3) * Portage on Gentoo/Linux (portage::libhandy) * Nimble for nimlang (nimble::zip >1.3) * Cargo for rust (cargo::base64 0.13.0) * Zypper on openSUSE (zypper::libsfml2 2.5) ### Package management features * The official repository provides nearly 500+ packages with simple compilation on all supported platforms * Full platform package support, support for cross-compiled dependent packages * Support package virtual environment using `xrepo env shell` * Precompiled package acceleration for Windows (NT) * Support self-built package repositories and private repository deployment * Third-party package repository support for repositories such as: vcpkg, conan, conda, etc. * Supports automatic pulling of remote toolchains * Supports dependency version locking ## Processing architecture Below is a diagram showing roughly the architecture of Xmake, and thus how it functions.

## Distributed Compilation - [X] Cross-platform support. - [X] Support for MSVC, Clang, GCC and other cross-compilation toolchains. - [X] Support for building for Android, Linux, Windows NT, and Darwin hosts. - [X] No dependencies other than the compilation toolchain. - [X] Support for build server load balancing scheduling. - [X] Support for real time compressed transfer of large files (lz4). - [X] Almost zero configuration cost, no shared filesystem required, for convenience and security. For more details see: [Distributed Compilation](https://xmake.io/guide/extras/distributed-compilation.html) ## Remote Compilation For more details see: [Remote Compilation](https://xmake.io/guide/extras/remote-compilation.html) ## Local/Remote Build Cache For more details see: [Build Cache Acceleration](https://xmake.io/guide/extras/build-cache.html) ## Benchmark Xmake's speed on is par with Ninja! The test project: [xmake-core](https://github.com/xmake-io/xmake/tree/master/core) ### Multi-task parallel compilation | buildsystem | Termux (8core/-j12) | buildsystem | MacOS (8core/-j12) | | ------------------ | --------------------- | ------------------ | -------------------- | | xmake | 24.890s | xmake | 12.264s | | ninja | 25.682s | ninja | 11.327s | | cmake(gen+make) | 5.416s+28.473s | cmake(gen+make) | 1.203s+14.030s | | cmake(gen+ninja) | 4.458s+24.842s | cmake(gen+ninja) | 0.988s+11.644s | ## Single task compilation | buildsystem | Termux (-j1) | buildsystem | MacOS (-j1) | | ------------------ | ------------------ | ------------------ | ---------------- | | xmake | 1m57.707s | xmake | 39.937s | | ninja | 1m52.845s | ninja | 38.995s | | cmake(gen+make) | 5.416s+2m10.539s | cmake(gen+make) | 1.203s+41.737s | | cmake(gen+ninja) | 4.458s+1m54.868s | cmake(gen+ninja) | 0.988s+38.022s | ## More Examples ### Debug and release profiles ```lua add_rules("mode.debug", "mode.release") target("console") set_kind("binary") add_files("src/*.c") if is_mode("debug") then add_defines("DEBUG") end ``` ### Custom scripts ```lua target("test") set_kind("binary") add_files("src/*.c") after_build(function (target) print("hello: %s", target:name()) os.exec("echo %s", target:targetfile()) end) ``` ### Automatic integration of dependent packages Download and use packages in [xmake-repo](https://github.com/xmake-io/xmake-repo) or third-party repositories: ```lua add_requires("tbox >1.6.1", "libuv master", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8") add_requires("conan::openssl/1.1.1g", {alias = "openssl", optional = true, debug = true}) target("test") set_kind("binary") add_files("src/*.c") add_packages("tbox", "libuv", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8", "openssl") ``` In addition, we can also use the [xrepo](https://github.com/xmake-io/xrepo) command to quickly install dependencies. ### Qt QuickApp Program ```lua target("test") add_rules("qt.quickapp") add_files("src/*.cpp") add_files("src/qml.qrc") ``` ### Cuda Program ```lua target("test") set_kind("binary") add_files("src/*.cu") add_cugencodes("native") add_cugencodes("compute_75") ``` ### WDK/UMDF Driver Program ```lua target("echo") add_rules("wdk.driver", "wdk.env.umdf") add_files("driver/*.c") add_files("driver/*.inx") add_includedirs("exe") target("app") add_rules("wdk.binary", "wdk.env.umdf") add_files("exe/*.cpp") ``` For more WDK driver examples (UMDF/KMDF/WDM), please visit [WDK Program Examples](https://xmake.io/examples/cpp/wdk.html) ### Darwin Applications ```lua target("test") add_rules("xcode.application") add_files("src/*.m", "src/**.storyboard", "src/*.xcassets") add_files("src/Info.plist") ``` ### Framework and Bundle Program (Darwin) ```lua target("test") add_rules("xcode.framework") -- or xcode.bundle add_files("src/*.m") add_files("src/Info.plist") ``` ### OpenMP Program ```lua add_requires("libomp", {optional = true}) target("loop") set_kind("binary") add_files("src/*.cpp") add_rules("c++.openmp") add_packages("libomp") ``` ### Zig Program ```lua target("test") set_kind("binary") add_files("src/main.zig") ``` ### Automatically fetch remote toolchain #### fetch a special version of LLVM Require the Clang version packaged with LLM-10 to compile a project. ```lua add_requires("llvm 10.x", {alias = "llvm-10"}) target("test") set_kind("binary") add_files("src/*.c") set_toolchains("llvm@llvm-10") ``` #### Fetch a cross-compilation toolchain We can also pull a specified cross-compilation toolchain in to compile the project. ```lua add_requires("muslcc") target("test") set_kind("binary") add_files("src/*.c") set_toolchains("@muslcc") ``` #### Fetch toolchain and packages We can also use the specified `muslcc` cross-compilation toolchain to compile and integrate all dependent packages. ```lua add_requires("muslcc") add_requires("zlib", "libogg", {system = false}) set_toolchains("@muslcc") target("test") set_kind("binary") add_files("src/*.c") add_packages("zlib", "libogg") ``` ## Plugins #### Generate IDE project file plugin(makefile, vs2002 - vs2026 .. ) ```bash $ xmake project -k vsxmake -m "debug,release" # New vsproj generator (Recommended) $ xmake project -k vs -m "debug,release" $ xmake project -k cmake $ xmake project -k ninja $ xmake project -k compile_commands ``` #### Run a custom lua script plugin ```bash $ xmake l ./test.lua $ xmake l -c "print('hello xmake!')" $ xmake l lib.detect.find_tool gcc $ xmake l > print("hello xmake!") > {1, 2, 3} < { 1, 2, 3 } ``` To see a list of builtin plugins, please visit [Builtin plugins](https://xmake.io/guide/extensions/builtin-plugins.html). Please download and install other plugins from the plugins repository [xmake-plugins](https://github.com/xmake-io/xmake-plugins). ## IDE/Editor Integration * [xmake-vscode](https://github.com/xmake-io/xmake-vscode) * [xmake-sublime](https://github.com/xmake-io/xmake-sublime) * [xmake-idea](https://github.com/xmake-io/xmake-idea) * [xmake-zed](https://github.com/xmake-io/xmake-zed) (thanks [@jeleferai](https://github.com/jeleferai)) * [xmake.vim](https://github.com/luzhlon/xmake.vim) (third-party, thanks [@luzhlon](https://github.com/luzhlon)) * [xmake-visualstudio](https://github.com/HelloWorld886/xmake-visualstudio) (third-party, thanks [@HelloWorld886](https://github.com/HelloWorld886)) * [xmake-qtcreator](https://github.com/Arthapz/xmake-project-manager) (third-party, thanks [@Arthapz](https://github.com/Arthapz)) ### Xmake Gradle Plugin (JNI) We can use the [xmake-gradle](https://github.com/xmake-io/xmake-gradle) plugin to compile JNI libraries via gradle. ``` plugins { id 'org.tboox.gradle-xmake-plugin' version '1.1.5' } android { externalNativeBuild { xmake { path "jni/xmake.lua" } } } ``` The `xmakeBuild` task will be injected into the `assemble` task automatically if the `gradle-xmake-plugin` has been applied. ```console $ ./gradlew app:assembleDebug > Task :nativelib:xmakeConfigureForArm64 > Task :nativelib:xmakeBuildForArm64 >> xmake build [ 50%]: cache compiling.debug nativelib.cc [ 75%]: linking.debug libnativelib.so [100%]: build ok! >> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/arm64-v8a > Task :nativelib:xmakeConfigureForArmv7 > Task :nativelib:xmakeBuildForArmv7 >> xmake build [ 50%]: cache compiling.debug nativelib.cc [ 75%]: linking.debug libnativelib.so [100%]: build ok! >> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/armeabi-v7a > Task :nativelib:preBuild > Task :nativelib:assemble > Task :app:assembleDebug ``` ## CI Integration ### GitHub Action The [github-action-setup-xmake](https://github.com/xmake-io/github-action-setup-xmake) plugin for GitHub Actions can allow you to use Xmake with minimal efforts if you use GitHub Actions for your CI pipeline. ```yaml uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: latest ``` ## Who is using Xmake? The list of people and projects who are using Xmake is available [here](https://xmake.io/about/who_is_using_xmake.html). If you are using Xmake, you are welcome to submit your information to the above list through a PR, so that other users and the developers can gauge interest. This also lets users use xmake more confidently and gives us motivation to continue to maintain it. This will help the Xmake project and it's community grow stronger and expand! ## Contacts * Email:[waruqi@gmail.com](mailto:waruqi@gmail.com) * Homepage:[xmake.io](https://xmake.io) * Community - [Chat on Reddit](https://www.reddit.com/r/xmake/) - [Chat on Telegram](https://t.me/tbooxorg) - [Chat on Discord](https://discord.gg/xmake) - Chat on QQ Group: 343118190, 662147501 * Source Code:[GitHub](https://github.com/xmake-io/xmake), [Gitee](https://gitee.com/tboox/xmake) * WeChat Public: tboox-os ## Thanks This project exists thanks to all the people who have [contributed](CONTRIBUTING.md): * [TitanSnow](https://github.com/TitanSnow): Provide the xmake [logo](https://github.com/TitanSnow/ts-xmake-logo) and install scripts * [uael](https://github.com/uael): Provide the semantic versioning library [sv](https://github.com/uael/sv) * [OpportunityLiu](https://github.com/OpportunityLiu): Improve cuda, tests and ci * [xq144](https://github.com/xq114): Improve `xrepo env shell`, and contribute a lot of packages to the [xmake-repo](https://github.com/xmake-io/xmake-repo) repository. * [star-hengxing](https://github.com/star-hengxing): Contribute a lot of packages to the [xmake-repo](https://github.com/xmake-io/xmake-repo) repository. * [Arthapz](https://github.com/Arthapz): Contribute new C++ Modules implementation. * [SirLynix](https://github.com/SirLynix): Contributed many packages and let more people know about xmake. * `enderger`: Helped smooth out the edges on the English translation of the README ### Powered by [![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSource) ================================================ FILE: README_zh.md ================================================

xmake

github-ci github-ci github-ci Github All Releases
license Reddit Telegram QQ Discord Donate
A cross-platform build utility based on Lua
Modern C/C++ build tools, Simple, Fast, Powerful dependency package integration
## 项目支持 通过[成为赞助者](https://xmake.io/zh/about/sponsor.html)来支持该项目。您的logo将显示在此处,并带有指向您网站的链接。🙏 ## 简介 Xmake 是一个基于 Lua 的轻量级跨平台构建工具。 它非常的轻量,没有任何依赖,因为它内置了 Lua 运行时。 它使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对新手非常友好,短时间内就能快速入门,能够让用户把更多的精力集中在实际的项目开发上。 我们能够使用它像 Make/Ninja 那样可以直接编译项目,也可以像 CMake/Meson 那样生成工程文件,另外它还有内置的包管理系统来帮助用户解决 C/C++ 依赖库的集成使用问题。 目前,Xmake 主要用于 C/C++ 项目的构建,但是同时也支持其他 native 语言的构建,可以实现跟 C/C++ 进行混合编译,同时编译速度也是非常的快,可以跟 Ninja 持平。 ``` Xmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache ``` 尽管不是很准确,但我们还是可以把 Xmake 按下面的方式来理解: ``` Xmake ≈ Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache ``` 如果你想要了解更多,请参考:[在线文档](https://xmake.io/zh/guide/quick-start.html), [Github](https://github.com/xmake-io/xmake)以及[Gitee](https://gitee.com/tboox/xmake) 和 [GitCode](https://gitcode.com/xmake-io/xmake),同时也欢迎加入我们的 [社区](https://xmake.io/zh/about/contact)。 ![](https://github.com/xmake-io/xmake-docs/raw/master/docs/public/assets/img/index/xmake-basic-render.gif) ## 课程 xmake 官方也推出了一些入门课程,带你一步步快速上手 xmake,课程列表如下: * [Xmake 带你轻松构建 C/C++ 项目](https://xmake.io/zh/about/course) ## 安装 #### 使用curl ```bash curl -fsSL https://xmake.io/shget.text | bash ``` #### 使用wget ```bash wget https://xmake.io/shget.text -O - | bash ``` #### 使用powershell ```powershell irm https://xmake.io/psget.text | iex ``` #### 其他安装方式 如果不想使用脚本安装,也可以点击查看 [安装文档](https://xmake.io/zh/guide/quick-start.html#installation),了解其他安装方法。 ## 简单的工程描述 ```lua target("hello") set_kind("binary") add_files("src/*.cpp") ``` ## 包依赖描述 ```lua add_requires("tbox 1.6.*", "zlib", "libpng ~1.6") ``` 官方的xmake包管理仓库: [xmake-repo](https://github.com/xmake-io/xmake-repo) ## 命令行使用 ### 创建工程 ```bash $ xmake create hello $ cd hello ``` ### 构建工程 ```bash $ xmake ``` ### 运行目标 ```bash $ xmake run console ``` ### 调试程序 ```bash $ xmake run -d console ``` ### 运行测试 ```bash $ xmake test ``` ### 配置平台 ```bash $ xmake f -p [windows|linux|macosx|android|iphoneos ..] -a [x86|arm64 ..] -m [debug|release] $ xmake ``` ### 图形化菜单配置 ```bash $ xmake f --menu ``` ## 跟ninja一样快的构建速度 测试工程: [xmake-core](https://github.com/xmake-io/xmake/tree/master/core) ### 多任务并行编译测试 | 构建系统 | Termux (8core/-j12) | 构建系统 | MacOS (8core/-j12) | |----- | ---- | --- | --- | |xmake | 24.890s | xmake | 12.264s | |ninja | 25.682s | ninja | 11.327s | |cmake(gen+make) | 5.416s+28.473s | cmake(gen+make) | 1.203s+14.030s | |cmake(gen+ninja) | 4.458s+24.842s | cmake(gen+ninja) | 0.988s+11.644s | ### 单任务编译测试 | 构建系统 | Termux (-j1) | 构建系统 | MacOS (-j1) | |----- | ---- | --- | --- | |xmake | 1m57.707s | xmake | 39.937s | |ninja | 1m52.845s | ninja | 38.995s | |cmake(gen+make) | 5.416s+2m10.539s | cmake(gen+make) | 1.203s+41.737s | |cmake(gen+ninja) | 4.458s+1m54.868s | cmake(gen+ninja) | 0.988s+38.022s | ## 包依赖管理 ### 架构和流程 ### 支持的包管理仓库 * 官方自建仓库 [xmake-repo](https://github.com/xmake-io/xmake-repo) (tbox >1.6.1) * 官方包管理器 [Xrepo](https://github.com/xmake-io/xrepo) * [用户自建仓库](https://xmake.io/package/remote_package?id=using-self-built-private-package-repository) * Conan (conan::openssl/1.1.1g) * Conda (conda::libpng 1.3.67) * Vcpkg (vcpkg::ffmpeg) * Homebrew/Linuxbrew (brew::pcre2/libpcre2-8) * Pacman on archlinux/msys2 (pacman::libcurl) * Apt on ubuntu/debian (apt::zlib1g-dev) * Clib (clib::clibs/bytes@0.0.4) * Dub (dub::log 0.4.3) * Portage on Gentoo/Linux (portage::libhandy) * Nimble for nimlang (nimble::zip >1.3) * Cargo for rust (cargo::base64 0.13.0) ### 包管理特性 * 官方仓库提供近 800+ 常用包,真正做到全平台一键下载集成编译 * 全平台包支持,支持交叉编译的依赖包集成 * 支持包虚拟环境管理和加载,`xrepo env shell` * Windows 云端预编译包加速 * 支持自建包仓库,私有仓库部署 * 第三方包仓库支持,提供更加丰富的包源,例如:vcpkg, conan, conda 等等 * 支持自动拉取使用云端工具链 * 支持包依赖锁定 ## 支持平台 * Windows (x86, x64, arm, arm64, arm64ec) * macOS (i386, x86_64, arm64) * Linux (i386, x86_64, arm, arm64, riscv, mips, 390x, sh4 ...) * FreeBSD (i386, x86_64) * NetBSD (i386, x86_64) * OpenBSD (i386, x86_64) * DragonflyBSD (i386, x86_64) * Solaris (i386, x86_64) * Android (x86, x86_64, armeabi, armeabi-v7a, arm64-v8a) * iOS (armv7, armv7s, arm64, i386, x86_64) * WatchOS (armv7k, i386) * AppleTVOS (armv7, arm64, i386, x86_64) * AppleXROS (arm64, x86_64) * MSYS (i386, x86_64) * MinGW (i386, x86_64, arm, arm64) * Cygwin (i386, x86_64) * Wasm (wasm32, wasm64) * Haiku (i386, x86_64) * Harmony (x86_64, armeabi-v7a, arm64-v8a) * Cross (cross-toolchains ..) ## 支持工具链 ```bash $ xmake show -l toolchains xcode Xcode IDE msvc Microsoft Visual C/C++ Compiler clang-cl LLVM Clang C/C++ Compiler compatible with msvc yasm The Yasm Modular Assembler clang A C language family frontend for LLVM go Go Programming Language Compiler dlang D Programming Language Compiler (Auto) dmd D Programming Language Compiler ldc The LLVM-based D Compiler gdc The GNU D Compiler (GDC) gfortran GNU Fortran Programming Language Compiler flang LLVM Fortran Compiler zig Zig Programming Language Compiler zigcc Use zig cc/c++ as C/C++ Compiler sdcc Small Device C Compiler cuda CUDA Toolkit (nvcc, nvc, nvc++, nvfortran) ndk Android NDK rust Rust Programming Language Compiler swift Swift Programming Language Compiler llvm A collection of modular and reusable compiler and toolchain technologies cross Common cross compilation toolchain nasm NASM Assembler gcc GNU Compiler Collection mingw Minimalist GNU for Windows gnu-rm GNU Arm Embedded Toolchain envs Environment variables toolchain fasm Flat Assembler tinycc Tiny C Compiler emcc A toolchain for compiling to asm.js and WebAssembly icc Intel C/C++ Compiler ifort Intel Fortran Compiler ifx Intel LLVM Fortran Compiler muslcc The musl-based cross-compilation toolchain fpc Free Pascal Programming Language Compiler wasi WASI-enabled WebAssembly C/C++ toolchain nim Nim Programming Language Compiler dotnet .NET SDK Toolchain circle A new C++20 compiler armcc ARM Compiler Version 5 of Keil MDK armclang ARM Compiler Version 6 of Keil MDK c51 Keil development tools for the 8051 Microcontroller Architecture icx Intel LLVM C/C++ Compiler dpcpp Intel LLVM C++ Compiler for data parallel programming model based on Khronos SYCL masm32 The MASM32 SDK iverilog Icarus Verilog verilator Verilator open-source SystemVerilog simulator and lint system cosmocc build-once run-anywhere hdk Harmony SDK ti-c2000 TI-CGT C2000 compiler ti-c6000 TI-CGT C6000 compiler iararm IAR ARM C/C++ Compiler kotlin-native Kotlin Native Programming Language Compiler ``` ## 支持语言 * C/C++ * Objc/Objc++ * Swift * Assembly * Golang * Rust * Dlang * Fortran * Cuda * Zig * Vala * Pascal * Nim * Verilog * FASM * NASM * YASM * MASM32 * Cppfront * Kotlin * C# ## 支持特性 * 语法简单易上手 * 快速安装,无任何依赖 * 全平台一键编译 * 支持交叉编译,智能分析交叉工具链信息 * 极速,多任务并行编译支持 * C++20 Module 支持 * 支持跨平台的 C/C++ 依赖包快速集成,内置包管理器 * 多语言混合编译支持 * 丰富的插件支持,提供各种工程生成器,例如:vs/makefile/cmakelists/compile_commands 生成插件 * REPL 交互式执行支持 * 增量编译支持,头文件依赖自动分析 * 工具链的快速切换、定制化支持 * 丰富的扩展模块支持 * 远程编译支持 * 分布式编译支持 * 内置的本地和远程编译缓存支持 ## 工程类型 * 静态库程序 * 动态库类型 * 控制台程序 * Cuda 程序 * Qt 应用程序 * WDK Windows 驱动程序 * WinSDK 应用程序 * MFC 应用程序 * iOS/MacOS 应用程序(支持.metal) * Framework和Bundle程序(iOS/MacOS) * SWIG/Pybind11 模块 (Lua, python, ...) * Luarocks 模块 * Protobuf 程序 * Lex/yacc 程序 * C++20 模块 * Linux 内核驱动模块 * Keil MDK/C51 嵌入式程序 * Verilog 仿真程序 ## 分布式编译和缓存 - [x] 跨平台支持 - [x] 支持 msvc, clang, gcc 和交叉编译工具链 - [x] 支持构建 android, ios, linux, win, macOS 程序 - [x] 除了编译工具链,无任何其他依赖 - [x] 支持编译服务器负载均衡调度 - [x] 支持大文件实时压缩传输 (lz4) - [x] 几乎零配置成本,无需共享文件系统,更加方便和安全 关于分布式编译和缓存,可以见下面的文档。 - [分布式编译](https://xmake.io/zh/guide/extras/distributed-compilation.html) - [编译缓存](https://xmake.io/zh/guide/extras/build-cache.html) ## 远程编译 更多详情见:[远程编译](https://xmake.io/zh/guide/extras/remote-compilation.html) ## 更多例子 #### Debug 和 Release 模式 ```lua add_rules("mode.debug", "mode.release") target("console") set_kind("binary") add_files("src/*.c") if is_mode("debug") then add_defines("DEBUG") end ``` #### 自定义脚本 ```lua target("test") set_kind("binary") add_files("src/*.c") after_build(function (target) print("hello: %s", target:name()) os.exec("echo %s", target:targetfile()) end) ``` #### 依赖包自动集成 下载和使用在 [xmake-repo](https://github.com/xmake-io/xmake-repo) 和第三方包仓库的依赖包: ```lua add_requires("tbox >1.6.1", "libuv master", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8") add_requires("conan::openssl/1.1.1g", {alias = "openssl", optional = true, debug = true}) target("test") set_kind("binary") add_files("src/*.c") add_packages("tbox", "libuv", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8", "openssl") ``` 另外,我们也可以使用 [xrepo](https://github.com/xmake-io/xrepo) 命令来快速安装依赖包。 #### Qt QuickApp 应用程序 ```lua target("test") add_rules("qt.quickapp") add_files("src/*.cpp") add_files("src/qml.qrc") ``` #### Cuda 程序 ```lua target("test") set_kind("binary") add_files("src/*.cu") add_cugencodes("native") add_cugencodes("compute_75") ``` #### WDK/UMDF 驱动程序 ```lua target("echo") add_rules("wdk.driver", "wdk.env.umdf") add_files("driver/*.c") add_files("driver/*.inx") add_includedirs("exe") target("app") add_rules("wdk.binary", "wdk.env.umdf") add_files("exe/*.cpp") ``` 更多WDK驱动程序例子(umdf/kmdf/wdm),见:[WDK工程例子](https://xmake.io/zh/examples/cpp/wdk.html) #### iOS/MacOS 应用程序 ```lua target("test") add_rules("xcode.application") add_files("src/*.m", "src/**.storyboard", "src/*.xcassets") add_files("src/Info.plist") ``` #### Framework 和 Bundle 程序(iOS/MacOS) ```lua target("test") add_rules("xcode.framework") -- 或者 xcode.bundle add_files("src/*.m") add_files("src/Info.plist") ``` #### OpenMP 程序 ```lua add_requires("libomp", {optional = true}) target("loop") set_kind("binary") add_files("src/*.cpp") add_rules("c++.openmp") add_packages("libomp") ``` #### Zig 程序 ```lua target("test") set_kind("binary") add_files("src/main.zig") ``` ### 自动拉取远程工具链 #### 拉取指定版本的 llvm 工具链 我们使用 llvm-10 中的 clang 来编译项目。 ```lua add_requires("llvm 10.x", {alias = "llvm-10"}) target("test") set_kind("binary") add_files("src/*.c") set_toolchains("llvm@llvm-10") ``` #### 拉取交叉编译工具链 我们也可以拉取指定的交叉编译工具链来编译项目。 ```lua add_requires("muslcc") target("test") set_kind("binary") add_files("src/*.c") set_toolchains("@muslcc") ``` #### 拉取工具链并且集成对应工具链编译的依赖包 我们也可以使用指定的muslcc交叉编译工具链去编译和集成所有的依赖包。 ```lua add_requires("muslcc") add_requires("zlib", "libogg", {system = false}) set_toolchains("@muslcc") target("test") set_kind("binary") add_files("src/*.c") add_packages("zlib", "libogg") ``` ## 插件 #### 生成IDE工程文件插件(makefile, vs2002 - vs2026, ...) ```bash $ xmake project -k vsxmake -m "debug,release" # 新版vs工程生成插件(推荐) $ xmake project -k vs -m "debug,release" $ xmake project -k cmake $ xmake project -k ninja $ xmake project -k compile_commands ``` #### 加载自定义lua脚本插件 ```bash $ xmake l ./test.lua $ xmake l -c "print('hello xmake!')" $ xmake l lib.detect.find_tool gcc $ xmake l > print("hello xmake!") > {1, 2, 3} < { 1, 2, 3 } ``` 更多内置插件见相关文档:[内置插件文档](https://xmake.io/zh/guide/extensions/builtin-plugins.html) 其他扩展插件,请到插件仓库进行下载安装: [xmake-plugins](https://github.com/xmake-io/xmake-plugins). ## IDE和编辑器插件 * [xmake-vscode](https://github.com/xmake-io/xmake-vscode) * [xmake-sublime](https://github.com/xmake-io/xmake-sublime) * [xmake-idea](https://github.com/xmake-io/xmake-idea) * [xmake-zed](https://github.com/xmake-io/xmake-zed) (thanks [@jeleferai](https://github.com/jeleferai)) * [xmake.vim](https://github.com/luzhlon/xmake.vim) (third-party, thanks [@luzhlon](https://github.com/luzhlon)) * [xmake-visualstudio](https://github.com/HelloWorld886/xmake-visualstudio) (third-party, thanks [@HelloWorld886](https://github.com/HelloWorld886)) * [xmake-qtcreator](https://github.com/Arthapz/xmake-project-manager) (third-party, thanks [@Arthapz](https://github.com/Arthapz)) ### XMake Gradle插件 (JNI) 我们也可以在Gradle中使用[xmake-gradle](https://github.com/xmake-io/xmake-gradle)插件来集成编译JNI库 ``` plugins { id 'org.tboox.gradle-xmake-plugin' version '1.1.5' } android { externalNativeBuild { xmake { path "jni/xmake.lua" } } } ``` 当`gradle-xmake-plugin`插件被应用生效后,`xmakeBuild`任务会自动注入到现有的`assemble`任务中去,自动执行jni库编译和集成。 ```console $ ./gradlew app:assembleDebug > Task :nativelib:xmakeConfigureForArm64 > Task :nativelib:xmakeBuildForArm64 >> xmake build [ 50%]: ccache compiling.debug nativelib.cc [ 75%]: linking.debug libnativelib.so [100%]: build ok! >> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/arm64-v8a > Task :nativelib:xmakeConfigureForArmv7 > Task :nativelib:xmakeBuildForArmv7 >> xmake build [ 50%]: ccache compiling.debug nativelib.cc [ 75%]: linking.debug libnativelib.so [100%]: build ok! >> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/armeabi-v7a > Task :nativelib:preBuild > Task :nativelib:assemble > Task :app:assembleDebug ``` ## CI 集成 ### GitHub Action 我们可以使用 [github-action-setup-xmake](https://github.com/xmake-io/github-action-setup-xmake) 在 Github Action 上实现跨平台安装集成 Xmake。 ``` uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: latest ``` ## 谁在使用 Xmake? 请点击 [用户列表](https://xmake.io/zh/about/who_is_using_xmake) 查看完整用户使用列表。 如果您在使用 xmake,也欢迎通过 PR 将信息提交至上面的列表,让更多的用户了解有多少用户在使用 xmake,也能让用户更加安心使用 xmake。 我们也会有更多的动力去持续投入,让 xmake 项目和社区更加繁荣。 ## 联系方式 * 邮箱:[waruqi@gmail.com](mailto:waruqi@gmail.com) * 主页:[xmake.io](https://xmake.io/zh/) * 社区 - [Reddit论坛](https://www.reddit.com/r/xmake/) - [Telegram群组](https://t.me/tbooxorg) - [Discord聊天室](https://discord.gg/xmake) - QQ群:343118190, 662147501 * 源码:[Github](https://github.com/xmake-io/xmake), [Gitee](https://gitee.com/tboox/xmake) * 微信公众号:tboox-os ## 感谢 感谢所有对xmake有所[贡献](CONTRIBUTING.md)的人: * [TitanSnow](https://github.com/TitanSnow): 提供xmake [logo](https://github.com/TitanSnow/ts-xmake-logo) 和安装脚本。 * [uael](https://github.com/uael): 提供语义版本跨平台c库 [sv](https://github.com/uael/sv)。 * [OpportunityLiu](https://github.com/OpportunityLiu): 改进cuda构建, tests框架和ci。 * [xq144](https://github.com/xq114): 改进 `xrepo env shell`,并贡献大量包到 [xmake-repo](https://github.com/xmake-io/xmake-repo) 仓库。 * [star-hengxing](https://github.com/star-hengxing): 贡献大量包到 [xmake-repo](https://github.com/xmake-io/xmake-repo) 仓库。 * [SirLynix](https://github.com/SirLynix): 贡献了许多的包,并且让更多的人知道和了解 xmake。 * [Arthapz](https://github.com/Arthapz): 贡献新的 C++ Modules 实现。 ================================================ FILE: configure ================================================ #!/bin/sh # A script-only build utility like autotools # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http:##www.apache.org#licenses#LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Copyright (C) 2022-present, Xmake Open Source Community. # # @author ruki # @homepage https://github.com/xmake-io/xmake.sh # #----------------------------------------------------------------------------- # some constants # xmake_sh_projectdir=$(X= cd -- "$(dirname -- "$0")" && pwd -P) xmake_sh_builddir="build" xmake_sh_version="1.0.5" xmake_sh_verbose=false xmake_sh_diagnosis=false xmake_sh_copyright="Copyright (C) 2022-present Ruki Wang, https://xmake.io." xmake_sh_makefile="${xmake_sh_projectdir}/Makefile" xmake_sh_ninjafile="${xmake_sh_projectdir}/build.ninja" #----------------------------------------------------------------------------- # some helper functions # raise() { echo "$@" 1>&2 ; exit 1 } vprint() { if "${xmake_sh_verbose}"; then echo "$@" fi } dprint() { if "${xmake_sh_diagnosis}"; then echo "$@" fi } # show and escape string instead of `echo -e`, because sh does not support it print() { printf "${@}\n" } wprint() { if "${xmake_sh_verbose}"; then printf "warning: ${@}\n" fi } # test empty string test_z() { if test "x${1}" = "x"; then return 0 fi return 1 } # test non-empty string test_nz() { if test "x${1}" != "x"; then return 0 fi return 1 } # test string is equal test_eq() { if test "x${1}" = "x${2}"; then return 0 fi return 1 } # test string is not equal test_nq() { if test "x${1}" != "x${2}"; then return 0 fi return 1 } string_toupper() { _ret=$(echo "$1" | tr '[a-z]' '[A-Z]') } string_tolower() { _ret=$(echo "$1" | tr '[A-Z]' '[a-z]') } string_replace() { local src="${1}" local search="${2}" local replace="${3}" if test_z "${search}"; then _ret="${src}" return fi local rest="${src}" local result="" local prefix="" while :; do case "${rest}" in *"${search}"*) prefix="${rest%%"${search}"*}" result="${result}${prefix}${replace}" rest="${rest#*"${search}"}" ;; *) result="${result}${rest}" break ;; esac done _ret="${result}" } # escape value for writing into ninja files _ninja_escape() { local rest="${1}" case "${rest}" in *\$*) local result="" while :; do case "${rest}" in *\$*) result="${result}${rest%%\$*}\$\$" rest="${rest#*\$}" ;; *) result="${result}${rest}" break ;; esac done _ret="${result}" ;; *) _ret="${rest}" ;; esac } _shell_escape_single_quotes() { local value="${1}" case "${value}" in *"'"*) local escaped="" while :; do case "${value}" in *"'"*) escaped="${escaped}${value%%\'*}'\"'\"'" value="${value#*\'}" ;; *) escaped="${escaped}${value}" break ;; esac done _ret="'${escaped}'" ;; *) _ret="'${value}'" ;; esac } # we avoid use `cut` command, because it's slow string_split() { local str="${1}" local sep="${2}" local idx="${3}" local oldifs="${IFS}" IFS="${sep}" set -- ${str} if test_nz "${idx}"; then case "${idx}" in 1) _ret="$1";; 2) _ret="$2";; 3) _ret="$3";; 4) _ret="$4";; 5) _ret="$5";; 6) _ret="$6";; esac else _ret="$1" _ret2="$2" _ret3="$3" _ret4="$4" _ret5="$5" _ret6="$6" fi IFS="${oldifs}" } # does contain sub-string? # e.g. # str="src/*.cpp" # string_contains "$str" "src" string_contains() { case "${1}" in *${2}*) return 0;; *) return 1;; esac return 1 } # does contain "*"? string_contains_star() { case "${1}" in *\**) return 0;; # bash *'*'*) return 0;; # csh *) return 1;; esac return 1 } # does contain "**"? string_contains_star2() { case "${1}" in *\*\**) return 0;; # bash *'**'*) return 0;; # csh *) return 1;; esac return 1 } # does startswith sub-string? # e.g. # str="src/*.cpp" # string_startswith "$str" "src" string_startswith() { case "${1}" in ${2}*) return 0;; *) return 1;; esac return 1 } # duplicate characters # e.g. string_dupch 10 "." => ........... string_dupch() { local count=${1} local ch=${2} local result="" while [ "${count:-0}" -gt 0 ]; do result="${result}${ch}" count=$((count - 1)) done printf '%s' "${result}" } # replace file content _io_replace_file() { local infile="${1}" local outfile="${2}" local patterns="${3}" sed "/./ {${patterns}}" "${infile}" > "${outfile}" } # try remove file or directory _os_tryrm() { if test -f "${1}"; then rm "${1}" elif test -d "${1}"; then rm -r "${1}" fi } # get temporary file # https://github.com/xmake-io/xmake/issues/5464 _os_tmpfile() { _ret=$(mktemp "${TMPDIR-/tmp}/tmp.XXXXXXXX") } # try run program _os_runv() { if ${xmake_sh_diagnosis}; then ${@} else ${@} >/dev/null 2>&1 fi local ok=$? if test "${ok}" -ne "0"; then return 1 fi return 0 } # try run program and get output _os_iorunv() { _os_tmpfile local tmpfile="${_ret}" ${@} >"${tmpfile}" 2>&1 local ok=$? if test "${ok}" -ne "0"; then _ret="" else local result=$(cat "${tmpfile}") _ret="${result}" fi _os_tryrm "${tmpfile}" } # find file in the given directory # e.g. _os_find . xmake.sh [depth] _os_find() { local dir="${1}" local name="${2}" local depth="${3}" if test_nz "${depth}"; then # Solaris doesn't support -maxdepth, use shell to filter depth if is_host "solaris"; then _ret="" local file="" for file in $(find "${dir}" -type f -name "${name}" | LC_ALL=C sort); do local relpath="${file#${dir}/}" local slash_count=$(echo "${relpath}" | tr -cd '/' | wc -c | tr -d ' ') if test "${slash_count}" = "$((${depth} - 1))"; then if test -z "${_ret}"; then _ret="${file}" else _ret="${_ret} ${file}" fi fi done else _ret=$(find "${dir}" -maxdepth "${depth}" -mindepth "${depth}" -type f -name "${name}" | LC_ALL=C sort) fi else _ret=$(find "${dir}" -type f -name "${name}" | LC_ALL=C sort) fi } # get date, "%Y%m%d%H%M" -> 202212072222 # Use deterministic timestamp from SOURCE_DATE_EPOCH if available # https://reproducible-builds.org/docs/source-date-epoch/ _os_date() { if test_z "${SOURCE_DATE_EPOCH}"; then _ret=$(date +"${1}") else # Use GNU date options first, then fallback to BSD's, and finally fallback to current time. _ret=$(date -u -d "@$SOURCE_DATE_EPOCH" +"${1}" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" +"${1}" 2>/dev/null || date +"${1}") fi } # we avoid use `basename`, because it's slow path_filename() { local path="${1}" if test_eq "${path}" "/"; then _ret="/" else _ret="${path##*/}" fi } path_extension() { path_filename "${1}"; local filename="${_ret}" _ret=".${filename##*.}" } path_basename() { path_filename "${1}"; local filename="${_ret}" _ret="${filename%.*}" } # we avoid use `dirname -- ${1}`, because it's too slow path_directory() { local path="${1}" if test_z "${path}"; then raise "invalid empty path in path_directory()." fi path="${path%/}" local dir="${path%/*}" if string_startswith "${path}" "/"; then if test_z "${dir}"; then dir="/" fi else dir="${dir#/}" if test_z "${dir}"; then dir="." fi fi _ret="${dir}" } # e.g. path_filename_fromdir "/tmp/file" "/tmp" -> "file" path_filename_fromdir() { _ret="${1#${2}/}" } path_is_absolute() { if string_startswith "${1}" "/"; then return 0 fi return 1 } # get relative path, e.g $(path_relative ${rootdir} ${absolute_path}` path_relative() { local source="${1}" local target="${2}" if test_z "${source}" || test_z "${target}"; then raise "invalid empty path in path_relative()" fi # patch missing "./" source=${source#./} source=${source#.} target=${target#./} target=${target#.} if test_z "${source}"; then _ret="${target}" return fi # find common path local result="" local common_part=$source while test_eq "${target#$common_part}" "${target}"; do # no match, means that candidate common part is not correct # go up one level (reduce common part) path_directory "${common_part}"; common_part="${_ret}" # and record that we went back, with correct / handling if test_z "${result}"; then result=".." else result="../${result}" fi done if test_eq "${common_part}" "/"; then # special case for root (no common path) result="${result}/" fi # since we now have identified the common part, # compute the non-common part local forward_part="${target#$common_part}" # and now stick all parts together if test_nz "${result}" && test_nz "${forward_part}"; then result="${result}${forward_part}" elif test_nz "${forward_part}"; then result="${forward_part#*/}" fi # same directory? if test_z "${result}" && test_eq "${source}" "${target}"; then result="." fi _ret="${result}" } path_sourcekind() { local sourcekind="" case "${1}" in *.cpp) sourcekind="cxx";; *.cc) sourcekind="cxx";; *.c) sourcekind="cc";; *.ixx) sourcekind="cxx";; *.mm) sourcekind="mxx";; *.m) sourcekind="mm";; *.S) sourcekind="as";; *.s) sourcekind="as";; *.asm) sourcekind="as";; *) raise "unknown sourcekind for ${1}" ;; esac _ret="${sourcekind}" } path_toolname() { local toolname="" case "${1}" in *-gcc) toolname="gcc";; */gcc) toolname="gcc";; gcc) toolname="gcc";; gcc-*) toolname="gcc";; */gcc-*) toolname="gcc";; *-g++) toolname="gxx";; */g++) toolname="gxx";; g++) toolname="gxx";; g++-*) toolname="gxx";; */g++-*) toolname="gxx";; xcrun*clang++) toolname="clangxx";; xcrun*clang) toolname="clang";; *-clang++) toolname="clangxx";; */clang++) toolname="clangxx";; clang++) toolname="clangxx";; clang++-*) toolname="clangxx";; */clang++-*) toolname="clangxx";; *-clang) toolname="clang";; */clang) toolname="clang";; clang) toolname="clang";; clang-*) toolname="clang";; */clang-*) toolname="clang";; */emcc) toolname="emcc";; emcc) toolname="emcc";; */em++) toolname="emxx";; em++) toolname="emxx";; */cosmocc) toolname="cosmocc";; cosmocc) toolname="cosmocc";; */cosmoc++) toolname="cosmocxx";; cosmoc++) toolname="cosmocxx";; *-ar) toolname="ar";; */ar) toolname="ar";; ar) toolname="ar";; */emar) toolname="emar";; emar) toolname="emar";; */cosmoar) toolname="cosmoar";; cosmoar) toolname="cosmoar";; cc) toolname="gcc";; */cc) toolname="gcc";; c++) toolname="gxx";; */c++) toolname="gxx";; tcc) toolname="tcc";; */tcc) toolname="tcc";; *) raise "unknown tool ${1}";; esac _ret="${toolname}" } # get flag name from toolkind, e.g. cc => cflags, cxx => cxxflags _get_flagname() { local toolkind="${1}" local flagname="" case "${toolkind}" in cc) flagname="cflags";; cxx) flagname="cxxflags";; as) flagname="asflags";; mm) flagname="mflags";; mxx) flagname="mxxflags";; ar) flagname="arflags";; sh) flagname="shflags";; ld) flagname="ldflags";; *) raise "unknown toolkind(${toolkind})!" ;; esac _ret="${flagname}" } # is enabled? true, yes, y _is_enabled() { local value=${1} if test_eq "${value}" "true"; then return 0 elif test_eq "${value}" "yes"; then return 0 elif test_eq "${value}" "y"; then return 0 fi return 1 } # deduplicate string list # .e.g "hello world hello how are you world" -> hello world how are you _dedup() { _ret=$(echo "${1}" | awk '{for (i = 1; i <= NF; ++i) if (!seen[$i]++) printf $i " "}') } # deduplicate string list from the reverse order # .e.g "hello world hello how are you world" -> hello how are you world _dedup_reverse() { local result="" local list="" local item="" list=$(echo "${1}" | awk '{for (i = NF; i > 0; --i) if (!seen[$i]++) printf $i " "}') for item in ${list}; do result="${item} ${result}" done _ret="${result}" } #----------------------------------------------------------------------------- # map functions # # define map, @note we can not use bash/declare to define map, because sh does not support it. # # _map "options" # _map_set "options" "key1" "value1" # _map_set "options" "key2" "value2" # _map_set "options" "key2" "value3" # _map_set "options" "key3" "value3" # _map_set "options" "key4" "__empty__" # _map_set "options" "key4" "__empty__" # _map_count "options"; _count="${_ret}" # _map_keys "options"; _keys="${_ret}" # echo ${_count} # for key in ${_keys}; do # _map_get "options" ${key}; value="{_ret}" # echo ${key} "->" ${value} # done # # echo "------" # _map_remove "options" "key3" # _map_count "options"; _count="${_ret}" # _map_keys "options"; _keys="${_ret}" # echo ${_count} # for key in ${_keys}; do # _map_get "options" ${key}; value="{_ret}" # echo ${key} "->" ${value} # done # _map() { local name=${1} # eval _map_${name}_count=0 # eval _map_${name}_keys="" } # because the shell is slow, we have to temporarily # disable some of the map features for performance. # #_map_count() { # local name=${1} # local count=$(eval echo \$_map_${name}_count) # _ret="${count}" #} _map_get() { local name="${1}" local key="${2}" _ret=$(eval echo \$_map_${name}_value_${key}) if test_eq "${_ret}" "__empty__"; then _ret="" fi } _map_has() { local name="${1}" local key="${2}" local value="" value=$(eval echo \$_map_${name}_value_${key}) if test_nz "${value}"; then return 0 fi return 1 } _map_set() { local name="${1}" local key="${2}" local value="${3}" # if ! _map_has ${name} ${key}; then # _map_count "options"; local count="${_ret}" # eval _map_${name}_count=$((${count} + 1)) # local keys=$(eval echo \$_map_${name}_keys) # keys="${keys} ${key}" # eval _map_${name}_keys=\${keys} # fi eval _map_${name}_value_${key}=\${value} } #_map_remove() { # local name="${1}" # local key="${2}" # if _map_has ${name} ${key}; then # _map_count "options"; local count="${_ret}" # eval _map_${name}_count=$((${count} - 1)) # eval _map_${name}_value_${key}="" # local keys=$(eval echo \$_map_${name}_keys) # local keys_new="" # local k="" # for k in ${keys}; do # if test_nq "${k}" "${key}"; then # keys_new="${keys_new} ${k}" # fi # done # eval _map_${name}_keys=\${keys_new} # fi #} #_map_keys() { # local name="${1}" # local keys=$(eval echo \$_map_${name}_keys) # _ret="${keys}" #} #----------------------------------------------------------------------------- # detect default environments # # detect hosts os_host=`uname` string_tolower ${os_host}; os_host="${_ret}" case "${os_host}" in *cygwin*) os_host="cygwin" ;; *mingw*|*msys*) os_host="msys" ;; *darwin*) os_host="macosx" ;; *linux*) os_host="linux" ;; *freebsd*) os_host="freebsd" ;; *netbsd*) os_host="netbsd" ;; *openbsd*) os_host="openbsd" ;; *dragonfly*) os_host="dragonflybsd" ;; *bsd*) os_host="bsd" ;; *sunos*) os_host="solaris" ;; *haiku*) os_host="haiku" ;; esac # determining host # e.g. # if is_host "linux" "macosx"; then # ... # fi is_host() { local host="" for host in $@; do if test_eq "${os_host}" "${host}"; then return 0 fi done return 1 } # detect host architecture os_arch=`uname -m | tr '[A-Z]' '[a-z]'` if test_eq "${os_arch}" "i686" || test_eq "${os_arch}" "i86pc"; then os_arch="i386" elif test_eq "${os_arch}" "amd64"; then os_arch="x86_64" elif test_eq "${os_arch}" "aarch64" || test_eq "${os_arch}" "arm64"; then os_arch="arm64" elif string_contains "${os_arch}" "armv7"; then os_arch="armv7" elif string_contains "${os_arch}" "arm"; then os_arch="arm" elif string_contains "${os_arch}" "power macintosh"; then os_arch="ppc" fi # set the default target platform _target_plat_default=${os_host} if is_host "msys"; then _target_plat_default="mingw" elif is_host "freebsd" "openbsd" "dragonflybsd" "netbsd"; then _target_plat_default="bsd" elif test_nz "${EMSDK}"; then _target_plat_default="wasm" fi # set the default target architecture _target_arch_default=${os_arch} if is_host "msys" && test_nz "${MSYSTEM_CARCH}"; then _target_arch_default="${MSYSTEM_CARCH}" elif test_nz "${TERMUX_ARCH}"; then _target_arch_default="${TERMUX_ARCH}" elif test_nz "${EMSDK}"; then _target_arch_default="wasm32" fi if test_eq "${_target_arch_default}" "i686"; then _target_arch_default="i386" elif test_eq "${_target_arch_default}" "aarch64" || test_eq "${_target_arch_default}" "arm64"; then _target_arch_default="arm64" elif string_contains "${_target_arch_default}" "armv7"; then _target_arch_default="armv7" elif string_contains "${_target_arch_default}" "arm"; then _target_arch_default="arm" fi # set the default target mode _target_mode_default="release" # set the default target kind _target_kind_default="static" # set the default project generator and build program if is_host "freebsd" "netbsd" "openbsd" "dragonflybsd" "bsd" "solaris"; then project_generator="gmake" _make_program_default="gmake" _ninja_program_default="ninja" elif is_host "msys" "cygwin"; then project_generator="gmake" _make_program_default="make.exe" _ninja_program_default="ninja.exe" else project_generator="gmake" _make_program_default="make" _ninja_program_default="ninja" fi # set the default directories if test -d "/usr/local"; then _install_prefix_default="/usr/local" elif test -d "/usr"; then _install_prefix_default="/usr" fi _install_bindir_default="\${prefix}/bin" _install_libdir_default="\${prefix}/lib" _install_includedir_default="\${prefix}/include" # determining target platform # e.g. # if is_plat "linux" "macosx"; then # ... # fi is_plat() { local plat="" for plat in $@; do if test_eq "${_target_plat}" "${plat}"; then return 0 fi done return 1 } # determining target architecture # e.g. # if is_arch "x86_64" "i386"; then # ... # fi is_arch() { local arch="" for arch in $@; do if test_eq "${_target_arch}" "${arch}"; then return 0 fi done return 1 } # determining target mode # e.g. # if is_mode "release"; then # ... # fi is_mode() { local mode="" for mode in $@; do if test_eq "${_target_mode}" "${mode}"; then return 0 fi done return 1 } # determining target kind # e.g. # if is_kind "release"; then # ... # fi is_kind() { local kind="" for kind in $@; do if test_eq "${_target_kind}" "${kind}"; then return 0 fi done return 1 } # determining target toolchain # e.g. # if is_toolchain "clang"; then # ... # fi is_toolchain() { local toolchain="" for toolchain in $@; do if test_eq "${_target_toolchain}" "${toolchain}"; then return 0 fi done return 1 } #----------------------------------------------------------------------------- # project configuration apis # # set project name set_project() { _xmake_sh_project_name="${1}" } # include the given xmake.sh file or directory # e.g. includes "src" "tests" includes() { local path="" for path in $@; do if test -f "${path}"; then path_directory "${path}"; xmake_sh_scriptdir="${_ret}" . "${path}" else local xmake_sh_scriptdir_cur=${xmake_sh_scriptdir} if test "x${xmake_sh_scriptdir}" != "x"; then xmake_sh_scriptdir="${xmake_sh_scriptdir_cur}/${path}" . "${xmake_sh_scriptdir}/xmake.sh" else . "${xmake_sh_projectdir}/${path}/xmake.sh" fi xmake_sh_scriptdir=${xmake_sh_scriptdir_cur} fi done } #----------------------------------------------------------------------------- # some helper functions # # split flags _split_flags() { string_replace "${1}" ":" " " } # get abstract flag for gcc/clang _get_abstract_flag_for_gcc_clang() { local toolkind="${1}" local toolname="${2}" local itemname="${3}" local value="${4}" local flag="" case "${itemname}" in defines) string_replace "${value}" '"' '\"'; value="${_ret}" flag="-D${value}" ;; undefines) flag="-U${value}";; includedirs) flag="-I${value}";; linkdirs) flag="-L${value}";; links) flag="-l${value}";; syslinks) flag="-l${value}";; frameworks) flag="-framework ${value}";; frameworkdirs) flag="-F${value}";; rpathdirs) if is_plat "macosx"; then string_replace "${value}" "\$ORIGIN" "@loader_path"; value="${_ret}" flag="-Xlinker -rpath -Xlinker ${value}" else # escape $ORIGIN in makefile, TODO we need also handle it for ninja string_replace "${value}" "@loader_path" '$$ORIGIN'; value="${_ret}" if is_plat "bsd"; then flag="-Wl,-zorigin -Wl,-rpath='${value}'" else flag="-Wl,-rpath='${value}'" fi fi ;; symbols) if test_eq "${value}" "debug"; then flag="-g" elif test_eq "${value}" "hidden"; then flag="-fvisibility=hidden" fi ;; strip) if test_eq "${value}" "debug"; then flag="-Wl,-S" elif test_eq "${value}" "all"; then if is_plat "macosx"; then flag="-Wl,-x -Wl,-dead_strip" else flag="-s" fi fi ;; warnings) if test_eq "${value}" "all" || test_eq "${value}" "more" || test_eq "${value}" "less"; then flag="-Wall" elif test_eq "${value}" "allextra"; then flag="-Wall -Wextra" elif test_eq "${value}" "error"; then flag="-Werror" elif test_eq "${value}" "everything"; then flag="-Wall -Wextra" elif test_eq "${value}" "none"; then flag="-w" fi ;; optimizes) if test_eq "${value}" "fast"; then flag="-O1" elif test_eq "${value}" "faster"; then flag="-O2" elif test_eq "${value}" "fastest"; then flag="-O3" elif test_eq "${value}" "smallest"; then if test_eq "${toolname}" "clang" || test_eq "${toolname}" "clangxx"; then flag="-Oz" else flag="-Os" fi elif test_eq "${value}" "aggressive"; then flag="-Ofast" elif test_eq "${value}" "none"; then flag="-O0" fi ;; languages) if test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "mm"; then case "${value}" in ansi) flag="-ansi";; c89) flag="-std=c89";; gnu89) flag="-std=gnu89";; c99) flag="-std=c99";; gnu99) flag="-std=gnu99";; c11) flag="-std=c11";; gnu11) flag="-std=gnu11";; c17) flag="-std=c17";; gnu17) flag="-std=gnu17";; esac elif test_eq "${toolkind}" "cxx" || test_eq "${toolkind}" "mxx"; then case "${value}" in cxx98) flag="-std=c++98";; c++98) flag="-std=c++98";; gnuxx98) flag="-std=gnu++98";; gnu++98) flag="-std=gnu++98";; cxx11) flag="-std=c++11";; c++11) flag="-std=c++11";; gnuxx11) flag="-std=gnu++11";; gnu++11) flag="-std=gnu++11";; cxx14) flag="-std=c++14";; c++14) flag="-std=c++14";; gnuxx14) flag="-std=gnu++14";; gnu++14) flag="-std=gnu++14";; cxx17) flag="-std=c++17";; c++17) flag="-std=c++17";; gnuxx17) flag="-std=gnu++17";; gnu++17) flag="-std=gnu++17";; cxx1z) flag="-std=c++1z";; c++1z) flag="-std=c++1z";; gnuxx1z) flag="-std=gnu++1z";; gnu++1z) flag="-std=gnu++1z";; cxx2a) flag="-std=c++2a";; c++2a) flag="-std=c++2a";; gnuxx2a) flag="-std=gnu++2a";; gnu++2a) flag="-std=gnu++2a";; cxx20) flag="-std=c++20";; c++20) flag="-std=c++20";; gnuxx20) flag="-std=gnu++20";; gnu++20) flag="-std=gnu++20";; cxx*) raise "unknown language value(${value})!" ;; c++*) raise "unknown language value(${value})!" ;; esac fi ;; *) raise "unknown itemname(${itemname})!" ;; esac _ret="${flag}" } # get abstract flags _get_abstract_flags() { local toolkind="${1}" local toolname="${2}" local itemname="${3}" local values="${4}" local flags="" local value="" for value in ${values}; do local flag="" case "${toolname}" in gcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; gxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; clang) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; clangxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; emcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; emxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; cosmocc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; cosmocxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; tcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; *) raise "unknown toolname(${toolname})!" ;; esac if test_nz "${flag}"; then flags="${flags} ${flag}" fi done _ret="${flags}" } #----------------------------------------------------------------------------- # option configuration apis # # define option option() { local name="${1}" local description="${2}" local default=${3} _xmake_sh_option_current="${name}" if ! ${_loading_options}; then if test_nz "${description}"; then _xmake_sh_option_current="" fi return fi if ! _map_has "options" "${name}_name"; then _xmake_sh_options="${_xmake_sh_options} ${name}" fi _map_set "options" "${name}_name" "${name}" _map_set "options" "${name}_description" "${description}" _map_set "options" "${name}_default" "${default}" # we end option if it's just one line if test_nz "${description}"; then _xmake_sh_option_current="" fi return 0 } option_end() { _xmake_sh_option_current="" } _map "options" # has the given option? _has_option() { local name=${1} if _map_has "options" "${name}_name"; then return 0 fi return 1 } # get the given option item _get_option_item() { local name=${1} local key=${2} _map_get "options" "${name}_${key}" } # set the given option item _set_option_item() { local name=${1} local key=${2} shift shift if test_nz "${name}"; then _map_set "options" "${name}_${key}" "${@}" else raise "please call set_${key}(${@}) in the option scope!" fi } # add values to the given option item _add_option_item() { local name=${1} local key=${2} shift shift if test_nz "${name}"; then _map_get "options" "${name}_${key}"; local values="${_ret}" values="${values} ${@}" _map_set "options" "${name}_${key}" "${values}" else raise "please call add_${key}(${@}) in the option scope!" fi } # get the give option value _get_option_value() { local name=${1} _get_option_item "${name}" "value" if test "x${_ret}" = "x"; then _get_option_item "${name}" "default" fi } # set the give option value _set_option_value() { local name=${1} local value=${2} _set_option_item "${name}" "value" "${value}" } # this option need checking? _option_need_checking() { local name="${1}" _get_option_item "${name}" "default"; local default="${_ret}" if test_nz "${default}"; then return 1 fi _get_option_item "${name}" "cfuncs"; local cfuncs="${_ret}" _get_option_item "${name}" "cxxfuncs"; local cxxfuncs="${_ret}" _get_option_item "${name}" "cincludes"; local cincludes="${_ret}" _get_option_item "${name}" "cxxincludes"; local cxxincludes="${_ret}" _get_option_item "${name}" "ctypes"; local ctypes="${_ret}" _get_option_item "${name}" "cxxtypes"; local cxxtypes="${_ret}" _get_option_item "${name}" "csnippets"; local csnippets="${_ret}" _get_option_item "${name}" "cxxsnippets"; local cxxsnippets="${_ret}" _get_option_item "${name}" "links"; local links="${_ret}" _get_option_item "${name}" "syslinks"; local syslinks="${_ret}" if test_nz "${cfuncs}" || test_nz "${cxxfuncs}" || test_nz "${cincludes}" || test_nz "${cxxincludes}" || test_nz "${ctypes}" || test_nz "${cxxtypes}" || test_nz "${csnippets}" || test_nz "${cxxsnippets}" || test_nz "${links}" || test_nz "${syslinks}"; then return 0 fi return 1 } # get options for the help menu _get_options_for_menu() { local options="" local name="" for name in ${_xmake_sh_options}; do _get_option_item "${name}" "showmenu"; local showmenu="${_ret}" if _is_enabled "${showmenu}"; then options="${options} ${name}" elif test_z "${showmenu}" && ! _option_need_checking "${name}"; then options="${options} ${name}" fi done _ret="${options}" } # get options for checking _get_options_for_checking() { local options="" local name="" for name in ${_xmake_sh_options}; do _get_option_item "${name}" "showmenu"; local showmenu="${_ret}" if test_z "${showmenu}" && _option_need_checking "${name}"; then options="${options} ${name}" fi done _ret="${options}" } # get abstract flags in option _get_option_abstract_flags() { local name="${1}" local toolkind="${2}" local toolname="${3}" local itemname="${4}" local values="${5}" if test_z "${values}"; then _get_option_item "${name}" "${itemname}"; values="${_ret}" fi _get_abstract_flags "${toolkind}" "${toolname}" "${itemname}" "${values}" } # is config for option is_config() { if ! ${_loading_targets}; then return 1 fi local name=${1} local value=${2} _get_option_value "${name}"; local value_cur="${_ret}" if test_eq "${value_cur}" "${value}"; then return 0 fi return 1 } # has config for option has_config() { if ! ${_loading_targets}; then return 1 fi local name=${1} _get_option_value "${name}"; local value_cur="${_ret}" if _is_enabled ${value_cur}; then return 0 fi return 1 } # set config for option, we can use it to modify option status when loading targets set_config() { local name=${1} local value=${2} _set_option_value "${name}" "${value}" } # set showmenu in option set_showmenu() { if ! ${_loading_options}; then return fi local show="${1}" _set_option_item "${_xmake_sh_option_current}" "showmenu" "${show}" } # set description in option set_description() { if ! ${_loading_options}; then return fi local description="${1}" _set_option_item "${_xmake_sh_option_current}" "description" "${description}" } # add cfuncs in option add_cfuncs() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cfuncs" "${@}" } # add cxxfuncs in option add_cxxfuncs() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cxxfuncs" "${@}" } # add cincludes in option add_cincludes() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cincludes" "${@}" } # add cxxincludes in option add_cxxincludes() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cxxincludes" "${@}" } # add ctypes in option add_ctypes() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "ctypes" "${@}" } # add cxxtypes in option add_cxxtypes() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cxxtypes" "${@}" } # add csnippets in option add_csnippets() { if ! ${_loading_options}; then return fi local csnippets="${1}" _add_option_item "${_xmake_sh_option_current}" "csnippets" "${csnippets}" } # add cxxsnippets in option add_cxxsnippets() { if ! ${_loading_options}; then return fi local cxxsnippets="${1}" _add_option_item "${_xmake_sh_option_current}" "cxxsnippets" "${cxxsnippets}" } # before_check in option before_check() { if ! ${_loading_options}; then return fi local funcname="${1}" _add_option_item "${_xmake_sh_option_current}" "before_check" "${funcname}" } #----------------------------------------------------------------------------- # target configuration apis # # define target target() { local name="${1}" _xmake_sh_target_current="${name}" if ! ${_loading_targets}; then return fi if ! _map_has "targets" "${name}_name"; then _xmake_sh_targets="${_xmake_sh_targets} ${name}" fi _map_set "targets" "${name}_name" "${name}" return 0 } target_end() { _xmake_sh_target_current="" } _map "targets" # has the given target? _has_target() { local name=${1} if _map_has "targets" "${name}_name"; then return 0 fi return 1 } # has the given target item _has_target_item() { local name=${1} local key=${2} if _map_has "targets" "${name}_${key}"; then return 0 elif _map_has "targets" "__root_${key}"; then return 0 fi return 1 } # get the given target item _get_target_item() { local name=${1} local key=${2} _map_get "targets" "${name}_${key}" local values="${_ret}" if _map_has "targets" "__root_${key}"; then _map_get "targets" "__root_${key}"; local root_values="${_ret}" if test_nz "${values}"; then values="${root_values} ${values}" else values="${root_values}" fi fi _ret="${values}" } # set the given target item _set_target_item() { local name=${1} local key=${2} shift shift if test_nz "${name}"; then _map_set "targets" "${name}_${key}" "${@}" else _map_set "targets" "__root_${key}" "${@}" fi } # add values to the given target item _add_target_item() { local name=${1} local key=${2} shift shift if test_nz "${name}"; then _map_get "targets" "${name}_${key}"; local values="${_ret}" values="${values} ${@}" _map_set "targets" "${name}_${key}" "${values}" else _map_get "targets" "__root_${key}"; local values="${_ret}" values="${values} ${@}" _map_set "targets" "__root_${key}" "${values}" fi } # is default? _is_target_default() { local name="${1}" if _has_target_item "${name}" "default"; then _get_target_item "${target}" "default"; local default="${_ret}" if _is_enabled ${default}; then return 0 fi return 1 fi return 0 } # get target basename _get_target_basename() { local name="${1}" _get_target_item "${name}" "basename"; local basename="${_ret}" if test_z "${basename}"; then basename="${name}" fi _ret="${basename}" } # get target extension _get_target_extension() { local name="${1}" local extension="" if _has_target_item "${name}" "extension"; then _get_target_item "${name}" "extension"; extension="${_ret}" elif is_plat "mingw"; then _get_target_item "${name}" "kind"; local kind="${_ret}" if test "x${kind}" = "xbinary"; then extension=".exe" elif test "x${kind}" = "xstatic"; then extension=".a" elif test "x${kind}" = "xshared"; then extension=".dll" fi else _get_target_item "${name}" "kind"; local kind="${_ret}" if test "x${kind}" = "xstatic"; then extension=".a" elif test "x${kind}" = "xshared"; then if is_plat "macosx"; then extension=".dylib" else extension=".so" fi fi fi _ret="${extension}" } # get target prefixname _get_target_prefixname() { local name="${1}" local prefixname="" if _has_target_item "${name}" "prefixname"; then _get_target_item "${name}" "prefixname"; prefixname="${_ret}" elif is_plat "mingw"; then _get_target_item "${name}" "kind"; local kind="${_ret}" if test "x${kind}" = "xstatic"; then prefixname="lib" elif test "x${kind}" = "xshared"; then prefixname="lib" fi else _get_target_item "${name}" "kind"; local kind="${_ret}" if test "x${kind}" = "xstatic"; then prefixname="lib" elif test "x${kind}" = "xshared"; then prefixname="lib" fi fi _ret="${prefixname}" } # get target filename _get_target_filename() { local name="${1}" _get_target_item "${name}" "filename"; local filename="${_ret}" if test_z "${filename}"; then _get_target_basename "${name}"; local basename="${_ret}" _get_target_extension "${name}"; local extension="${_ret}" _get_target_prefixname "${name}"; local prefixname="${_ret}" filename="${prefixname}${basename}${extension}" fi _ret="${filename}" } # get target soname # @see https://github.com/tboox/tbox/issues/214 # # set_version "1.0.1" "" "1" -> libfoo.so.1, libfoo.1.dylib # set_version "1.0.1" "" "A" -> libfoo.so.A, libfoo.A.dylib _get_target_soname() { local soname="" local name="${1}" _get_target_item "${name}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared" && is_plat "macosx" "linux" "bsd"; then _get_target_item "${name}" "version"; local version="${_ret}" _get_target_item "${name}" "version_soname"; local version_soname="${_ret}" if test_nz "${version}" && test_nz "${version_soname}"; then _get_target_filename "${name}"; soname="${_ret}" _get_target_extension "${name}"; local extension="${_ret}" if test_eq "${extension}" ".dylib"; then path_basename "${soname}"; local basename="${_ret}" soname="${basename}.${version_soname}${extension}" else soname="${soname}.${version_soname}" fi fi fi _ret="${soname}" } # get target directory _get_targetdir() { local name="${1}" _get_target_item "${name}" "targetdir"; local targetdir="${_ret}" if test_z "${targetdir}"; then targetdir="${xmake_sh_builddir}/${_target_plat}/${_target_arch}/${_target_mode}" fi _ret="${targetdir}" } # get target object directory _get_target_objectdir() { local name="${1}" _get_target_item "${name}" "objectdir"; local objectdir="${_ret}" if test_z "${objectdir}"; then objectdir="${xmake_sh_builddir}/.objs/${name}/${_target_plat}/${_target_arch}/${_target_mode}" fi _ret="${objectdir}" } # get target file path _get_target_file() { local name="${1}" _get_target_filename "${name}"; local filename="${_ret}" _get_targetdir "${name}"; local targetdir="${_ret}" local targetfile="${targetdir}/${filename}" _ret="${targetfile}" } # get target librarydeps _get_target_librarydeps_impl() { local name="${1}" local librarydeps="" local dep="" _get_target_item "${name}" "deps"; local deps="${_ret}" for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then librarydeps="${librarydeps} ${dep}" _get_target_librarydeps_impl "${dep}"; local dep_librarydeps="${_ret}" if test_nz "${dep_librarydeps}"; then librarydeps="${librarydeps} ${dep_librarydeps}" fi fi done _ret="${librarydeps}" } _get_target_librarydeps() { local name="${1}" _get_target_item "${name}" "librarydeps"; local librarydeps="${_ret}" if test_z "${librarydeps}" && test_nq "${librarydeps}" "__none__"; then _get_target_librarydeps_impl "${name}"; librarydeps="${_ret}" if test_nz "${librarydeps}"; then _dedup_reverse "${librarydeps}"; librarydeps="${_ret}" _set_target_item "${name}" "librarydeps" "${librarydeps}" else _set_target_item "${name}" "librarydeps" "__none__" fi fi if test_eq "${librarydeps}" "__none__"; then librarydeps="" fi _ret="${librarydeps}" } # get sourcefiles in target _get_target_sourcefiles() { local name="${1}" _get_target_item "${name}" "files" } # get objectfile in target _get_target_objectfile() { local name="${1}" local sourcefile="${2}" local extension=".o" if is_plat "mingw"; then extension=".obj" fi _get_target_objectdir "${name}"; local objectdir="${_ret}" local objectfile="${objectdir}/${sourcefile}${extension}" _ret="${objectfile}" } # get objectfiles in target _get_target_objectfiles() { local name="${1}" _get_target_sourcefiles "${name}"; local sourcefiles="${_ret}" local objectfiles="" local sourcefile="" for sourcefile in ${sourcefiles}; do _get_target_objectfile "${name}" "${sourcefile}"; local objectfile="${_ret}" objectfiles="${objectfiles} ${objectfile}" done _ret="${objectfiles}" } # get abstract flags in target _get_target_abstract_flags() { local name="${1}" local toolkind="${2}" local toolname="${3}" local itemname="${4}" local values="${5}" if test_z "${values}"; then # get values from target _get_target_item "${name}" "${itemname}"; values="${_ret}" # get values from target deps _get_target_librarydeps "${name}"; local deps="${_ret}" local dep="" for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then _get_target_item "${dep}" "${itemname}_public"; local depvalues="${_ret}" if test_nz "${depvalues}"; then values="${values} ${depvalues}" fi fi done fi if test_nz "${values}"; then _get_abstract_flags "${toolkind}" "${toolname}" "${itemname}" "${values}" else _ret="" fi } # get toolchain flags for ar in target _get_target_toolchain_flags_for_ar() { _ret="-cr" } # get toolchain flags for gcc in target _get_target_toolchain_flags_for_gcc() { local name="${1}" local toolkind="${2}" local flags="" if is_arch "i386"; then flags="${flags} -m32" fi _get_target_item "${name}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared"; then if test_eq "${toolkind}" "sh"; then flags="${flags} -shared -fPIC" elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then flags="${flags} -fPIC" fi # @see https://github.com/tboox/tbox/issues/214 if test_eq "${toolkind}" "sh"; then _get_target_soname "${name}"; local soname="${_ret}" if test_nz "${soname}"; then if is_plat "macosx"; then flags="${flags} -Wl,-install_name,${soname}" else flags="${flags} -Wl,-soname,${soname}" fi fi fi fi _ret="${flags}" } # get macOS sysroot and target flags for clang # usage: _get_macosx_sysroot_flags [quoted] # if quoted is "quoted", the sysroot path will be wrapped in escaped quotes (for eval) _get_macosx_sysroot_flags() { local flags="" if is_plat "macosx"; then _os_iorunv "xcrun" "-sdk" "macosx" "--show-sdk-path"; local sdkdir="${_ret}" if test_nz "${sdkdir}"; then if test_eq "${1}" "quoted"; then flags="${flags} -isysroot \"${sdkdir}\"" else flags="${flags} -isysroot ${sdkdir}" fi path_basename "${sdkdir}"; local basename="${_ret}" if test_nz "${basename}" && string_startswith "${basename}" "MacOSX"; then string_replace "${basename}" "MacOSX" ""; local target_minver="${_ret}" if test_nz "${target_minver}"; then flags="${flags} -target ${_target_arch}-apple-macos${target_minver}" fi fi fi fi _ret="${flags}" } # get toolchain flags for clang in target _get_target_toolchain_flags_for_clang() { local name="${1}" local toolkind="${2}" local flags="-Qunused-arguments" if is_arch "i386"; then flags="${flags} -m32" fi _get_target_item "${name}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared"; then if test_eq "${toolkind}" "sh"; then flags="${flags} -shared -fPIC" elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then flags="${flags} -fPIC" fi # @see https://github.com/tboox/tbox/issues/214 if test_eq "${toolkind}" "sh"; then _get_target_soname "${name}"; local soname="${_ret}" if test_nz "${soname}"; then if is_plat "macosx"; then flags="${flags} -Wl,-install_name,${soname}" else flags="${flags} -Wl,-soname,${soname}" fi fi fi fi # set target and sysroot _get_macosx_sysroot_flags "quoted"; flags="${flags}${_ret}" _ret="${flags}" } # get toolchain flags for tcc in target _get_target_toolchain_flags_for_tcc() { local name="${1}" local toolkind="${2}" local flags="" if is_arch "i386"; then flags="${flags} -m32" fi _get_target_item "${name}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared"; then if test_eq "${toolkind}" "sh"; then flags="${flags} -shared -fPIC" elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then flags="${flags} -fPIC" fi # @see https://github.com/tboox/tbox/issues/214 if test_eq "${toolkind}" "sh"; then _get_target_soname "${name}"; local soname="${_ret}" if test_nz "${soname}"; then if is_plat "macosx"; then flags="${flags} -Wl,-install_name,${soname}" else flags="${flags} -Wl,-soname,${soname}" fi fi fi fi # set target and sysroot _get_macosx_sysroot_flags "quoted"; flags="${flags}${_ret}" _ret="${flags}" } # get toolchain flags in target _get_target_toolchain_flags() { local name="${1}" local toolkind="${2}" local toolname="${3}" local flags="" case "${toolname}" in gcc) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";; gxx) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";; clang) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";; clangxx) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";; emcc) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";; emxx) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";; cosmocc) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";; cosmocxx) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";; tcc) _get_target_toolchain_flags_for_tcc "${name}" "${toolkind}"; flags="${_ret}";; ar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";; emar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";; cosmoar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";; *) raise "unknown toolname(${toolname})!" ;; esac _ret="${flags}" } # get compiler flags in target _get_target_compiler_flags() { local name="${1}" local toolkind="${2}" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local result="" # get toolchain flags _get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}" if test_nz "${toolchain_flags}"; then result="${result} ${toolchain_flags}" fi # get abstract flags local itemnames="symbols optimizes warnings languages defines undefines includedirs frameworkdirs frameworks" local itemname="" for itemname in ${itemnames}; do _get_target_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi done # get raw flags, e.g. add_cflags, add_cxxflags _get_flagname "${toolkind}"; local flagname="${_ret}" _get_target_item "${name}" "${flagname}"; local flags="${_ret}" # get flags from target deps _get_target_librarydeps "${name}"; local deps="${_ret}" local dep="" for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then _get_target_item "${dep}" "${flagname}_public"; local depflags="${_ret}" if test_nz "${depflags}"; then flags="${flags} ${depflags}" fi fi done if test_nz "${flags}"; then result="${result} ${flags}" fi if test_eq "${flagname}" "cflags" || test_eq "${flagname}" "cxxflags"; then _get_target_item "${name}" "cxflags"; flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi elif test_eq "${flagname}" "mflags" || test_eq "${flagname}" "mxxflags"; then _get_target_item "${name}" "mxflags"; flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi fi # get flags from environments, e.g. $CFLAGS, $CXXFLAGS if test_nz "${CPPFLAGS}"; then result="${result} ${CPPFLAGS}" fi if test_eq "${flagname}" "cflags" && test_nz "${CFLAGS}"; then result="${result} ${CFLAGS}" fi if test_eq "${flagname}" "cxxflags" && test_nz "${CXXFLAGS}"; then result="${result} ${CXXFLAGS}" fi if test_eq "${flagname}" "mflags" && test_nz "${MFLAGS}"; then result="${result} ${MFLAGS}" fi if test_eq "${flagname}" "mxxflags" && test_nz "${MXXFLAGS}"; then result="${result} ${MXXFLAGS}" fi _ret="${result}" } # get linker flags in target _get_target_linker_flags() { local name="${1}" local toolkind="${2}" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local result="" # get toolchain flags _get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}" if test_nz "${toolchain_flags}"; then result="${result} ${toolchain_flags}" fi # get flags from target deps _get_target_librarydeps "${name}"; local deps="${_ret}" local dep="" for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then _get_targetdir "${dep}"; local dep_targetdir="${_ret}" _get_target_basename "${dep}"; local dep_basename="${_ret}" _get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "linkdirs" "${dep_targetdir}"; local linkdirs_flags="${_ret}" _get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "links" "${dep_basename}"; local links_flags="${_ret}" if test_eq "${dep_kind}" "shared"; then local rpathdir="@loader_path" _get_targetdir "${name}"; local targetdir="${_ret}" path_relative "${targetdir}" "${dep_targetdir}"; local subdir="${_ret}" if test_nz "${subdir}"; then rpathdir="${rpathdir}/${subdir}" fi _get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "rpathdirs" "${rpathdir}"; local rpathdirs_flags="${_ret}" result="${result} ${rpathdirs_flags}" fi result="${result} ${linkdirs_flags} ${links_flags}" fi done # get abstract flags local itemnames="strip frameworkdirs linkdirs links rpathdirs frameworks syslinks" local itemname="" for itemname in ${itemnames}; do _get_target_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi done # get raw flags, e.g. add_ldflags, add_shflags _get_flagname "${toolkind}"; local flagname="${_ret}" _get_target_item "${name}" "${flagname}"; local flags="${_ret}" # get flags from target deps for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then _get_target_item "${dep}" "${flagname}_public"; local depflags="${_ret}" if test_nz "${depflags}"; then flags="${flags} ${depflags}" fi fi done if test_nz "${flags}"; then result="${result} ${flags}" fi # get flags from environments, e.g. $LDFLAGS if test_eq "${flagname}" "ldflags" && test_nz "${LDFLAGS}"; then result="${result} ${LDFLAGS}" fi if test_eq "${flagname}" "shflags" && test_nz "${LDFLAGS}"; then result="${result} ${LDFLAGS}" fi _ret="${result}" } # get archiver flags in target _get_target_archiver_flags() { local name="${1}" local toolkind="${2}" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local result="" # get toolchain flags _get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}" if test_nz "${toolchain_flags}"; then result="${result} ${toolchain_flags}" fi # get raw flags, e.g. add_arflags _get_flagname "${toolkind}"; local flagname="${_ret}" _get_target_item "${name}" "${flagname}"; local flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi _ret="${result}" } # get target flags _get_target_flags() { local name="${1}" local toolkind="${2}" local flags="" if test_eq "${toolkind}" "sh"; then _get_target_linker_flags "${name}" "${toolkind}"; flags="${_ret}" elif test_eq "${toolkind}" "ld"; then _get_target_linker_flags "${name}" "${toolkind}"; flags="${_ret}" elif test_eq "${toolkind}" "ar"; then _get_target_archiver_flags "${name}" "${toolkind}"; flags="${_ret}" else _get_target_compiler_flags "${name}" "${toolkind}"; flags="${_ret}" fi _ret="${flags}" } # add file paths in target _add_target_filepaths() { local key="$1" shift # we need avoid escape `*` automatically in for-loop local file="" string_replace "${@}" "\*" "?"; local list="${_ret}" if test_eq "${key}" "files"; then for file in ${list}; do path_sourcekind "${file}"; local sourcekind="${_ret}" _targets_toolkinds="${_targets_toolkinds} ${sourcekind}" done fi for file in ${list}; do string_replace "${file}" "?" "*"; file="${_ret}" if ! path_is_absolute "${file}"; then file="${xmake_sh_scriptdir}/${file}" fi local files="" if string_contains_star2 "${file}"; then path_directory "${file}"; local dir="${_ret}" path_filename_fromdir "${file}" "${dir}"; local name="${_ret}" _os_find "${dir}" "${name}"; files="${_ret}" elif string_contains_star "${file}"; then path_directory "${file}"; local dir="${_ret}" path_filename_fromdir "${file}" "${dir}"; local name="${_ret}" _os_find "${dir}" "${name}" 1; files="${_ret}" else files="${file}" fi for file in ${files}; do path_relative "${xmake_sh_projectdir}" "${file}"; file="${_ret}" _add_target_item "${_xmake_sh_target_current}" "${key}" "${file}" done done } # add install paths in target _add_target_installpaths() { local key="$1" local filepattern="${2}" local prefixdir="${3}" local filename=${4} # get root directory, e.g. "src/foo/(*.h)" -> "src/foo" local rootdir="" if string_contains "${filepattern}" "("; then string_split "${filepattern}" "(" 1; rootdir="${_ret}" rootdir=${rootdir%/} if ! path_is_absolute "${rootdir}"; then rootdir="${xmake_sh_scriptdir}/${rootdir}" fi path_relative "${xmake_sh_projectdir}" "${rootdir}"; rootdir="${_ret}" rootdir=${rootdir%/} fi # remove (), e.g. "src/(*.h)" -> "src/*.h" string_replace ${filepattern} "(" ""; filepattern="${_ret}" string_replace ${filepattern} ")" ""; filepattern="${_ret}" # get real path if ! path_is_absolute "${filepattern}"; then filepattern="${xmake_sh_scriptdir}/${filepattern}" fi local files="" if string_contains_star2 "${filepattern}"; then path_directory "${filepattern}"; local dir="${_ret}" path_filename_fromdir "${filepattern}" "${dir}"; local name="${_ret}" _os_find "${dir}" "${name}"; files="${_ret}" elif string_contains_star "${filepattern}"; then path_directory "${filepattern}"; local dir="${_ret}" path_filename_fromdir "${filepattern}" "${dir}"; local name="${_ret}" _os_find "${dir}" "${name}" 1; files="${_ret}" else files="${filepattern}" fi for file in ${files}; do path_relative "${xmake_sh_projectdir}" "${file}"; file="${_ret}" _add_target_item "${_xmake_sh_target_current}" "${key}" "${file}:${rootdir}:${prefixdir}:${filename}" done } # set target file path _set_target_filepath() { local key="${1}" local path="${2}" if ! path_is_absolute "${path}"; then path="${xmake_sh_scriptdir}/${path}" fi path_relative ${xmake_sh_projectdir} "${path}"; path="${_ret}" _set_target_item "${_xmake_sh_target_current}" "${key}" "${path}" } # set kind in target set_kind() { if ! ${_loading_targets}; then return fi local kind=${1} _set_target_item "${_xmake_sh_target_current}" "kind" "${kind}" case "${kind}" in binary) _targets_toolkinds="${_targets_toolkinds} ld";; static) _targets_toolkinds="${_targets_toolkinds} ar";; shared) _targets_toolkinds="${_targets_toolkinds} sh";; *) raise "unknown target kind ${kind}";; esac } # set version in target set_version() { if ! ${_loading_targets}; then return fi local version="${1}" local version_build="${2}" local version_soname="${3}" _set_target_item "${_xmake_sh_target_current}" "version" "${version}" _set_target_item "${_xmake_sh_target_current}" "version_build" "${version_build}" _set_target_item "${_xmake_sh_target_current}" "version_soname" "${version_soname}" } # set default in target set_default() { local default=${1} if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _set_target_item "${_xmake_sh_target_current}" "default" "${default}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _set_option_item "${_xmake_sh_option_current}" "default" "${default}" fi } # set configvar in target set_configvar() { if ! ${_loading_targets}; then return fi local name="${1}" local value="${2}" _set_target_item "${_xmake_sh_target_current}" "configvar_${name}" "${value}" _add_target_item "${_xmake_sh_target_current}" "configvars" "${name}" } # set filename in target set_filename() { if ! ${_loading_targets}; then return fi local filename="${1}" _set_target_item "${_xmake_sh_target_current}" "filename" "${filename}" } # set basename in target set_basename() { if ! ${_loading_targets}; then return fi local basename="${1}" _set_target_item "${_xmake_sh_target_current}" "basename" "${basename}" } # set extension in target set_extension() { if ! ${_loading_targets}; then return fi local extension=${1} _set_target_item "${_xmake_sh_target_current}" "extension" "${extension}" } # set prefixname in target set_prefixname() { if ! ${_loading_targets}; then return fi local prefixname=${1} _set_target_item "${_xmake_sh_target_current}" "prefixname" "${prefixname}" } # set target directory set_targetdir() { if ! ${_loading_targets}; then return fi _set_target_filepath "targetdir" "${1}" } # set target object directory set_objectdir() { if ! ${_loading_targets}; then return fi _set_target_filepath "objectdir" "${1}" } # set target config directory set_configdir() { if ! ${_loading_targets}; then return fi _set_target_filepath "configdir" "${1}" } # set target install directory set_installdir() { if ! ${_loading_targets}; then return fi _set_target_filepath "installdir" "${1}" } # add deps in target add_deps() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "deps" "${@}" } # add files in target add_files() { if ! ${_loading_targets}; then return fi _add_target_filepaths "files" "$@" } # add install files in target add_installfiles() { if ! ${_loading_targets}; then return fi _add_target_installpaths "installfiles" "$@" } # add header files in target add_headerfiles() { if ! ${_loading_targets}; then return fi _add_target_installpaths "headerfiles" "$@" } # add config files in target add_configfiles() { if ! ${_loading_targets}; then return fi _add_target_filepaths "configfiles" "$@" } # add defines in target add_defines() { local define="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for define in $@; do if test_nq "${define}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "defines" "${define}" else public=true fi done if ${public}; then for define in $@; do if test_nq "${define}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "defines_public" "${define}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "defines" "${@}" fi } # add undefines in target add_undefines() { local undefine="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for undefine in $@; do if test_nq "${undefine}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "undefines" "${undefine}" else public=true fi done if ${public}; then for undefine in $@; do if test_nq "${undefine}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "undefines_public" "${undefine}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "undefines" "${@}" fi } # add includedirs in target add_includedirs() { local public=false local dir="" for dir in $@; do if test_nq "${dir}" "{public}"; then if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi if string_startswith "${dir}" "${xmake_sh_projectdir}"; then path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" fi if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "includedirs" "${dir}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "includedirs" "${dir}" fi else public=true fi done if ${public}; then for dir in $@; do if test_nq "${dir}" "{public}"; then if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi if string_startswith "${dir}" "${xmake_sh_projectdir}"; then path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" fi if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "includedirs_public" "${dir}" fi fi done fi } # add links in target add_links() { local link="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for link in $@; do if test_nq "${link}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "links" "${link}" else public=true fi done if ${public}; then for link in $@; do if test_nq "${link}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "links_public" "${link}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "links" "${@}" fi } # add syslinks in target add_syslinks() { local syslink="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for syslink in $@; do if test_nq "${syslink}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "syslinks" "${syslink}" else public=true fi done if ${public}; then for syslink in $@; do if test_nq "${syslink}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "syslinks_public" "${syslink}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "syslinks" "${@}" fi } # add linkdirs in target add_linkdirs() { local dir="" local public=false for dir in $@; do if test_nq "${dir}" "{public}"; then if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi if string_startswith "${dir}" "${xmake_sh_projectdir}"; then path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" fi if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "linkdirs" "${dir}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "linkdirs" "${dir}" fi else public=true fi done if ${public}; then for dir in $@; do if test_nq "${dir}" "{public}"; then if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi if string_startswith "${dir}" "${xmake_sh_projectdir}"; then path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" fi if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "linkdirs_public" "${dir}" fi fi done fi } # add rpathdirs in target add_rpathdirs() { if ! ${_loading_targets}; then return fi local dir="" for dir in $@; do if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" _add_target_item "${_xmake_sh_target_current}" "rpathdirs" "${dir}" done } # add frameworks in target add_frameworks() { local framework="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for framework in $@; do if test_nq "${framework}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "frameworks" "${framework}" else public=true fi done if ${public}; then for framework in $@; do if test_nq "${framework}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "frameworks_public" "${framework}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "frameworks" "${@}" fi } # add frameworkdirs in target add_frameworkdirs() { local dir="" for dir in $@; do if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "frameworkdirs" "${dir}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "frameworkdirs" "${dir}" fi done } # set strip in target set_strip() { if ! ${_loading_targets}; then return fi local strip=${1} _set_target_item "${_xmake_sh_target_current}" "strip" "${strip}" } # set symbols in target set_symbols() { if ! ${_loading_targets}; then return fi local symbols="${1}" _set_target_item "${_xmake_sh_target_current}" "symbols" "${symbols}" } # set languages in target set_languages() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _set_target_item "${_xmake_sh_target_current}" "languages" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _set_option_item "${_xmake_sh_option_current}" "languages" "${@}" fi } # set warnings in target set_warnings() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _set_target_item "${_xmake_sh_target_current}" "warnings" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _set_option_item "${_xmake_sh_option_current}" "warnings" "${@}" fi } # set optimizes in target set_optimizes() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _set_target_item "${_xmake_sh_target_current}" "optimizes" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _set_option_item "${_xmake_sh_option_current}" "optimizes" "${@}" fi } # add cflags in target add_cflags() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "cflags" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "cflags" "${@}" fi } # add cxflags in target add_cxflags() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "cxflags" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "cxflags" "${@}" fi } # add cxxflags in target add_cxxflags() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "cxxflags" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "cxxflags" "${@}" fi } # add asflags in target add_asflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "asflags" "${@}" } # add mflags in target add_mflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "mflags" "${@}" } # add mxflags in target add_mxflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "mxflags" "${@}" } # add mxxflags in target add_mxxflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "mxxflags" "${@}" } # add ldflags in target add_ldflags() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "ldflags" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "ldflags" "${@}" fi } # add shflags in target add_shflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "shflags" "${@}" } # add arflags in target add_arflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "arflags" "${@}" } # add options in target add_options() { if ! ${_loading_targets}; then return fi local name="" local public=false for name in $@; do if test_nq "${name}" "{public}"; then public=true break fi done for name in $@; do if has_config "${name}"; then local itemname="" local itemnames="includedirs linkdirs links defines cflags cxflags cxxflags ldflags" for itemname in ${itemnames}; do _get_option_item "${name}" "${itemname}"; local values="${_ret}" if test_nz "${values}"; then _add_target_item "${_xmake_sh_target_current}" "${itemname}" "${values}" if $public; then _add_target_item "${_xmake_sh_target_current}" "${itemname}_public" "${values}" fi fi done fi done } # before_install in target before_install() { if ! ${_loading_targets}; then return fi local funcname="${1}" _add_target_item "${_xmake_sh_target_current}" "before_install" "${funcname}" } # after_install in target after_install() { if ! ${_loading_targets}; then return fi local funcname="${1}" _add_target_item "${_xmake_sh_target_current}" "after_install" "${funcname}" } #----------------------------------------------------------------------------- # toolchain configuration apis # # define toolchain toolchain() { local name="${1}" _xmake_sh_toolchain_current="${name}" if ! ${_loading_toolchains}; then return fi _xmake_sh_toolchains="${_xmake_sh_toolchains} ${name}" _map_set "toolchains" "${name}_name" "${name}" return 0 } toolchain_end() { _xmake_sh_toolchain_current="" } _map "toolchains" # has the given toolchain? _has_toolchain() { local name=${1} if _map_has "toolchains" "${name}_name"; then return 0 fi return 1 } # get the given toolchain item _get_toolchain_item() { local name=${1} local key=${2} _map_get "toolchains" "${name}_${key}" } # set the given toolchain item _set_toolchain_item() { local name=${1} local key=${2} local value="${3}" if test_nz "${name}"; then _map_set "toolchains" "${name}_${key}" "${value}" else raise "please set toolchain in the toolchain scope!" fi } # get the give toolchain toolset _get_toolchain_toolset() { local name=${1} local kind=${2} _get_toolchain_item "${name}" "toolset_${kind}" } # set the give toolchain toolset _set_toolchain_toolset() { local name=${1} local kind=${2} local programs="${3}" _set_toolchain_item "${name}" "toolset_${kind}" "${programs}" } # add the give toolchain toolset _add_toolchain_toolset() { local name=${1} local kind=${2} local program="${3}" _get_toolchain_item "${name}" "toolset_${kind}"; local programs="${_ret}" if test_nz "${programs}"; then programs="${programs}:${program}" else programs="${program}" fi _set_toolchain_item "${name}" "toolset_${kind}" "${programs}" } # set toolset in toolchain set_toolset() { if ! ${_loading_toolchains}; then return fi local kind=${1} shift local idx=0 while test $# != 0; do local program="${1}" local key="${kind}" if test_nq "${idx}" "0"; then key="${key}_${idx}" fi _set_toolchain_toolset "${_xmake_sh_toolchain_current}" "${key}" "${program}" idx=$((idx+1)) shift done } #----------------------------------------------------------------------------- # load options # # load options and toolchains _load_options_and_toolchains() { _loading_options=true _loading_toolchains=true _loading_targets=false local file=${xmake_sh_projectdir}/xmake.sh if test -f "${file}"; then includes "${file}" else # include all xmake.sh files in next sub-directories _os_find "${xmake_sh_projectdir}" "xmake.sh" "2" local files="${_ret}" for file in ${files}; do includes "${file}" done fi } _load_options_and_toolchains # show option usage _show_options_usage() { _get_options_for_menu; local options="${_ret}" for name in ${options}; do _get_option_item "${name}" "description"; local description="${_ret}" _get_option_item "${name}" "default"; local default="${_ret}" string_toupper ${name}; local head="--${name}="${_ret}"" local headsize=${#head} local tail="${description}" if test "x${default}" != "x"; then local defval=${default} if test "x${defval}" = "xtrue"; then defval="yes" elif test "x${defval}" = "xfalse"; then defval="no" fi tail="${tail} (default: ${defval})" fi local width=24 local padding_width=$((${width} - ${headsize})) local padding=$(string_dupch ${padding_width} " ") echo " ${head}${padding}${tail}" done } # show configure usage _show_usage() { echo ' Usage: '"$0"' [...] Options: [defaults in brackets after descriptions] Common options: --help Print this message. --version Only print version information. --verbose Display more information. --diagnosis Display lots of diagnosis information. --generator=GENERATOR Set the project generator. (default: '"${project_generator}"') - gmake - ninja --make=MAKE Set the make program. (default: '"${_make_program_default}"') --ninja=NINJA Set the Ninja program. (default: '"${_ninja_program_default}"') --plat=PLAT Compile for the given platform. (default: '"${_target_plat_default}"') - msys - cross - bsd - mingw - macosx - linux - wasm --arch=ARCH Compile for the given architecture. (default: '"${_target_arch_default}"') - msys: i386 x86_64 - cross: i386 x86_64 arm arm64 mips mips64 riscv riscv64 loong64 s390x ppc ppc64 sh4 - bsd: i386 x86_64 - mingw: i386 x86_64 arm arm64 - macosx: x86_64 arm64 - linux: i386 x86_64 armv7 armv7s arm64-v8a mips mips64 mipsel mips64el --mode=MODE Set the given compilation mode. (default: '"${_target_mode_default}"') - release - debug --kind=KIND Set the given target kind. (default: '"${_target_kind_default}"') - static - shared - binary --toolchain=TOOLCHAIN Set toolchain name. - clang - gcc - emcc - tinycc - cosmocc --builddir=DIR Set build directory. (default: '"${xmake_sh_builddir}"') Autoconf options: --build=BUILD Configure for building on BUILD [guessed] --host=HOST Cross-compile to build programs to run on HOST [BUILD] --prefix=PREFIX Set install files directory in tree rooted at PREFIX. (default: '"${_install_prefix_default}"') --bindir=DIR Set install binaries directory in PREFIX/DIR. (default: '"${_install_bindir_default}"') --libdir=DIR Set install libraries directory in PREFIX/DIR. (default: '"${_install_libdir_default}"') --includedir=DIR Set install includes directory in PREFIX/DIR. (default: '"${_install_includedir_default}"') Project options: '"$(_show_options_usage)"' ' exit 1 } # show xmake.sh version _show_version() { echo "xmake.sh v${xmake_sh_version}, A script-only build utility like autotools" echo "${xmake_sh_copyright}" echo ' _ _ ' echo " __ ___ __ __ __ _| | ______ ___| |__ " echo " \ \/ / | \/ |/ _ | |/ / __ \ / __| '_ \ " echo " > < | \__/ | /_| | < ___/_\__ \ | | | " echo " /_/\_\_|_| |_|\__ \|_|\_\____(_)___/_| |_| " echo ' by ruki, xmake.io' echo ' ' echo ' 👉 Manual: https://xmake.io/guide/quick-start ' echo ' 🙏 Donate: https://xmake.io/about/sponsor ' echo ' ' exit 2 } # --foo=yes => foo _parse_argument_name() { local arg="${1#--}" case "${arg}" in *=*) arg="${arg%%=*}" ;; esac string_replace "${arg}" "-" "_" } # --foo=yes => yes _parse_argument_value() { case "${1}" in *=*) _ret="${1#*=}" ;; *) _ret="" ;; esac } # parse input arguments _handle_option() { _parse_argument_name ${1}; local name="${_ret}" _parse_argument_value ${1}; local value="${_ret}" if test_eq "${name}" "help"; then _show_usage return 0 elif test_eq "${name}" "version"; then _show_version return 0 elif test_eq "${name}" "verbose"; then xmake_sh_verbose=true return 0 elif test_eq "${name}" "diagnosis"; then xmake_sh_diagnosis=true return 0 elif test_eq "${name}" "plat"; then _target_plat=${value} return 0 elif test_eq "${name}" "arch"; then _target_arch=${value} return 0 elif test_eq "${name}" "mode"; then _target_mode=${value} return 0 elif test_eq "${name}" "kind"; then _target_kind=${value} return 0 elif test_eq "${name}" "toolchain"; then _target_toolchain=${value} return 0 elif test_eq "${name}" "generator"; then project_generator=${value} return 0 elif test_eq "${name}" "make"; then _make_program=${value} return 0 elif test_eq "${name}" "ninja"; then _ninja_program=${value} return 0 elif test_eq "${name}" "prefix"; then _install_prefix_default="${value}" return 0 elif test_eq "${name}" "bindir"; then _install_bindir_default="${value}" return 0 elif test_eq "${name}" "libdir"; then _install_libdir_default="${value}" return 0 elif test_eq "${name}" "includedir"; then _install_includedir_default="${value}" return 0 elif test_eq "${name}" "builddir" || test_eq "${name}" "buildir"; then xmake_sh_builddir="${value}" return 0 elif test_eq "${name}" "build"; then _autoconf_build_type="${value}" return 0 elif test_eq "${name}" "host"; then _autoconf_host_type="${value}" return 0 elif _has_option "${name}"; then _set_option_value "${name}" "${value}" return 0 fi return 1 } while test $# != 0; do if ! _handle_option ${1}; then wprint "unknown option: $1" fi shift done #----------------------------------------------------------------------------- # handle some autoconf configurations # # parse triplet # https://github.com/xmake-io/xmake/issues/3869 # e.g. i686-linux-gnu, aarch64-apple-darwin, x86_64-w64-mingw32, i686-redhat-linux-gnu _parse_triplet() { local triplet="${1}" string_split "${triplet}" "-" } _get_arch_from_cpu() { local cpu="${1}" case "${cpu}" in i686) _ret="i386";; i386) _ret="i386";; x86_64) _ret="x86_64";; aarch64) _ret="arm64";; arm64) _ret="arm64";; arm*) _ret="arm";; *) _ret="${cpu}";; esac } _get_plat_from_vendor_os() { local vendor="${1}" local os="${2}" case "${vendor}" in linux) if string_contains "${os}" "android"; then _ret="android" else _ret="linux" fi ;; apple) if test_eq "${os}" "darwin"; then _ret="macosx" fi ;; w64) _ret="mingw";; *) _ret="${os}";; esac } _handle_autoconf_configs() { if test_z "${_autoconf_host_type}"; then _autoconf_host_type="${_autoconf_build_type}" fi if test_nz "${_autoconf_build_type}"; then _parse_triplet "${_autoconf_build_type}"; local cpu="${_ret}"; local vendor="${_ret2}"; local os="${_ret3}" _get_arch_from_cpu "${cpu}" if test_nz "${_ret}"; then os_arch="${_ret}" else wprint "unknown cpu: ${cpu} in --build=${value}" fi _get_plat_from_vendor_os "${vendor}" "${os}" if test_nz "${_ret}"; then os_host="${_ret}" else wprint "unknown vendor-os: ${vendor}-${os} in --build=${value}" fi fi if test_nz "${_autoconf_host_type}"; then _parse_triplet "${_autoconf_host_type}"; local cpu="${_ret}"; local vendor="${_ret2}"; local os="${_ret3}" _get_arch_from_cpu "${cpu}" if test_nz "${_ret}"; then _target_arch_default="${_ret}" else wprint "unknown cpu: ${cpu} in --host=${value}" fi _get_plat_from_vendor_os "${vendor}" "${os}" if test_nz "${_ret}"; then _target_plat_default="${_ret}" else wprint "unknown vendor-os: ${vendor}-${os} in --build=${value}" fi fi } _handle_autoconf_configs #----------------------------------------------------------------------------- # detect platform and toolchains # # envs toolchain toolchain "envs" set_toolset "as" "$CC" "$CXX" "$AS" set_toolset "cc" "$CC" set_toolset "cxx" "$CC" "$CXX" set_toolset "mm" "$CC" "$CXX" set_toolset "mxx" "$CC" "$CXX" set_toolset "ld" "$CXX" "$CC" "$LD" set_toolset "sh" "$CXX" "$CC" "$LD" set_toolset "ar" "$AR" "ar" toolchain_end # clang toolchain toolchain "clang" set_toolset "as" "clang" set_toolset "cc" "clang" set_toolset "cxx" "clang" "clang++" set_toolset "mm" "clang" set_toolset "mxx" "clang" "clang++" set_toolset "ld" "clang++" "clang" set_toolset "sh" "clang++" "clang" set_toolset "ar" "ar" toolchain_end # gcc toolchain toolchain "gcc" set_toolset "as" "gcc" set_toolset "cc" "gcc" set_toolset "cxx" "gcc" "g++" set_toolset "mm" "gcc" set_toolset "mxx" "gcc" "g++" set_toolset "ld" "g++" "gcc" set_toolset "sh" "g++" "gcc" set_toolset "ar" "ar" toolchain_end # mingw toolchain (x86_64) toolchain "x86_64_w64_mingw32" set_toolset "as" "x86_64-w64-mingw32-gcc" set_toolset "cc" "x86_64-w64-mingw32-gcc" set_toolset "cxx" "x86_64-w64-mingw32-gcc" "x86_64-w64-mingw32-g++" set_toolset "mm" "x86_64-w64-mingw32-gcc" set_toolset "mxx" "x86_64-w64-mingw32-gcc" "x86_64-w64-mingw32-g++" set_toolset "ld" "x86_64-w64-mingw32-g++" "x86_64-w64-mingw32-gcc" set_toolset "sh" "x86_64-w64-mingw32-g++" "x86_64-w64-mingw32-gcc" set_toolset "ar" "x86_64-w64-mingw32-ar" "ar" toolchain_end # mingw toolchain (i686) toolchain "i686_w64_mingw32" set_toolset "as" "i686-w64-mingw32-gcc" set_toolset "cc" "i686-w64-mingw32-gcc" set_toolset "cxx" "i686-w64-mingw32-gcc" "i686-w64-mingw32-g++" set_toolset "mm" "i686-w64-mingw32-gcc" set_toolset "mxx" "i686-w64-mingw32-gcc" "i686-w64-mingw32-g++" set_toolset "ld" "i686-w64-mingw32-g++" "i686-w64-mingw32-gcc" set_toolset "sh" "i686-w64-mingw32-g++" "i686-w64-mingw32-gcc" set_toolset "ar" "i686-w64-mingw32-ar" "ar" toolchain_end # aarch64 toolchain (aarch64) toolchain "aarch64_linux_gnu" set_toolset "as" "aarch64-linux-gnu-gcc" set_toolset "cc" "aarch64-linux-gnu-gcc" set_toolset "cxx" "aarch64-linux-gnu-gcc" "aarch64-linux-gnu-g++" set_toolset "mm" "aarch64-linux-gnu-gcc" set_toolset "mxx" "aarch64-linux-gnu-gcc" "aarch64-linux-gnu-g++" set_toolset "ld" "aarch64-linux-gnu-g++" "aarch64-linux-gnu-gcc" set_toolset "sh" "aarch64-linux-gnu-g++" "aarch64-linux-gnu-gcc" set_toolset "ar" "aarch64-linux-gnu-ar" "ar" toolchain_end # emcc toolchain (wasm32) toolchain "emcc" set_toolset "as" "emcc" set_toolset "cc" "emcc" set_toolset "cxx" "emcc" "em++" set_toolset "mm" "emcc" set_toolset "mxx" "emcc" "em++" set_toolset "ld" "em++" "emcc" set_toolset "sh" "em++" "emcc" set_toolset "ar" "emar" "ar" toolchain_end # cosmocc toolchain, e.g. ./configure --plat=linux --toolchain=cosmocc toolchain "cosmocc" set_toolset "as" "cosmocc" set_toolset "cc" "cosmocc" set_toolset "cxx" "cosmocc" "cosmoc++" set_toolset "mm" "cosmocc" set_toolset "mxx" "cosmocc" "cosmoc++" set_toolset "ld" "cosmoc++" "cosmocc" set_toolset "sh" "cosmoc++" "cosmocc" set_toolset "ar" "cosmoar" toolchain_end # tinycc toolchain toolchain "tinycc" set_toolset "as" "tcc" "gcc" "clang" set_toolset "cc" "tcc" set_toolset "cxx" "gcc" "g++" "clang" "clang++" set_toolset "mm" "gcc" "clang" set_toolset "mxx" "gcc" "g++" "clang" "clang++" set_toolset "ld" "tcc" set_toolset "sh" "tcc" set_toolset "ar" "tcc -ar" "ar" toolchain_end # check platform _check_platform() { if test "x${_target_plat}" = "x"; then _target_plat=${_target_plat_default} fi if test "x${_target_arch}" = "x"; then _target_arch=${_target_arch_default} fi if test "x${_target_mode}" = "x"; then _target_mode=${_target_mode_default} fi if test "x${_target_kind}" = "x"; then _target_kind=${_target_kind_default} fi echo "checking for platform ... ${_target_plat}" echo "checking for architecture ... ${_target_arch}" } # get toolchain compile command for gcc/clang _toolchain_compcmd_for_gcc_clang() { local program="${1}" local objectfile="${2}" local sourcefile="${3}" local flags="${4}" _ret="${program} -c ${flags} -o ${objectfile} ${sourcefile}" } # get toolchain link command for gcc/clang _toolchain_linkcmd_for_gcc_clang() { local toolkind="${1}" local program="${2}" local binaryfile="${3}" local objectfiles="${4}" local flags="${5}" if test_eq "${toolkind}" "sh"; then flags="-shared -fPIC ${flags}" fi _ret="${program} -o ${binaryfile} ${objectfiles} ${flags}" } # get toolchain link command for ar _toolchain_linkcmd_for_ar() { local toolkind="${1}" local program="${2}" local binaryfile="${3}" local objectfiles="${4}" local flags="${5}" _ret="${program} ${flags} ${binaryfile} ${objectfiles}" } # get toolchain compile command _toolchain_compcmd() { local sourcekind="${1}" local objectfile="${2}" local sourcefile="${3}" local flags="${4}" _get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local compcmd="" case "${toolname}" in gcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; gxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; clang) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; clangxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; emcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; emxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; cosmocc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; cosmocxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; tcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; *) raise "unknown toolname(${toolname})!" ;; esac _ret="${compcmd}" } # get toolchain link command _toolchain_linkcmd() { local toolkind="${1}" local binaryfile="${2}" local objectfiles="${3}" local flags="${4}" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" case "${toolname}" in gcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; gxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; clang) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; clangxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; emcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; emxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; cosmocc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; cosmocxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; tcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; ar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; emar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; cosmoar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; *) raise "unknown toolname(${toolname})!" ;; esac _ret="${linkcmd}" } # try make _toolchain_try_make() { local program="${1}" if _os_runv "${program}" "--version"; then return 0 fi return 1 } # try ninja _toolchain_try_ninja() { local program="${1}" if _os_runv "${program}" "--version"; then return 0 fi return 1 } # try gcc _toolchain_try_gcc() { if test "x${_toolchain_try_gcc_result}" = "xok"; then return 0 elif test "x${_toolchain_try_gcc_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_gcc_result="ok" return 0 fi _toolchain_try_gcc_result="no" return 1 } # try g++ _toolchain_try_gxx() { if test "x${_toolchain_try_gxx_result}" = "xok"; then return 0 elif test "x${_toolchain_try_gxx_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_gxx_result="ok" return 0 fi _toolchain_try_gxx_result="no" return 1 } # try clang _toolchain_try_clang() { if test "x${_toolchain_try_clang_result}" = "xok"; then return 0 elif test "x${_toolchain_try_clang_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_clang_result="ok" return 0 fi _toolchain_try_clang_result="no" return 1 } # try clang++ _toolchain_try_clangxx() { if test "x${_toolchain_try_clangxx_result}" = "xok"; then return 0 elif test "x${_toolchain_try_clangxx_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_clangxx_result="ok" return 0 fi _toolchain_try_clangxx_result="no" return 1 } # try tcc _toolchain_try_tcc() { if test "x${_toolchain_try_tcc_result}" = "xok"; then return 0 elif test "x${_toolchain_try_tcc_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "-v"; then _toolchain_try_tcc_result="ok" return 0 fi _toolchain_try_tcc_result="no" return 1 } # try ar _toolchain_try_ar() { local kind="${1}" local program="${2}" # generate the source file _os_tmpfile local tmpfile="${_ret}" local objectfile="${tmpfile}.o" local libraryfile="${tmpfile}.a" echo "" > "${objectfile}" # try linking it local ok=false if _os_runv "${program}" "-cr" "${libraryfile}" "${objectfile}"; then ok=true fi # remove files _os_tryrm "${objectfile}" _os_tryrm "${libraryfile}" if ${ok}; then return 0 fi return 1 } # try cosmoar _toolchain_try_cosmoar() { if test "x${_toolchain_try_cosmoar_result}" = "xok"; then return 0 elif test "x${_toolchain_try_cosmoar_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_cosmoar_result="ok" return 0 fi _toolchain_try_cosmoar_result="no" return 1 } # try program _toolchain_try_program() { local toolchain="${1}" local kind="${2}" local program="${3}" local ok=false path_toolname "${program}"; local toolname="${_ret}" case "${toolname}" in gcc) _toolchain_try_gcc "${kind}" "${program}" && ok=true;; gxx) _toolchain_try_gxx "${kind}" "${program}" && ok=true;; clang) _toolchain_try_clang "${kind}" "${program}" && ok=true;; clangxx) _toolchain_try_clangxx "${kind}" "${program}" && ok=true;; emcc) _toolchain_try_clang "${kind}" "${program}" && ok=true;; emxx) _toolchain_try_clangxx "${kind}" "${program}" && ok=true;; cosmocc) _toolchain_try_gcc "${kind}" "${program}" && ok=true;; cosmocxx) _toolchain_try_gxx "${kind}" "${program}" && ok=true;; tcc) _toolchain_try_tcc "${kind}" "${program}" && ok=true;; ar) _toolchain_try_ar "${kind}" "${program}" && ok=true;; emar) _toolchain_try_ar "${kind}" "${program}" && ok=true;; cosmoar) _toolchain_try_cosmoar "${kind}" "${program}" && ok=true;; *) raise "unknown toolname(${toolname})!" ;; esac if ${ok}; then vprint "checking for ${program} ... ok" return 0 fi vprint "checking for ${program} ... no" return 1 } # try toolset _toolchain_try_toolset() { local toolchain=${1} local kind=${2} local description=${3} local indices="0 1 2 3 4 5" for idx in ${indices}; do local key="${kind}" if test_nq "${idx}" "0"; then key="${key}_${idx}" fi _get_toolchain_toolset "${toolchain}" "${key}"; local program="${_ret}" if test_nz "${program}"; then if _toolchain_try_program "${toolchain}" "${kind}" "${program}"; then _set_toolchain_toolset "${toolchain}" "${kind}" "${program}" echo "checking for the ${description} (${kind}) ... ${program}" return 0 fi fi done return 1 } # try toolchain _toolchain_try() { local toolchain=${1} vprint "checking for $toolchain toolchain ..." if _toolchain_try_toolset "${toolchain}" "cc" "c compiler" && _toolchain_try_toolset "${toolchain}" "cxx" "c++ compiler" && _toolchain_try_toolset "${toolchain}" "as" "assembler" && _toolchain_try_toolset "${toolchain}" "mm" "objc compiler" && _toolchain_try_toolset "${toolchain}" "mxx" "objc++ compiler" && _toolchain_try_toolset "${toolchain}" "ld" "linker" && _toolchain_try_toolset "${toolchain}" "ar" "static library archiver" && _toolchain_try_toolset "${toolchain}" "sh" "shared library linker"; then return 0 fi return 1 } # detect make _toolchain_detect_make() { if test "x${_make_program}" = "x"; then _make_program=${_make_program_default} fi if _toolchain_try_make "${_make_program}"; then echo "checking for make ... ok" else echo "checking for make ... no" raise "make not found!" fi } # detect ninja _toolchain_detect_ninja() { if test "x${_ninja_program}" = "x"; then _ninja_program=${_ninja_program_default} fi if _toolchain_try_ninja "${_ninja_program}"; then echo "checking for ninja ... ok" else echo "checking for ninja ... no" raise "ninja not found!" fi } # detect build backend _toolchain_detect_backend() { if test "x${project_generator}" = "xgmake"; then _toolchain_detect_make elif test "x${project_generator}" = "xninja"; then _toolchain_detect_ninja fi } # detect toolchain _toolchain_detect() { # detect build backend _toolchain_detect_backend # detect toolchains local toolchains="${1}" if test "x${toolchains}" = "x"; then if is_plat "macosx"; then toolchains="envs clang gcc" elif is_plat "mingw"; then if is_arch "i386"; then toolchains="i686_w64_mingw32" else toolchains="x86_64_w64_mingw32" fi elif is_plat "wasm"; then toolchains="emcc" elif is_plat "linux" && ! is_arch "${os_arch}"; then toolchains="envs" if is_arch "arm64"; then toolchains="${toolchains} aarch64_linux_gnu" fi else toolchains="envs gcc clang" fi fi for toolchain in ${toolchains}; do if _toolchain_try "$toolchain"; then _target_toolchain=${toolchain} break fi done } # check toolchain _check_toolchain() { local toolchain=${_target_toolchain} _target_toolchain="" _toolchain_detect ${toolchain} if test "x${_target_toolchain}" != "x"; then echo "checking for toolchain ... ${_target_toolchain}" else echo "checking for toolchain ... no" raise "toolchain not found!" fi } # get function code # # sigsetjmp # sigsetjmp((void*)0, 0) # _get_funccode() { local func="${1}" local code="" if string_contains "${func}" "("; then code="${func}" else code="typedef void (*func_t)(); volatile func_t p${func} = (func_t)${func}; while (p${func}) {break;};" fi _ret="${code}" } # generate cxsnippets source code _generate_cxsnippets_sourcecode() { local funcs="${1}" local includes="${2}" local types="${3}" local snippets="${4}" local snippet_includes="" for include in $includes; do snippet_includes="${snippet_includes}#include \"${include}\"\n" done local snippet_types="" for type in $types; do string_replace "${type}" '[^a-zA-Z]' "_"; local typevar="${_ret}" snippet_types="${snippet_types}typedef ${type} __type_${typevar};\n" done local snippet_funcs="" for func in $funcs; do _get_funccode "${func}"; func="${_ret}" snippet_funcs="${snippet_funcs}${func}\n " done local snippets_code="" if test_nz "${snippet_includes}"; then snippets_code="${snippets_code}${snippet_includes}\n" fi if test_nz "${snippet_types}"; then snippets_code="${snippets_code}${snippet_types}\n" fi if test_nz "${snippets}"; then snippets_code="${snippets_code}${snippets}\n" fi _ret=' '"${snippets_code}"'int main(int argc, char** argv) { '"${snippet_funcs}"' return 0; }' } # check cxsnippets _check_cxsnippets() { local name="${1}" local kind="${2}" _get_option_item "${name}" "${kind}funcs"; local funcs="${_ret}" _get_option_item "${name}" "${kind}includes"; local includes="${_ret}" _get_option_item "${name}" "${kind}types"; local types="${_ret}" _get_option_item "${name}" "${kind}snippets"; local snippets="${_ret}" if test_z "${funcs}" && test_z "${includes}" && test_z "${types}" && test_z "${snippets}"; then return 0 fi # get c/c++ extension local extension=".c" local sourcekind="cc" if test_eq "${kind}" "cxx"; then extension=".cpp" sourcekind="cxx" fi # generate source code _generate_cxsnippets_sourcecode "${funcs}" "${includes}" "${types}" "${snippets}"; local sourcecode="${_ret}" dprint "${sourcecode}" # generate the source file _os_tmpfile local tmpfile="${_ret}" local sourcefile="${tmpfile}${extension}" local objectfile="${tmpfile}.o" local binaryfile="${tmpfile}.bin" print "${sourcecode}" > "${sourcefile}" # try compiling it local ok=false if ! ${ok}; then local compflags="" _get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local itemnames="languages warnings optimizes defines undefines includedirs" for itemname in ${itemnames}; do _get_option_abstract_flags "${name}" "${sourcekind}" "${toolname}" "${itemname}"; local flags="${_ret}" if test_nz "${flags}"; then _split_flags "${flags}"; flags="${_ret}" compflags="${compflags} ${flags}" fi done local flagnames="cxflags" if test_eq "${sourcekind}" "cxx"; then flagnames="${flagnames} cxxflags" else flagnames="${flagnames} cflags" fi for flagname in $flagnames; do _get_option_item "${name}" "${flagname}"; local flags="${_ret}" if test_nz "${flags}"; then compflags="${compflags} ${flags}" fi done if test_eq "${sourcekind}" "cxx"; then if test_nz "${CXXFLAGS}"; then compflags="${compflags} ${CXXFLAGS}" fi else if test_nz "${CFLAGS}"; then compflags="${compflags} ${CFLAGS}" fi fi if test_nz "${CPPFLAGS}"; then compflags="${compflags} ${CPPFLAGS}" fi # add -isysroot and -target on macOS to ensure system SDK headers are used for option checking _get_macosx_sysroot_flags; compflags="${_ret} ${compflags}" _toolchain_compcmd "${sourcekind}" "${objectfile}" "${sourcefile}" "${compflags}"; local compcmd="${_ret}" if ${xmake_sh_diagnosis}; then print "> ${compcmd}" fi if _os_runv ${compcmd}; then ok=true fi fi # try linking it _get_option_item "${name}" "links"; local links="${_ret}" _get_option_item "${name}" "syslinks"; local syslinks="${_ret}" _get_option_item "${name}" "ldflags"; local ldflags="${_ret}" if test_nz "${syslinks}"; then links="${links} ${syslinks}" fi if ${ok} && (test_nz "${links}" || test_nz "${ldflags}"); then local toolkind="ld" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local itemnames="linkdirs links syslinks" local linkflags="" for itemname in ${itemnames}; do _get_option_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}" if test_nz "${flags}"; then _split_flags "${flags}"; flags="${_ret}" linkflags="${linkflags} ${flags}" fi done _get_option_item "${name}" "ldflags"; local flags="${_ret}" if test_nz "${flags}"; then linkflags="${linkflags} ${flags}" fi if test_nz "${LDFLAGS}"; then linkflags="${linkflags} ${LDFLAGS}" fi _toolchain_linkcmd "${toolkind}" "${binaryfile}" "${objectfile}" "${linkflags}"; local linkcmd="${_ret}" if ${xmake_sh_diagnosis}; then print "> ${linkcmd}" fi if _os_runv ${linkcmd}; then ok=true else ok=false fi fi # trace if ${xmake_sh_verbose} || ${xmake_sh_diagnosis}; then if test_nz "${includes}"; then print "> checking for ${kind} includes(${includes})" fi if test_nz "${types}"; then print "> checking for ${kind} types(${types})" fi if test_nz "${funcs}"; then print "> checking for ${kind} funcs(${funcs})" fi if test_nz "${links}"; then print "> checking for ${kind} links(${links})" fi fi # remove files _os_tryrm "${sourcefile}" _os_tryrm "${objectfile}" _os_tryrm "${binaryfile}" if ${ok}; then return 0 fi return 1 } # check csnippets _check_csnippets() { local name="${1}" if _check_cxsnippets "${name}" "c"; then return 0 fi return 1 } # check cxxsnippets _check_cxxsnippets() { local name="${1}" if _check_cxsnippets "${name}" "cxx"; then return 0 fi return 1 } # check option _check_option() { local name="${1}" _get_option_value "${name}"; local value="${_ret}" _get_option_item "${name}" "default"; local default="${_ret}" if test_nz "${value}"; then if _is_enabled "${value}"; then return 0 else return 1 fi elif test_nz "${default}"; then if _is_enabled "${default}"; then return 0 else return 1 fi else _get_option_item "${name}" "before_check"; local before_check="${_ret}" if test_nz "${before_check}"; then eval ${before_check} fi if _check_csnippets "${name}" && _check_cxxsnippets "${name}"; then return 0 fi fi return 1 } # check options _check_options() { _get_options_for_checking; local options="${_ret}" for name in $options; do if _check_option "$name"; then echo "checking for ${name} .. ok" _set_option_value "${name}" true else echo "checking for ${name} .. no" _set_option_value "${name}" false fi done } # check all _check_all() { _check_platform _check_toolchain _check_options } _check_all #----------------------------------------------------------------------------- # init builtin variables, e.g. add_headerfiles "${builddir}/config.h" # projectdir="${xmake_sh_projectdir}" if path_is_absolute "${xmake_sh_builddir}"; then builddir="${xmake_sh_builddir}" else builddir="${xmake_sh_projectdir}/${xmake_sh_builddir}" fi buildir=${builddir} # deprecated plat="${_target_plat}" arch="${_target_arch}" mode="${_target_mode}" kind="${_target_kind}" #----------------------------------------------------------------------------- # load project targets # # load targets _load_targets() { echo "analyzing project configuration .." _loading_options=false _loading_toolchains=false _loading_targets=true _xmake_sh_option_current="" _xmake_sh_target_current="" _xmake_sh_toolchain_current="" local file=${xmake_sh_projectdir}/xmake.sh if test -f "${file}"; then includes "${file}" else # include all xmake.sh files in next sub-directories _os_find "${xmake_sh_projectdir}" "xmake.sh" 2; local files="${_ret}" for file in ${files}; do includes "${file}" done fi } _load_targets # get toolset kinds for all targets # e.g. cc cxx as mm mxx ld sh ar _get_targets_toolkinds() { if test_z "${_targets_toolkinds_dedup}"; then _dedup "${_targets_toolkinds}"; _targets_toolkinds_dedup="${_ret}" fi _ret="${_targets_toolkinds_dedup}" } #----------------------------------------------------------------------------- # generate configfiles # # vprint config variable in `${name}` _vprint_configvar_value() { local name="${1}" local value="${2}" vprint " > replace ${name} -> ${value}" } # vprint config variable in `${define name}` _vprint_configvar_define() { local name="${1}" local value="${2}" if test_z "${value}"; then vprint " > replace ${name} -> /* #undef ${name} */" elif test_eq "${value}" "1" || test_eq "${value}" "true"; then vprint " > replace ${name} -> #define ${name} 1" elif test_eq "${value}" "0" || test_eq "${value}" "false"; then vprint " > replace ${name} -> /*#define ${name} 0*/" else vprint " > replace ${name} -> #define ${name} ${value}" fi } # replace config variable in `${define name}` _replace_configvar_define() { local name="${1}" local value="${2}" if test_z "${value}"; then _ret="s/\${define ${name}}/\/*#undef ${name}*\//g" elif test_eq "${value}" "1" || test_eq "${value}" "true"; then _ret="s/\${define ${name}}/#define ${name} 1/g" elif test_eq "${value}" "0" || test_eq "${value}" "false"; then _ret="s/\${define ${name}}/\/*#define ${name} 0*\//g" else _ret="s/\${define ${name}}/#define ${name} ${value}/g" fi } # replace config variable in `${name}` _replace_configvar_value() { local name="${1}" local value="${2}" _ret="s@\${${name}}@${value}@g" } # generate configfile for the given target _generate_configfile() { local target="${1}" local configfile_in="${2}" _get_target_item "${target}" "configdir"; local configdir="${_ret}" if test_z "${configdir}"; then path_directory configfile_in; configdir="${_ret}" fi if ! test -d "${configdir}"; then mkdir -p "${configdir}" fi path_basename "${configfile_in}"; local filename="${_ret}" local configfile="${configdir}/${filename}" echo "generating ${configfile} .." # replace builtin variables local patterns="" local target_os="" if is_plat "mingw"; then target_os="windows" else target_os="${_target_plat}" fi string_toupper ${target_os}; target_os="${_ret}" _vprint_configvar_value "OS" "${target_os}" _replace_configvar_value "OS" "${target_os}"; patterns="${_ret};${patterns}" # replace version _get_target_item "${target}" "version"; local version="${_ret}" _get_target_item "${target}" "version_build"; local version_build="${_ret}" string_split "${version}" "." local version_major="${_ret}" local version_minor="${_ret2}" local version_alter="${_ret3}" if test_nz "${version}"; then _vprint_configvar_value "VERSION" "${version}" _replace_configvar_value "VERSION" "${version}"; patterns="${_ret};${patterns}" fi if test_nz "${version_major}"; then _vprint_configvar_value "VERSION_MAJOR" "${version_major}" _replace_configvar_value "VERSION_MAJOR" "${version_major}"; patterns="${_ret};${patterns}" fi if test_nz "${version_minor}"; then _vprint_configvar_value "VERSION_MINOR" "${version_minor}" _replace_configvar_value "VERSION_MINOR" "${version_minor}"; patterns="${_ret};${patterns}" fi if test_nz "${version_alter}"; then _vprint_configvar_value "VERSION_ALTER" "${version_alter}" _replace_configvar_value "VERSION_ALTER" "${version_alter}"; patterns="${_ret};${patterns}" fi if test_nz "${version_build}"; then _os_date "${version_build}"; version_build="${_ret}" _vprint_configvar_value "VERSION_BUILD" "${version_build}" _replace_configvar_value "VERSION_BUILD" "${version_build}"; patterns="${_ret};${patterns}" fi # replace git variables local content="" content=$(cat "${configfile_in}") if string_contains "${content}" "GIT_"; then _os_iorunv "git" "describe" "--tags"; local git_tag="${_ret}" _vprint_configvar_value "GIT_TAG" "${git_tag}" _replace_configvar_value "GIT_TAG" "${git_tag}"; patterns="${_ret};${patterns}" _os_iorunv "git" "describe" "--tags" "--long"; local git_tag_long="${_ret}" _vprint_configvar_value "GIT_TAG_LONG" "${git_tag_long}" _replace_configvar_value "GIT_TAG_LONG" "${git_tag_long}"; patterns="${_ret};${patterns}" _os_iorunv "git" "rev-parse" "--abbrev-ref" "HEAD"; local git_branch="${_ret}" _vprint_configvar_value "GIT_BRANCH" "${git_branch}" _replace_configvar_value "GIT_BRANCH" "${git_branch}"; patterns="${_ret};${patterns}" _os_iorunv "git" "rev-parse" "--short" "HEAD"; local git_commit="${_ret}" _vprint_configvar_value "GIT_COMMIT" "${git_commit}" _replace_configvar_value "GIT_COMMIT" "${git_commit}"; patterns="${_ret};${patterns}" _os_iorunv "git" "rev-parse" "HEAD"; local git_commit_long="${_ret}" _vprint_configvar_value "GIT_COMMIT_LONG" "${git_commit_long}" _replace_configvar_value "GIT_COMMIT_LONG" "${git_commit_long}"; patterns="${_ret};${patterns}" _os_iorunv "log" "-1" "--date=format:%Y%m%d%H%M%S" "--format=%ad"; local git_commit_date="${_ret}" _vprint_configvar_value "GIT_COMMIT_DATE" "${git_commit_date}" _replace_configvar_value "GIT_COMMIT_DATE" "${git_commit_date}"; patterns="${_ret};${patterns}" fi # replace configvars in target local count=0 local configfile_dst="${configfile}" _os_tmpfile; local tmpfile="${_ret}" cp "${configfile_in}" "${tmpfile}" _get_target_item "${target}" "configvars"; local configvars="${_ret}" for name in ${configvars}; do _get_target_item "${target}" "configvar_${name}"; local value="${_ret}" _vprint_configvar_define "${name}" "${value}" _vprint_configvar_value "${name}" "${value}" _replace_configvar_define "${name}" "${value}"; patterns="${_ret};${patterns}" _replace_configvar_value "${name}" "${value}"; patterns="${_ret};${patterns}" count=$((count + 1)) # do replace if test_eq "$count" "10"; then _io_replace_file "${tmpfile}" "${configfile}" "${patterns}" local swapfile="${tmpfile}" tmpfile="${configfile}" configfile="${swapfile}" patterns="" count=0 fi done # do replace (left) if test_nz "${patterns}"; then _io_replace_file "${tmpfile}" "${configfile}" "${patterns}" local swapfile="${tmpfile}" tmpfile="${configfile}" configfile="${swapfile}" patterns="" count=0 fi # replace fallback patterns='s/${define \(.*\)}/\/*#undef \1*\//g;' _io_replace_file "${tmpfile}" "${configfile}" "${patterns}" if test_nq "${configfile}" "${configfile_dst}"; then cp "${configfile}" "${configfile_dst}" fi echo "${configfile_dst} is generated!" } # generate configfiles _generate_configfiles() { for target in ${_xmake_sh_targets}; do _get_target_item "${target}" "configfiles"; local configfiles="${_ret}" for configfile in ${configfiles}; do _generate_configfile "${target}" "${configfile}" done done } _generate_configfiles #----------------------------------------------------------------------------- # generate gmake file # _gmake_begin() { echo "generating makefile .." } _gmake_add_header() { echo "# this is the build file for this project # it is autogenerated by the xmake.sh build system. # do not edit by hand. " > "${xmake_sh_makefile}" } _gmake_add_switches() { echo "ifneq (\$(VERBOSE),1)" >> "${xmake_sh_makefile}" echo "VV=@" >> "${xmake_sh_makefile}" echo "endif" >> "${xmake_sh_makefile}" echo "" >> "${xmake_sh_makefile}" echo "ifeq (\$(PREFIX),)" >> "${xmake_sh_makefile}" echo "PREFIX=${_install_prefix_default}" >> "${xmake_sh_makefile}" echo "endif" >> "${xmake_sh_makefile}" echo "" >> "${xmake_sh_makefile}" echo "INSTALLDIR:=\$(DESTDIR)" >> "${xmake_sh_makefile}" echo "ifneq (\$(PREFIX),)" >> "${xmake_sh_makefile}" echo "ifneq (\$(INSTALLDIR),)" >> "${xmake_sh_makefile}" echo "PREFIX_:=\$(patsubst /%,%,\$(PREFIX))" >> "${xmake_sh_makefile}" echo "INSTALLDIR:=\$(INSTALLDIR)/\$(PREFIX_)" >> "${xmake_sh_makefile}" echo "else" >> "${xmake_sh_makefile}" echo "INSTALLDIR:=\$(PREFIX)" >> "${xmake_sh_makefile}" echo "endif" >> "${xmake_sh_makefile}" echo "endif" >> "${xmake_sh_makefile}" echo "" >> "${xmake_sh_makefile}" } _gmake_add_flags() { _get_targets_toolkinds; local kinds="${_ret}" for target in ${_xmake_sh_targets}; do for kind in ${kinds}; do _get_target_flags "${target}" "${kind}"; local flags="${_ret}" _get_flagname "${kind}"; local flagname="${_ret}" local key="${target}_${flagname}" echo "${key}=${flags}" >> "${xmake_sh_makefile}" done echo "" >> "${xmake_sh_makefile}" done } _gmake_add_toolchains() { _get_targets_toolkinds; local kinds="${_ret}" for kind in ${kinds}; do _get_toolchain_toolset "${_target_toolchain}" "${kind}"; local program="${_ret}" local key="${kind}" echo "${key}=${program}" >> "${xmake_sh_makefile}" done echo "" >> "${xmake_sh_makefile}" } _gmake_add_build_object_for_gcc_clang() { local kind="${1}" local sourcefile="${2}" local objectfile="${3}" local flagname="${4}" path_directory "${objectfile}"; local objectdir="${_ret}" print "\t@mkdir -p ${objectdir}" >> "${xmake_sh_makefile}" print "\t\$(VV)\$(${kind}) -c \$(${flagname}) -o ${objectfile} ${sourcefile}" >> "${xmake_sh_makefile}" } _gmake_add_build_object() { local target=${1} local sourcefile="${2}" local objectfile="${3}" path_sourcekind "${sourcefile}"; local sourcekind="${_ret}" _get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" _get_flagname "${sourcekind}"; local flagname="${_ret}" flagname="${target}_${flagname}" echo "${objectfile}: ${sourcefile}" >> "${xmake_sh_makefile}" print "\t@echo compiling.${_target_mode} ${sourcefile}" >> "${xmake_sh_makefile}" case "${toolname}" in gcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; gxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; clang) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; clangxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; emcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; emxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; cosmocc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; cosmocxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; tcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; *) raise "unknown toolname(${toolname})!" ;; esac echo "" >> "${xmake_sh_makefile}" } _gmake_add_build_objects() { local target=${1} _get_target_sourcefiles "${target}"; local sourcefiles="${_ret}" for sourcefile in ${sourcefiles}; do _get_target_objectfile "${target}" "${sourcefile}"; local objectfile="${_ret}" _gmake_add_build_object "${target}" "${sourcefile}" "${objectfile}" done } _gmake_add_build_target_for_gcc_clang() { local kind="${1}" local targetfile="${2}" local objectfiles="${3}" local flagname="${4}" path_directory "${targetfile}"; local targetdir="${_ret}" print "\t@mkdir -p ${targetdir}" >> "${xmake_sh_makefile}" print "\t\$(VV)\$(${kind}) -o ${targetfile} ${objectfiles} \$(${flagname})" >> "${xmake_sh_makefile}" } _gmake_add_build_target_for_ar() { local kind="${1}" local targetfile="${2}" local objectfiles="${3}" local flagname="${4}" path_directory "${targetfile}"; local targetdir="${_ret}" print "\t@mkdir -p ${targetdir}" >> "${xmake_sh_makefile}" print "\t\$(VV)\$(${kind}) \$(${flagname}) ${flags} ${targetfile} ${objectfiles}" >> "${xmake_sh_makefile}" } _gmake_add_build_target() { local target=${1} _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_file "${target}"; local targetfile="${_ret}" _get_target_item "${target}" "deps"; local deps="${_ret}" _get_target_objectfiles "${target}"; local objectfiles="${_ret}" # get linker _get_target_item "${target}" "kind"; local targetkind="${_ret}" local toolkind="" case "${targetkind}" in binary) toolkind="ld";; static) toolkind="ar";; shared) toolkind="sh";; *) raise "unknown targetkind(${targetkind})!" ;; esac _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" # get linker flags _get_flagname "${toolkind}"; local flagname="${_ret}" flagname="${target}_${flagname}" # get depfiles local dep="" local depfiles="" for dep in ${deps}; do _get_target_file "${dep}"; local depfile="${_ret}" if test_nz "${depfiles}"; then depfiles="${depfiles} ${depfile}" else depfiles="${depfile}" fi done # link target echo "${target}: ${targetfile}" >> "${xmake_sh_makefile}" echo "${targetfile}: ${depfiles}${objectfiles}" >> "${xmake_sh_makefile}" if test_eq "${targetkind}" "static"; then print "\t@echo archiving.${_target_mode} ${targetfile}" >> "${xmake_sh_makefile}" else print "\t@echo linking.${_target_mode} ${targetfile}" >> "${xmake_sh_makefile}" fi case "${toolname}" in gcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; gxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; clang) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; clangxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; emcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; emxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; cosmocc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; cosmocxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; tcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; ar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; emar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; cosmoar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; *) raise "unknown toolname(${toolname})!" ;; esac # @see https://github.com/tboox/tbox/issues/214 if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; local version="${_ret}" _get_target_soname "${target}"; local soname="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then _get_target_filename "${target}"; local filename="${_ret}" _get_target_extension "${target}"; local extension="${_ret}" local targetfile_with_version="${targetdir}/${filename}.${version}" if test_eq "${extension}" ".dylib"; then path_basename "${filename}"; local basename="${_ret}" targetfile_with_version="${targetdir}/${basename}.${version}${extension}" fi local targetfile_with_soname="${targetdir}/${soname}" path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}" if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version}"; then print "\t@cp -p ${targetfile} ${targetfile_with_version}" >> "${xmake_sh_makefile}" print "\t@cd ${targetdir} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}" >> "${xmake_sh_makefile}" fi fi fi # end echo "" >> "${xmake_sh_makefile}" # build objects _gmake_add_build_objects "${target}" } _gmake_add_build_targets() { local target="" local defaults="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then defaults="${defaults} ${target}" fi done echo "default:${defaults}" >> "${xmake_sh_makefile}" echo "all:${_xmake_sh_targets}" >> "${xmake_sh_makefile}" echo ".PHONY: default all" >> "${xmake_sh_makefile}" echo "" >> "${xmake_sh_makefile}" for target in ${_xmake_sh_targets}; do _gmake_add_build_target "${target}" done } _gmake_add_build() { _gmake_add_build_targets } _gmake_add_run_target() { local target=${1} _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_file "${target}"; local targetfile="${_ret}" if is_plat "macosx"; then print "\t@DYLD_LIBRARY_PATH=${targetdir} ${targetfile}" >> "${xmake_sh_makefile}" elif is_plat "linux" "bsd"; then print "\t@LD_LIBRARY_PATH=${targetdir} ${targetfile}" >> "${xmake_sh_makefile}" else print "\t@${targetfile}" >> "${xmake_sh_makefile}" fi } _gmake_add_run_targets() { local target="" local targets="" for target in ${_xmake_sh_targets}; do _get_target_item "${target}" "kind"; local kind="${_ret}" if test "x${kind}" = "xbinary"; then if _is_target_default "${target}"; then targets="${targets} ${target}" fi fi done echo "run:${targets}" >> "${xmake_sh_makefile}" for target in ${targets}; do _gmake_add_run_target "${target}" done echo "" >> "${xmake_sh_makefile}" } _gmake_add_run() { _gmake_add_run_targets } _gmake_add_clean_target() { local target=${1} local objectfile="" _get_target_file "${target}"; local targetfile="${_ret}" _get_target_objectfiles "${target}"; local objectfiles="${_ret}" print "\t@rm ${targetfile}" >> "${xmake_sh_makefile}" for objectfile in ${objectfiles}; do print "\t@rm ${objectfile}" >> "${xmake_sh_makefile}" done # @see https://github.com/tboox/tbox/issues/214 _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_item "${target}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; local version="${_ret}" _get_target_soname "${target}"; local soname="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then _get_target_filename "${target}"; local filename="${_ret}" _get_target_extension "${target}"; local extension="${_ret}" local targetfile_with_version="${targetdir}/${filename}.${version}" if test_eq "${extension}" ".dylib"; then path_basename "${filename}"; local basename="${_ret}" targetfile_with_version="${targetdir}/${basename}.${version}${extension}" fi local targetfile_with_soname="${targetdir}/${soname}" print "\t@if test -f ${targetfile_with_soname}; then rm ${targetfile_with_soname}; fi" >> "${xmake_sh_makefile}" print "\t@if test -f ${targetfile_with_version}; then rm ${targetfile_with_version}; fi" >> "${xmake_sh_makefile}" fi fi } _gmake_add_clean_targets() { local target="" local targets="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then targets="${targets} ${target}" fi done echo "clean:${targets}" >> "${xmake_sh_makefile}" for target in ${targets}; do _gmake_add_clean_target "${target}" done echo "" >> "${xmake_sh_makefile}" } _gmake_add_clean() { _gmake_add_clean_targets } _gmake_add_install_target() { local target=${1} _get_target_file "${target}"; local targetfile="${_ret}" path_filename "${targetfile}"; local filename="${_ret}" _get_target_item "${target}" "installdir"; local installdir="${_ret}" _get_target_item "${target}" "kind"; local targetkind="${_ret}" if test_z "${installdir}"; then installdir="\$(INSTALLDIR)" fi # before install _get_target_item "${target}" "before_install"; local before_install="${_ret}" if test_nz "${before_install}"; then eval ${before_install} "\${target}" "\${installdir}" fi # @see https://github.com/tboox/tbox/issues/214 install_for_soname=false if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; local version="${_ret}" _get_target_soname "${target}"; local soname="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then _get_target_extension "${target}"; local extension="${_ret}" string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}" local targetfile_with_version="${_install_libdir_default}/${filename}.${version}" if test_eq "${extension}" ".dylib"; then path_basename "${filename}"; local basename="${_ret}" targetfile_with_version="${_install_libdir_default}/${basename}.${version}${extension}" fi local targetfile_with_soname="${_install_libdir_default}/${soname}" path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}" if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version}"; then install_for_soname=true fi fi fi # install target file if test_eq "${targetkind}" "binary"; then string_replace "${_install_bindir_default}" "\${prefix}" "${installdir}"; _install_bindir_default="${_ret}" print "\t@echo installing ${targetfile} to ${_install_bindir_default}" >> "${xmake_sh_makefile}" print "\t@mkdir -p ${_install_bindir_default}" >> "${xmake_sh_makefile}" print "\t@cp -p ${targetfile} ${_install_bindir_default}/${filename}" >> "${xmake_sh_makefile}" elif ${install_for_soname}; then string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}" print "\t@echo installing ${targetfile} to ${_install_libdir_default}" >> "${xmake_sh_makefile}" print "\t@mkdir -p ${_install_libdir_default}" >> "${xmake_sh_makefile}" print "\t@cp -p ${targetfile} ${targetfile_with_version}" >> "${xmake_sh_makefile}" print "\t@cd ${_install_libdir_default} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}" >> "${xmake_sh_makefile}" elif test_eq "${targetkind}" "static" || test_eq "${targetkind}" "shared"; then string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}" print "\t@echo installing ${targetfile} to ${_install_libdir_default}" >> "${xmake_sh_makefile}" print "\t@mkdir -p ${_install_libdir_default}" >> "${xmake_sh_makefile}" print "\t@cp -p ${targetfile} ${_install_libdir_default}/${filename}" >> "${xmake_sh_makefile}" fi # install header files _get_target_item "${target}" "headerfiles"; local headerfiles="${_ret}" if test_nz "${headerfiles}"; then string_replace "${_install_includedir_default}" "\${prefix}" "${installdir}"; _install_includedir_default="${_ret}" local srcheaderfile="" local includedir="${_install_includedir_default}" for srcheaderfile in ${headerfiles}; do string_split "${srcheaderfile}" ":" local srcheaderfile="${_ret}" local rootdir="${_ret2}" local prefixdir="${_ret3}" local filename="${_ret4}" if test_z "${filename}"; then path_filename "${srcheaderfile}"; filename="${_ret}" fi local dstheaderdir="${includedir}" if test_nz "${prefixdir}"; then dstheaderdir="${dstheaderdir}/${prefixdir}" fi local dstheaderfile="${dstheaderdir}/${filename}" if test_nz "${rootdir}"; then path_relative "${rootdir}" "${srcheaderfile}"; local subfile="${_ret}" dstheaderfile="${dstheaderdir}/${subfile}" fi path_directory "${dstheaderfile}"; dstheaderdir="${_ret}" print "\t@mkdir -p ${dstheaderdir}" >> "${xmake_sh_makefile}" print "\t@cp -p ${srcheaderfile} ${dstheaderfile}" >> "${xmake_sh_makefile}" done fi # install user files _get_target_item "${target}" "installfiles"; local installfiles="${_ret}" if test_nz "${installfiles}"; then local srcinstallfile="" for srcinstallfile in ${installfiles}; do string_split "${srcinstallfile}" ":" local srcinstallfile="${_ret}" local rootdir="${_ret2}" local prefixdir="${_ret3}" local filename="${_ret4}" if test_z "${filename}"; then path_filename "${srcinstallfile}"; filename="${_ret}" fi local dstinstalldir="${installdir}" if test_nz "${prefixdir}"; then dstinstalldir="${dstinstalldir}/${prefixdir}" fi local dstinstallfile="${dstinstalldir}/${filename}" if test_nz "${rootdir}"; then path_relative "${rootdir}" "${srcinstallfile}"; local subfile="${_ret}" dstinstallfile="${dstinstalldir}/${subfile}" fi path_directory "${dstinstallfile}"; dstinstalldir="${_ret}" print "\t@mkdir -p ${dstinstalldir}" >> "${xmake_sh_makefile}" print "\t@cp -p ${srcinstallfile} ${dstinstallfile}" >> "${xmake_sh_makefile}" done fi # after install _get_target_item "${target}" "after_install"; local after_install="${_ret}" if test_nz "${after_install}"; then eval ${after_install} "\${target}" "\${installdir}" fi } _gmake_add_install_targets() { local target="" local targets="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then targets="${targets} ${target}" fi done echo "install:${targets}" >> "${xmake_sh_makefile}" for target in ${targets}; do _gmake_add_install_target "${target}" done echo "" >> "${xmake_sh_makefile}" } _gmake_add_install() { _gmake_add_install_targets } _gmake_done() { echo "makefile is generated!" if "${xmake_sh_diagnosis}"; then cat "${xmake_sh_makefile}" fi } # generate build file for gmake _generate_for_gmake() { _gmake_begin _gmake_add_header _gmake_add_switches _gmake_add_toolchains _gmake_add_flags _gmake_add_build _gmake_add_clean _gmake_add_install _gmake_add_run _gmake_done } #----------------------------------------------------------------------------- # generate ninja file # _ninja_begin() { echo "generating ninja build file .." } _ninja_add_header() { echo "# this is the build file for this project # it is autogenerated by the xmake.sh build system. # do not edit by hand. " > "${xmake_sh_ninjafile}" echo "ninja_required_version = 1.3" >> "${xmake_sh_ninjafile}" echo "builddir = ${xmake_sh_builddir}" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" } _ninja_add_switches() { local value="" value="${_install_prefix_default}"; _ninja_escape "${value}"; value="${_ret}" echo "prefix_default = ${value}" >> "${xmake_sh_ninjafile}" value="${_install_bindir_default}"; _ninja_escape "${value}"; value="${_ret}" echo "bindir_default = ${value}" >> "${xmake_sh_ninjafile}" value="${_install_libdir_default}"; _ninja_escape "${value}"; value="${_ret}" echo "libdir_default = ${value}" >> "${xmake_sh_ninjafile}" value="${_install_includedir_default}"; _ninja_escape "${value}"; value="${_ret}" echo "includedir_default = ${value}" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" } _ninja_add_rules() { echo "rule command" >> "${xmake_sh_ninjafile}" echo " command = \$command" >> "${xmake_sh_ninjafile}" echo " description = \$description" >> "${xmake_sh_ninjafile}" echo " restat = \$restat" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" } _ninja_add_toolchains() { _get_targets_toolkinds; local kinds="${_ret}" if test_nz "${kinds}"; then echo "# toolchain programs" >> "${xmake_sh_ninjafile}" for kind in ${kinds}; do _get_toolchain_toolset "${_target_toolchain}" "${kind}"; local program="${_ret}" echo "${kind} = ${program}" >> "${xmake_sh_ninjafile}" done echo "" >> "${xmake_sh_ninjafile}" fi } _ninja_add_flags() { _get_targets_toolkinds; local kinds="${_ret}" for target in ${_xmake_sh_targets}; do for kind in ${kinds}; do _get_target_flags "${target}" "${kind}"; local flags="${_ret}" if test_nz "${flags}"; then _get_flagname "${kind}"; local flagname="${_ret}" local key="${target}_${flagname}" _ninja_escape "${flags}"; flags="${_ret}" echo "${key} = ${flags}" >> "${xmake_sh_ninjafile}" fi done echo "" >> "${xmake_sh_ninjafile}" done } _ninja_add_build_object() { local target=${1} local sourcefile="${2}" local objectfile="${3}" path_sourcekind "${sourcefile}"; local sourcekind="${_ret}" _get_target_flags "${target}" "${sourcekind}"; local flags="${_ret}" _toolchain_compcmd "${sourcekind}" "${objectfile}" "${sourcefile}" "${flags}"; local compcmd="${_ret}" path_directory "${objectfile}"; local objectdir="${_ret}" local use_shell_wrapper=false local command="mkdir -p \"${objectdir}\" && ${compcmd}" if is_host "msys" "cygwin" "mingw"; then use_shell_wrapper=true fi if ${use_shell_wrapper}; then _shell_escape_single_quotes "${command}"; local command_script="${_ret}" command="sh -lc ${command_script}" fi local description="compiling.${_target_mode} ${sourcefile}" _ninja_escape "${command}"; command="${_ret}" _ninja_escape "${description}"; description="${_ret}" echo "build ${objectfile}: command ${sourcefile}" >> "${xmake_sh_ninjafile}" echo " command = ${command}" >> "${xmake_sh_ninjafile}" echo " description = ${description}" >> "${xmake_sh_ninjafile}" echo " restat = 0" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" } _ninja_add_build_objects() { local target=${1} _get_target_sourcefiles "${target}"; local sourcefiles="${_ret}" for sourcefile in ${sourcefiles}; do _get_target_objectfile "${target}" "${sourcefile}"; local objectfile="${_ret}" _ninja_add_build_object "${target}" "${sourcefile}" "${objectfile}" done } _ninja_add_build_target() { local target=${1} _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_file "${target}"; local targetfile="${_ret}" _get_target_item "${target}" "deps"; local deps="${_ret}" _get_target_objectfiles "${target}"; local objectfiles="${_ret}" _get_target_item "${target}" "kind"; local targetkind="${_ret}" local toolkind="" case "${targetkind}" in binary) toolkind="ld";; static) toolkind="ar";; shared) toolkind="sh";; *) raise "unknown targetkind(${targetkind})!" ;; esac _get_target_flags "${target}" "${toolkind}"; local linkflags="${_ret}" _toolchain_linkcmd "${toolkind}" "${targetfile}" "${objectfiles}" "${linkflags}"; local linkcmd="${_ret}" local use_shell_wrapper=false local command="mkdir -p \"${targetdir}\" && ${linkcmd}" if is_host "msys" "cygwin" "mingw"; then use_shell_wrapper=true fi local description="linking.${_target_mode} ${targetfile}" if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; local version="${_ret}" _get_target_soname "${target}"; local soname="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then _get_target_filename "${target}"; local targetfilename="${_ret}" _get_target_extension "${target}"; local extension="${_ret}" local targetfile_with_version="${targetdir}/${targetfilename}.${version}" if test_eq "${extension}" ".dylib"; then path_basename "${targetfilename}"; local basename="${_ret}" targetfile_with_version="${targetdir}/${basename}.${version}${extension}" fi local targetfile_with_soname="${targetdir}/${soname}" path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}" if test_nq "${soname}" "${targetfilename}" && test_nq "${soname}" "${targetfilename_with_version}"; then command="${command} && cp -p ${targetfile} ${targetfile_with_version} && cd \"${targetdir}\" && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${targetfilename}" fi fi fi if ${use_shell_wrapper}; then _shell_escape_single_quotes "${command}"; local command_script="${_ret}" command="sh -lc ${command_script}" fi _ninja_escape "${command}"; command="${_ret}" _ninja_escape "${description}"; description="${_ret}" local orderdeps="" local dep="" for dep in ${deps}; do _get_target_file "${dep}"; local depfile="${_ret}" if test_nz "${orderdeps}"; then orderdeps="${orderdeps} ${depfile}" else orderdeps="${depfile}" fi done if test_nz "${orderdeps}"; then echo "build ${targetfile}: command ${objectfiles} | ${orderdeps}" >> "${xmake_sh_ninjafile}" else echo "build ${targetfile}: command ${objectfiles}" >> "${xmake_sh_ninjafile}" fi echo " command = ${command}" >> "${xmake_sh_ninjafile}" echo " description = ${description}" >> "${xmake_sh_ninjafile}" echo " restat = 0" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" echo "build ${target}: phony ${targetfile}" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" _ninja_add_build_objects "${target}" } _ninja_add_build_targets() { local target="" local defaults="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then if test_nz "${defaults}"; then defaults="${defaults} ${target}" else defaults="${target}" fi fi done if test_nz "${defaults}"; then echo "build default: phony ${defaults}" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" echo "default default" >> "${xmake_sh_ninjafile}" else echo "default all" >> "${xmake_sh_ninjafile}" fi echo "build all: phony ${_xmake_sh_targets}" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" for target in ${_xmake_sh_targets}; do _ninja_add_build_target "${target}" done } _ninja_add_build() { _ninja_add_build_targets } _ninja_add_run_target() { local target=${1} _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_file "${target}"; local targetfile="${_ret}" local command="" if is_host "msys" "cygwin" "mingw"; then local projectdir="${xmake_sh_projectdir}" local targetfile_rel="./${targetfile}" local targetfile_alt="./build/${targetfile#*/}" local targetbuilddir="${targetfile%/*}" local targetbuilddir_rel="./${targetbuilddir}" local targetbuilddir_alt="./build/${targetbuilddir#*/}" local run_script="cd \"${projectdir}\" && target=\"${targetfile_rel}\"; alt=\"${targetfile_alt}\"; if [ ! -f \"\$target\" ] && [ -f \"\$alt\" ]; then target=\"\$alt\"; fi; if [ ! -f \"\$target\" ]; then echo \"[ninja run] missing ${targetfile_rel} (and fallback ${targetfile_alt})\"; ls -l \"${targetbuilddir_rel}\" || true; ls -l \"${targetbuilddir_alt}\" || true; exit 1; fi; \"\$target\"" _shell_escape_single_quotes "${run_script}"; local run_script_escaped="${_ret}" command="sh -lc ${run_script_escaped}" elif is_plat "macosx"; then command="DYLD_LIBRARY_PATH=${targetdir} ${targetfile}" elif is_plat "linux" "bsd"; then command="LD_LIBRARY_PATH=${targetdir} ${targetfile}" else command="${targetfile}" fi local description="running.${_target_mode} ${targetfile}" _ninja_escape "${command}"; command="${_ret}" _ninja_escape "${description}"; description="${_ret}" echo "build run.${target}: command | ${targetfile}" >> "${xmake_sh_ninjafile}" echo " command = ${command}" >> "${xmake_sh_ninjafile}" echo " description = ${description}" >> "${xmake_sh_ninjafile}" echo " restat = 0" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" } _ninja_add_run_targets() { local target="" local runtargets="" for target in ${_xmake_sh_targets}; do _get_target_item "${target}" "kind"; local kind="${_ret}" if test_eq "${kind}" "binary"; then if _is_target_default "${target}"; then if test_nz "${runtargets}"; then runtargets="${runtargets} run.${target}" else runtargets="run.${target}" fi _ninja_add_run_target "${target}" fi fi done if test_nz "${runtargets}"; then echo "build run: phony ${runtargets}" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" fi } _ninja_add_run() { _ninja_add_run_targets } _ninja_add_clean_target() { local target=${1} _get_target_file "${target}"; local targetfile="${_ret}" _get_target_objectfiles "${target}"; local objectfiles="${_ret}" local removefiles="${targetfile}" local objectfile="" for objectfile in ${objectfiles}; do removefiles="${removefiles} ${objectfile}" done _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_item "${target}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; local version="${_ret}" _get_target_soname "${target}"; local soname="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then _get_target_filename "${target}"; local filename="${_ret}" _get_target_extension "${target}"; local extension="${_ret}" local targetfile_with_version="${targetdir}/${filename}.${version}" if test_eq "${extension}" ".dylib"; then path_basename "${filename}"; local basename="${_ret}" targetfile_with_version="${targetdir}/${basename}.${version}${extension}" fi local targetfile_with_soname="${targetdir}/${soname}" removefiles="${removefiles} ${targetfile_with_soname} ${targetfile_with_version}" fi fi local command="rm -f ${removefiles}" local description="cleaning.${_target_mode} ${target}" _ninja_escape "${command}"; command="${_ret}" _ninja_escape "${description}"; description="${_ret}" echo "build clean.${target}: command" >> "${xmake_sh_ninjafile}" echo " command = ${command}" >> "${xmake_sh_ninjafile}" echo " description = ${description}" >> "${xmake_sh_ninjafile}" echo " restat = 0" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" } _ninja_add_clean_targets() { local target="" local cleantargets="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then if test_nz "${cleantargets}"; then cleantargets="${cleantargets} clean.${target}" else cleantargets="clean.${target}" fi _ninja_add_clean_target "${target}" fi done if test_nz "${cleantargets}"; then echo "build clean: phony ${cleantargets}" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" fi } _ninja_add_clean() { _ninja_add_clean_targets } _ninja_install_prepare_script() { local target="${1}" local ninjadir="${xmake_sh_builddir}/.ninja" local scriptdir="${xmake_sh_projectdir}/${ninjadir}" mkdir -p "${scriptdir}" _ret="${scriptdir}/install_${target}.sh" _ret2="${ninjadir}/install_${target}.sh" } _ninja_install_write_header() { local scriptfile="${1}" local escaped_prefix_default="${2}" local escaped_installdir_template="${3}" local escaped_projectdir="${4}" local escaped_bindir_template="${5}" local escaped_libdir_template="${6}" local escaped_includedir_template="${7}" cat > "${scriptfile}" <> "${scriptfile}" elif ${install_for_soname}; then local version_template="${_install_libdir_default}/${filename}.${version}" if test_eq "${extension}" ".dylib"; then version_template="${_install_libdir_default}/${filename_basename}.${version}${extension}" fi _shell_escape_single_quotes "${targetfile}"; local escaped_targetfile="${_ret}" _shell_escape_single_quotes "${version_template}"; local escaped_version_template="${_ret}" _shell_escape_single_quotes "${soname}"; local escaped_soname="${_ret}" _shell_escape_single_quotes "${filename}"; local escaped_filename="${_ret}" cat >> "${scriptfile}" <> "${scriptfile}" fi } _ninja_install_append_headerfiles() { local scriptfile="${1}" local headerfiles="${2}" if test_nz "${headerfiles}"; then local srcheaderfile="" for srcheaderfile in ${headerfiles}; do string_split "${srcheaderfile}" ":" local srcheaderpath="${_ret}" local rootdir="${_ret2}" local prefixdir="${_ret3}" local headername="${_ret4}" if test_z "${headername}"; then path_filename "${srcheaderpath}"; headername="${_ret}" fi local dstheaderdir_template="${_install_includedir_default}" if test_nz "${prefixdir}"; then dstheaderdir_template="${dstheaderdir_template}/${prefixdir}" fi local dstheaderfile_template="" if test_nz "${rootdir}"; then path_relative "${rootdir}" "${srcheaderpath}"; local subfile="${_ret}" dstheaderfile_template="${dstheaderdir_template}/${subfile}" else dstheaderfile_template="${dstheaderdir_template}/${headername}" fi _shell_escape_single_quotes "${srcheaderpath}"; local escaped_src="${_ret}" _shell_escape_single_quotes "${dstheaderfile_template}"; local escaped_dst="${_ret}" echo "copy_file ${escaped_src} ${escaped_dst}" >> "${scriptfile}" done fi } _ninja_install_append_installfiles() { local scriptfile="${1}" local installdir="${2}" local installfiles="${3}" if test_nz "${installfiles}"; then local srcinstallfile="" for srcinstallfile in ${installfiles}; do string_split "${srcinstallfile}" ":" local srcfilepath="${_ret}" local rootdir="${_ret2}" local prefixdir="${_ret3}" local installname="${_ret4}" if test_z "${installname}"; then path_filename "${srcfilepath}"; installname="${_ret}" fi local dst_template="${installdir}" if test_z "${dst_template}"; then dst_template="\${prefix}" fi if test_nz "${prefixdir}"; then dst_template="${dst_template}/${prefixdir}" fi if test_nz "${rootdir}"; then path_relative "${rootdir}" "${srcfilepath}"; local subfile="${_ret}" dst_template="${dst_template}/${subfile}" else dst_template="${dst_template}/${installname}" fi _shell_escape_single_quotes "${srcfilepath}"; local escaped_src="${_ret}" _shell_escape_single_quotes "${dst_template}"; local escaped_dst="${_ret}" echo "copy_file ${escaped_src} ${escaped_dst}" >> "${scriptfile}" done fi } _ninja_add_install_target() { local target=${1} _get_target_file "${target}"; local targetfile="${_ret}" path_filename "${targetfile}"; local filename="${_ret}" _get_target_item "${target}" "installdir"; local installdir="${_ret}" _get_target_item "${target}" "kind"; local targetkind="${_ret}" local install_for_soname=false local version="" local soname="" local extension="" local filename_basename="" if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; version="${_ret}" _get_target_soname "${target}"; soname="${_ret}" _get_target_extension "${target}"; extension="${_ret}" path_basename "${filename}"; filename_basename="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then local targetfilename_with_version_guess="${filename}.${version}" if test_eq "${extension}" ".dylib"; then targetfilename_with_version_guess="${filename_basename}.${version}${extension}" fi if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version_guess}"; then install_for_soname=true fi fi fi _ninja_install_prepare_script "${target}" local scriptfile="${_ret}" local scriptfile_rel="${_ret2}" _shell_escape_single_quotes "${_install_prefix_default}"; local escaped_prefix_default="${_ret}" _shell_escape_single_quotes "${installdir}"; local escaped_installdir_template="${_ret}" _shell_escape_single_quotes "${xmake_sh_projectdir}"; local escaped_projectdir="${_ret}" _shell_escape_single_quotes "${_install_bindir_default}"; local escaped_bindir_template="${_ret}" _shell_escape_single_quotes "${_install_libdir_default}"; local escaped_libdir_template="${_ret}" _shell_escape_single_quotes "${_install_includedir_default}"; local escaped_includedir_template="${_ret}" _ninja_install_write_header "${scriptfile}" \ "${escaped_prefix_default}" \ "${escaped_installdir_template}" \ "${escaped_projectdir}" \ "${escaped_bindir_template}" \ "${escaped_libdir_template}" \ "${escaped_includedir_template}" _ninja_install_append_target_artifacts "${scriptfile}" "${targetkind}" "${install_for_soname}" \ "${targetfile}" "${filename}" "${version}" "${soname}" "${extension}" "${filename_basename}" _get_target_item "${target}" "headerfiles"; local headerfiles="${_ret}" _ninja_install_append_headerfiles "${scriptfile}" "${headerfiles}" _get_target_item "${target}" "installfiles"; local installfiles="${_ret}" _ninja_install_append_installfiles "${scriptfile}" "${installdir}" "${installfiles}" echo "" >> "${scriptfile}" chmod +x "${scriptfile}" local command="sh ${scriptfile_rel}" local description="installing.${_target_mode} ${target}" _ninja_escape "${command}"; command="${_ret}" _ninja_escape "${description}"; description="${_ret}" echo "build install.${target}: command | ${targetfile}" >> "${xmake_sh_ninjafile}" echo " command = ${command}" >> "${xmake_sh_ninjafile}" echo " description = ${description}" >> "${xmake_sh_ninjafile}" echo " restat = 0" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" } _ninja_add_install_targets() { local target="" local installtargets="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then if test_nz "${installtargets}"; then installtargets="${installtargets} install.${target}" else installtargets="install.${target}" fi _ninja_add_install_target "${target}" fi done if test_nz "${installtargets}"; then echo "build install: phony ${installtargets}" >> "${xmake_sh_ninjafile}" echo "" >> "${xmake_sh_ninjafile}" fi } _ninja_add_install() { _ninja_add_install_targets } _ninja_done() { echo "ninja build file is generated!" if "${xmake_sh_diagnosis}"; then cat "${xmake_sh_ninjafile}" fi } # generate build file for ninja _generate_for_ninja() { _ninja_begin _ninja_add_header _ninja_add_switches _ninja_add_toolchains _ninja_add_flags _ninja_add_rules _ninja_add_build _ninja_add_clean _ninja_add_install _ninja_add_run _ninja_done } #----------------------------------------------------------------------------- # generate build file # _generate_build_file() { if test_eq "${project_generator}" "gmake"; then _generate_for_gmake elif test_eq "${project_generator}" "ninja"; then _generate_for_ninja else raise "unknown generator: ${project_generator}" fi } _generate_build_file ================================================ FILE: core/src/cli/xmake.c ================================================ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "xmake/xmake.h" /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t main(tb_int_t argc, tb_char_t** argv) { return xm_engine_run("xmake", argc, argv, tb_null, tb_null); } ================================================ FILE: core/src/cli/xmake.lua ================================================ target("cli") -- disable this target if only build libaries if has_config("onlylib") then set_default(false) end -- add deps add_deps("xmake") -- make as a binary set_kind("binary") set_basename("xmake") set_targetdir("$(builddir)") -- add definitions add_defines("__tb_prefix__=\"xmake\"") -- add includes directory add_includedirs("$(projectdir)", "$(projectdir)/src") -- add common source files add_files("**.c") -- add resource files (it will be enabled after publishing new version) if is_plat("windows") then add_files("*.rc") end -- add links if is_plat("windows") then add_syslinks("ws2_32", "advapi32", "shell32", "wintrust", "crypt32") add_ldflags("/export:malloc", "/export:free", "/export:memmove") elseif is_plat("android") then add_syslinks("m", "c") elseif is_plat("macosx") and is_config("runtime", "luajit") then add_ldflags("-all_load", "-pagezero_size 10000", "-image_base 100000000") elseif is_plat("mingw") then add_ldflags("-static-libgcc", {force = true}) elseif is_plat("haiku") then add_syslinks("pthread", "network", "m", "c") else add_syslinks("pthread", "dl", "m", "c") end -- enable xp compatibility mode if is_plat("windows") then if is_arch("x86") then add_ldflags("/subsystem:console,5.01") else add_ldflags("/subsystem:console,5.02") end end -- add install files if is_plat("windows") then add_installfiles("$(projectdir)/../LICENSE.md") add_installfiles("$(projectdir)/../NOTICE.md") add_installfiles("$(projectdir)/../xmake/(**.lua)") add_installfiles("$(projectdir)/../xmake/(scripts/**)") add_installfiles("$(projectdir)/../xmake/(repository/templates/**)") add_installfiles("$(projectdir)/../scripts/xrepo.bat") add_installfiles("$(projectdir)/../scripts/xrepo.ps1") set_prefixdir("/", {bindir = "/"}) after_install(function (target) os.cp(path.join(os.programdir(), "winenv"), target:installdir()) end) else add_installfiles("$(projectdir)/../(xmake/**.lua)", {prefixdir = "share"}) add_installfiles("$(projectdir)/../(xmake/scripts/**)", {prefixdir = "share"}) add_installfiles("$(projectdir)/../(xmake/repository/templates/**)", {prefixdir = "share"}) add_installfiles("$(projectdir)/../scripts/xrepo.sh", {prefixdir = "bin", filename = "xrepo"}) end before_installcmd(function (target, batchcmds, opt) -- we need to avoid some old files interfering with xmake's module import. local package = opt.package if target:is_plat("windows") then batchcmds:rmdir(package:installdir("actions")) batchcmds:rmdir(package:installdir("core")) batchcmds:rmdir(package:installdir("includes")) batchcmds:rmdir(package:installdir("languages")) batchcmds:rmdir(package:installdir("modules")) batchcmds:rmdir(package:installdir("platforms")) batchcmds:rmdir(package:installdir("plugins")) batchcmds:rmdir(package:installdir("repository")) batchcmds:rmdir(package:installdir("rules")) batchcmds:rmdir(package:installdir("templates")) batchcmds:rmdir(package:installdir("scripts")) batchcmds:rmdir(package:installdir("themes")) batchcmds:rmdir(package:installdir("toolchains")) end end) ================================================ FILE: core/src/cli/xmake.rc ================================================ #include "xmake.config.h" #include "winres.h" #define _STR(x) #x #define STR(x) _STR(x) VS_VERSION_INFO VERSIONINFO FILEVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0 PRODUCTVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "000004B0" BEGIN VALUE "Comments", "A cross-platform build utility based on Lua\nwebsite: https://xmake.io" VALUE "CompanyName", "The Xmake Open Source Community" VALUE "FileDescription", "XMake build utility" VALUE "FileVersion", XM_CONFIG_VERSION "+" STR(XM_CONFIG_VERSION_BUILD) VALUE "InternalName", "xmake" VALUE "LegalCopyright", "Copyright (C) 2015-present Ruki Wang, https://xmake.io" VALUE "LegalTrademarks", "" VALUE "OriginalFilename", "xmake.exe" VALUE "ProductName", "XMake" VALUE "ProductVersion", XM_CONFIG_VERSION "+" STR(XM_CONFIG_VERSION_BUILD) END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0, 1200 END END IDI_APP ICON DISCARDABLE "xmake.ico" ================================================ FILE: core/src/cli/xmake.sh ================================================ #!/bin/sh target "cli" add_deps "xmake" set_kind "binary" set_basename "xmake" set_targetdir "${builddir}" # add definitions add_defines "__tb_prefix__=\"xmake\"" # add includes directory add_includedirs "${projectdir}/core" "${projectdir}/core/src" # add the common source files add_files "**.c" # add links if is_plat "macosx" && is_config "runtime" "luajit"; then add_ldflags "-all_load" "-pagezero_size 10000" "-image_base 100000000" elif is_plat "mingw"; then add_ldflags "-static-libgcc" "-lwintrust" "-lcrypt32" fi # add install files add_installfiles "${projectdir}/(xmake/**.lua)" "share" add_installfiles "${projectdir}/(xmake/scripts/*)" "share" add_installfiles "${projectdir}/(xmake/scripts/cmake_importfiles/**)" "share" add_installfiles "${projectdir}/(xmake/scripts/completions/**)" "share" add_installfiles "${projectdir}/(xmake/scripts/xpack/**)" "share" add_installfiles "${projectdir}/(xmake/scripts/xrepo/**)" "share" add_installfiles "${projectdir}/(xmake/scripts/virtualenvs/**)" "share" add_installfiles "${projectdir}/(xmake/scripts/conan/**)" "share" add_installfiles "${projectdir}/(xmake/scripts/module/**)" "share" add_installfiles "${projectdir}/(xmake/repository/templates/**)" "share" add_installfiles "${projectdir}/scripts/xrepo.sh" "bin" "xrepo" # fix os.exec() call incorrect program from /mingw64/bin. e.g. python, .. # # because xmake is installed to /mingw64/bin/xmake, # os.exec/CreateProcess always gives the highest priority to finding the process from /mingw64/bin (if it exists), # rather than from the $PATH environment variable. # # we install the xmake executable into a separate directory to ensure # that os.exec() does not look for additional executables. # # @see https://github.com/xmake-io/xmake/issues/3628 if is_host "msys"; then after_install "xmake_after_install" fi # add syslinks add_options "atomic" if is_plat "mingw" "msys" "cygwin"; then add_syslinks "ws2_32" "pthread" "m" elif is_plat "bsd" "solaris"; then add_syslinks "pthread" "m" elif is_plat "haiku"; then add_syslinks "pthread" "network" "m" elif test_nz "${TERMUX_ARCH}"; then add_syslinks "m" "dl" else add_syslinks "pthread" "dl" "m" "c" fi xmake_after_install() { local target=${1} local installdir=${2} if test_eq "${project_generator}" "gmake"; then print "\t@if test -f ${installdir}/bin/xmake.exe; then rm ${installdir}/bin/xmake.exe; fi" >> "${xmake_sh_makefile}" print "\t@cp ${projectdir}/scripts/msys/xmake.sh ${installdir}/bin/xmake" >> "${xmake_sh_makefile}" print "\t@cp ${projectdir}/scripts/msys/xmake.cmd ${installdir}/bin/xmake.cmd" >> "${xmake_sh_makefile}" print "\t@cp ${projectdir}/scripts/msys/xmake.ps1 ${installdir}/bin/xmake.ps1" >> "${xmake_sh_makefile}" print "\t@cp ${builddir}/xmake.exe ${installdir}/share/xmake" >> "${xmake_sh_makefile}" fi } ================================================ FILE: core/src/lua/xmake.lua ================================================ target("lua") set_kind("static") set_warnings("all") -- disable c99(/TP) for windows if is_plat("windows") then set_languages("c89") end -- add header files add_headerfiles("lua/(*.h)", {prefixdir = "lua"}) -- add include directories add_includedirs("lua", {public = true}) -- add the common source files add_files("lua/*.c|lua.c|onelua.c|loslib.c") if not is_plat("iphoneos") then add_files("lua/loslib.c") end -- add definitions add_defines("LUA_COMPAT_5_1", "LUA_COMPAT_5_2", "LUA_COMPAT_5_3", {public = true}) if is_plat("windows", "mingw") then -- it has been defined in luaconf.h --add_defines("LUA_USE_WINDOWS") elseif is_plat("macosx", "iphoneos") then add_defines("LUA_USE_MACOSX") else add_defines("LUA_USE_LINUX") end -- we just disable os.execute for ios, because os.execv do not use it -- @see https://github.com/xmake-io/xmake/issues/2187 on_load("iphoneos", function (target) local loslib_file = target:autogenfile("loslib.c") os.cp(path.join(os.scriptdir(), "lua", "loslib.c"), loslib_file) io.replace(loslib_file, "system(cmd)", "0", {plain = true}) target:add("files", loslib_file) end) ================================================ FILE: core/src/lua/xmake.sh ================================================ #!/bin/sh target "lua" set_kind "static" set_default false set_warnings "all" # add include directories add_includedirs "lua" "{public}" # add the common source files add_files "lua/lapi.c" add_files "lua/lauxlib.c" add_files "lua/lbaselib.c" add_files "lua/lcode.c" add_files "lua/lcorolib.c" add_files "lua/lctype.c" add_files "lua/ldblib.c" add_files "lua/ldebug.c" add_files "lua/ldo.c" add_files "lua/ldump.c" add_files "lua/lfunc.c" add_files "lua/lgc.c" add_files "lua/linit.c" add_files "lua/liolib.c" add_files "lua/llex.c" add_files "lua/lmathlib.c" add_files "lua/lmem.c" add_files "lua/loadlib.c" add_files "lua/lobject.c" add_files "lua/lopcodes.c" add_files "lua/loslib.c" add_files "lua/lparser.c" add_files "lua/lstate.c" add_files "lua/lstring.c" add_files "lua/lstrlib.c" add_files "lua/ltable.c" add_files "lua/ltablib.c" add_files "lua/ltm.c" add_files "lua/lundump.c" add_files "lua/lutf8lib.c" add_files "lua/lvm.c" add_files "lua/lzio.c" # add definitions add_defines "LUA_COMPAT_5_1" "LUA_COMPAT_5_2" "LUA_COMPAT_5_3" "{public}" if is_plat "mingw"; then true # it has been defined in luaconf.h #add_defines "LUA_USE_WINDOWS" elif is_plat "macosx"; then add_defines "LUA_USE_MACOSX" else add_defines "LUA_USE_LINUX" fi ================================================ FILE: core/src/lua-cjson/xmake.lua ================================================ target("lua-cjson") set_kind("static") set_warnings("all") if is_config("runtime", "luajit") then add_deps("luajit") else add_deps("lua") end if is_plat("windows") then set_languages("c89") end add_files("lua-cjson/*.c|fpconv.c") -- Use internal strtod() / g_fmt() code for performance and disable multi-thread add_defines("NDEBUG", "USE_INTERNAL_FPCONV") add_defines("XM_CONFIG_API_HAVE_LUA_CJSON", {public = true}) if is_plat("windows") then add_defines("inline=__inline") end ================================================ FILE: core/src/lua-cjson/xmake.sh ================================================ #!/bin/sh target "lua_cjson" set_kind "static" set_default false set_warnings "all" if has_config "external"; then if is_config "runtime" "luajit"; then if has_config "luajit"; then add_options "luajit" "{public}" fi else if has_config "lua"; then add_options "lua" "{public}" fi fi else if is_config "runtime" "luajit"; then add_deps "luajit" else add_deps "lua" fi fi add_files "lua-cjson/dtoa.c" add_files "lua-cjson/lua_cjson.c" add_files "lua-cjson/strbuf.c" add_files "lua-cjson/g_fmt.c" # Use internal strtod() / g_fmt() code for performance and disable multi-thread add_defines "NDEBUG" "USE_INTERNAL_FPCONV" add_defines "XM_CONFIG_API_HAVE_LUA_CJSON" "{public}" ================================================ FILE: core/src/luajit/xmake.lua ================================================ -- disable jit compiler for redhat and centos local jit = true local plat = "$(plat)" local arch = "$(arch)" if is_plat("msys", "mingw", "cygwin") then plat = "windows" arch = is_arch("x86_64") and "x64" or "x86" elseif is_plat("android") then plat = "linux" end if is_arch("arm64", "arm64-v8a") then arch = "arm64" elseif is_arch("arm.*") then arch = "arm" elseif is_arch("mips64.*") then arch = "mips64" jit = false end if os.isfile("/etc/redhat-release") then jit = false end local autogendir = path.join("luajit", "autogen", plat, jit and "jit" or "nojit", arch) -- add target target("luajit") -- make as a static library set_kind("static") -- set warning all and disable error set_warnings("all") -- disable c99(/TP) for windows if is_plat("windows") then set_languages("c89") end -- add header files add_headerfiles("luajit/src/(*.h)", {prefixdir = "luajit"}) -- add include directories add_includedirs(autogendir) add_includedirs("luajit/src", {public = true}) -- add the common source files add_files("luajit/src/*.c|ljamalg.c|luajit.c") if is_plat("windows") then add_files(autogendir .. "/lj_vm.obj") elseif is_plat("msys", "cygwin", "mingw") then add_files(autogendir .. "/lj_vm.o") else add_files(autogendir .. "/*.S") end add_defines("USE_LUAJIT", {interface = true}) -- disable jit compiler? if not jit then add_defines("LUAJIT_DISABLE_JIT") end -- using internal memory management under armv7, gc will cause a crash when free strings in lua_close() if arch == "arm" then add_defines("LUAJIT_USE_SYSMALLOC") end -- fix call math.sin/log crash for fedora/i386/lj_vm.S with `LDFLAGS = -specs=/usr/lib/rpm/redhat/redhat-hardened-ld` in xmake.spec/%set_build_flags if is_plat("linux") and is_arch("i386") then add_asflags("-fPIE") add_ldflags("-fPIE") end -- enable lua5.2 compat, @see http://luajit.org/extensions.html --[[ add_defines("LUAJIT_ENABLE_LUA52COMPAT") if not is_plat("windows") then add_cflags("-Wno-error=unused-function") end]] ================================================ FILE: core/src/luajit/xmake.sh ================================================ #!/bin/sh # disable jit compiler for redhat and centos jit=true jit_plat="${plat}" jit_arch="${arch}" if is_plat "mingw"; then jit_plat="windows" if is_arch "x86_64"; then jit_arch="x64" else jit_arch="x86" fi fi if is_arch "arm64" "arm64-v8a"; then jit_arch="arm64" elif is_arch "arm" "armv7"; then jit_arch="arm" elif is_arch "mips64"; then jit_arch="mips64" jit=false fi if test -f "/etc/redhat-release"; then jit=false fi if $jit; then jit_dir="jit" else jit_dir="nojit" fi jit_autogendir="luajit/autogen/${jit_plat}/${jit_dir}/${jit_arch}" target "luajit" set_kind "static" set_default false set_warnings "all" # add include directories add_includedirs "${jit_autogendir}" add_includedirs "luajit/src" "{public}" # add the common source files add_files "luajit/src/lj_*.c" add_files "luajit/src/lib_*.c" if is_plat "mingw"; then add_files "${jit_autogendir}/lj_vm.o" else add_files "${jit_autogendir}/*.S" fi add_defines "USE_LUAJIT" "{public}" # disable jit compiler? if ! $jit; then add_defines "LUAJIT_DISABLE_JIT" fi # using internal memory management under armv7 gc will cause a crash when free strings in lua_close if test_eq "${jit_arch}" "arm"; then add_defines "LUAJIT_USE_SYSMALLOC" fi # fix call math.sin/log crash for fedora/i386/lj_vm.S with `LDFLAGS = -specs=/usr/lib/rpm/redhat/redhat-hardened-ld` in xmake.spec/%set_build_flags if is_plat "linux" && is_arch "i386"; then add_asflags "-fPIE" add_ldflags "-fPIE" fi ================================================ FILE: core/src/lz4/xmake.lua ================================================ target("lz4") set_kind("static") set_warnings("all") -- disable c99(/TP) for windows if is_plat("windows") then set_languages("c89") end -- add header files add_headerfiles("lz4/lib/(*.h)") -- add include directories add_includedirs("lz4/lib", {public = true}) -- add the common source files add_files("lz4/lib/*.c|lz4file.c") -- add definitions add_defines("XXH_NAMESPACE=LZ4_") ================================================ FILE: core/src/lz4/xmake.sh ================================================ #!/bin/sh target "lz4" set_kind "static" set_default false set_warnings "all" add_includedirs "lz4/lib" "{public}" add_files "lz4/lib/lz4.c" add_files "lz4/lib/lz4frame.c" add_files "lz4/lib/lz4hc.c" add_files "lz4/lib/xxhash.c" add_defines "XXH_NAMESPACE=LZ4_" ================================================ FILE: core/src/pdcurses/xmake.lua ================================================ -- add target target("pdcurses") -- enable this target if not has_config("pdcurses") then set_default(false) end -- make as a static library set_kind("static") -- add includes directory add_includedirs("pdcurses", {public = true}) -- add the common source files add_files("pdcurses/pdcurses/*.c", "pdcurses/wincon/*.c") -- add definitions add_defines("PDC_WIDE") -- set languages set_languages("c89") -- unset warnings set_warnings("none") ================================================ FILE: core/src/sv/.gitignore ================================================ # Created by .ignore support plugin (hsz.mobi) ### Autotools template # http://www.gnu.org/software/automake Makefile.in /ar-lib /mdate-sh /py-compile /test-driver /ylwrap # http://www.gnu.org/software/autoconf /autom4te.cache /autoscan.log /autoscan-*.log /aclocal.m4 /compile /config.guess /config.h.in /config.sub /configure /configure.scan /depcomp /install-sh /missing /stamp-h1 # https://www.gnu.org/software/libtool/ /ltmain.sh # http://www.gnu.org/software/texinfo /texinfo.tex ### CMake template CMakeCache.txt CMakeFiles CMakeScripts Testing Makefile cmake_install.cmake install_manifest.txt compile_commands.json CTestTestfile.cmake ### C template # Prerequisites *.d # Object files *.o *.ko *.obj *.elf # Linker output *.ilk *.map *.exp # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # Debug files *.dSYM/ *.su *.idb *.pdb # Kernel Module Compile Results *.mod* *.cmd modules.order Module.symvers Mkfile.old dkms.conf ### JetBrains template # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff: .idea/**/workspace.xml .idea/**/tasks.xml .idea/dictionaries # Sensitive or high-churn files: .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.xml .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml # Gradle: .idea/**/gradle.xml .idea/**/libraries # Mongo Explorer plugin: .idea/**/mongoSettings.xml ## File-based project format: *.iws ## Plugin-specific files: # IntelliJ /out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Clion .idea/ cmake-build-debug/ # xmake .xmake/ build/ ================================================ FILE: core/src/sv/.travis.yml ================================================ sudo: false language: c before_install: - bash <(curl -s https://raw.githubusercontent.com/xmake-io/xmake/master/scripts/get.sh) install: - xmake - cd build - cmake .. - make all script: - ctest --verbose - cd .. && xmake check matrix: include: - os: linux - os: linux compiler: gcc-4.9 addons: apt: sources: - ubuntu-toolchain-r-test packages: - gcc-4.9 - os: linux compiler: gcc-5 addons: apt: sources: - ubuntu-toolchain-r-test packages: - gcc-5 - os: linux compiler: gcc-6 addons: apt: sources: - ubuntu-toolchain-r-test packages: - gcc-6 - os: linux compiler: clang-3.5 addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.5 packages: - clang-3.5 - os: linux compiler: clang-3.6 addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.6 packages: - clang-3.6 - os: linux compiler: clang-3.7 addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.7 packages: - clang-3.7 - os: linux compiler: clang-3.8 addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.8 packages: - clang-3.8 - os: linux compiler: clang-3.9 addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.9 packages: - clang-3.9 - os: linux dist: trusty compiler: clang-4.0 addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-4.0 packages: - clang-4.0 - os: osx osx_image: xcode6.4 compiler: clang - os: osx osx_image: xcode7.3 compiler: clang - os: osx osx_image: xcode8.3 compiler: clang ================================================ FILE: core/src/sv/xmake.lua ================================================ includes("sv") ================================================ FILE: core/src/sv/xmake.sh ================================================ #!/bin/sh target "sv" set_kind "static" set_default false set_languages "c99" add_includedirs "sv/include" "{public}" add_files "sv/src/*.c" ================================================ FILE: core/src/tbox/inc/bsd/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 3 #define TB_CONFIG_VERSION_BUILD 20230119 // defines #define TB_CONFIG_OS_BSD 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /* #undef TB_CONFIG_MICRO_ENABLE */ /* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 /* #undef TB_CONFIG_API_HAVE_DEPRECATED */ /* #undef TB_CONFIG_EXCEPTION_ENABLE */ // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // features #define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ /* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ /* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ /* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 #define TB_CONFIG_LIBC_HAVE_MEMMEM 1 #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 #define TB_CONFIG_LIBC_HAVE_STRLCPY 1 #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 #define TB_CONFIG_LIBC_HAVE_STRCASESTR 1 #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSLCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSNLEN */ #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */ /* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 #define TB_CONFIG_LIBC_HAVE_SETJMP 1 #define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1 #define TB_CONFIG_LIBC_HAVE_KILL 1 #define TB_CONFIG_LIBC_HAVE_BACKTRACE 1 #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 #define TB_CONFIG_LIBC_HAVE_SRANDOM 1 #define TB_CONFIG_LIBC_HAVE_RANDOM 1 // libm functions #define TB_CONFIG_LIBM_HAVE_SINCOS 1 #define TB_CONFIG_LIBM_HAVE_SINCOSF 1 #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_SELECT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 /* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */ #define TB_CONFIG_POSIX_HAVE_SOCKET 1 #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 #define TB_CONFIG_POSIX_HAVE_DLOPEN 1 #define TB_CONFIG_POSIX_HAVE_OPEN 1 /* #undef TB_CONFIG_POSIX_HAVE_STAT64 */ #define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1 #define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1 #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 #define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1 #define TB_CONFIG_POSIX_HAVE_SYSCONF 1 #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 /* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */ #define TB_CONFIG_POSIX_HAVE_REGCOMP 1 #define TB_CONFIG_POSIX_HAVE_REGEXEC 1 #define TB_CONFIG_POSIX_HAVE_READV 1 #define TB_CONFIG_POSIX_HAVE_WRITEV 1 #define TB_CONFIG_POSIX_HAVE_PREADV 1 #define TB_CONFIG_POSIX_HAVE_PWRITEV 1 /* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */ #define TB_CONFIG_POSIX_HAVE_FDATASYNC 1 /* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */ /* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #define TB_CONFIG_POSIX_HAVE_EXECVP 1 /* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */ #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 #define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1 #define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1 #define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1 #define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1 #define TB_CONFIG_POSIX_HAVE_FCNTL 1 #define TB_CONFIG_POSIX_HAVE_PIPE 1 #define TB_CONFIG_POSIX_HAVE_PIPE2 1 #define TB_CONFIG_POSIX_HAVE_MKFIFO 1 #define TB_CONFIG_POSIX_HAVE_MMAP 1 #define TB_CONFIG_POSIX_HAVE_FUTIMENS 1 #define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1 // windows functions /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */ // bsd functions #define TB_CONFIG_BSD_HAVE_FLOCK 1 // systemv functions #define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1 /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */ // valgrind functions /* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ #endif ================================================ FILE: core/src/tbox/inc/cygwin/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 3 #define TB_CONFIG_VERSION_BUILD 20230119 // defines #define TB_CONFIG_OS_WINDOWS 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /* #undef TB_CONFIG_MICRO_ENABLE */ /* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 /* #undef TB_CONFIG_API_HAVE_DEPRECATED */ /* #undef TB_CONFIG_EXCEPTION_ENABLE */ // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // features #define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ /* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ /* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ /* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */ #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 /* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */ #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */ #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 /* #undef TB_CONFIG_LIBC_HAVE_STRUPR */ /* #undef TB_CONFIG_LIBC_HAVE_STRLWR */ #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */ #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */ #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */ #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */ /* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 /* #undef TB_CONFIG_LIBC_HAVE_SETJMP */ /* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */ /* #undef TB_CONFIG_LIBC_HAVE_KILL */ /* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */ #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 /* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */ /* #undef TB_CONFIG_LIBC_HAVE_RANDOM */ // libm functions #define TB_CONFIG_LIBM_HAVE_SINCOS 1 #define TB_CONFIG_LIBM_HAVE_SINCOSF 1 #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions /* #undef TB_CONFIG_POSIX_HAVE_POLL */ /* #undef TB_CONFIG_POSIX_HAVE_SELECT */ #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 /* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */ /* #undef TB_CONFIG_POSIX_HAVE_SOCKET */ #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 /* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */ #define TB_CONFIG_POSIX_HAVE_OPEN 1 /* #undef TB_CONFIG_POSIX_HAVE_STAT64 */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */ /* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */ #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 /* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */ /* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */ #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 /* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */ /* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */ /* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */ /* #undef TB_CONFIG_POSIX_HAVE_READV */ /* #undef TB_CONFIG_POSIX_HAVE_WRITEV */ /* #undef TB_CONFIG_POSIX_HAVE_PREADV */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */ /* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */ /* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */ /* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */ /* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #define TB_CONFIG_POSIX_HAVE_EXECVP 1 #define TB_CONFIG_POSIX_HAVE_EXECVPE 1 #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 /* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */ /* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */ /* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */ /* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */ #define TB_CONFIG_POSIX_HAVE_FCNTL 1 /* #undef TB_CONFIG_POSIX_HAVE_PIPE */ /* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */ /* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */ /* #undef TB_CONFIG_POSIX_HAVE_MMAP */ /* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */ /* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */ // windows functions /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */ // bsd functions #define TB_CONFIG_BSD_HAVE_FLOCK 1 // systemv functions /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */ /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */ // valgrind functions /* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ #endif ================================================ FILE: core/src/tbox/inc/haiku/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 3 #define TB_CONFIG_VERSION_BUILD 20230201 // defines #define TB_CONFIG_OS_HAIKU 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /*#undef TB_CONFIG_MICRO_ENABLE*/ /*#undef TB_CONFIG_TYPE_HAVE_WCHAR*/ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 /*#undef TB_CONFIG_API_HAVE_DEPRECATED*/ /*#undef TB_CONFIG_EXCEPTION_ENABLE*/ // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // features #define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /*#undef TB_CONFIG_PACKAGE_HAVE_ZLIB*/ /*#undef TB_CONFIG_PACKAGE_HAVE_MYSQL*/ /*#undef TB_CONFIG_PACKAGE_HAVE_SQLITE3*/ /*#undef TB_CONFIG_PACKAGE_HAVE_OPENSSL*/ /*#undef TB_CONFIG_PACKAGE_HAVE_POLARSSL*/ /*#undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS*/ /*#undef TB_CONFIG_PACKAGE_HAVE_PCRE2*/ /*#undef TB_CONFIG_PACKAGE_HAVE_PCRE*/ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 #define TB_CONFIG_LIBC_HAVE_MEMMEM 1 #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 #define TB_CONFIG_LIBC_HAVE_STRLCPY 1 #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 #define TB_CONFIG_LIBC_HAVE_STRCASESTR 1 #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 /*#undef TB_CONFIG_LIBC_HAVE_STRUPR*/ /*#undef TB_CONFIG_LIBC_HAVE_STRLWR*/ #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSLCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /*#undef TB_CONFIG_LIBC_HAVE_WCSCASESTR*/ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /*#undef TB_CONFIG_LIBC_HAVE_WCSUPR*/ /*#undef TB_CONFIG_LIBC_HAVE_WCSLWR*/ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 #define TB_CONFIG_LIBC_HAVE_SETJMP 1 #define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1 #define TB_CONFIG_LIBC_HAVE_KILL 1 /*#undef TB_CONFIG_LIBC_HAVE_BACKTRACE*/ #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 #define TB_CONFIG_LIBC_HAVE_SRANDOM 1 #define TB_CONFIG_LIBC_HAVE_RANDOM 1 // libm functions #define TB_CONFIG_LIBM_HAVE_SINCOS 1 #define TB_CONFIG_LIBM_HAVE_SINCOSF 1 #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_SELECT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 /*#undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP*/ #define TB_CONFIG_POSIX_HAVE_SOCKET 1 #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 #define TB_CONFIG_POSIX_HAVE_DLOPEN 1 #define TB_CONFIG_POSIX_HAVE_OPEN 1 /*#undef TB_CONFIG_POSIX_HAVE_STAT64*/ /*#undef TB_CONFIG_POSIX_HAVE_LSTAT64*/ #define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1 #define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1 #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 #define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1 #define TB_CONFIG_POSIX_HAVE_SYSCONF 1 #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 /*#undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY*/ #define TB_CONFIG_POSIX_HAVE_REGCOMP 1 #define TB_CONFIG_POSIX_HAVE_REGEXEC 1 #define TB_CONFIG_POSIX_HAVE_READV 1 #define TB_CONFIG_POSIX_HAVE_WRITEV 1 /*#undef TB_CONFIG_POSIX_HAVE_PREADV*/ /*#undef TB_CONFIG_POSIX_HAVE_PWRITEV*/ /*#undef TB_CONFIG_POSIX_HAVE_PREAD64*/ /*#undef TB_CONFIG_POSIX_HAVE_PWRITE64*/ /*#undef TB_CONFIG_POSIX_HAVE_FDATASYNC*/ /*#undef TB_CONFIG_POSIX_HAVE_COPYFILE*/ /*#undef TB_CONFIG_POSIX_HAVE_SENDFILE*/ /*#undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE*/ /*#undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT*/ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP 1 #if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400) # undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15 #endif #define TB_CONFIG_POSIX_HAVE_EXECVP 1 #define TB_CONFIG_POSIX_HAVE_EXECVPE 1 #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 #define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1 #define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1 #define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1 #define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1 #define TB_CONFIG_POSIX_HAVE_FCNTL 1 #define TB_CONFIG_POSIX_HAVE_PIPE 1 /*#undef TB_CONFIG_POSIX_HAVE_PIPE2*/ #define TB_CONFIG_POSIX_HAVE_MKFIFO 1 #define TB_CONFIG_POSIX_HAVE_MMAP 1 #define TB_CONFIG_POSIX_HAVE_FUTIMENS 1 #define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1 // windows functions /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL*/ // bsd functions #define TB_CONFIG_BSD_HAVE_FLOCK 1 // systemv functions #define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1 /*#undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP*/ // linux functions /*#undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT*/ // valgrind functions /*#undef TB_CONFIG_VALGRIND_HAVE_VALGRIND_STACK_REGISTER*/ #endif ================================================ FILE: core/src/tbox/inc/iphoneos/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 3 #define TB_CONFIG_VERSION_BUILD 20230119 // defines #define TB_CONFIG_OS_IOS 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /* #undef TB_CONFIG_MICRO_ENABLE */ /* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 /* #undef TB_CONFIG_API_HAVE_DEPRECATED */ /* #undef TB_CONFIG_EXCEPTION_ENABLE */ // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // features #define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ /* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ /* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ /* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 #define TB_CONFIG_LIBC_HAVE_MEMMEM 1 #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 #define TB_CONFIG_LIBC_HAVE_STRLCPY 1 #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 #define TB_CONFIG_LIBC_HAVE_STRCASESTR 1 #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSLCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */ /* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 #define TB_CONFIG_LIBC_HAVE_SETJMP 1 #define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1 #define TB_CONFIG_LIBC_HAVE_KILL 1 #define TB_CONFIG_LIBC_HAVE_BACKTRACE 1 #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 #define TB_CONFIG_LIBC_HAVE_SRANDOM 1 #define TB_CONFIG_LIBC_HAVE_RANDOM 1 // libm functions /* #undef TB_CONFIG_LIBM_HAVE_SINCOS */ /* #undef TB_CONFIG_LIBM_HAVE_SINCOSF */ #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_SELECT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 /* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */ #define TB_CONFIG_POSIX_HAVE_SOCKET 1 #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 #define TB_CONFIG_POSIX_HAVE_DLOPEN 1 #define TB_CONFIG_POSIX_HAVE_OPEN 1 /* #undef TB_CONFIG_POSIX_HAVE_STAT64 */ #define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1 #define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1 /* #undef TB_CONFIG_POSIX_HAVE_SEM_INIT */ #define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1 #define TB_CONFIG_POSIX_HAVE_SYSCONF 1 #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 /* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */ #define TB_CONFIG_POSIX_HAVE_REGCOMP 1 #define TB_CONFIG_POSIX_HAVE_REGEXEC 1 #define TB_CONFIG_POSIX_HAVE_READV 1 #define TB_CONFIG_POSIX_HAVE_WRITEV 1 /* #undef TB_CONFIG_POSIX_HAVE_PREADV */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */ /* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */ /* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */ #define TB_CONFIG_POSIX_HAVE_COPYFILE 1 /* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 /* #undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP */ #if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400) # undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15 #endif #define TB_CONFIG_POSIX_HAVE_EXECVP 1 /* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */ #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 #define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1 #define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1 #define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1 #define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1 #define TB_CONFIG_POSIX_HAVE_FCNTL 1 #define TB_CONFIG_POSIX_HAVE_PIPE 1 /* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */ #define TB_CONFIG_POSIX_HAVE_MKFIFO 1 #define TB_CONFIG_POSIX_HAVE_MMAP 1 #define TB_CONFIG_POSIX_HAVE_FUTIMENS 1 #define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1 // windows functions /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */ // bsd functions #define TB_CONFIG_BSD_HAVE_FLOCK 1 // systemv functions #define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1 /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */ // valgrind functions /* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ #endif ================================================ FILE: core/src/tbox/inc/linux/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 3 #define TB_CONFIG_VERSION_BUILD 20230119 // defines #define TB_CONFIG_OS_LINUX 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /* #undef TB_CONFIG_MICRO_ENABLE */ /* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ /* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ /* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ /* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 #define TB_CONFIG_LIBC_HAVE_MEMMEM 1 #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 /* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */ #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRCASESTR 1 #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */ #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */ /* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 #define TB_CONFIG_LIBC_HAVE_SETJMP 1 #define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1 #define TB_CONFIG_LIBC_HAVE_KILL 1 /* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */ #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 #define TB_CONFIG_LIBC_HAVE_SRANDOM 1 #define TB_CONFIG_LIBC_HAVE_RANDOM 1 // libm functions #define TB_CONFIG_LIBM_HAVE_SINCOS 1 #define TB_CONFIG_LIBM_HAVE_SINCOSF 1 #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_SELECT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 #if defined(__ANDROID__) /* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */ #else # define TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP 1 #endif #define TB_CONFIG_POSIX_HAVE_SOCKET 1 #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 #define TB_CONFIG_POSIX_HAVE_DLOPEN 1 #define TB_CONFIG_POSIX_HAVE_OPEN 1 // alpine does not support /* #undef TB_CONFIG_POSIX_HAVE_STAT64 */ /* #undef TB_CONFIG_POSIX_HAVE_LSTAT64 */ #define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1 // alpine does not support /* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */ /* #undef TB_CONFIG_LINUX_HAVE_IFADDRS */ #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 #define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1 #define TB_CONFIG_POSIX_HAVE_SYSCONF 1 #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 #define TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY 1 #define TB_CONFIG_POSIX_HAVE_REGCOMP 1 #define TB_CONFIG_POSIX_HAVE_REGEXEC 1 #define TB_CONFIG_POSIX_HAVE_READV 1 #define TB_CONFIG_POSIX_HAVE_WRITEV 1 #define TB_CONFIG_POSIX_HAVE_PREADV 1 #define TB_CONFIG_POSIX_HAVE_PWRITEV 1 // alpine does not support /* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */ #define TB_CONFIG_POSIX_HAVE_FDATASYNC 1 /* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */ #define TB_CONFIG_POSIX_HAVE_SENDFILE 1 #ifdef __COSMOPOLITAN__ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */ #else # define TB_CONFIG_POSIX_HAVE_EPOLL_CREATE 1 # define TB_CONFIG_POSIX_HAVE_EPOLL_WAIT 1 #endif #if defined(__ANDROID__) /* #undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP */ #else # define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #endif #define TB_CONFIG_POSIX_HAVE_EXECVP 1 #define TB_CONFIG_POSIX_HAVE_EXECVPE 1 #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 #if defined(__ANDROID__) /* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */ #else # define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1 #endif #define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1 #define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1 #define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1 #define TB_CONFIG_POSIX_HAVE_FCNTL 1 #define TB_CONFIG_POSIX_HAVE_PIPE 1 /* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */ #ifdef __COSMOPOLITAN__ /* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */ #else # define TB_CONFIG_POSIX_HAVE_MKFIFO 1 #endif #define TB_CONFIG_POSIX_HAVE_FUTIMENS 1 #define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1 // bsd functions #define TB_CONFIG_BSD_HAVE_FLOCK 1 // systemv functions #define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1 #define TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP 1 // valgrind functions /* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ // linux functions #ifdef __COSMOPOLITAN__ /* #undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT */ #else # define TB_CONFIG_LINUX_HAVE_INOTIFY_INIT 1 #endif #endif ================================================ FILE: core/src/tbox/inc/macosx/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 3 #define TB_CONFIG_VERSION_BUILD 20230119 // defines #define TB_CONFIG_OS_MACOSX 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /* #undef TB_CONFIG_MICRO_ENABLE */ /* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ /* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ /* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ /* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 #define TB_CONFIG_LIBC_HAVE_MEMMEM 1 #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 #define TB_CONFIG_LIBC_HAVE_STRLCPY 1 #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRCASESTR 1 #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSLCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */ /* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 #define TB_CONFIG_LIBC_HAVE_SETJMP 1 #define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1 #define TB_CONFIG_LIBC_HAVE_KILL 1 #define TB_CONFIG_LIBC_HAVE_BACKTRACE 1 #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 #define TB_CONFIG_LIBC_HAVE_SRANDOM 1 #define TB_CONFIG_LIBC_HAVE_RANDOM 1 // libm functions /* #undef TB_CONFIG_LIBM_HAVE_SINCOS */ /* #undef TB_CONFIG_LIBM_HAVE_SINCOSF */ #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_SELECT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 /* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */ #define TB_CONFIG_POSIX_HAVE_SOCKET 1 #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 #define TB_CONFIG_POSIX_HAVE_DLOPEN 1 #define TB_CONFIG_POSIX_HAVE_OPEN 1 #if !defined(__arm64__) && !defined(__aarch64__) # define TB_CONFIG_POSIX_HAVE_STAT64 1 # define TB_CONFIG_POSIX_HAVE_LSTAT64 1 #else /* #undef TB_CONFIG_POSIX_HAVE_STAT64 */ #endif #define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1 #define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1 #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 #define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1 #define TB_CONFIG_POSIX_HAVE_SYSCONF 1 #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 /* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */ #define TB_CONFIG_POSIX_HAVE_REGCOMP 1 #define TB_CONFIG_POSIX_HAVE_REGEXEC 1 #define TB_CONFIG_POSIX_HAVE_READV 1 #define TB_CONFIG_POSIX_HAVE_WRITEV 1 /* #undef TB_CONFIG_POSIX_HAVE_PREADV */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */ /* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */ /* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */ #define TB_CONFIG_POSIX_HAVE_COPYFILE 1 /* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #define TB_CONFIG_POSIX_HAVE_EXECVP 1 /* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */ #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 #define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1 #define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1 #define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1 #define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1 #define TB_CONFIG_POSIX_HAVE_FCNTL 1 #define TB_CONFIG_POSIX_HAVE_PIPE 1 /* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */ #define TB_CONFIG_POSIX_HAVE_MKFIFO 1 #define TB_CONFIG_POSIX_HAVE_FUTIMENS 1 #define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1 // bsd functions #define TB_CONFIG_BSD_HAVE_FLOCK 1 // systemv functions #define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1 /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */ // valgrind functions /* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ #endif ================================================ FILE: core/src/tbox/inc/mingw/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 3 #define TB_CONFIG_VERSION_BUILD 20230119 // defines #define TB_CONFIG_OS_WINDOWS 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /* #undef TB_CONFIG_MICRO_ENABLE */ /* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 /* #undef TB_CONFIG_API_HAVE_DEPRECATED */ /* #undef TB_CONFIG_EXCEPTION_ENABLE */ // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // features #define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ /* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ /* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ /* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */ #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 /* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */ #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */ #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 /* #undef TB_CONFIG_LIBC_HAVE_STRUPR */ /* #undef TB_CONFIG_LIBC_HAVE_STRLWR */ #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */ #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */ #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */ #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */ /* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 /* #undef TB_CONFIG_LIBC_HAVE_SETJMP */ /* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */ /* #undef TB_CONFIG_LIBC_HAVE_KILL */ /* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */ #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 /* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */ /* #undef TB_CONFIG_LIBC_HAVE_RANDOM */ // libm functions #define TB_CONFIG_LIBM_HAVE_SINCOS 1 #define TB_CONFIG_LIBM_HAVE_SINCOSF 1 #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions /* #undef TB_CONFIG_POSIX_HAVE_POLL */ /* #undef TB_CONFIG_POSIX_HAVE_SELECT */ #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 /* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */ /* #undef TB_CONFIG_POSIX_HAVE_SOCKET */ #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 /* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */ #define TB_CONFIG_POSIX_HAVE_OPEN 1 /* #undef TB_CONFIG_POSIX_HAVE_STAT64 */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */ /* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */ #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 /* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */ /* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */ #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 /* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */ /* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */ /* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */ /* #undef TB_CONFIG_POSIX_HAVE_READV */ /* #undef TB_CONFIG_POSIX_HAVE_WRITEV */ /* #undef TB_CONFIG_POSIX_HAVE_PREADV */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */ /* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */ /* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */ /* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */ /* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #define TB_CONFIG_POSIX_HAVE_EXECVP 1 #define TB_CONFIG_POSIX_HAVE_EXECVPE 1 #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 /* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */ /* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */ /* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */ /* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */ #define TB_CONFIG_POSIX_HAVE_FCNTL 1 /* #undef TB_CONFIG_POSIX_HAVE_PIPE */ /* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */ /* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */ /* #undef TB_CONFIG_POSIX_HAVE_MMAP */ /* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */ /* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */ // windows functions /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */ // bsd functions #define TB_CONFIG_BSD_HAVE_FLOCK 1 // systemv functions /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */ /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */ // valgrind functions /* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ #endif ================================================ FILE: core/src/tbox/inc/msys/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 3 #define TB_CONFIG_VERSION_BUILD 20230119 // defines #define TB_CONFIG_OS_WINDOWS 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /* #undef TB_CONFIG_MICRO_ENABLE */ /* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 /* #undef TB_CONFIG_API_HAVE_DEPRECATED */ /* #undef TB_CONFIG_EXCEPTION_ENABLE */ // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // features #define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ /* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ /* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ /* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ /* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ /* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */ #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 /* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */ #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */ #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 /* #undef TB_CONFIG_LIBC_HAVE_STRUPR */ /* #undef TB_CONFIG_LIBC_HAVE_STRLWR */ #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */ #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */ #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */ #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */ /* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 /* #undef TB_CONFIG_LIBC_HAVE_SETJMP */ /* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */ /* #undef TB_CONFIG_LIBC_HAVE_KILL */ /* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */ #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 /* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */ /* #undef TB_CONFIG_LIBC_HAVE_RANDOM */ // libm functions #define TB_CONFIG_LIBM_HAVE_SINCOS 1 #define TB_CONFIG_LIBM_HAVE_SINCOSF 1 #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions /* #undef TB_CONFIG_POSIX_HAVE_POLL */ /* #undef TB_CONFIG_POSIX_HAVE_SELECT */ #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 /* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */ /* #undef TB_CONFIG_POSIX_HAVE_SOCKET */ #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 /* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */ #define TB_CONFIG_POSIX_HAVE_OPEN 1 /* #undef TB_CONFIG_POSIX_HAVE_STAT64 */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */ /* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */ #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 /* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */ /* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */ #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 /* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */ /* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */ /* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */ /* #undef TB_CONFIG_POSIX_HAVE_READV */ /* #undef TB_CONFIG_POSIX_HAVE_WRITEV */ /* #undef TB_CONFIG_POSIX_HAVE_PREADV */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */ /* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */ /* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */ /* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */ /* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */ /* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */ /* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #define TB_CONFIG_POSIX_HAVE_EXECVP 1 #define TB_CONFIG_POSIX_HAVE_EXECVPE 1 #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 /* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */ /* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */ /* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */ /* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */ /* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */ #define TB_CONFIG_POSIX_HAVE_FCNTL 1 /* #undef TB_CONFIG_POSIX_HAVE_PIPE */ /* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */ /* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */ /* #undef TB_CONFIG_POSIX_HAVE_MMAP */ /* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */ /* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */ // windows functions /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */ /* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */ // bsd functions #define TB_CONFIG_BSD_HAVE_FLOCK 1 // systemv functions /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */ /* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */ // valgrind functions /* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ #endif ================================================ FILE: core/src/tbox/inc/solaris/tbox.config.h ================================================ #ifndef TB_CONFIG_H #define TB_CONFIG_H // version #define TB_CONFIG_VERSION "1.7.7" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 7 #define TB_CONFIG_VERSION_ALTER 7 #define TB_CONFIG_VERSION_BUILD 20251123 // defines #define TB_CONFIG_OS_SOLARIS 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 /*#undef TB_CONFIG_MICRO_ENABLE*/ /*#undef TB_CONFIG_TYPE_HAVE_WCHAR*/ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 #define TB_CONFIG_FORCE_UTF8 1 /*#undef TB_CONFIG_API_HAVE_DEPRECATED*/ /*#undef TB_CONFIG_EXCEPTION_ENABLE*/ // keywords #define TB_CONFIG_KEYWORD_HAVE__thread 1 #define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 // features #define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1 // modules /* #undef TB_CONFIG_MODULE_HAVE_XML */ /* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 /* #undef TB_CONFIG_MODULE_HAVE_REGEX */ /* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ #define TB_CONFIG_MODULE_HAVE_CHARSET 1 /* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ /* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ // packages /*#undef TB_CONFIG_PACKAGE_HAVE_ZLIB*/ /*#undef TB_CONFIG_PACKAGE_HAVE_MYSQL*/ /*#undef TB_CONFIG_PACKAGE_HAVE_SQLITE3*/ /*#undef TB_CONFIG_PACKAGE_HAVE_OPENSSL*/ /*#undef TB_CONFIG_PACKAGE_HAVE_POLARSSL*/ /*#undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS*/ /*#undef TB_CONFIG_PACKAGE_HAVE_PCRE2*/ /*#undef TB_CONFIG_PACKAGE_HAVE_PCRE*/ // libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 /*#undef TB_CONFIG_LIBC_HAVE_MEMMEM*/ #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 /*#undef TB_CONFIG_LIBC_HAVE_STRLCPY*/ #define TB_CONFIG_LIBC_HAVE_STRLEN 1 /*#undef TB_CONFIG_LIBC_HAVE_STRNLEN*/ #define TB_CONFIG_LIBC_HAVE_STRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 /*#undef TB_CONFIG_LIBC_HAVE_STRCASESTR*/ #define TB_CONFIG_LIBC_HAVE_STRCMP 1 /*#undef TB_CONFIG_LIBC_HAVE_STRCASECMP*/ #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 /*#undef TB_CONFIG_LIBC_HAVE_STRNCASECMP*/ #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 /*#undef TB_CONFIG_LIBC_HAVE_WCSLCPY*/ #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 /*#undef TB_CONFIG_LIBC_HAVE_WCSNLEN*/ #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 /*#undef TB_CONFIG_LIBC_HAVE_WCSCASESTR*/ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 /*#undef TB_CONFIG_LIBC_HAVE_WCSCASECMP*/ #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 /*#undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP*/ #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 #define TB_CONFIG_LIBC_HAVE_TOWLOWER 1 #define TB_CONFIG_LIBC_HAVE_TOWUPPER 1 /*#undef TB_CONFIG_LIBC_HAVE_WCSUPR*/ /*#undef TB_CONFIG_LIBC_HAVE_WCSLWR*/ #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 #define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1 #define TB_CONFIG_LIBC_HAVE_SIGNAL 1 #define TB_CONFIG_LIBC_HAVE_SETJMP 1 /*#undef TB_CONFIG_LIBC_HAVE_SIGSETJMP*/ /*#undef TB_CONFIG_LIBC_HAVE_KILL*/ #define TB_CONFIG_LIBC_HAVE_BACKTRACE 1 #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 #define TB_CONFIG_LIBC_HAVE_FPUTC 1 #define TB_CONFIG_LIBC_HAVE_FGETC 1 #define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 #define TB_CONFIG_LIBC_HAVE_FGETS 1 #define TB_CONFIG_LIBC_HAVE_FREAD 1 #define TB_CONFIG_LIBC_HAVE_FWRITE 1 /*#undef TB_CONFIG_LIBC_HAVE_SRANDOM*/ /*#undef TB_CONFIG_LIBC_HAVE_RANDOM*/ // libm functions /*#undef TB_CONFIG_LIBM_HAVE_SINCOS*/ /*#undef TB_CONFIG_LIBM_HAVE_SINCOSF*/ #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 #define TB_CONFIG_LIBM_HAVE_SQRTF 1 #define TB_CONFIG_LIBM_HAVE_ACOS 1 #define TB_CONFIG_LIBM_HAVE_ACOSF 1 #define TB_CONFIG_LIBM_HAVE_ASIN 1 #define TB_CONFIG_LIBM_HAVE_ASINF 1 #define TB_CONFIG_LIBM_HAVE_POW 1 #define TB_CONFIG_LIBM_HAVE_POWF 1 #define TB_CONFIG_LIBM_HAVE_FMOD 1 #define TB_CONFIG_LIBM_HAVE_FMODF 1 #define TB_CONFIG_LIBM_HAVE_TAN 1 #define TB_CONFIG_LIBM_HAVE_TANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN 1 #define TB_CONFIG_LIBM_HAVE_ATANF 1 #define TB_CONFIG_LIBM_HAVE_ATAN2 1 #define TB_CONFIG_LIBM_HAVE_ATAN2F 1 #define TB_CONFIG_LIBM_HAVE_COS 1 #define TB_CONFIG_LIBM_HAVE_COSF 1 #define TB_CONFIG_LIBM_HAVE_SIN 1 #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 // posix functions #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_SELECT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 /*#undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP*/ #define TB_CONFIG_POSIX_HAVE_SOCKET 1 #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 #define TB_CONFIG_POSIX_HAVE_DLOPEN 1 #define TB_CONFIG_POSIX_HAVE_OPEN 1 /*#undef TB_CONFIG_POSIX_HAVE_STAT64*/ /*#undef TB_CONFIG_POSIX_HAVE_LSTAT64*/ #define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1 #define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1 #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 #define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1 #define TB_CONFIG_POSIX_HAVE_SYSCONF 1 #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 /*#undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY*/ #define TB_CONFIG_POSIX_HAVE_REGCOMP 1 #define TB_CONFIG_POSIX_HAVE_REGEXEC 1 #define TB_CONFIG_POSIX_HAVE_READV 1 #define TB_CONFIG_POSIX_HAVE_WRITEV 1 #define TB_CONFIG_POSIX_HAVE_PREADV 1 #define TB_CONFIG_POSIX_HAVE_PWRITEV 1 /*#undef TB_CONFIG_POSIX_HAVE_PREAD64*/ /*#undef TB_CONFIG_POSIX_HAVE_PWRITE64*/ #define TB_CONFIG_POSIX_HAVE_FDATASYNC 1 /*#undef TB_CONFIG_POSIX_HAVE_COPYFILE*/ #define TB_CONFIG_POSIX_HAVE_SENDFILE 1 /*#undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE*/ /*#undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT*/ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 /*#undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP*/ #if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400) # undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15 #endif #define TB_CONFIG_POSIX_HAVE_EXECVP 1 #define TB_CONFIG_POSIX_HAVE_EXECVPE 1 #define TB_CONFIG_POSIX_HAVE_FORK 1 /*#undef TB_CONFIG_POSIX_HAVE_VFORK*/ #define TB_CONFIG_POSIX_HAVE_WAITPID 1 #define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1 #define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1 #define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1 #define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1 #define TB_CONFIG_POSIX_HAVE_FCNTL 1 #define TB_CONFIG_POSIX_HAVE_PIPE 1 #define TB_CONFIG_POSIX_HAVE_PIPE2 1 #define TB_CONFIG_POSIX_HAVE_MKFIFO 1 #define TB_CONFIG_POSIX_HAVE_MMAP 1 /*#undef TB_CONFIG_POSIX_HAVE_FUTIMENS*/ /*#undef TB_CONFIG_POSIX_HAVE_UTIMENSAT*/ // windows functions /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ*/ /*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL*/ // bsd functions /*#undef TB_CONFIG_BSD_HAVE_FLOCK*/ // systemv functions #define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1 #define TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP 1 // linux functions /*#undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT*/ /*#undef TB_CONFIG_LINUX_HAVE_IFADDRS*/ // valgrind functions /*#undef TB_CONFIG_VALGRIND_HAVE_VALGRIND_STACK_REGISTER*/ #endif ================================================ FILE: core/src/tbox/xmake.lua ================================================ includes("tbox") -- enable hash, charset, utf8 modules for _, name in ipairs({ "hash", "charset", "force-utf8" }) do option(name) set_default(true) after_check(function (option) option:enable(true) end) option_end() end -- disable demo option("demo") set_default(false) option_end() ================================================ FILE: core/src/tbox/xmake.sh ================================================ #!/bin/sh set_config "hash" true set_config "charset" true set_config "force_utf8" true set_config "float" true set_config "demo" false check_interfaces_enabled=false includes "tbox/src" hide_options() { local name="" local options="demo small micro float info exception deprecated force_utf8 xml zip hash regex object charset database coroutine" for name in $options; do option "${name}" set_showmenu false option_end done } hide_options target "tbox" set_default false set_configvar "TB_CONFIG_MODULE_HAVE_HASH" 1 set_configvar "TB_CONFIG_MODULE_HAVE_CHARSET" 1 set_configvar "TB_CONFIG_FORCE_UTF8" 1 set_configvar "TB_CONFIG_TYPE_HAVE_FLOAT" 1 add_includedirs "inc/${plat}" "{public}" if is_mode "debug"; then add_defines "__tb_debug__" fi ================================================ FILE: core/src/xmake/base64/decode.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file base64.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "base64" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_base64_decode(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the string size_t size = 0; tb_char_t const *cstr = luaL_checklstring(lua, 1, &size); tb_check_return_val(cstr && size, 0); // decode it tb_byte_t buff[8192]; if (size < sizeof(buff)) { tb_size_t real = tb_base64_decode(cstr, size, buff, sizeof(buff)); if (real > 0) { lua_pushlstring(lua, (tb_char_t const *)buff, (tb_int_t)real); return 1; } } lua_pushnil(lua); lua_pushstring(lua, "buffer is too small"); return 2; } ================================================ FILE: core/src/xmake/base64/encode.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file base64.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "base64" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_base64_encode(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 1)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1); } if (xm_lua_isinteger(lua, 2)) { size = (tb_size_t)lua_tointeger(lua, 2); } if (!data || !size) { lua_pushnil(lua); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // encode it tb_char_t buff[8192]; if (size * 3 / 2 < sizeof(buff)) { tb_size_t real = tb_base64_encode(data, size, buff, sizeof(buff)); if (real > 0) { lua_pushlstring(lua, buff, (tb_int_t)real); return 1; } } lua_pushnil(lua); lua_pushstring(lua, "buffer is too small"); return 2; } ================================================ FILE: core/src/xmake/base64/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BASE64_PREFIX_H #define XM_BASE64_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/binutils/ar/extractlib.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file extractlib.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "extractlib" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* generate unique filename to handle name conflicts * * @param base_name the base filename * @param id the unique ID * @param output output buffer * @param output_size size of output buffer * @param output_len output: actual output length * @return tb_true on success */ static tb_bool_t xm_binutils_ar_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size, tb_size_t* output_len) { tb_assert_and_check_return_val(base_name && output && output_size > 0 && output_len, tb_false); // find the last dot for extension tb_char_t const *ext = tb_strrchr(base_name, '.'); tb_long_t n = -1; if (ext) { tb_size_t base_len = (tb_size_t)(ext - base_name); tb_size_t ext_len = tb_strlen(ext); if (base_len + ext_len + 16 < output_size) { n = tb_snprintf(output, output_size, "%.*s_%u%s", (tb_int_t)base_len, base_name, id, ext); } } else { // no extension if (tb_strlen(base_name) + 16 < output_size) { n = tb_snprintf(output, output_size, "%s_%u", base_name, id); } } if (n >= 0) { *output_len = (tb_size_t)n; return tb_true; } return tb_false; } /* extract AR archive to directory * * @param istream the input stream * @param outputdir the output directory * @return tb_true on success, tb_false on failure */ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir) { tb_assert_and_check_return_val(istream && outputdir, tb_false); // get output directory length tb_size_t outputdir_len = tb_strlen(outputdir); // check AR magic (!\n) if (!xm_binutils_ar_check_magic(istream, 0)) { return tb_false; } // ensure output directory exists // check if directory already exists if (!tb_file_info(outputdir, tb_null)) { // directory doesn't exist, create it if (!tb_directory_create(outputdir)) { return tb_false; } } tb_bool_t ok = tb_true; // iterate through AR members while (ok) { // read AR header // AR header is exactly 60 bytes: name[16] + date[12] + uid[6] + gid[6] + mode[8] + size[10] + fmag[2] xm_ar_header_t header; if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { // end of file break; } // parse member size tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10); if (member_size < 0) { ok = tb_false; break; } // get member name tb_char_t member_name[256] = {0}; tb_size_t name_len = 0; tb_hize_t name_bytes_read = 0; // get member name (handles both regular and extended name formats) tb_bool_t skip = tb_false; if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len, &name_bytes_read)) { skip = tb_true; } else if (xm_binutils_ar_is_symbol_table(member_name)) { // skip symbol tables skip = tb_true; } else if (!xm_binutils_ar_is_object_file(member_name)) { // only extract object files skip = tb_true; } if (skip) { // skip remaining data + padding using sequential read tb_hize_t skip_size = (tb_hize_t)member_size - name_bytes_read; if (member_size % 2) { skip_size++; // add padding } if (!tb_stream_skip(istream, skip_size)) { ok = tb_false; break; } continue; } // handle name conflicts by checking if file exists and renaming with ID tb_char_t output_name[512] = {0}; tb_char_t output_path_check[1024] = {0}; if (outputdir_len + 1 + name_len >= sizeof(output_path_check)) { ok = tb_false; break; } tb_snprintf(output_path_check, sizeof(output_path_check), "%s/%s", outputdir, member_name); // check if file already exists tb_uint32_t conflict_id = 1; tb_size_t output_name_len = name_len; if (tb_file_info(output_path_check, tb_null)) { // name conflict, try different IDs until we find an available name while (conflict_id < 10000) { // reasonable limit if (!xm_binutils_ar_generate_unique_name(member_name, conflict_id, output_name, sizeof(output_name), &output_name_len)) { ok = tb_false; break; } if (outputdir_len + 1 + output_name_len >= sizeof(output_path_check)) { ok = tb_false; break; } tb_snprintf(output_path_check, sizeof(output_path_check), "%s/%s", outputdir, output_name); if (!tb_file_info(output_path_check, tb_null)) { // found available name break; } conflict_id++; } if (conflict_id >= 10000) { ok = tb_false; break; } } else { // first occurrence, use original name tb_strlcpy(output_name, member_name, sizeof(output_name)); } // build output path tb_char_t output_path[1024] = {0}; if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) { ok = tb_false; break; } tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, output_name); // create output file tb_stream_ref_t ostream = tb_stream_init_from_file(output_path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); if (!ostream) { ok = tb_false; break; } if (!tb_stream_open(ostream)) { tb_stream_exit(ostream); ok = tb_false; break; } // copy member data to output file // member_size includes the name if extended format was used, so subtract name_bytes_read tb_hize_t remaining = (tb_hize_t)member_size - name_bytes_read; if (!xm_binutils_stream_copy(istream, ostream, remaining)) { ok = tb_false; } tb_stream_clos(ostream); tb_stream_exit(ostream); tb_check_break(ok); // align to 2-byte boundary (AR format requirement) if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { ok = tb_false; break; } } } return ok; } ================================================ FILE: core/src/xmake/binutils/ar/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BINUTILS_AR_PREFIX_H #define XM_BINUTILS_AR_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #include "../coff/prefix.h" #include "../elf/prefix.h" #include "../macho/prefix.h" #include "../wasm/prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * forward declarations */ extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); /* ////////////////////////////////////////////////////////////////////////////////////// * types */ #include "tbox/prefix/packed.h" typedef struct __xm_ar_header_t { tb_char_t name[16]; // file name (null-padded) tb_char_t date[12]; // modification time (decimal) tb_char_t uid[6]; // user ID (decimal) tb_char_t gid[6]; // group ID (decimal) tb_char_t mode[8]; // file mode (octal) tb_char_t size[10]; // file size (decimal) tb_char_t fmag[2]; // magic: "`\n" } __tb_packed__ xm_ar_header_t; #include "tbox/prefix/packed.h" /* ////////////////////////////////////////////////////////////////////////////////////// * inline implementation */ /* parse decimal number from string * * @param str the string * @param len the length * @return the parsed number, or -1 on error */ static __tb_inline__ tb_int64_t xm_binutils_ar_parse_decimal(tb_char_t const *str, tb_size_t len) { tb_assert_and_check_return_val(str && len > 0, -1); tb_int64_t result = 0; for (tb_size_t i = 0; i < len; i++) { if (str[i] == ' ' || str[i] == '\0') { break; } if (str[i] < '0' || str[i] > '9') { return -1; } result = result * 10 + (str[i] - '0'); } return result; } /* get member name from AR header, handling extended names (#N/L format) * * @param istream the input stream * @param header the AR header * @param name output buffer for the name * @param name_size size of the name buffer * @param name_len output: actual name length * @param bytes_read output: total bytes read from stream (including newline, for extended names) * @return tb_true on success, tb_false on failure */ static __tb_inline__ tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_header_t const* header, tb_char_t* name, tb_size_t name_size, tb_size_t* name_len, tb_hize_t* bytes_read) { tb_assert_and_check_return_val(istream && header && name && name_size > 0 && name_len && bytes_read, tb_false); *bytes_read = 0; /* check for extended name format (#N/L or #1/N) * In BSD AR format: * - #1/N means name is directly after header, N is total length (including name) * - #N/L means name length is N, total length is L * - #1/N can also mean name is in long name table at offset 1 * We'll try to read the name directly from stream first */ if (header->name[0] == '#') { // find the '/' separator tb_size_t slash_pos = 0; for (tb_size_t i = 1; i < 16; i++) { if (header->name[i] == '/') { slash_pos = i; break; } } if (slash_pos > 0 && slash_pos < 16) { // parse the number before '/' (could be name length or offset) tb_int64_t first_num = xm_binutils_ar_parse_decimal(header->name + 1, slash_pos - 1); // parse the number after '/' (total length) tb_int64_t total_length = xm_binutils_ar_parse_decimal(header->name + slash_pos + 1, 16 - slash_pos - 1); if (first_num <= 0 || total_length <= 0) { return tb_false; } /* In BSD AR format, extended name is directly after header * The name data starts immediately after the header, no newline * Read exactly total_length bytes for the name section */ tb_byte_t c; tb_size_t name_bytes = 0; tb_hize_t bytes_read_so_far = 0; // Read name characters until we hit null terminator or reach total_length while (bytes_read_so_far < (tb_hize_t)total_length && name_bytes < name_size - 1) { if (!tb_stream_bread(istream, &c, 1)) { return tb_false; } bytes_read_so_far++; if (c == '\0') { // Stop reading name at null terminator, but continue reading to reach total_length break; } // Include all characters in the name, including newlines if present name[name_bytes++] = (tb_char_t)c; } name[name_bytes] = '\0'; *name_len = name_bytes; // Skip remaining bytes to reach total_length (there may be padding or null terminators) if (bytes_read_so_far < (tb_hize_t)total_length) { tb_hize_t remaining_to_read = (tb_hize_t)total_length - bytes_read_so_far; if (!tb_stream_skip(istream, remaining_to_read)) { return tb_false; } } // Total bytes read = name + padding = total_length *bytes_read = (tb_hize_t)total_length; return tb_true; } } if (header->name[0] == '/') { if (header->name[1] == '/') { tb_strlcpy(name, "//", name_size); *name_len = 2; } else { tb_strlcpy(name, "/", name_size); *name_len = 1; } *bytes_read = 0; return tb_true; } // regular name (null-terminated or space-padded) tb_size_t i = 0; for (i = 0; i < 16 && i < name_size - 1; i++) { if (header->name[i] == ' ' || header->name[i] == '\0' || header->name[i] == '/') { break; } name[i] = header->name[i]; } name[i] = '\0'; *name_len = i; *bytes_read = 0; // Regular names are in header, not read from stream return tb_true; } /* check AR magic (!\n) * * @param istream the input stream * @param base_offset the base offset * @return tb_true on success, tb_false on failure */ static __tb_inline__ tb_bool_t xm_binutils_ar_check_magic(tb_stream_ref_t istream, tb_hize_t base_offset) { tb_uint8_t magic[8]; if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, magic, 8)) { return tb_false; } if (magic[0] != '!' || magic[1] != '<' || magic[2] != 'a' || magic[3] != 'r' || magic[4] != 'c' || magic[5] != 'h' || (magic[6] != '>' && magic[6] != '\n') || (magic[7] != '\n' && magic[7] != '\r')) { return tb_false; } return tb_true; } /* check if member is a symbol table (should be skipped) * * @param name the member name * @return tb_true if it's a symbol table, tb_false otherwise */ static __tb_inline__ tb_bool_t xm_binutils_ar_is_symbol_table(tb_char_t const *name) { tb_assert_and_check_return_val(name, tb_false); return (tb_strcmp(name, "__.SYMDEF") == 0 || tb_strcmp(name, "__.SYMDEF SORTED") == 0 || tb_strcmp(name, "/") == 0 || tb_strcmp(name, "//") == 0 || tb_strncmp(name, "__.SYMDEF", 9) == 0); } /* check if member is an object file (based on extension) * * @param name the member name * @return tb_true if it's likely an object file, tb_false otherwise */ static __tb_inline__ tb_bool_t xm_binutils_ar_is_object_file(tb_char_t const *name) { tb_assert_and_check_return_val(name, tb_false); tb_size_t len = tb_strlen(name); if (len == 0) { return tb_false; } // check common object file extensions if (len >= 2 && name[len - 2] == '.' && name[len - 1] == 'o') { return tb_true; } if (len >= 4 && tb_strcmp(name + len - 4, ".obj") == 0) { return tb_true; } // check if it's a COFF/ELF/Mach-O file by detecting format // For now, we'll extract all non-symbol-table members return tb_true; } #endif ================================================ FILE: core/src/xmake/binutils/ar/readsyms.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file readsyms.c * */ #define TB_TRACE_MODULE_NAME "readsyms_ar" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_int_t xm_binutils_ar_detect_member_format(tb_stream_ref_t istream, tb_hize_t base_offset) { tb_uint8_t magic[8] = {0}; if (!tb_stream_seek(istream, base_offset)) { return -1; } if (!tb_stream_bread(istream, magic, 8)) { tb_stream_seek(istream, base_offset); return -1; } tb_stream_seek(istream, base_offset); if (magic[0] == XM_WASM_MAGIC0 && magic[1] == XM_WASM_MAGIC1 && magic[2] == XM_WASM_MAGIC2 && magic[3] == XM_WASM_MAGIC3) { return XM_BINUTILS_FORMAT_WASM; } if (magic[0] == XM_ELF_MAGIC0 && magic[1] == XM_ELF_MAGIC1 && magic[2] == XM_ELF_MAGIC2 && magic[3] == XM_ELF_MAGIC3) { return XM_BINUTILS_FORMAT_ELF; } tb_uint32_t macho_magic = tb_bits_get_u32_be(magic); if (macho_magic == XM_MACHO_MAGIC_32 || macho_magic == XM_MACHO_MAGIC_64 || macho_magic == XM_MACHO_MAGIC_32_BE || macho_magic == XM_MACHO_MAGIC_64_BE) { return XM_BINUTILS_FORMAT_MACHO; } return XM_BINUTILS_FORMAT_UNKNOWN; } /* parse BSD symbol table (__.SYMDEF or __.SYMDEF SORTED) * * Header: * - ranlib_size (uint32_t) * - ranlibs (struct ranlib[ranlib_size/8]) * - strtab_size (uint32_t) * - strtab (char[strtab_size]) * * struct ranlib { * uint32_t ran_strx; // offset into string table * uint32_t ran_off; // offset into archive * }; */ static tb_bool_t xm_binutils_ar_parse_bsd_symdef(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) { tb_hize_t start_pos = tb_stream_offset(istream); // read size of ranlib array tb_uint32_t ranlib_size = 0; if (!tb_stream_bread_u32_le(istream, &ranlib_size)) { return tb_false; } // sanity check if (ranlib_size == 0 || ranlib_size >= member_size) { tb_stream_seek(istream, start_pos); return tb_false; } // read ranlib array tb_size_t num_ranlibs = ranlib_size / 8; // allocate buffers tb_uint32_t* ran_strx = tb_nalloc_type(num_ranlibs, tb_uint32_t); tb_uint32_t* ran_off = tb_nalloc_type(num_ranlibs, tb_uint32_t); if (!ran_strx || !ran_off) { if (ran_strx) { tb_free(ran_strx); } if (ran_off) { tb_free(ran_off); } tb_stream_seek(istream, start_pos); return tb_false; } tb_size_t i; for (i = 0; i < num_ranlibs; i++) { if (!tb_stream_bread_u32_le(istream, &ran_strx[i]) || !tb_stream_bread_u32_le(istream, &ran_off[i])) { tb_free(ran_strx); tb_free(ran_off); tb_stream_seek(istream, start_pos); return tb_false; } } // read string table size tb_uint32_t strtab_size = 0; if (!tb_stream_bread_u32_le(istream, &strtab_size)) { tb_free(ran_strx); tb_free(ran_off); tb_stream_seek(istream, start_pos); return tb_false; } // read string table tb_char_t* strtab = (tb_char_t*)tb_malloc_bytes(strtab_size); if (!strtab) { tb_free(ran_strx); tb_free(ran_off); tb_stream_seek(istream, start_pos); return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)strtab, strtab_size)) { tb_free(strtab); tb_free(ran_strx); tb_free(ran_off); tb_stream_seek(istream, start_pos); return tb_false; } // populate map for (i = 0; i < num_ranlibs; i++) { tb_uint32_t off = ran_off[i]; tb_uint32_t strx = ran_strx[i]; if (strx < strtab_size) { tb_char_t* name = strtab + strx; // add to map: map[off] = { {name=name, type="T"}, ... } lua_pushinteger(lua, off); lua_rawget(lua, map_idx); if (lua_isnil(lua, -1)) { lua_pop(lua, 1); lua_newtable(lua); lua_pushinteger(lua, off); lua_pushvalue(lua, -2); lua_rawset(lua, map_idx); } int count = (int)lua_objlen(lua, -1); lua_newtable(lua); lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); lua_pushstring(lua, "type"); lua_pushstring(lua, "T"); lua_settable(lua, -3); lua_rawseti(lua, -2, count + 1); lua_pop(lua, 1); // pop list } } tb_free(strtab); tb_free(ran_strx); tb_free(ran_off); return tb_true; } /* parse SysV symbol table (/) * * Header: * - num_symbols (uint32_t BE) * - offsets (uint32_t[num_symbols] BE) * - string table (null-terminated strings) */ static tb_bool_t xm_binutils_ar_parse_sysv_symdef(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) { tb_hize_t start_pos = tb_stream_offset(istream); // read number of symbols tb_uint32_t num_symbols = 0; if (!tb_stream_bread_u32_be(istream, &num_symbols)) { return tb_false; } // sanity check if (num_symbols == 0 || num_symbols * 4 >= member_size) { tb_stream_seek(istream, start_pos); return tb_false; } // read offsets tb_uint32_t* offsets = tb_nalloc_type(num_symbols, tb_uint32_t); if (!offsets) { tb_stream_seek(istream, start_pos); return tb_false; } tb_size_t i; for (i = 0; i < num_symbols; i++) { if (!tb_stream_bread_u32_be(istream, &offsets[i])) { tb_free(offsets); tb_stream_seek(istream, start_pos); return tb_false; } } // read string table tb_hize_t current = tb_stream_offset(istream); tb_hize_t strtab_size = member_size - (current - start_pos); tb_char_t* strtab = (tb_char_t*)tb_malloc_bytes((tb_size_t)strtab_size); if (!strtab) { tb_free(offsets); tb_stream_seek(istream, start_pos); return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)strtab, (tb_size_t)strtab_size)) { tb_free(strtab); tb_free(offsets); tb_stream_seek(istream, start_pos); return tb_false; } // populate map tb_char_t* p = strtab; tb_char_t* end = strtab + strtab_size; for (i = 0; i < num_symbols; i++) { if (p >= end) { break; } tb_char_t* name = p; tb_size_t len = tb_strlen(name); p += len + 1; tb_uint32_t off = offsets[i]; // add to map lua_pushinteger(lua, off); lua_rawget(lua, map_idx); if (lua_isnil(lua, -1)) { lua_pop(lua, 1); lua_newtable(lua); lua_pushinteger(lua, off); lua_pushvalue(lua, -2); lua_rawset(lua, map_idx); } int count = (int)lua_objlen(lua, -1); lua_newtable(lua); lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); lua_pushstring(lua, "type"); lua_pushstring(lua, "T"); lua_settable(lua, -3); lua_rawseti(lua, -2, count + 1); lua_pop(lua, 1); // pop list } tb_free(strtab); tb_free(offsets); return tb_true; } /* read symbols from AR archive * * @param istream the input stream * @param base_offset the base offset * @param lua the lua state * @return tb_true on success, tb_false on failure */ tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State* lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // check AR magic (!\n) if (!xm_binutils_ar_check_magic(istream, base_offset)) { return tb_false; } // get result list index int list_idx = lua_gettop(lua); // init map table for symbol table lua_newtable(lua); int map_idx = lua_gettop(lua); tb_bool_t ok = tb_true; tb_size_t object_count = 0; // iterate through AR members while (ok) { // save member header position tb_hize_t member_header_pos = tb_stream_offset(istream); /* read AR header * AR header is exactly 60 bytes: name[16] + date[12] + uid[6] + gid[6] + mode[8] + size[10] + fmag[2] */ xm_ar_header_t header; if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { // end of file break; } // parse member size tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10); if (member_size < 0) { ok = tb_false; break; } // get member name tb_char_t member_name[256] = {0}; tb_size_t name_len = 0; tb_hize_t name_bytes_read = 0; // get member name (handles both regular and extended name formats) tb_bool_t skip = tb_false; if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len, &name_bytes_read)) { skip = tb_true; } else { if (xm_binutils_ar_is_symbol_table(member_name)) { /* parse symbol table * * The symbol table in the archive only contains symbol names and their offsets, * but lacks detailed symbol type information (e.g., distinguishing between code and data). * However, for object files that cannot be parsed (e.g., LTO bitcode) or unknown formats, * parsing the symbol table serves as a robust fallback to ensure symbols are extracted. */ tb_hize_t current = tb_stream_offset(istream); if (tb_strcmp(member_name, "/") == 0) { xm_binutils_ar_parse_sysv_symdef(istream, member_size, lua, map_idx); } else if (tb_strcmp(member_name, "//") != 0) { xm_binutils_ar_parse_bsd_symdef(istream, member_size, lua, map_idx); } tb_stream_seek(istream, current); // restore position for skip skip = tb_true; } else if (!xm_binutils_ar_is_object_file(member_name)) { // only extract object files skip = tb_true; } } if (skip) { // skip remaining data + padding using sequential read tb_hize_t skip_size = (tb_hize_t)member_size - name_bytes_read; if (member_size % 2) { skip_size++; // add padding } if (!tb_stream_skip(istream, skip_size)) { ok = tb_false; break; } continue; } // save current position tb_hize_t current_pos = tb_stream_offset(istream); // detect format tb_int_t format = xm_binutils_ar_detect_member_format(istream, current_pos); if (format != XM_BINUTILS_FORMAT_AR) { // create entry table lua_newtable(lua); // object name lua_pushstring(lua, "objectfile"); lua_pushstring(lua, member_name); lua_settable(lua, -3); // symbols lua_pushstring(lua, "symbols"); tb_bool_t read_ok = tb_false; if (format == XM_BINUTILS_FORMAT_COFF) { read_ok = xm_binutils_coff_read_symbols(istream, current_pos, lua); } else if (format == XM_BINUTILS_FORMAT_ELF) { read_ok = xm_binutils_elf_read_symbols(istream, current_pos, lua); } else if (format == XM_BINUTILS_FORMAT_MACHO) { read_ok = xm_binutils_macho_read_symbols(istream, current_pos, lua); } else if (format == XM_BINUTILS_FORMAT_WASM) { read_ok = xm_binutils_wasm_read_symbols(istream, current_pos, lua); } if (!read_ok) { /* try get from map * * If parsing the object file fails (e.g. for LTO bitcode or unsupported formats), * we fall back to using the symbols parsed from the archive symbol table. * Although the type information is less accurate (defaulting to "T"), * it guarantees that symbols are not lost. * * cast to lua_Integer to avoid warning C4244 on 32-bit MSVC * member_header_pos is tb_hize_t (64-bit), but AR offsets are usually 32-bit */ lua_pushinteger(lua, (lua_Integer)member_header_pos); lua_rawget(lua, map_idx); if (!lua_isnil(lua, -1)) { read_ok = tb_true; } else { lua_pop(lua, 1); } } if (read_ok) { lua_settable(lua, -3); lua_rawseti(lua, list_idx, (int)(++object_count)); } else { lua_pop(lua, 2); // pop symbols key and entry table } } // skip to next member tb_hize_t member_data_read = tb_stream_offset(istream) - current_pos; tb_hize_t remaining_size = (tb_hize_t)member_size - name_bytes_read - member_data_read; if (member_size % 2) { remaining_size++; // add padding } if (remaining_size > 0) { if (!tb_stream_skip(istream, remaining_size)) { ok = tb_false; break; } } else if (remaining_size < 0) { /* should not happen if readsyms functions respect boundaries, but just in case * seek back to correct position */ if (!tb_stream_seek(istream, current_pos + (tb_hize_t)member_size - name_bytes_read + (member_size % 2))) { ok = tb_false; break; } } } lua_remove(lua, map_idx); return ok; } ================================================ FILE: core/src/xmake/binutils/bin2c.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bin2c.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bin2c" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_BIN2C_DATA_SIZE (8 * 1024) #define XM_BIN2C_LINE_SIZE (4 * 1024) #define XM_BIN2C_LINEWIDTH_MAX ((XM_BIN2C_LINE_SIZE - 2) / 6) /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ // optimized hex conversion table static tb_char_t const *xm_binutils_bin2c_digits = "0123456789ABCDEF"; // inline hex conversion for better performance static __tb_inline__ tb_void_t xm_binutils_bin2c_write_hex(tb_char_t *str, tb_byte_t value) { str[0] = ' '; str[1] = '0'; str[2] = 'x'; str[3] = xm_binutils_bin2c_digits[(value >> 4) & 15]; str[4] = xm_binutils_bin2c_digits[value & 15]; } static tb_bool_t xm_binutils_bin2c_dump(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_int_t linewidth, tb_bool_t nozeroend) { tb_bool_t first = tb_true; tb_bool_t zero_pending = tb_false; tb_byte_t data[XM_BIN2C_DATA_SIZE]; tb_char_t line[XM_BIN2C_LINE_SIZE]; tb_size_t linesize = 0; tb_size_t bytes_in_line = 0; tb_size_t data_pos = 0; tb_size_t data_size = 0; tb_assert_and_check_return_val(linewidth > 0 && linewidth <= XM_BIN2C_LINEWIDTH_MAX, tb_false); while (!tb_stream_beof(istream) || data_pos < data_size || zero_pending) { // read a large chunk of data if buffer is empty if (data_pos >= data_size) { // handle pending zero terminator if (zero_pending) { data[0] = '\0'; data_size = 1; data_pos = 0; zero_pending = tb_false; } else { tb_hong_t left = tb_stream_left(istream); tb_size_t to_read = (tb_size_t)tb_min(left, (tb_hong_t)XM_BIN2C_DATA_SIZE); tb_check_break(to_read); if (!tb_stream_bread(istream, data, to_read)) { break; } data_size = to_read; data_pos = 0; // check if we need to add zero terminator at the end if (!nozeroend && tb_stream_beof(istream)) { if (data_size < XM_BIN2C_DATA_SIZE) { // can add directly to current buffer data[data_size++] = '\0'; } else { // buffer is full, need to add zero in next iteration zero_pending = tb_true; } } } } // process bytes from buffer while (data_pos < data_size) { // check if we need a new line if (bytes_in_line >= (tb_size_t)linewidth) { // write line (tb_stream_bwrit_line will add newline automatically) if (tb_stream_bwrit_line(ostream, line, linesize) < 0) { return tb_false; } linesize = 0; bytes_in_line = 0; first = tb_false; } // ensure we have enough space in line buffer (6 chars per byte: ", 0xXX") if (linesize + 6 > sizeof(line)) { // flush partial line if buffer is full if (linesize > 0) { if (!tb_stream_bwrit(ostream, (tb_byte_t *)line, linesize)) { return tb_false; } linesize = 0; } } // add separator if (bytes_in_line == 0 && first) { line[linesize++] = ' '; first = tb_false; } else { line[linesize++] = ','; } // write hex value (inline for performance) xm_binutils_bin2c_write_hex(line + linesize, data[data_pos]); linesize += 5; bytes_in_line++; data_pos++; } } // flush remaining line if (linesize > 0) { // write line (tb_stream_bwrit_line will add newline automatically) if (tb_stream_bwrit_line(ostream, line, linesize) < 0) { return tb_false; } } return tb_stream_beof(istream); } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* generate c/c++ code from the binary file * * local ok, errors = binutils.bin2c(binaryfile, outputfile, linewidth, nozeroend) */ tb_int_t xm_binutils_bin2c(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the binaryfile tb_char_t const *binaryfile = luaL_checkstring(lua, 1); tb_check_return_val(binaryfile, 0); // get the outputfile tb_char_t const *outputfile = luaL_checkstring(lua, 2); tb_check_return_val(outputfile, 0); // get line width tb_int_t linewidth = (tb_int_t)lua_tointeger(lua, 3); // no zero end? tb_bool_t nozeroend = (tb_bool_t)lua_toboolean(lua, 4); // do dump tb_bool_t ok = tb_false; tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO); tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); do { if (!tb_stream_open(istream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2c: open %s failed", binaryfile); break; } if (!tb_stream_open(ostream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2c: open %s failed", outputfile); break; } if (!xm_binutils_bin2c_dump(istream, ostream, linewidth, nozeroend)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2c: dump data failed"); break; } ok = tb_true; lua_pushboolean(lua, ok); } while (0); if (istream) { tb_stream_clos(istream); } istream = tb_null; if (ostream) { tb_stream_clos(ostream); } ostream = tb_null; return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/binutils/coff/bin2coff.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bin2coff.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bin2coff" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_binutils_bin2coff_dump(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_char_t const *symbol_prefix, tb_char_t const *arch, tb_char_t const *basename, tb_bool_t zeroend) { tb_assert_and_check_return_val(istream && ostream, tb_false); // get file size tb_hong_t filesize = tb_stream_size(istream); if (filesize < 0 || filesize > 0xffffffffU) { return tb_false; } tb_uint32_t datasize = (tb_uint32_t)filesize; // add null terminator if zeroend is true if (zeroend) { if (datasize >= 0xffffffffU) { return tb_false; // would overflow } datasize++; } // determine architecture for symbol prefix adjustment tb_uint16_t machine = xm_binutils_coff_get_machine(arch); tb_bool_t is_i386 = (machine == XM_COFF_MACHINE_I386); // generate symbol names from filename tb_char_t symbol_name[256] = {0}; tb_char_t symbol_start[256] = {0}; tb_char_t symbol_end[256] = {0}; // use basename or default to "data" if (!basename || !basename[0]) { basename = "data"; } // build symbol name // note: on i386 Windows, C compiler automatically adds an underscore prefix to external symbols // so if we use "_binary_", the actual symbol becomes "__binary_" after compilation // to match, we need to ensure the prefix has two underscores for i386 if (symbol_prefix) { if (is_i386 && symbol_prefix[0] == '_' && symbol_prefix[1] != '_') { // i386: if prefix starts with single underscore, add another one tb_snprintf(symbol_name, sizeof(symbol_name), "_%s%s", symbol_prefix, basename); } else { tb_snprintf(symbol_name, sizeof(symbol_name), "%s%s", symbol_prefix, basename); } } else { if (is_i386) { tb_snprintf(symbol_name, sizeof(symbol_name), "__binary_%s", basename); } else { tb_snprintf(symbol_name, sizeof(symbol_name), "_binary_%s", basename); } } // replace non-alphanumeric with underscore xm_binutils_sanitize_symbol_name(symbol_name); tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name); tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name); // calculate offsets tb_uint32_t header_size = sizeof(xm_coff_header_t); tb_uint32_t section_header_size = sizeof(xm_coff_section_t); tb_uint32_t section_data_ofs = header_size + section_header_size; tb_uint32_t section_data_size = datasize; tb_uint32_t section_data_padding = (4 - (section_data_size & 3)) & 3; tb_uint32_t symbol_table_ofs = section_data_ofs + section_data_size + section_data_padding; // calculate string table size (content only, excluding the 4-byte size field) tb_uint32_t string_table_content_size = 0; tb_size_t start_len = tb_strlen(symbol_start); tb_size_t end_len = tb_strlen(symbol_end); if (start_len > 8) { string_table_content_size += (tb_uint32_t)(start_len + 1); } if (end_len > 8) { string_table_content_size += (tb_uint32_t)(end_len + 1); } // string table size field should include the size field itself tb_uint32_t string_table_size = 4 + string_table_content_size; // write COFF header xm_coff_header_t header; tb_memset(&header, 0, sizeof(header)); header.machine = machine; header.nsects = 1; header.time = 0; header.symtabofs = symbol_table_ofs; // note: COFF spec says nsyms is the number of symbol table entries (including aux entries) // section symbol (1) + aux entry (1) + start symbol (1) + end symbol (1) = 4 entries // total size: 4 * 18 = 72 bytes // i386 linker calculates string table as symtabofs + nsyms * 18 = symtabofs + 72 (correct) // when reading symbols, linker follows naux fields to skip aux entries correctly // from mingw i386 analysis: section symbols MUST have aux entry (naux=1) header.nsyms = 4; // 3 symbols + 1 aux entry header.opthdr = 0; header.flags = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) { return tb_false; } // write section header (.rdata) xm_coff_section_t section; tb_memset(§ion, 0, sizeof(section)); tb_strncpy(section.name, ".rdata", 8); section.vsize = datasize; section.vaddr = 0; section.size = datasize; section.ofs = section_data_ofs; section.relocofs = 0; section.linenoofs = 0; section.nreloc = 0; section.nlineno = 0; section.flags = XM_COFF_SECTION_RDATA; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion, sizeof(section))) { return tb_false; } // write section data if (!xm_binutils_stream_copy(istream, ostream, filesize)) { return tb_false; } // append null terminator if zeroend is true if (zeroend) { tb_byte_t zero = 0; if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } // align to 4 bytes if (section_data_padding > 0) { xm_binutils_coff_write_padding(ostream, section_data_padding); } // write symbol table // symbol 0: .rdata section symbol xm_coff_symbol_t sym_section; tb_memset(&sym_section, 0, sizeof(sym_section)); tb_strncpy(sym_section.n.shortname.name, ".rdata", 8); sym_section.value = 0; sym_section.sect = 1; // section index (1-based) sym_section.type = 0; // IMAGE_SYM_TYPE_NULL sym_section.scl = 3; // IMAGE_SYM_CLASS_STATIC // section symbol MUST have auxiliary entry for i386 compatibility (as seen in mingw-generated files) sym_section.naux = 1; // auxiliary entry (required for i386) if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_section, sizeof(sym_section))) { return tb_false; } // auxiliary entry for section (18 bytes total) xm_coff_aux_section_t aux_section; tb_memset(&aux_section, 0, sizeof(aux_section)); aux_section.length = datasize; aux_section.nreloc = 0; aux_section.nlineno = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&aux_section, sizeof(aux_section))) { return tb_false; } // symbol 1: _binary_xxx_start (or __binary_xxx_start for i386) tb_uint32_t strtab_offset = 4; // start after size field xm_binutils_coff_write_symbol_name(ostream, symbol_start, &strtab_offset); xm_coff_symbol_tail_t sym_start_tail; tb_memset(&sym_start_tail, 0, sizeof(sym_start_tail)); sym_start_tail.value = 0; sym_start_tail.sect = 1; sym_start_tail.type = 0; // IMAGE_SYM_TYPE_NULL sym_start_tail.scl = 2; // IMAGE_SYM_CLASS_EXTERNAL sym_start_tail.naux = 0; // no auxiliary entry if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start_tail, sizeof(sym_start_tail))) { return tb_false; } // symbol 2: _binary_xxx_end (or __binary_xxx_end for i386) xm_binutils_coff_write_symbol_name(ostream, symbol_end, &strtab_offset); xm_coff_symbol_tail_t sym_end_tail; tb_memset(&sym_end_tail, 0, sizeof(sym_end_tail)); sym_end_tail.value = datasize; sym_end_tail.sect = 1; sym_end_tail.type = 0; // IMAGE_SYM_TYPE_NULL sym_end_tail.scl = 2; // IMAGE_SYM_CLASS_EXTERNAL sym_end_tail.naux = 0; // no auxiliary entry if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end_tail, sizeof(sym_end_tail))) { return tb_false; } // write string table // symbol table size: section symbol (18) + aux entry (18) + start symbol (18) + end symbol (18) = 72 bytes // string table starts at symtabofs + 72, which matches nsyms * 18 = 4 * 18 = 72 if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&string_table_size, 4)) { return tb_false; } if (start_len > 8) { xm_binutils_coff_write_string(ostream, symbol_start, start_len); tb_byte_t null = 0; tb_stream_bwrit(ostream, &null, 1); } if (end_len > 8) { xm_binutils_coff_write_string(ostream, symbol_end, end_len); tb_byte_t null = 0; tb_stream_bwrit(ostream, &null, 1); } return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* generate COFF object file from binary file * * @param lua the lua state * @return 1 on success, 2 on failure (with error message on stack) */ tb_int_t xm_binutils_bin2coff(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the binaryfile tb_char_t const *binaryfile = luaL_checkstring(lua, 1); tb_check_return_val(binaryfile, 0); // get the outputfile tb_char_t const *outputfile = luaL_checkstring(lua, 2); tb_check_return_val(outputfile, 0); // get symbol prefix (optional) tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null; // get arch (optional) tb_char_t const *arch = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null; // get basename (optional) tb_char_t const *basename = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null; // get zeroend (optional, default: false) tb_bool_t zeroend = lua_toboolean(lua, 6); // do dump tb_bool_t ok = tb_false; tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO); tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); do { if (!tb_stream_open(istream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2coff: open %s failed", binaryfile); break; } if (!tb_stream_open(ostream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2coff: open %s failed", outputfile); break; } if (!xm_binutils_bin2coff_dump(istream, ostream, symbol_prefix, arch, basename, zeroend)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2coff: dump data failed"); break; } ok = tb_true; lua_pushboolean(lua, ok); } while (0); if (istream) { tb_stream_clos(istream); } istream = tb_null; if (ostream) { tb_stream_clos(ostream); } ostream = tb_null; return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/binutils/coff/deplibs.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file deplibs.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "deplibs_coff" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_uint32_t xm_binutils_coff_get_import_rva(tb_stream_ref_t istream, tb_uint16_t opthdr_size) { // save current offset tb_hize_t opt_offset = tb_stream_offset(istream); tb_uint32_t import_rva = 0; // read magic tb_uint16_t magic = 0; if (tb_stream_bread(istream, (tb_byte_t*)&magic, sizeof(magic))) { // seek back if (tb_stream_seek(istream, opt_offset)) { if (magic == XM_PE32_MAGIC) { xm_pe32_opt_header_t opt_header = {0}; if (tb_stream_bread(istream, (tb_byte_t*)&opt_header, tb_min(sizeof(opt_header), opthdr_size))) { if (opt_header.number_of_rva_and_sizes > 1) { import_rva = opt_header.data_directory[1].vaddr; } } } else if (magic == XM_PE32P_MAGIC) { xm_pe32p_opt_header_t opt_header = {0}; if (tb_stream_bread(istream, (tb_byte_t*)&opt_header, tb_min(sizeof(opt_header), opthdr_size))) { if (opt_header.number_of_rva_and_sizes > 1) { import_rva = opt_header.data_directory[1].vaddr; } } } } } return import_rva; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); tb_bool_t ok = tb_false; xm_coff_section_t* sections = tb_null; do { // read COFF header xm_coff_header_t header; if (!tb_stream_seek(istream, base_offset)) break; if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) break; // read optional header and import rva tb_uint32_t import_rva = 0; if (header.opthdr > 0) { import_rva = xm_binutils_coff_get_import_rva(istream, header.opthdr); } // read section headers if (header.nsects > 0) { sections = tb_nalloc_type(header.nsects, xm_coff_section_t); if (!sections) break; tb_hize_t section_offset = base_offset + sizeof(xm_coff_header_t) + header.opthdr; if (!tb_stream_seek(istream, section_offset)) break; if (!tb_stream_bread(istream, (tb_byte_t*)sections, header.nsects * sizeof(xm_coff_section_t))) break; } if (!sections) { if (header.nsects > 0) break; ok = tb_true; break; } tb_size_t result_count = 0; tb_bool_t failed = tb_false; for (tb_uint16_t i = 0; i < header.nsects; i++) { xm_coff_section_t* section = §ions[i]; // check if it is .idata section (import directory table) tb_bool_t found_idt = tb_false; tb_uint32_t idt_offset = 0; if (import_rva != 0) { // check if import rva is in this section if (import_rva >= section->vaddr && import_rva < section->vaddr + section->vsize) { idt_offset = section->ofs + (import_rva - section->vaddr); found_idt = tb_true; } } else { // fallback to check section name if (tb_strncmp(section->name, ".idata", 6) == 0) { idt_offset = section->ofs; found_idt = tb_true; } } if (found_idt) { /* read import directory table * The .idata section contains the Import Directory Table. * Each entry is 20 bytes (IMAGE_IMPORT_DESCRIPTOR). * The table ends with a null entry. */ /* We need to iterate over IMAGE_IMPORT_DESCRIPTOR entries. * struct IMAGE_IMPORT_DESCRIPTOR { * DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) * DWORD TimeDateStamp; // 0 if not bound, * DWORD ForwarderChain; // -1 if no forwarders * DWORD Name; // RVA to DLL name * DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) * }; */ if (!tb_stream_seek(istream, idt_offset)) { failed = tb_true; break; } while (1) { xm_coff_import_directory_table_t entry; if (!tb_stream_bread(istream, (tb_byte_t*)&entry, sizeof(entry))) { break; } // check for null entry (end of table) if (entry.original_first_thunk == 0 && entry.name_rva == 0) { break; } tb_uint32_t name_rva = tb_bits_le_to_ne_u32(entry.name_rva); if (name_rva != 0) { /* map RVA to file offset to read the name * We need to find the section that contains this RVA. */ tb_hize_t saved_pos_inner = tb_stream_offset(istream); tb_uint32_t name_file_offset = 0; // Find the section containing name_rva for (tb_uint16_t k = 0; k < header.nsects; k++) { xm_coff_section_t* s = §ions[k]; if (name_rva >= s->vaddr && name_rva < s->vaddr + s->vsize) { name_file_offset = s->ofs + (name_rva - s->vaddr); break; } } if (name_file_offset != 0) { tb_char_t dll_name[256]; if (xm_binutils_read_string(istream, name_file_offset, dll_name, sizeof(dll_name)) && dll_name[0]) { lua_pushinteger(lua, result_count + 1); lua_pushstring(lua, dll_name); lua_settable(lua, -3); result_count++; } } tb_stream_seek(istream, saved_pos_inner); } } break; } } tb_check_break(!failed); ok = tb_true; } while (0); if (sections) tb_free(sections); return ok; } ================================================ FILE: core/src/xmake/binutils/coff/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BINUTILS_COFF_PREFIX_H #define XM_BINUTILS_COFF_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_COFF_MACHINE_I386 0x014c #define XM_COFF_MACHINE_AMD64 0x8664 #define XM_COFF_MACHINE_ARM 0x01c0 #define XM_COFF_MACHINE_ARM64 0xaa64 // PE Optional Header Magic #define XM_PE32_MAGIC 0x10b #define XM_PE32P_MAGIC 0x20b // COFF section flags #define XM_COFF_SCN_CNT_CODE 0x20 // IMAGE_SCN_CNT_CODE #define XM_COFF_SCN_CNT_INITIALIZED_DATA 0x40 // IMAGE_SCN_CNT_INITIALIZED_DATA #define XM_COFF_SCN_CNT_UNINITIALIZED_DATA 0x80 // IMAGE_SCN_CNT_UNINITIALIZED_DATA #define XM_COFF_SECTION_RDATA 0x40000040 // IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ /* ////////////////////////////////////////////////////////////////////////////////////// * types */ #include "tbox/prefix/packed.h" typedef struct __xm_coff_header_t { tb_uint16_t machine; tb_uint16_t nsects; tb_uint32_t time; tb_uint32_t symtabofs; tb_uint32_t nsyms; tb_uint16_t opthdr; tb_uint16_t flags; } __tb_packed__ xm_coff_header_t; typedef struct __xm_pe32_data_directory_t { tb_uint32_t vaddr; tb_uint32_t size; } __tb_packed__ xm_pe32_data_directory_t; typedef struct __xm_pe32_opt_header_t { tb_uint16_t magic; tb_uint8_t major_linker_version; tb_uint8_t minor_linker_version; tb_uint32_t size_of_code; tb_uint32_t size_of_initialized_data; tb_uint32_t size_of_uninitialized_data; tb_uint32_t address_of_entry_point; tb_uint32_t base_of_code; tb_uint32_t base_of_data; tb_uint32_t image_base; tb_uint32_t section_alignment; tb_uint32_t file_alignment; tb_uint16_t major_operating_system_version; tb_uint16_t minor_operating_system_version; tb_uint16_t major_image_version; tb_uint16_t minor_image_version; tb_uint16_t major_subsystem_version; tb_uint16_t minor_subsystem_version; tb_uint32_t win32_version_value; tb_uint32_t size_of_image; tb_uint32_t size_of_headers; tb_uint32_t checksum; tb_uint16_t subsystem; tb_uint16_t dll_characteristics; tb_uint32_t size_of_stack_reserve; tb_uint32_t size_of_stack_commit; tb_uint32_t size_of_heap_reserve; tb_uint32_t size_of_heap_commit; tb_uint32_t loader_flags; tb_uint32_t number_of_rva_and_sizes; xm_pe32_data_directory_t data_directory[16]; } __tb_packed__ xm_pe32_opt_header_t; typedef struct __xm_pe32p_opt_header_t { tb_uint16_t magic; tb_uint8_t major_linker_version; tb_uint8_t minor_linker_version; tb_uint32_t size_of_code; tb_uint32_t size_of_initialized_data; tb_uint32_t size_of_uninitialized_data; tb_uint32_t address_of_entry_point; tb_uint32_t base_of_code; tb_uint64_t image_base; tb_uint32_t section_alignment; tb_uint32_t file_alignment; tb_uint16_t major_operating_system_version; tb_uint16_t minor_operating_system_version; tb_uint16_t major_image_version; tb_uint16_t minor_image_version; tb_uint16_t major_subsystem_version; tb_uint16_t minor_subsystem_version; tb_uint32_t win32_version_value; tb_uint32_t size_of_image; tb_uint32_t size_of_headers; tb_uint32_t checksum; tb_uint16_t subsystem; tb_uint16_t dll_characteristics; tb_uint64_t size_of_stack_reserve; tb_uint64_t size_of_stack_commit; tb_uint64_t size_of_heap_reserve; tb_uint64_t size_of_heap_commit; tb_uint32_t loader_flags; tb_uint32_t number_of_rva_and_sizes; xm_pe32_data_directory_t data_directory[16]; } __tb_packed__ xm_pe32p_opt_header_t; typedef struct __xm_coff_import_directory_table_t { tb_uint32_t original_first_thunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) tb_uint32_t time_date_stamp; // 0 if not bound, -1 if bound, and real date\time stamp in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) O.W. date/time stamp of DLL bound to (Old BIND) tb_uint32_t forwarder_chain; // -1 if no forwarders tb_uint32_t name_rva; // RVA to name tb_uint32_t first_thunk; // RVA to IAT (if bound this IAT has actual addresses) } __tb_packed__ xm_coff_import_directory_table_t; typedef struct __xm_coff_import_header_t { tb_uint16_t sig1; // 0 tb_uint16_t sig2; // 0xffff tb_uint16_t version; tb_uint16_t machine; tb_uint32_t time; tb_uint32_t size; // size of data tb_uint16_t ordinal; // ordinal or hint tb_uint16_t type; // type } __tb_packed__ xm_coff_import_header_t; typedef struct __xm_coff_anon_header_t { tb_uint16_t sig1; // 0 tb_uint16_t sig2; // 0xffff tb_uint16_t version; tb_uint16_t machine; tb_uint32_t time; tb_uint8_t clsid[16]; tb_uint32_t size; // size of data } __tb_packed__ xm_coff_anon_header_t; typedef struct __xm_coff_section_t { tb_char_t name[8]; tb_uint32_t vsize; tb_uint32_t vaddr; tb_uint32_t size; tb_uint32_t ofs; tb_uint32_t relocofs; tb_uint32_t linenoofs; tb_uint16_t nreloc; tb_uint16_t nlineno; tb_uint32_t flags; } __tb_packed__ xm_coff_section_t; typedef struct __xm_coff_symbol_t { union { struct { tb_char_t name[8]; } shortname; struct { tb_uint32_t zeros; tb_uint32_t offset; } longname; } n; tb_uint32_t value; tb_int16_t sect; tb_uint16_t type; tb_uint8_t scl; tb_uint8_t naux; } __tb_packed__ xm_coff_symbol_t; typedef struct __xm_coff_aux_section_t { tb_uint32_t length; tb_uint16_t nreloc; tb_uint16_t nlineno; tb_uint8_t reserved[10]; } __tb_packed__ xm_coff_aux_section_t; typedef struct __xm_coff_symbol_tail_t { tb_uint32_t value; tb_int16_t sect; tb_uint16_t type; tb_uint8_t scl; tb_uint8_t naux; } __tb_packed__ xm_coff_symbol_tail_t; #include "tbox/prefix/packed.h" /* ////////////////////////////////////////////////////////////////////////////////////// * inline implementation */ /* get machine type from architecture string * * @param arch the architecture string (e.g., "x86_64", "i386", "arm64") * @return the machine type */ static __tb_inline__ tb_uint16_t xm_binutils_coff_get_machine(tb_char_t const *arch) { if (!arch) { return XM_COFF_MACHINE_I386; } if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) { return XM_COFF_MACHINE_AMD64; } else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0) { return XM_COFF_MACHINE_ARM64; } else if (tb_strcmp(arch, "arm") == 0) { return XM_COFF_MACHINE_ARM; } else if (tb_strcmp(arch, "i386") == 0 || tb_strcmp(arch, "x86") == 0) { return XM_COFF_MACHINE_I386; } return XM_COFF_MACHINE_I386; } /* write string to stream * * @param ostream the output stream * @param str the string to write * @param len the length (0 for auto-detect) */ static __tb_inline__ tb_void_t xm_binutils_coff_write_string(tb_stream_ref_t ostream, tb_char_t const *str, tb_size_t len) { tb_assert_and_check_return(ostream && str); if (len == 0) { len = tb_strlen(str); } tb_stream_bwrit(ostream, (tb_byte_t const *)str, len); } /* write padding bytes to stream * * @param ostream the output stream * @param count the number of padding bytes */ static __tb_inline__ tb_void_t xm_binutils_coff_write_padding(tb_stream_ref_t ostream, tb_size_t count) { tb_assert_and_check_return(ostream); tb_byte_t zero = 0; while (count-- > 0) { tb_stream_bwrit(ostream, &zero, 1); } } /* write symbol name to stream (handles short and long names) * * @param ostream the output stream * @param name the symbol name * @param strtab_offset the string table offset (updated if long name) */ static __tb_inline__ tb_void_t xm_binutils_coff_write_symbol_name(tb_stream_ref_t ostream, tb_char_t const *name, tb_uint32_t *strtab_offset) { tb_assert_and_check_return(ostream && name && strtab_offset); tb_size_t len = tb_strlen(name); if (len <= 8) { // short name: store directly in symbol name field xm_binutils_coff_write_string(ostream, name, len); if (len < 8) { xm_binutils_coff_write_padding(ostream, 8 - len); } } else { // long name: store offset in string table tb_uint32_t zeros = 0; tb_stream_bwrit(ostream, (tb_byte_t const *)&zeros, 4); tb_stream_bwrit(ostream, (tb_byte_t const *)strtab_offset, 4); *strtab_offset += (tb_uint32_t)(len + 1); // +1 for null terminator } } /* ////////////////////////////////////////////////////////////////////////////////////// * readsyms inline implementation */ /* read string from COFF string table * * @param istream the input stream * @param strtab_offset the string table offset (including 4-byte size field) * @param offset the string offset (from start of string table content, after size field) * @return the string (static buffer, valid until next call) */ static __tb_inline__ tb_bool_t xm_binutils_coff_read_string(tb_stream_ref_t istream, tb_hize_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) { tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false); // In COFF format, the offset in symbol table is from the start of string table // (including the 4-byte size field). So offset=4 points to the first string after // the size field, offset=74 points to a string at position 74 from the start. // read string table size first to validate offset tb_uint32_t strtab_size = 0; tb_hize_t saved_pos = tb_stream_offset(istream); if (!tb_stream_seek(istream, strtab_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&strtab_size, 4)) { tb_stream_seek(istream, saved_pos); return tb_false; } // check offset (must be >= 4 to skip the size field, and < strtab_size) if (offset < 4 || offset >= strtab_size) { tb_stream_seek(istream, saved_pos); return tb_false; } // restore position and use common implementation tb_stream_seek(istream, saved_pos); return xm_binutils_read_string(istream, strtab_offset + offset, name, name_size); } /* get symbol name from COFF symbol entry * * @param istream the input stream * @param sym the symbol entry * @param strtab_offset the string table offset * @param name the buffer to store the symbol name * @param name_size the size of the buffer * @return tb_true on success, tb_false on failure */ static __tb_inline__ tb_bool_t xm_binutils_coff_get_symbol_name(tb_stream_ref_t istream, xm_coff_symbol_t const *sym, tb_hize_t strtab_offset, tb_char_t *name, tb_size_t name_size) { tb_assert_and_check_return_val(istream && sym && name && name_size > 0, tb_false); // check if it's a long name (first 4 bytes are zeros) if (sym->n.longname.zeros == 0) { // long name: read from string table return xm_binutils_coff_read_string(istream, strtab_offset, sym->n.longname.offset, name, name_size); } else { // short name: use directly tb_size_t len = tb_min(8, name_size - 1); tb_strncpy(name, sym->n.shortname.name, len); name[len] = '\0'; // trim trailing nulls while (len > 0 && name[len - 1] == '\0') { len--; } name[len] = '\0'; return tb_true; } } /* get symbol type character (nm-style) from COFF symbol * * @param scl the storage class * @param sect the section number (0 = undefined, 1-based) * @param sections the section headers array * @param nsects the number of sections * @return the type character (T/t/D/d/B/b/U) */ static __tb_inline__ tb_char_t xm_binutils_coff_get_symbol_type_char(tb_uint8_t scl, tb_int16_t sect, xm_coff_section_t const *sections, tb_uint16_t nsects) { // undefined symbol if (sect == 0) { return 'U'; } // check if external tb_bool_t is_external = (scl == 2); // IMAGE_SYM_CLASS_EXTERNAL // check section flags to determine type if (sections && sect > 0 && sect <= nsects) { tb_uint32_t flags = sections[sect - 1].flags; // section numbers are 1-based // IMAGE_SCN_CNT_CODE (0x20) - code section if (flags & XM_COFF_SCN_CNT_CODE) { return is_external ? 'T' : 't'; // text section } // IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80) - bss section if (flags & XM_COFF_SCN_CNT_UNINITIALIZED_DATA) { return is_external ? 'B' : 'b'; // bss section } // IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) - data section if (flags & XM_COFF_SCN_CNT_INITIALIZED_DATA) { return is_external ? 'D' : 'd'; // data section } } // fallback: use section number heuristic if (sect == 1) { return is_external ? 'T' : 't'; // text section } else if (sect == 2) { return is_external ? 'D' : 'd'; // data section } else if (sect == 3) { return is_external ? 'B' : 'b'; // bss section } return is_external ? 'S' : 's'; // other section } #endif ================================================ FILE: core/src/xmake/binutils/coff/readsyms.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file readsyms.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "readsyms_coff" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_binutils_coff_read_import_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_coff_header_t const* header) { // create result table lua_newtable(lua); /* check version * version is the low 16 bits of the time field (offset 4) * xm_coff_header_t: machine(2), nsects(2), time(4) * xm_coff_import_header_t: sig1(2), sig2(2), version(2), machine(2) */ tb_uint16_t version = header->time & 0xffff; if (version == 1) { // anonymous object header (used for CLSID) /* * @note we can not read symbols from the anonymous object (LTO/GL/LTCG), * because it does not contain the symbol table. */ xm_coff_anon_header_t anon_header; if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&anon_header, sizeof(anon_header))) { return tb_false; } } else { // import header xm_coff_import_header_t import_header; if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&import_header, sizeof(import_header))) { return tb_false; } // read symbol name (it follows the header) tb_char_t name[256] = {0}; tb_size_t pos = 0; tb_byte_t c; while (pos < sizeof(name) - 1) { if (!tb_stream_bread(istream, &c, 1)) { break; } if (c == 0) { break; } name[pos++] = (tb_char_t)c; } name[pos] = '\0'; if (name[0]) { lua_pushinteger(lua, 1); lua_newtable(lua); // name lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); // type lua_pushstring(lua, "type"); lua_pushstring(lua, "I"); lua_settable(lua, -3); lua_settable(lua, -3); } } return tb_true; } tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // read COFF header xm_coff_header_t header; if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { return tb_false; } // check if it is an import object if (header.machine == 0 && header.nsects == 0xffff) { return xm_binutils_coff_read_import_symbols(istream, base_offset, lua, &header); } // check if there are symbols if (header.nsyms == 0 || header.symtabofs == 0) { lua_newtable(lua); return tb_true; } // create result table lua_newtable(lua); // read string table offset (after symbol table) tb_uint32_t strtab_offset = header.symtabofs + header.nsyms * 18; // each symbol is 18 bytes // read section headers to determine section types xm_coff_section_t *sections = tb_null; if (header.nsects > 0) { sections = (xm_coff_section_t*)tb_malloc(header.nsects * sizeof(xm_coff_section_t)); if (sections) { tb_hize_t saved_pos = tb_stream_offset(istream); // section headers are after COFF header and optional header tb_uint32_t section_offset = sizeof(xm_coff_header_t) + (header.opthdr > 0 ? header.opthdr : 0); if (tb_stream_seek(istream, base_offset + section_offset)) { for (tb_uint16_t i = 0; i < header.nsects; i++) { if (!tb_stream_bread(istream, (tb_byte_t*)§ions[i], sizeof(xm_coff_section_t))) { break; } } } tb_stream_seek(istream, saved_pos); } } // read symbols if (!tb_stream_seek(istream, base_offset + header.symtabofs)) { if (sections) { tb_free(sections); } return tb_false; } tb_uint32_t sym_index = 0; tb_uint32_t sym_count = 0; while (sym_index < header.nsyms) { // read symbol xm_coff_symbol_t sym; if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) { if (sections) { tb_free(sections); } return tb_false; } tb_bool_t skip = tb_false; tb_char_t name[256] = {0}; if (!xm_binutils_coff_get_symbol_name(istream, &sym, base_offset + strtab_offset, name, sizeof(name)) || !name[0]) { skip = tb_true; } else if (name[0] == '.') { skip = tb_true; } else if (tb_strchr(name, '$') != tb_null || tb_strstr(name, ".constprop") != tb_null || tb_strstr(name, ".startup") != tb_null || tb_strstr(name, "ta$") != tb_null) { skip = tb_true; } if (!skip) { // create symbol table entry lua_pushinteger(lua, sym_count + 1); lua_newtable(lua); // name lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_coff_get_symbol_type_char(sym.scl, sym.sect, sections, header.nsects); tb_char_t type_str[2] = {type_char, '\0'}; lua_pushstring(lua, "type"); lua_pushstring(lua, type_str); lua_settable(lua, -3); lua_settable(lua, -3); sym_count++; } // skip to the next symbol, including auxiliary entries sym_index++; if (sym.naux > 0) { sym_index += sym.naux; if (!tb_stream_seek(istream, tb_stream_offset(istream) + sym.naux * 18)) { if (sections) { tb_free(sections); } return tb_false; } } } if (sections) { tb_free(sections); } return tb_true; } ================================================ FILE: core/src/xmake/binutils/deplibs.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file deplibs.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "deplibs" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "coff/prefix.h" #include "elf/prefix.h" #include "macho/prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * forward declarations */ extern tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_elf_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_macho_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* get dependent libraries from binary file (auto-detect format) * * @param lua the lua state * @return 1 on success (table on stack), 2 on failure (with error message on stack) */ tb_int_t xm_binutils_deplibs(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the binary file path tb_char_t const *binaryfile = luaL_checkstring(lua, 1); tb_check_return_val(binaryfile, 0); // open file tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO); if (!istream) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "open %s failed", binaryfile); return 2; } tb_bool_t ok = tb_false; do { if (!tb_stream_open(istream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "open %s failed", binaryfile); break; } // detect format tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "cannot detect file format"); break; } // create result list lua_newtable(lua); // get dependents based on format if (format == XM_BINUTILS_FORMAT_COFF) { if (!xm_binutils_coff_deplibs(istream, 0, lua)) { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "failed to parse COFF"); break; } } else if (format == XM_BINUTILS_FORMAT_PE) { // seek to e_lfanew if (!tb_stream_seek(istream, 0x3c)) { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "failed to seek to e_lfanew"); break; } // read e_lfanew tb_uint32_t e_lfanew = 0; if (!tb_stream_bread(istream, (tb_byte_t*)&e_lfanew, 4)) { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "failed to read e_lfanew"); break; } // e_lfanew is little endian e_lfanew = tb_bits_le_to_ne_u32(e_lfanew); // call coff deplibs with offset = e_lfanew + 4 (skip PE signature) if (!xm_binutils_coff_deplibs(istream, e_lfanew + 4, lua)) { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "failed to parse PE/COFF"); break; } } else if (format == XM_BINUTILS_FORMAT_MACHO) { if (!xm_binutils_macho_deplibs(istream, 0, lua)) { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "failed to parse Mach-O"); break; } } else if (format == XM_BINUTILS_FORMAT_ELF) { if (!xm_binutils_elf_deplibs(istream, 0, lua)) { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "failed to parse ELF"); break; } } else if (format == XM_BINUTILS_FORMAT_WASM) { } else { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "unsupported format %d", format); break; } ok = tb_true; } while (0); if (istream) { tb_stream_exit(istream); } return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/binutils/elf/bin2elf.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bin2elf.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bin2elf" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_char_t const *symbol_prefix, tb_char_t const *arch, tb_char_t const *basename, tb_bool_t zeroend) { tb_assert_and_check_return_val(istream && ostream, tb_false); // get file size tb_hong_t filesize = tb_stream_size(istream); if (filesize < 0 || filesize > 0xffffffffU) { return tb_false; } tb_uint32_t datasize = (tb_uint32_t)filesize; // add null terminator if zeroend is true if (zeroend) { if (datasize >= 0xffffffffU) { return tb_false; // would overflow } datasize++; } // generate symbol names from filename tb_char_t symbol_name[256] = {0}; tb_char_t symbol_start[256] = {0}; tb_char_t symbol_end[256] = {0}; // use basename or default to "data" if (!basename || !basename[0]) { basename = "data"; } // build symbol name if (symbol_prefix) { tb_snprintf(symbol_name, sizeof(symbol_name), "%s%s", symbol_prefix, basename); } else { tb_snprintf(symbol_name, sizeof(symbol_name), "_binary_%s", basename); } // replace non-alphanumeric with underscore xm_binutils_sanitize_symbol_name(symbol_name); tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name); tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name); // calculate offsets tb_uint32_t header_size = sizeof(xm_elf32_header_t); tb_uint32_t section_header_size = sizeof(xm_elf32_section_t); tb_uint32_t section_count = 6; // NULL, .rodata, .symtab, .strtab, .shstrtab, .note.GNU-stack tb_uint32_t section_headers_ofs = header_size; tb_uint32_t rodata_ofs = section_headers_ofs + section_count * section_header_size; tb_uint32_t rodata_size = datasize; tb_uint32_t rodata_padding = (4 - (rodata_size & 3)) & 3; // align to 4 bytes for 32-bit tb_uint32_t symtab_ofs = rodata_ofs + rodata_size + rodata_padding; tb_uint32_t symtab_size = 3 * sizeof(xm_elf32_symbol_t); // NULL, start, end tb_uint32_t symtab_padding = (4 - (symtab_size & 3)) & 3; // align to 4 bytes tb_uint32_t strtab_ofs = symtab_ofs + symtab_size + symtab_padding; // calculate string table size tb_size_t start_len = tb_strlen(symbol_start); tb_size_t end_len = tb_strlen(symbol_end); tb_uint32_t strtab_size = 1; // initial null byte strtab_size += (tb_uint32_t)(start_len + 1); strtab_size += (tb_uint32_t)(end_len + 1); tb_uint32_t strtab_padding = (4 - (strtab_size & 3)) & 3; // align to 4 bytes tb_uint32_t shstrtab_ofs = strtab_ofs + strtab_size + strtab_padding; // calculate section header string table size tb_uint32_t shstrtab_size = 1; // initial null byte shstrtab_size += 8; // ".rodata\0" (7 + 1) shstrtab_size += 8; // ".symtab\0" (7 + 1) shstrtab_size += 8; // ".strtab\0" (7 + 1) shstrtab_size += 10; // ".shstrtab\0" (9 + 1) shstrtab_size += 16; // ".note.GNU-stack\0" (15 + 1) // write ELF header xm_elf32_header_t header; tb_memset(&header, 0, sizeof(header)); header.e_ident[0] = 0x7f; header.e_ident[1] = 'E'; header.e_ident[2] = 'L'; header.e_ident[3] = 'F'; header.e_ident[XM_ELF_EI_CLASS] = XM_ELF_CLASS32; header.e_ident[5] = 1; // ELFDATA2LSB header.e_ident[6] = 1; // EV_CURRENT header.e_ident[7] = 0; // ELFOSABI_SYSV header.e_type = 1; // ET_REL header.e_machine = xm_binutils_elf_get_machine(arch); header.e_version = 1; header.e_shoff = section_headers_ofs; header.e_ehsize = header_size; header.e_shentsize = section_header_size; header.e_shnum = section_count; header.e_shstrndx = 4; // .shstrtab section index if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) { return tb_false; } // write section headers xm_elf32_section_t section_null; tb_memset(§ion_null, 0, sizeof(section_null)); if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_null, sizeof(section_null))) { return tb_false; } // write .rodata section header xm_elf32_section_t section_rodata; tb_memset(§ion_rodata, 0, sizeof(section_rodata)); section_rodata.sh_name = 1; // ".rodata" in shstrtab section_rodata.sh_type = XM_ELF_SHT_PROGBITS; section_rodata.sh_flags = XM_ELF_SHF_ALLOC; section_rodata.sh_offset = rodata_ofs; section_rodata.sh_size = rodata_size; section_rodata.sh_addralign = 4; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_rodata, sizeof(section_rodata))) { return tb_false; } // write .symtab section header xm_elf32_section_t section_symtab; tb_memset(§ion_symtab, 0, sizeof(section_symtab)); section_symtab.sh_name = 9; // ".symtab" in shstrtab section_symtab.sh_type = XM_ELF_SHT_SYMTAB; section_symtab.sh_offset = symtab_ofs; section_symtab.sh_size = symtab_size; section_symtab.sh_link = 3; // .strtab section index section_symtab.sh_info = 1; // first global symbol index section_symtab.sh_addralign = 4; section_symtab.sh_entsize = sizeof(xm_elf32_symbol_t); if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_symtab, sizeof(section_symtab))) { return tb_false; } // write .strtab section header xm_elf32_section_t section_strtab; tb_memset(§ion_strtab, 0, sizeof(section_strtab)); section_strtab.sh_name = 17; // ".strtab" in shstrtab section_strtab.sh_type = XM_ELF_SHT_STRTAB; section_strtab.sh_offset = strtab_ofs; section_strtab.sh_size = strtab_size; section_strtab.sh_addralign = 1; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_strtab, sizeof(section_strtab))) { return tb_false; } // write .shstrtab section header xm_elf32_section_t section_shstrtab; tb_memset(§ion_shstrtab, 0, sizeof(section_shstrtab)); section_shstrtab.sh_name = 25; // ".shstrtab" in shstrtab section_shstrtab.sh_type = XM_ELF_SHT_STRTAB; section_shstrtab.sh_offset = shstrtab_ofs; section_shstrtab.sh_size = shstrtab_size; section_shstrtab.sh_addralign = 1; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_shstrtab, sizeof(section_shstrtab))) { return tb_false; } // write .note.GNU-stack section header (empty section to mark stack as non-executable) xm_elf32_section_t section_note_gnu_stack; tb_memset(§ion_note_gnu_stack, 0, sizeof(section_note_gnu_stack)); section_note_gnu_stack.sh_name = 35; // ".note.GNU-stack" in shstrtab (25 + 10) section_note_gnu_stack.sh_type = XM_ELF_SHT_PROGBITS; section_note_gnu_stack.sh_flags = 0; // no flags section_note_gnu_stack.sh_offset = shstrtab_ofs + shstrtab_size; // after .shstrtab section_note_gnu_stack.sh_size = 0; // empty section section_note_gnu_stack.sh_addralign = 1; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_note_gnu_stack, sizeof(section_note_gnu_stack))) { return tb_false; } // write .rodata section data if (!xm_binutils_stream_copy(istream, ostream, filesize)) { return tb_false; } // append null terminator if zeroend is true if (zeroend) { tb_byte_t zero = 0; if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } // align .rodata to 4 bytes if (rodata_padding > 0) { tb_byte_t zero = 0; while (rodata_padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write symbol table // symbol 0: NULL symbol xm_elf32_symbol_t sym_null; tb_memset(&sym_null, 0, sizeof(sym_null)); if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_null, sizeof(sym_null))) { return tb_false; } // symbol 1: _binary_xxx_start xm_elf32_symbol_t sym_start; tb_memset(&sym_start, 0, sizeof(sym_start)); sym_start.st_name = 1; // offset in .strtab (after initial null) sym_start.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT; sym_start.st_shndx = 1; // .rodata section index sym_start.st_value = 0; sym_start.st_size = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start, sizeof(sym_start))) { return tb_false; } // symbol 2: _binary_xxx_end xm_elf32_symbol_t sym_end; tb_memset(&sym_end, 0, sizeof(sym_end)); sym_end.st_name = 1 + (tb_uint32_t)(start_len + 1); // offset in .strtab sym_end.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT; sym_end.st_shndx = 1; // .rodata section index sym_end.st_value = rodata_size; sym_end.st_size = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end, sizeof(sym_end))) { return tb_false; } // align .symtab to 4 bytes if (symtab_padding > 0) { tb_byte_t zero = 0; while (symtab_padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write string table tb_byte_t null = 0; if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } // align .strtab to 4 bytes if (strtab_padding > 0) { tb_byte_t zero = 0; while (strtab_padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write section header string table if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".rodata", 7)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".symtab", 7)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".strtab", 7)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".shstrtab", 9)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".note.GNU-stack", 15)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } return tb_true; } static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_char_t const *symbol_prefix, tb_char_t const *arch, tb_char_t const *basename, tb_bool_t zeroend) { tb_assert_and_check_return_val(istream && ostream, tb_false); // get file size tb_hong_t filesize = tb_stream_size(istream); if (filesize < 0 || filesize > 0xffffffffU) { return tb_false; } tb_uint32_t datasize = (tb_uint32_t)filesize; // add null terminator if zeroend is true if (zeroend) { if (datasize >= 0xffffffffU) { return tb_false; // would overflow } datasize++; } // generate symbol names from filename tb_char_t symbol_name[256] = {0}; tb_char_t symbol_start[256] = {0}; tb_char_t symbol_end[256] = {0}; // use basename or default to "data" if (!basename || !basename[0]) { basename = "data"; } // build symbol name if (symbol_prefix) { tb_snprintf(symbol_name, sizeof(symbol_name), "%s%s", symbol_prefix, basename); } else { tb_snprintf(symbol_name, sizeof(symbol_name), "_binary_%s", basename); } // replace non-alphanumeric with underscore xm_binutils_sanitize_symbol_name(symbol_name); tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name); tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name); // calculate offsets tb_uint32_t header_size = sizeof(xm_elf64_header_t); tb_uint32_t section_header_size = sizeof(xm_elf64_section_t); tb_uint32_t section_count = 6; // NULL, .rodata, .symtab, .strtab, .shstrtab, .note.GNU-stack tb_uint32_t section_headers_ofs = header_size; tb_uint32_t rodata_ofs = section_headers_ofs + section_count * section_header_size; tb_uint32_t rodata_size = datasize; tb_uint32_t rodata_padding = (8 - (rodata_size & 7)) & 7; tb_uint32_t symtab_ofs = rodata_ofs + rodata_size + rodata_padding; tb_uint32_t symtab_size = 3 * sizeof(xm_elf64_symbol_t); // NULL, start, end tb_uint32_t symtab_padding = (8 - (symtab_size & 7)) & 7; tb_uint32_t strtab_ofs = symtab_ofs + symtab_size + symtab_padding; // calculate string table size tb_size_t start_len = tb_strlen(symbol_start); tb_size_t end_len = tb_strlen(symbol_end); tb_uint32_t strtab_size = 1; // initial null byte strtab_size += (tb_uint32_t)(start_len + 1); strtab_size += (tb_uint32_t)(end_len + 1); tb_uint32_t strtab_padding = (8 - (strtab_size & 7)) & 7; // calculate section header string table size tb_uint32_t shstrtab_size = 1; // initial null byte shstrtab_size += 8; // ".rodata\0" (7 + 1) shstrtab_size += 8; // ".symtab\0" (7 + 1) shstrtab_size += 8; // ".strtab\0" (7 + 1) shstrtab_size += 10; // ".shstrtab\0" (9 + 1) shstrtab_size += 16; // ".note.GNU-stack\0" (15 + 1) tb_uint32_t shstrtab_ofs = strtab_ofs + strtab_size + strtab_padding; // write ELF header xm_elf64_header_t header; tb_memset(&header, 0, sizeof(header)); header.e_ident[0] = 0x7f; header.e_ident[1] = 'E'; header.e_ident[2] = 'L'; header.e_ident[3] = 'F'; header.e_ident[XM_ELF_EI_CLASS] = XM_ELF_CLASS64; header.e_ident[5] = 1; // ELFDATA2LSB header.e_ident[6] = 1; // EV_CURRENT header.e_ident[7] = 0; // ELFOSABI_SYSV header.e_type = 1; // ET_REL header.e_machine = xm_binutils_elf_get_machine(arch); header.e_version = 1; header.e_shoff = section_headers_ofs; header.e_ehsize = header_size; header.e_shentsize = section_header_size; header.e_shnum = section_count; header.e_shstrndx = 4; // .shstrtab section index if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) { return tb_false; } // write section headers xm_elf64_section_t section_null; tb_memset(§ion_null, 0, sizeof(section_null)); if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_null, sizeof(section_null))) { return tb_false; } // write .rodata section header xm_elf64_section_t section_rodata; tb_memset(§ion_rodata, 0, sizeof(section_rodata)); section_rodata.sh_name = 1; // ".rodata" in shstrtab section_rodata.sh_type = XM_ELF_SHT_PROGBITS; section_rodata.sh_flags = XM_ELF_SHF_ALLOC; section_rodata.sh_offset = rodata_ofs; section_rodata.sh_size = rodata_size; section_rodata.sh_addralign = 8; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_rodata, sizeof(section_rodata))) { return tb_false; } // write .symtab section header xm_elf64_section_t section_symtab; tb_memset(§ion_symtab, 0, sizeof(section_symtab)); section_symtab.sh_name = 9; // ".symtab" in shstrtab section_symtab.sh_type = XM_ELF_SHT_SYMTAB; section_symtab.sh_offset = symtab_ofs; section_symtab.sh_size = symtab_size; section_symtab.sh_link = 3; // .strtab section index section_symtab.sh_info = 1; // first global symbol index section_symtab.sh_addralign = 8; section_symtab.sh_entsize = sizeof(xm_elf64_symbol_t); if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_symtab, sizeof(section_symtab))) { return tb_false; } // write .strtab section header xm_elf64_section_t section_strtab; tb_memset(§ion_strtab, 0, sizeof(section_strtab)); section_strtab.sh_name = 17; // ".strtab" in shstrtab section_strtab.sh_type = XM_ELF_SHT_STRTAB; section_strtab.sh_offset = strtab_ofs; section_strtab.sh_size = strtab_size; section_strtab.sh_addralign = 1; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_strtab, sizeof(section_strtab))) { return tb_false; } // write .shstrtab section header xm_elf64_section_t section_shstrtab; tb_memset(§ion_shstrtab, 0, sizeof(section_shstrtab)); section_shstrtab.sh_name = 25; // ".shstrtab" in shstrtab section_shstrtab.sh_type = XM_ELF_SHT_STRTAB; section_shstrtab.sh_offset = shstrtab_ofs; // points to initial null byte section_shstrtab.sh_size = shstrtab_size; // size includes initial null and all strings section_shstrtab.sh_addralign = 1; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_shstrtab, sizeof(section_shstrtab))) { return tb_false; } // write .note.GNU-stack section header (empty section to mark stack as non-executable) xm_elf64_section_t section_note_gnu_stack; tb_memset(§ion_note_gnu_stack, 0, sizeof(section_note_gnu_stack)); section_note_gnu_stack.sh_name = 35; // ".note.GNU-stack" in shstrtab (25 + 10) section_note_gnu_stack.sh_type = XM_ELF_SHT_PROGBITS; section_note_gnu_stack.sh_flags = 0; // no flags section_note_gnu_stack.sh_offset = shstrtab_ofs + shstrtab_size; // after .shstrtab section_note_gnu_stack.sh_size = 0; // empty section section_note_gnu_stack.sh_addralign = 1; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_note_gnu_stack, sizeof(section_note_gnu_stack))) { return tb_false; } // write .rodata section data if (!xm_binutils_stream_copy(istream, ostream, filesize)) { return tb_false; } // append null terminator if zeroend is true if (zeroend) { tb_byte_t zero = 0; if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } // align .rodata to 8 bytes if (rodata_padding > 0) { tb_byte_t zero = 0; while (rodata_padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write symbol table // symbol 0: NULL symbol xm_elf64_symbol_t sym_null; tb_memset(&sym_null, 0, sizeof(sym_null)); if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_null, sizeof(sym_null))) { return tb_false; } // symbol 1: _binary_xxx_start xm_elf64_symbol_t sym_start; tb_memset(&sym_start, 0, sizeof(sym_start)); sym_start.st_name = 1; // offset in .strtab (after initial null) sym_start.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT; sym_start.st_shndx = 1; // .rodata section index sym_start.st_value = 0; sym_start.st_size = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start, sizeof(sym_start))) { return tb_false; } // symbol 2: _binary_xxx_end xm_elf64_symbol_t sym_end; tb_memset(&sym_end, 0, sizeof(sym_end)); sym_end.st_name = 1 + (tb_uint32_t)(start_len + 1); // offset in .strtab sym_end.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT; sym_end.st_shndx = 1; // .rodata section index sym_end.st_value = rodata_size; sym_end.st_size = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end, sizeof(sym_end))) { return tb_false; } // align .symtab to 8 bytes if (symtab_padding > 0) { tb_byte_t zero = 0; while (symtab_padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write string table tb_byte_t null = 0; if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } // align .strtab to 8 bytes if (strtab_padding > 0) { tb_byte_t zero = 0; while (strtab_padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write section header string table if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".rodata", 7)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".symtab", 7)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".strtab", 7)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".shstrtab", 9)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".note.GNU-stack", 15)) { return tb_false; } if (!tb_stream_bwrit(ostream, &null, 1)) { return tb_false; } return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* generate ELF object file from binary file * * local ok, errors = binutils.bin2elf(binaryfile, outputfile, symbol_prefix, arch, basename, zeroend) */ tb_int_t xm_binutils_bin2elf(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the binaryfile tb_char_t const *binaryfile = luaL_checkstring(lua, 1); tb_check_return_val(binaryfile, 0); // get the outputfile tb_char_t const *outputfile = luaL_checkstring(lua, 2); tb_check_return_val(outputfile, 0); // get symbol prefix (optional) tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null; // get arch (optional) tb_char_t const *arch = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null; // get basename (optional) tb_char_t const *basename = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null; // get zeroend (optional, default: false) tb_bool_t zeroend = lua_toboolean(lua, 6); // do dump tb_bool_t ok = tb_false; tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO); tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); do { if (!tb_stream_open(istream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2elf: open %s failed", binaryfile); break; } if (!tb_stream_open(ostream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2elf: open %s failed", outputfile); break; } // choose 32-bit or 64-bit ELF based on architecture tb_bool_t is_64bit = xm_binutils_elf_is_64bit(arch); if (is_64bit) { if (!xm_binutils_bin2elf_dump_64(istream, ostream, symbol_prefix, arch, basename, zeroend)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2elf: dump data failed"); break; } } else { if (!xm_binutils_bin2elf_dump_32(istream, ostream, symbol_prefix, arch, basename, zeroend)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2elf: dump data failed"); break; } } ok = tb_true; lua_pushboolean(lua, ok); } while (0); if (istream) tb_stream_clos(istream); istream = tb_null; if (ostream) tb_stream_clos(ostream); ostream = tb_null; return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/binutils/elf/deplibs.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file deplibs.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "deplibs_elf" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_binutils_elf_check_path(tb_char_t const* path, tb_char_t const* name, tb_char_t* output, tb_size_t output_size) { tb_char_t fullpath[TB_PATH_MAXN]; tb_snprintf(fullpath, sizeof(fullpath), "%s/%s", path, name); if (tb_file_info(fullpath, tb_null)) { if (output) { tb_strlcpy(output, fullpath, output_size); } return tb_true; } return tb_false; } static tb_void_t xm_binutils_elf_resolve_path(tb_char_t const* name, tb_char_t const* rpath, tb_char_t const* binary_dir, tb_char_t* output, tb_size_t output_size) { // absolute path? if (tb_path_is_absolute(name)) { tb_strlcpy(output, name, output_size); return; } // try rpath/runpath if (rpath && binary_dir) { tb_char_t const* p = rpath; tb_char_t const* e = tb_null; while (*p) { e = tb_strchr(p, ':'); tb_size_t n = e ? (tb_size_t)(e - p) : tb_strlen(p); if (n > 0) { tb_char_t path[TB_PATH_MAXN]; tb_char_t expanded_path[TB_PATH_MAXN]; tb_strncpy(path, p, n); path[n] = '\0'; // replace $ORIGIN tb_char_t* origin = tb_strstr(path, "$ORIGIN"); if (origin) { tb_long_t len = tb_snprintf(expanded_path, sizeof(expanded_path), "%.*s%s%s", (tb_int_t)(origin - path), path, binary_dir, origin + 7); if (len >= 0) { if (xm_binutils_elf_check_path(expanded_path, name, output, output_size)) { return; } } } else { if (xm_binutils_elf_check_path(path, name, output, output_size)) { return; } } } if (e) p = e + 1; else break; } } // try system paths static tb_char_t const* s_sys_paths[] = { "/lib", "/usr/lib", "/lib64", "/usr/lib64", "/usr/local/lib", "/usr/local/lib64", "/lib/x86_64-linux-gnu", // Debian/Ubuntu "/usr/lib/x86_64-linux-gnu", "/lib/i386-linux-gnu", "/usr/lib/i386-linux-gnu", "/lib/aarch64-linux-gnu", "/usr/lib/aarch64-linux-gnu", "/lib/arm-linux-gnueabihf", "/usr/lib/arm-linux-gnueabihf", tb_null }; for (tb_char_t const** sys_path = s_sys_paths; *sys_path; sys_path++) { if (xm_binutils_elf_check_path(*sys_path, name, output, output_size)) { return; } } // not found, return original name tb_strlcpy(output, name, output_size); } static tb_bool_t xm_binutils_elf_deplibs_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // read ELF header xm_elf32_header_t header; if (!xm_binutils_elf_read_header_32(istream, base_offset, &header)) { return tb_false; } // find program interpreter (PT_INTERP) and push tb_char_t name[256]; tb_size_t result_count = 0; if (xm_binutils_elf_find_interp_32(istream, base_offset, &header, name, sizeof(name))) { lua_pushinteger(lua, result_count + 1); lua_pushstring(lua, name); lua_settable(lua, -3); result_count++; } // build dynamic/string table context xm_elf_context_t ctx; if (!xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) { return tb_true; } // scan .dynamic entries: collect NEEDED and read RPATH/RUNPATH tb_uint32_t count = (tb_uint32_t)(ctx.dynamic_size / sizeof(xm_elf32_dynamic_t)); if (!tb_stream_seek(istream, base_offset + ctx.dynamic_offset)) { return tb_false; } tb_char_t rpath[8192] = {0}; tb_char_t runpath[8192] = {0}; tb_vector_ref_t needed_libs = tb_vector_init(0, tb_element_str(tb_true)); if (needed_libs) { for (tb_uint32_t i = 0; i < count; i++) { xm_elf32_dynamic_t dyn; if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) { break; } if (dyn.d_tag == XM_ELF_DT_NULL) { break; } if (dyn.d_tag == XM_ELF_DT_NEEDED || dyn.d_tag == XM_ELF_DT_SONAME || dyn.d_tag == XM_ELF_DT_AUXILIARY || dyn.d_tag == XM_ELF_DT_FILTER) { tb_char_t name[256]; if (xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, name, sizeof(name)) && name[0]) { tb_vector_insert_tail(needed_libs, name); } } else if (dyn.d_tag == XM_ELF_DT_RPATH) { xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, rpath, sizeof(rpath)); } else if (dyn.d_tag == XM_ELF_DT_RUNPATH) { xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, runpath, sizeof(runpath)); } } tb_char_t const* binary_path = tb_null; tb_char_t binary_dir[TB_PATH_MAXN] = {0}; if (tb_stream_ctrl(istream, TB_STREAM_CTRL_GET_PATH, &binary_path) && binary_path) { tb_path_directory(binary_path, binary_dir, sizeof(binary_dir)); } // resolve $ORIGIN and rpath/runpath, push full paths tb_for_all (tb_char_t const*, name, needed_libs) { tb_char_t fullpath[TB_PATH_MAXN]; xm_binutils_elf_resolve_path(name, runpath[0]? runpath : rpath, binary_dir[0]? binary_dir : tb_null, fullpath, sizeof(fullpath)); lua_pushinteger(lua, result_count + 1); lua_pushstring(lua, fullpath); lua_settable(lua, -3); result_count++; } tb_vector_exit(needed_libs); } return tb_true; } static tb_bool_t xm_binutils_elf_deplibs_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // read ELF header xm_elf64_header_t header; if (!xm_binutils_elf_read_header_64(istream, base_offset, &header)) { return tb_false; } // find program interpreter (PT_INTERP) and push tb_char_t name[256]; tb_size_t result_count = 0; if (xm_binutils_elf_find_interp_64(istream, base_offset, &header, name, sizeof(name))) { lua_pushinteger(lua, result_count + 1); lua_pushstring(lua, name); lua_settable(lua, -3); result_count++; } // build dynamic/string table context xm_elf_context_t ctx; if (!xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) { return tb_true; } // read dynamic entries tb_uint32_t count = (tb_uint32_t)(ctx.dynamic_size / sizeof(xm_elf64_dynamic_t)); if (!tb_stream_seek(istream, base_offset + ctx.dynamic_offset)) { return tb_false; } tb_char_t rpath[8192] = {0}; tb_char_t runpath[8192] = {0}; tb_vector_ref_t needed_libs = tb_vector_init(0, tb_element_str(tb_true)); if (needed_libs) { for (tb_uint32_t i = 0; i < count; i++) { xm_elf64_dynamic_t dyn; if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) { break; } if (dyn.d_tag == XM_ELF_DT_NULL) { break; } if (dyn.d_tag == XM_ELF_DT_NEEDED || dyn.d_tag == XM_ELF_DT_SONAME || dyn.d_tag == XM_ELF_DT_AUXILIARY || dyn.d_tag == XM_ELF_DT_FILTER) { tb_char_t name[256]; if (xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, name, sizeof(name)) && name[0]) { tb_vector_insert_tail(needed_libs, name); } } else if (dyn.d_tag == XM_ELF_DT_RPATH) { xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, rpath, sizeof(rpath)); } else if (dyn.d_tag == XM_ELF_DT_RUNPATH) { xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, runpath, sizeof(runpath)); } } // get binary directory tb_char_t const* binary_path = tb_null; tb_char_t binary_dir[TB_PATH_MAXN] = {0}; if (tb_stream_ctrl(istream, TB_STREAM_CTRL_GET_PATH, &binary_path) && binary_path) { tb_path_directory(binary_path, binary_dir, sizeof(binary_dir)); } // resolve and push paths tb_for_all (tb_char_t const*, name, needed_libs) { tb_char_t fullpath[TB_PATH_MAXN]; xm_binutils_elf_resolve_path(name, runpath[0]? runpath : rpath, binary_dir[0]? binary_dir : tb_null, fullpath, sizeof(fullpath)); lua_pushinteger(lua, result_count + 1); lua_pushstring(lua, fullpath); lua_settable(lua, -3); result_count++; } tb_vector_exit(needed_libs); } return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t xm_binutils_elf_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // read and check ELF magic tb_uint8_t magic[4]; if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, magic, 4)) { return tb_false; } if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') { return tb_false; } // check ELF class (32-bit or 64-bit) tb_uint8_t elf_class; if (!tb_stream_seek(istream, base_offset + 4)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) { return tb_false; } if (elf_class == 1) { return xm_binutils_elf_deplibs_32(istream, base_offset, lua); } else if (elf_class == 2) { return xm_binutils_elf_deplibs_64(istream, base_offset, lua); } return tb_false; } ================================================ FILE: core/src/xmake/binutils/elf/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BINUTILS_ELF_PREFIX_H #define XM_BINUTILS_ELF_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_ELF_MAGIC0 0x7f #define XM_ELF_MAGIC1 'E' #define XM_ELF_MAGIC2 'L' #define XM_ELF_MAGIC3 'F' // ELF class #define XM_ELF_EI_CLASS 4 #define XM_ELF_CLASS32 1 #define XM_ELF_CLASS64 2 #define XM_ELF_MACHINE_NONE 0x00 #define XM_ELF_MACHINE_SPARC 0x02 #define XM_ELF_MACHINE_I386 0x03 #define XM_ELF_MACHINE_MIPS 0x08 #define XM_ELF_MACHINE_POWERPC 0x14 #define XM_ELF_MACHINE_POWERPC64 0x15 #define XM_ELF_MACHINE_S390 0x16 #define XM_ELF_MACHINE_ARM 0x28 #define XM_ELF_MACHINE_SUPERH 0x2a #define XM_ELF_MACHINE_SPARC64 0x2b #define XM_ELF_MACHINE_IA_64 0x32 #define XM_ELF_MACHINE_X86_64 0x3e #define XM_ELF_MACHINE_RISCV 0xf3 #define XM_ELF_MACHINE_ARM64 0xb7 #define XM_ELF_MACHINE_WASM 0xe7 #define XM_ELF_MACHINE_LOONGARCH 0x102 #define XM_ELF_SHT_PROGBITS 0x1 #define XM_ELF_SHT_SYMTAB 0x2 #define XM_ELF_SHT_STRTAB 0x3 #define XM_ELF_SHT_DYNAMIC 0x6 #define XM_ELF_PT_LOAD 1 #define XM_ELF_PT_DYNAMIC 2 #define XM_ELF_PT_INTERP 3 #define XM_ELF_DT_NULL 0 #define XM_ELF_DT_NEEDED 1 #define XM_ELF_DT_STRTAB 5 #define XM_ELF_DT_STRSZ 10 #define XM_ELF_DT_SONAME 14 #define XM_ELF_DT_RPATH 15 #define XM_ELF_DT_RUNPATH 29 #define XM_ELF_DT_AUXILIARY 0x7ffffffd #define XM_ELF_DT_FILTER 0x7fffffff #define XM_ELF_SHF_ALLOC 0x2 #define XM_ELF_SHF_WRITE 0x1 #define XM_ELF_STB_GLOBAL 0x1 #define XM_ELF_STT_OBJECT 0x1 /* ////////////////////////////////////////////////////////////////////////////////////// * types */ #include "tbox/prefix/packed.h" typedef struct __xm_elf_context_t { tb_hize_t dynamic_offset; // file offset of .dynamic tb_hize_t dynamic_size; // size of .dynamic tb_hize_t strtab_offset; // file offset of .dynstr tb_hize_t strtab_size; // size of .dynstr tb_hize_t symtab_offset; // file offset of .symtab tb_hize_t symtab_size; // size of .symtab tb_hize_t symstr_offset; // file offset of .strtab (for .symtab) tb_hize_t symstr_size; // size of .strtab (for .symtab) tb_bool_t is64; } xm_elf_context_t; typedef struct __xm_elf32_header_t { tb_uint8_t e_ident[16]; tb_uint16_t e_type; tb_uint16_t e_machine; tb_uint32_t e_version; tb_uint32_t e_entry; tb_uint32_t e_phoff; tb_uint32_t e_shoff; tb_uint32_t e_flags; tb_uint16_t e_ehsize; tb_uint16_t e_phentsize; tb_uint16_t e_phnum; tb_uint16_t e_shentsize; tb_uint16_t e_shnum; tb_uint16_t e_shstrndx; } __tb_packed__ xm_elf32_header_t; typedef struct __xm_elf32_section_t { tb_uint32_t sh_name; tb_uint32_t sh_type; tb_uint32_t sh_flags; tb_uint32_t sh_addr; tb_uint32_t sh_offset; tb_uint32_t sh_size; tb_uint32_t sh_link; tb_uint32_t sh_info; tb_uint32_t sh_addralign; tb_uint32_t sh_entsize; } __tb_packed__ xm_elf32_section_t; typedef struct __xm_elf32_symbol_t { tb_uint32_t st_name; tb_uint32_t st_value; tb_uint32_t st_size; tb_uint8_t st_info; tb_uint8_t st_other; tb_uint16_t st_shndx; } __tb_packed__ xm_elf32_symbol_t; typedef struct __xm_elf32_phdr_t { tb_uint32_t p_type; tb_uint32_t p_offset; tb_uint32_t p_vaddr; tb_uint32_t p_paddr; tb_uint32_t p_filesz; tb_uint32_t p_memsz; tb_uint32_t p_flags; tb_uint32_t p_align; } __tb_packed__ xm_elf32_phdr_t; typedef struct __xm_elf64_header_t { tb_uint8_t e_ident[16]; tb_uint16_t e_type; tb_uint16_t e_machine; tb_uint32_t e_version; tb_uint64_t e_entry; tb_uint64_t e_phoff; tb_uint64_t e_shoff; tb_uint32_t e_flags; tb_uint16_t e_ehsize; tb_uint16_t e_phentsize; tb_uint16_t e_phnum; tb_uint16_t e_shentsize; tb_uint16_t e_shnum; tb_uint16_t e_shstrndx; } __tb_packed__ xm_elf64_header_t; typedef struct __xm_elf64_section_t { tb_uint32_t sh_name; tb_uint32_t sh_type; tb_uint64_t sh_flags; tb_uint64_t sh_addr; tb_uint64_t sh_offset; tb_uint64_t sh_size; tb_uint32_t sh_link; tb_uint32_t sh_info; tb_uint64_t sh_addralign; tb_uint64_t sh_entsize; } __tb_packed__ xm_elf64_section_t; typedef struct __xm_elf64_symbol_t { tb_uint32_t st_name; tb_uint8_t st_info; tb_uint8_t st_other; tb_uint16_t st_shndx; tb_uint64_t st_value; tb_uint64_t st_size; } __tb_packed__ xm_elf64_symbol_t; typedef struct __xm_elf64_phdr_t { tb_uint32_t p_type; tb_uint32_t p_flags; tb_uint64_t p_offset; tb_uint64_t p_vaddr; tb_uint64_t p_paddr; tb_uint64_t p_filesz; tb_uint64_t p_memsz; tb_uint64_t p_align; } __tb_packed__ xm_elf64_phdr_t; typedef struct __xm_elf32_dynamic_t { tb_int32_t d_tag; union { tb_uint32_t d_val; tb_uint32_t d_ptr; } d_un; } __tb_packed__ xm_elf32_dynamic_t; typedef struct __xm_elf64_dynamic_t { tb_int64_t d_tag; union { tb_uint64_t d_val; tb_uint64_t d_ptr; } d_un; } __tb_packed__ xm_elf64_dynamic_t; #include "tbox/prefix/packed.h" /* ////////////////////////////////////////////////////////////////////////////////////// * inline implementation */ /* get machine type from architecture string * * @param arch the architecture string (e.g., "x86_64", "i386", "arm64", "riscv") * @return the machine type */ static __tb_inline__ tb_uint16_t xm_binutils_elf_get_machine(tb_char_t const *arch) { if (!arch) { return XM_ELF_MACHINE_X86_64; } // x86/x86_64 if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) { return XM_ELF_MACHINE_X86_64; } else if (tb_strcmp(arch, "i386") == 0 || tb_strcmp(arch, "x86") == 0) { return XM_ELF_MACHINE_I386; } // ARM else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0 || tb_strcmp(arch, "arm64-v8a") == 0) { return XM_ELF_MACHINE_ARM64; } else if (tb_strcmp(arch, "arm") == 0 || tb_strcmp(arch, "armv7") == 0 || tb_strcmp(arch, "armeabi-v7a") == 0 || tb_strcmp(arch, "armv6") == 0 || tb_strcmp(arch, "armv5") == 0) { return XM_ELF_MACHINE_ARM; } // MIPS (MIPS and MIPS64 use same machine type, distinguished by ELF class) else if (tb_strncmp(arch, "mips", 4) == 0) { return XM_ELF_MACHINE_MIPS; } // PowerPC else if (tb_strncmp(arch, "ppc64", 5) == 0 || tb_strncmp(arch, "powerpc64", 9) == 0) { return XM_ELF_MACHINE_POWERPC64; } else if (tb_strncmp(arch, "ppc", 3) == 0 || tb_strncmp(arch, "powerpc", 7) == 0) { return XM_ELF_MACHINE_POWERPC; } // RISC-V (RISC-V and RISC-V64 use different machine types) else if (tb_strncmp(arch, "riscv64", 7) == 0 || (tb_strncmp(arch, "riscv", 5) == 0 && tb_strstr(arch, "64"))) { return XM_ELF_MACHINE_RISCV; // RISC-V 64-bit uses same machine type, distinguished by ELF class } else if (tb_strncmp(arch, "riscv", 5) == 0) { return XM_ELF_MACHINE_RISCV; } // SPARC else if (tb_strncmp(arch, "sparc64", 7) == 0) { return XM_ELF_MACHINE_SPARC64; } else if (tb_strncmp(arch, "sparc", 5) == 0) { return XM_ELF_MACHINE_SPARC; } // s390x else if (tb_strcmp(arch, "s390x") == 0 || tb_strcmp(arch, "s390") == 0) { return XM_ELF_MACHINE_S390; } // LoongArch (LoongArch and LoongArch64 use same machine type, distinguished by ELF class) else if (tb_strncmp(arch, "loongarch", 9) == 0 || tb_strncmp(arch, "loong64", 7) == 0) { return XM_ELF_MACHINE_LOONGARCH; } // WebAssembly (WASM and WASM64 use same machine type, distinguished by ELF class) else if (tb_strncmp(arch, "wasm", 4) == 0) { return XM_ELF_MACHINE_WASM; } // SuperH else if (tb_strncmp(arch, "sh", 2) == 0 || tb_strncmp(arch, "superh", 6) == 0) { return XM_ELF_MACHINE_SUPERH; } // IA-64 (Itanium) else if (tb_strcmp(arch, "ia64") == 0 || tb_strcmp(arch, "itanium") == 0) { return XM_ELF_MACHINE_IA_64; } return XM_ELF_MACHINE_X86_64; } /* check if architecture is 64-bit * * @param arch the architecture string * @return tb_true if 64-bit, tb_false otherwise */ static __tb_inline__ tb_bool_t xm_binutils_elf_is_64bit(tb_char_t const *arch) { return xm_binutils_arch_is_64bit(arch); } /* ////////////////////////////////////////////////////////////////////////////////////// * readsyms inline implementation */ /* get symbol type character (nm-style) from ELF symbol * * @param st_info the symbol info byte * @param st_shndx the section index (0 = undefined) * @return the type character (T/t/D/d/B/b/U) */ static __tb_inline__ tb_char_t xm_binutils_elf_get_symbol_type_char(tb_uint8_t st_info, tb_uint16_t st_shndx) { // undefined symbol if (st_shndx == 0) { return 'U'; } // check bind (global = uppercase, local = lowercase) tb_uint8_t bind = (st_info >> 4) & 0xf; tb_bool_t is_global = (bind == 1); // STB_GLOBAL // check type tb_uint8_t type = st_info & 0xf; if (type == 2) { // STT_FUNC return is_global ? 'T' : 't'; // text (function) } else if (type == 1) { // STT_OBJECT // For object symbols, we need section info to determine data/bss // For simplicity, we'll use 'D' for data, 'B' for bss // This is a heuristic - in practice, we'd need to check section flags return is_global ? 'D' : 'd'; // data (assume data section) } // other types return is_global ? 'S' : 's'; // other section } /* get symbol bind string from ELF symbol info * * @param st_info the symbol info byte * @return the bind string */ static __tb_inline__ tb_char_t const *xm_binutils_elf_get_symbol_bind(tb_uint8_t st_info) { tb_uint8_t bind = (st_info >> 4) & 0xf; switch (bind) { case 0: return "local"; case 1: return "global"; case 2: return "weak"; default: return "unknown"; } } // read ELF header (32-bit) static __tb_inline__ tb_bool_t xm_binutils_elf_read_header_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf32_header_t* header) { if (!tb_stream_seek(istream, base_offset)) return tb_false; if (!tb_stream_bread(istream, (tb_byte_t*)header, sizeof(*header))) return tb_false; return tb_true; } // read ELF header (64-bit) static __tb_inline__ tb_bool_t xm_binutils_elf_read_header_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf64_header_t* header) { if (!tb_stream_seek(istream, base_offset)) return tb_false; if (!tb_stream_bread(istream, (tb_byte_t*)header, sizeof(*header))) return tb_false; return tb_true; } static __tb_inline__ tb_bool_t xm_binutils_elf_get_context_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) { tb_memset(ctx, 0, sizeof(xm_elf_context_t)); ctx->is64 = tb_false; // read ELF header xm_elf32_header_t header; if (!xm_binutils_elf_read_header_32(istream, base_offset, &header)) return tb_false; // try to find from section headers first if (header.e_shoff != 0 && header.e_shnum > 0) { if (tb_stream_seek(istream, base_offset + header.e_shoff)) { for (tb_uint16_t i = 0; i < header.e_shnum; i++) { xm_elf32_section_t section; if (!tb_stream_bread(istream, (tb_byte_t*)§ion, sizeof(section))) break; if (section.sh_type == XM_ELF_SHT_DYNAMIC) { ctx->dynamic_offset = section.sh_offset; ctx->dynamic_size = section.sh_size; // find string table via sh_link xm_elf32_section_t strtab_section; if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf32_section_t)) && tb_stream_bread(istream, (tb_byte_t*)&strtab_section, sizeof(strtab_section))) { ctx->strtab_offset = strtab_section.sh_offset; ctx->strtab_size = strtab_section.sh_size; } } else if (section.sh_type == XM_ELF_SHT_SYMTAB) { ctx->symtab_offset = section.sh_offset; ctx->symtab_size = section.sh_size; xm_elf32_section_t symstr_section; if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf32_section_t)) && tb_stream_bread(istream, (tb_byte_t*)&symstr_section, sizeof(symstr_section))) { ctx->symstr_offset = symstr_section.sh_offset; ctx->symstr_size = symstr_section.sh_size; } } } } } // fallback to program headers if ((ctx->dynamic_offset == 0 || ctx->strtab_offset == 0) && header.e_phoff != 0 && header.e_phnum > 0) { if (tb_stream_seek(istream, base_offset + header.e_phoff)) { for (tb_uint16_t i = 0; i < header.e_phnum; i++) { xm_elf32_phdr_t phdr; if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break; if (phdr.p_type == XM_ELF_PT_DYNAMIC) { ctx->dynamic_offset = phdr.p_offset; ctx->dynamic_size = phdr.p_memsz; break; } } } if (ctx->dynamic_offset > 0 && ctx->dynamic_size > 0) { // read dynamic entries to find strtab address and size tb_uint64_t strtab_vaddr = 0; tb_uint64_t strtab_sz = 0; tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / sizeof(xm_elf32_dynamic_t)); if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) { for (tb_uint32_t i = 0; i < count; i++) { xm_elf32_dynamic_t dyn; if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break; if (dyn.d_tag == XM_ELF_DT_STRTAB) strtab_vaddr = dyn.d_un.d_val; else if (dyn.d_tag == XM_ELF_DT_STRSZ) strtab_sz = dyn.d_un.d_val; } } if (strtab_vaddr > 0) { // map strtab vaddr to file offset using PT_LOAD if (tb_stream_seek(istream, base_offset + header.e_phoff)) { for (tb_uint16_t i = 0; i < header.e_phnum; i++) { xm_elf32_phdr_t phdr; if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break; if (phdr.p_type == XM_ELF_PT_LOAD && strtab_vaddr >= phdr.p_vaddr && strtab_vaddr < phdr.p_vaddr + phdr.p_memsz) { ctx->strtab_offset = phdr.p_offset + (strtab_vaddr - phdr.p_vaddr); ctx->strtab_size = strtab_sz; break; } } } } } } return (ctx->dynamic_offset != 0 && ctx->strtab_offset != 0); } static __tb_inline__ tb_bool_t xm_binutils_elf_get_context_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) { tb_memset(ctx, 0, sizeof(xm_elf_context_t)); ctx->is64 = tb_true; // read ELF header xm_elf64_header_t header; if (!xm_binutils_elf_read_header_64(istream, base_offset, &header)) return tb_false; // try to find from section headers first if (header.e_shoff != 0 && header.e_shnum > 0) { if (tb_stream_seek(istream, base_offset + header.e_shoff)) { for (tb_uint16_t i = 0; i < header.e_shnum; i++) { xm_elf64_section_t section; if (!tb_stream_bread(istream, (tb_byte_t*)§ion, sizeof(section))) break; if (section.sh_type == XM_ELF_SHT_DYNAMIC) { ctx->dynamic_offset = section.sh_offset; ctx->dynamic_size = section.sh_size; // find string table via sh_link xm_elf64_section_t strtab_section; if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf64_section_t)) && tb_stream_bread(istream, (tb_byte_t*)&strtab_section, sizeof(strtab_section))) { ctx->strtab_offset = strtab_section.sh_offset; ctx->strtab_size = strtab_section.sh_size; } } else if (section.sh_type == XM_ELF_SHT_SYMTAB) { ctx->symtab_offset = section.sh_offset; ctx->symtab_size = section.sh_size; xm_elf64_section_t symstr_section; if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf64_section_t)) && tb_stream_bread(istream, (tb_byte_t*)&symstr_section, sizeof(symstr_section))) { ctx->symstr_offset = symstr_section.sh_offset; ctx->symstr_size = symstr_section.sh_size; } } } } } // fallback to program headers if ((ctx->dynamic_offset == 0 || ctx->strtab_offset == 0) && header.e_phoff != 0 && header.e_phnum > 0) { if (tb_stream_seek(istream, base_offset + header.e_phoff)) { for (tb_uint16_t i = 0; i < header.e_phnum; i++) { xm_elf64_phdr_t phdr; if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break; if (phdr.p_type == XM_ELF_PT_DYNAMIC) { ctx->dynamic_offset = phdr.p_offset; ctx->dynamic_size = phdr.p_memsz; break; } } } if (ctx->dynamic_offset > 0 && ctx->dynamic_size > 0) { // read dynamic entries to find strtab address and size tb_uint64_t strtab_vaddr = 0; tb_uint64_t strtab_sz = 0; tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / sizeof(xm_elf64_dynamic_t)); if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) { for (tb_uint32_t i = 0; i < count; i++) { xm_elf64_dynamic_t dyn; if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break; if (dyn.d_tag == XM_ELF_DT_STRTAB) strtab_vaddr = dyn.d_un.d_val; else if (dyn.d_tag == XM_ELF_DT_STRSZ) strtab_sz = dyn.d_un.d_val; } } if (strtab_vaddr > 0) { // map strtab vaddr to file offset using PT_LOAD if (tb_stream_seek(istream, base_offset + header.e_phoff)) { for (tb_uint16_t i = 0; i < header.e_phnum; i++) { xm_elf64_phdr_t phdr; if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break; if (phdr.p_type == XM_ELF_PT_LOAD && strtab_vaddr >= phdr.p_vaddr && strtab_vaddr < phdr.p_vaddr + phdr.p_memsz) { ctx->strtab_offset = phdr.p_offset + (strtab_vaddr - phdr.p_vaddr); ctx->strtab_size = strtab_sz; break; } } } } } } return (ctx->dynamic_offset != 0 && ctx->strtab_offset != 0); } // find PT_INTERP and read interpreter path (32-bit) static __tb_inline__ tb_bool_t xm_binutils_elf_find_interp_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf32_header_t const* header, tb_char_t* name, tb_size_t size) { if (header->e_phoff != 0 && header->e_phnum > 0) { if (tb_stream_seek(istream, base_offset + header->e_phoff)) { for (tb_uint16_t i = 0; i < header->e_phnum; i++) { xm_elf32_phdr_t phdr; if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break; if (phdr.p_type == XM_ELF_PT_INTERP) { return xm_binutils_read_string(istream, base_offset + phdr.p_offset, name, size) && name[0]; } } } } return tb_false; } // find PT_INTERP and read interpreter path (64-bit) static __tb_inline__ tb_bool_t xm_binutils_elf_find_interp_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf64_header_t const* header, tb_char_t* name, tb_size_t size) { if (header->e_phoff != 0 && header->e_phnum > 0) { if (tb_stream_seek(istream, base_offset + header->e_phoff)) { for (tb_uint16_t i = 0; i < header->e_phnum; i++) { xm_elf64_phdr_t phdr; if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break; if (phdr.p_type == XM_ELF_PT_INTERP) { return xm_binutils_read_string(istream, base_offset + phdr.p_offset, name, size) && name[0]; } } } } return tb_false; } #endif ================================================ FILE: core/src/xmake/binutils/elf/readsyms.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file readsyms.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "readsyms_elf" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // build context and ensure .symtab/.strtab are available xm_elf_context_t ctx; xm_binutils_elf_get_context_32(istream, base_offset, &ctx); if (!ctx.symtab_offset || !ctx.symstr_offset) { // no symbol table present: return empty result lua_newtable(lua); return tb_true; } // create result table lua_newtable(lua); // compute symbol count and seek to .symtab tb_uint32_t sym_count = (tb_uint32_t)(ctx.symtab_size / sizeof(xm_elf32_symbol_t)); if (!tb_stream_seek(istream, base_offset + ctx.symtab_offset)) { return tb_false; } tb_uint32_t result_count = 0; for (tb_uint32_t i = 0; i < sym_count; i++) { xm_elf32_symbol_t sym; if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) { return tb_false; } // skip NULL symbol entries if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) { continue; } // skip section/file symbols tb_uint8_t type = sym.st_info & 0xf; if (type == 3 || type == 4) { continue; } // read symbol name from .strtab tb_char_t name[256]; if (!xm_binutils_read_string(istream, base_offset + ctx.symstr_offset + sym.st_name, name, sizeof(name)) || !name[0]) { continue; } // skip internal ('.', '$') and local-defined symbols if (name[0] == '.' || name[0] == '$') { continue; } tb_uint8_t bind = (sym.st_info >> 4) & 0xf; if (bind == 0 && sym.st_shndx != 0) { continue; } // push symbol entry: name + nm-style type lua_pushinteger(lua, result_count + 1); lua_newtable(lua); lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); tb_char_t type_char = xm_binutils_elf_get_symbol_type_char(sym.st_info, sym.st_shndx); tb_char_t type_str[2] = {type_char, '\0'}; lua_pushstring(lua, "type"); lua_pushstring(lua, type_str); lua_settable(lua, -3); lua_settable(lua, -3); result_count++; } return tb_true; } tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // build context and ensure .symtab/.strtab are available xm_elf_context_t ctx; xm_binutils_elf_get_context_64(istream, base_offset, &ctx); if (!ctx.symtab_offset || !ctx.symstr_offset) { // no symbol table present: return empty result lua_newtable(lua); return tb_true; } // create result table lua_newtable(lua); // compute symbol count and seek to .symtab tb_uint32_t sym_count = (tb_uint32_t)(ctx.symtab_size / sizeof(xm_elf64_symbol_t)); if (!tb_stream_seek(istream, base_offset + ctx.symtab_offset)) { return tb_false; } tb_uint32_t result_count = 0; for (tb_uint32_t i = 0; i < sym_count; i++) { xm_elf64_symbol_t sym; if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) { return tb_false; } // skip NULL symbol entries if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) { continue; } // skip section/file symbols tb_uint8_t type = sym.st_info & 0xf; if (type == 3 || type == 4) { continue; } // read symbol name from .strtab tb_char_t name[256]; if (!xm_binutils_read_string(istream, base_offset + ctx.symstr_offset + sym.st_name, name, sizeof(name)) || !name[0]) { continue; } // skip internal ('.', '$') and local-defined symbols if (name[0] == '.' || name[0] == '$') { continue; } tb_uint8_t bind = (sym.st_info >> 4) & 0xf; if (bind == 0 && sym.st_shndx != 0) { continue; } // push symbol entry: name + nm-style type lua_pushinteger(lua, result_count + 1); lua_newtable(lua); lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); tb_char_t type_char = xm_binutils_elf_get_symbol_type_char(sym.st_info, sym.st_shndx); tb_char_t type_str[2] = {type_char, '\0'}; lua_pushstring(lua, "type"); lua_pushstring(lua, type_str); lua_settable(lua, -3); lua_settable(lua, -3); result_count++; } return tb_true; } tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // read and check ELF magic tb_uint8_t magic[4]; if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, magic, 4)) { return tb_false; } if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') { return tb_false; } // check ELF class (32-bit or 64-bit) tb_uint8_t elf_class; if (!tb_stream_seek(istream, base_offset + 4)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) { return tb_false; } if (elf_class == 1) { return xm_binutils_elf_read_symbols_32(istream, base_offset, lua); } else if (elf_class == 2) { return xm_binutils_elf_read_symbols_64(istream, base_offset, lua); } return tb_false; } ================================================ FILE: core/src/xmake/binutils/elf/rpath.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rpath.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rpath_elf" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_binutils_elf_add_rpaths(lua_State *lua, tb_char_t const* rpath, tb_size_t* pcount) { if (!rpath || !*rpath) return; tb_char_t path[TB_PATH_MAXN]; tb_char_t const* p = rpath; tb_char_t const* e = tb_null; while (*p) { e = tb_strchr(p, ':'); tb_size_t n = e ? (tb_size_t)(e - p) : tb_strlen(p); if (n > 0) { if (n > sizeof(path) - 1) n = sizeof(path) - 1; tb_strncpy(path, p, n); path[n] = '\0'; lua_pushinteger(lua, *pcount + 1); lua_pushstring(lua, path); lua_settable(lua, -3); (*pcount)++; } if (e) p = e + 1; else break; } } // parse .dynamic section and read DT_RPATH/DT_RUNPATH to build rpath list static tb_bool_t xm_binutils_elf_rpath_list_impl(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx, lua_State *lua) { tb_bool_t ok = tb_false; do { tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / (ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t))); if (!tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) break; tb_char_t rpath[8192] = {0}; tb_char_t runpath[8192] = {0}; // scan dynamic entries for (tb_uint32_t i = 0; i < count; i++) { tb_hize_t val = 0; tb_hize_t tag = 0; if (ctx->is64) { xm_elf64_dynamic_t dyn; if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break; tag = dyn.d_tag; val = dyn.d_un.d_val; } else { xm_elf32_dynamic_t dyn; if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break; tag = dyn.d_tag; val = dyn.d_un.d_val; } if (tag == XM_ELF_DT_NULL) break; // read rpath/runpath string from strtab if (tag == XM_ELF_DT_RPATH) { xm_binutils_read_string(istream, base_offset + ctx->strtab_offset + val, rpath, sizeof(rpath)); } else if (tag == XM_ELF_DT_RUNPATH) { xm_binutils_read_string(istream, base_offset + ctx->strtab_offset + val, runpath, sizeof(runpath)); } } // split rpath(s) and push into Lua table tb_size_t result_count = 0; if (runpath[0]) { xm_binutils_elf_add_rpaths(lua, runpath, &result_count); } else if (rpath[0]) { xm_binutils_elf_add_rpaths(lua, rpath, &result_count); } ok = tb_true; } while (0); return ok; } // remove DT_RPATH/DT_RUNPATH entries from .dynamic and write back static tb_bool_t xm_binutils_elf_rpath_clean_impl(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) { tb_bool_t ok = tb_false; tb_byte_t* buffer = tb_null; do { tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / (ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t))); // allocate buffer for all dynamic entries tb_size_t dyn_size = (tb_size_t)ctx->dynamic_size; buffer = (tb_byte_t*)tb_malloc(dyn_size); if (!buffer) break; if (!tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) break; if (!tb_stream_bread(istream, buffer, dyn_size)) break; // p: read pointer, w: write pointer after filtering tb_byte_t* p = buffer; tb_byte_t* w = buffer; tb_size_t entry_size = ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t); for (tb_uint32_t i = 0; i < count; i++) { tb_hize_t tag = 0; if (ctx->is64) { tag = ((xm_elf64_dynamic_t*)p)->d_tag; } else { tag = ((xm_elf32_dynamic_t*)p)->d_tag; } if (tag == XM_ELF_DT_NULL) { // copy NULL entry and stop tb_memcpy(w, p, entry_size); w += entry_size; p += entry_size; break; } // keep entries except rpath/runpath if (tag != XM_ELF_DT_RPATH && tag != XM_ELF_DT_RUNPATH) { if (w != p) tb_memcpy(w, p, entry_size); w += entry_size; } p += entry_size; } // fill remaining with NULLs if (w < buffer + dyn_size) { tb_memset(w, 0, (buffer + dyn_size) - w); } // write back if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) { tb_stream_bwrit(istream, buffer, dyn_size); } ok = tb_true; } while (0); if (buffer) tb_free(buffer); return ok; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t xm_binutils_elf_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); tb_bool_t ok = tb_false; do { // read ident tb_byte_t ident[16]; if (!tb_stream_seek(istream, base_offset)) break; if (!tb_stream_bread(istream, ident, sizeof(ident))) break; // build ELF context (dynamic, strtab offsets) xm_elf_context_t ctx; if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS32) { if (xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) { if (xm_binutils_elf_rpath_list_impl(istream, base_offset, &ctx, lua)) ok = tb_true; } } else if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS64) { if (xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) { if (xm_binutils_elf_rpath_list_impl(istream, base_offset, &ctx, lua)) ok = tb_true; } } } while (0); return ok; } tb_bool_t xm_binutils_elf_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset) { tb_assert_and_check_return_val(istream, tb_false); tb_bool_t ok = tb_false; do { // read ident tb_byte_t ident[16]; if (!tb_stream_seek(istream, base_offset)) break; if (!tb_stream_bread(istream, ident, sizeof(ident))) break; // build ELF context and cleanup rpath entries xm_elf_context_t ctx; if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS32) { if (xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) { if (xm_binutils_elf_rpath_clean_impl(istream, base_offset, &ctx)) ok = tb_true; } } else if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS64) { if (xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) { if (xm_binutils_elf_rpath_clean_impl(istream, base_offset, &ctx)) ok = tb_true; } } } while (0); return ok; } ================================================ FILE: core/src/xmake/binutils/extractlib.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file extractlib.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "extractlib" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "ar/prefix.h" #include "mslib/prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * forward declarations */ extern tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir); extern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* extract static library to directory (Lua interface) * Supports AR format (.a) and MSVC lib format (.lib) * * @param lua the lua state * * libraryfile = lua[1] * outputdir = lua[2] * plain = lua[3] (optional, default: true) * * @return 1 on success, 2 on failure (with error message) */ tb_int_t xm_binutils_extractlib(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the library file path tb_char_t const *libraryfile = luaL_checkstring(lua, 1); tb_check_return_val(libraryfile, 0); // get the output directory tb_char_t const *outputdir = luaL_checkstring(lua, 2); tb_check_return_val(outputdir, 0); // get the plain mode (optional) tb_bool_t plain = tb_true; if (lua_gettop(lua) >= 3 && !lua_isnil(lua, 3)) { plain = lua_toboolean(lua, 3); } // open library file tb_stream_ref_t istream = tb_stream_init_from_file(libraryfile, TB_FILE_MODE_RO); if (!istream) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "open %s failed", libraryfile); return 2; } tb_bool_t ok = tb_false; tb_char_t const* error_msg = tb_null; do { if (!tb_stream_open(istream)) { error_msg = "open failed"; break; } // detect format tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { error_msg = "cannot detect format"; break; } // extract based on format if (format == XM_BINUTILS_FORMAT_AR) { // AR archive format (.a or .lib in AR format) // if the file extension is .lib, we use the msvc lib extractor to support long paths and subdirectories tb_size_t n = tb_strlen(libraryfile); if (n > 4 && !tb_strnicmp(libraryfile + n - 4, ".lib", 4)) { if (!xm_binutils_mslib_extract(istream, outputdir, plain)) { error_msg = "extract MSVC lib failed"; break; } } else { if (!xm_binutils_ar_extract(istream, outputdir)) { error_msg = "extract AR archive failed"; break; } } ok = tb_true; } else if (format == XM_BINUTILS_FORMAT_COFF) { // MSVC lib format (.lib in COFF format) // Check if it's actually a library (not just a single object file) // MSVC lib files can be: // 1. Import libraries (different format) // 2. Static libraries (COFF archive format, similar to AR but different) if (!xm_binutils_mslib_extract(istream, outputdir, plain)) { error_msg = "extract MSVC lib failed"; break; } ok = tb_true; } else { error_msg = "unsupported format (only AR and MSVC lib are supported)"; break; } } while (0); if (istream) { tb_stream_clos(istream); tb_stream_exit(istream); } if (ok) { lua_pushboolean(lua, tb_true); return 1; } else { lua_pushboolean(lua, tb_false); if (error_msg) { lua_pushfstring(lua, "%s %s", error_msg, libraryfile); } else { lua_pushfstring(lua, "unknown error for %s", libraryfile); } return 2; } } ================================================ FILE: core/src/xmake/binutils/format.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file format.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "format" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ /* check PE by validating DOS header (MZ/ZM) and PE signature at e_lfanew * * note: unlike ELF/Mach-O/AR, PE needs an additional read/peek to locate the PE signature. */ static tb_bool_t xm_binutils_format_is_pe(tb_stream_ref_t istream, tb_byte_t* first8) { tb_assert_and_check_return_val(istream && first8, tb_false); tb_bool_t ok = tb_false; do { // fast reject: DOS magic tb_check_break((first8[0] == 'M' && first8[1] == 'Z') || (first8[0] == 'Z' && first8[1] == 'M')); // ensure we can read enough for DOS stub + PE signature tb_hong_t size = tb_stream_size(istream); if (size > 0 && size < XM_BINUTILS_PE_DOS_STUB_MIN_SIZE + 4) { break; } // peek a bounded prefix to locate e_lfanew and PE\\0\\0 signature tb_size_t max_peek = 4096; if (size > 0) { max_peek = (tb_size_t)tb_min((tb_hize_t)max_peek, (tb_hize_t)size); } tb_byte_t* p = tb_null; if (!tb_stream_peek(istream, &p, max_peek)) { break; } // e_lfanew points to PE signature offset tb_uint32_t e_lfanew = tb_bits_get_u32_le(p + XM_BINUTILS_PE_DOS_ELFANEW_OFFSET); tb_check_break(e_lfanew >= XM_BINUTILS_PE_DOS_STUB_MIN_SIZE); tb_check_break((tb_size_t)e_lfanew + 4 <= max_peek); tb_check_break(size <= 0 || (tb_hize_t)e_lfanew + 4 <= (tb_hize_t)size); tb_byte_t const* signature = p + (tb_size_t)e_lfanew; ok = (signature[0] == 'P' && signature[1] == 'E' && signature[2] == 0 && signature[3] == 0); } while (0); return ok; } // quick header checks from the first 8 bytes static __tb_inline__ tb_bool_t xm_binutils_format_is_ar(tb_byte_t const* first8) { return first8[0] == '!' && first8[1] == '<' && first8[2] == 'a' && first8[3] == 'r' && first8[4] == 'c' && first8[5] == 'h' && (first8[6] == '>' || first8[6] == '\n') && (first8[7] == '\n' || first8[7] == '\r'); } static __tb_inline__ tb_bool_t xm_binutils_format_is_shebang(tb_byte_t const* first2) { return first2[0] == '#' && first2[1] == '!'; } static __tb_inline__ tb_bool_t xm_binutils_format_is_ape(tb_byte_t const* first8) { return first8[0] == 'M' && first8[1] == 'Z' && first8[2] == 'q' && first8[3] == 'F' && first8[4] == 'p' && first8[5] == 'D'; } static __tb_inline__ tb_bool_t xm_binutils_format_is_wasm(tb_byte_t const* first8) { return first8[0] == 0x00 && first8[1] == 0x61 && first8[2] == 0x73 && first8[3] == 0x6d; } static __tb_inline__ tb_bool_t xm_binutils_format_is_elf(tb_byte_t const* first8) { return first8[0] == 0x7f && first8[1] == 'E' && first8[2] == 'L' && first8[3] == 'F'; } static __tb_inline__ tb_bool_t xm_binutils_format_is_macho(tb_byte_t const* first8) { return (first8[0] == 0xfe && first8[1] == 0xed && first8[2] == 0xfa && (first8[3] == 0xce || first8[3] == 0xcf)) || (first8[0] == 0xce && first8[1] == 0xfa && first8[2] == 0xed && first8[3] == 0xfe) || (first8[0] == 0xcf && first8[1] == 0xfa && first8[2] == 0xed && first8[3] == 0xfe); } static __tb_inline__ tb_bool_t xm_binutils_format_is_coff(tb_byte_t const* first8) { tb_uint16_t machine = tb_bits_get_u16_le(first8); if (machine == 0x0000) { tb_uint16_t machine2 = tb_bits_get_u16_le(first8 + 2); if (machine2 == 0xffff) { return tb_true; } } return machine == XM_BINUTILS_COFF_MACHINE_I386 || machine == XM_BINUTILS_COFF_MACHINE_AMD64 || machine == XM_BINUTILS_COFF_MACHINE_ARM || machine == XM_BINUTILS_COFF_MACHINE_ARM64; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* detect object file format from stream * * @param istream the input stream * @return XM_BINUTILS_FORMAT_COFF, XM_BINUTILS_FORMAT_ELF, XM_BINUTILS_FORMAT_MACHO, * XM_BINUTILS_FORMAT_AR, XM_BINUTILS_FORMAT_PE, XM_BINUTILS_FORMAT_UNKNOWN, or -1 on error */ tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream) { tb_assert_and_check_return_val(istream, -1); tb_assert_and_check_return_val(tb_stream_offset(istream) == 0, -1); tb_int_t format = -1; do { tb_byte_t* p2 = tb_null; if (!tb_stream_peek(istream, &p2, 2)) { tb_hong_t size = tb_stream_size(istream); if (size > 0 && size < 2) { format = XM_BINUTILS_FORMAT_UNKNOWN; } break; } if (xm_binutils_format_is_shebang(p2)) { format = XM_BINUTILS_FORMAT_SHEBANG; break; } tb_byte_t* p = tb_null; if (!tb_stream_peek(istream, &p, 8)) { tb_hong_t size = tb_stream_size(istream); if (size > 0 && size < 8) { format = XM_BINUTILS_FORMAT_UNKNOWN; } break; } if (xm_binutils_format_is_ar(p)) { format = XM_BINUTILS_FORMAT_AR; break; } if (xm_binutils_format_is_ape(p)) { format = XM_BINUTILS_FORMAT_APE; break; } if (xm_binutils_format_is_wasm(p)) { format = XM_BINUTILS_FORMAT_WASM; break; } if (xm_binutils_format_is_elf(p)) { format = XM_BINUTILS_FORMAT_ELF; break; } if (xm_binutils_format_is_macho(p)) { format = XM_BINUTILS_FORMAT_MACHO; break; } if (xm_binutils_format_is_pe(istream, p)) { format = XM_BINUTILS_FORMAT_PE; break; } if (xm_binutils_format_is_coff(p)) { format = XM_BINUTILS_FORMAT_COFF; break; } format = XM_BINUTILS_FORMAT_UNKNOWN; } while (0); return format; } /* ////////////////////////////////////////////////////////////////////////////////////// * lua implementation */ /* get binary file format (auto-detect format) * * local format, errors = binutils.format(filepath) */ tb_int_t xm_binutils_format(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the binary file path tb_char_t const *binaryfile = luaL_checkstring(lua, 1); tb_check_return_val(binaryfile, 0); // open file tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO); if (!istream) { lua_pushnil(lua); lua_pushfstring(lua, "open %s failed", binaryfile); return 2; } tb_bool_t ok = tb_false; do { if (!tb_stream_open(istream)) { lua_pushnil(lua); lua_pushfstring(lua, "open %s failed", binaryfile); break; } tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { lua_pushnil(lua); lua_pushliteral(lua, "cannot detect file format"); break; } switch (format) { case XM_BINUTILS_FORMAT_COFF: lua_pushliteral(lua, "coff"); break; case XM_BINUTILS_FORMAT_ELF: lua_pushliteral(lua, "elf"); break; case XM_BINUTILS_FORMAT_MACHO: lua_pushliteral(lua, "macho"); break; case XM_BINUTILS_FORMAT_AR: lua_pushliteral(lua, "ar"); break; case XM_BINUTILS_FORMAT_PE: lua_pushliteral(lua, "pe"); break; case XM_BINUTILS_FORMAT_SHEBANG: lua_pushliteral(lua, "shebang"); break; case XM_BINUTILS_FORMAT_APE: lua_pushliteral(lua, "ape"); break; case XM_BINUTILS_FORMAT_WASM: lua_pushliteral(lua, "wasm"); break; default: lua_pushliteral(lua, "unknown"); break; } ok = tb_true; } while (0); if (istream) { tb_stream_exit(istream); } return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/binutils/macho/bin2macho.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bin2macho.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bin2macho" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_binutils_bin2macho_dump_64(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_char_t const *symbol_prefix, tb_char_t const *plat, tb_char_t const *arch, tb_char_t const *basename, tb_uint32_t minos, tb_uint32_t sdk, tb_bool_t zeroend) { tb_assert_and_check_return_val(istream && ostream, tb_false); // get file size tb_hong_t filesize = tb_stream_size(istream); if (filesize < 0 || filesize > 0xffffffffU) { return tb_false; } tb_uint32_t datasize = (tb_uint32_t)filesize; // add null terminator if zeroend is true if (zeroend) { if (datasize >= 0xffffffffU) { return tb_false; // would overflow } datasize++; } // generate symbol names from filename tb_char_t symbol_name[256] = {0}; tb_char_t symbol_start[256] = {0}; tb_char_t symbol_end[256] = {0}; // use basename or default to "data" if (!basename || !basename[0]) { basename = "data"; } // build symbol name // On macOS, C compiler adds an underscore prefix, so we generate symbols with two underscores // (C code declares _binary_xxx, compiler generates __binary_xxx in object file, so we define __binary_xxx) if (symbol_prefix) { tb_snprintf(symbol_name, sizeof(symbol_name), "_%s%s", symbol_prefix, basename); } else { tb_snprintf(symbol_name, sizeof(symbol_name), "__binary_%s", basename); } // replace non-alphanumeric with underscore xm_binutils_sanitize_symbol_name(symbol_name); tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name); tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name); // calculate offsets tb_uint32_t header_size = sizeof(xm_macho_header_64_t); tb_uint32_t segment_cmd_size = sizeof(xm_macho_segment_command_64_t); tb_uint32_t section_size = sizeof(xm_macho_section_64_t); tb_uint32_t symtab_cmd_size = sizeof(xm_macho_symtab_command_t); tb_uint32_t build_version_cmd_size = sizeof(xm_macho_build_version_command_t); tb_uint32_t segment_cmd_total_size = segment_cmd_size + section_size; tb_uint32_t data_offset = xm_binutils_macho_align(header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size, 8); tb_uint32_t data_size = datasize; tb_uint32_t data_end_offset = data_offset + data_size; tb_uint32_t symtab_offset = xm_binutils_macho_align(data_end_offset, 8); tb_uint32_t nlist_size = sizeof(xm_macho_nlist_64_t); tb_uint32_t nlist_count = 2; // start, end tb_uint32_t strtab_offset = symtab_offset + nlist_size * nlist_count; tb_uint32_t strtab_size = 4; // initial 4-byte size field tb_size_t start_len = tb_strlen(symbol_start); tb_size_t end_len = tb_strlen(symbol_end); strtab_size += (tb_uint32_t)(start_len + 1); strtab_size += (tb_uint32_t)(end_len + 1); strtab_size = xm_binutils_macho_align(strtab_size, 8); // write Mach-O header xm_macho_header_64_t header; tb_memset(&header, 0, sizeof(header)); header.magic = XM_MACHO_MAGIC_64; header.cputype = xm_binutils_macho_get_cputype(arch); header.cpusubtype = xm_binutils_macho_get_cpusubtype(arch); header.filetype = XM_MACHO_FILE_TYPE_OBJECT; header.ncmds = 3; // segment + symtab + build_version header.sizeofcmds = segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size; header.flags = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) { return tb_false; } // write segment command xm_macho_segment_command_64_t segment; tb_memset(&segment, 0, sizeof(segment)); segment.cmd = XM_MACHO_LC_SEGMENT_64; segment.cmdsize = segment_cmd_total_size; tb_strncpy(segment.segname, "__TEXT", 16); segment.vmaddr = 0; segment.vmsize = data_size; segment.fileoff = data_offset; segment.filesize = data_size; segment.maxprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x) segment.initprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x) segment.nsects = 1; segment.flags = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&segment, sizeof(segment))) { return tb_false; } // write section xm_macho_section_64_t section; tb_memset(§ion, 0, sizeof(section)); tb_strncpy(section.sectname, "__const", 16); tb_strncpy(section.segname, "__TEXT", 16); section.addr = 0; section.size = data_size; section.offset = data_offset; section.align = 3; // 2^3 = 8 bytes section.reloff = 0; section.nreloc = 0; section.flags = XM_MACHO_SECT_TYPE_REGULAR | XM_MACHO_SECT_ATTR_SOME_INITS; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion, sizeof(section))) { return tb_false; } // write symtab command xm_macho_symtab_command_t symtab; tb_memset(&symtab, 0, sizeof(symtab)); symtab.cmd = XM_MACHO_LC_SYMTAB; symtab.cmdsize = symtab_cmd_size; symtab.symoff = symtab_offset; symtab.nsyms = nlist_count; symtab.stroff = strtab_offset; symtab.strsize = strtab_size; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&symtab, sizeof(symtab))) { return tb_false; } // write build version command xm_macho_build_version_command_t build_version; tb_memset(&build_version, 0, sizeof(build_version)); build_version.cmd = XM_MACHO_LC_BUILD_VERSION; build_version.cmdsize = build_version_cmd_size; build_version.platform = xm_binutils_macho_get_platform(plat); build_version.minos = minos; build_version.sdk = sdk; build_version.ntools = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&build_version, sizeof(build_version))) { return tb_false; } // align to 8 bytes tb_uint32_t padding = data_offset - (header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size); if (padding > 0) { tb_byte_t zero = 0; while (padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write section data if (!xm_binutils_stream_copy(istream, ostream, filesize)) { return tb_false; } // append null terminator if zeroend is true if (zeroend) { tb_byte_t zero = 0; if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } // align to 8 bytes padding = symtab_offset - data_end_offset; if (padding > 0) { tb_byte_t zero = 0; while (padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write symbol table // strx starts from 4 (after 4-byte size field) tb_uint32_t strx = 4; // symbol 0: _binary_xxx_start xm_macho_nlist_64_t nlist_start; tb_memset(&nlist_start, 0, sizeof(nlist_start)); nlist_start.strx = strx; nlist_start.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT nlist_start.sect = 1; nlist_start.desc = 0; nlist_start.value = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_start, sizeof(nlist_start))) { return tb_false; } strx += (tb_uint32_t)(start_len + 1); // symbol 1: _binary_xxx_end xm_macho_nlist_64_t nlist_end; tb_memset(&nlist_end, 0, sizeof(nlist_end)); nlist_end.strx = strx; nlist_end.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT nlist_end.sect = 1; nlist_end.desc = 0; nlist_end.value = data_size; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_end, sizeof(nlist_end))) { return tb_false; } strx += (tb_uint32_t)(end_len + 1); // align to 8 bytes padding = strtab_offset - (symtab_offset + nlist_size * nlist_count); if (padding > 0) { tb_byte_t zero = 0; while (padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write string table tb_stream_bwrit(ostream, (tb_byte_t const *)&strtab_size, 4); tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len); tb_byte_t null = 0; tb_stream_bwrit(ostream, &null, 1); tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len); tb_stream_bwrit(ostream, &null, 1); // align string table to 8 bytes padding = strtab_size - (4 + (tb_uint32_t)start_len + 1 + (tb_uint32_t)end_len + 1); if (padding > 0) { tb_byte_t zero = 0; while (padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } return tb_true; } static tb_bool_t xm_binutils_bin2macho_dump_32(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_char_t const *symbol_prefix, tb_char_t const *plat, tb_char_t const *arch, tb_char_t const *basename, tb_uint32_t minos, tb_uint32_t sdk, tb_bool_t zeroend) { tb_assert_and_check_return_val(istream && ostream, tb_false); // get file size tb_hong_t filesize = tb_stream_size(istream); if (filesize < 0 || filesize > 0xffffffffU) { return tb_false; } tb_uint32_t datasize = (tb_uint32_t)filesize; // add null terminator if zeroend is true if (zeroend) { if (datasize >= 0xffffffffU) { return tb_false; // would overflow } datasize++; } // generate symbol names from filename tb_char_t symbol_name[256] = {0}; tb_char_t symbol_start[256] = {0}; tb_char_t symbol_end[256] = {0}; // use basename or default to "data" if (!basename || !basename[0]) { basename = "data"; } // build symbol name // On macOS, C compiler adds an underscore prefix, so we generate symbols with two underscores // (C code declares _binary_xxx, compiler generates __binary_xxx in object file, so we define __binary_xxx) if (symbol_prefix) { tb_snprintf(symbol_name, sizeof(symbol_name), "_%s%s", symbol_prefix, basename); } else { tb_snprintf(symbol_name, sizeof(symbol_name), "__binary_%s", basename); } // replace non-alphanumeric with underscore xm_binutils_sanitize_symbol_name(symbol_name); tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name); tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name); // calculate offsets tb_uint32_t header_size = sizeof(xm_macho_header_32_t); tb_uint32_t segment_cmd_size = sizeof(xm_macho_segment_command_t); tb_uint32_t section_size = sizeof(xm_macho_section_t); tb_uint32_t symtab_cmd_size = sizeof(xm_macho_symtab_command_t); tb_uint32_t build_version_cmd_size = sizeof(xm_macho_build_version_command_t); tb_uint32_t segment_cmd_total_size = segment_cmd_size + section_size; tb_uint32_t data_offset = xm_binutils_macho_align(header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size, 4); tb_uint32_t data_size = datasize; tb_uint32_t data_end_offset = data_offset + data_size; tb_uint32_t symtab_offset = xm_binutils_macho_align(data_end_offset, 4); tb_uint32_t nlist_size = sizeof(xm_macho_nlist_t); tb_uint32_t nlist_count = 2; // start, end tb_uint32_t strtab_offset = symtab_offset + nlist_size * nlist_count; tb_uint32_t strtab_size = 4; // initial 4-byte size field tb_size_t start_len = tb_strlen(symbol_start); tb_size_t end_len = tb_strlen(symbol_end); strtab_size += (tb_uint32_t)(start_len + 1); strtab_size += (tb_uint32_t)(end_len + 1); strtab_size = xm_binutils_macho_align(strtab_size, 4); // write Mach-O header xm_macho_header_32_t header; tb_memset(&header, 0, sizeof(header)); header.magic = XM_MACHO_MAGIC_32; header.cputype = xm_binutils_macho_get_cputype(arch); header.cpusubtype = xm_binutils_macho_get_cpusubtype(arch); header.filetype = XM_MACHO_FILE_TYPE_OBJECT; header.ncmds = 3; // segment + symtab + build_version header.sizeofcmds = segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size; header.flags = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) { return tb_false; } // write segment command xm_macho_segment_command_t segment; tb_memset(&segment, 0, sizeof(segment)); segment.cmd = XM_MACHO_LC_SEGMENT; segment.cmdsize = segment_cmd_total_size; tb_strncpy(segment.segname, "__TEXT", 16); segment.vmaddr = 0; segment.vmsize = data_size; segment.fileoff = data_offset; segment.filesize = data_size; segment.maxprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x) segment.initprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x) segment.nsects = 1; segment.flags = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&segment, sizeof(segment))) { return tb_false; } // write section xm_macho_section_t section; tb_memset(§ion, 0, sizeof(section)); tb_strncpy(section.sectname, "__const", 16); tb_strncpy(section.segname, "__TEXT", 16); section.addr = 0; section.size = data_size; section.offset = data_offset; section.align = 2; // 2^2 = 4 bytes section.reloff = 0; section.nreloc = 0; section.flags = XM_MACHO_SECT_TYPE_REGULAR | XM_MACHO_SECT_ATTR_SOME_INITS; section.reserved1 = 0; section.reserved2 = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion, sizeof(section))) { return tb_false; } // write symtab command xm_macho_symtab_command_t symtab; tb_memset(&symtab, 0, sizeof(symtab)); symtab.cmd = XM_MACHO_LC_SYMTAB; symtab.cmdsize = symtab_cmd_size; symtab.symoff = symtab_offset; symtab.nsyms = nlist_count; symtab.stroff = strtab_offset; symtab.strsize = strtab_size; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&symtab, sizeof(symtab))) { return tb_false; } // write build version command xm_macho_build_version_command_t build_version; tb_memset(&build_version, 0, sizeof(build_version)); build_version.cmd = XM_MACHO_LC_BUILD_VERSION; build_version.cmdsize = build_version_cmd_size; build_version.platform = xm_binutils_macho_get_platform(plat); build_version.minos = minos; build_version.sdk = sdk; build_version.ntools = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&build_version, sizeof(build_version))) { return tb_false; } // align to 4 bytes tb_uint32_t padding = data_offset - (header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size); if (padding > 0) { tb_byte_t zero = 0; while (padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write section data if (!xm_binutils_stream_copy(istream, ostream, filesize)) { return tb_false; } // append null terminator if zeroend is true if (zeroend) { tb_byte_t zero = 0; if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } // align to 4 bytes padding = symtab_offset - data_end_offset; if (padding > 0) { tb_byte_t zero = 0; while (padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write symbol table // strx starts from 4 (after 4-byte size field) tb_uint32_t strx = 4; // symbol 0: _binary_xxx_start xm_macho_nlist_t nlist_start; tb_memset(&nlist_start, 0, sizeof(nlist_start)); nlist_start.strx = strx; nlist_start.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT nlist_start.sect = 1; nlist_start.desc = 0; nlist_start.value = 0; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_start, sizeof(nlist_start))) { return tb_false; } strx += (tb_uint32_t)(start_len + 1); // symbol 1: _binary_xxx_end xm_macho_nlist_t nlist_end; tb_memset(&nlist_end, 0, sizeof(nlist_end)); nlist_end.strx = strx; nlist_end.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT nlist_end.sect = 1; nlist_end.desc = 0; nlist_end.value = data_size; if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_end, sizeof(nlist_end))) { return tb_false; } strx += (tb_uint32_t)(end_len + 1); // align to 4 bytes padding = strtab_offset - (symtab_offset + nlist_size * nlist_count); if (padding > 0) { tb_byte_t zero = 0; while (padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } // write string table tb_stream_bwrit(ostream, (tb_byte_t const *)&strtab_size, 4); tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len); tb_byte_t null = 0; tb_stream_bwrit(ostream, &null, 1); tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len); tb_stream_bwrit(ostream, &null, 1); // align string table to 4 bytes padding = strtab_size - (4 + (tb_uint32_t)start_len + 1 + (tb_uint32_t)end_len + 1); if (padding > 0) { tb_byte_t zero = 0; while (padding-- > 0) { if (!tb_stream_bwrit(ostream, &zero, 1)) { return tb_false; } } } return tb_true; } static tb_bool_t xm_binutils_bin2macho_dump(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_char_t const *symbol_prefix, tb_char_t const *plat, tb_char_t const *arch, tb_char_t const *basename, tb_uint32_t minos, tb_uint32_t sdk, tb_bool_t zeroend) { if (xm_binutils_macho_is_64bit(arch)) { return xm_binutils_bin2macho_dump_64(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend); } else { return xm_binutils_bin2macho_dump_32(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend); } } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* generate Mach-O object file from binary file * * local ok, errors = binutils.bin2macho(binaryfile, outputfile, symbol_prefix, plat, arch, basename) */ tb_int_t xm_binutils_bin2macho(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the binaryfile tb_char_t const *binaryfile = luaL_checkstring(lua, 1); tb_check_return_val(binaryfile, 0); // get the outputfile tb_char_t const *outputfile = luaL_checkstring(lua, 2); tb_check_return_val(outputfile, 0); // get symbol prefix (optional) tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null; // get plat (optional) tb_char_t const *plat = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null; // get arch (optional) tb_char_t const *arch = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null; // get basename (optional) tb_char_t const *basename = lua_isstring(lua, 6) ? lua_tostring(lua, 6) : tb_null; // get minos version string (optional) tb_char_t const *minos_str = lua_isstring(lua, 7) ? lua_tostring(lua, 7) : tb_null; tb_uint32_t minos = xm_binutils_macho_parse_version(minos_str); // get sdk version string (optional) tb_char_t const *sdk_str = lua_isstring(lua, 8) ? lua_tostring(lua, 8) : tb_null; tb_uint32_t sdk = xm_binutils_macho_parse_version(sdk_str); // get zeroend (optional, default: false) tb_bool_t zeroend = lua_toboolean(lua, 9); // do dump tb_bool_t ok = tb_false; tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO); tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); do { if (!tb_stream_open(istream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2macho: open %s failed", binaryfile); break; } if (!tb_stream_open(ostream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2macho: open %s failed", outputfile); break; } if (!xm_binutils_bin2macho_dump(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2macho: dump data failed"); break; } ok = tb_true; lua_pushboolean(lua, ok); } while (0); if (istream) { tb_stream_clos(istream); } istream = tb_null; if (ostream) { tb_stream_clos(ostream); } ostream = tb_null; return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/binutils/macho/deplibs.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file deplibs.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "deplibs_macho" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t xm_binutils_macho_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // init Mach-O context xm_macho_context_t context; if (!xm_binutils_macho_context_init(istream, base_offset, &context)) { return tb_false; } // skip header to reach load commands tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t); if (!tb_stream_seek(istream, base_offset + header_size)) { return tb_false; } lua_newtable(lua); tb_size_t result_count = 0; // iterate load commands for (tb_uint32_t i = 0; i < context.ncmds; i++) { xm_macho_load_command_t lc; tb_hize_t current_cmd_offset = tb_stream_offset(istream); if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) { return tb_false; } xm_binutils_macho_swap_load_command(&lc, context.swap); // check for LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_ID_DYLIB if (lc.cmd == XM_MACHO_LC_LOAD_DYLIB || lc.cmd == XM_MACHO_LC_ID_DYLIB || lc.cmd == XM_MACHO_LC_LOAD_WEAK_DYLIB || lc.cmd == XM_MACHO_LC_REEXPORT_DYLIB) { xm_macho_dylib_command_t dc; if (tb_stream_seek(istream, current_cmd_offset)) { if (tb_stream_bread(istream, (tb_byte_t*)&dc, sizeof(dc))) { xm_binutils_macho_swap_dylib_command(&dc, context.swap); tb_uint32_t name_offset = dc.dylib.offset; if (name_offset < lc.cmdsize) { // name is at current_cmd_offset + name_offset if (tb_stream_seek(istream, current_cmd_offset + name_offset)) { tb_char_t dylib_path[1024]; tb_size_t max_len = lc.cmdsize - name_offset; if (max_len > sizeof(dylib_path) - 1) max_len = sizeof(dylib_path) - 1; tb_size_t pos = 0; tb_byte_t c; while (pos < max_len) { if (!tb_stream_bread(istream, &c, 1)) break; if (c == 0) break; dylib_path[pos++] = (tb_char_t)c; } dylib_path[pos] = '\0'; if (pos > 0) { lua_pushinteger(lua, result_count + 1); lua_pushstring(lua, dylib_path); lua_settable(lua, -3); result_count++; } } } } } } // move to next command if (!tb_stream_seek(istream, current_cmd_offset + lc.cmdsize)) { break; } } return tb_true; } ================================================ FILE: core/src/xmake/binutils/macho/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BINUTILS_MACHO_PREFIX_H #define XM_BINUTILS_MACHO_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_MACHO_MAGIC_32 0xfeedface // MH_MAGIC - little endian #define XM_MACHO_MAGIC_64 0xfeedfacf // MH_MAGIC_64 - little endian #define XM_MACHO_MAGIC_32_BE 0xcefaedfe // MH_CIGAM - big endian #define XM_MACHO_MAGIC_64_BE 0xcffaedfe // MH_CIGAM_64 - big endian #define XM_MACHO_MAGIC_FAT 0xcafebabe #define XM_MACHO_CPU_TYPE_X86 7 #define XM_MACHO_CPU_TYPE_X86_64 0x01000007 #define XM_MACHO_CPU_TYPE_ARM 12 #define XM_MACHO_CPU_TYPE_ARM64 0x0100000c #define XM_MACHO_CPU_SUBTYPE_X86 3 #define XM_MACHO_CPU_SUBTYPE_X86_64 3 #define XM_MACHO_CPU_SUBTYPE_ARM 9 #define XM_MACHO_CPU_SUBTYPE_ARM64 0 #define XM_MACHO_FILE_TYPE_OBJECT 1 #define XM_MACHO_LC_SEGMENT 0x1 #define XM_MACHO_LC_SEGMENT_64 0x19 #define XM_MACHO_LC_SYMTAB 0x2 #define XM_MACHO_LC_LOAD_DYLIB 0xc #define XM_MACHO_LC_ID_DYLIB 0xd #define XM_MACHO_LC_RPATH (0x1c | 0x80000000) #define XM_MACHO_LC_LOAD_WEAK_DYLIB (0x18 | 0x80000000) #define XM_MACHO_LC_REEXPORT_DYLIB (0x1f | 0x80000000) #define XM_MACHO_LC_BUILD_VERSION 0x32 #define XM_MACHO_PLATFORM_MACOS 1 #define XM_MACHO_PLATFORM_IOS 2 #define XM_MACHO_PLATFORM_TVOS 3 #define XM_MACHO_PLATFORM_WATCHOS 4 #define XM_MACHO_SECT_TYPE_REGULAR 0x0 #define XM_MACHO_SECT_ATTR_SOME_INITS 0x400 #define XM_MACHO_SECT_ATTR_PURE_INSTRUCTIONS 0x80000000 #define XM_MACHO_N_TYPE_MASK 0x0e #define XM_MACHO_N_TYPE_SECT 0x0e #define XM_MACHO_N_EXT 0x01 #define XM_MACHO_VM_PROT_READ 1 #define XM_MACHO_VM_PROT_WRITE 2 #define XM_MACHO_VM_PROT_EXECUTE 4 /* ////////////////////////////////////////////////////////////////////////////////////// * types */ #include "tbox/prefix/packed.h" typedef struct __xm_macho_header_32_t { tb_uint32_t magic; tb_uint32_t cputype; tb_uint32_t cpusubtype; tb_uint32_t filetype; tb_uint32_t ncmds; tb_uint32_t sizeofcmds; tb_uint32_t flags; } __tb_packed__ xm_macho_header_32_t; typedef struct __xm_macho_header_64_t { tb_uint32_t magic; tb_uint32_t cputype; tb_uint32_t cpusubtype; tb_uint32_t filetype; tb_uint32_t ncmds; tb_uint32_t sizeofcmds; tb_uint32_t flags; tb_uint32_t reserved; } __tb_packed__ xm_macho_header_64_t; typedef struct __xm_macho_rpath_command_t { tb_uint32_t cmd; tb_uint32_t cmdsize; tb_uint32_t path_offset; } __tb_packed__ xm_macho_rpath_command_t; typedef struct __xm_macho_segment_command_t { tb_uint32_t cmd; tb_uint32_t cmdsize; tb_char_t segname[16]; tb_uint32_t vmaddr; tb_uint32_t vmsize; tb_uint32_t fileoff; tb_uint32_t filesize; tb_uint32_t maxprot; tb_uint32_t initprot; tb_uint32_t nsects; tb_uint32_t flags; } __tb_packed__ xm_macho_segment_command_t; typedef struct __xm_macho_segment_command_64_t { tb_uint32_t cmd; tb_uint32_t cmdsize; tb_char_t segname[16]; tb_uint64_t vmaddr; tb_uint64_t vmsize; tb_uint64_t fileoff; tb_uint64_t filesize; tb_uint32_t maxprot; tb_uint32_t initprot; tb_uint32_t nsects; tb_uint32_t flags; } __tb_packed__ xm_macho_segment_command_64_t; typedef struct __xm_macho_section_t { tb_char_t sectname[16]; tb_char_t segname[16]; tb_uint32_t addr; tb_uint32_t size; tb_uint32_t offset; tb_uint32_t align; tb_uint32_t reloff; tb_uint32_t nreloc; tb_uint32_t flags; tb_uint32_t reserved1; tb_uint32_t reserved2; } __tb_packed__ xm_macho_section_t; typedef struct __xm_macho_section_64_t { tb_char_t sectname[16]; tb_char_t segname[16]; tb_uint64_t addr; tb_uint64_t size; tb_uint32_t offset; tb_uint32_t align; tb_uint32_t reloff; tb_uint32_t nreloc; tb_uint32_t flags; tb_uint32_t reserved1; tb_uint32_t reserved2; tb_uint32_t reserved3; } __tb_packed__ xm_macho_section_64_t; typedef struct __xm_macho_symtab_command_t { tb_uint32_t cmd; tb_uint32_t cmdsize; tb_uint32_t symoff; tb_uint32_t nsyms; tb_uint32_t stroff; tb_uint32_t strsize; } __tb_packed__ xm_macho_symtab_command_t; typedef struct __xm_macho_build_version_command_t { tb_uint32_t cmd; tb_uint32_t cmdsize; tb_uint32_t platform; tb_uint32_t minos; tb_uint32_t sdk; tb_uint32_t ntools; } __tb_packed__ xm_macho_build_version_command_t; typedef struct __xm_macho_nlist_t { tb_uint32_t strx; tb_uint8_t type; tb_uint8_t sect; tb_int16_t desc; tb_uint32_t value; } __tb_packed__ xm_macho_nlist_t; typedef struct __xm_macho_nlist_64_t { tb_uint32_t strx; tb_uint8_t type; tb_uint8_t sect; tb_uint16_t desc; tb_uint64_t value; } __tb_packed__ xm_macho_nlist_64_t; typedef struct __xm_macho_load_command_t { tb_uint32_t cmd; tb_uint32_t cmdsize; } __tb_packed__ xm_macho_load_command_t; typedef struct __xm_macho_dylib_t { tb_uint32_t offset; tb_uint32_t timestamp; tb_uint32_t current_version; tb_uint32_t compatibility_version; } __tb_packed__ xm_macho_dylib_t; typedef struct __xm_macho_dylib_command_t { tb_uint32_t cmd; tb_uint32_t cmdsize; xm_macho_dylib_t dylib; } __tb_packed__ xm_macho_dylib_command_t; typedef struct __xm_macho_context_t { union { xm_macho_header_32_t header32; xm_macho_header_64_t header64; } header; tb_bool_t is64; tb_bool_t swap; tb_uint32_t ncmds; tb_uint32_t sizeofcmds; } __tb_packed__ xm_macho_context_t; #include "tbox/prefix/packed.h" /* ////////////////////////////////////////////////////////////////////////////////////// * inline implementation */ // byte-swap Mach-O header fields if needed static __tb_inline__ tb_void_t xm_binutils_macho_swap_header_32(xm_macho_header_32_t *header, tb_bool_t swap) { if (swap) { header->magic = tb_bits_swap_u32(header->magic); header->cputype = tb_bits_swap_u32(header->cputype); header->cpusubtype = tb_bits_swap_u32(header->cpusubtype); header->filetype = tb_bits_swap_u32(header->filetype); header->ncmds = tb_bits_swap_u32(header->ncmds); header->sizeofcmds = tb_bits_swap_u32(header->sizeofcmds); header->flags = tb_bits_swap_u32(header->flags); } } // byte-swap Mach-O header 64 fields if needed static __tb_inline__ tb_void_t xm_binutils_macho_swap_header_64(xm_macho_header_64_t *header, tb_bool_t swap) { if (swap) { header->magic = tb_bits_swap_u32(header->magic); header->cputype = tb_bits_swap_u32(header->cputype); header->cpusubtype = tb_bits_swap_u32(header->cpusubtype); header->filetype = tb_bits_swap_u32(header->filetype); header->ncmds = tb_bits_swap_u32(header->ncmds); header->sizeofcmds = tb_bits_swap_u32(header->sizeofcmds); header->flags = tb_bits_swap_u32(header->flags); header->reserved = tb_bits_swap_u32(header->reserved); } } // init Mach-O context static __tb_inline__ tb_bool_t xm_binutils_macho_context_init(tb_stream_ref_t istream, tb_hize_t base_offset, xm_macho_context_t* context) { tb_assert_and_check_return_val(istream && context, tb_false); // read Mach-O header if (!tb_stream_seek(istream, base_offset)) return tb_false; if (!tb_stream_bread(istream, (tb_byte_t*)&context->header.header32, sizeof(xm_macho_header_32_t))) return tb_false; // check magic tb_uint32_t magic = context->header.header32.magic; if (magic == XM_MACHO_MAGIC_32) { context->is64 = tb_false; context->swap = tb_false; } else if (magic == XM_MACHO_MAGIC_32_BE) { context->is64 = tb_false; context->swap = tb_true; } else if (magic == XM_MACHO_MAGIC_64) { context->is64 = tb_true; context->swap = tb_false; } else if (magic == XM_MACHO_MAGIC_64_BE) { context->is64 = tb_true; context->swap = tb_true; } else { return tb_false; // Not a Mach-O file } if (context->is64) { if (!tb_stream_seek(istream, base_offset)) return tb_false; if (!tb_stream_bread(istream, (tb_byte_t*)&context->header.header64, sizeof(xm_macho_header_64_t))) return tb_false; xm_binutils_macho_swap_header_64(&context->header.header64, context->swap); context->ncmds = context->header.header64.ncmds; context->sizeofcmds = context->header.header64.sizeofcmds; } else { xm_binutils_macho_swap_header_32(&context->header.header32, context->swap); context->ncmds = context->header.header32.ncmds; context->sizeofcmds = context->header.header32.sizeofcmds; } return tb_true; } // byte-swap load command fields if needed static __tb_inline__ tb_void_t xm_binutils_macho_swap_load_command(xm_macho_load_command_t *lc, tb_bool_t swap) { if (swap) { lc->cmd = tb_bits_swap_u32(lc->cmd); lc->cmdsize = tb_bits_swap_u32(lc->cmdsize); } } // byte-swap dylib command fields if needed static __tb_inline__ tb_void_t xm_binutils_macho_swap_dylib_command(xm_macho_dylib_command_t *dc, tb_bool_t swap) { if (swap) { dc->cmd = tb_bits_swap_u32(dc->cmd); dc->cmdsize = tb_bits_swap_u32(dc->cmdsize); dc->dylib.offset = tb_bits_swap_u32(dc->dylib.offset); dc->dylib.timestamp = tb_bits_swap_u32(dc->dylib.timestamp); dc->dylib.current_version = tb_bits_swap_u32(dc->dylib.current_version); dc->dylib.compatibility_version = tb_bits_swap_u32(dc->dylib.compatibility_version); } } // byte-swap rpath command fields if needed static __tb_inline__ tb_void_t xm_binutils_macho_swap_rpath_command(xm_macho_rpath_command_t *rc, tb_bool_t swap) { if (swap) { rc->cmd = tb_bits_swap_u32(rc->cmd); rc->cmdsize = tb_bits_swap_u32(rc->cmdsize); rc->path_offset = tb_bits_swap_u32(rc->path_offset); } } // byte-swap symtab command fields if needed static __tb_inline__ tb_void_t xm_binutils_macho_swap_symtab_command(xm_macho_symtab_command_t *cmd, tb_bool_t swap) { if (swap) { cmd->cmd = tb_bits_swap_u32(cmd->cmd); cmd->cmdsize = tb_bits_swap_u32(cmd->cmdsize); cmd->symoff = tb_bits_swap_u32(cmd->symoff); cmd->nsyms = tb_bits_swap_u32(cmd->nsyms); cmd->stroff = tb_bits_swap_u32(cmd->stroff); cmd->strsize = tb_bits_swap_u32(cmd->strsize); } } // byte-swap nlist 32 fields if needed static __tb_inline__ tb_void_t xm_binutils_macho_swap_nlist_32(xm_macho_nlist_t *nlist, tb_bool_t swap) { if (swap) { nlist->strx = tb_bits_swap_u32(nlist->strx); nlist->desc = tb_bits_swap_u16(nlist->desc); nlist->value = tb_bits_swap_u32(nlist->value); } } // byte-swap nlist 64 fields if needed static __tb_inline__ tb_void_t xm_binutils_macho_swap_nlist_64(xm_macho_nlist_64_t *nlist, tb_bool_t swap) { if (swap) { nlist->strx = tb_bits_swap_u32(nlist->strx); nlist->desc = tb_bits_swap_u16(nlist->desc); nlist->value = tb_bits_swap_u64(nlist->value); } } /* get CPU type from architecture string * * @param arch the architecture string (e.g., "x86_64", "i386", "arm64") * @return the CPU type */ static __tb_inline__ tb_uint32_t xm_binutils_macho_get_cputype(tb_char_t const *arch) { if (!arch) { return XM_MACHO_CPU_TYPE_X86_64; } if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) { return XM_MACHO_CPU_TYPE_X86_64; } else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0) { return XM_MACHO_CPU_TYPE_ARM64; } else if (tb_strcmp(arch, "arm") == 0) { return XM_MACHO_CPU_TYPE_ARM; } else if (tb_strcmp(arch, "x86") == 0 || tb_strcmp(arch, "i386") == 0) { return XM_MACHO_CPU_TYPE_X86; } return XM_MACHO_CPU_TYPE_X86_64; } /* get CPU subtype from architecture string * * @param arch the architecture string * @return the CPU subtype */ static __tb_inline__ tb_uint32_t xm_binutils_macho_get_cpusubtype(tb_char_t const *arch) { if (!arch) { return XM_MACHO_CPU_SUBTYPE_X86_64; } if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) { return XM_MACHO_CPU_SUBTYPE_X86_64; } else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0) { return XM_MACHO_CPU_SUBTYPE_ARM64; } else if (tb_strcmp(arch, "arm") == 0) { return XM_MACHO_CPU_SUBTYPE_ARM; } else if (tb_strcmp(arch, "x86") == 0 || tb_strcmp(arch, "i386") == 0) { return XM_MACHO_CPU_SUBTYPE_X86; } return XM_MACHO_CPU_SUBTYPE_X86_64; } /* check if architecture is 64-bit * * @param arch the architecture string * @return tb_true if 64-bit, tb_false otherwise */ static __tb_inline__ tb_bool_t xm_binutils_macho_is_64bit(tb_char_t const *arch) { if (!arch) { return tb_true; } if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) { return tb_true; } else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0) { return tb_true; } else if (tb_strcmp(arch, "arm") == 0) { return tb_false; } else if (tb_strcmp(arch, "x86") == 0 || tb_strcmp(arch, "i386") == 0) { return tb_false; } return tb_true; } /* align value to specified alignment * * @param value the value to align * @param align the alignment (must be power of 2) * @return the aligned value */ static __tb_inline__ tb_uint32_t xm_binutils_macho_align(tb_uint32_t value, tb_uint32_t align) { return ((value + align - 1) & ~(align - 1)); } /* get platform from platform string * * @param platform the platform string (e.g., "macosx", "ios", "tvos", "watchos") * @return the platform constant */ static __tb_inline__ tb_uint32_t xm_binutils_macho_get_platform(tb_char_t const *platform) { if (!platform) { return XM_MACHO_PLATFORM_MACOS; } if (tb_strcmp(platform, "macosx") == 0 || tb_strcmp(platform, "macos") == 0) { return XM_MACHO_PLATFORM_MACOS; } else if (tb_strcmp(platform, "iphoneos") == 0 || tb_strcmp(platform, "ios") == 0) { return XM_MACHO_PLATFORM_IOS; } else if (tb_strcmp(platform, "appletvos") == 0 || tb_strcmp(platform, "tvos") == 0) { return XM_MACHO_PLATFORM_TVOS; } else if (tb_strcmp(platform, "watchos") == 0) { return XM_MACHO_PLATFORM_WATCHOS; } return XM_MACHO_PLATFORM_MACOS; } /* parse version string to Mach-O format * * @param version_str the version string (e.g., "10.0" or "18.2") * @return the version in Mach-O format (major << 16) | (minor << 8) | patch */ static __tb_inline__ tb_uint32_t xm_binutils_macho_parse_version(tb_char_t const *version_str) { if (!version_str || !version_str[0]) { return 0x000a0000; // default: 10.0.0 } tb_uint32_t major = 0; tb_uint32_t minor = 0; tb_uint32_t patch = 0; tb_char_t const *p = version_str; // parse major while (*p && tb_isdigit(*p)) { major = major * 10 + (*p - '0'); p++; } if (*p == '.') { p++; // parse minor while (*p && tb_isdigit(*p)) { minor = minor * 10 + (*p - '0'); p++; } if (*p == '.') { p++; // parse patch while (*p && tb_isdigit(*p)) { patch = patch * 10 + (*p - '0'); p++; } } } return (major << 16) | (minor << 8) | patch; } /* ////////////////////////////////////////////////////////////////////////////////////// * readsyms inline implementation */ /* read string from Mach-O string table * * @param istream the input stream * @param strtab_offset the string table offset * @param offset the string offset (nlist.strx, relative to string table start, including 4-byte size field) * @param name the buffer to store the string * @param name_size the size of the buffer * @return tb_true on success, tb_false on failure */ static __tb_inline__ tb_bool_t xm_binutils_macho_read_string(tb_stream_ref_t istream, tb_hize_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) { tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false); // nlist.strx is offset from string table start (including 4-byte size field) tb_hize_t saved_pos = tb_stream_offset(istream); if (!tb_stream_seek(istream, strtab_offset + offset)) { return tb_false; } tb_size_t pos = 0; tb_byte_t c; while (pos < name_size - 1) { if (!tb_stream_bread(istream, &c, 1)) { tb_stream_seek(istream, saved_pos); return tb_false; } if (c == 0) { break; } name[pos++] = (tb_char_t)c; } name[pos] = '\0'; tb_stream_seek(istream, saved_pos); return tb_true; } /* get symbol type character (nm-style) from Mach-O symbol * * @param type the symbol type byte * @param sect the section number (0 = undefined) * @return the type character (T/t/D/d/B/b/U) */ static __tb_inline__ tb_char_t xm_binutils_macho_get_symbol_type_char(tb_uint8_t type, tb_uint8_t sect) { // undefined symbol if (sect == 0) { return 'U'; } // check if external tb_bool_t is_external = (type & XM_MACHO_N_EXT) != 0; // check if in section tb_uint8_t n_type = type & XM_MACHO_N_TYPE_MASK; if (n_type == XM_MACHO_N_TYPE_SECT) { // section 1 is usually __TEXT,__text (text) // section 2 is usually __DATA,__data (data) // section 3 is usually __DATA,__bss (bss) // For simplicity, we'll use section number to determine type // This is a heuristic and may not be 100% accurate if (sect == 1) { return is_external ? 'T' : 't'; // text section } else if (sect == 2) { return is_external ? 'D' : 'd'; // data section } else if (sect == 3) { return is_external ? 'B' : 'b'; // bss section } else { return is_external ? 'S' : 's'; // other section } } return '?'; // unknown } /* get symbol bind string from Mach-O symbol type * * @param type the symbol type byte * @return the bind string */ static __tb_inline__ tb_char_t const *xm_binutils_macho_get_symbol_bind(tb_uint8_t type) { if (type & XM_MACHO_N_EXT) { return "external"; } return "local"; } #endif ================================================ FILE: core/src/xmake/binutils/macho/readsyms.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file readsyms.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "readsyms_macho" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_macho_context_t* context) { tb_assert_and_check_return_val(istream && lua && context, tb_false); // find LC_SYMTAB command xm_macho_symtab_command_t symtab_cmd; tb_bool_t found_symtab = tb_false; tb_uint32_t offset = sizeof(xm_macho_header_32_t); for (tb_uint32_t i = 0; i < context->ncmds; i++) { tb_uint32_t cmd; tb_uint32_t cmdsize; if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmdsize, 4)) { return tb_false; } if (context->swap) { cmd = tb_bits_swap_u32(cmd); cmdsize = tb_bits_swap_u32(cmdsize); } if (cmd == XM_MACHO_LC_SYMTAB) { if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) { return tb_false; } xm_binutils_macho_swap_symtab_command(&symtab_cmd, context->swap); found_symtab = tb_true; break; } offset += cmdsize; } if (!found_symtab) { lua_newtable(lua); return tb_true; } // create result table lua_newtable(lua); // read symbols if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) { return tb_false; } tb_uint32_t result_count = 0; for (tb_uint32_t i = 0; i < symtab_cmd.nsyms; i++) { xm_macho_nlist_t nlist; if (!tb_stream_bread(istream, (tb_byte_t*)&nlist, sizeof(nlist))) { return tb_false; } xm_binutils_macho_swap_nlist_32(&nlist, context->swap); // skip NULL symbols if (nlist.strx == 0) { continue; } // get symbol name tb_char_t name[256]; if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) { continue; } // skip internal symbols (starting with .) if (name[0] == '.') { continue; } // create symbol table entry lua_pushinteger(lua, result_count + 1); lua_newtable(lua); // name lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect); tb_char_t type_str[2] = {type_char, '\0'}; lua_pushstring(lua, "type"); lua_pushstring(lua, type_str); lua_settable(lua, -3); lua_settable(lua, -3); result_count++; } return tb_true; } tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_macho_context_t* context) { tb_assert_and_check_return_val(istream && lua && context, tb_false); // find LC_SYMTAB command xm_macho_symtab_command_t symtab_cmd; tb_bool_t found_symtab = tb_false; tb_uint32_t offset = sizeof(xm_macho_header_64_t); for (tb_uint32_t i = 0; i < context->ncmds; i++) { tb_uint32_t cmd; tb_uint32_t cmdsize; if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmdsize, 4)) { return tb_false; } if (context->swap) { cmd = tb_bits_swap_u32(cmd); cmdsize = tb_bits_swap_u32(cmdsize); } if (cmd == XM_MACHO_LC_SYMTAB) { if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) { return tb_false; } xm_binutils_macho_swap_symtab_command(&symtab_cmd, context->swap); found_symtab = tb_true; break; } offset += cmdsize; } if (!found_symtab) { lua_newtable(lua); return tb_true; } // create result table lua_newtable(lua); // read symbols if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) { return tb_false; } tb_uint32_t result_count = 0; for (tb_uint32_t i = 0; i < symtab_cmd.nsyms; i++) { xm_macho_nlist_64_t nlist; if (!tb_stream_bread(istream, (tb_byte_t*)&nlist, sizeof(nlist))) { return tb_false; } xm_binutils_macho_swap_nlist_64(&nlist, context->swap); // skip NULL symbols if (nlist.strx == 0) { continue; } // get symbol name tb_char_t name[256]; if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) { continue; } // skip internal symbols (starting with .) if (name[0] == '.') { continue; } // create symbol table entry lua_pushinteger(lua, result_count + 1); lua_newtable(lua); // name lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect); tb_char_t type_str[2] = {type_char, '\0'}; lua_pushstring(lua, "type"); lua_pushstring(lua, type_str); lua_settable(lua, -3); lua_settable(lua, -3); result_count++; } return tb_true; } tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // init Mach-O context xm_macho_context_t context; if (!xm_binutils_macho_context_init(istream, base_offset, &context)) { return tb_false; } if (!context.is64) { return xm_binutils_macho_read_symbols_32(istream, base_offset, lua, &context); } else { return xm_binutils_macho_read_symbols_64(istream, base_offset, lua, &context); } } ================================================ FILE: core/src/xmake/binutils/macho/rpath.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rpath.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rpath_macho" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t xm_binutils_macho_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); tb_bool_t ok = tb_false; do { // init Mach-O context xm_macho_context_t context; if (!xm_binutils_macho_context_init(istream, base_offset, &context)) break; // skip header to reach load commands tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t); if (!tb_stream_seek(istream, base_offset + header_size)) break; tb_size_t result_count = 0; // iterate load commands tb_uint32_t i = 0; for (i = 0; i < context.ncmds; i++) { xm_macho_load_command_t lc; tb_hize_t current_cmd_offset = tb_stream_offset(istream); if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) break; xm_binutils_macho_swap_load_command(&lc, context.swap); // check for LC_RPATH if (lc.cmd == XM_MACHO_LC_RPATH) { xm_macho_rpath_command_t rc; if (tb_stream_seek(istream, current_cmd_offset)) { if (tb_stream_bread(istream, (tb_byte_t*)&rc, sizeof(rc))) { xm_binutils_macho_swap_rpath_command(&rc, context.swap); tb_uint32_t name_offset = rc.path_offset; if (name_offset < lc.cmdsize) { // name is at current_cmd_offset + name_offset tb_char_t rpath[TB_PATH_MAXN]; if (xm_binutils_read_string(istream, current_cmd_offset + name_offset, rpath, sizeof(rpath))) { if (tb_strlen(rpath) > 0) { lua_pushinteger(lua, result_count + 1); lua_pushstring(lua, rpath); lua_settable(lua, -3); result_count++; } } } } } } // move to next command if (!tb_stream_seek(istream, current_cmd_offset + lc.cmdsize)) break; } if (i < context.ncmds) break; ok = tb_true; } while (0); return ok; } tb_bool_t xm_binutils_macho_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset) { tb_assert_and_check_return_val(istream, tb_false); tb_bool_t ok = tb_false; tb_byte_t* buffer = tb_null; do { // init Mach-O context xm_macho_context_t context; if (!xm_binutils_macho_context_init(istream, base_offset, &context)) break; tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t); if (!tb_stream_seek(istream, base_offset + header_size)) break; tb_hize_t read_offset = base_offset + header_size; tb_hize_t write_offset = read_offset; tb_uint32_t new_ncmds = 0; tb_uint32_t new_sizeofcmds = 0; tb_bool_t found = tb_false; buffer = (tb_byte_t*)tb_malloc(64 * 1024); // 64KB should be enough for any load command if (!buffer) break; tb_uint32_t i = 0; for (i = 0; i < context.ncmds; i++) { xm_macho_load_command_t lc; if (!tb_stream_seek(istream, read_offset)) break; if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) break; xm_binutils_macho_swap_load_command(&lc, context.swap); tb_bool_t remove = tb_false; if (lc.cmd == XM_MACHO_LC_RPATH) { remove = tb_true; found = tb_true; } if (!remove) { // copy command to write_offset if (read_offset != write_offset) { if (lc.cmdsize > 64 * 1024) break; if (!tb_stream_seek(istream, read_offset)) break; if (!tb_stream_bread(istream, buffer, lc.cmdsize)) break; if (!tb_stream_seek(istream, write_offset)) break; if (!tb_stream_bwrit(istream, buffer, lc.cmdsize)) break; } write_offset += lc.cmdsize; new_ncmds++; new_sizeofcmds += lc.cmdsize; } read_offset += lc.cmdsize; } if (i < context.ncmds) break; if (found) { // zero out the remaining space if (read_offset > write_offset) { tb_hize_t diff = read_offset - write_offset; if (!tb_stream_seek(istream, write_offset)) break; tb_byte_t zero = 0; tb_bool_t write_ok = tb_true; for (tb_hize_t k = 0; k < diff; k++) { if (!tb_stream_bwrit(istream, &zero, 1)) { write_ok = tb_false; break; } } if (!write_ok) break; } // update header if (context.is64) { context.header.header64.ncmds = new_ncmds; context.header.header64.sizeofcmds = new_sizeofcmds; xm_binutils_macho_swap_header_64(&context.header.header64, context.swap); if (!tb_stream_seek(istream, base_offset)) break; if (!tb_stream_bwrit(istream, (tb_byte_t const*)&context.header.header64, sizeof(xm_macho_header_64_t))) break; } else { context.header.header32.ncmds = new_ncmds; context.header.header32.sizeofcmds = new_sizeofcmds; xm_binutils_macho_swap_header_32(&context.header.header32, context.swap); if (!tb_stream_seek(istream, base_offset)) break; if (!tb_stream_bwrit(istream, (tb_byte_t const*)&context.header.header32, sizeof(xm_macho_header_32_t))) break; } } ok = tb_true; } while (0); if (buffer) tb_free(buffer); return ok; } ================================================ FILE: core/src/xmake/binutils/mslib/extractlib.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file extractlib.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "mslib_extract" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* generate unique name for output file * * @param base_name the base name * @param id the unique id * @param output output buffer * @param output_size output buffer size * @param output_len output: actual output length * @return tb_true on success, tb_false on failure */ static tb_bool_t xm_binutils_mslib_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size, tb_size_t* output_len) { tb_assert_and_check_return_val(base_name && output && output_size > 0 && output_len, tb_false); // find the last dot for extension tb_char_t const *ext = tb_strrchr(base_name, '.'); tb_long_t n = -1; if (ext) { tb_size_t base_len = (tb_size_t)(ext - base_name); tb_size_t ext_len = tb_strlen(ext); if (base_len + ext_len + 16 < output_size) { n = tb_snprintf(output, output_size, "%.*s_%u%s", (tb_int_t)base_len, base_name, id, ext); } } else { // no extension if (tb_strlen(base_name) + 16 < output_size) { n = tb_snprintf(output, output_size, "%s_%u", base_name, id); } } if (n >= 0) { *output_len = (tb_size_t)n; return tb_true; } return tb_false; } /* extract MSVC lib archive to directory * * @param istream the input stream * @param outputdir the output directory * @param plain extract all object files to the same directory * @return tb_true on success, tb_false on failure */ tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain) { tb_assert_and_check_return_val(istream && outputdir, tb_false); // check magic (!\n) if (!xm_binutils_mslib_check_magic(istream)) { return tb_false; } /* ensure output directory exists * check if directory already exists */ if (!tb_file_info(outputdir, tb_null)) { // directory doesn't exist, create it if (!tb_directory_create(outputdir)) { return tb_false; } } tb_bool_t ok = tb_true; tb_char_t* longnames = tb_null; tb_size_t longnames_size = 0; // iterate through members while (ok) { // read header xm_mslib_header_t header; if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { // end of file break; } // parse member size tb_int64_t member_size = xm_binutils_mslib_parse_decimal(header.size, 10); if (member_size < 0) { ok = tb_false; break; } // parse member name tb_char_t member_name[256] = {0}; tb_bool_t is_longname_table = tb_false; if (header.name[0] == '/') { if (header.name[1] == '/') { // long name table (//) is_longname_table = tb_true; } else if (tb_isdigit(header.name[1])) { // offset into long name table (/123) tb_int64_t offset = xm_binutils_mslib_parse_decimal(header.name + 1, 15); if (offset >= 0 && (tb_size_t)offset < longnames_size) { /* copy from longnames * names in longnames are null-terminated */ tb_strlcpy(member_name, longnames + offset, sizeof(member_name)); } } else { /* symbol table or other special member (/) * usually symbol table is just "/" */ tb_strlcpy(member_name, "/", sizeof(member_name)); } } else { // short name, ends with / tb_size_t i = 0; for (i = 0; i < 16 && header.name[i] != '/'; i++) { member_name[i] = header.name[i]; } member_name[i] = '\0'; } if (is_longname_table) { tb_char_t* new_longnames = (tb_char_t*)tb_ralloc(longnames, (tb_size_t)member_size + 1); if (!new_longnames) { ok = tb_false; break; } longnames = new_longnames; if (!tb_stream_bread(istream, (tb_byte_t*)longnames, (tb_size_t)member_size)) { ok = tb_false; break; } longnames[member_size] = '\0'; longnames_size = (tb_size_t)member_size; // align if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { ok = tb_false; break; } } continue; } /* check if we should extract * skip empty names, symbol tables (/), long name table (//) - handled above, * and __.SYMDEF (SysV/BSD style symbol table, just in case) */ if (member_name[0] == '\0' || tb_strcmp(member_name, "/") == 0 || tb_strcmp(member_name, "//") == 0 || tb_strncmp(member_name, "__.SYMDEF", 9) == 0) { // skip member data if (!tb_stream_skip(istream, member_size)) { ok = tb_false; break; } // align if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { ok = tb_false; break; } } continue; } /* construct output path * replace \ with / */ tb_size_t name_len = tb_strlen(member_name); for (tb_size_t i = 0; i < name_len; i++) { if (member_name[i] == '\\') { member_name[i] = '/'; } } // check output path length tb_char_t output_path[1024]; if (plain) { // get filename only tb_char_t const* name = tb_strrchr(member_name, '/'); if (name) { name++; } else { name = member_name; } // check conflicts tb_char_t output_name[512]; tb_size_t output_name_len = tb_strlen(name); tb_size_t outputdir_len = tb_strlen(outputdir); if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) { ok = tb_false; break; } tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, name); if (tb_file_info(output_path, tb_null)) { // name conflict, try different IDs tb_uint32_t conflict_id = 1; while (conflict_id < 10000) { if (!xm_binutils_mslib_generate_unique_name(name, conflict_id, output_name, sizeof(output_name), &output_name_len)) { ok = tb_false; break; } if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) { ok = tb_false; break; } tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, output_name); if (!tb_file_info(output_path, tb_null)) { break; } conflict_id++; } tb_check_break(ok); if (conflict_id >= 10000) { ok = tb_false; break; } } } else { if (tb_strlen(outputdir) + 1 + name_len >= sizeof(output_path)) { ok = tb_false; break; } tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, member_name); } // ensure directory exists tb_char_t const* p = tb_strrchr(output_path, '/'); if (p) { tb_char_t dir[1024]; tb_size_t len = p - output_path; if (len < sizeof(dir)) { tb_strncpy(dir, output_path, len); dir[len] = '\0'; if (!tb_file_info(dir, tb_null)) { if (!tb_directory_create(dir)) { ok = tb_false; break; } } } } // write file tb_stream_ref_t ostream = tb_stream_init_from_file(output_path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); if (ostream) { if (tb_stream_open(ostream)) { if (!xm_binutils_stream_copy(istream, ostream, member_size)) { ok = tb_false; } } else { ok = tb_false; } tb_stream_exit(ostream); } else { ok = tb_false; } tb_check_break(ok); // align to 2-byte boundary if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { ok = tb_false; break; } } } if (longnames) { tb_free(longnames); } return ok; } ================================================ FILE: core/src/xmake/binutils/mslib/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BINUTILS_MSLIB_PREFIX_H #define XM_BINUTILS_MSLIB_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // MSVC lib header #include "tbox/prefix/packed.h" typedef struct __xm_mslib_header_t { tb_char_t name[16]; tb_char_t date[12]; tb_char_t uid[6]; tb_char_t gid[6]; tb_char_t mode[8]; tb_char_t size[10]; tb_char_t fmag[2]; } __tb_packed__ xm_mslib_header_t; #include "tbox/prefix/packed.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ static __tb_inline__ tb_int64_t xm_binutils_mslib_parse_decimal(tb_char_t const *p, tb_size_t n) { tb_assert_and_check_return_val(p && n > 0, -1); tb_int64_t v = 0; tb_char_t const* e = p + n; while (p < e && *p == ' ') { p++; } while (p < e && *p >= '0' && *p <= '9') { v = v * 10 + (*p - '0'); p++; } return v; } static __tb_inline__ tb_bool_t xm_binutils_mslib_check_magic(tb_stream_ref_t istream) { tb_char_t magic[8]; if (!tb_stream_bread(istream, (tb_byte_t*)magic, 8)) { return tb_false; } return tb_strncmp(magic, "!\n", 8) == 0; } #endif ================================================ FILE: core/src/xmake/binutils/mslib/readsyms.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file readsyms.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "mslib_readsyms" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * forward declarations */ extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t xm_binutils_mslib_parse_archive_symbols(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) { // try to parse as Second Linker Member (LE) tb_hize_t start_pos = tb_stream_offset(istream); tb_uint32_t* offsets = tb_null; tb_uint16_t* indices = tb_null; tb_char_t* string_table = tb_null; tb_bool_t ok = tb_false; do { // read number of members tb_uint32_t num_members = 0; if (!tb_stream_bread_u32_le(istream, &num_members)) { break; } // sanity check if (num_members == 0 || num_members > 65536 || num_members * 4 >= member_size) { break; } // read offsets offsets = tb_nalloc_type(num_members, tb_uint32_t); tb_check_break(offsets); tb_size_t i; for (i = 0; i < num_members; i++) { if (!tb_stream_bread_u32_le(istream, &offsets[i])) { break; } } if (i < num_members) { break; } // read number of symbols tb_uint32_t num_symbols = 0; if (!tb_stream_bread_u32_le(istream, &num_symbols)) { break; } if (num_symbols == 0 || num_symbols > 1000000) { break; } // read indices indices = tb_nalloc_type(num_symbols, tb_uint16_t); tb_check_break(indices); for (i = 0; i < num_symbols; i++) { if (!tb_stream_bread_u16_le(istream, &indices[i])) { break; } } if (i < num_symbols) { break; } // read string table tb_hize_t current = tb_stream_offset(istream); tb_hize_t string_table_size = member_size - (current - start_pos); string_table = (tb_char_t*)tb_malloc_bytes((tb_size_t)string_table_size); tb_check_break(string_table); if (!tb_stream_bread(istream, (tb_byte_t*)string_table, (tb_size_t)string_table_size)) { break; } // populate map tb_char_t* p = string_table; tb_char_t* end = string_table + string_table_size; for (i = 0; i < num_symbols; i++) { if (p >= end) { break; } tb_char_t* sym_name = p; tb_size_t sym_len = tb_strlen(sym_name); p += sym_len + 1; tb_uint16_t idx = indices[i]; if (idx > 0 && idx <= num_members) { tb_uint32_t offset = offsets[idx - 1]; lua_pushinteger(lua, offset); lua_rawget(lua, map_idx); if (lua_isnil(lua, -1)) { lua_pop(lua, 1); lua_newtable(lua); lua_pushinteger(lua, offset); lua_pushvalue(lua, -2); lua_rawset(lua, map_idx); } int count = (int)lua_objlen(lua, -1); lua_pushstring(lua, sym_name); lua_rawseti(lua, -2, count + 1); lua_pop(lua, 1); // pop list } } ok = tb_true; } while (0); if (offsets) { tb_free(offsets); } if (indices) { tb_free(indices); } if (string_table) { tb_free(string_table); } if (!ok) { tb_stream_seek(istream, start_pos); } return ok; } /* read symbols from MSVC lib archive * * @param istream the input stream * @param base_offset the base offset * @param lua the lua state * @return tb_true on success, tb_false on failure */ tb_bool_t xm_binutils_mslib_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State* lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // check magic (!\n) if (!xm_binutils_mslib_check_magic(istream)) { return tb_false; } // create map table (offset -> symbols) lua_newtable(lua); int map_idx = lua_gettop(lua); tb_bool_t ok = tb_true; tb_size_t object_count = 0; tb_char_t* longnames = tb_null; tb_size_t longnames_size = 0; // iterate through members while (ok) { // read header xm_mslib_header_t header; if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { // end of file break; } // parse member size tb_int64_t member_size = xm_binutils_mslib_parse_decimal(header.size, 10); if (member_size < 0) { ok = tb_false; break; } // parse member name tb_char_t member_name[256] = {0}; tb_bool_t is_longname_table = tb_false; if (header.name[0] == '/') { if (header.name[1] == '/') { // long name table (//) is_longname_table = tb_true; } else if (tb_isdigit(header.name[1])) { // offset into long name table (/123) tb_int64_t offset = xm_binutils_mslib_parse_decimal(header.name + 1, 15); if (offset >= 0 && (tb_size_t)offset < longnames_size) { /* copy from longnames * names in longnames are null-terminated */ tb_strlcpy(member_name, longnames + offset, sizeof(member_name)); } } else { /* symbol table or other special member (/) * usually symbol table is just "/" */ tb_strlcpy(member_name, "/", sizeof(member_name)); } } else { // short name, ends with / tb_size_t i = 0; for (i = 0; i < 16 && header.name[i] != '/'; i++) { member_name[i] = header.name[i]; } member_name[i] = '\0'; } if (is_longname_table) { longnames = (tb_char_t*)tb_ralloc(longnames, (tb_size_t)member_size + 1); if (!longnames || !tb_stream_bread(istream, (tb_byte_t*)longnames, (tb_size_t)member_size)) { ok = tb_false; break; } longnames[member_size] = '\0'; longnames_size = (tb_size_t)member_size; // align if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { ok = tb_false; break; } } continue; } // check if we should process /* skip empty names, long name table (//) - handled above, * and __.SYMDEF (SysV/BSD style symbol table, just in case) */ if (member_name[0] == '\0' || tb_strcmp(member_name, "//") == 0 || tb_strncmp(member_name, "__.SYMDEF", 9) == 0) { // skip member data if (!tb_stream_skip(istream, member_size)) { ok = tb_false; break; } // align if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { ok = tb_false; break; } } continue; } if (tb_strcmp(member_name, "/") == 0) { // try to parse archive symbols if (!xm_binutils_mslib_parse_archive_symbols(istream, (tb_hize_t)member_size, lua, map_idx)) { // if failed, skip member data if (!tb_stream_skip(istream, member_size)) { ok = tb_false; break; } } // align if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { ok = tb_false; break; } } continue; } // save current position tb_hize_t current_pos = tb_stream_offset(istream); tb_hize_t header_offset = current_pos - sizeof(xm_mslib_header_t); // detect format tb_int_t format = xm_binutils_format_detect(istream); if (format != XM_BINUTILS_FORMAT_UNKNOWN && format != XM_BINUTILS_FORMAT_AR) { // create entry table lua_newtable(lua); // object name lua_pushstring(lua, "objectfile"); lua_pushstring(lua, member_name); lua_settable(lua, -3); // symbols lua_pushstring(lua, "symbols"); tb_bool_t read_ok = tb_false; if (format == XM_BINUTILS_FORMAT_COFF) { read_ok = xm_binutils_coff_read_symbols(istream, current_pos, lua); } else if (format == XM_BINUTILS_FORMAT_ELF) { read_ok = xm_binutils_elf_read_symbols(istream, current_pos, lua); } else if (format == XM_BINUTILS_FORMAT_MACHO) { read_ok = xm_binutils_macho_read_symbols(istream, current_pos, lua); } // if read failed or empty, try map tb_bool_t has_symbols = tb_false; if (read_ok) { if (lua_objlen(lua, -1) > 0) { has_symbols = tb_true; } else { lua_pop(lua, 1); // pop empty table } } if (!has_symbols) { // check map lua_pushinteger(lua, (lua_Integer)header_offset); lua_rawget(lua, map_idx); if (lua_istable(lua, -1)) { // convert list of names to list of {name=..., type="global"} lua_newtable(lua); // result table int count = (int)lua_objlen(lua, -2); for (int i = 1; i <= count; i++) { lua_rawgeti(lua, -2, i); const char* name = lua_tostring(lua, -1); if (name) { lua_newtable(lua); lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); lua_pushstring(lua, "type"); lua_pushstring(lua, "T"); lua_settable(lua, -3); lua_rawseti(lua, -3, i); } lua_pop(lua, 1); // pop name } lua_remove(lua, -2); // remove map entry list has_symbols = tb_true; } else { lua_pop(lua, 1); // pop nil } } if (has_symbols) { lua_settable(lua, -3); lua_rawseti(lua, map_idx - 1, (int)(++object_count)); } else { lua_pop(lua, 2); // pop symbols key and entry table } } // skip to next member tb_hize_t member_data_read = tb_stream_offset(istream) - current_pos; tb_hize_t remaining_size = (tb_hize_t)member_size - member_data_read; if (remaining_size > 0) { if (!tb_stream_skip(istream, remaining_size)) { ok = tb_false; break; } } else if (remaining_size < 0) { if (!tb_stream_seek(istream, current_pos + (tb_hize_t)member_size)) { ok = tb_false; break; } } // align to 2-byte boundary if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { ok = tb_false; break; } } } if (longnames) { tb_free(longnames); } lua_remove(lua, map_idx); return ok; } ================================================ FILE: core/src/xmake/binutils/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BINUTILS_PREFIX_H #define XM_BINUTILS_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_BINUTILS_FORMAT_COFF 1 #define XM_BINUTILS_FORMAT_ELF 2 #define XM_BINUTILS_FORMAT_MACHO 3 #define XM_BINUTILS_FORMAT_AR 4 #define XM_BINUTILS_FORMAT_PE 5 #define XM_BINUTILS_FORMAT_SHEBANG 6 #define XM_BINUTILS_FORMAT_APE 7 #define XM_BINUTILS_FORMAT_WASM 8 #define XM_BINUTILS_FORMAT_UNKNOWN 0 // COFF machine types (for format detection) #define XM_BINUTILS_COFF_MACHINE_I386 0x014c #define XM_BINUTILS_COFF_MACHINE_AMD64 0x8664 #define XM_BINUTILS_COFF_MACHINE_ARM 0x01c0 #define XM_BINUTILS_COFF_MACHINE_ARM64 0xaa64 // PE/DOS offsets/signatures (for format detection) #define XM_BINUTILS_PE_DOS_STUB_MIN_SIZE (0x40) #define XM_BINUTILS_PE_DOS_ELFANEW_OFFSET (0x3c) #define XM_BINUTILS_PE_NT_SIGNATURE (0x00004550) // "PE\0\0" little endian /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream); /* ////////////////////////////////////////////////////////////////////////////////////// * inline implementation */ /* read magic bytes from stream (preserves stream position) * * @param istream the input stream * @param magic the buffer to store magic bytes (must be at least 4 bytes) * @param size the number of bytes to read (typically 4) * * @return tb_true on success, tb_false on failure */ static __tb_inline__ tb_bool_t xm_binutils_read_magic(tb_stream_ref_t istream, tb_uint8_t *magic, tb_size_t size) { tb_assert_and_check_return_val(istream && magic && size > 0, tb_false); tb_hize_t saved_pos = tb_stream_offset(istream); if (!tb_stream_seek(istream, 0)) { return tb_false; } tb_bool_t ok = tb_false; if (tb_stream_bread(istream, magic, size)) { ok = tb_true; } tb_stream_seek(istream, saved_pos); return ok; } /* copy data from input stream to output stream * * @param istream the input stream * @param ostream the output stream * @param size the size to copy * * @return tb_true on success, tb_false on failure */ static __tb_inline__ tb_bool_t xm_binutils_stream_copy(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_hize_t size) { tb_assert_and_check_return_val(istream && ostream, tb_false); if (size == 0) { return tb_true; } tb_byte_t data[TB_STREAM_BLOCK_MAXN]; tb_hize_t writ = 0; do { tb_size_t need = (tb_size_t)tb_min(size - writ, (tb_hize_t)TB_STREAM_BLOCK_MAXN); tb_check_break(need); if (!tb_stream_bread(istream, data, need)) { return tb_false; } if (!tb_stream_bwrit(ostream, data, need)) { return tb_false; } writ += need; tb_check_break(writ < size); } while (1); return tb_true; } /* sanitize symbol name (replace non-alphanumeric characters with underscores) * * @param name the symbol name */ static __tb_inline__ void xm_binutils_sanitize_symbol_name(tb_char_t* name) { tb_assert_and_check_return(name); for (tb_size_t i = 0; name[i]; i++) { if (!tb_isalpha(name[i]) && !tb_isdigit(name[i]) && name[i] != '_') { name[i] = '_'; } } } /* read string from stream at specified offset * * @param istream the input stream * @param offset the offset to read from * @param name the buffer to store the string * @param name_size the size of the buffer * * @return tb_true on success, tb_false on failure */ static __tb_inline__ tb_bool_t xm_binutils_read_string(tb_stream_ref_t istream, tb_hize_t offset, tb_char_t *name, tb_size_t name_size) { tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false); tb_hize_t saved_pos = tb_stream_offset(istream); if (!tb_stream_seek(istream, offset)) { return tb_false; } tb_size_t pos = 0; tb_byte_t c; while (pos < name_size - 1) { if (!tb_stream_bread(istream, &c, 1)) { tb_stream_seek(istream, saved_pos); return tb_false; } if (c == 0) { break; } name[pos++] = (tb_char_t)c; } name[pos] = '\0'; tb_stream_seek(istream, saved_pos); return tb_true; } /* check if architecture is 64-bit * * @param arch the architecture string * @return tb_true if 64-bit, tb_false otherwise */ static __tb_inline__ tb_bool_t xm_binutils_arch_is_64bit(tb_char_t const *arch) { if (!arch) { return tb_true; } // x86_64 if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) { return tb_true; } // ARM64 else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0 || tb_strcmp(arch, "arm64-v8a") == 0) { return tb_true; } // MIPS64 else if (tb_strncmp(arch, "mips64", 6) == 0) { return tb_true; } // PowerPC64 else if (tb_strncmp(arch, "ppc64", 5) == 0 || tb_strncmp(arch, "powerpc64", 9) == 0) { return tb_true; } // RISC-V 64 else if (tb_strncmp(arch, "riscv64", 7) == 0 || (tb_strncmp(arch, "riscv", 5) == 0 && tb_strstr(arch, "64"))) { return tb_true; } // SPARC64 else if (tb_strncmp(arch, "sparc64", 7) == 0) { return tb_true; } // s390x else if (tb_strcmp(arch, "s390x") == 0) { return tb_true; } // LoongArch64 else if (tb_strncmp(arch, "loongarch64", 11) == 0) { return tb_true; } // WebAssembly 64 else if (tb_strcmp(arch, "wasm64") == 0) { return tb_true; } // IA-64 else if (tb_strcmp(arch, "ia64") == 0 || tb_strcmp(arch, "itanium") == 0) { return tb_true; } return tb_false; } #endif ================================================ FILE: core/src/xmake/binutils/readsyms.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file readsyms.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "readsyms" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "coff/prefix.h" #include "elf/prefix.h" #include "macho/prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * forward declarations */ extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_mslib_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* read symbols from object file (auto-detect format) * * @param lua the lua state * @return 1 on success (table on stack), 2 on failure (with error message on stack) */ tb_int_t xm_binutils_readsyms(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the object file path tb_char_t const *objectfile = luaL_checkstring(lua, 1); tb_check_return_val(objectfile, 0); // open file tb_stream_ref_t istream = tb_stream_init_from_file(objectfile, TB_FILE_MODE_RO); if (!istream) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "open %s failed", objectfile); return 2; } tb_bool_t ok = tb_false; do { if (!tb_stream_open(istream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "open %s failed", objectfile); break; } // detect format tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "cannot detect file format"); break; } // create result list lua_newtable(lua); // read symbols based on format if (format == XM_BINUTILS_FORMAT_AR) { // AR archive (.a or .lib) tb_bool_t is_mslib = tb_false; if (objectfile) { tb_size_t len = tb_strlen(objectfile); if (len > 4 && tb_stricmp(objectfile + len - 4, ".lib") == 0) { is_mslib = tb_true; } } if (is_mslib) { if (!xm_binutils_mslib_read_symbols(istream, 0, lua)) { // fallback to ar if (!xm_binutils_ar_read_symbols(istream, 0, lua)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "read AR/MSLIB archive symbols failed"); break; } } } else { if (!xm_binutils_ar_read_symbols(istream, 0, lua)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "read AR archive symbols failed"); break; } } } else { // single object file (COFF, ELF, Mach-O) // create entry table lua_newtable(lua); // object name lua_pushstring(lua, "objectfile"); tb_char_t const* name = tb_strrchr(objectfile, '/'); if (!name) { name = tb_strrchr(objectfile, '\\'); } if (!name) { name = objectfile; } else { name++; } lua_pushstring(lua, name); lua_settable(lua, -3); // symbols lua_pushstring(lua, "symbols"); tb_bool_t read_ok = tb_false; if (format == XM_BINUTILS_FORMAT_COFF) { read_ok = xm_binutils_coff_read_symbols(istream, 0, lua); } else if (format == XM_BINUTILS_FORMAT_ELF) { read_ok = xm_binutils_elf_read_symbols(istream, 0, lua); } else if (format == XM_BINUTILS_FORMAT_MACHO) { read_ok = xm_binutils_macho_read_symbols(istream, 0, lua); } else if (format == XM_BINUTILS_FORMAT_WASM) { read_ok = xm_binutils_wasm_read_symbols(istream, 0, lua); } if (read_ok) { lua_settable(lua, -3); lua_rawseti(lua, -2, 1); } else { lua_pop(lua, 2); // pop entry table and result list lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "read symbols failed"); break; } } ok = tb_true; } while (0); if (istream) { tb_stream_clos(istream); } istream = tb_null; return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/binutils/rpath.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rpath.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rpath" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "elf/prefix.h" #include "macho/prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ tb_bool_t xm_binutils_elf_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); tb_bool_t xm_binutils_macho_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); tb_bool_t xm_binutils_elf_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset); tb_bool_t xm_binutils_macho_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* get rpath list from binary file (auto-detect format) * * @param lua the lua state * @return 1 on success (table on stack), 2 on failure (with error message on stack) */ tb_int_t xm_binutils_rpath_list(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the binary file path tb_char_t const *binaryfile = luaL_checkstring(lua, 1); tb_check_return_val(binaryfile, 0); // open file tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO); if (!istream) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_list: open %s failed", binaryfile); return 2; } tb_bool_t ok = tb_false; do { if (!tb_stream_open(istream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_list: open %s failed", binaryfile); break; } // detect format tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_list: cannot detect file format"); break; } // create result list lua_newtable(lua); // get rpath list based on format if (format == XM_BINUTILS_FORMAT_ELF) { if (!xm_binutils_elf_rpath_list(istream, 0, lua)) { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_list: failed to parse ELF"); break; } } else if (format == XM_BINUTILS_FORMAT_MACHO) { if (!xm_binutils_macho_rpath_list(istream, 0, lua)) { lua_pop(lua, 1); // pop table lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_list: failed to parse Mach-O"); break; } } else { /* not supported or no rpath for this format * return empty table */ } ok = tb_true; } while (0); if (istream) tb_stream_exit(istream); return ok ? 1 : 2; } /* clean all rpaths from binary file * * @param lua the lua state * @return 1 on success, 2 on failure */ tb_int_t xm_binutils_rpath_clean(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get arguments tb_char_t const *binaryfile = luaL_checkstring(lua, 1); tb_check_return_val(binaryfile, 0); // open file tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RW); if (!istream) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_clean: open %s failed", binaryfile); return 2; } tb_bool_t ok = tb_false; do { if (!tb_stream_open(istream)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_clean: open %s failed", binaryfile); break; } // detect format tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_clean: cannot detect file format"); break; } // clean rpath if (format == XM_BINUTILS_FORMAT_ELF) { if (!xm_binutils_elf_rpath_clean(istream, 0)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_clean: failed to clean ELF"); break; } } else if (format == XM_BINUTILS_FORMAT_MACHO) { if (!xm_binutils_macho_rpath_clean(istream, 0)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_clean: failed to clean Mach-O"); break; } } else { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_clean: format not supported"); break; } lua_pushboolean(lua, tb_true); ok = tb_true; } while (0); if (istream) tb_stream_exit(istream); return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/binutils/wasm/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BINUTILS_WASM_PREFIX_H #define XM_BINUTILS_WASM_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // wasm file magic: \0asm #define XM_WASM_MAGIC0 0x00 #define XM_WASM_MAGIC1 0x61 #define XM_WASM_MAGIC2 0x73 #define XM_WASM_MAGIC3 0x6d // wasm header size: magic(4) + version(4) #define XM_WASM_HEADER_SIZE 8 // wasm section ids #define XM_WASM_SECTION_IMPORT 2 #define XM_WASM_SECTION_EXPORT 7 // wasm custom section names #define XM_WASM_CUSTOM_LINKING "linking" #define XM_WASM_CUSTOM_NAME "name" // wasm import/export kinds #define XM_WASM_KIND_FUNC 0 #define XM_WASM_KIND_TABLE 1 #define XM_WASM_KIND_MEMORY 2 #define XM_WASM_KIND_GLOBAL 3 #define XM_WASM_KIND_TAG 4 // wasm limits flags #define XM_WASM_LIMITS_HAS_MAX 0x01 #define XM_WASM_LIMITS_MEM64 0x04 // leb128 max bytes #define XM_WASM_U32_LEB_MAX 5 #define XM_WASM_U64_LEB_MAX 10 // linking custom section #define XM_WASM_LINKING_VERSION_2 2 #define XM_WASM_LINKING_SUBSEC_SYMTAB 8 // symbol table kinds (linking section) #define XM_WASM_SYMTAB_KIND_FUNCTION 0 #define XM_WASM_SYMTAB_KIND_DATA 1 #define XM_WASM_SYMTAB_KIND_GLOBAL 2 #define XM_WASM_SYMTAB_KIND_SECTION 3 #define XM_WASM_SYMTAB_KIND_EVENT 4 #define XM_WASM_SYMTAB_KIND_TABLE 5 #define XM_WASM_SYMTAB_KIND_TAG 6 // symbol table flags (linking section) #define XM_WASM_SYMTAB_FLAG_UNDEFINED 0x10 // symbol types for binutils.readsyms #define XM_WASM_SYM_UNDEF "U" #define XM_WASM_SYM_TEXT "T" #define XM_WASM_SYM_DATA "D" /* ////////////////////////////////////////////////////////////////////////////////////// * inline implementation */ // decode unsigned leb128 (u32) from current stream offset static __tb_inline__ tb_bool_t xm_binutils_wasm_read_u32_leb(tb_stream_ref_t istream, tb_uint32_t* out) { tb_uint32_t result = 0; tb_uint32_t shift = 0; tb_byte_t byte = 0; for (tb_size_t i = 0; i < XM_WASM_U32_LEB_MAX; i++) { if (!tb_stream_bread(istream, &byte, 1)) { return tb_false; } result |= ((tb_uint32_t)(byte & 0x7f)) << shift; if (!(byte & 0x80)) { *out = result; return tb_true; } shift += 7; } return tb_false; } // decode unsigned leb128 (u64) from current stream offset static __tb_inline__ tb_bool_t xm_binutils_wasm_read_u64_leb(tb_stream_ref_t istream, tb_uint64_t* out) { tb_uint64_t result = 0; tb_uint32_t shift = 0; tb_byte_t byte = 0; for (tb_size_t i = 0; i < XM_WASM_U64_LEB_MAX; i++) { if (!tb_stream_bread(istream, &byte, 1)) { return tb_false; } result |= ((tb_uint64_t)(byte & 0x7f)) << shift; if (!(byte & 0x80)) { *out = result; return tb_true; } shift += 7; } return tb_false; } // read wasm "name" (u32 leb length + bytes), truncate to fit buffer and skip remaining bytes static __tb_inline__ tb_bool_t xm_binutils_wasm_read_name(tb_stream_ref_t istream, tb_char_t* name, tb_size_t name_size) { tb_uint32_t len = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &len)) { return tb_false; } tb_size_t readn = (tb_size_t)tb_min((tb_uint32_t)(name_size > 0 ? name_size - 1 : 0), len); if (readn && !tb_stream_bread(istream, (tb_byte_t*)name, readn)) { return tb_false; } if (name_size) { name[readn] = '\0'; } if (len > readn) { if (!tb_stream_skip(istream, (tb_hize_t)(len - readn))) { return tb_false; } } return tb_true; } // skip wasm limits used by table/memory types, supports wasm32 and wasm64(memory64) static __tb_inline__ tb_bool_t xm_binutils_wasm_skip_limits(tb_stream_ref_t istream) { tb_uint32_t flags = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &flags)) { return tb_false; } if (flags & XM_WASM_LIMITS_MEM64) { tb_uint64_t tmp64 = 0; if (!xm_binutils_wasm_read_u64_leb(istream, &tmp64)) { return tb_false; } if (flags & XM_WASM_LIMITS_HAS_MAX) { if (!xm_binutils_wasm_read_u64_leb(istream, &tmp64)) { return tb_false; } } } else { tb_uint32_t tmp32 = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &tmp32)) { return tb_false; } if (flags & XM_WASM_LIMITS_HAS_MAX) { if (!xm_binutils_wasm_read_u32_leb(istream, &tmp32)) { return tb_false; } } } return tb_true; } // add one symbol table entry: {name=..., type=...} static __tb_inline__ tb_void_t xm_binutils_wasm_add_symbol(lua_State* lua, tb_size_t* result_count, tb_char_t const* name, tb_char_t const* type) { lua_pushinteger(lua, (lua_Integer)(*result_count + 1)); lua_newtable(lua); lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); lua_pushstring(lua, "type"); lua_pushstring(lua, type); lua_settable(lua, -3); lua_settable(lua, -3); (*result_count)++; } // seek and validate wasm header at base_offset, leave stream offset after header static __tb_inline__ tb_bool_t xm_binutils_wasm_check_header(tb_stream_ref_t istream, tb_hize_t base_offset) { if (!tb_stream_seek(istream, base_offset)) { return tb_false; } tb_uint8_t header[XM_WASM_HEADER_SIZE]; if (!tb_stream_bread(istream, header, XM_WASM_HEADER_SIZE)) { return tb_false; } if (header[0] != XM_WASM_MAGIC0 || header[1] != XM_WASM_MAGIC1 || header[2] != XM_WASM_MAGIC2 || header[3] != XM_WASM_MAGIC3) { return tb_false; } return tb_true; } #endif ================================================ FILE: core/src/xmake/binutils/wasm/readsyms.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file readsyms.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "wasm_readsyms" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t xm_binutils_wasm_parse_linking_symtab(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) { tb_uint32_t symcount = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &symcount)) { return tb_false; } for (tb_uint32_t i = 0; i < symcount; i++) { tb_byte_t kind = 0; if (!tb_stream_bread(istream, &kind, 1)) { return tb_false; } tb_uint32_t flags = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &flags)) { return tb_false; } tb_bool_t is_undef = (flags & XM_WASM_SYMTAB_FLAG_UNDEFINED) != 0; tb_char_t name[256] = {0}; if (kind == XM_WASM_SYMTAB_KIND_FUNCTION || kind == XM_WASM_SYMTAB_KIND_GLOBAL || kind == XM_WASM_SYMTAB_KIND_EVENT || kind == XM_WASM_SYMTAB_KIND_TABLE || kind == XM_WASM_SYMTAB_KIND_TAG) { if (!is_undef) { tb_uint32_t index = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &index)) { return tb_false; } } if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { return tb_false; } } else if (kind == XM_WASM_SYMTAB_KIND_DATA) { if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { return tb_false; } if (!is_undef) { tb_uint32_t tmp = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // segment return tb_false; } if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // offset return tb_false; } if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // size return tb_false; } } } else if (kind == XM_WASM_SYMTAB_KIND_SECTION) { tb_uint32_t section_index = 0; if (!xm_binutils_wasm_read_u32_leb(istream, §ion_index)) { return tb_false; } if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { return tb_false; } } else { return tb_false; } if (name[0]) { tb_char_t const* type = XM_WASM_SYM_DATA; if (is_undef) { type = XM_WASM_SYM_UNDEF; } else if (kind == XM_WASM_SYMTAB_KIND_FUNCTION) { type = XM_WASM_SYM_TEXT; } xm_binutils_wasm_add_symbol(lua, result_count, name, type); } if (tb_stream_offset(istream) > payload_end) { return tb_false; } } return tb_true; } static tb_bool_t xm_binutils_wasm_parse_custom_linking(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) { tb_uint32_t version = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &version)) { return tb_false; } while (tb_stream_offset(istream) < payload_end) { tb_byte_t subsec_type = 0; if (!tb_stream_bread(istream, &subsec_type, 1)) { return tb_false; } tb_uint32_t subsec_size = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &subsec_size)) { return tb_false; } tb_hize_t subsec_end = tb_stream_offset(istream) + (tb_hize_t)subsec_size; if (subsec_end > payload_end) { return tb_false; } if (subsec_type == XM_WASM_LINKING_SUBSEC_SYMTAB) { if (!xm_binutils_wasm_parse_linking_symtab(istream, subsec_end, lua, result_count)) { return tb_false; } } if (tb_stream_offset(istream) < subsec_end) { if (!tb_stream_seek(istream, subsec_end)) { return tb_false; } } } return version > 0 ? tb_true : tb_false; } static tb_bool_t xm_binutils_wasm_parse_custom_name(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) { // only use the name section as a fallback when we have no symbols yet if (*result_count != 0) { return tb_true; } while (tb_stream_offset(istream) < payload_end) { tb_byte_t subsec_type = 0; if (!tb_stream_bread(istream, &subsec_type, 1)) { return tb_false; } tb_uint32_t subsec_size = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &subsec_size)) { return tb_false; } tb_hize_t subsec_end = tb_stream_offset(istream) + (tb_hize_t)subsec_size; if (subsec_end > payload_end) { return tb_false; } if (subsec_type == 1) { tb_uint32_t count = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &count)) { return tb_false; } for (tb_uint32_t i = 0; i < count; i++) { tb_uint32_t index = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &index)) { return tb_false; } tb_char_t name[256] = {0}; if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { return tb_false; } if (name[0]) { xm_binutils_wasm_add_symbol(lua, result_count, name, XM_WASM_SYM_TEXT); } if (tb_stream_offset(istream) > subsec_end) { return tb_false; } } } if (tb_stream_offset(istream) < subsec_end) { if (!tb_stream_seek(istream, subsec_end)) { return tb_false; } } } return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); if (!xm_binutils_wasm_check_header(istream, base_offset)) { return tb_false; } lua_newtable(lua); tb_size_t result_count = 0; // parse wasm sections until EOF, collect imports/exports as symbols for (;;) { tb_byte_t section_id = 0; if (!tb_stream_bread(istream, §ion_id, 1)) { break; } tb_uint32_t payload_len = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &payload_len)) { break; } tb_hize_t payload_start = tb_stream_offset(istream); tb_hize_t payload_end = payload_start + (tb_hize_t)payload_len; if (payload_len == 0) { continue; } if (section_id == 0) { // custom section: name + custom payload tb_char_t custom_name[64] = {0}; if (!xm_binutils_wasm_read_name(istream, custom_name, sizeof(custom_name))) { break; } if (!tb_strcmp(custom_name, XM_WASM_CUSTOM_LINKING)) { if (!xm_binutils_wasm_parse_custom_linking(istream, payload_end, lua, &result_count)) { break; } } else if (!tb_strcmp(custom_name, XM_WASM_CUSTOM_NAME)) { if (!xm_binutils_wasm_parse_custom_name(istream, payload_end, lua, &result_count)) { break; } } } else if (section_id == XM_WASM_SECTION_IMPORT) { // import section: (vec import), each import => undefined symbol tb_uint32_t count = 0; if (xm_binutils_wasm_read_u32_leb(istream, &count)) { for (tb_uint32_t i = 0; i < count; i++) { tb_char_t module[256] = {0}; tb_char_t field[256] = {0}; if (!xm_binutils_wasm_read_name(istream, module, sizeof(module))) { break; } if (!xm_binutils_wasm_read_name(istream, field, sizeof(field))) { break; } tb_byte_t kind = 0; if (!tb_stream_bread(istream, &kind, 1)) { break; } tb_uint32_t tmp = 0; if (kind == XM_WASM_KIND_FUNC) { // type index (u32) if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { break; } } else if (kind == XM_WASM_KIND_TABLE) { // table type: elemtype + limits if (!tb_stream_bread(istream, (tb_byte_t*)&kind, 1)) { break; } if (!xm_binutils_wasm_skip_limits(istream)) { break; } } else if (kind == XM_WASM_KIND_MEMORY) { // memory type: limits if (!xm_binutils_wasm_skip_limits(istream)) { break; } } else if (kind == XM_WASM_KIND_GLOBAL) { // global type: valtype + mut tb_byte_t b = 0; if (!tb_stream_bread(istream, &b, 1)) { break; } if (!tb_stream_bread(istream, &b, 1)) { break; } } else if (kind == XM_WASM_KIND_TAG) { // tag: attribute + type index if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { break; } } else { break; } // keep consistent with nm-style output: use the imported field name as symbol name if (field[0]) { xm_binutils_wasm_add_symbol(lua, &result_count, field, XM_WASM_SYM_UNDEF); } else if (module[0]) { xm_binutils_wasm_add_symbol(lua, &result_count, module, XM_WASM_SYM_UNDEF); } } } } else if (section_id == XM_WASM_SECTION_EXPORT) { // export section: (vec export), each export => defined symbol tb_uint32_t count = 0; if (xm_binutils_wasm_read_u32_leb(istream, &count)) { for (tb_uint32_t i = 0; i < count; i++) { tb_char_t name[256] = {0}; if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { break; } tb_byte_t kind = 0; if (!tb_stream_bread(istream, &kind, 1)) { break; } tb_uint32_t index = 0; if (!xm_binutils_wasm_read_u32_leb(istream, &index)) { break; } if (name[0]) { // keep consistent with other formats: function => "T", others => "D" tb_char_t const* type = XM_WASM_SYM_DATA; if (kind == XM_WASM_KIND_FUNC) { type = XM_WASM_SYM_TEXT; } xm_binutils_wasm_add_symbol(lua, &result_count, name, type); } } } } // always seek to end of section payload to continue scanning if (tb_stream_offset(istream) < payload_end) { if (!tb_stream_seek(istream, payload_end)) { break; } } } return tb_true; } ================================================ FILE: core/src/xmake/bloom_filter/bloom_filter_clear.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bloom_filter_clear.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bloom_filter_clear" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_bloom_filter_clear(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the bloom filter tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(filter, 0); // clear filter tb_bloom_filter_clear(filter); lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/bloom_filter/bloom_filter_close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bloom_filter_close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bloom_filter_close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_bloom_filter_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the bloom filter tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(filter, 0); // exit filter tb_bloom_filter_exit(filter); // save result: ok lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/bloom_filter/bloom_filter_data.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bloom_filter_data.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bloom_filter_data" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_bloom_filter_data(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the bloom filter tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(filter, 0); // get data tb_pointer_t data = (tb_pointer_t)tb_bloom_filter_data(filter); if (data) { xm_lua_pushpointer(lua, data); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/bloom_filter/bloom_filter_data_set.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bloom_filter_data_set.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bloom_filter_data_set" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_bloom_filter_data_set(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the bloom filter tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(filter, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (xm_lua_isinteger(lua, 3)) { size = (tb_size_t)lua_tointeger(lua, 3); } if (!data || !size) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // set data tb_bool_t ok = tb_bloom_filter_data_set(filter, data, size); lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/bloom_filter/bloom_filter_get.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bloom_filter_get.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bloom_filter_get" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_bloom_filter_get(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the bloom filter tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(filter, 0); // get item tb_char_t const *item = luaL_checkstring(lua, 2); tb_assert_and_check_return_val(item, 0); // get item tb_bool_t ok = tb_bloom_filter_get(filter, item); lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/bloom_filter/bloom_filter_open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bloom_filter_open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bloom_filter_open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_bloom_filter_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get arguments tb_int_t probability = (tb_int_t)lua_tointeger(lua, 1); tb_int_t hash_count = (tb_int_t)lua_tointeger(lua, 2); tb_int_t item_maxn = (tb_int_t)lua_tointeger(lua, 3); if (hash_count > 16 || item_maxn < 0) { lua_pushnil(lua); lua_pushfstring(lua, "invalid hash count(%p) and item maxn(%d)!", hash_count, item_maxn); return 2; } // init the bloom filter tb_bloom_filter_ref_t filter = tb_bloom_filter_init(probability, hash_count, item_maxn, tb_element_str(tb_true)); if (filter) { xm_lua_pushpointer(lua, (tb_pointer_t)filter); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/bloom_filter/bloom_filter_set.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bloom_filter_set.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bloom_filter_set" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_bloom_filter_set(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the bloom filter tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(filter, 0); // get item tb_char_t const *item = luaL_checkstring(lua, 2); tb_assert_and_check_return_val(item, 0); // set item tb_bool_t ok = tb_bloom_filter_set(filter, item); lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/bloom_filter/bloom_filter_size.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file bloom_filter_size.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "bloom_filter_size" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_bloom_filter_size(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the bloom filter tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(filter, 0); // get size tb_size_t size = tb_bloom_filter_size(filter); lua_pushinteger(lua, (tb_int_t)size); return 1; } ================================================ FILE: core/src/xmake/bloom_filter/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except idata compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to idata writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_BLOOM_FILTER_PREFIX_H #define XM_BLOOM_FILTER_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/config.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file config.h * */ #ifndef XM_CORE_CONFIG_H #define XM_CORE_CONFIG_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "xmake.config.h" #endif ================================================ FILE: core/src/xmake/curses/curses.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file curses.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "curses" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #ifdef XM_CONFIG_API_HAVE_CURSES #include "prefix.h" #include #if defined(PDCURSES) // fix macro redefinition #undef MOUSE_MOVED #endif #define NCURSES_MOUSE_VERSION 2 #ifdef TB_COMPILER_IS_MINGW #include #else #include #endif #if defined(NCURSES_VERSION) #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_CURSES_STDSCR "curses.stdscr" #define XM_CURSES_WINDOW "curses.window" #define XM_CURSES_OK(v) (((v) == ERR) ? 0 : 1) // define functions #define XM_CURSES_NUMBER(n) \ static int xm_curses_##n(lua_State *lua) { \ lua_pushnumber(lua, n()); \ return 1; \ } #define XM_CURSES_NUMBER2(n, v) \ static int xm_curses_##n(lua_State *lua) { \ lua_pushnumber(lua, v); \ return 1; \ } #define XM_CURSES_BOOL(n) \ static int xm_curses_##n(lua_State *lua) { \ lua_pushboolean(lua, n()); \ return 1; \ } #define XM_CURSES_BOOLOK(n) \ static int xm_curses_##n(lua_State *lua) { \ lua_pushboolean(lua, XM_CURSES_OK(n())); \ return 1; \ } #define XM_CURSES_WINDOW_BOOLOK(n) \ static int xm_curses_window_##n(lua_State *lua) { \ WINDOW *w = xm_curses_window_check(lua, 1); \ lua_pushboolean(lua, XM_CURSES_OK(n(w))); \ return 1; \ } // define constants #define XM_CURSES_CONST_(n, v) \ lua_pushstring(lua, n); \ lua_pushnumber(lua, v); \ lua_settable(lua, lua_upvalueindex(1)); #define XM_CURSES_CONST(s) XM_CURSES_CONST_(#s, s) #define XM_CURSES_CONST2(s, v) XM_CURSES_CONST_(#s, v) /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ // map key for pdcurses, keeping the keys consistent with ncurses static int g_mapkey = 0; /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static chtype xm_curses_checkch(lua_State *lua, int index) { if (lua_type(lua, index) == LUA_TNUMBER) { return (chtype)luaL_checknumber(lua, index); } if (lua_type(lua, index) == LUA_TSTRING) { return *lua_tostring(lua, index); } #ifdef USE_LUAJIT luaL_typerror(lua, index, "chtype"); #endif return (chtype)0; } // get character and map key static int xm_curses_window_getch_impl(WINDOW *w) { #ifdef PDCURSES static int has_key = 0; static int temp_key = 0; int key; if (g_mapkey && has_key) { has_key = 0; return temp_key; } key = wgetch(w); if (key == KEY_RESIZE) resize_term(0, 0); if (key == ERR || !g_mapkey) return key; if (key >= ALT_A && key <= ALT_Z) { has_key = 1; temp_key = key - ALT_A + 'A'; } else if (key >= ALT_0 && key <= ALT_9) { has_key = 1; temp_key = key - ALT_0 + '0'; } else { switch (key) { case ALT_DEL: temp_key = KEY_DC; break; case ALT_INS: temp_key = KEY_IC; break; case ALT_HOME: temp_key = KEY_HOME; break; case ALT_END: temp_key = KEY_END; break; case ALT_PGUP: temp_key = KEY_PPAGE; break; case ALT_PGDN: temp_key = KEY_NPAGE; break; case ALT_UP: temp_key = KEY_UP; break; case ALT_DOWN: temp_key = KEY_DOWN; break; case ALT_RIGHT: temp_key = KEY_RIGHT; break; case ALT_LEFT: temp_key = KEY_LEFT; break; case ALT_BKSP: temp_key = KEY_BACKSPACE; break; default: return key; } } has_key = 1; return 27; #else return wgetch(w); #endif } // new a window object static void xm_curses_window_new(lua_State *lua, WINDOW *nw) { if (nw) { WINDOW **w = (WINDOW **)lua_newuserdata(lua, sizeof(WINDOW *)); luaL_getmetatable(lua, XM_CURSES_WINDOW); lua_setmetatable(lua, -2); *w = nw; } else { lua_pushliteral(lua, "failed to create window"); lua_error(lua); } } // get window static WINDOW **xm_curses_window_get(lua_State *lua, int index) { WINDOW **w = (WINDOW **)luaL_checkudata(lua, index, XM_CURSES_WINDOW); if (w == NULL) luaL_argerror(lua, index, "bad curses window"); return w; } // get and check window static WINDOW *xm_curses_window_check(lua_State *lua, int index) { WINDOW **w = xm_curses_window_get(lua, index); if (*w == NULL) luaL_argerror(lua, index, "attempt to use closed curses window"); return *w; } // tostring(window) static int xm_curses_window_tostring(lua_State *lua) { WINDOW **w = xm_curses_window_get(lua, 1); char const *s = NULL; if (*w) s = (char const *)lua_touserdata(lua, 1); lua_pushfstring(lua, "curses window (%s)", s ? s : "closed"); return 1; } // window:move(y, x) static int xm_curses_window_move(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int y = luaL_checkint(lua, 2); int x = luaL_checkint(lua, 3); lua_pushboolean(lua, XM_CURSES_OK(wmove(w, y, x))); return 1; } // window:getyx(y, x) static int xm_curses_window_getyx(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int y, x; getyx(w, y, x); lua_pushnumber(lua, y); lua_pushnumber(lua, x); return 2; } // window:getmaxyx(y, x) static int xm_curses_window_getmaxyx(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int y, x; getmaxyx(w, y, x); lua_pushnumber(lua, y); lua_pushnumber(lua, x); return 2; } // window:delwin() static int xm_curses_window_delwin(lua_State *lua) { WINDOW **w = xm_curses_window_get(lua, 1); if (*w && *w != stdscr) { delwin(*w); *w = NULL; } return 0; } // window:addch(ch) static int xm_curses_window_addch(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); chtype ch = xm_curses_checkch(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(waddch(w, ch))); return 1; } // window:addnstr(str) static int xm_curses_window_addnstr(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); const char *str = luaL_checkstring(lua, 2); int n = luaL_optint(lua, 3, -1); if (n < 0) n = (int)lua_strlen(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(waddnstr(w, str, n))); return 1; } // window:keypad(true) static int xm_curses_window_keypad(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int enabled = lua_isnoneornil(lua, 2) ? 1 : lua_toboolean(lua, 2); if (enabled) { // on WIN32 ALT keys need to be mapped, so to make sure you get the wanted keys, // only makes sense when using keypad(true) and echo(false) g_mapkey = 1; } lua_pushboolean(lua, XM_CURSES_OK(keypad(w, enabled))); return 1; } // window:meta(true) static int xm_curses_window_meta(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int enabled = lua_toboolean(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(meta(w, enabled))); return 1; } // window:nodelay(true) static int xm_curses_window_nodelay(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int enabled = lua_toboolean(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(nodelay(w, enabled))); return 1; } // window:leaveok(true) static int xm_curses_window_leaveok(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int enabled = lua_toboolean(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(leaveok(w, enabled))); return 1; } // window:getch() static int xm_curses_window_getch(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int c = xm_curses_window_getch_impl(w); if (c == ERR) return 0; lua_pushnumber(lua, c); return 1; } // window:attroff(attrs) static int xm_curses_window_attroff(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int attrs = luaL_checkint(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(wattroff(w, attrs))); return 1; } // window:attron(attrs) static int xm_curses_window_attron(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int attrs = luaL_checkint(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(wattron(w, attrs))); return 1; } // window:attrset(attrs) static int xm_curses_window_attrset(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int attrs = luaL_checkint(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(wattrset(w, attrs))); return 1; } // window:copywin(...) static int xm_curses_window_copywin(lua_State *lua) { WINDOW *srcwin = xm_curses_window_check(lua, 1); WINDOW *dstwin = xm_curses_window_check(lua, 2); int sminrow = luaL_checkint(lua, 3); int smincol = luaL_checkint(lua, 4); int dminrow = luaL_checkint(lua, 5); int dmincol = luaL_checkint(lua, 6); int dmaxrow = luaL_checkint(lua, 7); int dmaxcol = luaL_checkint(lua, 8); int overlay = lua_toboolean(lua, 9); lua_pushboolean(lua, XM_CURSES_OK( copywin(srcwin, dstwin, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, overlay))); return 1; } // clean window after exiting program static void xm_curses_cleanup() { if (!isendwin()) { wclear(stdscr); wrefresh(stdscr); endwin(); } } // register constants static void xm_curses_register_constants(lua_State *lua) { // colors XM_CURSES_CONST(COLOR_BLACK) XM_CURSES_CONST(COLOR_RED) XM_CURSES_CONST(COLOR_GREEN) XM_CURSES_CONST(COLOR_YELLOW) XM_CURSES_CONST(COLOR_BLUE) XM_CURSES_CONST(COLOR_MAGENTA) XM_CURSES_CONST(COLOR_CYAN) XM_CURSES_CONST(COLOR_WHITE) // alternate character set XM_CURSES_CONST(ACS_BLOCK) XM_CURSES_CONST(ACS_BOARD) XM_CURSES_CONST(ACS_BTEE) XM_CURSES_CONST(ACS_TTEE) XM_CURSES_CONST(ACS_LTEE) XM_CURSES_CONST(ACS_RTEE) XM_CURSES_CONST(ACS_LLCORNER) XM_CURSES_CONST(ACS_LRCORNER) XM_CURSES_CONST(ACS_URCORNER) XM_CURSES_CONST(ACS_ULCORNER) XM_CURSES_CONST(ACS_LARROW) XM_CURSES_CONST(ACS_RARROW) XM_CURSES_CONST(ACS_UARROW) XM_CURSES_CONST(ACS_DARROW) XM_CURSES_CONST(ACS_HLINE) XM_CURSES_CONST(ACS_VLINE) XM_CURSES_CONST(ACS_BULLET) XM_CURSES_CONST(ACS_CKBOARD) XM_CURSES_CONST(ACS_LANTERN) XM_CURSES_CONST(ACS_DEGREE) XM_CURSES_CONST(ACS_DIAMOND) XM_CURSES_CONST(ACS_PLMINUS) XM_CURSES_CONST(ACS_PLUS) XM_CURSES_CONST(ACS_S1) XM_CURSES_CONST(ACS_S9) // attributes XM_CURSES_CONST(A_NORMAL) XM_CURSES_CONST(A_STANDOUT) XM_CURSES_CONST(A_UNDERLINE) XM_CURSES_CONST(A_REVERSE) XM_CURSES_CONST(A_BLINK) XM_CURSES_CONST(A_DIM) XM_CURSES_CONST(A_BOLD) XM_CURSES_CONST(A_PROTECT) XM_CURSES_CONST(A_INVIS) XM_CURSES_CONST(A_ALTCHARSET) XM_CURSES_CONST(A_CHARTEXT) // key functions XM_CURSES_CONST(KEY_BREAK) XM_CURSES_CONST(KEY_DOWN) XM_CURSES_CONST(KEY_UP) XM_CURSES_CONST(KEY_LEFT) XM_CURSES_CONST(KEY_RIGHT) XM_CURSES_CONST(KEY_HOME) XM_CURSES_CONST(KEY_BACKSPACE) XM_CURSES_CONST(KEY_DL) XM_CURSES_CONST(KEY_IL) XM_CURSES_CONST(KEY_DC) XM_CURSES_CONST(KEY_IC) XM_CURSES_CONST(KEY_EIC) XM_CURSES_CONST(KEY_CLEAR) XM_CURSES_CONST(KEY_EOS) XM_CURSES_CONST(KEY_EOL) XM_CURSES_CONST(KEY_SF) XM_CURSES_CONST(KEY_SR) XM_CURSES_CONST(KEY_NPAGE) XM_CURSES_CONST(KEY_PPAGE) XM_CURSES_CONST(KEY_STAB) XM_CURSES_CONST(KEY_CTAB) XM_CURSES_CONST(KEY_CATAB) XM_CURSES_CONST(KEY_ENTER) XM_CURSES_CONST(KEY_SRESET) XM_CURSES_CONST(KEY_RESET) XM_CURSES_CONST(KEY_PRINT) XM_CURSES_CONST(KEY_LL) XM_CURSES_CONST(KEY_A1) XM_CURSES_CONST(KEY_A3) XM_CURSES_CONST(KEY_B2) XM_CURSES_CONST(KEY_C1) XM_CURSES_CONST(KEY_C3) XM_CURSES_CONST(KEY_BTAB) XM_CURSES_CONST(KEY_BEG) XM_CURSES_CONST(KEY_CANCEL) XM_CURSES_CONST(KEY_CLOSE) XM_CURSES_CONST(KEY_COMMAND) XM_CURSES_CONST(KEY_COPY) XM_CURSES_CONST(KEY_CREATE) XM_CURSES_CONST(KEY_END) XM_CURSES_CONST(KEY_EXIT) XM_CURSES_CONST(KEY_FIND) XM_CURSES_CONST(KEY_HELP) XM_CURSES_CONST(KEY_MARK) XM_CURSES_CONST(KEY_MESSAGE) #ifdef PDCURSES // https://github.com/xmake-io/xmake/issues/1610#issuecomment-971149885 XM_CURSES_CONST(KEY_C2) XM_CURSES_CONST(KEY_A2) XM_CURSES_CONST(KEY_B1) XM_CURSES_CONST(KEY_B3) #endif #if !defined(XCURSES) #ifndef NOMOUSE XM_CURSES_CONST(KEY_MOUSE) #endif #endif XM_CURSES_CONST(KEY_MOVE) XM_CURSES_CONST(KEY_NEXT) XM_CURSES_CONST(KEY_OPEN) XM_CURSES_CONST(KEY_OPTIONS) XM_CURSES_CONST(KEY_PREVIOUS) XM_CURSES_CONST(KEY_REDO) XM_CURSES_CONST(KEY_REFERENCE) XM_CURSES_CONST(KEY_REFRESH) XM_CURSES_CONST(KEY_REPLACE) XM_CURSES_CONST(KEY_RESIZE) XM_CURSES_CONST(KEY_RESTART) XM_CURSES_CONST(KEY_RESUME) XM_CURSES_CONST(KEY_SAVE) XM_CURSES_CONST(KEY_SBEG) XM_CURSES_CONST(KEY_SCANCEL) XM_CURSES_CONST(KEY_SCOMMAND) XM_CURSES_CONST(KEY_SCOPY) XM_CURSES_CONST(KEY_SCREATE) XM_CURSES_CONST(KEY_SDC) XM_CURSES_CONST(KEY_SDL) XM_CURSES_CONST(KEY_SELECT) XM_CURSES_CONST(KEY_SEND) XM_CURSES_CONST(KEY_SEOL) XM_CURSES_CONST(KEY_SEXIT) XM_CURSES_CONST(KEY_SFIND) XM_CURSES_CONST(KEY_SHELP) XM_CURSES_CONST(KEY_SHOME) XM_CURSES_CONST(KEY_SIC) XM_CURSES_CONST(KEY_SLEFT) XM_CURSES_CONST(KEY_SMESSAGE) XM_CURSES_CONST(KEY_SMOVE) XM_CURSES_CONST(KEY_SNEXT) XM_CURSES_CONST(KEY_SOPTIONS) XM_CURSES_CONST(KEY_SPREVIOUS) XM_CURSES_CONST(KEY_SPRINT) XM_CURSES_CONST(KEY_SREDO) XM_CURSES_CONST(KEY_SREPLACE) XM_CURSES_CONST(KEY_SRIGHT) XM_CURSES_CONST(KEY_SRSUME) XM_CURSES_CONST(KEY_SSAVE) XM_CURSES_CONST(KEY_SSUSPEND) XM_CURSES_CONST(KEY_SUNDO) XM_CURSES_CONST(KEY_SUSPEND) XM_CURSES_CONST(KEY_UNDO) // KEY_Fx 0 <= x <= 63 XM_CURSES_CONST(KEY_F0) XM_CURSES_CONST2(KEY_F1, KEY_F(1)) XM_CURSES_CONST2(KEY_F2, KEY_F(2)) XM_CURSES_CONST2(KEY_F3, KEY_F(3)) XM_CURSES_CONST2(KEY_F4, KEY_F(4)) XM_CURSES_CONST2(KEY_F5, KEY_F(5)) XM_CURSES_CONST2(KEY_F6, KEY_F(6)) XM_CURSES_CONST2(KEY_F7, KEY_F(7)) XM_CURSES_CONST2(KEY_F8, KEY_F(8)) XM_CURSES_CONST2(KEY_F9, KEY_F(9)) XM_CURSES_CONST2(KEY_F10, KEY_F(10)) XM_CURSES_CONST2(KEY_F11, KEY_F(11)) XM_CURSES_CONST2(KEY_F12, KEY_F(12)) #if !defined(XCURSES) #ifndef NOMOUSE // mouse constants XM_CURSES_CONST(BUTTON1_RELEASED) XM_CURSES_CONST(BUTTON1_PRESSED) XM_CURSES_CONST(BUTTON1_CLICKED) XM_CURSES_CONST(BUTTON1_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON1_TRIPLE_CLICKED) XM_CURSES_CONST(BUTTON2_RELEASED) XM_CURSES_CONST(BUTTON2_PRESSED) XM_CURSES_CONST(BUTTON2_CLICKED) XM_CURSES_CONST(BUTTON2_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON2_TRIPLE_CLICKED) XM_CURSES_CONST(BUTTON3_RELEASED) XM_CURSES_CONST(BUTTON3_PRESSED) XM_CURSES_CONST(BUTTON3_CLICKED) XM_CURSES_CONST(BUTTON3_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON3_TRIPLE_CLICKED) XM_CURSES_CONST(BUTTON4_RELEASED) XM_CURSES_CONST(BUTTON4_PRESSED) XM_CURSES_CONST(BUTTON4_CLICKED) XM_CURSES_CONST(BUTTON4_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON4_TRIPLE_CLICKED) XM_CURSES_CONST(BUTTON_CTRL) XM_CURSES_CONST(BUTTON_SHIFT) XM_CURSES_CONST(BUTTON_ALT) XM_CURSES_CONST(REPORT_MOUSE_POSITION) XM_CURSES_CONST(ALL_MOUSE_EVENTS) #if NCURSES_MOUSE_VERSION > 1 XM_CURSES_CONST(BUTTON5_RELEASED) XM_CURSES_CONST(BUTTON5_PRESSED) XM_CURSES_CONST(BUTTON5_CLICKED) XM_CURSES_CONST(BUTTON5_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON5_TRIPLE_CLICKED) #endif #endif #endif } // init curses static int xm_curses_initscr(lua_State *lua) { WINDOW *w = initscr(); if (!w) return 0; xm_curses_window_new(lua, w); #if defined(NCURSES_VERSION) // ESCDELAY = 0; set_escdelay(0); #endif lua_pushstring(lua, XM_CURSES_STDSCR); lua_pushvalue(lua, -2); lua_rawset(lua, LUA_REGISTRYINDEX); xm_curses_register_constants(lua); #ifndef PDCURSES atexit(xm_curses_cleanup); #endif return 1; } static int xm_curses_endwin(lua_State *lua) { endwin(); #ifdef XCURSES XCursesExit(); exit(0); #endif return 0; } static int xm_curses_stdscr(lua_State *lua) { lua_pushstring(lua, XM_CURSES_STDSCR); lua_rawget(lua, LUA_REGISTRYINDEX); return 1; } #if !defined(XCURSES) && !defined(NOMOUSE) static int xm_curses_getmouse(lua_State *lua) { MEVENT e; if (getmouse(&e) == OK) { lua_pushinteger(lua, e.bstate); lua_pushinteger(lua, e.x); lua_pushinteger(lua, e.y); lua_pushinteger(lua, e.z); lua_pushinteger(lua, e.id); return 5; } lua_pushnil(lua); return 1; } static int xm_curses_mousemask(lua_State *lua) { mmask_t m = luaL_checkint(lua, 1); mmask_t om; m = mousemask(m, &om); lua_pushinteger(lua, m); lua_pushinteger(lua, om); return 2; } #endif static int xm_curses_init_pair(lua_State *lua) { short pair = luaL_checkint(lua, 1); short f = luaL_checkint(lua, 2); short b = luaL_checkint(lua, 3); lua_pushboolean(lua, XM_CURSES_OK(init_pair(pair, f, b))); return 1; } static int xm_curses_COLOR_PAIR(lua_State *lua) { int n = luaL_checkint(lua, 1); lua_pushnumber(lua, COLOR_PAIR(n)); return 1; } static int xm_curses_curs_set(lua_State *lua) { int vis = luaL_checkint(lua, 1); int state = curs_set(vis); if (state == ERR) return 0; lua_pushnumber(lua, state); return 1; } static int xm_curses_napms(lua_State *lua) { int ms = luaL_checkint(lua, 1); lua_pushboolean(lua, XM_CURSES_OK(napms(ms))); return 1; } static int xm_curses_cbreak(lua_State *lua) { if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) { lua_pushboolean(lua, XM_CURSES_OK(cbreak())); } else { lua_pushboolean(lua, XM_CURSES_OK(nocbreak())); } return 1; } static int xm_curses_echo(lua_State *lua) { if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) { lua_pushboolean(lua, XM_CURSES_OK(echo())); } else { lua_pushboolean(lua, XM_CURSES_OK(noecho())); } return 1; } static int xm_curses_nl(lua_State *lua) { if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) { lua_pushboolean(lua, XM_CURSES_OK(nl())); } else { lua_pushboolean(lua, XM_CURSES_OK(nonl())); } return 1; } static int xm_curses_newpad(lua_State *lua) { int nlines = luaL_checkint(lua, 1); int ncols = luaL_checkint(lua, 2); xm_curses_window_new(lua, newpad(nlines, ncols)); return 1; } XM_CURSES_NUMBER2(COLS, COLS) XM_CURSES_NUMBER2(LINES, LINES) XM_CURSES_BOOL(isendwin) XM_CURSES_BOOLOK(start_color) XM_CURSES_BOOL(has_colors) XM_CURSES_BOOLOK(doupdate) XM_CURSES_WINDOW_BOOLOK(wclear) XM_CURSES_WINDOW_BOOLOK(wnoutrefresh) /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ static const luaL_Reg g_window_functions[] = { { "close", xm_curses_window_delwin }, { "keypad", xm_curses_window_keypad }, { "meta", xm_curses_window_meta }, { "nodelay", xm_curses_window_nodelay }, { "leaveok", xm_curses_window_leaveok }, { "move", xm_curses_window_move }, { "clear", xm_curses_window_wclear }, { "noutrefresh", xm_curses_window_wnoutrefresh }, { "attroff", xm_curses_window_attroff }, { "attron", xm_curses_window_attron }, { "attrset", xm_curses_window_attrset }, { "getch", xm_curses_window_getch }, { "getyx", xm_curses_window_getyx }, { "getmaxyx", xm_curses_window_getmaxyx }, { "addch", xm_curses_window_addch }, { "addstr", xm_curses_window_addnstr }, { "copy", xm_curses_window_copywin }, { "__gc", xm_curses_window_delwin }, { "__tostring", xm_curses_window_tostring }, { NULL, NULL }, }; static const luaL_Reg g_curses_functions[] = { { "done", xm_curses_endwin }, { "isdone", xm_curses_isendwin }, { "main_window", xm_curses_stdscr }, { "columns", xm_curses_COLS }, { "lines", xm_curses_LINES }, { "start_color", xm_curses_start_color }, { "has_colors", xm_curses_has_colors }, { "init_pair", xm_curses_init_pair }, { "color_pair", xm_curses_COLOR_PAIR }, { "napms", xm_curses_napms }, { "cursor_set", xm_curses_curs_set }, { "new_pad", xm_curses_newpad }, { "doupdate", xm_curses_doupdate }, { "cbreak", xm_curses_cbreak }, { "echo", xm_curses_echo }, { "nl", xm_curses_nl }, #if !defined(XCURSES) #ifndef NOMOUSE { "mousemask", xm_curses_mousemask }, { "getmouse", xm_curses_getmouse }, #endif #endif { NULL, NULL }, }; /* ////////////////////////////////////////////////////////////////////////////////////// * implementations */ int xm_lua_curses_register(lua_State *lua, const char *module) { // create new metatable for window objects luaL_newmetatable(lua, XM_CURSES_WINDOW); lua_pushliteral(lua, "__index"); lua_pushvalue(lua, -2); /* push metatable */ lua_rawset(lua, -3); /* metatable.__index = metatable */ luaL_setfuncs(lua, g_window_functions, 0); lua_pop(lua, 1); /* remove metatable from stack */ // create global table with curses methods/variables/constants lua_newtable(lua); luaL_setfuncs(lua, g_curses_functions, 0); // add curses.init() lua_pushstring(lua, "init"); lua_pushvalue(lua, -2); lua_pushcclosure(lua, xm_curses_initscr, 1); lua_settable(lua, -3); // register global curses module lua_setglobal(lua, module); /* since version 5.4, the ncurses library decides how to interpret non-ASCII data using the nl_langinfo function. * that means that you have to call setlocale() in the application and encode Unicode strings using one of the system’s available encodings. * * and we need to link libncurses_window.so for drawing vline, hline characters */ #if defined(NCURSES_VERSION) setlocale(LC_ALL, ""); #endif return 1; } #endif ================================================ FILE: core/src/xmake/curses/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author uael * @file prefix.h * */ #ifndef XM_CURSES_PREFIX_H #define XM_CURSES_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/engine.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file engine.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "engine" #define TB_TRACE_MODULE_DEBUG (1) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "xmake.h" #include "io/poller.h" #if defined(TB_CONFIG_OS_WINDOWS) #include #include #include #elif defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS) #include #include #include #elif defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) || defined(TB_CONFIG_OS_ANDROID) || \ defined(TB_CONFIG_OS_HAIKU) || defined(TB_CONFIG_OS_SOLARIS) #include #include #endif #ifdef TB_CONFIG_OS_BSD #include #include #include #endif #ifdef TB_CONFIG_OS_SOLARIS #include #include #endif #ifdef TB_CONFIG_OS_HAIKU #include #endif #ifdef __COSMOPOLITAN__ #include #endif // for uid #ifndef TB_CONFIG_OS_WINDOWS #include #include #endif // for embed files #ifdef XM_EMBED_ENABLE #include "lz4/prefix.h" #endif /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // proc/self #if defined(TB_CONFIG_OS_LINUX) #define XM_PROC_SELF_FILE "/proc/self/exe" #elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__) && !defined(__FreeBSD__) #if defined(__NetBSD__) #define XM_PROC_SELF_FILE "/proc/curproc/exe" #else #define XM_PROC_SELF_FILE "/proc/curproc/file" #endif #elif defined(TB_CONFIG_OS_SOLARIS) #define XM_PROC_SELF_FILE "/proc/self/path/a.out" #endif // hook lua memory allocator #define XM_HOOK_LUA_MEMALLOC (0) /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the engine type typedef struct __xm_engine_t { // the lua lua_State *lua; // the engine name tb_char_t name[64]; // the io poller tb_poller_ref_t poller; xm_poller_state_t poller_state; #ifdef XM_EMBED_ENABLE // the temporary directory tb_char_t tmpdir[TB_PATH_MAXN]; // the embed files tb_byte_t const *embeddata[32]; tb_size_t embedsize[32]; tb_size_t embedcount; #endif } xm_engine_t; /* ////////////////////////////////////////////////////////////////////////////////////// * declaration */ // the os functions tb_int_t xm_os_argv(lua_State *lua); tb_int_t xm_os_args(lua_State *lua); tb_int_t xm_os_find(lua_State *lua); tb_int_t xm_os_link(lua_State *lua); tb_int_t xm_os_isdir(lua_State *lua); tb_int_t xm_os_rmdir(lua_State *lua); tb_int_t xm_os_mkdir(lua_State *lua); tb_int_t xm_os_cpdir(lua_State *lua); tb_int_t xm_os_chdir(lua_State *lua); tb_int_t xm_os_mtime(lua_State *lua); tb_int_t xm_os_sleep(lua_State *lua); tb_int_t xm_os_mclock(lua_State *lua); tb_int_t xm_os_curdir(lua_State *lua); tb_int_t xm_os_tmpdir(lua_State *lua); tb_int_t xm_os_islink(lua_State *lua); tb_int_t xm_os_isfile(lua_State *lua); tb_int_t xm_os_touch(lua_State *lua); tb_int_t xm_os_rmfile(lua_State *lua); tb_int_t xm_os_cpfile(lua_State *lua); tb_int_t xm_os_fscase(lua_State *lua); tb_int_t xm_os_rename(lua_State *lua); tb_int_t xm_os_exists(lua_State *lua); tb_int_t xm_os_setenv(lua_State *lua); tb_int_t xm_os_getenv(lua_State *lua); tb_int_t xm_os_getenvs(lua_State *lua); tb_int_t xm_os_cpuinfo(lua_State *lua); tb_int_t xm_os_meminfo(lua_State *lua); tb_int_t xm_os_readlink(lua_State *lua); tb_int_t xm_os_filesize(lua_State *lua); tb_int_t xm_os_access(lua_State *lua); tb_int_t xm_os_emptydir(lua_State *lua); tb_int_t xm_os_syserror(lua_State *lua); tb_int_t xm_os_strerror(lua_State *lua); tb_int_t xm_os_getwinsize(lua_State *lua); tb_int_t xm_os_getpid(lua_State *lua); tb_int_t xm_os_signal(lua_State *lua); #ifndef TB_CONFIG_OS_WINDOWS tb_int_t xm_os_uid(lua_State *lua); tb_int_t xm_os_gid(lua_State *lua); tb_int_t xm_os_getown(lua_State *lua); #endif // the io/file functions tb_int_t xm_io_stdfile(lua_State *lua); tb_int_t xm_io_file_open(lua_State *lua); tb_int_t xm_io_file_read(lua_State *lua); tb_int_t xm_io_file_readable(lua_State *lua); tb_int_t xm_io_file_seek(lua_State *lua); tb_int_t xm_io_file_size(lua_State *lua); tb_int_t xm_io_file_rawfd(lua_State *lua); tb_int_t xm_io_file_write(lua_State *lua); tb_int_t xm_io_file_flush(lua_State *lua); tb_int_t xm_io_file_close(lua_State *lua); tb_int_t xm_io_file_convert(lua_State *lua); tb_int_t xm_io_file_isatty(lua_State *lua); // the io/filelock functions tb_int_t xm_io_filelock_open(lua_State *lua); tb_int_t xm_io_filelock_lock(lua_State *lua); tb_int_t xm_io_filelock_unlock(lua_State *lua); tb_int_t xm_io_filelock_trylock(lua_State *lua); tb_int_t xm_io_filelock_close(lua_State *lua); // the io/socket functions tb_int_t xm_io_socket_open(lua_State *lua); tb_int_t xm_io_socket_rawfd(lua_State *lua); tb_int_t xm_io_socket_peeraddr(lua_State *lua); tb_int_t xm_io_socket_wait(lua_State *lua); tb_int_t xm_io_socket_bind(lua_State *lua); tb_int_t xm_io_socket_ctrl(lua_State *lua); tb_int_t xm_io_socket_listen(lua_State *lua); tb_int_t xm_io_socket_accept(lua_State *lua); tb_int_t xm_io_socket_connect(lua_State *lua); tb_int_t xm_io_socket_send(lua_State *lua); tb_int_t xm_io_socket_sendto(lua_State *lua); tb_int_t xm_io_socket_sendfile(lua_State *lua); tb_int_t xm_io_socket_recv(lua_State *lua); tb_int_t xm_io_socket_recvfrom(lua_State *lua); tb_int_t xm_io_socket_kill(lua_State *lua); tb_int_t xm_io_socket_close(lua_State *lua); // the io/pipe functions tb_int_t xm_io_pipe_open(lua_State *lua); tb_int_t xm_io_pipe_openpair(lua_State *lua); tb_int_t xm_io_pipe_close(lua_State *lua); tb_int_t xm_io_pipe_read(lua_State *lua); tb_int_t xm_io_pipe_write(lua_State *lua); tb_int_t xm_io_pipe_wait(lua_State *lua); tb_int_t xm_io_pipe_connect(lua_State *lua); // the io/poller functions tb_int_t xm_io_poller_insert(lua_State *lua); tb_int_t xm_io_poller_modify(lua_State *lua); tb_int_t xm_io_poller_remove(lua_State *lua); tb_int_t xm_io_poller_spank(lua_State *lua); tb_int_t xm_io_poller_support(lua_State *lua); tb_int_t xm_io_poller_wait(lua_State *lua); // the path functions tb_int_t xm_path_relative(lua_State *lua); tb_int_t xm_path_absolute(lua_State *lua); tb_int_t xm_path_translate(lua_State *lua); tb_int_t xm_path_directory(lua_State *lua); tb_int_t xm_path_is_absolute(lua_State *lua); // the hash functions tb_int_t xm_hash_uuid4(lua_State *lua); tb_int_t xm_hash_sha(lua_State *lua); tb_int_t xm_hash_md5(lua_State *lua); tb_int_t xm_hash_xxhash(lua_State *lua); tb_int_t xm_hash_rand32(lua_State *lua); tb_int_t xm_hash_rand64(lua_State *lua); tb_int_t xm_hash_rand128(lua_State *lua); // the base64 functions tb_int_t xm_base64_encode(lua_State *lua); tb_int_t xm_base64_decode(lua_State *lua); // the lz4 functions tb_int_t xm_lz4_compress(lua_State *lua); tb_int_t xm_lz4_decompress(lua_State *lua); tb_int_t xm_lz4_block_compress(lua_State *lua); tb_int_t xm_lz4_block_decompress(lua_State *lua); tb_int_t xm_lz4_compress_file(lua_State *lua); tb_int_t xm_lz4_decompress_file(lua_State *lua); tb_int_t xm_lz4_compress_stream_open(lua_State *lua); tb_int_t xm_lz4_compress_stream_read(lua_State *lua); tb_int_t xm_lz4_compress_stream_write(lua_State *lua); tb_int_t xm_lz4_compress_stream_close(lua_State *lua); tb_int_t xm_lz4_decompress_stream_open(lua_State *lua); tb_int_t xm_lz4_decompress_stream_read(lua_State *lua); tb_int_t xm_lz4_decompress_stream_write(lua_State *lua); tb_int_t xm_lz4_decompress_stream_close(lua_State *lua); // the bloom filter functions tb_int_t xm_bloom_filter_open(lua_State *lua); tb_int_t xm_bloom_filter_close(lua_State *lua); tb_int_t xm_bloom_filter_clear(lua_State *lua); tb_int_t xm_bloom_filter_data(lua_State *lua); tb_int_t xm_bloom_filter_size(lua_State *lua); tb_int_t xm_bloom_filter_get(lua_State *lua); tb_int_t xm_bloom_filter_set(lua_State *lua); tb_int_t xm_bloom_filter_data_set(lua_State *lua); // the windows functions #ifdef TB_CONFIG_OS_WINDOWS tb_int_t xm_winos_cp_info(lua_State *lua); tb_int_t xm_winos_console_cp(lua_State *lua); tb_int_t xm_winos_console_output_cp(lua_State *lua); tb_int_t xm_winos_ansi_cp(lua_State *lua); tb_int_t xm_winos_oem_cp(lua_State *lua); tb_int_t xm_winos_logical_drives(lua_State *lua); tb_int_t xm_winos_registry_query(lua_State *lua); tb_int_t xm_winos_registry_keys(lua_State *lua); tb_int_t xm_winos_registry_values(lua_State *lua); tb_int_t xm_winos_short_path(lua_State *lua); tb_int_t xm_winos_processes(lua_State* lua); tb_int_t xm_winos_set_error_mode(lua_State *lua); tb_int_t xm_winos_file_signature(lua_State *lua); #endif // the utf8 functions tb_int_t xm_utf8_len(lua_State *lua); tb_int_t xm_utf8_char(lua_State *lua); tb_int_t xm_utf8_byte(lua_State *lua); tb_int_t xm_utf8_codepoint(lua_State *lua); tb_int_t xm_utf8_offset(lua_State *lua); tb_int_t xm_utf8_codes(lua_State *lua); tb_int_t xm_utf8_sub(lua_State *lua); tb_int_t xm_utf8_reverse(lua_State *lua); tb_int_t xm_utf8_lastof(lua_State *lua); tb_int_t xm_utf8_find(lua_State *lua); tb_int_t xm_utf8_width(lua_State *lua); // the string functions tb_int_t xm_string_trim(lua_State *lua); tb_int_t xm_string_split(lua_State *lua); tb_int_t xm_string_lastof(lua_State *lua); tb_int_t xm_string_convert(lua_State *lua); tb_int_t xm_string_endswith(lua_State *lua); tb_int_t xm_string_startswith(lua_State *lua); tb_int_t xm_string_lower(lua_State *lua); tb_int_t xm_string_upper(lua_State *lua); // the process functions tb_int_t xm_process_open(lua_State *lua); tb_int_t xm_process_openv(lua_State *lua); tb_int_t xm_process_wait(lua_State *lua); tb_int_t xm_process_kill(lua_State *lua); tb_int_t xm_process_close(lua_State *lua); // the fwatcher functions tb_int_t xm_fwatcher_open(lua_State *lua); tb_int_t xm_fwatcher_add(lua_State *lua); tb_int_t xm_fwatcher_remove(lua_State *lua); tb_int_t xm_fwatcher_wait(lua_State *lua); tb_int_t xm_fwatcher_close(lua_State *lua); // the sandbox functions tb_int_t xm_sandbox_interactive(lua_State *lua); #ifdef XM_CONFIG_API_HAVE_READLINE // the readline functions tb_int_t xm_readline_readline(lua_State *lua); tb_int_t xm_readline_history_list(lua_State *lua); tb_int_t xm_readline_add_history(lua_State *lua); tb_int_t xm_readline_clear_history(lua_State *lua); #endif // the semver functions tb_int_t xm_semver_parse(lua_State *lua); tb_int_t xm_semver_compare(lua_State *lua); tb_int_t xm_semver_satisfies(lua_State *lua); tb_int_t xm_semver_select(lua_State *lua); // the libc functions tb_int_t xm_libc_malloc(lua_State *lua); tb_int_t xm_libc_free(lua_State *lua); tb_int_t xm_libc_memcpy(lua_State *lua); tb_int_t xm_libc_memmov(lua_State *lua); tb_int_t xm_libc_memset(lua_State *lua); tb_int_t xm_libc_strndup(lua_State *lua); tb_int_t xm_libc_dataptr(lua_State *lua); tb_int_t xm_libc_byteof(lua_State *lua); tb_int_t xm_libc_setbyte(lua_State *lua); // the tty functions tb_int_t xm_tty_term_mode(lua_State *lua); tb_int_t xm_tty_session_id(lua_State *lua); // the package functions tb_int_t xm_package_loadxmi(lua_State *lua); // the binutils functions tb_int_t xm_binutils_bin2c(lua_State *lua); tb_int_t xm_binutils_bin2coff(lua_State *lua); tb_int_t xm_binutils_bin2macho(lua_State *lua); tb_int_t xm_binutils_bin2elf(lua_State *lua); tb_int_t xm_binutils_readsyms(lua_State *lua); tb_int_t xm_binutils_deplibs(lua_State *lua); tb_int_t xm_binutils_rpath_list(lua_State *lua); tb_int_t xm_binutils_rpath_clean(lua_State *lua); tb_int_t xm_binutils_extractlib(lua_State *lua); tb_int_t xm_binutils_format(lua_State *lua); #ifdef XM_CONFIG_API_HAVE_CURSES // register curses functions tb_int_t xm_lua_curses_register(lua_State *lua, tb_char_t const *module); #endif // the thread functions tb_int_t xm_thread_init(lua_State *lua); tb_int_t xm_thread_exit(lua_State *lua); tb_int_t xm_thread_wait(lua_State *lua); tb_int_t xm_thread_suspend(lua_State *lua); tb_int_t xm_thread_resume(lua_State *lua); // the thread/mutex functions tb_int_t xm_thread_mutex_init(lua_State *lua); tb_int_t xm_thread_mutex_exit(lua_State *lua); tb_int_t xm_thread_mutex_lock(lua_State *lua); tb_int_t xm_thread_mutex_trylock(lua_State *lua); tb_int_t xm_thread_mutex_unlock(lua_State *lua); tb_int_t xm_thread_mutex_incref(lua_State *lua); // the thread/event functions tb_int_t xm_thread_event_init(lua_State *lua); tb_int_t xm_thread_event_exit(lua_State *lua); tb_int_t xm_thread_event_post(lua_State *lua); tb_int_t xm_thread_event_wait(lua_State *lua); tb_int_t xm_thread_event_incref(lua_State *lua); // the thread/semaphore functions tb_int_t xm_thread_semaphore_init(lua_State *lua); tb_int_t xm_thread_semaphore_exit(lua_State *lua); tb_int_t xm_thread_semaphore_post(lua_State *lua); tb_int_t xm_thread_semaphore_wait(lua_State *lua); tb_int_t xm_thread_semaphore_incref(lua_State *lua); // the thread/queue functions tb_int_t xm_thread_queue_init(lua_State *lua); tb_int_t xm_thread_queue_exit(lua_State *lua); tb_int_t xm_thread_queue_size(lua_State *lua); tb_int_t xm_thread_queue_clear(lua_State *lua); tb_int_t xm_thread_queue_incref(lua_State *lua); tb_int_t xm_thread_queue_push(lua_State *lua); tb_int_t xm_thread_queue_pop(lua_State *lua); // the thread/sharedata functions tb_int_t xm_thread_sharedata_init(lua_State *lua); tb_int_t xm_thread_sharedata_exit(lua_State *lua); tb_int_t xm_thread_sharedata_clear(lua_State *lua); tb_int_t xm_thread_sharedata_incref(lua_State *lua); tb_int_t xm_thread_sharedata_set(lua_State *lua); tb_int_t xm_thread_sharedata_get_(lua_State *lua); // open cjson __tb_extern_c_enter__ tb_int_t luaopen_cjson(lua_State *l); __tb_extern_c_leave__ /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ // the os functions static luaL_Reg const g_os_functions[] = { { "argv", xm_os_argv }, { "args", xm_os_args }, { "find", xm_os_find }, { "link", xm_os_link }, { "isdir", xm_os_isdir }, { "rmdir", xm_os_rmdir }, { "mkdir", xm_os_mkdir }, { "cpdir", xm_os_cpdir }, { "chdir", xm_os_chdir }, { "mtime", xm_os_mtime }, { "sleep", xm_os_sleep }, { "mclock", xm_os_mclock }, { "curdir", xm_os_curdir }, { "tmpdir", xm_os_tmpdir }, { "islink", xm_os_islink }, { "isfile", xm_os_isfile }, { "touch", xm_os_touch }, { "rmfile", xm_os_rmfile }, { "cpfile", xm_os_cpfile }, { "fscase", xm_os_fscase }, { "rename", xm_os_rename }, { "exists", xm_os_exists }, { "access", xm_os_access }, { "setenv", xm_os_setenv }, { "getenv", xm_os_getenv }, { "getenvs", xm_os_getenvs }, { "cpuinfo", xm_os_cpuinfo }, { "meminfo", xm_os_meminfo }, { "readlink", xm_os_readlink }, { "emptydir", xm_os_emptydir }, { "strerror", xm_os_strerror }, { "syserror", xm_os_syserror }, { "filesize", xm_os_filesize }, { "getwinsize", xm_os_getwinsize }, { "getpid", xm_os_getpid }, { "signal", xm_os_signal }, #ifndef TB_CONFIG_OS_WINDOWS { "uid", xm_os_uid }, { "gid", xm_os_gid }, { "getown", xm_os_getown }, #endif { tb_null, tb_null }, }; // the windows functions #ifdef TB_CONFIG_OS_WINDOWS static luaL_Reg const g_winos_functions[] = { { "cp_info", xm_winos_cp_info }, { "console_cp", xm_winos_console_cp }, { "console_output_cp", xm_winos_console_output_cp }, { "oem_cp", xm_winos_oem_cp }, { "ansi_cp", xm_winos_ansi_cp }, { "logical_drives", xm_winos_logical_drives }, { "registry_query", xm_winos_registry_query }, { "registry_keys", xm_winos_registry_keys }, { "registry_values", xm_winos_registry_values }, { "short_path", xm_winos_short_path }, { "processes", xm_winos_processes }, { "set_error_mode", xm_winos_set_error_mode }, { "file_signature", xm_winos_file_signature }, { tb_null, tb_null }, }; #endif // the io functions static luaL_Reg const g_io_functions[] = { { "stdfile", xm_io_stdfile }, { "file_open", xm_io_file_open }, { "file_read", xm_io_file_read }, { "file_readable", xm_io_file_readable }, { "file_seek", xm_io_file_seek }, { "file_size", xm_io_file_size }, { "file_write", xm_io_file_write }, { "file_flush", xm_io_file_flush }, { "file_isatty", xm_io_file_isatty }, { "file_close", xm_io_file_close }, { "file_convert", xm_io_file_convert }, { "file_rawfd", xm_io_file_rawfd }, { "filelock_open", xm_io_filelock_open }, { "filelock_lock", xm_io_filelock_lock }, { "filelock_trylock", xm_io_filelock_trylock }, { "filelock_unlock", xm_io_filelock_unlock }, { "filelock_close", xm_io_filelock_close }, { "socket_open", xm_io_socket_open }, { "socket_rawfd", xm_io_socket_rawfd }, { "socket_peeraddr", xm_io_socket_peeraddr }, { "socket_wait", xm_io_socket_wait }, { "socket_bind", xm_io_socket_bind }, { "socket_ctrl", xm_io_socket_ctrl }, { "socket_listen", xm_io_socket_listen }, { "socket_accept", xm_io_socket_accept }, { "socket_connect", xm_io_socket_connect }, { "socket_send", xm_io_socket_send }, { "socket_sendto", xm_io_socket_sendto }, { "socket_sendfile", xm_io_socket_sendfile }, { "socket_recv", xm_io_socket_recv }, { "socket_recvfrom", xm_io_socket_recvfrom }, { "socket_kill", xm_io_socket_kill }, { "socket_close", xm_io_socket_close }, { "pipe_open", xm_io_pipe_open }, { "pipe_openpair", xm_io_pipe_openpair }, { "pipe_close", xm_io_pipe_close }, { "pipe_read", xm_io_pipe_read }, { "pipe_write", xm_io_pipe_write }, { "pipe_wait", xm_io_pipe_wait }, { "pipe_connect", xm_io_pipe_connect }, { "poller_insert", xm_io_poller_insert }, { "poller_modify", xm_io_poller_modify }, { "poller_remove", xm_io_poller_remove }, { "poller_spank", xm_io_poller_spank }, { "poller_support", xm_io_poller_support }, { "poller_wait", xm_io_poller_wait }, { tb_null, tb_null }, }; // the path functions static luaL_Reg const g_path_functions[] = { { "relative", xm_path_relative }, { "absolute", xm_path_absolute }, { "translate", xm_path_translate }, { "directory", xm_path_directory }, { "is_absolute", xm_path_is_absolute }, { tb_null, tb_null }, }; // the hash functions static luaL_Reg const g_hash_functions[] = { { "uuid4", xm_hash_uuid4 }, { "sha", xm_hash_sha }, { "md5", xm_hash_md5 }, { "xxhash", xm_hash_xxhash }, { "rand32", xm_hash_rand32 }, { "rand64", xm_hash_rand64 }, { "rand128", xm_hash_rand128 }, { tb_null, tb_null }, }; // the base64 functions static luaL_Reg const g_base64_functions[] = { { "encode", xm_base64_encode }, { "decode", xm_base64_decode }, { tb_null, tb_null }, }; // the lz4 functions static luaL_Reg const g_lz4_functions[] = { { "compress", xm_lz4_compress }, { "decompress", xm_lz4_decompress }, { "block_compress", xm_lz4_block_compress }, { "block_decompress", xm_lz4_block_decompress }, { "compress_file", xm_lz4_compress_file }, { "decompress_file", xm_lz4_decompress_file }, { "compress_stream_open", xm_lz4_compress_stream_open }, { "compress_stream_read", xm_lz4_compress_stream_read }, { "compress_stream_write", xm_lz4_compress_stream_write }, { "compress_stream_close", xm_lz4_compress_stream_close }, { "decompress_stream_open", xm_lz4_decompress_stream_open }, { "decompress_stream_read", xm_lz4_decompress_stream_read }, { "decompress_stream_write", xm_lz4_decompress_stream_write }, { "decompress_stream_close", xm_lz4_decompress_stream_close }, { tb_null, tb_null }, }; // the bloom filter functions static luaL_Reg const g_bloom_filter_functions[] = { { "open", xm_bloom_filter_open }, { "close", xm_bloom_filter_close }, { "clear", xm_bloom_filter_clear }, { "data", xm_bloom_filter_data }, { "size", xm_bloom_filter_size }, { "get", xm_bloom_filter_get }, { "set", xm_bloom_filter_set }, { "data_set", xm_bloom_filter_data_set }, { tb_null, tb_null }, }; // the utf8 functions static luaL_Reg const g_utf8_functions[] = { {"char", xm_utf8_char}, {"byte", xm_utf8_byte}, {"codes", xm_utf8_codes}, {"codepoint", xm_utf8_codepoint}, {"len", xm_utf8_len}, {"offset", xm_utf8_offset}, {"sub", xm_utf8_sub}, {"reverse", xm_utf8_reverse}, {"lastof", xm_utf8_lastof}, {"find", xm_utf8_find}, {"width", xm_utf8_width}, {"wcwidth", xm_utf8_width}, {"wcswidth", xm_utf8_width}, {tb_null, tb_null} }; // the string functions static luaL_Reg const g_string_functions[] = { { "trim", xm_string_trim }, { "split", xm_string_split }, { "lastof", xm_string_lastof }, { "convert", xm_string_convert }, { "endswith", xm_string_endswith }, { "startswith", xm_string_startswith }, { "lower", xm_string_lower }, { "upper", xm_string_upper }, { tb_null, tb_null }, }; // the process functions static luaL_Reg const g_process_functions[] = { { "open", xm_process_open }, { "openv", xm_process_openv }, { "wait", xm_process_wait }, { "kill", xm_process_kill }, { "close", xm_process_close }, { tb_null, tb_null }, }; // the fwatcher functions static luaL_Reg const g_fwatcher_functions[] = { { "open", xm_fwatcher_open }, { "add", xm_fwatcher_add }, { "remove", xm_fwatcher_remove }, { "wait", xm_fwatcher_wait }, { "close", xm_fwatcher_close }, { tb_null, tb_null }, }; // the sandbox functions static luaL_Reg const g_sandbox_functions[] = { { "interactive", xm_sandbox_interactive }, { tb_null, tb_null }, }; #ifdef XM_CONFIG_API_HAVE_READLINE // the readline functions static luaL_Reg const g_readline_functions[] = { { "readline", xm_readline_readline }, { "history_list", xm_readline_history_list }, { "add_history", xm_readline_add_history }, { "clear_history", xm_readline_clear_history }, { tb_null, tb_null }, }; #endif // the semver functions static luaL_Reg const g_semver_functions[] = { { "parse", xm_semver_parse }, { "compare", xm_semver_compare }, { "satisfies", xm_semver_satisfies }, { "select", xm_semver_select }, { tb_null, tb_null }, }; // the libc functions static luaL_Reg const g_libc_functions[] = { { "malloc", xm_libc_malloc }, { "free", xm_libc_free }, { "memcpy", xm_libc_memcpy }, { "memset", xm_libc_memset }, { "memmov", xm_libc_memmov }, { "strndup", xm_libc_strndup }, { "dataptr", xm_libc_dataptr }, { "byteof", xm_libc_byteof }, { "setbyte", xm_libc_setbyte }, { tb_null, tb_null }, }; // the tty functions static luaL_Reg const g_tty_functions[] = { { "term_mode", xm_tty_term_mode }, { "session_id", xm_tty_session_id }, { tb_null, tb_null }, }; // the package functions static luaL_Reg const g_package_functions[] = { { "loadxmi", xm_package_loadxmi }, { tb_null, tb_null }, }; // the binutils functions static luaL_Reg const g_binutils_functions[] = { { "bin2c", xm_binutils_bin2c }, { "bin2coff", xm_binutils_bin2coff }, { "bin2macho", xm_binutils_bin2macho }, { "bin2elf", xm_binutils_bin2elf }, { "readsyms", xm_binutils_readsyms }, { "deplibs", xm_binutils_deplibs }, { "rpath_list", xm_binutils_rpath_list }, { "rpath_clean", xm_binutils_rpath_clean }, { "extractlib", xm_binutils_extractlib }, { "format", xm_binutils_format }, { tb_null, tb_null }, }; // the thread functions static luaL_Reg const g_thread_functions[] = { { "thread_init", xm_thread_init }, { "thread_exit", xm_thread_exit }, { "thread_wait", xm_thread_wait }, { "thread_resume", xm_thread_resume }, { "thread_suspend", xm_thread_suspend }, { "mutex_init", xm_thread_mutex_init }, { "mutex_exit", xm_thread_mutex_exit }, { "mutex_lock", xm_thread_mutex_lock }, { "mutex_trylock", xm_thread_mutex_trylock }, { "mutex_unlock", xm_thread_mutex_unlock }, { "mutex_incref", xm_thread_mutex_incref }, { "event_init", xm_thread_event_init }, { "event_exit", xm_thread_event_exit }, { "event_post", xm_thread_event_post }, { "event_wait", xm_thread_event_wait }, { "event_incref", xm_thread_event_incref }, { "semaphore_init", xm_thread_semaphore_init }, { "semaphore_exit", xm_thread_semaphore_exit }, { "semaphore_post", xm_thread_semaphore_post }, { "semaphore_wait", xm_thread_semaphore_wait }, { "semaphore_incref", xm_thread_semaphore_incref }, { "queue_init", xm_thread_queue_init }, { "queue_exit", xm_thread_queue_exit }, { "queue_size", xm_thread_queue_size }, { "queue_clear", xm_thread_queue_clear }, { "queue_incref", xm_thread_queue_incref }, { "queue_push", xm_thread_queue_push }, { "queue_pop", xm_thread_queue_pop }, { "sharedata_init", xm_thread_sharedata_init }, { "sharedata_exit", xm_thread_sharedata_exit }, { "sharedata_clear", xm_thread_sharedata_clear }, { "sharedata_incref", xm_thread_sharedata_incref }, { "sharedata_set", xm_thread_sharedata_set }, { "sharedata_get", xm_thread_sharedata_get_ }, { tb_null, tb_null }, }; // the utf8 functions // the lua global instance for signal handler static lua_State *g_lua = tb_null; // the xmake script files data #ifdef XM_EMBED_ENABLE __tb_extern_c_enter__ extern tb_byte_t _binary_xmake_xmz_start[]; extern tb_byte_t _binary_xmake_xmz_end[]; __tb_extern_c_leave__ #endif /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_engine_save_arguments(xm_engine_t *engine, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv) { tb_assert_and_check_return_val(engine && engine->lua && argc >= 1 && argv, tb_false); #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) tb_wchar_t **argvw = CommandLineToArgvW(GetCommandLineW(), &argc); #endif // put a new table into the stack lua_newtable(engine->lua); // patch the task arguments list if (taskargv) { tb_char_t **taskarg = taskargv; while (*taskarg) { lua_pushstring(engine->lua, *taskarg); lua_rawseti(engine->lua, -2, (int)lua_objlen(engine->lua, -2) + 1); taskarg++; } } // save all arguments to the new table tb_int_t i = 0; for (i = 1; i < argc; i++) { #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) tb_char_t argvbuf[4096] = { 0 }; tb_wcstombs(argvbuf, argvw[i], tb_arrayn(argvbuf)); // table_new[table.getn(table_new) + 1] = argv[i] lua_pushstring(engine->lua, argvbuf); #else lua_pushstring(engine->lua, argv[i]); #endif lua_rawseti(engine->lua, -2, (int)lua_objlen(engine->lua, -2) + 1); } // _ARGV = table_new lua_setglobal(engine->lua, "_ARGV"); return tb_true; } static tb_bool_t xm_engine_get_program_file(xm_engine_t *engine, tb_char_t **argv, tb_char_t *path, tb_size_t maxn) { tb_assert_and_check_return_val(engine && path && maxn, tb_false); /* we cache it, because the current path will be changed in thread. * * The executable file compiled using cosmocc on macOS might retrieve a relative path to the programfile. * If the root directory has been changed, the retrieved programfile will be a non-existent path. */ static tb_char_t s_program_filepath[TB_PATH_MAXN] = { 0 }; if (s_program_filepath[0]) { tb_strlcpy(path, s_program_filepath, maxn); lua_pushstring(engine->lua, s_program_filepath); lua_setglobal(engine->lua, "_PROGRAM_FILE"); return tb_true; } tb_bool_t ok = tb_false; do { // get it from the environment variable first if (tb_environment_first("XMAKE_PROGRAM_FILE", path, maxn) && tb_file_info(path, tb_null)) { ok = tb_true; break; } #if defined(TB_CONFIG_OS_WINDOWS) // get the executale file path as program directory tb_wchar_t buf[TB_PATH_MAXN] = { 0 }; tb_size_t size = (tb_size_t)GetModuleFileNameW(tb_null, buf, (DWORD)TB_PATH_MAXN); tb_assert_and_check_break(size < TB_PATH_MAXN); buf[size] = L'\0'; size = tb_wcstombs(path, buf, maxn); tb_assert_and_check_break(size < maxn); path[size] = '\0'; ok = tb_true; #elif defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS) /* * _NSGetExecutablePath() copies the path of the main executable into the buffer. The bufsize parameter * should initially be the size of the buffer. The function returns 0 if the path was successfully copied, * and *bufsize is left unchanged. It returns -1 if the buffer is not large enough, and *bufsize is set * to the size required. * * Note that _NSGetExecutablePath will return "a path" to the executable not a "real path" to the executable. * That is the path may be a symbolic link and not the real file. With deep directories the total bufsize * needed could be more than MAXPATHLEN. */ tb_uint32_t bufsize = (tb_uint32_t)maxn; if (!_NSGetExecutablePath(path, &bufsize)) { ok = tb_true; } #elif defined(XM_PROC_SELF_FILE) /* get the executale file path as program directory * * @see it may be a relative path */ ssize_t size = readlink(XM_PROC_SELF_FILE, path, (size_t)maxn); if (size > 0 && size < maxn) { path[size] = '\0'; // ignore cosmocc ape binary, we fallback to argv[0], .e.g /usr/bin/ape, /home/ruki/.ape-1.10 tb_char_t const* filename = tb_strrchr(path, '/'); if (!tb_strstr(filename ? filename + 1 : path, "ape")) { ok = tb_true; } } #elif defined(TB_CONFIG_OS_BSD) && defined(KERN_PROC_PATHNAME) // only for FreeBSD and OpenBSD, https://github.com/xmake-io/xmake/issues/2948 tb_int_t mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; size_t size = maxn; if (sysctl(mib, 4, path, &size, tb_null, 0) == 0 && size < maxn) { path[size] = '\0'; ok = tb_true; } #elif defined(TB_CONFIG_OS_HAIKU) int32 cookie = 0; image_info info; while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { if (info.type == B_APP_IMAGE) { tb_strlcpy(path, info.name, maxn); ok = tb_true; break; } } #else static tb_char_t const *s_paths[] = { "~/.local/bin/xmake", "/usr/local/bin/xmake", "/usr/bin/xmake", }; for (tb_size_t i = 0; i < tb_arrayn(s_paths); i++) { tb_char_t const *p = s_paths[i]; if (tb_file_info(p, tb_null)) { tb_strlcpy(path, p, maxn); ok = tb_true; break; } } #endif if (!ok && argv) { tb_char_t const *p = argv[0]; if (p && tb_file_info(p, tb_null)) { if (tb_path_is_absolute(p)) { tb_strlcpy(path, p, maxn); } else { if (!tb_path_absolute(p, path, maxn)) { tb_strlcpy(path, p, maxn); } } ok = tb_true; } } } while (0); if (ok) { tb_trace_d("programfile: %s", path); // cache it tb_strlcpy(s_program_filepath, path, sizeof(s_program_filepath)); // save the directory to the global variable: _PROGRAM_FILE lua_pushstring(engine->lua, path); lua_setglobal(engine->lua, "_PROGRAM_FILE"); } return ok; } #ifdef XM_EMBED_ENABLE static tb_bool_t xm_engine_get_temporary_directory(tb_char_t *path, tb_size_t maxn, tb_char_t const *name, tb_char_t const *version_cstr) { tb_char_t data[TB_PATH_MAXN] = { 0 }; if (tb_directory_temporary(data, sizeof(data))) { // get euid tb_int_t euid = 0; #ifndef TB_CONFIG_OS_WINDOWS euid = geteuid(); #endif tb_snprintf(path, maxn, "%s/.%s%d/%s", data, name, euid, version_cstr); return tb_true; } return tb_false; } #endif static tb_bool_t xm_engine_get_program_directory(xm_engine_t *engine, tb_char_t *path, tb_size_t maxn, tb_char_t const *programfile) { tb_assert_and_check_return_val(engine && path && maxn, tb_false); static tb_char_t s_program_directory[TB_PATH_MAXN] = { 0 }; if (s_program_directory[0]) { tb_strlcpy(path, s_program_directory, maxn); lua_pushstring(engine->lua, s_program_directory); lua_setglobal(engine->lua, "_PROGRAM_DIR"); return tb_true; } tb_bool_t ok = tb_false; tb_char_t data[TB_PATH_MAXN] = { 0 }; do { #ifdef XM_EMBED_ENABLE tb_size_t embedcount = engine->embedcount; if (embedcount) { tb_uint32_t crc32 = 0; for (tb_size_t i = 0; i < embedcount; i++) { crc32 += tb_crc32_make(engine->embeddata[i], engine->embedsize[i], 0); } tb_snprintf(path, maxn, "%s/%x", engine->tmpdir, crc32); } else { tb_strlcpy(path, engine->tmpdir, maxn); } ok = tb_true; break; #endif // get it from the environment variable first if (tb_environment_first("XMAKE_PROGRAM_DIR", data, sizeof(data)) && tb_path_absolute(data, path, maxn)) { ok = tb_true; break; } // get it from program file path if (programfile) { // get real program file path from the symbol link #if !defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_CONFIG_OS_IOS) tb_char_t programpath[TB_PATH_MAXN]; tb_long_t size = readlink(programfile, programpath, sizeof(programpath)); if (size >= 0 && size < sizeof(programpath)) { programpath[size] = '\0'; // soft link to relative path? fix it if (!tb_path_is_absolute(programpath)) { tb_char_t buff[TB_PATH_MAXN]; tb_char_t const *rootdir = tb_path_directory(programfile, buff, sizeof(buff)); if (rootdir && tb_path_absolute_to( rootdir, programpath, path, maxn)) { // @note path and programfile are same buffer tb_strlcpy(programpath, path, maxn); } } } else tb_strlcpy(programpath, programfile, sizeof(programpath)); #else tb_char_t const *programpath = programfile; #endif // get the root directory tb_char_t data[TB_PATH_MAXN]; tb_char_t const *rootdir = tb_path_directory(programpath, data, sizeof(data)); tb_assert_and_check_break(rootdir); // init share/name sub-directory tb_char_t sharedir[128]; tb_snprintf(sharedir, sizeof(sharedir), "../share/%s", engine->name); // find the program (lua) directory tb_size_t i; tb_file_info_t info; tb_char_t scriptpath[TB_PATH_MAXN]; tb_char_t const *subdirs[] = { ".", sharedir, }; for (i = 0; i < tb_arrayn(subdirs); i++) { // get program directory if (tb_path_absolute_to(rootdir, subdirs[i], path, maxn) && tb_path_absolute_to(path, "core/_xmake_main.lua", scriptpath, sizeof(scriptpath)) && tb_file_info(scriptpath, &info) && info.type == TB_FILE_TYPE_FILE) { ok = tb_true; break; } } } } while (0); if (ok) { tb_trace_d("programdir: %s", path); // cache it tb_strlcpy(s_program_directory, path, sizeof(s_program_directory)); // save the directory to the global variable: _PROGRAM_DIR lua_pushstring(engine->lua, path); lua_setglobal(engine->lua, "_PROGRAM_DIR"); } return ok; } static tb_bool_t xm_engine_get_project_directory(xm_engine_t *engine, tb_char_t *path, tb_size_t maxn) { tb_assert_and_check_return_val(engine && path && maxn, tb_false); tb_bool_t ok = tb_false; do { // attempt to get it from the environment variable first tb_char_t data[TB_PATH_MAXN] = { 0 }; if (!tb_environment_first("XMAKE_PROJECT_DIR", data, sizeof(data)) || !tb_path_absolute(data, path, maxn)) { // get it from the current directory if (!tb_directory_current(path, maxn)) { break; } } tb_trace_d("project: %s", path); // save the directory to the global variable: _PROJECT_DIR lua_pushstring(engine->lua, path); lua_setglobal(engine->lua, "_PROJECT_DIR"); ok = tb_true; } while (0); // failed? if (!ok) { tb_printf("error: not found the project directory!\n"); } return ok; } #if defined(TB_CONFIG_OS_WINDOWS) || defined(SIGINT) static tb_void_t xm_engine_dump_traceback(lua_State *lua) { // @note it's not safe, but it doesn't matter, we're just trying to get the stack backtrace for debugging lua_getglobal(lua, "debug"); lua_getfield(lua, -1, "traceback"); lua_replace(lua, -2); lua_pushvalue(lua, 1); lua_call(lua, 1, 1); tb_trace_i("%s", lua_tostring(lua, -1)); } #endif #if defined(TB_CONFIG_OS_WINDOWS) static BOOL WINAPI xm_engine_signal_handler(DWORD signo) { if (signo == CTRL_C_EVENT && g_lua) { xm_engine_dump_traceback(g_lua); tb_abort(); } return TRUE; } #elif defined(SIGINT) static tb_void_t xm_engine_signal_handler(tb_int_t signo) { if (signo == SIGINT && g_lua) { xm_engine_dump_traceback(g_lua); tb_abort(); } } #endif static tb_void_t xm_engine_init_host(xm_engine_t *engine) { tb_assert_and_check_return(engine && engine->lua); // init system host tb_char_t const *syshost = tb_null; #if defined(__COSMOPOLITAN__) struct utsname buffer; if (uname(&buffer) == 0) { if (tb_strstr(buffer.sysname, "Darwin")) { syshost = "macosx"; } else if (tb_strstr(buffer.sysname, "Linux")) { syshost = "linux"; } else if (tb_strstr(buffer.sysname, "Windows")) { syshost = "windows"; } } #elif defined(TB_CONFIG_OS_WINDOWS) syshost = "windows"; #elif defined(TB_CONFIG_OS_MACOSX) syshost = "macosx"; #elif defined(TB_CONFIG_OS_LINUX) syshost = "linux"; #elif defined(TB_CONFIG_OS_BSD) syshost = "bsd"; #elif defined(TB_CONFIG_OS_SOLARIS) syshost = "solaris"; #elif defined(TB_CONFIG_OS_IOS) syshost = "ios"; #elif defined(TB_CONFIG_OS_ANDROID) syshost = "android"; #elif defined(TB_CONFIG_OS_HAIKU) syshost = "haiku"; #endif lua_pushstring(engine->lua, syshost ? syshost : "unknown"); lua_setglobal(engine->lua, "_HOST"); // init subsystem host tb_char_t const *subhost = syshost; #if defined(TB_CONFIG_OS_WINDOWS) #if defined(TB_COMPILER_ON_MSYS) subhost = "msys"; #elif defined(TB_COMPILER_ON_CYGWIN) subhost = "cygwin"; #else { tb_char_t data[64] = { 0 }; if (tb_environment_first("MSYSTEM", data, sizeof(data))) { // on msys? if (!tb_strnicmp(data, "mingw", 5) // mingw32/64 on msys2 || !tb_strnicmp(data, "clang", 5) // clang32/64 on msys2, @see https://github.com/xmake-io/xmake/issues/3060 || !tb_stricmp(data, "ucrt64") // ucrt64 https://www.msys2.org/docs/environments/ || !tb_stricmp(data, "msys")) { // on msys2 subhost = "msys"; } } } #endif #endif lua_pushstring(engine->lua, subhost ? subhost : "unknown"); lua_setglobal(engine->lua, "_SUBHOST"); } static __tb_inline__ tb_char_t const *xm_engine_xmake_arch() { tb_char_t const *arch = tb_null; #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #if defined(TB_ARCH_x64) arch = "x64"; #elif defined(TB_ARCH_ARM64) arch = "arm64"; #elif defined(TB_ARCH_ARM) arch = "arm"; #else arch = "x86"; #endif #elif defined(TB_ARCH_x64) arch = "x86_64"; #elif defined(TB_ARCH_x86) arch = "i386"; #elif defined(TB_ARCH_ARM64) arch = "arm64"; #else arch = TB_ARCH_STRING; #endif return arch; } static tb_void_t xm_engine_init_arch(xm_engine_t *engine) { tb_assert_and_check_return(engine && engine->lua); // init xmake arch tb_char_t const *xmakearch = xm_engine_xmake_arch(); lua_pushstring(engine->lua, xmakearch); lua_setglobal(engine->lua, "_XMAKE_ARCH"); // init system architecture tb_char_t const *sysarch = tb_null; #if defined(__COSMOPOLITAN__) struct utsname buffer; if (uname(&buffer) == 0) { sysarch = buffer.machine; if (tb_strstr(buffer.sysname, "Windows")) { if (!tb_strcmp(buffer.machine, "x86_64")) { sysarch = "x64"; } else if (!tb_strcmp(buffer.machine, "i686") || !tb_strcmp(buffer.machine, "i386")) { sysarch = "x86"; } } else if (!tb_strcmp(buffer.machine, "aarch64")) { sysarch = "arm64"; } } #elif defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) // the GetNativeSystemInfo function type typedef void(WINAPI * GetNativeSystemInfo_t)(LPSYSTEM_INFO); // get system info SYSTEM_INFO systeminfo = { 0 }; GetNativeSystemInfo_t pGetNativeSystemInfo = tb_null; tb_dynamic_ref_t kernel32 = tb_dynamic_init("kernel32.dll"); if (kernel32) { pGetNativeSystemInfo = (GetNativeSystemInfo_t)tb_dynamic_func(kernel32, "GetNativeSystemInfo"); } if (pGetNativeSystemInfo) { pGetNativeSystemInfo(&systeminfo); } else { GetSystemInfo(&systeminfo); } // init architecture switch (systeminfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_AMD64: sysarch = "x64"; break; #if defined(PROCESSOR_ARCHITECTURE_ARM64) case PROCESSOR_ARCHITECTURE_ARM64: sysarch = "arm64"; break; #endif case PROCESSOR_ARCHITECTURE_ARM: sysarch = "arm"; break; case PROCESSOR_ARCHITECTURE_INTEL: sysarch = "x86"; break; default: break; } #endif if (!sysarch) { sysarch = xmakearch; } lua_pushstring(engine->lua, sysarch); lua_setglobal(engine->lua, "_ARCH"); // init subsystem architecture tb_char_t const *subarch = sysarch; #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) // get architecture from msys environment tb_char_t data[64] = { 0 }; if (tb_environment_first("MSYSTEM_CARCH", data, sizeof(data))) { if (!tb_strcmp(data, "i686")) { subarch = "i386"; } else { subarch = data; } } #endif lua_pushstring(engine->lua, subarch); lua_setglobal(engine->lua, "_SUBARCH"); } static tb_void_t xm_engine_init_features(xm_engine_t *engine) { tb_assert_and_check_return(engine && engine->lua); // init features lua_newtable(engine->lua); // get path seperator lua_pushstring(engine->lua, "path_sep"); #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) lua_pushstring(engine->lua, "\\"); #else lua_pushstring(engine->lua, "/"); #endif lua_settable(engine->lua, -3); // get environment path seperator lua_pushstring(engine->lua, "path_envsep"); #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) lua_pushstring(engine->lua, ";"); #else lua_pushstring(engine->lua, ":"); #endif lua_settable(engine->lua, -3); lua_setglobal(engine->lua, "_FEATURES"); } static tb_void_t xm_engine_init_signal(xm_engine_t *engine) { // we enable it to catch the current lua stack in ctrl-c signal handler if XMAKE_PROFILE=stuck tb_char_t data[64] = { 0 }; if (!tb_environment_first("XMAKE_PROFILE", data, sizeof(data)) || tb_strcmp(data, "stuck")) { return; } g_lua = engine->lua; #if defined(TB_CONFIG_OS_WINDOWS) SetConsoleCtrlHandler(xm_engine_signal_handler, TRUE); #elif defined(SIGINT) signal(SIGINT, xm_engine_signal_handler); #endif } #if XM_HOOK_LUA_MEMALLOC // udata is unused, it has been used by engine. see xm_engine_bind_to_lua() static tb_pointer_t xm_engine_lua_realloc(tb_pointer_t udata, tb_pointer_t data, size_t osize, size_t nsize) { tb_pointer_t ptr = tb_null; if (nsize == 0 && data) { tb_free(data); } else if (!data) { ptr = tb_malloc((tb_size_t)nsize); } else if (nsize != osize) { ptr = tb_ralloc(data, (tb_size_t)nsize); } else { ptr = data; } return ptr; } #endif #ifdef XM_EMBED_ENABLE static tb_bool_t xm_engine_extract_programfiles_impl(xm_engine_t *engine, tb_char_t const *programdir, tb_byte_t const *data, tb_size_t size) { // do decompress tb_bool_t ok = tb_false; LZ4F_errorCode_t code; LZ4F_decompressionContext_t ctx = tb_null; tb_buffer_t result; do { tb_buffer_init(&result); code = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(code)) { break; } tb_byte_t buffer[8192]; tb_bool_t failed = tb_false; while (1) { size_t advance = (size_t)size; size_t buffer_size = sizeof(buffer); code = LZ4F_decompress(ctx, buffer, &buffer_size, data, &advance, tb_null); if (LZ4F_isError(code)) { failed = tb_true; break; } if (buffer_size == 0) { break; } data += advance; size -= advance; tb_buffer_memncat(&result, buffer, buffer_size); } tb_assert_and_check_break(!failed && tb_buffer_size(&result)); ok = tb_true; } while (0); // extract files to programdir if (ok) { data = tb_buffer_data(&result); size = tb_buffer_size(&result); tb_byte_t const *p = data; tb_byte_t const *e = data + size; tb_size_t n = 0; tb_char_t filepath[TB_PATH_MAXN]; tb_long_t pos = tb_snprintf(filepath, sizeof(filepath), "%s/", programdir); while (p < e) { // get filepath n = (tb_size_t)tb_bits_get_u16_be(p); p += 2; tb_assert_and_check_break(pos + n + 1 < sizeof(filepath)); tb_strncpy(filepath + pos, (tb_char_t const *)p, n); filepath[pos + n] = '\0'; p += n; // get filedata n = (tb_size_t)tb_bits_get_u32_be(p); p += 4; // write file tb_trace_d("extracting %s, %lu bytes ..", filepath, n); tb_stream_ref_t stream = tb_stream_init_from_file(filepath, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); tb_assert_and_check_break(stream); if (tb_stream_open(stream)) { tb_stream_bwrit(stream, p, n); tb_stream_exit(stream); } p += n; } ok = (p == e); if (!ok) { tb_trace_e("extract program files failed"); } } else { tb_trace_e("decompress program files failed, %s", LZ4F_getErrorName(code)); } if (ctx) { LZ4F_freeDecompressionContext(ctx); ctx = tb_null; } tb_buffer_exit(&result); return ok; } static tb_bool_t xm_engine_extract_programfiles(xm_engine_t *engine, tb_char_t const *programdir) { tb_file_info_t info = { 0 }; if (!tb_file_info(programdir, &info)) { tb_byte_t const *data = _binary_xmake_xmz_start; tb_size_t size = _binary_xmake_xmz_end - _binary_xmake_xmz_start; if (!xm_engine_extract_programfiles_impl(engine, programdir, data, size)) { return tb_false; } tb_size_t embedcount = engine->embedcount; for (tb_size_t i = 0; i < embedcount; i++) { data = engine->embeddata[i]; size = engine->embedsize[i]; if (!xm_engine_extract_programfiles_impl(engine, programdir, data, size)) { return tb_false; } } } return tb_true; } #endif static tb_void_t xm_engine_bind_to_lua(lua_State *lua, xm_engine_t *engine) { lua_pushlightuserdata(lua, engine); lua_setglobal(lua, "__global_engine"); } // load and execute the main script static tb_bool_t xm_engine_load_main_script(xm_engine_t *engine, tb_char_t const *mainfile) { #ifdef TB_CONFIG_OS_WINDOWS // use tb_file_init to support unicode file path on windows tb_bool_t ok = tb_false; tb_file_ref_t file = tb_null; tb_byte_t *data = tb_null; do { // open file file = tb_file_init(mainfile, TB_FILE_MODE_RO); if (!file) { tb_printf("error: cannot open file: %s\n", mainfile); break; } // get file size tb_size_t size = (tb_size_t)tb_file_size(file); tb_assert_and_check_break(size); // allocate buffer data = (tb_byte_t *)tb_malloc(size); tb_assert_and_check_break(data); // read file content if (!tb_file_read(file, data, size)) { tb_printf("error: cannot read file: %s\n", mainfile); break; } // load lua buffer if (luaL_loadbuffer(engine->lua, (tb_char_t const *)data, size, mainfile)) { tb_printf("error: %s\n", lua_tostring(engine->lua, -1)); break; } // execute lua script if (lua_pcall(engine->lua, 0, LUA_MULTRET, 0)) { tb_printf("error: %s\n", lua_tostring(engine->lua, -1)); break; } ok = tb_true; } while (0); if (data) { tb_free(data); } if (file) { tb_file_exit(file); } return ok; #else if (luaL_dofile(engine->lua, mainfile)) { tb_printf("error: %s\n", lua_tostring(engine->lua, -1)); return tb_false; } return tb_true; #endif } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ xm_engine_ref_t xm_engine_init(tb_char_t const *name, xm_engine_lni_initalizer_cb_t lni_initalizer) { tb_bool_t ok = tb_false; xm_engine_t *engine = tb_null; do { // init self engine = tb_malloc0_type(xm_engine_t); tb_assert_and_check_break(engine); // init name tb_strlcpy(engine->name, name, sizeof(engine->name)); // init lua #if XM_HOOK_LUA_MEMALLOC engine->lua = lua_newstate(xm_engine_lua_realloc, tb_null); #else engine->lua = luaL_newstate(); #endif tb_assert_and_check_break(engine->lua); // open lua libraries luaL_openlibs(engine->lua); // bind os functions xm_lua_register(engine->lua, "os", g_os_functions); // bind io functions xm_lua_register(engine->lua, "io", g_io_functions); // bind path functions xm_lua_register(engine->lua, "path", g_path_functions); // bind hash functions xm_lua_register(engine->lua, "hash", g_hash_functions); // bind lz4 functions xm_lua_register(engine->lua, "lz4", g_lz4_functions); // bind bloom filter functions xm_lua_register(engine->lua, "bloom_filter", g_bloom_filter_functions); // bind base64 functions xm_lua_register(engine->lua, "base64", g_base64_functions); // bind utf8 functions xm_lua_register(engine->lua, "utf8", g_utf8_functions); // bind string functions xm_lua_register(engine->lua, "string", g_string_functions); // bind process functions xm_lua_register(engine->lua, "process", g_process_functions); // bind fwatcher functions xm_lua_register(engine->lua, "fwatcher", g_fwatcher_functions); // bind sandbox functions xm_lua_register(engine->lua, "sandbox", g_sandbox_functions); // bind windows functions #ifdef TB_CONFIG_OS_WINDOWS xm_lua_register(engine->lua, "winos", g_winos_functions); #endif #ifdef XM_CONFIG_API_HAVE_READLINE // bind readline functions xm_lua_register(engine->lua, "readline", g_readline_functions); #endif // bind semver functions xm_lua_register(engine->lua, "semver", g_semver_functions); // bind libc functions xm_lua_register(engine->lua, "libc", g_libc_functions); // bind tty functions xm_lua_register(engine->lua, "tty", g_tty_functions); // bind package functions xm_lua_register(engine->lua, "package", g_package_functions); // bind binutils functions xm_lua_register(engine->lua, "binutils", g_binutils_functions); // bind thread functions xm_lua_register(engine->lua, "thread", g_thread_functions); #ifdef XM_CONFIG_API_HAVE_CURSES // bind curses xm_lua_curses_register(engine->lua, "curses"); #endif #ifdef XM_CONFIG_API_HAVE_LUA_CJSON // bind cjson luaopen_cjson(engine->lua); lua_setglobal(engine->lua, "cjson"); #endif // bind engine to lua xm_engine_bind_to_lua(engine->lua, engine); // init host xm_engine_init_host(engine); // init architecture xm_engine_init_arch(engine); // init features xm_engine_init_features(engine); // init signal xm_engine_init_signal(engine); // get version tb_version_t const *version = xm_version(); tb_assert_and_check_break(version); // init version string tb_char_t version_cstr[256] = { 0 }; if (tb_strcmp(XM_CONFIG_VERSION_BRANCH, "") && tb_strcmp(XM_CONFIG_VERSION_COMMIT, "")) { tb_snprintf(version_cstr, sizeof(version_cstr), "%u.%u.%u+%s.%s", version->major, version->minor, version->alter, XM_CONFIG_VERSION_BRANCH, XM_CONFIG_VERSION_COMMIT); } else { tb_snprintf(version_cstr, sizeof(version_cstr), "%u.%u.%u+%llu", version->major, version->minor, version->alter, (unsigned long long)version->build); } lua_pushstring(engine->lua, version_cstr); lua_setglobal(engine->lua, "_VERSION"); #ifdef XM_EMBED_ENABLE // init the temporary directory if (!xm_engine_get_temporary_directory(engine->tmpdir, sizeof(engine->tmpdir), name, version_cstr)) { break; } lua_pushboolean(engine->lua, tb_true); lua_setglobal(engine->lua, "_EMBED"); #endif // init short version string tb_snprintf(version_cstr, sizeof(version_cstr), "%u.%u.%u", version->major, version->minor, version->alter); lua_pushstring(engine->lua, version_cstr); lua_setglobal(engine->lua, "_VERSION_SHORT"); // init engine name lua_pushstring(engine->lua, name ? name : "xmake"); lua_setglobal(engine->lua, "_NAME"); // use luajit as runtime? #ifdef USE_LUAJIT lua_pushboolean(engine->lua, tb_true); #else lua_pushboolean(engine->lua, tb_false); #endif lua_setglobal(engine->lua, "_LUAJIT"); // init namespace: xmake lua_newtable(engine->lua); lua_setglobal(engine->lua, "xmake"); /* do lua initializer and init namespace: _lni * * we can get the lni modules for _lni or `import("lib.lni.xxx")` in sandbox */ lua_newtable(engine->lua); if (lni_initalizer) { lni_initalizer((xm_engine_ref_t)engine, engine->lua); } lua_setglobal(engine->lua, "_lni"); #ifdef TB_CONFIG_OS_WINDOWS // enable terminal colors output for windows cmd HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE); if (output != INVALID_HANDLE_VALUE) { DWORD mode; if (GetConsoleMode(output, &mode)) { // attempt to enable 0x4: ENABLE_VIRTUAL_TERMINAL_PROCESSING if (SetConsoleMode(output, mode | 0x4)) { tb_environment_set("COLORTERM", "color256"); } } } #endif ok = tb_true; } while (0); if (!ok) { if (engine) { xm_engine_exit((xm_engine_ref_t)engine); } engine = tb_null; } return (xm_engine_ref_t)engine; } tb_void_t xm_engine_exit(xm_engine_ref_t self) { xm_engine_t *engine = (xm_engine_t *)self; tb_assert_and_check_return(engine); // exit lua if (engine->lua) { lua_close(engine->lua); } engine->lua = tb_null; // exit poller if (engine->poller) { tb_poller_exit(engine->poller); } engine->poller = tb_null; // exit it tb_free(engine); } tb_int_t xm_engine_main(xm_engine_ref_t self, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv) { xm_engine_t *engine = (xm_engine_t *)self; tb_assert_and_check_return_val(engine && engine->lua, -1); #if defined(TB_CONFIG_OS_WINDOWS) && defined(TB_COMPILER_IS_MSVC) // set "stdin" to have unicode mode if (_isatty(_fileno(stdin))) { _setmode(_fileno(stdin), _O_U16TEXT); } #endif // save main arguments to the global variable: _ARGV if (!xm_engine_save_arguments(engine, argc, argv, taskargv)) { return -1; } // get the project directory tb_char_t path[TB_PATH_MAXN] = { 0 }; if (!xm_engine_get_project_directory(engine, path, sizeof(path))) { return -1; } // get the program file if (!xm_engine_get_program_file(engine, argv, path, sizeof(path))) { return -1; } // get the program directory if (!xm_engine_get_program_directory(engine, path, sizeof(path), path)) { return -1; } #ifdef XM_EMBED_ENABLE if (!xm_engine_extract_programfiles(engine, path)) { return -1; } #endif // append the main script path tb_strcat(path, "/core/_xmake_main.lua"); // exists this script? if (!tb_file_info(path, tb_null)) { tb_printf("not found main script: %s\n", path); return -1; } tb_trace_d("main: %s", path); // load and execute the main script if (!xm_engine_load_main_script(engine, path)) { return -1; } // set the error function lua_getglobal(engine->lua, "debug"); lua_getfield(engine->lua, -1, "traceback"); // call the main function lua_getglobal(engine->lua, "_xmake_main"); if (lua_pcall(engine->lua, 0, 1, -2)) { tb_printf("error: %s\n", lua_tostring(engine->lua, -1)); return -1; } // get the error code return (tb_int_t)lua_tonumber(engine->lua, -1); } tb_void_t xm_engine_register(xm_engine_ref_t self, tb_char_t const *module, luaL_Reg const funcs[]) { xm_engine_t *engine = (xm_engine_t *)self; tb_assert_and_check_return(engine && engine->lua && module && funcs); // do register lua_pushstring(engine->lua, module); lua_newtable(engine->lua); xm_lua_register(engine->lua, tb_null, funcs); lua_rawset(engine->lua, -3); } #ifdef XM_EMBED_ENABLE tb_void_t xm_engine_add_embedfiles(xm_engine_ref_t self, tb_byte_t const *data, tb_size_t size) { xm_engine_t *engine = (xm_engine_t *)self; tb_assert_and_check_return(engine && engine->embedcount < tb_arrayn(engine->embedsize) && data && size); engine->embeddata[engine->embedcount] = data; engine->embedsize[engine->embedcount] = size; engine->embedcount++; } #endif lua_State *xm_engine_lua(xm_engine_ref_t self) { xm_engine_t *engine = (xm_engine_t *)self; tb_assert_and_check_return_val(engine, tb_null); return engine->lua; } tb_poller_ref_t xm_engine_poller(xm_engine_ref_t self) { xm_engine_t *engine = (xm_engine_t *)self; tb_assert_and_check_return_val(engine, tb_null); if (!engine->poller) { // init poller engine->poller_state.lua = engine->lua; tb_poller_ref_t poller = tb_poller_init(&engine->poller_state); tb_assert_and_check_return_val(poller, tb_null); // attach poller to the current thread tb_poller_attach(poller); engine->poller = poller; } return engine->poller; } tb_int_t xm_engine_run(tb_char_t const *name, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv, xm_engine_lni_initalizer_cb_t lni_initalizer) { tb_int_t ok = -1; if (xm_init()) { xm_engine_ref_t engine = xm_engine_init(name, lni_initalizer); if (engine) { ok = xm_engine_main(engine, argc, argv, taskargv); xm_engine_exit(engine); } xm_exit(); } return ok; } xm_engine_ref_t xm_engine_get(lua_State *lua) { tb_assert_and_check_return_val(lua, tb_null); lua_getglobal(lua, "__global_engine"); return (xm_engine_ref_t)lua_touserdata(lua, -1); } ================================================ FILE: core/src/xmake/engine.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file engine.h * */ #ifndef XM_ENGINE_H #define XM_ENGINE_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ __tb_extern_c_enter__ /* ////////////////////////////////////////////////////////////////////////////////////// * types */ /// the xmake engine type typedef struct { tb_int_t dummy; } const *xm_engine_ref_t; /// the lni initializer callback type typedef tb_void_t (*xm_engine_lni_initalizer_cb_t)(xm_engine_ref_t engine, lua_State *lua); /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ /*! init the engine * * @param name the engine name * @param lni_initalizer the lni initializer * * @return the engine */ xm_engine_ref_t xm_engine_init(tb_char_t const *name, xm_engine_lni_initalizer_cb_t lni_initalizer); /*! exit the engine * * @param engine the engine */ tb_void_t xm_engine_exit(xm_engine_ref_t engine); /*! do the main entry of the engine * * @param engine the engine * @param argc the argument count of the console * @param argv the argument list of the console * @param taskargv the argument list of sub-task, e.g. taskargv(lua -vD lua.main) for xmake lua -vD lua.main arg1 arg2 .. * * @return the error code of main() */ tb_int_t xm_engine_main(xm_engine_ref_t engine, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv); /*! register lni modules in the engine, @note we need to call it in lni_initalizer() * * @param engine the engine * @param module the lni module name * @param funcs the lni module functions */ tb_void_t xm_engine_register(xm_engine_ref_t engine, tb_char_t const *module, luaL_Reg const funcs[]); /*! add the embed files * * @param engine the engine * @param data the embedfiles data * @param size the data size */ tb_void_t xm_engine_add_embedfiles(xm_engine_ref_t engine, tb_byte_t const *data, tb_size_t size); /* get lua state from engine * * @param engine the engine * * @return the lua state */ lua_State *xm_engine_lua(xm_engine_ref_t engine); /* get poller from engine * * @param engine the engine * * @return the poller */ tb_poller_ref_t xm_engine_poller(xm_engine_ref_t engine); /*! run main entry of the engine singleton * * @param name the engine name * @param argc the argument count of the console * @param argv the argument list of the console * @param taskargv the argument list of sub-task, e.g. taskargv(lua -vD lua.main) for xmake lua -vD lua.main arg1 arg2 .. * @param lni_initalizer the lni initializer * * @return the error code of main() */ tb_int_t xm_engine_run(tb_char_t const *name, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv, xm_engine_lni_initalizer_cb_t lni_initalizer); /*! get engine from the given lua state * * @param lua the lua state * * @return the engine */ xm_engine_ref_t xm_engine_get(lua_State *lua); /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ __tb_extern_c_leave__ #endif ================================================ FILE: core/src/xmake/engine_pool.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file engine_pool.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "engine_pool" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "xmake.h" #include "engine.h" #include "engine_pool.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // the max engine pool count #define XM_ENGINE_POOL_MAXN (128) // the singleton type of engine pool #define XM_ENGINE_POOL (TB_SINGLETON_TYPE_USER + 4) /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_handle_t xm_engine_pool_instance_init(tb_cpointer_t *ppriv) { xm_engine_pool_ref_t engine_pool = xm_engine_pool_init(); tb_assert_and_check_return_val(engine_pool, tb_null); return (tb_handle_t)engine_pool; } static tb_void_t xm_engine_pool_instance_exit(tb_handle_t engine_pool, tb_cpointer_t priv) { if (engine_pool) { xm_engine_pool_exit((xm_engine_pool_ref_t)engine_pool); } } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ xm_engine_pool_ref_t xm_engine_pool() { return (xm_engine_pool_ref_t)tb_singleton_instance( XM_ENGINE_POOL, xm_engine_pool_instance_init, xm_engine_pool_instance_exit, tb_null, tb_null); } xm_engine_pool_ref_t xm_engine_pool_init() { return tb_single_list_init(0, tb_element_ptr(tb_null, tb_null)); } tb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool) { if (engine_pool) { tb_for_all(xm_engine_ref_t, engine, engine_pool) { if (engine) { xm_engine_exit(engine); } } tb_single_list_exit(engine_pool); } } xm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool) { xm_engine_ref_t engine = tb_null; if (tb_single_list_size(engine_pool) > 0) { engine = (xm_engine_ref_t)tb_single_list_head(engine_pool); tb_single_list_remove_head(engine_pool); } return engine; } tb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine) { if (tb_single_list_size(engine_pool) < XM_ENGINE_POOL_MAXN) { tb_single_list_insert_tail(engine_pool, engine); return tb_true; } return tb_false; } ================================================ FILE: core/src/xmake/engine_pool.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file engine_pool.h * */ #ifndef XM_ENGINE_POOL_H #define XM_ENGINE_POOL_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ __tb_extern_c_enter__ /* ////////////////////////////////////////////////////////////////////////////////////// * types */ /// the xmake engine pool type typedef tb_single_list_ref_t xm_engine_pool_ref_t; /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // get the engine pool singleton xm_engine_pool_ref_t xm_engine_pool(tb_void_t); /*! init the engine_pool * * @return the engine pool */ xm_engine_pool_ref_t xm_engine_pool_init(tb_void_t); /*! exit the engine_pool * * @param engine_pool the engine_pool */ tb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool); /*! alloc a engine from the engine_pool * * @param engine_pool the engine_pool * * @return the engine */ xm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool); /*! free a engine to the engine_pool * * @param engine_pool the engine_pool * @param engine the engine * * @return tb_true or tb_false */ tb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine); /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ __tb_extern_c_leave__ #endif ================================================ FILE: core/src/xmake/fwatcher/add.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file add.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "fwatcher.add" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // fwatcher.add(watchdir, recursion) tb_int_t xm_fwatcher_add(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the fwatcher tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(fwatcher, 0); // get watchdir tb_char_t const *watchdir = luaL_checkstring(lua, 2); tb_check_return_val(watchdir, 0); // get recursion tb_bool_t recursion = lua_toboolean(lua, 3); // add watchdir tb_bool_t ok = tb_fwatcher_add(fwatcher, watchdir, recursion); // save result lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/fwatcher/close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "fwatcher.close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // fwatcher.close(p) tb_int_t xm_fwatcher_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the fwatcher tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(fwatcher, 0); // exit fwatcher tb_fwatcher_exit(fwatcher); // save result: ok lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/fwatcher/open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "fwatcher.open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_fwatcher_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // init fwatcher tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)tb_fwatcher_init(); if (fwatcher) { xm_lua_pushpointer(lua, (tb_pointer_t)fwatcher); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/fwatcher/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_FWATCHER_PREFIX_H #define XM_FWATCHER_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/fwatcher/remove.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file remove.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "fwatcher.remove" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // fwatcher.remove(watchdir) tb_int_t xm_fwatcher_remove(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the fwatcher tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(fwatcher, 0); // get watchdir tb_char_t const *watchdir = luaL_checkstring(lua, 2); tb_check_return_val(watchdir, 0); // remove watchdir tb_bool_t ok = tb_fwatcher_remove(fwatcher, watchdir); // save result lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/fwatcher/wait.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file wait.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "fwatcher.wait" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // fwatcher.wait(p) tb_int_t xm_fwatcher_wait(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the fwatcher tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(fwatcher, 0); // get the timeout tb_long_t timeout = (tb_long_t)luaL_checkinteger(lua, 2); // wait fwatcher event tb_fwatcher_event_t event; tb_long_t ok = tb_fwatcher_wait(fwatcher, &event, timeout); // save result lua_pushinteger(lua, ok); if (ok > 0) { lua_newtable(lua); lua_pushstring(lua, "path"); lua_pushstring(lua, event.filepath); lua_settable(lua, -3); lua_pushstring(lua, "type"); lua_pushinteger(lua, event.event); lua_settable(lua, -3); return 2; } return 1; } ================================================ FILE: core/src/xmake/hash/md5.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file md5.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "md5" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_hash_md5(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is bytes? get data and size if (xm_lua_isinteger(lua, 1) && xm_lua_isinteger(lua, 2)) { tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1); tb_size_t size = (tb_size_t)lua_tointeger(lua, 2); if (!data || !size) { lua_pushnil(lua); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // compute md5 tb_byte_t buffer[16]; tb_md5_make(data, size, buffer, sizeof(buffer)); // make md5 string tb_char_t s[256]; tb_size_t n = xm_hash_make_cstr(s, buffer, 16); // save result lua_pushlstring(lua, s, n); return 1; } // get the filename tb_char_t const *filename = luaL_checkstring(lua, 1); tb_check_return_val(filename, 0); // load data from file tb_bool_t ok = tb_false; tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO); if (stream) { // open stream if (tb_stream_open(stream)) { // init md5 tb_md5_t md5; tb_md5_init(&md5, 0); // read data and update md5 tb_byte_t data[TB_STREAM_BLOCK_MAXN]; while (!tb_stream_beof(stream)) { // read data tb_long_t real = tb_stream_read(stream, data, sizeof(data)); if (real > 0) { tb_md5_spak(&md5, data, real); // no data? continue it } else if (!real) { // wait real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream)); tb_check_break(real > 0); // has read? tb_assert_and_check_break(real & TB_STREAM_WAIT_READ); } // failed or end? else { break; } } // exit md5 tb_byte_t buffer[16]; tb_md5_exit(&md5, buffer, sizeof(buffer)); // make md5 string tb_char_t s[256]; tb_size_t n = xm_hash_make_cstr(s, buffer, 16); // save result lua_pushlstring(lua, s, n); ok = tb_true; } // exit stream tb_stream_exit(stream); } if (!ok) { lua_pushnil(lua); // check if file exists to provide more specific error message if (!tb_file_info(filename, tb_null)) { lua_pushfstring(lua, "file not found: %s", filename); } else { lua_pushfstring(lua, "failed to read file: %s", filename); } return 2; } return 1; } ================================================ FILE: core/src/xmake/hash/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_HASH_PREFIX_H #define XM_HASH_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * helper implementation */ static __tb_inline__ tb_uint64_t xm_hash_xorshift64(tb_uint64_t x) { x ^= x << 13; x ^= x >> 7; x ^= x << 17; return x; } // http://xorshift.di.unimi.it/xorshift128plus.c static __tb_inline__ tb_uint64_t xm_hash_xorshift128(tb_uint64_t *s) { tb_uint64_t s1 = s[0]; tb_uint64_t const s0 = s[1]; s[0] = s0; s1 ^= s1 << 23; s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); return s[1] + s0; } static __tb_inline__ tb_size_t xm_hash_make_cstr(tb_char_t hash[256], tb_byte_t const *data, tb_size_t size) { static tb_char_t const *digits_table = "0123456789abcdef"; tb_size_t i = 0; tb_byte_t value; tb_char_t *s = hash; for (i = 0; i < size; ++i) { value = data[i]; s[0] = digits_table[(value >> 4) & 15]; s[1] = digits_table[value & 15]; s += 2; } *s = '\0'; return s - hash; } #endif ================================================ FILE: core/src/xmake/hash/rand128.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rand128.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rand128" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_hash_rand128(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); static union { tb_byte_t b[16]; tb_uint64_t word[2]; } s_seed = { 0 }; if (!s_seed.word[0] && !s_seed.word[1]) { s_seed.word[0] = (tb_uint64_t)tb_uclock(); s_seed.word[1] = (tb_uint64_t)tb_uclock(); } s_seed.word[0] = xm_hash_xorshift128(s_seed.word); s_seed.word[1] = xm_hash_xorshift128(s_seed.word); tb_char_t s[256]; tb_size_t n = xm_hash_make_cstr(s, s_seed.b, 16); lua_pushlstring(lua, s, n); return 1; } ================================================ FILE: core/src/xmake/hash/rand32.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rand32.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rand32" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_hash_rand32(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); static tb_uint64_t s_seed = 0; if (!s_seed) { s_seed = (tb_uint64_t)tb_uclock(); } s_seed = xm_hash_xorshift64(s_seed); tb_char_t s[256]; tb_uint32_t word = (s_seed >> 32) ^ (s_seed & 0xffffffff); tb_size_t n = xm_hash_make_cstr(s, (tb_byte_t const *)&word, 4); lua_pushlstring(lua, s, n); return 1; } ================================================ FILE: core/src/xmake/hash/rand64.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rand64.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rand64" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_hash_rand64(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); static union { tb_byte_t b[8]; tb_uint64_t word; } s_seed = { 0 }; if (!s_seed.word) { s_seed.word = (tb_uint64_t)tb_uclock(); } s_seed.word = xm_hash_xorshift64(s_seed.word); tb_char_t s[256]; tb_size_t n = xm_hash_make_cstr(s, s_seed.b, 8); lua_pushlstring(lua, s, n); return 1; } ================================================ FILE: core/src/xmake/hash/sha.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sha.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "sha" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_hash_sha(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get mode tb_size_t mode = (tb_size_t)lua_tointeger(lua, 1); // is bytes? get data and size if (xm_lua_isinteger(lua, 2) && xm_lua_isinteger(lua, 3)) { tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); tb_size_t size = (tb_size_t)lua_tointeger(lua, 3); if (!data || !size) { lua_pushnil(lua); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // compute sha tb_sha_t sha; tb_byte_t buffer[32]; tb_sha_init(&sha, mode); tb_sha_spak(&sha, data, size); tb_sha_exit(&sha, buffer, sizeof(buffer)); // make sha string tb_char_t s[256]; tb_size_t n = sha.digest_len << 2; tb_size_t len = xm_hash_make_cstr(s, buffer, n); // save result lua_pushlstring(lua, s, len); return 1; } // get the filename tb_char_t const *filename = luaL_checkstring(lua, 2); tb_check_return_val(filename, 0); // load data from file tb_bool_t ok = tb_false; tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO); if (stream) { // open stream if (tb_stream_open(stream)) { // init sha tb_sha_t sha; tb_sha_init(&sha, mode); // read data and update sha tb_byte_t data[TB_STREAM_BLOCK_MAXN]; while (!tb_stream_beof(stream)) { // read data tb_long_t real = tb_stream_read(stream, data, sizeof(data)); if (real > 0) { tb_sha_spak(&sha, data, real); // no data? continue it } else if (!real) { // wait real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream)); tb_check_break(real > 0); // has read? tb_assert_and_check_break(real & TB_STREAM_WAIT_READ); } // failed or end? else { break; } } // exit sha tb_byte_t buffer[32]; tb_sha_exit(&sha, buffer, sizeof(buffer)); // make sha string tb_char_t s[256]; tb_size_t n = sha.digest_len << 2; tb_size_t len = xm_hash_make_cstr(s, buffer, n); // save result lua_pushlstring(lua, s, len); ok = tb_true; } // exit stream tb_stream_exit(stream); } if (!ok) { lua_pushnil(lua); // check if file exists to provide more specific error message if (!tb_file_info(filename, tb_null)) { lua_pushfstring(lua, "file not found: %s", filename); } else { lua_pushfstring(lua, "failed to read file: %s", filename); } return 2; } return 1; } ================================================ FILE: core/src/xmake/hash/uuid4.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file uuid4.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "uuid4" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_hash_uuid4(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the name tb_char_t const *name = luaL_optstring(lua, 1, tb_null); // make uuid, use version 4 tb_char_t uuid[37]; lua_pushstring(lua, tb_uuid4_make_cstr(uuid, name)); return 1; } ================================================ FILE: core/src/xmake/hash/xxhash.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file xxhash.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "xxhash" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #define XXH_NAMESPACE XM_ #define XXH_STATIC_LINKING_ONLY #define XXH_IMPLEMENTATION #include "xxhash/xxhash.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_hash_xxhash(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get mode tb_size_t mode = (tb_size_t)lua_tointeger(lua, 1); if (mode != 32 && mode != 64 && mode != 128) { lua_pushnil(lua); lua_pushfstring(lua, "invalid mode(%d)!", (tb_int_t)mode); return 2; } // is bytes? get data and size if (xm_lua_isinteger(lua, 2) && xm_lua_isinteger(lua, 3)) { tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); tb_size_t size = (tb_size_t)lua_tointeger(lua, 3); if (!data || !size) { lua_pushnil(lua); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // compuate hash tb_byte_t const *buffer = tb_null; tb_uint32_t value32; XXH64_hash_t value64; XXH128_hash_t value128; if (mode == 128) { value128 = XM_XXH3_128bits(data, size); buffer = (tb_byte_t const *)&value128; } else if (mode == 64) { value64 = XM_XXH3_64bits(data, size); buffer = (tb_byte_t const *)&value64; } else if (mode == 32) { value64 = XM_XXH3_64bits(data, size); value32 = (value64 >> 32) ^ (value64 & 0xffffffff); buffer = (tb_byte_t const *)&value32; } if (!buffer) { lua_pushnil(lua); lua_pushfstring(lua, "empty buffer!"); return 2; } // make xxhash string tb_char_t s[256]; tb_size_t n = mode >> 3; tb_size_t len = xm_hash_make_cstr(s, buffer, n); // save result lua_pushlstring(lua, s, len); return 1; } // get the filename tb_char_t const *filename = luaL_checkstring(lua, 2); tb_check_return_val(filename, 0); // load data from file tb_bool_t ok = tb_false; tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO); if (stream) { // open stream XXH3_state_t *state = XM_XXH3_createState(); if (tb_stream_open(stream) && state) { // reset xxhash if (mode == 32 || mode == 64) { XM_XXH3_64bits_reset(state); } else { XM_XXH3_128bits_reset(state); } // read data and update xxhash tb_byte_t data[TB_STREAM_BLOCK_MAXN]; while (!tb_stream_beof(stream)) { // read data tb_long_t real = tb_stream_read(stream, data, sizeof(data)); if (real > 0) { if (mode == 32 || mode == 64) { XM_XXH3_64bits_update(state, data, real); } else { XM_XXH3_128bits_update(state, data, real); } } // no data? continue it else if (!real) { // wait real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream)); tb_check_break(real > 0); // has read? tb_assert_and_check_break(real & TB_STREAM_WAIT_READ); } // failed or end? else { break; } } // compuate hash tb_byte_t const *buffer; tb_uint32_t value32; XXH64_hash_t value64; XXH128_hash_t value128; if (mode == 128) { value128 = XM_XXH3_128bits_digest(state); buffer = (tb_byte_t const *)&value128; } else if (mode == 64) { value64 = XM_XXH3_64bits_digest(state); buffer = (tb_byte_t const *)&value64; } else if (mode == 32) { value64 = XM_XXH3_64bits_digest(state); value32 = (value64 >> 32) ^ (value64 & 0xffffffff); buffer = (tb_byte_t const *)&value32; } // make xxhash string tb_char_t s[256]; tb_size_t n = mode >> 3; tb_size_t len = xm_hash_make_cstr(s, buffer, n); // save result lua_pushlstring(lua, s, len); ok = tb_true; } // exit stream tb_stream_exit(stream); // exit xxhash if (state) { XM_XXH3_freeState(state); } } if (!ok) { lua_pushnil(lua); // check if file exists to provide more specific error message if (!tb_file_info(filename, tb_null)) { lua_pushfstring(lua, "file not found: %s", filename); } else { lua_pushfstring(lua, "failed to read file: %s", filename); } return 2; } return 1; } ================================================ FILE: core/src/xmake/io/file_close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu, ruki * @file file_close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.file_close(file) tb_int_t xm_io_file_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) xm_io_return_error(lua, "close(invalid file)!"); // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // close file if (xm_io_file_is_file(file)) { tb_assert(file->u.file_ref); #ifdef TB_CONFIG_OS_WINDOWS // write cached data first tb_byte_t const *odata = tb_buffer_data(&file->wcache); tb_size_t osize = tb_buffer_size(&file->wcache); if (odata && osize) { if (!tb_stream_bwrit(file->u.file_ref, odata, osize)) return tb_false; tb_buffer_clear(&file->wcache); } #endif // flush filter stream cache, TODO we should fix it in tbox/stream if ((file->mode & TB_FILE_MODE_RW) == TB_FILE_MODE_RW && file->fstream) { if (!tb_stream_sync(file->u.file_ref, tb_false)) return tb_false; } // close file tb_stream_clos(file->u.file_ref); file->u.file_ref = tb_null; // exit fstream if (file->fstream) { tb_stream_exit(file->fstream); } file->fstream = tb_null; // exit stream if (file->stream) { tb_stream_exit(file->stream); } file->stream = tb_null; // exit the line cache buffer tb_buffer_exit(&file->rcache); tb_buffer_exit(&file->wcache); // gc will free it if no any refs for lua_newuserdata() // ... lua_pushboolean(lua, tb_true); return 1; } else // for stdfile (gc/close) { // exit the line cache buffer tb_buffer_exit(&file->rcache); tb_buffer_exit(&file->wcache); // gc will free it if no any refs for lua_newuserdata() // ... lua_pushboolean(lua, tb_true); return 1; } } ================================================ FILE: core/src/xmake/io/file_convert.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file file_convert.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_convert" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "../utils/charset.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* convert file * * @param srcpath the srcpath * @param dstpath the dstpath * @param ftype the from-charset type, e.g. ascii, gb2312, gbk, ios8859, ucs2, ucs4, utf8, utf16, utf32 * @param ttype the to-charset type * * @code * io.convert(srcpath, dstpath, "gbk", "utf8") * io.convert(srcpath, dstpath, "utf8", "gb2312") * @endcode */ tb_int_t xm_io_file_convert(lua_State *lua) { // check tb_assert_and_check_return_val(lua, 0); #ifdef TB_CONFIG_MODULE_HAVE_CHARSET // get arguments tb_char_t const *srcpath = luaL_checkstring(lua, 1); tb_char_t const *dstpath = luaL_checkstring(lua, 2); tb_char_t const *fname = luaL_checkstring(lua, 3); tb_char_t const *tname = luaL_checkstring(lua, 4); tb_check_return_val(srcpath && dstpath && fname && tname, 0); // get charset type tb_size_t ftype = TB_CHARSET_TYPE_UTF8; tb_size_t ttype = TB_CHARSET_TYPE_UTF8; xm_charset_entry_ref_t fentry = xm_charset_find_by_name(fname); if (fentry) ftype = fentry->type; else { lua_pushfstring(lua, "invalid charset: %s", fname); lua_error(lua); } xm_charset_entry_ref_t tentry = xm_charset_find_by_name(tname); if (tentry) ttype = tentry->type; else { lua_pushfstring(lua, "invalid charset: %s", tname); lua_error(lua); } // done tb_bool_t ok = tb_false; tb_stream_ref_t istream = tb_null; tb_stream_ref_t ostream = tb_null; tb_stream_ref_t fstream = tb_null; do { // init istream istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO); tb_assert_and_check_break(istream); // open istream if (!tb_stream_open(istream)) break; // skip bom tb_size_t skip = 0; tb_byte_t* bom_data = tb_null; tb_long_t bom_size = tb_stream_peek(istream, &bom_data, 3); if (bom_size >= 3 && ftype == TB_CHARSET_TYPE_UTF8 && bom_data[0] == 0xef && bom_data[1] == 0xbb && bom_data[2] == 0xbf) { skip = 3; } else if (bom_size >= 2 && (ftype & TB_CHARSET_TYPE_UTF16)) { if (bom_data[0] == 0xff && bom_data[1] == 0xfe) skip = 2; else if (bom_data[0] == 0xfe && bom_data[1] == 0xff) skip = 2; } if (skip > 0 && !tb_stream_skip(istream, skip)) break; // init ostream ostream = tb_stream_init_from_file(dstpath, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); tb_assert_and_check_break(ostream); // open ostream if (!tb_stream_open(ostream)) break; // write bom if (!tb_strcmp(tname, "utf8bom")) { static tb_byte_t const k_bom[] = {0xef, 0xbb, 0xbf}; if (!tb_stream_bwrit(ostream, k_bom, 3)) break; } else if (!tb_strcmp(tname, "utf16lebom")) { static tb_byte_t const k_bom[] = {0xff, 0xfe}; if (!tb_stream_bwrit(ostream, k_bom, 2)) break; } else if (!tb_strcmp(tname, "utf16bom")) { #ifndef TB_WORDS_BIGENDIAN static tb_byte_t const k_bom[] = {0xff, 0xfe}; #else static tb_byte_t const k_bom[] = {0xfe, 0xff}; #endif if (!tb_stream_bwrit(ostream, k_bom, 2)) break; } // init fstream fstream = tb_stream_init_filter_from_charset(istream, ftype, ttype); tb_assert_and_check_break(fstream); // open fstream if (!tb_stream_open(fstream)) break; // transfer tb_byte_t data[TB_STREAM_BLOCK_MAXN]; while (1) { tb_long_t real = tb_stream_read(fstream, data, sizeof(data)); if (real > 0) { if (!tb_stream_bwrit(ostream, data, real)) break; } else if (real == 0) { tb_long_t wait = tb_stream_wait(fstream, TB_STREAM_WAIT_READ, tb_stream_timeout(fstream)); if (wait <= 0) break; } else break; } // ok ok = tb_true; } while (0); // exit fstream if (fstream) tb_stream_exit(fstream); fstream = tb_null; // exit istream if (istream) tb_stream_exit(istream); istream = tb_null; // exit ostream if (ostream) tb_stream_exit(ostream); ostream = tb_null; // ok? lua_pushboolean(lua, ok); return 1; #else lua_pushboolean(lua, tb_false); return 1; #endif } ================================================ FILE: core/src/xmake/io/file_flush.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu, ruki * @file file_flush.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_flush" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_io_std_flush_impl(xm_io_file_t *file) { tb_assert_and_check_return_val(xm_io_file_is_std(file), tb_false); return (file->u.std_ref != tb_stdfile_input()) ? tb_stdfile_flush(file->u.std_ref) : tb_false; } static tb_bool_t xm_io_file_flush_impl(xm_io_file_t *file) { tb_assert_and_check_return_val(xm_io_file_is_file(file), tb_false); #ifdef TB_CONFIG_OS_WINDOWS // write cached data first tb_byte_t const *odata = tb_buffer_data(&file->wcache); tb_size_t osize = tb_buffer_size(&file->wcache); if (odata && osize) { if (!tb_stream_bwrit(file->u.file_ref, odata, osize)) return tb_false; tb_buffer_clear(&file->wcache); } #endif return tb_stream_sync(file->u.file_ref, tb_false); } /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.file_flush(file) tb_int_t xm_io_file_flush(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) { xm_io_return_error(lua, "flush(invalid file)!"); } // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // flush file tb_bool_t ok = xm_io_file_is_file(file) ? xm_io_file_flush_impl(file) : xm_io_std_flush_impl(file); if (ok) { lua_pushboolean(lua, tb_true); return 1; } else { xm_io_return_error(lua, "failed to flush file"); } } ================================================ FILE: core/src/xmake/io/file_isatty.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu * @file file_isatty.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_isatty" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.file_isatty(file) tb_int_t xm_io_file_isatty(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) { xm_io_return_error(lua, "isatty(invalid file)!"); } // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // is tty? lua_pushboolean(lua, xm_io_file_is_tty(file)); return 1; } ================================================ FILE: core/src/xmake/io/file_open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu, ruki * @file file_open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // num of bytes read to guess encoding #define CHECK_SIZE (1024) // is utf-8 tail character #define IS_UTF8_TAIL(c) (c >= 0x80 && c < 0xc0) /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_size_t xm_io_file_detect_charset(tb_byte_t const **data_ptr, tb_long_t size) { tb_assert(data_ptr && *data_ptr); tb_byte_t const *data = *data_ptr; tb_size_t charset = XM_IO_FILE_ENCODING_BINARY; do { // is luajit bitcode? open as binary if (size >= 3 && data[0] == 27 && data[1] == 'L' && data[2] == 'J') { break; } // utf-8 with bom if (size >= 3 && data[0] == 239 && data[1] == 187 && data[2] == 191) { charset = TB_CHARSET_TYPE_UTF8; data += 3; // skip bom break; } if (size >= 2) { // utf16be if (data[0] == 254 && data[1] == 255) { charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; data += 2; // skip bom break; } // utf16le else if (data[0] == 255 && data[1] == 254) { charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; data += 2; // skip bom break; } } tb_sint16_t utf16be_conf = 0; tb_sint16_t utf16le_conf = 0; tb_sint16_t utf8_conf = 0; tb_sint16_t ascii_conf = 0; tb_sint16_t zero_count = 0; for (tb_long_t i = 0; i < (size - 4) && i < CHECK_SIZE; i++) { if (data[i] == 0) { zero_count++; } if (data[i] < 0x80) { ascii_conf++; } else { ascii_conf = TB_MINS16; } if (i % 2 == 0) { if (data[i] == 0) { utf16be_conf++; } if (data[i + 1] == 0) { utf16le_conf++; } } if (IS_UTF8_TAIL(data[i])) { // continue } else if (data[i] < 0x80) { utf8_conf++; } else if (data[i] >= 0xc0 && data[i] < 0xe0 && IS_UTF8_TAIL(data[i + 1])) { utf8_conf++; } else if (data[i] >= 0xe0 && data[i] < 0xf0 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2])) { utf8_conf++; } else if (data[i] >= 0xf0 && data[i] < 0xf8 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2]) && IS_UTF8_TAIL(data[i + 3])) { utf8_conf++; } else { utf8_conf = TB_MINS16; } } if (ascii_conf > 0 && zero_count <= 1) { charset = TB_CHARSET_TYPE_UTF8; break; } if (utf8_conf > 0 && zero_count <= 1) { charset = TB_CHARSET_TYPE_UTF8; break; } if (utf16be_conf > 0 && utf16be_conf > utf16le_conf) { charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; break; } if (utf16le_conf > 0 && utf16le_conf >= utf16be_conf) { charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; break; } if (utf8_conf > 0) { charset = TB_CHARSET_TYPE_UTF8; break; } #ifdef TB_CONFIG_OS_WINDOWS charset = TB_CHARSET_TYPE_ANSI; #endif } while (0); *data_ptr = data; return charset; } static tb_size_t xm_io_file_detect_encoding(tb_stream_ref_t stream, tb_long_t *pbomoff) { tb_assert_and_check_return_val(stream && pbomoff, XM_IO_FILE_ENCODING_BINARY); // detect encoding tb_byte_t *data = tb_null; tb_size_t encoding = XM_IO_FILE_ENCODING_BINARY; tb_long_t size = tb_stream_peek(stream, &data, CHECK_SIZE); if (size > 0) { tb_byte_t const *p = data; encoding = xm_io_file_detect_charset(&p, size); *pbomoff = p - data; } return encoding; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.file_open(path, modestr) tb_int_t xm_io_file_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get file path and mode tb_char_t const *path = luaL_checkstring(lua, 1); tb_char_t const *modestr = luaL_optstring(lua, 2, "r"); tb_assert_and_check_return_val(path && modestr, 0); // get file mode value tb_size_t mode; switch (modestr[0]) { case 'w': mode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC; break; case 'a': mode = TB_FILE_MODE_RW | TB_FILE_MODE_APPEND | TB_FILE_MODE_CREAT; break; case 'r': default: mode = TB_FILE_MODE_RO; break; } // get file encoding tb_long_t bomoff = 0; tb_stream_ref_t stream = tb_null; tb_bool_t update = !!tb_strchr(modestr, '+'); tb_size_t encoding = XM_IO_FILE_ENCODING_UNKNOWN; if (modestr[1] == 'b' || (update && modestr[2] == 'b')) { encoding = XM_IO_FILE_ENCODING_BINARY; } else if (tb_strstr(modestr, "utf8") || tb_strstr(modestr, "utf-8")) { encoding = TB_CHARSET_TYPE_UTF8; } else if (tb_strstr(modestr, "utf16le") || tb_strstr(modestr, "utf-16le")) { encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; } else if (tb_strstr(modestr, "utf16be") || tb_strstr(modestr, "utf-16be")) { encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; } else if (tb_strstr(modestr, "utf16") || tb_strstr(modestr, "utf-16")) { encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE; } else if (tb_strstr(modestr, "ansi")) { encoding = TB_CHARSET_TYPE_ANSI; } else if (tb_strstr(modestr, "gbk")) { encoding = TB_CHARSET_TYPE_GBK; } else if (tb_strstr(modestr, "gb2312")) { encoding = TB_CHARSET_TYPE_GB2312; } else if (tb_strstr(modestr, "iso8859")) { encoding = TB_CHARSET_TYPE_ISO8859; } else if (modestr[0] == 'w' || modestr[0] == 'a') { // set to utf-8 if not specified for the writing mode encoding = TB_CHARSET_TYPE_UTF8; } else if (modestr[0] == 'r') { // detect encoding if not specified for the reading mode stream = tb_stream_init_from_file(path, mode); if (stream && tb_stream_open(stream)) { encoding = xm_io_file_detect_encoding(stream, &bomoff); } else { if (stream) { tb_stream_exit(stream); } xm_io_return_error(lua, "file not found!"); } } else { xm_io_return_error(lua, "invalid open mode!"); } tb_assert_and_check_return_val(encoding != XM_IO_FILE_ENCODING_UNKNOWN, 0); // write data with utf bom? e.g. utf8bom, utf16lebom, utf16bom tb_bool_t utfbom = tb_false; if (tb_strstr(modestr, "bom")) { utfbom = tb_true; } // open file tb_bool_t open_ok = tb_false; tb_stream_ref_t file_ref = tb_null; tb_stream_ref_t fstream = tb_null; do { // init stream from file stream = stream ? stream : tb_stream_init_from_file(path, mode); tb_assert_and_check_break(stream); // is transcode? tb_bool_t is_transcode = encoding != TB_CHARSET_TYPE_UTF8 && encoding != XM_IO_FILE_ENCODING_BINARY; if (is_transcode) { if (modestr[0] == 'r') { fstream = tb_stream_init_filter_from_charset(stream, encoding, TB_CHARSET_TYPE_UTF8); } else { fstream = tb_stream_init_filter_from_charset(stream, TB_CHARSET_TYPE_UTF8, encoding); } tb_assert_and_check_break(fstream); // use fstream as file file_ref = fstream; } else { file_ref = stream; } // open file stream if (!tb_stream_open(file_ref)) { break; } // skip bom characters if exists if (bomoff > 0 && !tb_stream_seek(stream, bomoff)) { break; } open_ok = tb_true; } while (0); // open failed? if (!open_ok) { // exit stream if (stream) { tb_stream_exit(stream); } stream = tb_null; // exit charset stream filter if (fstream) { tb_stream_exit(fstream); } fstream = tb_null; // return errors xm_io_return_error(lua, "failed to open file!"); } // make file xm_io_file_t *file = (xm_io_file_t *)lua_newuserdata(lua, sizeof(xm_io_file_t)); tb_assert_and_check_return_val(file, 0); // init file file->u.file_ref = file_ref; file->stream = stream; file->fstream = fstream; file->mode = mode; file->type = XM_IO_FILE_TYPE_FILE; file->encoding = encoding; file->utfbom = utfbom; // init the read/write line cache buffer tb_buffer_init(&file->rcache); tb_buffer_init(&file->wcache); return 1; } ================================================ FILE: core/src/xmake/io/file_rawfd.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file file_rawfd.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_rawfd" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // file to fd #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #define xm_io_file2fd(file) (lua_Number)((tb_size_t)(file)) #else #define xm_io_file2fd(file) (lua_Number) tb_file2fd(file) #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* io.file_rawfd(file) * * @note this interface is very dangerous and is only used in some special/hacking cases. * * e.g. set VS_UNICODE_OUTPUT=fd to enable vs unicode output, @see https://github.com/xmake-io/xmake/issues/528 */ tb_int_t xm_io_file_rawfd(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) { xm_io_return_error(lua, "get rawfd for invalid file!"); } // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // get file raw fd if (xm_io_file_is_file(file)) { tb_file_ref_t rawfile = tb_null; if (tb_stream_ctrl(file->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile)) { lua_pushnumber(lua, xm_io_file2fd(rawfile)); return 1; } } // get rawfd failed xm_io_return_error(lua, "get rawfd for invalid file!"); } ================================================ FILE: core/src/xmake/io/file_read.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu, ruki * @file file_read.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_read" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ typedef enum __xm_pushline_state_e { PL_EOF, PL_FIN, PL_CONL, PL_FAIL, } xm_pushline_state_e; /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t xm_io_file_stream_skip_sequential(tb_stream_ref_t stream, tb_hize_t size) { tb_byte_t discard[TB_STREAM_BLOCK_MAXN]; tb_hize_t left = size; while (left) { tb_size_t need = left > (tb_hize_t)sizeof(discard) ? (tb_size_t)sizeof(discard) : (tb_size_t)left; tb_long_t read = tb_stream_read(stream, discard, need); if (read > 0) { left -= read; } else if (!read) { read = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); tb_check_return_val(read > 0, tb_false); } else { return tb_false; } } return tb_true; } static tb_bool_t xm_io_file_stream_skip(tb_stream_ref_t stream, tb_hize_t size, tb_bool_t sequential) { if (sequential) { return xm_io_file_stream_skip_sequential(stream, size); } return tb_stream_skip(stream, size); } static tb_long_t xm_io_file_buffer_readline(tb_stream_ref_t stream, tb_buffer_ref_t line) { tb_assert_and_check_return_val(stream && line, -1); // read line and reserve crlf tb_bool_t eof = tb_false; tb_hize_t offset = 0; tb_byte_t *data = tb_null; tb_hong_t size = tb_stream_size(stream); tb_bool_t sequential_consume = (size == 0); while (sequential_consume || (offset = tb_stream_offset(stream)) < size) { tb_long_t real = tb_stream_peek(stream, &data, XM_IO_BLOCK_MAXN); if (real > 0) { tb_char_t const *e = tb_strnchr((tb_char_t const *)data, real, '\n'); if (e) { tb_size_t n = (tb_byte_t const *)e + 1 - data; tb_buffer_memncat(line, data, n); if (!xm_io_file_stream_skip(stream, n, sequential_consume)) return -1; break; } else { tb_buffer_memncat(line, data, real); if (!xm_io_file_stream_skip(stream, (tb_hize_t)real, sequential_consume)) return -1; } } else if (!real) { real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); if (real <= 0) { eof = tb_true; break; } } else { eof = tb_true; break; } } tb_size_t linesize = tb_buffer_size(line); if (linesize) { return linesize; } else { return (eof || tb_stream_beof(stream)) ? -1 : 0; } } static tb_int_t xm_io_file_buffer_pushline(tb_buffer_ref_t buf, xm_io_file_t *file, tb_char_t const *continuation, tb_bool_t keep_crlf) { tb_assert(buf && file && continuation && xm_io_file_is_file(file) && file->u.file_ref); // is binary? tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; if (is_binary) { continuation = ""; keep_crlf = tb_true; } // clear line buffer tb_buffer_clear(&file->rcache); // read line data tb_long_t size = xm_io_file_buffer_readline(file->u.file_ref, &file->rcache); // translate line data tb_int_t result = PL_FAIL; tb_char_t *data = tb_null; tb_size_t conlen = tb_strlen(continuation); do { // eof? if (size < 0) { result = PL_EOF; break; } // patch two '\0' tb_buffer_memncat(&file->rcache, (tb_byte_t const *)"\0\0", 2); // get line data data = (tb_char_t *)tb_buffer_data(&file->rcache); tb_assert_and_check_break(data); // no lf found if (size > 0 && data[size - 1] != '\n') { result = PL_FIN; } else if (size > 1) { // crlf? => lf if (!is_binary && data[size - 2] == '\r') { data[size - 2] = '\n'; size--; } // has continuation? tb_bool_t has_conline = conlen && size >= conlen + 1 && tb_strncmp(continuation, (tb_char_t const *)(data + size - conlen - 1), conlen) == 0; // do not keep crlf, strip the last lf if (!keep_crlf && !has_conline) { size--; } // strip it if has continuation? if (has_conline) { size -= conlen + 1; } data[size] = '\0'; result = has_conline ? PL_CONL : PL_FIN; } else { // a single '\n' if (!keep_crlf) { size = 0; } result = PL_FIN; } } while (0); // push line data if (data && size > 0 && (result == PL_FIN || result == PL_CONL)) { tb_buffer_memncat(buf, (tb_byte_t const *)data, size); } // return result return result; } static tb_int_t xm_io_file_read_all_directly(lua_State *lua, xm_io_file_t *file) { tb_assert(lua && file && xm_io_file_is_file(file) && file->u.file_ref); // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) { xm_io_return_error(lua, "init buffer failed!"); } tb_byte_t *data = tb_buffer_resize(&file->rcache, XM_IO_BLOCK_MAXN); if (!data) { tb_buffer_exit(&buf); xm_io_return_error(lua, "out of memory: failed to resize read cache"); } // read all tb_stream_ref_t stream = file->u.file_ref; tb_hize_t offset = 0; tb_hong_t size = tb_stream_size(stream); tb_bool_t sequential_consume = (size == 0); while (sequential_consume || (offset = tb_stream_offset(stream)) < size) { tb_long_t real = tb_stream_read(stream, data, XM_IO_BLOCK_MAXN); if (real > 0) { tb_buffer_memncat(&buf, data, real); } else if (!real) { real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); tb_check_break(real > 0); } else { break; } } if (tb_buffer_size(&buf)) { lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); } else { lua_pushliteral(lua, ""); } tb_buffer_exit(&buf); return 1; } static tb_bool_t xm_io_file_read_all_to_buffer(xm_io_file_t *file, tb_buffer_ref_t buf) { tb_assert(file && xm_io_file_is_file(file) && file->u.file_ref && buf); tb_byte_t *data = tb_buffer_resize(&file->rcache, XM_IO_BLOCK_MAXN); tb_assert_and_check_return_val(data, tb_false); tb_stream_ref_t stream = file->u.file_ref; tb_hize_t offset = 0; tb_hong_t size = tb_stream_size(stream); tb_bool_t sequential_consume = (size == 0); while (sequential_consume || (offset = tb_stream_offset(stream)) < size) { tb_long_t real = tb_stream_read(stream, data, XM_IO_BLOCK_MAXN); if (real > 0) { tb_buffer_memncat(buf, data, real); } else if (!real) { real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); tb_check_break(real > 0); } else { break; } } return tb_true; } static tb_int_t xm_io_file_read_all_with_continuation(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) { tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref); tb_buffer_t buf; if (!tb_buffer_init(&buf)) { xm_io_return_error(lua, "init buffer failed!"); } while (1) { tb_int_t state = xm_io_file_buffer_pushline(&buf, file, continuation, tb_true); if (state == PL_EOF) { break; } if (state == PL_FAIL) { tb_buffer_exit(&buf); xm_io_return_error(lua, "failed to readall"); } } if (tb_buffer_size(&buf)) { lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); } else { lua_pushliteral(lua, ""); } tb_buffer_exit(&buf); return 1; } static tb_int_t xm_io_file_read_all(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) { tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref); // is binary? read all directly tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; if (is_binary) { return xm_io_file_read_all_directly(lua, file); } if (*continuation != '\0') { return xm_io_file_read_all_with_continuation(lua, file, continuation); } tb_buffer_t raw; tb_buffer_t out; tb_bool_t raw_ok = tb_false; tb_bool_t out_ok = tb_false; tb_int_t result = 0; tb_char_t const *errors = tb_null; do { if (!tb_buffer_init(&raw)) { errors = "init buffer failed!"; result = 2; break; } raw_ok = tb_true; if (!xm_io_file_read_all_to_buffer(file, &raw)) { errors = "failed to read all"; result = 2; break; } tb_size_t rawsize = tb_buffer_size(&raw); if (!tb_buffer_init(&out)) { errors = "init buffer failed!"; result = 2; break; } out_ok = tb_true; if (!rawsize) { lua_pushliteral(lua, ""); result = 1; break; } tb_byte_t const *rawdata = (tb_byte_t const *)tb_buffer_data(&raw); tb_byte_t const *p = rawdata; tb_byte_t const *b = rawdata; tb_byte_t const *e = rawdata + rawsize; while (p < e) { if (*p == '\r' && p + 1 < e && p[1] == '\n') { if (p > b) { tb_buffer_memncat(&out, b, p - b); } tb_buffer_memncat(&out, (tb_byte_t const *)"\n", 1); p += 2; b = p; } else { p++; } } if (tb_buffer_size(&out)) { if (e > b) { tb_buffer_memncat(&out, b, e - b); } lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&out), tb_buffer_size(&out)); result = 1; break; } lua_pushlstring(lua, (tb_char_t const *)rawdata, rawsize); result = 1; } while (0); if (out_ok) { tb_buffer_exit(&out); } if (raw_ok) { tb_buffer_exit(&raw); } if (result == 2) { lua_pushnil(lua); lua_pushstring(lua, errors); } return result; } static tb_int_t xm_io_file_read_line(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation, tb_bool_t keep_crlf) { tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref); // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) { xm_io_return_error(lua, "init buffer failed!"); } // read line tb_bool_t has_content = tb_false; while (1) { switch (xm_io_file_buffer_pushline(&buf, file, continuation, keep_crlf)) { case PL_EOF: if (!has_content) { lua_pushnil(lua); } else { lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); } tb_buffer_exit(&buf); return 1; case PL_FIN: lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); tb_buffer_exit(&buf); return 1; case PL_CONL: has_content = tb_true; continue; case PL_FAIL: default: tb_buffer_exit(&buf); xm_io_return_error(lua, "failed to readline"); break; } } } static tb_int_t xm_io_file_read_n(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation, tb_long_t n) { tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref); // check continuation if (*continuation != '\0') { xm_io_return_error(lua, "continuation is not supported for read number of bytes"); } // check encoding if (file->encoding != XM_IO_FILE_ENCODING_BINARY) { xm_io_return_error(lua, "read number of bytes only allows binary file, reopen with 'rb' and try again"); } tb_bool_t ok = tb_false; if (n == 0) { tb_byte_t *data = tb_null; if (tb_stream_need(file->u.file_ref, &data, 1)) { lua_pushliteral(lua, ""); ok = tb_true; } } else { tb_byte_t *bufptr = tb_buffer_resize(&file->rcache, n + 1); if (bufptr) { if (tb_stream_bread(file->u.file_ref, bufptr, n)) { lua_pushlstring(lua, (tb_char_t const *)bufptr, n); ok = tb_true; } } } if (!ok) { lua_pushnil(lua); } return 1; } static tb_size_t xm_io_file_std_buffer_pushline(tb_buffer_ref_t buf, xm_io_file_t *file, tb_char_t const *continuation, tb_bool_t keep_crlf) { tb_assert(buf && file && continuation && xm_io_file_is_std(file)); // get input buffer tb_char_t strbuf[8192]; tb_size_t buflen = 0; tb_size_t result = PL_FAIL; if (tb_stdfile_gets(file->u.std_ref, strbuf, tb_arrayn(strbuf) - 1)) { buflen = tb_strlen(strbuf); } else { return PL_EOF; } tb_size_t conlen = tb_strlen(continuation); if (buflen > 0 && strbuf[buflen - 1] != '\n') { // end of file, no lf found result = PL_FIN; } else if (buflen > 1) { // crlf? => lf if (strbuf[buflen - 2] == '\r') { strbuf[buflen - 2] = '\n'; buflen--; } // has continuation? tb_bool_t has_conline = conlen && buflen >= conlen + 1 && tb_strncmp(continuation, (strbuf + buflen - conlen - 1), conlen) == 0; // do not keep crlf, strip the last lf if (!keep_crlf && !has_conline) { buflen--; } // strip it if has continuation? if (has_conline) { buflen -= conlen + 1; } strbuf[buflen] = '\0'; result = has_conline ? PL_CONL : PL_FIN; } else { // a single '\n' if (!keep_crlf) { buflen = 0; } result = PL_FIN; } if (result == PL_FIN || result == PL_CONL) { tb_buffer_memncat(buf, (tb_byte_t const *)strbuf, buflen); } return result; } static tb_int_t xm_io_file_std_read_line(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation, tb_bool_t keep_crlf) { tb_assert(lua && file && continuation && xm_io_file_is_std(file)); // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) { xm_io_return_error(lua, "init buffer failed!"); } // read line tb_bool_t has_content = tb_false; while (1) { switch (xm_io_file_std_buffer_pushline(&buf, file, continuation, keep_crlf)) { case PL_EOF: if (!has_content) { lua_pushnil(lua); } else { lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); } tb_buffer_exit(&buf); return 1; case PL_FIN: lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); tb_buffer_exit(&buf); return 1; case PL_CONL: has_content = tb_true; continue; case PL_FAIL: default: tb_buffer_exit(&buf); xm_io_return_error(lua, "failed to readline"); break; } } } static tb_int_t xm_io_file_std_read_all(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) { tb_assert(lua && file && continuation && xm_io_file_is_std(file)); // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) xm_io_return_error(lua, "init buffer failed!"); // read all tb_bool_t has_content = tb_false; while (1) { switch (xm_io_file_std_buffer_pushline(&buf, file, continuation, tb_true)) { case PL_EOF: if (!has_content) lua_pushliteral(lua, ""); else lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); tb_buffer_exit(&buf); return 1; case PL_FIN: case PL_CONL: has_content = tb_true; continue; case PL_FAIL: default: tb_buffer_exit(&buf); xm_io_return_error(lua, "failed to readline"); break; } } } static tb_int_t xm_io_file_std_read_n(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation, tb_long_t n) { tb_assert(lua && file && continuation && xm_io_file_is_std(file)); // check continuation if (*continuation != '\0') xm_io_return_error(lua, "continuation is not supported for std streams"); // io.read(0) if (n == 0) { tb_char_t ch; if (!tb_stdfile_peek(file->u.std_ref, &ch)) lua_pushnil(lua); else lua_pushliteral(lua, ""); return 1; } // get line buffer tb_byte_t *buf_ptr = tb_buffer_resize(&file->rcache, (tb_size_t)n); tb_assert(buf_ptr); // io.read(n) if (tb_stdfile_read(file->u.std_ref, buf_ptr, (tb_size_t)n)) lua_pushlstring(lua, (tb_char_t const *)buf_ptr, (size_t)n); else lua_pushnil(lua); return 1; } static tb_int_t xm_io_file_std_read_num(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) { tb_assert(lua && file && continuation && xm_io_file_is_std(file)); // check continuation if (*continuation != '\0') xm_io_return_error(lua, "continuation is not supported for std streams"); // read number tb_char_t strbuf[512]; if (tb_stdfile_gets(file->u.std_ref, strbuf, tb_arrayn(strbuf))) lua_pushnumber(lua, tb_s10tod(strbuf)); // TODO check invalid float number string and push nil else lua_pushnil(lua); return 1; } /* io.file_read(file, [mode, [continuation]]) * io.file_read(file, "all", "\\") * io.file_read(file, "L") * io.file_read(file, "l") * io.file_read(file, "n") * io.file_read(file, 10) */ tb_int_t xm_io_file_read(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) xm_io_return_error(lua, "read(invalid file)!"); // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // get arguments tb_char_t const *mode = luaL_optstring(lua, 2, "l"); tb_char_t const *continuation = luaL_optstring(lua, 3, ""); tb_assert_and_check_return_val(mode && continuation, 0); tb_long_t count = -1; if (lua_isnumber(lua, 2)) { count = (tb_long_t)lua_tointeger(lua, 2); if (count < 0) xm_io_return_error(lua, "invalid read size, must be positive nubmber or 0"); } else if (*mode == '*') mode++; if (xm_io_file_is_file(file)) { if (count >= 0) return xm_io_file_read_n(lua, file, continuation, count); switch (*mode) { case 'a': return xm_io_file_read_all(lua, file, continuation); case 'L': return xm_io_file_read_line(lua, file, continuation, tb_true); case 'n': xm_io_return_error(lua, "read number is not implemented"); case 'l': return xm_io_file_read_line(lua, file, continuation, tb_false); default: xm_io_return_error(lua, "unknonwn read mode"); return 0; } } else { if (count >= 0) return xm_io_file_std_read_n(lua, file, continuation, count); switch (*mode) { case 'a': return xm_io_file_std_read_all(lua, file, continuation); case 'L': return xm_io_file_std_read_line(lua, file, continuation, tb_true); case 'n': return xm_io_file_std_read_num(lua, file, continuation); case 'l': return xm_io_file_std_read_line(lua, file, continuation, tb_false); default: xm_io_return_error(lua, "unknonwn read mode"); return 0; } } } ================================================ FILE: core/src/xmake/io/file_readable.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file file_readable.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_readable" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_io_file_readable(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) { xm_io_return_error(lua, "read(invalid file)!"); } // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // has readable data? tb_bool_t ok = tb_false; if (xm_io_file_is_file(file)) { ok = tb_stream_left(file->u.file_ref) > 0; } else { ok = tb_stdfile_readable(file->u.std_ref); } lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/io/file_seek.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu, ruki * @file file_seek.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_seek" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.file_seek(file, [whence [, offset]]) tb_int_t xm_io_file_seek(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) { xm_io_return_error(lua, "seek(invalid file)!"); } // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // get whence and offset tb_char_t const *whence = luaL_optstring(lua, 2, "cur"); tb_hong_t offset = (tb_hong_t)luaL_optnumber(lua, 3, 0); tb_assert_and_check_return_val(whence, 0); // seek file if (xm_io_file_is_file(file)) { tb_assert(file->u.file_ref); switch (*whence) { case 's': // "set" break; case 'e': // "end" { tb_hong_t size = tb_stream_size(file->u.file_ref); if (size > 0 && size + offset <= size) { offset = size + offset; } else { xm_io_return_error(lua, "seek failed, invalid offset!"); } } break; default: // "cur" offset = tb_stream_offset(file->u.file_ref) + offset; break; } if (tb_stream_seek(file->u.file_ref, offset)) { lua_pushnumber(lua, (lua_Number)offset); return 1; } else { xm_io_return_error(lua, "seek failed!"); } } else { xm_io_return_error(lua, "seek is not supported on this file"); } } ================================================ FILE: core/src/xmake/io/file_size.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu, ruki * @file file_size.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_size" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.file_size(file) tb_int_t xm_io_file_size(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) { xm_io_return_error(lua, "get size for invalid file!"); } // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // get file length if (xm_io_file_is_file(file)) { // get size from raw file stream, because we cannot get size from fstream tb_assert(file->stream); lua_pushnumber(lua, (lua_Number)tb_stream_size(file->stream)); return 1; } else { xm_io_return_error(lua, "get size for invalid file!"); } } ================================================ FILE: core/src/xmake/io/file_write.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu, ruki * @file file_write.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_write" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_io_file_write_file_utfbom(xm_io_file_t *file) { tb_assert(file && xm_io_file_is_file(file) && file->u.file_ref); // write bom switch (file->encoding) { case TB_CHARSET_TYPE_UTF8: { static tb_byte_t bom[] = { 0xef, 0xbb, 0xbf }; tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom)); } break; case TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE: { static tb_byte_t bom[] = { 0xff, 0xfe }; tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom)); } break; case TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE: { static tb_byte_t bom[] = { 0xfe, 0xff }; tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom)); } break; default: break; } } static tb_void_t xm_io_file_write_file_directly(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) { tb_assert(file && data && xm_io_file_is_file(file) && file->u.file_ref); tb_stream_bwrit(file->u.file_ref, data, size); } static tb_void_t xm_io_file_write_file_transcrlf(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) { tb_assert(file && data && xm_io_file_is_file(file) && file->u.file_ref); #ifdef TB_CONFIG_OS_WINDOWS // write cached data first tb_byte_t const *odata = tb_buffer_data(&file->wcache); tb_size_t osize = tb_buffer_size(&file->wcache); if (odata && osize) { if (!tb_stream_bwrit(file->u.file_ref, odata, osize)) return; tb_buffer_clear(&file->wcache); } // write data by lines tb_char_t const *p = (tb_char_t const *)data; tb_char_t const *e = p + size; tb_char_t const *lf = tb_null; while (p < e) { lf = tb_strnchr(p, e - p, '\n'); if (lf) { if (lf > p && lf[-1] == '\r') { if (!tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)p, lf + 1 - p)) break; } else { if (lf > p && !tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)p, lf - p)) break; if (!tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)"\r\n", 2)) break; } // next line p = lf + 1; } else { // cache the left data tb_buffer_memncat(&file->wcache, (tb_byte_t const *)p, e - p); p = e; break; } } #else return xm_io_file_write_file_directly(file, data, size); #endif } static tb_void_t xm_io_file_write_std(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) { tb_assert(file && data && xm_io_file_is_std(file)); // check type tb_size_t type = (file->type & ~XM_IO_FILE_FLAG_TTY); tb_check_return(type != XM_IO_FILE_TYPE_STDIN); // write data to stdout/stderr tb_stdfile_writ(file->u.std_ref, data, size); } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.file_write(file, ...) tb_int_t xm_io_file_write(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is user data? if (!lua_isuserdata(lua, 1)) xm_io_return_error(lua, "write(invalid file)!"); // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1); tb_check_return_val(file, 0); // write file data tb_int_t narg = lua_gettop(lua); if (narg > 1) { tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; for (tb_int_t i = 2; i <= narg; i++) { // get data size_t datasize = 0; tb_byte_t const *data = tb_null; if (lua_isstring(lua, i)) { data = (tb_byte_t const *)luaL_checklstring(lua, i, &datasize); } else if (lua_istable(lua, i)) { // get bytes data lua_pushstring(lua, "data"); lua_gettable(lua, i); if (xm_lua_isinteger(lua, -1)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, -1); } lua_pop(lua, 1); tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); lua_pushstring(lua, "size"); lua_gettable(lua, i); if (xm_lua_isinteger(lua, -1)) { datasize = (tb_size_t)lua_tointeger(lua, -1); } lua_pop(lua, 1); // mark as binary data is_binary = tb_true; } tb_check_continue(datasize); tb_assert_and_check_break(data); // write data to std or file if (xm_io_file_is_std(file)) { xm_io_file_write_std(file, data, (tb_size_t)datasize); } else if (is_binary) { xm_io_file_write_file_directly(file, data, (tb_size_t)datasize); } else { // write utf bom first? if (file->utfbom) { xm_io_file_write_file_utfbom(file); file->utfbom = tb_false; } xm_io_file_write_file_transcrlf(file, data, (tb_size_t)datasize); } } } lua_settop(lua, 1); lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/io/filelock_close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file filelock_close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "filelock_close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.filelock_close(lock) tb_int_t xm_io_filelock_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check lock? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get lock tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(lock, 0); // exit lock tb_filelock_exit(lock); // save result: ok lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/io/filelock_lock.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file filelock_lock.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "filelock_lock" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* lock file * * exclusive lock: io.filelock_lock(lock, "/xxxx/filelock") * shared lock: io.filelock_lock(lock, "/xxxx/filelock", {shared = true}) */ tb_int_t xm_io_filelock_lock(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get option argument tb_bool_t is_shared = tb_false; if (lua_istable(lua, 2)) { // is shared lock? lua_pushstring(lua, "shared"); lua_gettable(lua, 2); is_shared = (tb_bool_t)lua_toboolean(lua, -1); lua_pop(lua, 1); } // check lock? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get lock tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(lock, 0); // lock it tb_bool_t ok = tb_filelock_enter(lock, is_shared ? TB_FILELOCK_MODE_SH : TB_FILELOCK_MODE_EX); lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/io/filelock_open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file filelock_open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "filelock_open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* * io.filelock_open(path) */ tb_int_t xm_io_filelock_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get file path tb_char_t const *path = luaL_checkstring(lua, 1); tb_assert_and_check_return_val(path, 0); // init file lock tb_long_t tryn = 2; tb_filelock_ref_t lock = tb_null; while (!lock && tryn-- > 0) { lock = tb_filelock_init_from_path(path, tb_file_info(path, tb_null) ? TB_FILE_MODE_RW : TB_FILE_MODE_RW | TB_FILE_MODE_CREAT); } if (lock) { xm_lua_pushpointer(lua, (tb_pointer_t)lock); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/io/filelock_trylock.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file filelock_trylock.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "filelock_trylock" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* try to lock file * * exclusive lock: io.filelock_trylock("/xxxx/filelock") * shared lock: io.filelock_trylock("/xxxx/filelock", {shared = true}) */ tb_int_t xm_io_filelock_trylock(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get option argument tb_bool_t is_shared = tb_false; if (lua_istable(lua, 2)) { // is shared lock? lua_pushstring(lua, "shared"); lua_gettable(lua, 2); is_shared = (tb_bool_t)lua_toboolean(lua, -1); lua_pop(lua, 1); } // check lock? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get lock tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(lock, 0); // try to lock it tb_bool_t ok = tb_filelock_enter_try(lock, is_shared ? TB_FILELOCK_MODE_SH : TB_FILELOCK_MODE_EX); lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/io/filelock_unlock.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file filelock_unlock.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "filelock_unlock" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.filelock_unlock(lock) tb_int_t xm_io_filelock_unlock(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check lock? if (!xm_lua_topointer(lua, 1)) { return 0; } // get lock tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(lock, 0); // unlock it tb_bool_t ok = tb_filelock_leave(lock); lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/io/iscygpty.c ================================================ /* * iscygpty.c -- part of ptycheck * https://github.com/k-takata/ptycheck * * Copyright (c) 2015-2017 K.Takata * * You can redistribute it and/or modify it under the terms of either * the MIT license (as described below) or the Vim license. * * 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 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. */ #ifdef _WIN32 #include #include #include #include #ifdef USE_FILEEXTD /* VC 7.1 or earlier doesn't support SAL. */ #if !defined(_MSC_VER) || (_MSC_VER < 1400) #define __out #define __in #define __in_opt #endif /* Win32 FileID API Library: * http://www.microsoft.com/en-us/download/details.aspx?id=22599 * Needed for WinXP. */ #include #else /* USE_FILEEXTD */ /* VC 8 or earlier. */ #if defined(_MSC_VER) && (_MSC_VER < 1500) #ifdef ENABLE_STUB_IMPL #define STUB_IMPL #else #error "Win32 FileID API Library is required for VC2005 or earlier." #endif #endif #endif /* USE_FILEEXTD */ #if _WIN32_WINNT >= 0x0600 #define USE_DYNFILEID // we need to enable it for supporting xp #endif #ifdef USE_DYNFILEID typedef BOOL(WINAPI *pfnGetFileInformationByHandleEx)(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize); static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL; #ifndef USE_FILEEXTD static BOOL WINAPI stub_GetFileInformationByHandleEx(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize) { return FALSE; } #endif static void setup_fileid_api(void) { if (pGetFileInformationByHandleEx != NULL) { return; } pGetFileInformationByHandleEx = (pfnGetFileInformationByHandleEx) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetFileInformationByHandleEx"); if (pGetFileInformationByHandleEx == NULL) { #ifdef USE_FILEEXTD pGetFileInformationByHandleEx = GetFileInformationByHandleEx; #else pGetFileInformationByHandleEx = stub_GetFileInformationByHandleEx; #endif } } #else #define pGetFileInformationByHandleEx GetFileInformationByHandleEx #define setup_fileid_api() #endif #define is_wprefix(s, prefix) (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) /* Check if the fd handle is a cygwin/msys's pty. */ int is_cygpty(HANDLE h) { #if defined(STUB_IMPL) return 0; #elif _WIN32_WINNT >= 0x0600 int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * (MAX_PATH - 1); FILE_NAME_INFO *nameinfo; WCHAR *p = NULL; setup_fileid_api(); if (h == INVALID_HANDLE_VALUE) { return 0; } /* Cygwin/msys's pty is a pipe. */ if (GetFileType(h) != FILE_TYPE_PIPE) { return 0; } nameinfo = (FILE_NAME_INFO *)malloc(size + sizeof(WCHAR)); if (nameinfo == NULL) { return 0; } /* Check the name of the pipe: * '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' */ if (pGetFileInformationByHandleEx(h, FileNameInfo, nameinfo, size)) { nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; p = nameinfo->FileName; if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ p += 8; } else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */ p += 6; } else { p = NULL; } if (p != NULL) { while (*p && isxdigit(*p)) { /* Skip 16-digit hexadecimal. */ ++p; } if (is_wprefix(p, L"-pty")) { p += 4; } else { p = NULL; } } if (p != NULL) { while (*p && isdigit(*p)) { /* Skip pty number. */ ++p; } if (is_wprefix(p, L"-from-master")) { //p += 12; } else if (is_wprefix(p, L"-to-master")) { //p += 10; } else { p = NULL; } } } free(nameinfo); return (p != NULL); #else return 0; #endif } #endif /* _WIN32 */ ================================================ FILE: core/src/xmake/io/pipe_close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file pipe_close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "pipe_close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.pipe_close(pipe) tb_int_t xm_io_pipe_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check pipe? if (!xm_pipe_file_is_valid(lua, 1)) { return 0; } // get the pipe file tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1); tb_check_return_val(pipefile, 0); // exit pipe file lua_pushboolean(lua, tb_pipe_file_exit(pipefile)); return 1; } ================================================ FILE: core/src/xmake/io/pipe_connect.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file pipe_connect.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "pipe_connect" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.pipe_connect(pipefile) tb_int_t xm_io_pipe_connect(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check pipe if (!xm_lua_ispointer(lua, 1)) { lua_pushnumber(lua, -1); lua_pushliteral(lua, "invalid pipe!"); return 2; } // get pipe file tb_pipe_file_ref_t pipefile = (tb_pipe_file_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(pipefile, 0); // connect pipe lua_pushnumber(lua, (tb_int_t)tb_pipe_file_connect(pipefile)); return 1; } ================================================ FILE: core/src/xmake/io/pipe_open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file pipe_open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "pipe_open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* * io.pipe_open(name, mode, buffsize) */ tb_int_t xm_io_pipe_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get pipe name and mode tb_char_t const *name = luaL_checkstring(lua, 1); tb_char_t const *modestr = luaL_optstring(lua, 2, "r"); tb_assert_and_check_return_val(name && modestr, 0); // get pipe mode value tb_size_t mode = TB_PIPE_MODE_RO; if (modestr[0] == 'w') { mode = TB_PIPE_MODE_WO; } // set block mode if (modestr[1] == 'B') { mode |= TB_PIPE_MODE_BLOCK; } // get buffer size tb_size_t buffsize = (tb_size_t)luaL_checknumber(lua, 3); // open pipe file tb_pipe_file_ref_t pipefile = tb_pipe_file_init(name, mode, buffsize); if (pipefile) { xm_lua_pushpointer(lua, (tb_pointer_t)pipefile); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/io/pipe_openpair.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file pipe_openpair.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "pipe_openpair" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* * io.pipe_openpair(mode, buffsize) */ tb_int_t xm_io_pipe_openpair(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get pipe mode tb_char_t const *modestr = luaL_optstring(lua, 1, "AA"); tb_assert_and_check_return_val(modestr, 0); // init mode tb_size_t mode[2] = { 0 }; if (modestr[0] == 'B') { mode[0] |= TB_PIPE_MODE_BLOCK; } if (modestr[1] == 'B') { mode[1] |= TB_PIPE_MODE_BLOCK; } // get buffer size tb_size_t buffsize = (tb_size_t)luaL_checknumber(lua, 2); // init pipe tb_pipe_file_ref_t pipefile[2]; if (tb_pipe_file_init_pair(pipefile, mode, buffsize)) { xm_lua_pushpointer(lua, (tb_pointer_t)pipefile[0]); xm_lua_pushpointer(lua, (tb_pointer_t)pipefile[1]); } else { lua_pushnil(lua); lua_pushnil(lua); } return 2; } ================================================ FILE: core/src/xmake/io/pipe_read.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file pipe_read.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "pipe_read" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // real, data_or_errors = io.pipe_read(pipefile, size) tb_int_t xm_io_pipe_read(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check pipe file if (!xm_pipe_file_is_valid(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid pipe file!"); return 2; } // get pipe file tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1); tb_check_return_val(pipefile, 0); // get data tb_byte_t *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (!data) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p)!", data); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // get size tb_long_t size = 0; if (xm_lua_isinteger(lua, 3)) { size = (tb_long_t)lua_tointeger(lua, 3); } if (size <= 0) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size); return 2; } // read data tb_long_t real = tb_pipe_file_read(pipefile, data, size); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/io/pipe_wait.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file pipe_wait.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "pipe_wait" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.pipe_wait(pipefile, events, timeout) tb_int_t xm_io_pipe_wait(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check pipe? if (!xm_pipe_file_is_valid(lua, 1)) { return 0; } // get pipe file tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1); tb_check_return_val(pipefile, 0); // get events tb_size_t events = (tb_size_t)luaL_checknumber(lua, 2); // get timeout tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 3); // wait pipe lua_pushnumber(lua, (tb_int_t)tb_pipe_file_wait(pipefile, events, timeout)); return 1; } ================================================ FILE: core/src/xmake/io/pipe_write.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file pipe_write.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "pipe_write" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.pipe_write(pipefile, data, start, last) tb_int_t xm_io_pipe_write(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check pipe if (!xm_pipe_file_is_valid(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid pipe file!"); return 2; } // get pipe file tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1); tb_check_return_val(pipefile, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (xm_lua_isinteger(lua, 3)) { size = (tb_size_t)lua_tointeger(lua, 3); } if (!data || !size) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // write data tb_long_t real = tb_pipe_file_write(pipefile, data, size); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/io/poller.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file poller.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "poller" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "poller.h" #include "../engine.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_poller_ref_t xm_io_poller(lua_State *lua) { tb_poller_ref_t poller = tb_null; xm_engine_ref_t engine = xm_engine_get(lua); if (engine) { poller = xm_engine_poller(engine); } tb_assert(poller); return poller; } ================================================ FILE: core/src/xmake/io/poller.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file poller.h * */ #ifndef XM_IO_POLLER_H #define XM_IO_POLLER_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the poller state in wait events typedef struct __xm_poller_state_t { lua_State *lua; tb_int_t events_count; } xm_poller_state_t; /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ /* get io poller * * @return the io poller */ tb_poller_ref_t xm_io_poller(lua_State *lua); #endif ================================================ FILE: core/src/xmake/io/poller_insert.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file poller_insert.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "poller_insert" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "poller.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.poller_insert(obj:otype(), obj:cdata(), events) tb_int_t xm_io_poller_insert(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 2)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "invalid poller object!"); return 2; } // get otype tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1); // get cdata tb_char_t const *cdata_str = tb_null; tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer2(lua, 2, &cdata_str); tb_check_return_val(cdata, 0); // get events tb_size_t events = (tb_size_t)luaL_checknumber(lua, 3); // insert events to poller tb_poller_object_t object; object.type = otype; object.ref.ptr = cdata; lua_pushboolean(lua, tb_poller_insert(xm_io_poller(lua), &object, events, cdata_str)); return 1; } ================================================ FILE: core/src/xmake/io/poller_modify.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file poller_modify.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "poller_modify" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "poller.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.poller_modify(obj:otype(), obj:cdata(), events) tb_int_t xm_io_poller_modify(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 2)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "invalid poller object!"); return 2; } // get otype tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1); // get cdata tb_char_t const *cdata_str = tb_null; tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer2(lua, 2, &cdata_str); tb_check_return_val(cdata, 0); // get events tb_size_t events = (tb_size_t)luaL_checknumber(lua, 3); // modify events in poller tb_poller_object_t object; object.type = otype; object.ref.ptr = cdata; lua_pushboolean(lua, tb_poller_modify(xm_io_poller(lua), &object, events, cdata_str)); return 1; } ================================================ FILE: core/src/xmake/io/poller_remove.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file poller_remove.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "poller_remove" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "poller.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.poller_remove(obj:otype(), obj) tb_int_t xm_io_poller_remove(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 2)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "invalid poller object!"); return 2; } // get otype tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1); // get cdata tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer(lua, 2); tb_check_return_val(cdata, 0); // remove events from poller tb_poller_object_t object; object.type = otype; object.ref.ptr = cdata; lua_pushboolean(lua, tb_poller_remove(xm_io_poller(lua), &object)); return 1; } ================================================ FILE: core/src/xmake/io/poller_spank.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file poller_spank.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "poller_spank" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "poller.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.poller_spank() tb_int_t xm_io_poller_spank(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // spank the poller, break the tb_poller_wait() and return all events tb_poller_spak(xm_io_poller(lua)); return 0; } ================================================ FILE: core/src/xmake/io/poller_support.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file poller_support.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "poller_support" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "poller.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.poller_support(events) tb_int_t xm_io_poller_support(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get events tb_size_t events = (tb_size_t)luaL_checknumber(lua, 1); // support events for poller lua_pushboolean(lua, tb_poller_support(xm_io_poller(lua), events)); return 1; } ================================================ FILE: core/src/xmake/io/poller_wait.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file poller_wait.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "poller_wait" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "poller.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_io_poller_event(tb_poller_ref_t poller, tb_poller_object_ref_t object, tb_long_t events, tb_cpointer_t priv) { xm_poller_state_t *state = (xm_poller_state_t *)tb_poller_priv(poller); tb_assert_and_check_return(state && state->lua); // save object and events lua_State *lua = state->lua; lua_newtable(lua); lua_pushinteger(lua, (tb_int_t)object->type); lua_rawseti(lua, -2, 1); if (priv) { lua_pushstring(lua, (tb_char_t const *)priv); } else { lua_pushlightuserdata(lua, object->ref.ptr); } lua_rawseti(lua, -2, 2); if (object->type == TB_POLLER_OBJECT_FWATCHER) { lua_newtable(lua); tb_fwatcher_event_t *event = (tb_fwatcher_event_t *)events; if (event) { lua_pushstring(lua, "path"); lua_pushstring(lua, event->filepath); lua_settable(lua, -3); lua_pushstring(lua, "type"); lua_pushinteger(lua, event->event); lua_settable(lua, -3); } } else { lua_pushinteger(lua, (tb_int_t)events); } lua_rawseti(lua, -2, 3); lua_rawseti(lua, -2, ++state->events_count); } /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // local events, count = io.poller_wait(timeout) tb_int_t xm_io_poller_wait(lua_State *lua) { tb_poller_ref_t poller = xm_io_poller(lua); tb_assert_and_check_return_val(poller && lua, 0); // get timeout tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 1); // reset events count xm_poller_state_t *state = (xm_poller_state_t *)tb_poller_priv(poller); state->events_count = 0; // wait it lua_newtable(lua); tb_long_t count = tb_poller_wait(poller, xm_io_poller_event, timeout); if (count > 0) { lua_pushinteger(lua, (tb_int_t)count); return 2; } else if (!count) { // timeout lua_pop(lua, 1); lua_pushnil(lua); lua_pushinteger(lua, 0); return 2; } lua_pop(lua, 1); lua_pushnil(lua); lua_pushinteger(lua, -1); return 2; } ================================================ FILE: core/src/xmake/io/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_IO_PREFIX_H #define XM_IO_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_IO_BLOCK_MAXN (TB_STREAM_BLOCK_MAXN * 10) // return io error #define xm_io_return_error(lua, error) \ do { \ lua_pushnil(lua); \ lua_pushliteral(lua, error); \ return 2; \ } while (0) /* ////////////////////////////////////////////////////////////////////////////////////// * types */ typedef enum __xm_io_file_type_e { XM_IO_FILE_TYPE_FILE = 0 //!< disk file , XM_IO_FILE_TYPE_STDIN = 1, XM_IO_FILE_TYPE_STDOUT = 2, XM_IO_FILE_TYPE_STDERR = 3 , XM_IO_FILE_FLAG_TTY = 0x10 //!< mark tty std stream } xm_io_file_type_e; /* use negetive numbers for this enum, its a extension for tb_charset_type_e * before adding new values, make sure they have not conflicts with values in tb_charset_type_e */ typedef enum __xm_io_file_encoding_e { XM_IO_FILE_ENCODING_UNKNOWN = -1, XM_IO_FILE_ENCODING_BINARY = -2 } xm_io_file_encoding_e; // the file type typedef struct __xm_io_file_t { union { /* the normal file for XM_IO_FILE_TYPE_FILE * * direct: file_ref -> stream -> file * transcode: file_ref -> fstream -> stream -> file */ tb_stream_ref_t file_ref; // the standard io file tb_stdfile_ref_t std_ref; } u; tb_stream_ref_t stream; // the file stream for XM_IO_FILE_TYPE_FILE tb_stream_ref_t fstream; // the file charset stream filter tb_size_t mode; // tb_file_mode_t tb_size_t type; // xm_io_file_type_e tb_size_t encoding; // value of xm_io_file_encoding_e or tb_charset_type_e tb_bool_t utfbom; // write utf-bom for utf encoding? tb_buffer_t rcache; // the read line cache buffer tb_buffer_t wcache; // the write line cache buffer } xm_io_file_t; static __tb_inline__ tb_bool_t xm_io_file_is_file(xm_io_file_t const *file) { return file && file->type == XM_IO_FILE_TYPE_FILE; } static __tb_inline__ tb_bool_t xm_io_file_is_std(xm_io_file_t const *file) { return file && file->type != XM_IO_FILE_TYPE_FILE; } static __tb_inline__ tb_bool_t xm_io_file_is_tty(xm_io_file_t const *file) { return file && (file->type & XM_IO_FILE_FLAG_TTY); } // check pipe file static __tb_inline__ tb_bool_t xm_pipe_file_is_valid(lua_State *lua, tb_int_t index) { return xm_lua_ispointer(lua, index) || xm_lua_isinteger(lua, index); } // get the pipe file from arguments static __tb_inline__ tb_pipe_file_ref_t xm_pipe_file_get(lua_State *lua, tb_int_t index) { tb_pipe_file_ref_t pipe_file = tb_null; if (xm_lua_isinteger(lua, index)) pipe_file = (tb_pipe_file_ref_t)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); else if (xm_lua_ispointer(lua, index)) pipe_file = (tb_pipe_file_ref_t)xm_lua_topointer(lua, index); return pipe_file; } #endif ================================================ FILE: core/src/xmake/io/socket_accept.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_accept.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_accept" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // local sock = io.socket_accept(sock) tb_int_t xm_io_socket_accept(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // accept socket tb_socket_ref_t client = tb_socket_accept(sock, tb_null); if (client) { xm_lua_pushpointer(lua, (tb_pointer_t)client); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/io/socket_bind.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_bind.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_bind" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.socket_bind(sock, addr, port, family) tb_int_t xm_io_socket_bind(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket if (!xm_lua_ispointer(lua, 1)) { lua_pushboolean(lua, tb_false); lua_pushliteral(lua, "invalid socket!"); return 2; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get address tb_char_t const *address = lua_tostring(lua, 2); tb_assert_and_check_return_val(address, 0); // get family tb_uint8_t family = (tb_uint8_t)luaL_checknumber(lua, 4); // init address tb_ipaddr_t addr; if (family == TB_IPADDR_FAMILY_UNIX) { tb_bool_t is_abstract = (tb_bool_t)lua_toboolean(lua, 3); tb_ipaddr_unix_set_cstr(&addr, address, is_abstract); } else { tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 3); tb_ipaddr_set(&addr, address, port, family); } // bind socket lua_pushboolean(lua, tb_socket_bind(sock, &addr)); return 1; } ================================================ FILE: core/src/xmake/io/socket_close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.socket_close(sock) tb_int_t xm_io_socket_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // exit socket lua_pushboolean(lua, tb_socket_exit(sock)); return 1; } ================================================ FILE: core/src/xmake/io/socket_connect.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_connect.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_connect" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.socket_connect(sock, addr, port, family) tb_int_t xm_io_socket_connect(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket if (!xm_lua_ispointer(lua, 1)) { lua_pushnumber(lua, -1); lua_pushliteral(lua, "invalid socket!"); return 2; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get address tb_char_t const *address = lua_tostring(lua, 2); tb_assert_and_check_return_val(address, 0); // get family tb_uint8_t family = (tb_uint8_t)luaL_checknumber(lua, 4); // init address tb_ipaddr_t addr; if (family == TB_IPADDR_FAMILY_UNIX) { tb_bool_t is_abstract = (tb_bool_t)lua_toboolean(lua, 3); tb_ipaddr_unix_set_cstr(&addr, address, is_abstract); } else { tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 3); tb_ipaddr_set(&addr, address, port, family); } // connect socket lua_pushnumber(lua, (tb_int_t)tb_socket_connect(sock, &addr)); return 1; } ================================================ FILE: core/src/xmake/io/socket_ctrl.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_ctrl.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_ctrl" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.socket_ctrl(sock, code, value) tb_int_t xm_io_socket_ctrl(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket if (!xm_lua_ispointer(lua, 1)) { lua_pushnumber(lua, -1); lua_pushliteral(lua, "invalid socket!"); return 2; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get code tb_size_t code = (tb_size_t)luaL_checkinteger(lua, 2); // get value tb_size_t value = (tb_size_t)luaL_checkinteger(lua, 3); // control socket lua_pushboolean(lua, tb_socket_ctrl(sock, code, value)); return 1; } ================================================ FILE: core/src/xmake/io/socket_kill.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_kill.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_kill" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // local sock = io.socket_kill(sock) tb_int_t xm_io_socket_kill(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // kill socket tb_socket_kill(sock, TB_SOCKET_KILL_RW); return 0; } ================================================ FILE: core/src/xmake/io/socket_listen.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_listen.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_listen" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.socket_listen(sock, backlog) tb_int_t xm_io_socket_listen(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get backlog tb_size_t backlog = (tb_size_t)luaL_checknumber(lua, 2); // listen socket lua_pushnumber(lua, (tb_int_t)tb_socket_listen(sock, backlog)); return 1; } ================================================ FILE: core/src/xmake/io/socket_open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* * io.socket_open(socktype, family) */ tb_int_t xm_io_socket_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get socket type tb_size_t socktype = (tb_size_t)luaL_checknumber(lua, 1); // get address family tb_size_t family = (tb_size_t)luaL_checknumber(lua, 2); // map socket type switch (socktype) { case 2: socktype = TB_SOCKET_TYPE_UDP; break; case 3: socktype = TB_SOCKET_TYPE_ICMP; break; default: socktype = TB_SOCKET_TYPE_TCP; break; } // init socket tb_socket_ref_t sock = tb_socket_init(socktype, family); if (sock) { xm_lua_pushpointer(lua, (tb_pointer_t)sock); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/io/socket_peeraddr.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this sock except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @sock socket_peeraddr.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_peeraddr" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // socket to fd #define xm_io_sock2fd(sock) (lua_Number) tb_sock2fd(sock) /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* io.socket_peeraddr(sock) */ tb_int_t xm_io_socket_peeraddr(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { xm_io_return_error(lua, "get peer address for invalid sock!"); } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get peer address tb_ipaddr_t addr; tb_char_t data[256]; tb_char_t const *cstr = tb_null; if (tb_socket_peer(sock, &addr) && (cstr = tb_ipaddr_cstr(&addr, data, sizeof(data)))) { lua_pushstring(lua, cstr); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/io/socket_rawfd.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this sock except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @sock socket_rawfd.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_rawfd" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // socket to fd #define xm_io_sock2fd(sock) (lua_Number) tb_sock2fd(sock) /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* io.socket_rawfd(sock) */ tb_int_t xm_io_socket_rawfd(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) xm_io_return_error(lua, "get rawfd for invalid sock!"); // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // return result lua_pushnumber(lua, xm_io_sock2fd(sock)); return 1; } ================================================ FILE: core/src/xmake/io/socket_recv.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_recv.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_recv" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // real, data_or_errors = io.socket_recv(sock, size) tb_int_t xm_io_socket_recv(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid socket!"); return 2; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get data tb_byte_t *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (!data) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p)!", data); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // get size tb_long_t size = 0; if (xm_lua_isinteger(lua, 3)) { size = (tb_long_t)lua_tointeger(lua, 3); } if (size <= 0) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size); return 2; } // recv data tb_long_t real = tb_socket_recv(sock, data, size); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/io/socket_recvfrom.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_recvfrom.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_recvfrom" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // real, data_or_errors, addr, port = io.socket_recvfrom(sock, size) tb_int_t xm_io_socket_recvfrom(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid socket!"); return 2; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get data tb_byte_t *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (!data) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p)!", data); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // get size tb_long_t size = 0; if (xm_lua_isinteger(lua, 3)) { size = (tb_long_t)lua_tointeger(lua, 3); } if (size <= 0) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size); return 2; } // recv data tb_ipaddr_t ipaddr; tb_ipaddr_clear(&ipaddr); tb_int_t retn = 1; tb_long_t real = tb_socket_urecv(sock, &ipaddr, data, size); lua_pushinteger(lua, (tb_int_t)real); if (real > 0) { retn = 2; lua_pushnil(lua); if (!tb_ipaddr_is_empty(&ipaddr)) { tb_char_t buffer[256]; tb_char_t const *ipstr = tb_ipaddr_ip_cstr(&ipaddr, buffer, sizeof(buffer)); if (ipstr) { lua_pushstring(lua, ipstr); lua_pushinteger(lua, (tb_int_t)tb_ipaddr_port(&ipaddr)); retn = 4; } } } return retn; } ================================================ FILE: core/src/xmake/io/socket_send.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_send.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_send" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.socket_send(sock, data, start, last) tb_int_t xm_io_socket_send(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid socket!"); return 2; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (xm_lua_isinteger(lua, 3)) { size = (tb_size_t)lua_tointeger(lua, 3); } if (!data || !size) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // send data tb_long_t real = tb_socket_send(sock, data, size); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/io/socket_sendfile.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_sendfile.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_sendfile" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.socket_sendfile(sock, file, start, last) tb_int_t xm_io_socket_sendfile(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid socket!"); return 2; } // check file if (!lua_isuserdata(lua, 2)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid file!"); return 2; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get file xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 2); tb_check_return_val(file, 0); // does not support stdfile if (!xm_io_file_is_file(file) || !file->stream) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid file type!"); return 2; } // get file reference tb_file_ref_t rawfile = tb_null; if (!tb_stream_ctrl(file->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) || !rawfile) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "cannot get file reference!"); return 2; } // get file size tb_hize_t filesize = tb_file_size(rawfile); if (!filesize) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "cannot send empty file!"); return 2; } // get start tb_long_t start = 1; if (lua_isnumber(lua, 3)) { start = (tb_long_t)lua_tonumber(lua, 3); } if (start < 1 || start > filesize) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid start position(%d)!", (tb_int_t)start); return 2; } // get last tb_long_t last = (tb_long_t)filesize; if (lua_isnumber(lua, 4)) { last = (tb_long_t)lua_tonumber(lua, 4); } if (last < start - 1 || last > filesize + start - 1) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid last position(%d)!", (tb_int_t)last); return 2; } // send file data tb_long_t real = (tb_long_t)tb_socket_sendf(sock, rawfile, start - 1, last - start + 1); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/io/socket_sendto.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_sendto.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_sendto" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // io.socket_sendto(sock, data, addr, port) tb_int_t xm_io_socket_sendto(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid socket!"); return 2; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (xm_lua_isinteger(lua, 3)) { size = (tb_size_t)lua_tointeger(lua, 3); } if (!data || !size) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // get address tb_char_t const *addr = lua_tostring(lua, 4); tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 5); if (!addr || !port) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid address!"); return 2; } // get address family tb_size_t family = (tb_size_t)luaL_checknumber(lua, 6); // init ip address tb_ipaddr_t ipaddr; tb_ipaddr_set(&ipaddr, addr, port, (tb_uint8_t)family); // send data tb_long_t real = tb_socket_usend(sock, &ipaddr, data, size); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/io/socket_wait.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file socket_wait.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "socket_wait" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.socket_wait(sock, events, timeout) tb_int_t xm_io_socket_wait(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check socket? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get socket tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(sock, 0); // get events tb_size_t events = (tb_size_t)luaL_checknumber(lua, 2); // get timeout tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 3); // wait socket lua_pushnumber(lua, (tb_int_t)tb_socket_wait(sock, events, timeout)); return 1; } ================================================ FILE: core/src/xmake/io/stdfile.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu, ruki * @file stdfile.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "stdfile" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifdef TB_CONFIG_OS_WINDOWS #include #include "iscygpty.c" #else #include #include #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // the singleton type of stdfile #define XM_IO_STDFILE_STDIN (TB_SINGLETON_TYPE_USER + 1) #define XM_IO_STDFILE_STDOUT (TB_SINGLETON_TYPE_USER + 2) #define XM_IO_STDFILE_STDERR (TB_SINGLETON_TYPE_USER + 3) /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_size_t xm_io_stdfile_isatty(tb_size_t type) { tb_bool_t answer = tb_false; #if defined(TB_CONFIG_OS_WINDOWS) DWORD mode; HANDLE console_handle = tb_null; switch (type) { case XM_IO_FILE_TYPE_STDIN: console_handle = GetStdHandle(STD_INPUT_HANDLE); break; case XM_IO_FILE_TYPE_STDOUT: console_handle = GetStdHandle(STD_OUTPUT_HANDLE); break; case XM_IO_FILE_TYPE_STDERR: console_handle = GetStdHandle(STD_ERROR_HANDLE); break; } answer = GetConsoleMode(console_handle, &mode); /* we cannot call is_cygpty for stdin, because it will cause io.readable is always true * https://github.com/xmake-io/xmake/issues/2504#issuecomment-1170130756 */ if (!answer && type != XM_IO_FILE_TYPE_STDIN) { answer = is_cygpty(console_handle); } #else switch (type) { case XM_IO_FILE_TYPE_STDIN: answer = isatty(fileno(stdin)); break; case XM_IO_FILE_TYPE_STDOUT: answer = isatty(fileno(stdout)); break; case XM_IO_FILE_TYPE_STDERR: answer = isatty(fileno(stderr)); break; } #endif if (answer) { type |= XM_IO_FILE_FLAG_TTY; } return type; } // @see https://github.com/xmake-io/xmake/issues/2580 static tb_void_t xm_io_stdfile_init_buffer(tb_size_t type) { #if !defined(TB_CONFIG_OS_WINDOWS) struct stat stats; tb_int_t size = BUFSIZ; if (fstat(fileno(stdout), &stats) != -1) { size = stats.st_blksize; } setvbuf(stdout, tb_null, _IOLBF, size); #endif } static xm_io_file_t *xm_io_stdfile_new(lua_State *lua, tb_size_t type) { // init stdfile tb_stdfile_ref_t fp = tb_null; switch (type) { case XM_IO_FILE_TYPE_STDIN: fp = tb_stdfile_input(); break; case XM_IO_FILE_TYPE_STDOUT: fp = tb_stdfile_output(); break; case XM_IO_FILE_TYPE_STDERR: fp = tb_stdfile_error(); break; } // new file xm_io_file_t *file = (xm_io_file_t *)lua_newuserdata(lua, sizeof(xm_io_file_t)); tb_assert_and_check_return_val(file, tb_null); // init file file->u.std_ref = fp; file->stream = tb_null; file->fstream = tb_null; file->type = xm_io_stdfile_isatty(type); file->encoding = TB_CHARSET_TYPE_UTF8; // init stdio buffer xm_io_stdfile_init_buffer(type); // init the read/write line cache buffer tb_buffer_init(&file->rcache); tb_buffer_init(&file->wcache); return file; } /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ // io.stdfile(stdin: 1, stdout: 2, stderr: 3) tb_int_t xm_io_stdfile(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get std type tb_long_t type = (tb_long_t)lua_tointeger(lua, 1); /* push a new stdfile * * @note we need to ensure that it is a singleton in the external lua script, and will only be created once, e.g. io.stdin, io.stdout, io.stderr */ xm_io_file_t *file = xm_io_stdfile_new(lua, type); if (file) { return 1; } else { xm_io_return_error(lua, "invalid stdfile type!"); } } ================================================ FILE: core/src/xmake/libc/byteof.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file byteof.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "byteof" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_byteof(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get data tb_pointer_t data = tb_null; if (lua_isnumber(lua, 1)) { data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1); } else if (lua_isstring(lua, 1)) { data = (tb_pointer_t)luaL_checkstring(lua, 1); } else { xm_libc_return_error(lua, "libc.byteof(invalid data)!"); } // get offset tb_int_t offset = 0; if (lua_isnumber(lua, 2)) { offset = (tb_int_t)lua_tointeger(lua, 2); } else { xm_libc_return_error(lua, "libc.byteof(invalid offset)!"); } lua_pushinteger(lua, ((tb_byte_t const *)data)[offset]); return 1; } ================================================ FILE: core/src/xmake/libc/dataptr.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file dataptr.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "dataptr" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_dataptr(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_pointer_t data = tb_null; if (lua_isstring(lua, 1)) { data = (tb_pointer_t)luaL_checkstring(lua, 1); } else if (lua_isnumber(lua, 1)) { data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1); } else if (xm_lua_ispointer(lua, 1)) { data = (tb_pointer_t)xm_lua_topointer(lua, 1); } else { xm_libc_return_error(lua, "libc.dataptr(invalid data)!"); } lua_pushinteger(lua, (lua_Integer)(tb_long_t)data); return 1; } ================================================ FILE: core/src/xmake/libc/free.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file free.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "free" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_free(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // do free tb_pointer_t data = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1); if (data) { tb_free(data); } return 0; } ================================================ FILE: core/src/xmake/libc/malloc.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file malloc.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "malloc" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_malloc(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // do malloc tb_pointer_t data = tb_null; tb_long_t size = (tb_long_t)luaL_checkinteger(lua, 1); if (size > 0) { data = tb_malloc(size); } lua_pushinteger(lua, (lua_Integer)(tb_long_t)data); return 1; } ================================================ FILE: core/src/xmake/libc/memcpy.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file memcpy.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "memcpy" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_memcpy(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // do memcpy tb_pointer_t dst = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1); tb_pointer_t src = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 2); tb_int_t size = (tb_int_t)lua_tointeger(lua, 3); if (dst && src && size > 0) { tb_memcpy(dst, src, size); } return 0; } ================================================ FILE: core/src/xmake/libc/memmov.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file memmov.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "memmov" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_memmov(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // do memmov tb_pointer_t dst = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1); tb_pointer_t src = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 2); tb_int_t size = (tb_int_t)lua_tointeger(lua, 3); if (dst && src && size > 0) { tb_memmov(dst, src, size); } return 0; } ================================================ FILE: core/src/xmake/libc/memset.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file memset.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "memset" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_memset(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // do memset tb_pointer_t data = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1); tb_char_t ch = (tb_char_t)lua_tointeger(lua, 2); tb_int_t size = (tb_int_t)lua_tointeger(lua, 3); if (data && size > 0) { tb_memset(data, ch, size); } return 0; } ================================================ FILE: core/src/xmake/libc/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_LIBC_PREFIX_H #define XM_LIBC_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // return libc error #define xm_libc_return_error(lua, error) \ do { \ lua_pushnil(lua); \ lua_pushliteral(lua, error); \ return 2; \ } while (0) #endif ================================================ FILE: core/src/xmake/libc/setbyte.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file setbyte.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "setbyte" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_setbyte(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get data tb_pointer_t data = tb_null; if (lua_isnumber(lua, 1)) { data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1); } else if (lua_isstring(lua, 1)) { data = (tb_pointer_t)luaL_checkstring(lua, 1); } else { xm_libc_return_error(lua, "libc.setbyte(invalid data)!"); } // get offset tb_int_t offset = 0; if (lua_isnumber(lua, 2)) { offset = (tb_int_t)lua_tointeger(lua, 2); } else { xm_libc_return_error(lua, "libc.setbyte(invalid offset)!"); } // set byte if (lua_isnumber(lua, 3)) { ((tb_byte_t *)data)[offset] = (tb_byte_t)lua_tointeger(lua, 3); } else { xm_libc_return_error(lua, "libc.setbyte(invalid value)!"); } return 0; } ================================================ FILE: core/src/xmake/libc/strndup.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file strndup.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "strndup" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_libc_strndup(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // do strndup tb_char_t const *s = tb_null; if (lua_isnumber(lua, 1)) { s = (tb_char_t const *)(tb_size_t)lua_tointeger(lua, 1); } else if (lua_isstring(lua, 2)) { s = lua_tostring(lua, 2); } else { xm_libc_return_error(lua, "libc.strndup(invalid args)!"); } tb_int_t n = (tb_int_t)lua_tointeger(lua, 2); if (s && n >= 0) { lua_pushlstring(lua, s, n); } else { lua_pushliteral(lua, ""); } return 1; } ================================================ FILE: core/src/xmake/lz4/block_compress.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file block_compress.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "block_compress" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_block_compress(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get data and size tb_int_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 1)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1); } if (xm_lua_isinteger(lua, 2)) { size = (tb_int_t)lua_tointeger(lua, 2); } if (!data || !size || size > LZ4_MAX_INPUT_SIZE) { lua_pushnil(lua); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // do compress tb_bool_t ok = tb_false; tb_byte_t *output_data = tb_null; tb_byte_t buffer[8192]; do { tb_int_t output_size = LZ4_compressBound(size); tb_assert_and_check_break(output_size); output_data = output_size <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(output_size); tb_assert_and_check_break(output_data); tb_int_t real = LZ4_compress_default((tb_char_t const *)data, (tb_char_t *)output_data, size, output_size); tb_assert_and_check_break(real > 0); lua_pushlstring(lua, (tb_char_t const *)output_data, real); ok = tb_true; } while (0); if (output_data && output_data != buffer) { tb_free(output_data); output_data = tb_null; } if (!ok) { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/lz4/block_decompress.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file block_decompress.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "block_decompress" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_block_decompress(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 1)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1); } if (xm_lua_isinteger(lua, 2)) { size = (tb_size_t)lua_tointeger(lua, 2); } if (!data || !size) { lua_pushnil(lua); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // get real size tb_int_t real = (tb_int_t)lua_tointeger(lua, 3); if (real <= 0) { lua_pushnil(lua); lua_pushfstring(lua, "invalid output size(%d)!", real); return 2; } // do decompress tb_bool_t ok = tb_false; tb_byte_t *output_data = tb_null; tb_byte_t buffer[8192]; do { output_data = real <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(real); tb_assert_and_check_break(output_data); tb_int_t r = LZ4_decompress_safe((tb_char_t const *)data, (tb_char_t *)output_data, (tb_int_t)size, real); tb_assert_and_check_break(r > 0); lua_pushlstring(lua, (tb_char_t const *)output_data, r); ok = tb_true; } while (0); if (output_data && output_data != buffer) { tb_free(output_data); output_data = tb_null; } if (!ok) { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/lz4/compress.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file compress.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "compress" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_compress(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 1)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1); } if (xm_lua_isinteger(lua, 2)) { size = (tb_size_t)lua_tointeger(lua, 2); } if (!data || !size) { lua_pushnil(lua); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // do compress tb_bool_t ok = tb_false; tb_char_t const *error = tb_null; tb_byte_t *output_data = tb_null; tb_byte_t buffer[8192]; do { tb_size_t output_size = LZ4F_compressFrameBound(size, tb_null); tb_assert_and_check_break(output_size); output_data = output_size <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(output_size); tb_assert_and_check_break(output_data); tb_size_t real_or_errs = LZ4F_compressFrame(output_data, output_size, data, size, tb_null); if (LZ4F_isError(real_or_errs)) { error = LZ4F_getErrorName(real_or_errs); break; } lua_pushlstring(lua, (tb_char_t const *)output_data, real_or_errs); ok = tb_true; } while (0); if (output_data && output_data != buffer) { tb_free(output_data); output_data = tb_null; } if (!ok) { lua_pushnil(lua); lua_pushstring(lua, error ? error : "unknown"); return 2; } return 1; } ================================================ FILE: core/src/xmake/lz4/compress_file.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file compress_file.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "compress_file" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_compress_file(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the file paths tb_char_t const *srcpath = luaL_checkstring(lua, 1); tb_char_t const *dstpath = luaL_checkstring(lua, 2); tb_check_return_val(srcpath && dstpath, 0); // init lz4 stream xm_lz4_cstream_t *stream_lz4 = xm_lz4_cstream_init(); tb_check_return_val(stream_lz4, 0); // do compress tb_bool_t ok = tb_false; tb_stream_ref_t istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO); tb_stream_ref_t ostream = tb_stream_init_from_file(dstpath, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); if (istream && ostream && tb_stream_open(istream) && tb_stream_open(ostream)) { tb_bool_t write_ok = tb_false; tb_byte_t idata[TB_STREAM_BLOCK_MAXN]; tb_byte_t odata[TB_STREAM_BLOCK_MAXN]; while (!tb_stream_beof(istream)) { write_ok = tb_false; tb_long_t ireal = (tb_long_t)tb_stream_read(istream, idata, sizeof(idata)); if (ireal > 0) { tb_long_t r = xm_lz4_cstream_write(stream_lz4, idata, ireal, tb_stream_beof(istream)); tb_assert_and_check_break(r >= 0); tb_check_continue(r > 0); tb_long_t oreal; while ((oreal = xm_lz4_cstream_read(stream_lz4, odata, sizeof(odata))) > 0) { if (!tb_stream_bwrit(ostream, odata, oreal)) { oreal = -1; break; } } tb_assert_and_check_break(oreal >= 0); } else { break; } write_ok = tb_true; } if (tb_stream_beof(istream) && write_ok) { ok = tb_true; } } // exit stream if (istream) { tb_stream_exit(istream); istream = tb_null; } if (ostream) { tb_stream_exit(ostream); ostream = tb_null; } xm_lz4_cstream_exit(stream_lz4); lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/lz4/compress_stream_close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file compress_stream_close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "compress_stream_close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_compress_stream_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the stream xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1); tb_check_return_val(stream, 0); // exit stream xm_lz4_cstream_exit(stream); // save result: ok lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/lz4/compress_stream_open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file compress_stream_open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "compress_stream_open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_compress_stream_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_lz4_cstream_t *stream = xm_lz4_cstream_init(); if (stream) { xm_lua_pushpointer(lua, (tb_pointer_t)stream); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/lz4/compress_stream_read.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file compress_stream_read.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "compress_stream_read" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_compress_stream_read(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check handle if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid handle!"); return 2; } // get stream xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1); tb_check_return_val(stream, 0); // get data tb_byte_t *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (!data) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p)!", data); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // get size tb_long_t size = 0; if (xm_lua_isinteger(lua, 3)) { size = (tb_long_t)lua_tointeger(lua, 3); } if (size <= 0) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size); return 2; } // read data tb_long_t real = xm_lz4_cstream_read(stream, data, size); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/lz4/compress_stream_write.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file compress_stream_write.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "compress_stream_write" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_compress_stream_write(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check handle if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid handle!"); return 2; } // get stream xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1); tb_check_return_val(stream, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (xm_lua_isinteger(lua, 3)) { size = (tb_size_t)lua_tointeger(lua, 3); } if (!data || !size) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // is end? tb_bool_t end = tb_false; if (lua_isboolean(lua, 4)) { end = lua_toboolean(lua, 4); } // write data tb_long_t real = xm_lz4_cstream_write(stream, data, size, end); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/lz4/decompress.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file decompress.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "decompress" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_decompress(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 1)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1); } if (xm_lua_isinteger(lua, 2)) { size = (tb_size_t)lua_tointeger(lua, 2); } if (!data || !size) { lua_pushnil(lua); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // do decompress tb_bool_t ok = tb_false; LZ4F_errorCode_t code; LZ4F_decompressionContext_t ctx = tb_null; tb_buffer_t result; do { tb_buffer_init(&result); code = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(code)) { break; } tb_byte_t buffer[8192]; tb_bool_t failed = tb_false; while (1) { size_t advance = (size_t)size; size_t buffer_size = sizeof(buffer); code = LZ4F_decompress(ctx, buffer, &buffer_size, data, &advance, tb_null); if (LZ4F_isError(code)) { failed = tb_true; break; } if (buffer_size == 0) { break; } data += advance; size -= advance; tb_buffer_memncat(&result, buffer, buffer_size); } tb_assert_and_check_break(!failed && tb_buffer_size(&result)); lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&result), tb_buffer_size(&result)); ok = tb_true; } while (0); if (ctx) { LZ4F_freeDecompressionContext(ctx); ctx = tb_null; } tb_buffer_exit(&result); if (!ok) { tb_char_t const *error = LZ4F_getErrorName(code); lua_pushnil(lua); lua_pushstring(lua, error ? error : "unknown"); return 2; } return 1; } ================================================ FILE: core/src/xmake/lz4/decompress_file.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file dedecompress_file.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "dedecompress_file" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_decompress_file(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the file paths tb_char_t const *srcpath = luaL_checkstring(lua, 1); tb_char_t const *dstpath = luaL_checkstring(lua, 2); tb_check_return_val(srcpath && dstpath, 0); // init lz4 stream xm_lz4_dstream_t *stream_lz4 = xm_lz4_dstream_init(); tb_check_return_val(stream_lz4, 0); // do decompress tb_bool_t ok = tb_false; tb_stream_ref_t istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO); tb_stream_ref_t ostream = tb_stream_init_from_file(dstpath, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); if (istream && ostream && tb_stream_open(istream) && tb_stream_open(ostream)) { tb_bool_t write_ok = tb_false; tb_byte_t idata[TB_STREAM_BLOCK_MAXN]; tb_byte_t odata[TB_STREAM_BLOCK_MAXN]; while (!tb_stream_beof(istream)) { write_ok = tb_false; tb_long_t ireal = (tb_long_t)tb_stream_read(istream, idata, sizeof(idata)); if (ireal > 0) { tb_long_t r = xm_lz4_dstream_write(stream_lz4, idata, ireal, tb_stream_beof(istream)); tb_assert_and_check_break(r >= 0); tb_check_continue(r > 0); tb_long_t oreal; while ((oreal = xm_lz4_dstream_read(stream_lz4, odata, sizeof(odata))) > 0) { if (!tb_stream_bwrit(ostream, odata, oreal)) { oreal = -1; break; } } tb_assert_and_check_break(oreal >= 0); } else { break; } write_ok = tb_true; } if (tb_stream_beof(istream) && write_ok) { ok = tb_true; } } // exit stream if (istream) { tb_stream_exit(istream); istream = tb_null; } if (ostream) { tb_stream_exit(ostream); ostream = tb_null; } xm_lz4_dstream_exit(stream_lz4); lua_pushboolean(lua, ok); return 1; } ================================================ FILE: core/src/xmake/lz4/decompress_stream_close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file decompress_stream_close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "decompress_stream_close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_decompress_stream_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the stream xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1); tb_check_return_val(stream, 0); // exit stream xm_lz4_dstream_exit(stream); // save result: ok lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/lz4/decompress_stream_open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file decompress_stream_open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "decompress_stream_open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_decompress_stream_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_lz4_dstream_t *stream = xm_lz4_dstream_init(); if (stream) { xm_lua_pushpointer(lua, (tb_pointer_t)stream); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/lz4/decompress_stream_read.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file decompress_stream_read.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "decompress_stream_read" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_decompress_stream_read(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check handle if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid handle!"); return 2; } // get stream xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1); tb_check_return_val(stream, 0); // get data tb_byte_t *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (!data) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p)!", data); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // get size tb_long_t size = 0; if (xm_lua_isinteger(lua, 3)) { size = (tb_long_t)lua_tointeger(lua, 3); } if (size <= 0) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size); return 2; } // read data tb_long_t real = xm_lz4_dstream_read(stream, data, size); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/lz4/decompress_stream_write.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file decompress_stream_write.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "decompress_stream_write" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_lz4_decompress_stream_write(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check handle if (!xm_lua_ispointer(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid handle!"); return 2; } // get stream xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1); tb_check_return_val(stream, 0); // get data and size tb_size_t size = 0; tb_byte_t const *data = tb_null; if (xm_lua_isinteger(lua, 2)) { data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2); } if (xm_lua_isinteger(lua, 3)) { size = (tb_size_t)lua_tointeger(lua, 3); } if (!data || !size) { lua_pushinteger(lua, -1); lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size); return 2; } tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t)); // write data tb_long_t real = xm_lz4_dstream_write(stream, data, size, tb_false); lua_pushinteger(lua, (tb_int_t)real); return 1; } ================================================ FILE: core/src/xmake/lz4/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except idata compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to idata writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_LZ4_PREFIX_H #define XM_LZ4_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #include "lz4frame.h" #include "lz4.h" #include "lz4hc.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // we need to define LZ4_byte if < 1.9.3 #if defined(LZ4_VERSION_NUMBER) && LZ4_VERSION_NUMBER < (1 * 100 * 100 + 9 * 100 + 3) #if defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) #include typedef int8_t LZ4_i8; typedef uint8_t LZ4_byte; typedef uint16_t LZ4_u16; typedef uint32_t LZ4_u32; #else typedef signed char LZ4_i8; typedef unsigned char LZ4_byte; typedef unsigned short LZ4_u16; typedef unsigned int LZ4_u32; #endif #endif /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the lz4 compress stream type typedef struct __xm_lz4_cstream_t { LZ4F_cctx *cctx; LZ4_byte *buffer; tb_size_t buffer_size; tb_size_t buffer_maxn; tb_size_t write_maxn; tb_size_t header_size; LZ4_byte header[LZ4F_HEADER_SIZE_MAX]; } xm_lz4_cstream_t; // the lz4 decompress stream type typedef struct __xm_lz4_dstream_t { LZ4F_dctx *dctx; LZ4_byte *buffer; tb_size_t buffer_size; tb_size_t buffer_maxn; tb_size_t header_size; LZ4_byte header[LZ4F_HEADER_SIZE_MAX]; } xm_lz4_dstream_t; /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ static __tb_inline__ tb_void_t xm_lz4_cstream_exit(xm_lz4_cstream_t *stream) { if (stream) { if (stream->cctx) { LZ4F_freeCompressionContext(stream->cctx); stream->cctx = tb_null; } if (stream->buffer) { tb_free(stream->buffer); stream->buffer = tb_null; } tb_free(stream); } } static __tb_inline__ xm_lz4_cstream_t *xm_lz4_cstream_init() { tb_size_t ret; tb_bool_t ok = tb_false; xm_lz4_cstream_t *stream = tb_null; LZ4F_preferences_t const *prefsPtr = tb_null; do { stream = tb_malloc0_type(xm_lz4_cstream_t); tb_assert_and_check_break(stream); stream->write_maxn = 64 * 1024; stream->buffer_maxn = LZ4F_compressBound(stream->write_maxn, prefsPtr); stream->buffer = (LZ4_byte *)tb_malloc(stream->buffer_maxn); tb_assert_and_check_break(stream->buffer); ret = LZ4F_createCompressionContext(&stream->cctx, LZ4F_getVersion()); if (LZ4F_isError(ret)) break; ret = LZ4F_compressBegin(stream->cctx, stream->header, LZ4F_HEADER_SIZE_MAX, prefsPtr); if (LZ4F_isError(ret)) break; stream->header_size = ret; ok = tb_true; } while (0); if (!ok && stream) { xm_lz4_cstream_exit(stream); stream = tb_null; } return stream; } static __tb_inline__ tb_long_t xm_lz4_cstream_write(xm_lz4_cstream_t *stream, tb_byte_t const *idata, tb_size_t isize, tb_bool_t end) { tb_assert_and_check_return_val(stream && stream->cctx && idata && isize, -1); tb_assert_and_check_return_val(isize <= stream->write_maxn, -1); tb_assert_and_check_return_val(stream->buffer_size + isize < stream->buffer_maxn, -1); tb_size_t real = LZ4F_compressUpdate(stream->cctx, stream->buffer + stream->buffer_size, stream->buffer_maxn - stream->buffer_size, idata, isize, tb_null); if (LZ4F_isError(real)) return -1; stream->buffer_size += real; if (end) { tb_size_t ret = LZ4F_compressEnd(stream->cctx, stream->buffer + stream->buffer_size, stream->buffer_maxn - stream->buffer_size, tb_null); if (LZ4F_isError(ret)) return -1; real += ret; stream->buffer_size += ret; } return isize; } static __tb_inline__ tb_long_t xm_lz4_cstream_read(xm_lz4_cstream_t *stream, tb_byte_t *odata, tb_size_t osize) { tb_assert_and_check_return_val(stream && stream->cctx && odata && osize, -1); tb_assert_and_check_return_val(osize >= stream->header_size, -1); tb_size_t read = 0; if (stream->header_size) { tb_memcpy(odata, stream->header, stream->header_size); read += stream->header_size; osize -= stream->header_size; stream->header_size = 0; } tb_size_t need = tb_min(stream->buffer_size, osize); tb_memcpy(odata + read, stream->buffer, need); if (need < stream->buffer_size) tb_memmov(stream->buffer, stream->buffer + need, stream->buffer_size - need); stream->buffer_size -= need; read += need; return read; } static __tb_inline__ tb_void_t xm_lz4_dstream_exit(xm_lz4_dstream_t *stream) { if (stream) { if (stream->dctx) { LZ4F_freeDecompressionContext(stream->dctx); stream->dctx = tb_null; } if (stream->buffer) { tb_free(stream->buffer); stream->buffer = tb_null; } tb_free(stream); } } static __tb_inline__ xm_lz4_dstream_t *xm_lz4_dstream_init() { LZ4F_errorCode_t ret; tb_bool_t ok = tb_false; xm_lz4_dstream_t *stream = tb_null; do { stream = tb_malloc0_type(xm_lz4_dstream_t); tb_assert_and_check_break(stream); ret = LZ4F_createDecompressionContext(&stream->dctx, LZ4F_getVersion()); if (LZ4F_isError(ret)) break; ok = tb_true; } while (0); if (!ok && stream) { xm_lz4_dstream_exit(stream); stream = tb_null; } return stream; } static __tb_inline__ tb_long_t xm_lz4_dstream_write(xm_lz4_dstream_t *stream, tb_byte_t const *idata, tb_size_t isize, tb_bool_t end) { tb_assert_and_check_return_val(stream && stream->dctx && idata && isize, -1); // read header first const tb_size_t header_size = sizeof(stream->header); if (stream->header_size < header_size) { tb_size_t size = tb_min(header_size - stream->header_size, isize); tb_memcpy(stream->header + stream->header_size, idata, size); stream->header_size += size; idata += size; isize -= size; // get frame info if header is ok if (stream->header_size == header_size) { LZ4F_frameInfo_t info; size_t consumed_size = header_size; LZ4F_errorCode_t ret = LZ4F_getFrameInfo(stream->dctx, &info, stream->header, &consumed_size); if (LZ4F_isError(ret)) return -1; switch (info.blockSizeID) { case LZ4F_default: case LZ4F_max64KB: stream->buffer_maxn = 64 * 1024; break; case LZ4F_max256KB: stream->buffer_maxn = 256 * 1024; break; case LZ4F_max1MB: stream->buffer_maxn = 1 * 1024 * 1024; break; case LZ4F_max4MB: stream->buffer_maxn = 4 * 1024 * 1024; break; default: return -1; } stream->buffer = (LZ4_byte *)tb_malloc(stream->buffer_maxn); tb_assert_and_check_return_val(stream->buffer, -1); stream->buffer_size = header_size - consumed_size; tb_memcpy(stream->buffer, stream->header + consumed_size, stream->buffer_size); } } tb_check_return_val(stream->header_size == header_size && isize, 0); tb_assert_and_check_return_val(stream->buffer && stream->buffer_size + isize <= stream->buffer_maxn, -1); // append the input data tb_memcpy(stream->buffer + stream->buffer_size, idata, isize); stream->buffer_size += isize; return isize; } static __tb_inline__ tb_long_t xm_lz4_dstream_read(xm_lz4_dstream_t *stream, tb_byte_t *odata, tb_size_t osize) { tb_assert_and_check_return_val(stream && stream->dctx && stream->buffer && odata && osize, -1); tb_check_return_val(stream->buffer_size, 0); // do decompress size_t srcsize = stream->buffer_size; size_t dstsize = osize; tb_size_t ret = LZ4F_decompress(stream->dctx, odata, &dstsize, stream->buffer, &srcsize, tb_null); if (LZ4F_isError(ret)) return -1; // move the left input data if (srcsize < stream->buffer_size) tb_memmov(stream->buffer, stream->buffer + srcsize, stream->buffer_size - srcsize); stream->buffer_size -= srcsize; return dstsize; } #endif ================================================ FILE: core/src/xmake/os/access.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file access.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "access" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_access(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const* path = luaL_checkstring(lua, 1); tb_char_t const* mode_str = luaL_checkstring(lua, 2); tb_check_return_val(path && mode_str, 0); // parse mode tb_size_t mode = 0; while (*mode_str) { switch (*mode_str) { case 'r': mode |= TB_FILE_MODE_RO; break; case 'w': mode |= TB_FILE_MODE_WO; break; case 'x': mode |= TB_FILE_MODE_EXEC; break; default: break; } mode_str++; } // os.access(path, mode) lua_pushboolean(lua, tb_file_access(path, mode)); return 1; } ================================================ FILE: core/src/xmake/os/args.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file args.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "os.args" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t tb_os_args_append( tb_string_ref_t result, tb_char_t const *cstr, tb_size_t size, tb_bool_t escape, tb_bool_t nowrap) { tb_assert_and_check_return(size < TB_PATH_MAXN); // need wrap quote? tb_char_t ch; tb_char_t const *p = cstr; tb_bool_t wrap_quote = tb_false; if (!nowrap) { while ((ch = *p)) { if (ch == ' ') { wrap_quote = tb_true; } p++; } } // wrap begin quote if (wrap_quote) { tb_string_chrcat(result, '\"'); } // escape characters p = cstr; while ((ch = *p)) { // escape '"' or '\\' if (ch == '\"' || ((escape || wrap_quote) && ch == '\\')) { tb_string_chrcat(result, '\\'); } tb_string_chrcat(result, ch); p++; } // wrap end quote if (wrap_quote) { tb_string_chrcat(result, '\"'); } } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // os.args({"xx", "yy"}, {escape = true}) tb_int_t xm_os_args(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // escape '\\' characters in global? tb_bool_t escape = tb_false; if (lua_istable(lua, 2)) { // is escape? lua_pushstring(lua, "escape"); lua_gettable(lua, 2); escape = lua_toboolean(lua, -1); lua_pop(lua, 1); } // disable to wrap quote characters in global? tb_bool_t nowrap = tb_false; if (lua_istable(lua, 2)) { // is nowrap? lua_pushstring(lua, "nowrap"); lua_gettable(lua, 2); nowrap = lua_toboolean(lua, -1); lua_pop(lua, 1); } // init result tb_string_t result; tb_string_init(&result); // make string from arguments list if (lua_istable(lua, 1)) { tb_size_t i = 0; tb_size_t n = (tb_size_t)lua_objlen(lua, 1); for (i = 1; i <= n; i++) { // add space if (i != 1) { tb_string_chrcat(&result, ' '); } // add argument lua_pushnumber(lua, (tb_int_t)i); lua_rawget(lua, 1); if (lua_istable(lua, -1)) { // is path instance? lua_pushstring(lua, "_STR"); lua_gettable(lua, -2); size_t size = 0; tb_char_t const *cstr = luaL_checklstring(lua, -1, &size); if (cstr && size) { tb_os_args_append(&result, cstr, size, escape, nowrap); } lua_pop(lua, 1); } else { size_t size = 0; tb_char_t const *cstr = luaL_checklstring(lua, -1, &size); if (cstr && size) { tb_os_args_append(&result, cstr, size, escape, nowrap); } } lua_pop(lua, 1); } } else { size_t size = 0; tb_char_t const *cstr = luaL_checklstring(lua, 1, &size); if (cstr && size) { tb_os_args_append(&result, cstr, size, escape, nowrap); } } // return result tb_size_t size = tb_string_size(&result); if (size) { lua_pushlstring(lua, tb_string_cstr(&result), size); } else { lua_pushliteral(lua, ""); } tb_string_exit(&result); return 1; } ================================================ FILE: core/src/xmake/os/argv.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file argv.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "os.argv" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_argv(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the argument string tb_char_t const *args = luaL_checkstring(lua, 1); tb_check_return_val(args, 0); // split only? do not escape tb_bool_t splitonly = tb_false; if (lua_istable(lua, 2)) { lua_pushstring(lua, "splitonly"); lua_gettable(lua, 2); splitonly = lua_toboolean(lua, -1); lua_pop(lua, 1); } // parse argument list tb_string_t arg; do { // init table lua_newtable(lua); // init arg if (!tb_string_init(&arg)) { break; } // parse command to the arguments tb_int_t i = 1; tb_int_t skip = 0; tb_int_t escape = 0; tb_char_t quote = 0; tb_char_t ch = 0; tb_char_t const *p = args; while ((ch = *p)) { // no escape now? if (!escape) { // enter quote? if (!quote && (ch == '\"' || ch == '\'')) { quote = ch; skip = 1; } else if (ch == quote) { // leave quote? quote = 0; skip = 1; } else if (ch == '\\' && (p[1] == '\\' || p[1] == '\"')) { // escape character? only escape \\ and \" escape = 1; skip = 1; } else if (!quote && tb_isspace(ch)) { // is argument end with ' '? // save this argument tb_string_ltrim(&arg); if (tb_string_size(&arg)) { // save argument lua_pushstring(lua, tb_string_cstr(&arg)); lua_rawseti(lua, -2, i++); } // clear argument tb_string_clear(&arg); } } // save this charactor to argument if (splitonly || !skip) { tb_string_chrcat(&arg, ch); } // step and cancel escape if (escape == 1) { escape++; } else if (escape == 2) { escape = 0; } // clear skip skip = 0; // next p++; } // save this argument tb_string_ltrim(&arg); if (tb_string_size(&arg)) { // save argument lua_pushstring(lua, tb_string_cstr(&arg)); lua_rawseti(lua, -2, i++); } } while (0); // exit arg tb_string_exit(&arg); return 1; } ================================================ FILE: core/src/xmake/os/chdir.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file chdir.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "chdir" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_chdir(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // done os.chdir(path) lua_pushboolean(lua, tb_directory_current_set(path)); return 1; } ================================================ FILE: core/src/xmake/os/cpdir.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file cpdir.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "cpdir" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_cpdir(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the source and destination tb_char_t const *src = luaL_checkstring(lua, 1); tb_char_t const *dst = luaL_checkstring(lua, 2); tb_check_return_val(src && dst, 0); // init copy flags tb_size_t flags = TB_FILE_COPY_NONE; tb_bool_t is_symlink = lua_toboolean(lua, 3); if (is_symlink) { flags |= TB_FILE_COPY_LINK; } tb_bool_t copy_if_different = lua_toboolean(lua, 4); if (copy_if_different) { flags |= TB_FILE_COPY_IF_DIFFERENT; } // do copy lua_pushboolean(lua, tb_directory_copy(src, dst, flags)); return 1; } ================================================ FILE: core/src/xmake/os/cpfile.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file cpfile.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "cpfile" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_cpfile(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the source and destination tb_char_t const *src = luaL_checkstring(lua, 1); tb_char_t const *dst = luaL_checkstring(lua, 2); tb_check_return_val(src && dst, 0); // init copy flags tb_size_t flags = TB_FILE_COPY_NONE; tb_bool_t is_symlink = lua_toboolean(lua, 3); if (is_symlink) { flags |= TB_FILE_COPY_LINK; } tb_bool_t is_writeable = lua_toboolean(lua, 4); if (is_writeable) { flags |= TB_FILE_COPY_WRITEABLE; } tb_bool_t copy_if_different = lua_toboolean(lua, 5); if (copy_if_different) { flags |= TB_FILE_COPY_IF_DIFFERENT; } // do copy lua_pushboolean(lua, tb_file_copy(src, dst, flags)); return 1; } ================================================ FILE: core/src/xmake/os/cpuinfo.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file cpuinfo.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "cpuinfo" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #if defined(TB_CONFIG_OS_MACOSX) #include #include #include #include #include #elif defined(TB_CONFIG_OS_WINDOWS) #include #elif defined(TB_CONFIG_OS_LINUX) #include #elif defined(TB_CONFIG_OS_BSD) #include #include #include #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ #if defined(TB_CONFIG_OS_WINDOWS) static tb_uint64_t xm_os_cpuinfo_subtract_times(FILETIME const *one, FILETIME const *two) { LARGE_INTEGER a, b; a.LowPart = one->dwLowDateTime; a.HighPart = one->dwHighDateTime; b.LowPart = two->dwLowDateTime; b.HighPart = two->dwHighDateTime; return (tb_uint64_t)(a.QuadPart - b.QuadPart); } #endif static tb_float_t xm_os_cpuinfo_usagerate() { #if defined(TB_CONFIG_OS_MACOSX) tb_float_t usagerate = 0; natural_t cpu_count = 0; processor_info_array_t cpuinfo; mach_msg_type_number_t cpuinfo_count; static tb_hong_t s_time = 0; if (tb_mclock() - s_time > 1000 && host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, &cpuinfo, &cpuinfo_count) == KERN_SUCCESS) { static processor_info_array_t s_cpuinfo_prev = tb_null; static mach_msg_type_number_t s_cpuinfo_count_prev = 0; for (tb_int_t i = 0; i < cpu_count; ++i) { tb_int_t use, total; if (s_cpuinfo_prev) { use = (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] - s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_USER]) + (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] - s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM]) + (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE] - s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_NICE]); total = use + (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE] - s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]); } else { use = cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] + cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] + cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE]; total = use + cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]; } usagerate += total > 0 ? ((tb_float_t)use / (tb_float_t)total) : 0; } if (s_cpuinfo_prev) { vm_deallocate(mach_task_self(), (vm_address_t)s_cpuinfo_prev, sizeof(integer_t) * s_cpuinfo_count_prev); } s_time = tb_mclock(); s_cpuinfo_prev = cpuinfo; s_cpuinfo_count_prev = cpuinfo_count; } return cpu_count > 0 ? usagerate / cpu_count : 0; #elif defined(TB_CONFIG_OS_WINDOWS) // kernel include idle_time tb_float_t usagerate = 0; FILETIME idle, kernel, user; if (GetSystemTimes(&idle, &kernel, &user)) { static FILETIME idle_prev = { 0 }; static FILETIME kernel_prev = { 0 }; static FILETIME user_prev = { 0 }; if (idle_prev.dwLowDateTime != 0 && idle_prev.dwHighDateTime != 0) { tb_uint64_t idle_diff = xm_os_cpuinfo_subtract_times(&idle, &idle_prev); tb_uint64_t kernel_diff = xm_os_cpuinfo_subtract_times(&kernel, &kernel_prev); tb_uint64_t user_diff = xm_os_cpuinfo_subtract_times(&user, &user_prev); // kernel_time - idle_time = kernel_time, because kernel include idle_time tb_uint64_t sys_total = kernel_diff + user_diff; tb_uint64_t kernel_total = kernel_diff - idle_diff; // sometimes kernel_time > idle_time if (sys_total > 0) { usagerate = (tb_float_t)((tb_double_t)(kernel_total + user_diff) / sys_total); } } idle_prev = idle; kernel_prev = kernel; user_prev = user; } return usagerate; #elif defined(TB_CONFIG_OS_LINUX) tb_float_t usagerate = 0; if (tb_file_info("/proc/stat", tb_null)) { FILE *fp = fopen("/proc/stat", "r"); if (fp) { tb_char_t line[8192]; static tb_int64_t total_prev = 0; static tb_int64_t active_prev = 0; while (!feof(fp)) { /* cpu 548760 0 867417 102226682 12430 0 9089 0 0 0 * cpu0 136863 0 218110 25632388 2706 0 2328 0 0 0 * cpu1 148383 0 213941 25627686 3925 0 2129 0 0 0 * * The meanings of the columns are as follows, from left to right: * * user: normal processes executing in user mode * nice: niced processes executing in user mode * system: processes executing in kernel mode * idle: twiddling thumbs * iowait: waiting for I/O to complete * irq: servicing interrupts * softirq: servicing softirqs * steal * guest * guest_nice */ if (fgets(line, sizeof(line), fp) && !tb_strncmp(line, "cpu ", 4)) { long long user, nice, sys, idle, iowait, irq, softirq, steal, guest, guest_nice; if (10 == sscanf(line, "cpu %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld", &user, &nice, &sys, &idle, &iowait, &irq, &softirq, &steal, &guest, &guest_nice)) { tb_int64_t active = (tb_int64_t)(user + nice + sys + irq + softirq + steal + guest + guest_nice); tb_int64_t total = (tb_int64_t)(user + nice + sys + idle + iowait + irq + softirq + steal + guest + guest_nice); if (total_prev > 0 && active_prev > 0) { tb_int64_t total_diff = total - total_prev; tb_int64_t active_diff = active - active_prev; if (total_diff > 0) { usagerate = (tb_float_t)((tb_double_t)active_diff / total_diff); } } total_prev = total; active_prev = active; } break; } } fclose(fp); } } return usagerate; #elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__) #define CP_USER 0 #define CP_NICE 1 #define CP_SYS 2 #define CP_INTR 3 #define CP_IDLE 4 #define CPUSTATES 5 static tb_int64_t total_prev = 0; static tb_int64_t active_prev = 0; tb_float_t usagerate = 0; long states[CPUSTATES] = { 0 }; size_t states_size = sizeof(states); if (sysctlbyname("kern.cp_time", &states, &states_size, tb_null, 0) == 0) { tb_long_t user = states[CP_USER]; tb_long_t nice = states[CP_NICE]; tb_long_t sys = states[CP_SYS]; tb_long_t intr = states[CP_INTR]; tb_long_t idle = states[CP_IDLE]; tb_int64_t active = user + nice + sys + intr; tb_int64_t total = user + nice + sys + idle + intr; if (total_prev > 0 && active_prev > 0) { tb_int64_t total_diff = total - total_prev; tb_int64_t active_diff = active - active_prev; if (total_diff > 0) { usagerate = (tb_float_t)((tb_double_t)active_diff / total_diff); } } total_prev = total; active_prev = active; } return usagerate; #else return 0; #endif } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* local cpuinfo = os.cpuinfo() * { * ncpu = 4, * ... * } */ tb_int_t xm_os_cpuinfo(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // init table lua_newtable(lua); // get cpu number tb_int_t ncpu = (tb_int_t)tb_cpu_count(); lua_pushstring(lua, "ncpu"); lua_pushinteger(lua, ncpu > 0 ? ncpu : 1); lua_settable(lua, -3); // get cpu usage rate tb_float_t usagerate = xm_os_cpuinfo_usagerate(); if (usagerate >= 0) { lua_pushstring(lua, "usagerate"); lua_pushnumber(lua, usagerate); lua_settable(lua, -3); } return 1; } ================================================ FILE: core/src/xmake/os/curdir.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file curdir.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "curdir" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_curdir(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // os.curdir() tb_char_t path[TB_PATH_MAXN]; if (tb_directory_current(path, sizeof(path))) { lua_pushstring(lua, path); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/os/emptydir.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file emptydir.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "emptydir" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_long_t xm_os_emptydir_walk(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) { tb_bool_t *is_emptydir = (tb_bool_t *)priv; tb_assert_and_check_return_val(path && info && is_emptydir, TB_DIRECTORY_WALK_CODE_END); // is emptydir? if (info->type == TB_FILE_TYPE_FILE || info->type == TB_FILE_TYPE_DIRECTORY) { *is_emptydir = tb_false; return tb_false; } return TB_DIRECTORY_WALK_CODE_CONTINUE; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_emptydir(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the directory tb_char_t const *dir = luaL_checkstring(lua, 1); tb_check_return_val(dir, 0); // os.emptydir(dir) tb_bool_t is_emptydir = tb_true; tb_directory_walk(dir, tb_true, tb_true, xm_os_emptydir_walk, &is_emptydir); // is emptydir? lua_pushboolean(lua, is_emptydir); return 1; } ================================================ FILE: core/src/xmake/os/exists.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file exists.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "exists" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_exists(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // os.exists(path) lua_pushboolean(lua, tb_file_info(path, tb_null)); return 1; } ================================================ FILE: core/src/xmake/os/filesize.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file filesize.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "filesize" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_filesize(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // os.filesize(path) tb_file_info_t info = { 0 }; if (tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_FILE)) { lua_pushinteger(lua, (lua_Integer)info.size); } else { lua_pushinteger(lua, 0); } return 1; } ================================================ FILE: core/src/xmake/os/find.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file find.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "find" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_long_t xm_os_find_walk(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) { tb_value_ref_t tuple = (tb_value_ref_t)priv; tb_assert_and_check_return_val(path && info && tuple, TB_DIRECTORY_WALK_CODE_END); // the lua lua_State *lua = (lua_State *)tuple[0].ptr; tb_assert_and_check_return_val(lua, TB_DIRECTORY_WALK_CODE_END); // the pattern tb_char_t const *pattern = (tb_char_t const *)tuple[1].cstr; tb_assert_and_check_return_val(pattern, TB_DIRECTORY_WALK_CODE_END); // remove ./ for path if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) { path = path + 2; } // the match mode tb_long_t mode = tuple[2].l; // the count tb_size_t *pcount = &(tuple[3].ul); tb_trace_d("path[%c]: %s", info->type == TB_FILE_TYPE_DIRECTORY ? 'd' : 'f', path); // we can ignore it directly if this path is file, but we need directory tb_size_t needtype = (mode == 1) ? TB_FILE_TYPE_DIRECTORY : ((mode == 0) ? TB_FILE_TYPE_FILE : (TB_FILE_TYPE_FILE | TB_FILE_TYPE_DIRECTORY)); if (info->type == TB_FILE_TYPE_FILE && needtype == TB_FILE_TYPE_DIRECTORY) { return TB_DIRECTORY_WALK_CODE_CONTINUE; } // do path:match(pattern) lua_getfield(lua, -1, "match"); lua_pushstring(lua, path); lua_pushstring(lua, pattern); if (lua_pcall(lua, 2, 1, 0)) { tb_printf("error: call string.match(%s, %s) failed: %s!\n", path, pattern, lua_tostring(lua, -1)); return TB_DIRECTORY_WALK_CODE_END; } // match ok? tb_bool_t matched = tb_false; tb_bool_t skip_recursion = tb_false; if (lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1))) { // exists excludes? tb_bool_t excluded = tb_false; if (lua_istable(lua, 5)) { // the root directory size_t rootlen = 0; tb_char_t const *rootdir = luaL_checklstring(lua, 1, &rootlen); tb_assert_and_check_return_val(rootdir && rootlen, TB_DIRECTORY_WALK_CODE_END); tb_assert(!tb_strncmp(path, rootdir, rootlen)); tb_assert(rootlen + 1 <= tb_strlen(path)); // skip the rootdir if not "." if (tb_strcmp(rootdir, ".")) { path += rootlen + 1; } // exclude paths tb_int_t i = 0; tb_int_t count = (tb_int_t)lua_objlen(lua, 5); for (i = 0; i < count && !excluded; i++) { // get exclude lua_rawgeti(lua, 5, i + 1); tb_char_t const *exclude = lua_tostring(lua, -1); if (exclude) { // do path:match(exclude) lua_getfield(lua, -3, "match"); lua_pushstring(lua, path); lua_pushstring(lua, exclude); if (lua_pcall(lua, 2, 1, 0)) { tb_printf("error: call string.match(%s, %s) failed: %s!\n", path, exclude, lua_tostring(lua, -1)); } // matched? excluded = lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1)); // pop the match result lua_pop(lua, 1); } // pop exclude lua_pop(lua, 1); } } // does not exclude this path? if (!excluded) { // match file or directory? if (info->type & needtype) { // save it lua_rawseti(lua, -3, (tb_int_t)(++*pcount)); // do callback function if (lua_isfunction(lua, 6)) { // do callback(path, isdir) lua_pushvalue(lua, 6); lua_pushstring(lua, path); lua_pushboolean(lua, info->type == TB_FILE_TYPE_DIRECTORY); lua_call(lua, 2, 1); // is continue? tb_bool_t is_continue = lua_toboolean(lua, -1); lua_pop(lua, 1); if (!is_continue) { return TB_DIRECTORY_WALK_CODE_END; } } matched = tb_true; } } // we do not recurse sub-directories if this path has been excluded and it's directory else { skip_recursion = tb_true; } } if (!matched) { lua_pop(lua, 1); } return skip_recursion ? TB_DIRECTORY_WALK_CODE_SKIP_RECURSION : TB_DIRECTORY_WALK_CODE_CONTINUE; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_find(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the root directory tb_char_t const *rootdir = luaL_checkstring(lua, 1); tb_check_return_val(rootdir, 0); // get the pattern tb_char_t const *pattern = luaL_checkstring(lua, 2); tb_check_return_val(pattern, 0); // the recursion level tb_long_t recursion = (tb_long_t)lua_tointeger(lua, 3); // the match mode tb_long_t mode = (tb_long_t)lua_tointeger(lua, 4); // init table lua_newtable(lua); // get string package lua_getglobal(lua, "string"); // do os.find(root, name) tb_value_t tuple[4]; tuple[0].ptr = lua; tuple[1].cstr = pattern; tuple[2].l = mode; tuple[3].ul = 0; tb_directory_walk(rootdir, recursion, tb_true, xm_os_find_walk, tuple); // pop string package lua_pop(lua, 1); // return count lua_pushinteger(lua, tuple[3].ul); return 2; } ================================================ FILE: core/src/xmake/os/fscase.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file fscase.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "fscase" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_fscase(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); #if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 174 tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); lua_pushinteger(lua, (tb_int_t)tb_file_fscase(path)); #else lua_pushinteger(lua, -1); #endif return 1; } ================================================ FILE: core/src/xmake/os/getenv.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file getenv.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "getenv" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // the separator #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #define XM_OS_ENV_SEP ';' #else #define XM_OS_ENV_SEP ':' #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_getenv(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the name tb_char_t const *name = luaL_checkstring(lua, 1); tb_check_return_val(name, 0); // init values tb_string_t values; if (!tb_string_init(&values)) { return 0; } // init environment tb_environment_ref_t environment = tb_environment_init(); if (environment) { // load variable if (tb_environment_load(environment, name)) { // make values tb_bool_t is_first = tb_true; tb_for_all_if(tb_char_t const *, value, environment, value) { // append separator if (!is_first) { tb_string_chrcat(&values, XM_OS_ENV_SEP); } else { is_first = tb_false; } // append value tb_string_cstrcat(&values, value); } } // exit environment tb_environment_exit(environment); } // save result if (tb_string_size(&values)) { lua_pushstring(lua, tb_string_cstr(&values)); } else { lua_pushnil(lua); } // exit values tb_string_exit(&values); return 1; } ================================================ FILE: core/src/xmake/os/getenvs.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file getenvs.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "getenvs" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // the separator #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #define XM_OS_ENV_SEP ';' #else #define XM_OS_ENV_SEP ':' #endif /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ // the user environment #if !defined(TB_CONFIG_OS_WINDOWS) || defined(TB_COMPILER_LIKE_UNIX) extern tb_char_t **environ; #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t xm_os_getenvs_trim(tb_char_t const **sstr, tb_char_t const **estr) { tb_assert(sstr && estr && *sstr && *estr); tb_char_t const *p = *sstr; tb_char_t const *e = *estr; // trim left while (p < e && tb_isspace(*p)) { p++; } // trim right while (e > p && tb_isspace(*(e - 1))) { e--; } // save trimmed string *sstr = p; *estr = e; } static tb_void_t xm_os_getenvs_process_line(lua_State *lua, tb_char_t const *line) { tb_assert_and_check_return(lua && line); tb_size_t n = tb_strlen(line); tb_check_return(n > 0); // find '=' separator tb_char_t const *p = tb_strchr(line, '='); tb_check_return(p); // get key and value parts tb_char_t const *key_start = line; tb_char_t const *key_end = p; tb_char_t const *value_start = p + 1; tb_char_t const *value_end = line + n; // trim key xm_os_getenvs_trim(&key_start, &key_end); if (key_start >= key_end) { return; } // trim value xm_os_getenvs_trim(&value_start, &value_end); // get key and value lengths tb_size_t key_len = key_end - key_start; tb_size_t value_len = value_end > value_start ? value_end - value_start : 0; // handle Windows-specific PATH conversion tb_char_t const *final_key_start = key_start; tb_size_t final_key_len = key_len; #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) if (key_len == 4 && tb_strnicmp(key_start, "path", 4) == 0) { // use "PATH" instead of "path" static tb_char_t const PATH_UPPER[] = "PATH"; final_key_start = PATH_UPPER; final_key_len = 4; } #endif // set key-value pair in Lua table using pushlstring to avoid length limits lua_pushlstring(lua, final_key_start, final_key_len); lua_pushlstring(lua, value_start, value_len); lua_rawset(lua, -3); } tb_int_t xm_os_getenvs(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // init table lua_newtable(lua); #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) tb_wchar_t const *p = (tb_wchar_t const *)GetEnvironmentStringsW(); if (p) { tb_char_t *data = tb_null; tb_size_t maxn = 0; tb_char_t line[TB_PATH_MAXN]; tb_size_t n = 0; while (*p) { n = tb_wcslen(p); if (n + 1 < tb_arrayn(line)) { if (tb_wtoa(line, p, tb_arrayn(line)) >= 0) { xm_os_getenvs_process_line(lua, line); } } else { if (!data) { maxn = n + 1; data = (tb_char_t *)tb_malloc(maxn); } else if (n >= maxn) { maxn = n + TB_PATH_MAXN + 1; data = (tb_char_t *)tb_ralloc(data, maxn); } tb_assert_and_check_break(data); if (tb_wtoa(data, p, maxn) >= 0) { xm_os_getenvs_process_line(lua, data); } } p += n + 1; } if (data && data != line) { tb_free(data); } data = tb_null; } #else tb_char_t const **p = (tb_char_t const **)environ; if (p) { while (*p) { xm_os_getenvs_process_line(lua, *p); p++; } } #endif return 1; } ================================================ FILE: core/src/xmake/os/getown.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file getown.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "getown" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifndef TB_CONFIG_OS_WINDOWS #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ #ifndef TB_CONFIG_OS_WINDOWS // get owner by a given path tb_int_t xm_os_getown(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the pathname tb_char_t const *pathname = luaL_checkstring(lua, 1); tb_check_return_val(pathname, 0); // get stat struct stat sts; if (stat(pathname, &sts) != 0) { return 0; } // push lua_newtable(lua); lua_pushstring(lua, "uid"); lua_pushinteger(lua, sts.st_uid); lua_settable(lua, -3); lua_pushstring(lua, "gid"); lua_pushinteger(lua, sts.st_gid); lua_settable(lua, -3); return 1; } #endif ================================================ FILE: core/src/xmake/os/getpid.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file getpid.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "getpid" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifdef TB_CONFIG_OS_WINDOWS #include #else #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_getpid(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); #ifdef TB_CONFIG_OS_WINDOWS lua_pushinteger(lua, (tb_int_t)GetCurrentProcessId()); #else lua_pushinteger(lua, (tb_int_t)getpid()); #endif return 1; } ================================================ FILE: core/src/xmake/os/getwinsize.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file getwinsize.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "getwinsize" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #include #else #include #include // for errno #include // for STDOUT_FILENO #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // get console window size tb_int_t xm_os_getwinsize(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // init default window size (we will not consider winsize limit if cannot get it) tb_int_t w = TB_MAXS16, h = TB_MAXS16; // get winsize #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { w = (tb_int_t)csbi.dwSize.X; h = (tb_int_t)csbi.dwSize.Y; } #elif defined(TB_CONFIG_OS_SOLARIS) // Solaris doesn't support winsize/TIOCGWINSZ, use default values #else struct winsize size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) == 0) { w = (tb_int_t)size.ws_col; h = (tb_int_t)size.ws_row; } #endif /* local winsize = os.getwinsize() * * return * { * width = -1 or .. * , height = -1 or .. * } */ lua_newtable(lua); lua_pushstring(lua, "width"); lua_pushinteger(lua, w); lua_settable(lua, -3); lua_pushstring(lua, "height"); lua_pushinteger(lua, h); lua_settable(lua, -3); return 1; } ================================================ FILE: core/src/xmake/os/gid.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file gid.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "gid" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifndef TB_CONFIG_OS_WINDOWS #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ #ifndef TB_CONFIG_OS_WINDOWS // get & set gid tb_int_t xm_os_gid(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_int_t rgidset = -1; tb_int_t egidset = -1; tb_int_t argc = lua_gettop(lua); if (argc == 1) { if (lua_istable(lua, 1)) { // os.gid({["rgid"] = rgid, ["egid"] = egid}) lua_getfield(lua, 1, "rgid"); lua_getfield(lua, 1, "egid"); if (!lua_isnil(lua, -1)) { if (!lua_isnumber(lua, -1)) { lua_pushfstring(lua, "invalid field type(%s) in `egid` for os.gid", luaL_typename(lua, -1)); lua_error(lua); return 0; } egidset = (tb_int_t)lua_tonumber(lua, -1); } lua_pop(lua, 1); if (!lua_isnil(lua, -1)) { if (!lua_isnumber(lua, -1)) { lua_pushfstring(lua, "invalid field type(%s) in `rgid` for os.gid", luaL_typename(lua, -1)); lua_error(lua); return 0; } rgidset = (tb_int_t)lua_tonumber(lua, -1); } lua_pop(lua, 1); } else if (lua_isnumber(lua, 1)) { // os.gid(gid) rgidset = egidset = (tb_int_t)lua_tonumber(lua, 1); } else { lua_pushfstring(lua, "invalid argument type(%s) for os.gid", luaL_typename(lua, 1)); lua_error(lua); return 0; } } else if (argc == 2) { // os.gid(rgid, egid) if (!lua_isnil(lua, 1)) { if (!lua_isnumber(lua, 1)) { lua_pushfstring(lua, "invalid argument type(%s) for os.gid", luaL_typename(lua, 1)); lua_error(lua); return 0; } rgidset = (tb_int_t)lua_tonumber(lua, 1); } if (!lua_isnil(lua, 2)) { if (!lua_isnumber(lua, 2)) { lua_pushfstring(lua, "invalid argument type(%s) for os.gid", luaL_typename(lua, 2)); lua_error(lua); return 0; } egidset = (tb_int_t)lua_tonumber(lua, 2); } } else if (argc != 0) { lua_pushstring(lua, "invalid argument count for os.gid"); lua_error(lua); return 0; } // store return value lua_newtable(lua); if (rgidset != -1 || egidset != -1) { // set rgid & egid lua_pushstring(lua, "errno"); lua_pushinteger(lua, setregid(rgidset, egidset) != 0 ? errno : 0); lua_settable(lua, -3); } // get gid & egid gid_t gid = getgid(); gid_t egid = getegid(); // push lua_pushstring(lua, "rgid"); lua_pushinteger(lua, gid); lua_settable(lua, -3); lua_pushstring(lua, "egid"); lua_pushinteger(lua, egid); lua_settable(lua, -3); return 1; } #endif ================================================ FILE: core/src/xmake/os/isdir.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file isdir.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "isdir" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_isdir(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // is directory? tb_file_info_t info = { 0 }; lua_pushboolean(lua, tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_DIRECTORY)); return 1; } ================================================ FILE: core/src/xmake/os/isfile.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file isfile.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "isfile" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_isfile(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // is file? tb_file_info_t info = { 0 }; lua_pushboolean(lua, tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_FILE)); return 1; } ================================================ FILE: core/src/xmake/os/islink.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file islink.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "islink" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_islink(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // is link? tb_file_info_t info = { 0 }; lua_pushboolean(lua, tb_file_info(path, &info) && (info.flags & TB_FILE_FLAG_LINK)); return 1; } ================================================ FILE: core/src/xmake/os/link.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file link.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "link" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_link(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the source and destination tb_char_t const *src = luaL_checkstring(lua, 1); tb_char_t const *dst = luaL_checkstring(lua, 2); tb_check_return_val(src && dst, 0); // do os.link(src, dst) lua_pushboolean(lua, tb_file_link(src, dst)); return 1; } ================================================ FILE: core/src/xmake/os/mclock.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mclock.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "mclock" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // os.mclock() tb_int_t xm_os_mclock(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // save result lua_pushnumber(lua, (lua_Number)tb_mclock()); return 1; } ================================================ FILE: core/src/xmake/os/meminfo.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file meminfo.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "meminfo" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #if defined(TB_CONFIG_OS_MACOSX) #include #include #include #include #include #include #elif defined(TB_CONFIG_OS_LINUX) #include #include #elif defined(TB_CONFIG_OS_WINDOWS) #include #elif defined(TB_CONFIG_OS_BSD) #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ #ifdef TB_CONFIG_OS_LINUX static tb_int64_t xm_os_meminfo_get_value(tb_char_t const *buffer, tb_char_t const *name) { tb_char_t const *p = tb_strstr(buffer, name); return p ? tb_stoi64(p + tb_strlen(name)) : 0; } #endif // get the used memory size (MB) static tb_bool_t xm_os_meminfo_stats(tb_int_t *ptotalsize, tb_int_t *pavailsize) { #if defined(TB_CONFIG_OS_MACOSX) vm_statistics64_data_t vmstat; mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info_t)&vmstat, &count) == KERN_SUCCESS) { tb_int_t pagesize = (tb_int_t)tb_page_size(); tb_int64_t totalsize = (tb_int64_t)(vmstat.inactive_count + vmstat.free_count + vmstat.active_count + vmstat.wire_count #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + vmstat.compressor_page_count #endif ) * pagesize; /* * NB: speculative pages are already accounted for in "free_count", * so "speculative_count" is the number of "free" pages that are * used to hold data that was read speculatively from disk but * haven't actually been used by anyone so far. * */ tb_int64_t availsize = (tb_int64_t)(vmstat.inactive_count + vmstat.free_count - vmstat.speculative_count) * pagesize; *ptotalsize = (tb_int_t)(totalsize / (1024 * 1024)); *pavailsize = (tb_int_t)(availsize / (1024 * 1024)); return tb_true; } #elif defined(TB_CONFIG_OS_LINUX) /* we get meminfo from /proc/meminfo * * @see https://github.com/rfjakob/earlyoom/blob/cba1d599e4a7484c45ac017aa7702ff879f15846/meminfo.c#L52 */ if (tb_file_info("/proc/meminfo", tb_null)) { tb_bool_t ok = tb_false; FILE *fp = fopen("/proc/meminfo", "r"); if (fp) { // 8192 should be enough for the foreseeable future. tb_char_t buffer[8192]; size_t len = fread(buffer, 1, sizeof(buffer) - 1, fp); if (!ferror(fp) && len) { tb_int64_t totalsize = xm_os_meminfo_get_value(buffer, "MemTotal:"); tb_int64_t availsize = xm_os_meminfo_get_value(buffer, "MemAvailable:"); if (availsize <= 0) { tb_int64_t cachesize = xm_os_meminfo_get_value(buffer, "Cached:"); tb_int64_t freesize = xm_os_meminfo_get_value(buffer, "MemFree:"); tb_int64_t buffersize = xm_os_meminfo_get_value(buffer, "Buffers:"); tb_int64_t shmemsize = xm_os_meminfo_get_value(buffer, "Shmem:"); if (cachesize >= 0 && freesize >= 0 && buffersize >= 0 && shmemsize >= 0) { availsize = freesize + buffersize + cachesize - shmemsize; } } if (totalsize > 0 && availsize >= 0) { *ptotalsize = (tb_int_t)(totalsize / 1024); *pavailsize = (tb_int_t)(availsize / 1024); ok = tb_true; } } fclose(fp); } return ok; } else { struct sysinfo info = { 0 }; if (sysinfo(&info) == 0) { *ptotalsize = (tb_int_t)(info.totalram / (1024 * 1024)); *pavailsize = (tb_int_t)((info.freeram + info.bufferram /* + cache size */) / (1024 * 1024)); return tb_true; } } #elif defined(TB_CONFIG_OS_WINDOWS) MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); if (GlobalMemoryStatusEx(&statex)) { *ptotalsize = (tb_int_t)(statex.ullTotalPhys / (1024 * 1024)); *pavailsize = (tb_int_t)(statex.ullAvailPhys / (1024 * 1024)); return tb_true; } #elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__) unsigned long totalsize; size_t size = sizeof(totalsize); if (sysctlbyname("hw.physmem", &totalsize, &size, tb_null, 0) != 0) { return tb_false; } // http://web.mit.edu/freebsd/head/usr.bin/systat/vmstat.c tb_uint32_t v_free_count; size = sizeof(v_free_count); if (sysctlbyname("vm.stats.vm.v_free_count", &v_free_count, &size, tb_null, 0) != 0) { return tb_false; } tb_uint32_t v_inactive_count; size = sizeof(v_inactive_count); if (sysctlbyname("vm.stats.vm.v_inactive_count", &v_inactive_count, &size, tb_null, 0) != 0) { return tb_false; } *ptotalsize = (tb_int_t)(totalsize / (1024 * 1024)); *pavailsize = (tb_int_t)(((tb_int64_t)(v_free_count + v_inactive_count) * tb_page_size()) / (1024 * 1024)); return tb_true; #endif return tb_false; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_meminfo(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // init table lua_newtable(lua); // get the pagesize (bytes) tb_int_t pagesize = (tb_int_t)tb_page_size(); lua_pushstring(lua, "pagesize"); lua_pushinteger(lua, pagesize); lua_settable(lua, -3); // get the memory size (MB) tb_int_t availsize = 0; tb_int_t totalsize = 0; if (xm_os_meminfo_stats(&totalsize, &availsize)) { lua_pushstring(lua, "totalsize"); lua_pushinteger(lua, totalsize); lua_settable(lua, -3); lua_pushstring(lua, "availsize"); lua_pushinteger(lua, availsize); lua_settable(lua, -3); } return 1; } ================================================ FILE: core/src/xmake/os/mkdir.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mkdir.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "mkdir" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_mkdir(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // os.mkdir(path) tb_file_info_t info = { 0 }; if (!tb_file_info(path, &info) || (info.type != TB_FILE_TYPE_DIRECTORY)) { lua_pushboolean(lua, tb_directory_create(path)); } else { lua_pushboolean(lua, tb_true); } return 1; } ================================================ FILE: core/src/xmake/os/mtime.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mtime.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "mtime" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_mtime(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // os.mtime(path) tb_file_info_t info = { 0 }; if (tb_file_info(path, &info)) { lua_pushinteger(lua, (lua_Integer)info.mtime); } else { lua_pushinteger(lua, 0); } return 1; } ================================================ FILE: core/src/xmake/os/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_OS_PREFIX_H #define XM_OS_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/os/processes.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file processes.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "processes" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifdef TB_CONFIG_OS_WINDOWS #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_winos_processes(lua_State* lua) { #ifdef TB_CONFIG_OS_WINDOWS // init result table lua_newtable(lua); HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot != INVALID_HANDLE_VALUE) { PROCESSENTRY32W pe32; pe32.dwSize = sizeof(PROCESSENTRY32W); if (Process32FirstW(hSnapshot, &pe32)) { tb_int_t i = 1; do { // new process entry table lua_newtable(lua); // name tb_char_t name[MAX_PATH * 4]; tb_size_t size = tb_wtoa(name, pe32.szExeFile, sizeof(name)); if (size != -1) { lua_pushlstring(lua, name, size); } else { lua_pushstring(lua, ""); } lua_setfield(lua, -2, "name"); // pid lua_pushinteger(lua, (tb_int_t)pe32.th32ProcessID); lua_setfield(lua, -2, "pid"); // ppid lua_pushinteger(lua, (tb_int_t)pe32.th32ParentProcessID); lua_setfield(lua, -2, "parent_pid"); // result[i++] = entry lua_rawseti(lua, -2, i++); } while (Process32NextW(hSnapshot, &pe32)); } CloseHandle(hSnapshot); } return 1; #else return 0; #endif } ================================================ FILE: core/src/xmake/os/readlink.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file readlink.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "readlink" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifndef TB_CONFIG_OS_WINDOWS #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_readlink(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // is link? #if defined(TB_CONFIG_OS_WINDOWS) lua_pushnil(lua); #else tb_char_t srcpath[TB_PATH_MAXN]; tb_long_t size = readlink(path, srcpath, TB_PATH_MAXN); if (size == TB_PATH_MAXN) { tb_size_t maxn = TB_PATH_MAXN * 2; tb_char_t *data = (tb_char_t *)tb_malloc(maxn); if (data) { tb_long_t size = readlink(path, data, maxn); if (size > 0 && size < maxn) { data[size] = '\0'; lua_pushstring(lua, data); } else { lua_pushnil(lua); } tb_free(data); } } else if (size >= 0 && size < TB_PATH_MAXN) { srcpath[size] = '\0'; lua_pushstring(lua, srcpath); } else { lua_pushnil(lua); } #endif return 1; } ================================================ FILE: core/src/xmake/os/rename.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rename.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rename" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_rename(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the source and destination tb_char_t const *src = luaL_checkstring(lua, 1); tb_char_t const *dst = luaL_checkstring(lua, 2); tb_check_return_val(src && dst, 0); // do rename lua_pushboolean(lua, tb_file_rename(src, dst)); return 1; } ================================================ FILE: core/src/xmake/os/rmdir.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rmdir.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rmdir" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_long_t xm_os_rmdir_empty(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) { tb_bool_t *is_emptydir = (tb_bool_t *)priv; tb_assert_and_check_return_val(path && info && is_emptydir, TB_DIRECTORY_WALK_CODE_END); // is emptydir? if (info->type == TB_FILE_TYPE_DIRECTORY || info->type == TB_FILE_TYPE_FILE) { // not emptydir *is_emptydir = tb_false; return TB_DIRECTORY_WALK_CODE_END; } return TB_DIRECTORY_WALK_CODE_CONTINUE; } static tb_long_t xm_os_rmdir_remove(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) { tb_assert_and_check_return_val(path, TB_DIRECTORY_WALK_CODE_END); // is directory? if (info->type == TB_FILE_TYPE_DIRECTORY) { // is emptydir? tb_bool_t is_emptydir = tb_true; tb_directory_walk(path, tb_false, tb_true, xm_os_rmdir_empty, &is_emptydir); tb_trace_d("path: %s, emptydir: %u", path, is_emptydir); // remove empty directory if (is_emptydir) { tb_directory_remove(path); } } return TB_DIRECTORY_WALK_CODE_CONTINUE; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_rmdir(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // only remove empty directory? tb_bool_t rmempty = lua_toboolean(lua, 2); if (rmempty) { // remove all empty directories tb_directory_walk(path, tb_true, tb_false, xm_os_rmdir_remove, tb_null); // remove empty root directory tb_bool_t is_emptydir = tb_true; tb_directory_walk(path, tb_false, tb_true, xm_os_rmdir_empty, &is_emptydir); if (is_emptydir) { tb_directory_remove(path); } tb_trace_d("path: %s, emptydir: %u", path, is_emptydir); lua_pushboolean(lua, !tb_file_info(path, tb_null)); } else { // os.rmdir(path) lua_pushboolean(lua, tb_directory_remove(path)); } return 1; } ================================================ FILE: core/src/xmake/os/rmfile.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file rmfile.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "rmfile" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_rmfile(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // do remove lua_pushboolean(lua, tb_file_remove(path)); return 1; } ================================================ FILE: core/src/xmake/os/setenv.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file setenv.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "setenv" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // ok = os.setenv(name, value) tb_int_t xm_os_setenv(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the name and value size_t value_size = 0; tb_char_t const *name = luaL_checkstring(lua, 1); tb_char_t const *value = luaL_checklstring(lua, 2, &value_size); tb_check_return_val(name, 0); // set it lua_pushboolean(lua, value ? tb_environment_set(name, value) : tb_false); return 1; } ================================================ FILE: core/src/xmake/os/signal.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file signal.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "signal" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #if defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS) #include #include #elif defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) || defined(TB_CONFIG_OS_ANDROID) || \ defined(TB_CONFIG_OS_HAIKU) #include #include #endif #ifdef TB_CONFIG_OS_BSD #include #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * types */ typedef enum __xm_os_signal_e { XM_OS_SIGINT = 2 } xm_os_signal_e; typedef enum __xm_os_signal_handler_e { XM_OS_SIGFUN = 0, XM_OS_SIGDFL = 1, XM_OS_SIGIGN = 2, } xm_os_signal_handler_e; /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ static lua_State *g_lua = tb_null; /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_os_signal_handler_impl(tb_int_t signo) { // do callback(signo) lua_State *lua = g_lua; if (lua) { tb_char_t name[64] = { 0 }; tb_snprintf(name, sizeof(name), "_SIGNAL_HANDLER_%d", signo); lua_getglobal(lua, name); lua_pushinteger(lua, signo); lua_call(lua, 1, 0); } } #if defined(TB_CONFIG_OS_WINDOWS) static BOOL WINAPI xm_os_signal_handler(DWORD ctrl_type) { if (ctrl_type == CTRL_C_EVENT) { xm_os_signal_handler_impl(XM_OS_SIGINT); } return TRUE; } #elif defined(SIGINT) static tb_void_t xm_os_signal_handler(tb_int_t signo_native) { tb_int_t signo = -1; switch (signo_native) { case SIGINT: signo = XM_OS_SIGINT; break; default: break; } if (signo >= 0) { xm_os_signal_handler_impl(signo); } } #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_signal(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); g_lua = lua; tb_int_t handler = XM_OS_SIGFUN; // check signal handler if (lua_isnumber(lua, 2)) { handler = (tb_int_t)luaL_checkinteger(lua, 2); } else if (!lua_isfunction(lua, 2)) { return 0; } // save signal handler tb_int_t signo = (tb_int_t)luaL_checkinteger(lua, 1); if (handler == XM_OS_SIGFUN) { tb_char_t name[64] = { 0 }; tb_snprintf(name, sizeof(name), "_SIGNAL_HANDLER_%d", signo); lua_pushvalue(lua, 2); lua_setglobal(lua, name); } #if defined(TB_CONFIG_OS_WINDOWS) if (signo != XM_OS_SIGINT) { return 0; } switch (handler) { case XM_OS_SIGFUN: SetConsoleCtrlHandler(xm_os_signal_handler, TRUE); break; case XM_OS_SIGDFL: SetConsoleCtrlHandler(NULL, FALSE); break; case XM_OS_SIGIGN: SetConsoleCtrlHandler(NULL, TRUE); break; default: break; } #elif defined(SIGINT) switch (signo) { case XM_OS_SIGINT: signo = SIGINT; break; default: return 0; } switch (handler) { case XM_OS_SIGFUN: signal(signo, xm_os_signal_handler); break; case XM_OS_SIGDFL: signal(signo, SIG_DFL); break; case XM_OS_SIGIGN: signal(signo, SIG_IGN); break; default: break; } #endif return 0; } ================================================ FILE: core/src/xmake/os/sleep.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sleep.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "sleep" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_sleep(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_long_t interval = (tb_long_t)luaL_checklong(lua, 1); if (interval >= 0) { tb_msleep(interval); } return 0; } ================================================ FILE: core/src/xmake/os/strerror.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file strerror.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "strerror" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #include #else #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_strerror(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get syserror state tb_size_t syserror = tb_syserror_state(); if (syserror != TB_STATE_SYSERROR_UNKNOWN_ERROR) { tb_char_t const *strerr = "Unknown"; switch (syserror) { case TB_STATE_SYSERROR_NOT_PERM: strerr = "Permission denied"; break; #if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 173 case TB_STATE_SYSERROR_NOT_ACCESS: strerr = "Not access because it is busy"; break; #endif case TB_STATE_SYSERROR_NOT_FILEDIR: strerr = "No such file or directory"; break; default: break; } lua_pushstring(lua, strerr); } else { #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) tb_char_t strerr[128] = { 0 }; tb_snprintf(strerr, sizeof(strerr), "Unknown Error (%lu)", (tb_size_t)GetLastError()); lua_pushstring(lua, strerr); #else lua_pushstring(lua, strerror(errno)); #endif } return 1; } ================================================ FILE: core/src/xmake/os/syserror.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file syserror.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "syserror" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_syserror(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get syserror state tb_int_t err = 0; tb_size_t syserror = tb_syserror_state(); switch (syserror) { case TB_STATE_SYSERROR_NOT_PERM: err = 1; break; case TB_STATE_SYSERROR_NOT_FILEDIR: err = 2; break; #if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 173 case TB_STATE_SYSERROR_NOT_ACCESS: err = 3; break; #endif case TB_STATE_SYSERROR_UNKNOWN_ERROR: err = -1; break; } lua_pushinteger(lua, err); return 1; } ================================================ FILE: core/src/xmake/os/tmpdir.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file tmpdir.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "tmpdir" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_tmpdir(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // os.tmpdir() tb_char_t path[TB_PATH_MAXN]; if (tb_directory_temporary(path, sizeof(path))) { lua_pushstring(lua, path); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/os/touch.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file touch.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "touch" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_touch(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); tb_time_t atime = (tb_time_t)luaL_checknumber(lua, 2); tb_time_t mtime = (tb_time_t)luaL_checknumber(lua, 3); lua_pushboolean(lua, tb_file_touch(path, atime, mtime)); return 1; } ================================================ FILE: core/src/xmake/os/uid.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file uid.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "uid" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifndef TB_CONFIG_OS_WINDOWS #include #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ #ifndef TB_CONFIG_OS_WINDOWS // get & set uid tb_int_t xm_os_uid(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_int_t ruidset = -1; tb_int_t euidset = -1; tb_int_t argc = lua_gettop(lua); if (argc == 1) { if (lua_istable(lua, 1)) { // os.uid({["ruid"] = ruid, ["euid"] = euid}) lua_getfield(lua, 1, "ruid"); lua_getfield(lua, 1, "euid"); if (!lua_isnil(lua, -1)) { if (!lua_isnumber(lua, -1)) { lua_pushfstring(lua, "invalid field type(%s) in `euid` for os.uid", luaL_typename(lua, -1)); lua_error(lua); return 0; } euidset = (tb_int_t)lua_tonumber(lua, -1); } lua_pop(lua, 1); if (!lua_isnil(lua, -1)) { if (!lua_isnumber(lua, -1)) { lua_pushfstring(lua, "invalid field type(%s) in `ruid` for os.uid", luaL_typename(lua, -1)); lua_error(lua); return 0; } ruidset = (tb_int_t)lua_tonumber(lua, -1); } lua_pop(lua, 1); } else if (lua_isnumber(lua, 1)) { // os.uid(uid) ruidset = euidset = (tb_int_t)lua_tonumber(lua, 1); } else { lua_pushfstring(lua, "invalid argument type(%s) for os.uid", luaL_typename(lua, 1)); lua_error(lua); return 0; } } else if (argc == 2) { // os.uid(ruid, euid) if (!lua_isnil(lua, 1)) { if (!lua_isnumber(lua, 1)) { lua_pushfstring(lua, "invalid argument type(%s) for os.uid", luaL_typename(lua, 1)); lua_error(lua); return 0; } ruidset = (tb_int_t)lua_tonumber(lua, 1); } if (!lua_isnil(lua, 2)) { if (!lua_isnumber(lua, 2)) { lua_pushfstring(lua, "invalid argument type(%s) for os.uid", luaL_typename(lua, 2)); lua_error(lua); return 0; } euidset = (tb_int_t)lua_tonumber(lua, 2); } } else if (argc != 0) { lua_pushstring(lua, "invalid argument count for os.uid"); lua_error(lua); return 0; } // store return value lua_newtable(lua); if (ruidset != -1 || euidset != -1) { // set ruid & euid lua_pushstring(lua, "errno"); lua_pushinteger(lua, setreuid(ruidset, euidset) != 0 ? errno : 0); lua_settable(lua, -3); } // get uid & euid uid_t uid = getuid(); uid_t euid = geteuid(); // push lua_pushstring(lua, "ruid"); lua_pushinteger(lua, uid); lua_settable(lua, -3); lua_pushstring(lua, "euid"); lua_pushinteger(lua, euid); lua_settable(lua, -3); return 1; } #endif ================================================ FILE: core/src/xmake/package/loadxmi.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file loadxmi.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "loadxmi" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifdef USE_LUAJIT #define XMI_USE_LUAJIT #endif #include "xmi.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ typedef int (*xm_setup_func_t)(xmi_lua_ops_t *ops); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_package_loadxmi(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); tb_char_t const *name = luaL_checkstring(lua, 2); tb_check_return_val(name, 0); // load module library tb_dynamic_ref_t lib = tb_dynamic_init(path); if (!lib) { lua_pushnil(lua); lua_pushfstring(lua, "load %s failed", path); return 2; } // get xmiopen_xxx function lua_CFunction luaopen_func = (lua_CFunction)tb_dynamic_func(lib, name); if (!luaopen_func) { lua_pushnil(lua); lua_pushfstring(lua, "cannot get symbol %s failed", name); return 2; } // get xmisetup function xm_setup_func_t xmisetup_func = (xm_setup_func_t)tb_dynamic_func(lib, "xmisetup"); if (!xmisetup_func) { lua_pushnil(lua); lua_pushfstring(lua, "cannot get symbol xmisetup failed"); return 2; } // setup lua interfaces static xmi_lua_ops_t s_luaops = { 0 }; static tb_bool_t s_luaops_inited = tb_false; if (!s_luaops_inited) { // get functions #ifdef XMI_USE_LUAJIT s_luaops._lua_newuserdata = &lua_newuserdata; #else s_luaops._lua_getglobal = &lua_getglobal; s_luaops._lua_geti = &lua_geti; s_luaops._lua_rawgetp = &lua_rawgetp; s_luaops._lua_getiuservalue = &lua_getiuservalue; s_luaops._lua_newuserdatauv = &lua_newuserdatauv; #endif s_luaops._lua_gettable = &lua_gettable; s_luaops._lua_getfield = &lua_getfield; s_luaops._lua_rawget = &lua_rawget; s_luaops._lua_rawgeti = &lua_rawgeti; s_luaops._lua_createtable = &lua_createtable; s_luaops._lua_getmetatable = &lua_getmetatable; // set functions #ifndef XMI_USE_LUAJIT s_luaops._lua_setglobal = &lua_setglobal; s_luaops._lua_seti = &lua_seti; s_luaops._lua_rawsetp = &lua_rawsetp; s_luaops._lua_setiuservalue = &lua_setiuservalue; #endif s_luaops._lua_settable = &lua_settable; s_luaops._lua_setfield = &lua_setfield; s_luaops._lua_rawset = &lua_rawset; s_luaops._lua_rawseti = &lua_rawseti; s_luaops._lua_setmetatable = &lua_setmetatable; // access functions s_luaops._lua_isnumber = &lua_isnumber; s_luaops._lua_isstring = &lua_isstring; s_luaops._lua_iscfunction = &lua_iscfunction; s_luaops._lua_isuserdata = &lua_isuserdata; s_luaops._lua_type = &lua_type; s_luaops._lua_typename = &lua_typename; #ifndef XMI_USE_LUAJIT s_luaops._lua_isinteger = &lua_isinteger; #endif s_luaops._lua_tonumberx = &lua_tonumberx; s_luaops._lua_tointegerx = &lua_tointegerx; s_luaops._lua_toboolean = &lua_toboolean; s_luaops._lua_tolstring = &lua_tolstring; s_luaops._lua_tocfunction = &lua_tocfunction; s_luaops._lua_touserdata = &lua_touserdata; s_luaops._lua_tothread = &lua_tothread; s_luaops._lua_topointer = &lua_topointer; #ifndef XMI_USE_LUAJIT s_luaops._lua_rawlen = &lua_rawlen; #endif // push functions s_luaops._lua_pushnil = &lua_pushnil; s_luaops._lua_pushinteger = &lua_pushinteger; s_luaops._lua_pushboolean = &lua_pushboolean; s_luaops._lua_pushnumber = &lua_pushnumber; s_luaops._lua_pushlstring = &lua_pushlstring; s_luaops._lua_pushstring = &lua_pushstring; s_luaops._lua_pushvfstring = &lua_pushvfstring; s_luaops._lua_pushfstring = &lua_pushfstring; s_luaops._lua_pushcclosure = &lua_pushcclosure; s_luaops._lua_pushlightuserdata = &lua_pushlightuserdata; s_luaops._lua_pushthread = &lua_pushthread; // stack functions #ifdef XMI_USE_LUAJIT s_luaops._lua_insert = &lua_insert; s_luaops._lua_remove = &lua_remove; s_luaops._lua_replace = &lua_replace; #else s_luaops._lua_absindex = &lua_absindex; s_luaops._lua_rotate = &lua_rotate; #endif s_luaops._lua_gettop = &lua_gettop; s_luaops._lua_settop = &lua_settop; s_luaops._lua_pushvalue = &lua_pushvalue; s_luaops._lua_copy = &lua_copy; s_luaops._lua_checkstack = &lua_checkstack; s_luaops._lua_xmove = &lua_xmove; // miscellaneous functions s_luaops._lua_error = &lua_error; s_luaops._lua_next = &lua_next; s_luaops._lua_concat = &lua_concat; s_luaops._lua_getallocf = &lua_getallocf; s_luaops._lua_setallocf = &lua_setallocf; #ifndef XMI_USE_LUAJIT s_luaops._lua_len = &lua_len; s_luaops._lua_toclose = &lua_toclose; s_luaops._lua_closeslot = &lua_closeslot; s_luaops._lua_stringtonumber = &lua_stringtonumber; #endif // 'load' and 'call' functions #ifdef XMI_USE_LUAJIT s_luaops._lua_call = &lua_call; s_luaops._lua_pcall = &lua_pcall; #else s_luaops._lua_callk = &lua_callk; s_luaops._lua_pcallk = &lua_pcallk; #endif s_luaops._lua_load = &lua_load; s_luaops._lua_dump = &lua_dump; // luaL functions #ifndef XMI_USE_LUAJIT s_luaops._luaL_tolstring = &luaL_tolstring; s_luaops._luaL_typeerror = &luaL_typeerror; #endif s_luaops._luaL_getmetafield = &luaL_getmetafield; s_luaops._luaL_callmeta = &luaL_callmeta; s_luaops._luaL_argerror = &luaL_argerror; s_luaops._luaL_checklstring = &luaL_checklstring; s_luaops._luaL_optlstring = &luaL_optlstring; s_luaops._luaL_checknumber = &luaL_checknumber; s_luaops._luaL_optnumber = &luaL_optnumber; s_luaops._luaL_checkinteger = &luaL_checkinteger; s_luaops._luaL_optinteger = &luaL_optinteger; s_luaops._luaL_checkstack = &luaL_checkstack; s_luaops._luaL_checktype = &luaL_checktype; s_luaops._luaL_checkany = &luaL_checkany; s_luaops._luaL_newmetatable = &luaL_newmetatable; s_luaops._luaL_testudata = &luaL_testudata; s_luaops._luaL_checkudata = &luaL_checkudata; s_luaops._luaL_where = &luaL_where; s_luaops._luaL_error = &luaL_error; s_luaops._luaL_checkoption = &luaL_checkoption; s_luaops._luaL_fileresult = &luaL_fileresult; s_luaops._luaL_execresult = &luaL_execresult; s_luaops._luaL_setfuncs = &luaL_setfuncs; s_luaops._luaL_loadfilex = &luaL_loadfilex; s_luaops._luaL_loadstring = &luaL_loadstring; s_luaops_inited = tb_true; } xmisetup_func(&s_luaops); // load module lua_pushcfunction(lua, luaopen_func); return 1; } ================================================ FILE: core/src/xmake/package/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_PACKAGE_PREFIX_H #define XM_PACKAGE_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/path/absolute.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file absolute.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "absolute" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_path_absolute(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // get the root tb_char_t const *root = luaL_optstring(lua, 2, tb_null); // do path:absolute(root) tb_char_t data[TB_PATH_MAXN]; lua_pushstring(lua, tb_path_absolute_to(root, path, data, sizeof(data) - 1)); return 1; } ================================================ FILE: core/src/xmake/path/directory.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file directory.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "directory" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_path_directory(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // do path:directory() tb_char_t data[TB_PATH_MAXN]; tb_char_t const *dir = tb_path_directory(path, data, sizeof(data)); if (dir) { lua_pushstring(lua, dir); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/path/is_absolute.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file is_absolute.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "is_absolute" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_path_is_absolute(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // path:is_absolute() lua_pushboolean(lua, tb_path_is_absolute(path)); return 1; } ================================================ FILE: core/src/xmake/path/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_PATH_PREFIX_H #define XM_PATH_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/path/relative.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file relative.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "relative" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_path_relative(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const *path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // get the root tb_char_t const *root = luaL_optstring(lua, 2, tb_null); // path:relative(root) tb_char_t data[TB_PATH_MAXN]; lua_pushstring(lua, tb_path_relative_to(root, path, data, sizeof(data) - 1)); return 1; } ================================================ FILE: core/src/xmake/path/translate.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file translate.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "translate" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_path_translate(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the path size_t path_size = 0; tb_char_t const *path = luaL_checklstring(lua, 1, &path_size); tb_check_return_val(path, 0); // get the option argument, e.g. {normalize = true} tb_bool_t normalize = tb_false; if (lua_istable(lua, 2)) { lua_pushstring(lua, "normalize"); lua_gettable(lua, 2); if (lua_toboolean(lua, -1)) { normalize = tb_true; } lua_pop(lua, 1); } // do path:translate() tb_char_t data[TB_PATH_MAXN]; tb_size_t size = tb_path_translate_to(path, (tb_size_t)path_size, data, sizeof(data), normalize); if (size) { lua_pushlstring(lua, data, (size_t)size); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/prefix/config.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file config.h * */ #ifndef XM_PREFIX_CONFIG_H #define XM_PREFIX_CONFIG_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../config.h" #include "tbox/tbox.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ /*! @def __xm_small__ * * small mode */ #if XM_CONFIG_SMALL #define __xm_small__ #endif /*! @def __xm_debug__ * * debug mode */ #ifdef __tb_debug__ #define __xm_debug__ #endif /* unix/gcc on msys/cygwin? do not support it now! * * @see https://github.com/xmake-io/xmake/issues/681 * * on msys: * pacman -S mingw-w64-i686-gcc * pacman -S mingw-w64-x86_64-gcc * * e.g. * $ pacman -S mingw-w64-x86_64-gcc * $ which gcc * /mingw64/bin/gcc * $ cd xmake * $ make build * $ make install prefix=/mingw64 */ #if defined(TB_CONFIG_OS_WINDOWS) && defined(TB_COMPILER_LIKE_UNIX) #error "do not support gcc on msys/cygwin, please uses mingw-w64-[i686|x86_64]-gcc" #endif #endif ================================================ FILE: core/src/xmake/prefix/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_PREFIX_PREFIX_H #define XM_PREFIX_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "config.h" #include "version.h" #endif ================================================ FILE: core/src/xmake/prefix/version.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file version.h * */ #ifndef XM_PREFIX_VERSION_H #define XM_PREFIX_VERSION_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "config.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ /// the major version #define XM_VERSION_MAJOR XM_CONFIG_VERSION_MAJOR /// the minor version #define XM_VERSION_MINOR XM_CONFIG_VERSION_MINOR /// the alter version #define XM_VERSION_ALTER XM_CONFIG_VERSION_ALTER /// the build version #ifndef XM_CONFIG_VERSION_BUILD #define XM_CONFIG_VERSION_BUILD 0 #endif #define XM_VERSION_BUILD XM_CONFIG_VERSION_BUILD /// the build version string #define XM_VERSION_BUILD_STRING __tb_mstring_ex__(XM_CONFIG_VERSION_BUILD) /// the version string #define XM_VERSION_STRING \ __tb_mstrcat6__("xmake_", \ __tb_mstring_ex__(__tb_mconcat8_ex__( \ v, XM_VERSION_MAJOR, _, XM_VERSION_MINOR, _, XM_VERSION_ALTER, _, XM_CONFIG_VERSION_BUILD)), \ "_", \ TB_ARCH_VERSION_STRING, \ " by ", \ TB_COMPILER_VERSION_STRING) /// the short version string #define XM_VERSION_SHORT_STRING \ __tb_mstrcat__("xmake_", \ __tb_mstring_ex__(__tb_mconcat8_ex__( \ v, XM_VERSION_MAJOR, _, XM_VERSION_MINOR, _, XM_VERSION_ALTER, _, XM_CONFIG_VERSION_BUILD))) #endif ================================================ FILE: core/src/xmake/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_PREFIX_H #define XM_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix/prefix.h" #include "luaconf.h" #if defined(TB_CONFIG_OS_WINDOWS) && defined(__cplusplus) #undef LUA_API #undef LUALIB_API #define LUA_API extern "C" #define LUALIB_API LUA_API #endif #ifdef USE_LUAJIT #include "luajit.h" #include "lualib.h" #include "lauxlib.h" #else #include "lua.h" #include "lualib.h" #include "lauxlib.h" #endif /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // define lua_Unsigned for luajit/lua5.1 #if defined(USE_LUAJIT) || LUA_VERSION_NUM < 503 typedef size_t lua_Unsigned; #endif /* ////////////////////////////////////////////////////////////////////////////////////// * private interfaces */ // this issue has been fixed, @see https://github.com/LuaJIT/LuaJIT/commit/e9af1abec542e6f9851ff2368e7f196b6382a44c #if 0 //TB_CPU_BIT64 /* we use this interface instead of lua_pushlightuserdata() to fix bad light userdata pointer bug * * @see https://github.com/xmake-io/xmake/issues/914 * https://github.com/LuaJIT/LuaJIT/pull/230 * * @note we cannot lua_newuserdata() because we need pass this pointer to the external lua code * in poller_wait()/event_callback, but lua_pushuserdata does not exists */ static __tb_inline__ tb_void_t xm_lua_pushpointer(lua_State* lua, tb_pointer_t ptr) { tb_uint64_t ptrval = (tb_uint64_t)ptr; if ((ptrval >> 47) == 0) lua_pushlightuserdata(lua, ptr); else { tb_char_t str[64]; tb_long_t len = tb_snprintf(str, sizeof(str), "%p", ptr); lua_pushlstring(lua, str, len); } } static __tb_inline__ tb_bool_t xm_lua_ispointer(lua_State* lua, tb_int_t idx) { return lua_isuserdata(lua, idx) || lua_isstring(lua, idx); } static __tb_inline__ tb_pointer_t xm_lua_topointer2(lua_State* lua, tb_int_t idx, tb_char_t const** pstr) { tb_pointer_t ptr = tb_null; if (lua_isuserdata(lua, idx)) { ptr = lua_touserdata(lua, idx); if (pstr) *pstr = tb_null; } else { size_t len = 0; tb_char_t const* str = luaL_checklstring(lua, idx, &len); if (str && len > 2 && str[0] == '0' && str[1] == 'x') ptr = (tb_pointer_t)tb_s16tou64(str); if (pstr) *pstr = str; } return ptr; } static __tb_inline__ tb_pointer_t xm_lua_topointer(lua_State* lua, tb_int_t idx) { return xm_lua_topointer2(lua, idx, tb_null); } #else static __tb_inline__ tb_void_t xm_lua_pushpointer(lua_State *lua, tb_pointer_t ptr) { lua_pushlightuserdata(lua, ptr); } static __tb_inline__ tb_bool_t xm_lua_ispointer(lua_State *lua, tb_int_t idx) { return lua_isuserdata(lua, idx); } static __tb_inline__ tb_pointer_t xm_lua_topointer2(lua_State *lua, tb_int_t idx, tb_char_t const **pstr) { if (pstr) *pstr = tb_null; return lua_touserdata(lua, idx); } static __tb_inline__ tb_pointer_t xm_lua_topointer(lua_State *lua, tb_int_t idx) { return lua_touserdata(lua, idx); } #endif static __tb_inline__ tb_void_t xm_lua_register(lua_State *lua, tb_char_t const *libname, luaL_Reg const *l) { #if LUA_VERSION_NUM >= 504 if (libname) { lua_getglobal(lua, libname); if (lua_isnil(lua, -1)) { lua_pop(lua, 1); lua_newtable(lua); } luaL_setfuncs(lua, l, 0); lua_setglobal(lua, libname); } else { luaL_setfuncs(lua, l, 0); } #else luaL_register(lua, libname, l); #endif } static __tb_inline__ tb_int_t xm_lua_isinteger(lua_State *lua, int idx) { #ifdef USE_LUAJIT return lua_isnumber(lua, idx); #else return lua_isinteger(lua, idx); #endif } #endif ================================================ FILE: core/src/xmake/process/close.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file close.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "process.close" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // process.close(p) tb_int_t xm_process_close(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the process tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(process, 0); // exit process tb_process_exit(process); // save result: ok lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/process/kill.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file kill.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "process.kill" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // process.kill(p) tb_int_t xm_process_kill(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get the process tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(process, 0); // kill process tb_process_kill(process); return 0; } ================================================ FILE: core/src/xmake/process/open.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file open.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "process.open" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "../io/prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* p = process.open(command, * {outpath = "", errpath = "", outfile = "", * errfile = "", outpipe = "", errpipe = "", * infile = "", inpipe = "", inpipe = "", * envs = {"PATH=xxx", "XXX=yyy"}}) */ tb_int_t xm_process_open(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get command size_t command_size = 0; tb_char_t const *command = luaL_checklstring(lua, 1, &command_size); tb_check_return_val(command, 0); // init attributes tb_process_attr_t attr = { 0 }; // get option arguments tb_size_t envn = 0; tb_char_t const *envs[1024] = { 0 }; tb_char_t const *inpath = tb_null; tb_char_t const *outpath = tb_null; tb_char_t const *errpath = tb_null; xm_io_file_t *infile = tb_null; xm_io_file_t *outfile = tb_null; xm_io_file_t *errfile = tb_null; tb_pipe_file_ref_t inpipe = tb_null; tb_pipe_file_ref_t outpipe = tb_null; tb_pipe_file_ref_t errpipe = tb_null; if (lua_istable(lua, 2)) { // is detached? lua_pushstring(lua, "detach"); lua_gettable(lua, 2); if (lua_toboolean(lua, -1)) { attr.flags |= TB_PROCESS_FLAG_DETACH; } lua_pop(lua, 1); // get curdir lua_pushstring(lua, "curdir"); lua_gettable(lua, 3); attr.curdir = lua_tostring(lua, -1); lua_pop(lua, 1); // get inpath lua_pushstring(lua, "inpath"); lua_gettable(lua, 2); inpath = lua_tostring(lua, -1); lua_pop(lua, 1); // get outpath lua_pushstring(lua, "outpath"); lua_gettable(lua, 2); outpath = lua_tostring(lua, -1); lua_pop(lua, 1); // get errpath lua_pushstring(lua, "errpath"); lua_gettable(lua, 2); errpath = lua_tostring(lua, -1); lua_pop(lua, 1); // get infile if (!inpath) { lua_pushstring(lua, "infile"); lua_gettable(lua, 3); infile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get outfile if (!outpath) { lua_pushstring(lua, "outfile"); lua_gettable(lua, 3); outfile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get errfile if (!errpath) { lua_pushstring(lua, "errfile"); lua_gettable(lua, 3); errfile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get inpipe if (!inpath && !infile) { lua_pushstring(lua, "inpipe"); lua_gettable(lua, 3); inpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get outpipe if (!outpath && !outfile) { lua_pushstring(lua, "outpipe"); lua_gettable(lua, 3); outpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get errpipe if (!errpath && !errfile) { lua_pushstring(lua, "errpipe"); lua_gettable(lua, 3); errpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get environments lua_pushstring(lua, "envs"); lua_gettable(lua, 2); if (lua_istable(lua, -1)) { // get environment variables count tb_size_t count = (tb_size_t)lua_objlen(lua, -1); // get all passed environment variables tb_size_t i; for (i = 0; i < count; i++) { // get envs[i] lua_pushinteger(lua, i + 1); lua_gettable(lua, -2); // is string? if (lua_isstring(lua, -1)) { // add this environment value if (envn + 1 < tb_arrayn(envs)) { envs[envn++] = lua_tostring(lua, -1); } else { // error lua_pushfstring(lua, "envs is too large(%d > %d) for process.openv", (tb_int_t)envn, tb_arrayn(envs) - 1); lua_error(lua); } } else { // error lua_pushfstring(lua, "invalid envs[%d] type(%s) for process.openv", (tb_int_t)i, luaL_typename(lua, -1)); lua_error(lua); } // pop it lua_pop(lua, 1); } } lua_pop(lua, 1); } // redirect stdin? if (inpath) { // redirect stdin to file attr.in.path = inpath; attr.inmode = TB_FILE_MODE_RO; attr.intype = TB_PROCESS_REDIRECT_TYPE_FILEPATH; } else if (infile && xm_io_file_is_file(infile)) { tb_file_ref_t rawfile = tb_null; if (tb_stream_ctrl(infile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) { attr.in.file = rawfile; attr.intype = TB_PROCESS_REDIRECT_TYPE_FILE; } } else if (inpipe) { attr.in.pipe = inpipe; attr.intype = TB_PROCESS_REDIRECT_TYPE_PIPE; } // redirect stdout? if (outpath) { // redirect stdout to file attr.out.path = outpath; attr.outmode = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT; attr.outtype = TB_PROCESS_REDIRECT_TYPE_FILEPATH; } else if (outfile && xm_io_file_is_file(outfile)) { tb_file_ref_t rawfile = tb_null; if (tb_stream_ctrl(outfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) { attr.out.file = rawfile; attr.outtype = TB_PROCESS_REDIRECT_TYPE_FILE; } } else if (outpipe) { attr.out.pipe = outpipe; attr.outtype = TB_PROCESS_REDIRECT_TYPE_PIPE; } // redirect stderr? if (errpath) { // redirect stderr to file attr.err.path = errpath; attr.errmode = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT; attr.errtype = TB_PROCESS_REDIRECT_TYPE_FILEPATH; } else if (errfile && xm_io_file_is_file(errfile)) { tb_file_ref_t rawfile = tb_null; if (tb_stream_ctrl(errfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) { attr.err.file = rawfile; attr.errtype = TB_PROCESS_REDIRECT_TYPE_FILE; } } else if (errpipe) { attr.err.pipe = errpipe; attr.errtype = TB_PROCESS_REDIRECT_TYPE_PIPE; } // set the new environments if (envn > 0) { attr.envp = envs; } // init process tb_process_ref_t process = (tb_process_ref_t)tb_process_init_cmd(command, &attr); if (process) { xm_lua_pushpointer(lua, (tb_pointer_t)process); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/process/openv.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file openv.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "process.openv" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "../io/prefix.h" #if defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) || \ defined(TB_CONFIG_OS_HAIKU) || defined(TB_COMPILER_IS_MINGW) #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* p = process.openv(shellname, argv, * {outpath = "", errpath = "", outfile = "", * errfile = "", outpipe = "", errpipe = "", * infile = "", inpipe = "", inpipe = "", * envs = {"PATH=xxx", "XXX=yyy"}}) */ tb_int_t xm_process_openv(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // check argv if (!lua_istable(lua, 2)) { // error lua_pushfstring(lua, "invalid argv type(%s) for process.openv", luaL_typename(lua, 2)); lua_error(lua); return 0; } // get shellname tb_char_t const *shellname = lua_tostring(lua, 1); tb_check_return_val(shellname, 0); // get the arguments count tb_long_t argn = (tb_long_t)lua_objlen(lua, 2); tb_check_return_val(argn >= 0, 0); // get arguments tb_size_t argi = 0; tb_char_t const **argv = tb_nalloc0_type(1 + argn + 1, tb_char_t const *); tb_check_return_val(argv, 0); // fill arguments argv[0] = shellname; for (argi = 0; argi < argn; argi++) { // get argv[i] lua_pushinteger(lua, argi + 1); lua_gettable(lua, 2); // is string? if (lua_isstring(lua, -1)) { // pass this argument argv[1 + argi] = lua_tostring(lua, -1); } // is path instance? else if (lua_istable(lua, -1)) { lua_pushstring(lua, "_STR"); lua_gettable(lua, -2); argv[1 + argi] = lua_tostring(lua, -1); lua_pop(lua, 1); } else { // error lua_pushfstring(lua, "invalid argv[%d] type(%s) for process.openv", (tb_int_t)argi, luaL_typename(lua, -1)); lua_error(lua); } // pop it lua_pop(lua, 1); } // init attributes tb_process_attr_t attr = { 0 }; // get option arguments tb_bool_t exclusive = tb_false; tb_size_t envn = 0; tb_char_t const *envs[1024] = { 0 }; tb_char_t const *inpath = tb_null; tb_char_t const *outpath = tb_null; tb_char_t const *errpath = tb_null; xm_io_file_t *infile = tb_null; xm_io_file_t *outfile = tb_null; xm_io_file_t *errfile = tb_null; tb_pipe_file_ref_t inpipe = tb_null; tb_pipe_file_ref_t outpipe = tb_null; tb_pipe_file_ref_t errpipe = tb_null; if (lua_istable(lua, 3)) { // is detached? lua_pushstring(lua, "detach"); lua_gettable(lua, 3); if (lua_toboolean(lua, -1)) { attr.flags |= TB_PROCESS_FLAG_DETACH; } lua_pop(lua, 1); // is exclusive? lua_pushstring(lua, "exclusive"); lua_gettable(lua, 3); if (lua_toboolean(lua, -1)) { exclusive = tb_true; } lua_pop(lua, 1); // get curdir lua_pushstring(lua, "curdir"); lua_gettable(lua, 3); attr.curdir = lua_tostring(lua, -1); lua_pop(lua, 1); // get inpath lua_pushstring(lua, "inpath"); lua_gettable(lua, 3); inpath = lua_tostring(lua, -1); lua_pop(lua, 1); // get outpath lua_pushstring(lua, "outpath"); lua_gettable(lua, 3); outpath = lua_tostring(lua, -1); lua_pop(lua, 1); // get errpath lua_pushstring(lua, "errpath"); lua_gettable(lua, 3); errpath = lua_tostring(lua, -1); lua_pop(lua, 1); // get infile if (!inpath) { lua_pushstring(lua, "infile"); lua_gettable(lua, 3); infile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get outfile if (!outpath) { lua_pushstring(lua, "outfile"); lua_gettable(lua, 3); outfile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get errfile if (!errpath) { lua_pushstring(lua, "errfile"); lua_gettable(lua, 3); errfile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get inpipe if (!inpath && !infile) { lua_pushstring(lua, "inpipe"); lua_gettable(lua, 3); inpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get outpipe if (!outpath && !outfile) { lua_pushstring(lua, "outpipe"); lua_gettable(lua, 3); outpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get errpipe if (!errpath && !errfile) { lua_pushstring(lua, "errpipe"); lua_gettable(lua, 3); errpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } // get environments lua_pushstring(lua, "envs"); lua_gettable(lua, 3); if (lua_istable(lua, -1)) { // get environment variables count tb_size_t count = (tb_size_t)lua_objlen(lua, -1); // get all passed environment variables tb_size_t i; for (i = 0; i < count; i++) { // get envs[i] lua_pushinteger(lua, i + 1); lua_gettable(lua, -2); // is string? if (lua_isstring(lua, -1)) { // add this environment value if (envn + 1 < tb_arrayn(envs)) { envs[envn++] = lua_tostring(lua, -1); } else { // error lua_pushfstring(lua, "envs is too large(%d > %d) for process.openv", (tb_int_t)envn, tb_arrayn(envs) - 1); lua_error(lua); } } else { // error lua_pushfstring(lua, "invalid envs[%d] type(%s) for process.openv", (tb_int_t)i, luaL_typename(lua, -1)); lua_error(lua); } // pop it lua_pop(lua, 1); } } lua_pop(lua, 1); } // redirect stdin? if (inpath) { // redirect stdin to file attr.in.path = inpath; attr.inmode = TB_FILE_MODE_RO; attr.intype = TB_PROCESS_REDIRECT_TYPE_FILEPATH; } else if (infile && xm_io_file_is_file(infile)) { tb_file_ref_t rawfile = tb_null; if (tb_stream_ctrl(infile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) { attr.in.file = rawfile; attr.intype = TB_PROCESS_REDIRECT_TYPE_FILE; } } else if (inpipe) { attr.in.pipe = inpipe; attr.intype = TB_PROCESS_REDIRECT_TYPE_PIPE; } // redirect stdout? if (outpath) { // redirect stdout to file attr.out.path = outpath; attr.outmode = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT; attr.outtype = TB_PROCESS_REDIRECT_TYPE_FILEPATH; } else if (outfile && xm_io_file_is_file(outfile)) { tb_file_ref_t rawfile = tb_null; if (tb_stream_ctrl(outfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) { attr.out.file = rawfile; attr.outtype = TB_PROCESS_REDIRECT_TYPE_FILE; } } else if (outpipe) { attr.out.pipe = outpipe; attr.outtype = TB_PROCESS_REDIRECT_TYPE_PIPE; } // redirect stderr? if (errpath) { // redirect stderr to file attr.err.path = errpath; attr.errmode = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT; attr.errtype = TB_PROCESS_REDIRECT_TYPE_FILEPATH; } else if (errfile && xm_io_file_is_file(errfile)) { tb_file_ref_t rawfile = tb_null; if (tb_stream_ctrl(errfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) { attr.err.file = rawfile; attr.errtype = TB_PROCESS_REDIRECT_TYPE_FILE; } } else if (errpipe) { attr.err.pipe = errpipe; attr.errtype = TB_PROCESS_REDIRECT_TYPE_PIPE; } // set the new environments if (envn > 0) { attr.envp = envs; } /* we need to ignore SIGINT and SIGQUIT if we enter exclusive mode * @see https://github.com/xmake-io/xmake/discussions/2893 */ #if defined(SIGINT) if (exclusive) { signal(SIGINT, SIG_IGN); } #endif #if defined(SIGQUIT) if (exclusive) { signal(SIGQUIT, SIG_IGN); } #endif // init process tb_process_ref_t process = (tb_process_ref_t)tb_process_init(shellname, argv, &attr); if (process) { xm_lua_pushpointer(lua, (tb_pointer_t)process); } else { lua_pushnil(lua); } // exit argv if (argv) { tb_free(argv); } argv = tb_null; return 1; } ================================================ FILE: core/src/xmake/process/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_PROCESS_PREFIX_H #define XM_PROCESS_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/process/wait.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file wait.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "process.wait" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // ok, status = process.wait(proc, timeout) tb_int_t xm_process_wait(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { // error lua_pushfstring(lua, "invalid argument type(%s) for process.wait", luaL_typename(lua, 1)); lua_error(lua); return 0; } // get the process tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1); tb_check_return_val(process, 0); // get the timeout tb_long_t timeout = (tb_long_t)luaL_checkinteger(lua, 2); // wait it tb_long_t status = 0; tb_long_t ok = tb_process_wait(process, &status, timeout); // save result lua_pushinteger(lua, ok); lua_pushinteger(lua, status); return 2; } ================================================ FILE: core/src/xmake/readline/add_history.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file add_history.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "add_history" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ #ifdef XM_CONFIG_API_HAVE_READLINE // add_history wrapper tb_int_t xm_readline_add_history(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get history tb_char_t const *history = luaL_checkstring(lua, 1); tb_check_return_val(history, 0); // call add_history add_history(history); return 0; } #endif ================================================ FILE: core/src/xmake/readline/clear_history.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file clear_history.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "clear_history" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ #ifdef XM_CONFIG_API_HAVE_READLINE // clear_history wrapper tb_int_t xm_readline_clear_history(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); #ifdef TB_CONFIG_OS_MACOSX // call clear_history (will crash on macOS) for (tb_int_t i = history_length - 1; i >= 0; --i) { remove_history(i); } #else clear_history(); #endif return 0; } #endif ================================================ FILE: core/src/xmake/readline/history_list.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file history_list.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "history_list" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ #ifdef XM_CONFIG_API_HAVE_READLINE // history_list wrapper tb_int_t xm_readline_history_list(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // history list lua_newtable(lua); #ifdef TB_CONFIG_OS_MACOSX for (tb_int_t i = 1; i <= history_length; ++i) { lua_newtable(lua); // field line lua_pushstring(lua, "line"); lua_pushstring(lua, history_get(i)->line); lua_settable(lua, -3); // set back lua_rawseti(lua, -2, i); } #else tb_int_t i = 1; for (HIST_ENTRY **p = history_list(); *p; ++p, ++i) { lua_newtable(lua); // field line lua_pushstring(lua, "line"); lua_pushstring(lua, (*p)->line); lua_settable(lua, -3); // set back lua_rawseti(lua, -2, i); } #endif return 1; } #endif ================================================ FILE: core/src/xmake/readline/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file prefix.h * */ #ifndef XM_READLINE_PREFIX_H #define XM_READLINE_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #ifdef XM_CONFIG_API_HAVE_READLINE #include // on some OS (like centos) required #include #include #endif #endif ================================================ FILE: core/src/xmake/readline/readline.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow * @file readline.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "readline" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifdef XM_CONFIG_API_HAVE_READLINE /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // readline wrapper tb_int_t xm_readline_readline(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the prompt tb_char_t const *prompt = luaL_optstring(lua, 1, tb_null); // call readline tb_char_t *line = readline(prompt); if (line) { // return line lua_pushstring(lua, line); // free it tb_free(line); } else { lua_pushnil(lua); } return 1; } #endif ================================================ FILE: core/src/xmake/sandbox/interactive.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file interactive.c * */ /* Runs interactive commands, read-eval-print (REPL) * * Major portions taken verbatim or adapted from LuaJIT frontend and the Lua interpreter. * Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h * Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "sandbox.interactive" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "../winos/ansi.h" #ifdef XM_CONFIG_API_HAVE_READLINE #include #include #include #include // on some OS (like centos) required #endif /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // buffer size for prompt #define LUA_PROMPT_BUFSIZE 4096 // for lua5.4 #ifndef LUA_QL #define LUA_QL(x) "'" x "'" #endif /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ // report results static tb_void_t xm_sandbox_report(lua_State *lua) { if (!lua_isnil(lua, -1)) { // get message tb_char_t const *msg = lua_tostring(lua, -1); if (!msg) { msg = "(error object is not a string)"; } // print it tb_printl(msg); tb_print_sync(); // pop this message lua_pop(lua, 1); } } // the traceback function static tb_int_t xm_sandbox_traceback(lua_State *lua) { if (!lua_isstring(lua, 1)) { // non-string error object? try metamethod. if (lua_isnoneornil(lua, 1) || !luaL_callmeta(lua, 1, "__tostring") || !lua_isstring(lua, -1)) { return 1; // return non-string error object. } // replace object by result of __tostring metamethod. lua_remove(lua, 1); } // return backtrace luaL_traceback(lua, lua, lua_tostring(lua, 1), 1); return 1; } // execute codes static tb_int_t xm_sandbox_docall(lua_State *lua, tb_int_t narg, tb_int_t clear) { /* get error function index * * stack: arg1(sandbox_scope) scriptfunc(top) -> ... */ tb_int_t errfunc = lua_gettop(lua) - narg; // push traceback function lua_pushcfunction(lua, xm_sandbox_traceback); // put it under chunk and args lua_insert(lua, errfunc); /* execute it * * stack: errfunc arg1 scriptfunc -> ... * after: errfunc arg1 [results] -> ... */ tb_int_t status = lua_pcall(lua, narg, (clear ? 0 : LUA_MULTRET), errfunc); // remove traceback function lua_remove(lua, errfunc); // force a complete garbage collection in case of errors if (status != 0) { lua_gc(lua, LUA_GCCOLLECT, 0); } return status; } // this line is incomplete? static tb_int_t xm_sandbox_incomplete(lua_State *lua, tb_int_t status) { // syntax error? if (status == LUA_ERRSYNTAX) { size_t lmsg; tb_char_t const *msg = lua_tolstring(lua, -1, &lmsg); tb_char_t const *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); if (tb_strstr(msg, LUA_QL("")) == tp) { lua_pop(lua, 1); return 1; } } return 0; } // read line static tb_size_t xm_sandbox_readline(tb_char_t *data, tb_size_t maxn, tb_char_t const *prompt) { #ifdef XM_CONFIG_API_HAVE_READLINE // get line tb_char_t const *line = readline(prompt); if (line) { // add line to history add_history(line); // copy line to data tb_size_t size = tb_strlcpy(data, line, maxn); // free line free((void *)line); // truncated? if (size >= maxn) { return 0; } return size; } #else // print prompt tb_printf(prompt); tb_print_sync(); // get input buffer if (tb_stdfile_gets(tb_stdfile_input(), data, maxn)) { return tb_strlen(data); } #endif // no more input return 0; } // read and push input line static tb_int_t xm_sandbox_pushline(lua_State *lua, tb_char_t const *prompt2) { // read line tb_char_t data[LUA_PROMPT_BUFSIZE]; tb_size_t size = xm_sandbox_readline(data, sizeof(data), prompt2); if (size) { // split line '\0' if (data[size - 1] == '\n') { data[size - 1] = '\0'; } // push line lua_pushstring(lua, data); return 1; } // no input return 0; } // load code line static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) { // clear stack lua_settop(lua, top); // get prompt strings from arg1(sandbox_scope) lua_pushstring(lua, "$interactive_prompt"); lua_gettable(lua, 1); tb_char_t const *prompt = lua_tostring(lua, -1); lua_pop(lua, 1); lua_pushstring(lua, "$interactive_prompt2"); lua_gettable(lua, 1); tb_char_t const *prompt2 = lua_tostring(lua, -1); lua_pop(lua, 1); // read first line tb_int_t status; tb_char_t data[LUA_PROMPT_BUFSIZE]; tb_size_t size = xm_sandbox_readline(data + 7, sizeof(data) - 7, prompt); if (size) { // split line '\0' if (data[size - 1] == '\n') { data[--size] = '\0'; } // patch "return " tb_memcpy(data, "return ", 7); // attempt to load "return ..." status = luaL_loadbuffer(lua, data, size + 7, "=stdin"); if (status != LUA_ERRSYNTAX) { return status; } // pop error msg lua_pop(lua, 1); // push line to load it again lua_pushstring(lua, data + 7); } else return -1; // load input line while (1) { /* repeat until gets a complete line * * stack: arg1(sandbox_scope) scriptbuffer(top) -> ... * after: arg1(sandbox_scope) scriptbuffer scriptfunc(top) -> ... */ status = luaL_loadbuffer(lua, lua_tostring(lua, -1), (size_t)lua_strlen(lua, -1), "=stdin"); // complete? if (!xm_sandbox_incomplete(lua, status)) { break; } // get more input if (!xm_sandbox_pushline(lua, prompt2)) { return -1; } // cancel multi-line input? if (!tb_strcmp(lua_tostring(lua, -1), "q")) { lua_pop(lua, 2); lua_pushstring(lua, "return "); continue; } /* add a new line * * stack: arg1 scriptbuffer scriptfunc scriptbuffer "\n"(top) -> ... */ lua_pushliteral(lua, "\n"); // between the two lines lua_insert(lua, -2); /* join them * * stack: arg1 scriptbuffer scriptfunc scriptbuffer scriptbuffer "\n"(top) -> ... * after: arg1 scriptbuffer scriptfunc scriptbuffer+"\n"(top) -> ... */ lua_concat(lua, 3); } // remove redundant scriptbuffer lua_remove(lua, -2); return status; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // sandbox.interactive() tb_int_t xm_sandbox_interactive(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); /* get init stack top * * stack: arg1(sandbox_scope) */ tb_int_t top = lua_gettop(lua); // enter interactive tb_int_t status; while ((status = xm_sandbox_loadline(lua, top)) != -1) { // execute codes if (status == 0) { /* bind sandbox * * stack: arg1(top) scriptfunc arg1(sandbox_scope) -> ... */ #ifdef USE_LUAJIT lua_pushvalue(lua, 1); lua_setfenv(lua, -2); #else // stack: arg1(top) scriptfunc $interactive_setfenv scriptfunc arg1(sandbox_scope) -> ... lua_getfield(lua, 1, "$interactive_setfenv"); lua_pushvalue(lua, -2); lua_pushvalue(lua, 1); if (lua_pcall(lua, 2, 0, 0) != 0) { tb_printl(lua_pushfstring(lua, "error calling " LUA_QL("$interactive_setfenv") " (%s)", lua_tostring(lua, -1))); } #endif /* run script * * stack: arg1(top) scriptfunc -> ... */ status = xm_sandbox_docall(lua, 0, 0); } // report errors if (status) { xm_sandbox_report(lua); } // print any results if (status == 0 && lua_gettop(lua) > top) { // get results count tb_int_t count = lua_gettop(lua) - top; /* dump results * * stack: arg1(sandbox_scope) [results] -> ... * after: arg1(sandbox_scope) $interactive_dump [results] -> ... */ lua_getfield(lua, 1, "$interactive_dump"); // load $interactive_dump() from sandbox_scope lua_insert(lua, -(count + 1)); if (lua_pcall(lua, count, 0, 0) != 0) { tb_printl( lua_pushfstring(lua, "error calling " LUA_QL("$interactive_dump") " (%s)", lua_tostring(lua, -1))); } } } // clear stack lua_settop(lua, top); tb_printl(""); tb_print_sync(); return 0; } ================================================ FILE: core/src/xmake/sandbox/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_SANDBOX_PREFIX_H #define XM_SANDBOX_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/semver/compare.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author uael * @file compare.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "compare" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // semver.compare("v1.0.1-beta", "1.2") > 0? tb_int_t xm_semver_compare(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the version1 string tb_char_t const *version1_str = luaL_checkstring(lua, 1); tb_check_return_val(version1_str, 0); // get the version2 string tb_char_t const *version2_str = luaL_checkstring(lua, 2); tb_check_return_val(version2_str, 0); // try to parse version1 string semver_t semver1 = { 0 }; if (semver_tryn(&semver1, version1_str, tb_strlen(version1_str))) { lua_pushnil(lua); lua_pushfstring(lua, "unable to parse semver '%s'", version1_str); return 2; } // try to parse version2 string semver_t semver2 = { 0 }; if (semver_tryn(&semver2, version2_str, tb_strlen(version2_str))) { lua_pushnil(lua); lua_pushfstring(lua, "unable to parse semver '%s'", version2_str); return 2; } // do compare lua_pushinteger(lua, semver_pcmp(&semver1, &semver2)); semver_dtor(&semver1); semver_dtor(&semver2); return 1; } ================================================ FILE: core/src/xmake/semver/parse.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author uael * @file parse.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "parse" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* version = semver.parse("v1.0.1-beta") * * { patch = 1 , raw = v1.0.1-beta , version = v1.0.1-beta , major = 1 , build = { } , minor = 0 , prerelease = { beta } } * */ tb_int_t xm_semver_parse(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the version string tb_char_t const *version_str = luaL_checkstring(lua, 1); tb_check_return_val(version_str, 0); // try to parse version string semver_t semver = { 0 }; if (semver_tryn(&semver, version_str, tb_strlen(version_str))) { lua_pushnil(lua); lua_pushfstring(lua, "unable to parse semver '%s'", version_str); return 2; } lua_pushsemver(lua, &semver); semver_dtor(&semver); return 1; } ================================================ FILE: core/src/xmake/semver/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author uael * @file prefix.h * */ #ifndef XM_SEMVER_PREFIX_H #define XM_SEMVER_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #include "semver.h" /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ __tb_extern_c_enter__ /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ /* push struct semver * * @param lua the lua context * @param semver the semver struct * */ tb_void_t lua_pushsemver(lua_State *lua, semver_t const *semver); /* ////////////////////////////////////////////////////////////////////////////////////// * leave */ __tb_extern_c_leave__ #endif ================================================ FILE: core/src/xmake/semver/satisfies.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author uael * @file satisfies.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "satisfies" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* satisfies the given version range? * * semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') => true */ tb_int_t xm_semver_satisfies(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the version string tb_char_t const *version_str = luaL_checkstring(lua, 1); tb_char_t const *range_str = luaL_checkstring(lua, 2); tb_assert_and_check_return_val(version_str && range_str, 0); // parse the version range string semver_range_t range = { 0 }; if (semver_rangen(&range, range_str, tb_strlen(range_str))) { // range is branch name? try to match it semver_t range_semver = { 0 }; if (!tb_strcmp(version_str, range_str)) { lua_pushboolean(lua, tb_true); return 1; } // range is a single version? try to compare it else if (!semver_tryn(&range_semver, range_str, tb_strlen(range_str))) { semver_t semver = { 0 }; if (!semver_tryn(&semver, version_str, tb_strlen(version_str))) { lua_pushboolean(lua, semver_pcmp(&semver, &range_semver) == 0); semver_dtor(&semver); semver_dtor(&range_semver); return 1; } else { semver_dtor(&range_semver); lua_pushnil(lua); lua_pushfstring(lua, "unable to parse semver '%s'", version_str); return 2; } } else { lua_pushnil(lua); lua_pushfstring(lua, "unable to parse semver range '%s'", range_str); return 2; } } // try to parse the version string semver_t semver = { 0 }; if (semver_tryn(&semver, version_str, tb_strlen(version_str))) { lua_pushnil(lua); lua_pushfstring(lua, "unable to parse semver '%s'", version_str); return 2; } // satisfies this range? lua_pushboolean(lua, semver_range_match(semver, range)); semver_dtor(&semver); semver_range_dtor(&range); return 1; } ================================================ FILE: core/src/xmake/semver/select.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author uael * @file select.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "select" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_semver_select_from_versions_tags1( lua_State *lua, tb_int_t fromidx, semver_t *semver, semver_range_t const *range, semvers_t *matches) { // clear matches semvers_pclear(matches); // select all matches lua_Integer i = 0; luaL_checktype(lua, fromidx, LUA_TTABLE); for (i = lua_objlen(lua, fromidx); i > 0; --i) { lua_pushinteger(lua, i); lua_gettable(lua, fromidx); tb_char_t const *source_str = luaL_checkstring(lua, -1); if (source_str && semver_tryn(semver, source_str, tb_strlen(source_str)) == 0) { if (semver_range_pmatch(semver, range)) { semvers_ppush(matches, *semver); } else { semver_dtor(semver); } } lua_pop(lua, 1); } // no matches? tb_check_return_val(matches->length, tb_false); // sort matches semvers_psort(matches); // get the newest version semver_t top = semvers_ppop(matches); lua_createtable(lua, 0, 2); // return results lua_pushstring(lua, top.raw); lua_setfield(lua, -2, "version"); lua_pushstring(lua, fromidx == 2 ? "version" : "tag"); lua_setfield(lua, -2, "source"); // exit the popped semver semver_dtor(&top); return tb_true; } static tb_bool_t xm_semver_select_from_versions_tags2( lua_State *lua, tb_int_t fromidx, semver_t *semver, tb_char_t const *version_str, tb_size_t version_len) { lua_Integer i = 0; luaL_checktype(lua, fromidx, LUA_TTABLE); for (i = lua_objlen(lua, fromidx); i > 0; --i) { lua_pushinteger(lua, i); lua_gettable(lua, fromidx); tb_char_t const *source_str = luaL_checkstring(lua, -1); tb_size_t source_len = tb_strlen(source_str); lua_pop(lua, 1); if (source_len == version_len && tb_strncmp(source_str, version_str, version_len) == 0) { lua_createtable(lua, 0, 2); lua_pushlstring(lua, source_str, source_len); lua_setfield(lua, -2, "version"); lua_pushstring(lua, fromidx == 2 ? "version" : "tag"); lua_setfield(lua, -2, "source"); return tb_true; } } return tb_false; } static tb_bool_t xm_semver_select_from_branches(lua_State *lua, tb_int_t fromidx, tb_char_t const *range_str, tb_size_t range_len) { lua_Integer i = 0; luaL_checktype(lua, fromidx, LUA_TTABLE); for (i = lua_objlen(lua, fromidx); i > 0; --i) { lua_pushinteger(lua, i); lua_gettable(lua, fromidx); tb_char_t const *source_str = luaL_checkstring(lua, -1); tb_size_t source_len = tb_strlen(source_str); lua_pop(lua, 1); if (source_len == range_len && tb_memcmp(source_str, range_str, source_len) == 0) { lua_createtable(lua, 0, 2); lua_pushlstring(lua, source_str, source_len); lua_setfield(lua, -2, "version"); lua_pushstring(lua, "branch"); lua_setfield(lua, -2, "source"); return tb_true; } } return tb_false; } static tb_bool_t xm_semver_select_latest_from_versions_tags(lua_State *lua, tb_int_t fromidx, semver_t *semver, semvers_t *matches) { // clear matches semvers_pclear(matches); // push all versions to matches lua_Integer i = 0; luaL_checktype(lua, fromidx, LUA_TTABLE); for (i = lua_objlen(lua, fromidx); i > 0; --i) { lua_pushinteger(lua, i); lua_gettable(lua, fromidx); tb_char_t const *source_str = luaL_checkstring(lua, -1); if (source_str && semver_tryn(semver, source_str, tb_strlen(source_str)) == 0) { semvers_ppush(matches, *semver); } lua_pop(lua, 1); } tb_check_return_val(matches->length, tb_false); // sort matches semvers_psort(matches); // get the newest match semver_t top = semvers_ppop(matches); lua_createtable(lua, 0, 2); // return results lua_pushstring(lua, top.raw); lua_setfield(lua, -2, "version"); lua_pushstring(lua, fromidx == 2 ? "version" : "tag"); lua_setfield(lua, -2, "source"); semver_dtor(&top); return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* select version * * local versioninfo, errors = semver.select(">=1.5.0 <1.6", {"1.5.0", "1.5.1"}, {"v1.5.0", ..}, {"latest", "dev"}) */ tb_int_t xm_semver_select(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // select version tb_bool_t ok = tb_false; tb_bool_t is_range = tb_false; tb_char_t const *range_str = tb_null; semver_t semver = { 0 }; semvers_t matches = { 0 }; semver_range_t range = { 0 }; do { // get the version range string range_str = luaL_checkstring(lua, 1); tb_check_break(range_str); // get the range string length tb_size_t range_len = tb_strlen(range_str); // parse the version range string is_range = semver_rangen(&range, range_str, range_len) == 0; if (is_range) { // attempt to select version from the versions list first if (xm_semver_select_from_versions_tags1(lua, 2, &semver, &range, &matches)) { ok = tb_true; break; } // attempt to select version from the tags list if (xm_semver_select_from_versions_tags1(lua, 3, &semver, &range, &matches)) { ok = tb_true; break; } } else { // attempt to select version from the versions list first if (xm_semver_select_from_versions_tags2(lua, 2, &semver, range_str, range_len)) { ok = tb_true; break; } // attempt to select version from the tags list if (xm_semver_select_from_versions_tags2(lua, 3, &semver, range_str, range_len)) { ok = tb_true; break; } } // attempt to select version from the branches if (xm_semver_select_from_branches(lua, 4, range_str, range_len)) { ok = tb_true; break; } // select the latest version from the tags and versions if be latest if (!tb_strcmp(range_str, "latest")) { // attempt to select latest version from the versions list if (xm_semver_select_latest_from_versions_tags(lua, 2, &semver, &matches)) { ok = tb_true; break; } // attempt to select latest version from the tags list if (xm_semver_select_latest_from_versions_tags(lua, 3, &semver, &matches)) { ok = tb_true; break; } } } while (0); // exit matches semvers_dtor(matches); // exit range semver_range_dtor(&range); // failed? if (!ok) { if (!is_range) { lua_pushnil(lua); lua_pushfstring(lua, "unable to parse semver range '%s'", range_str); } lua_pushnil(lua); lua_pushfstring(lua, "unable to select version for range '%s'", range_str); return 2; } return 1; } ================================================ FILE: core/src/xmake/semver/semver.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author uael * @file semver.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "semver" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_void_t lua_pushsemver(lua_State *lua, semver_t const *semver) { tb_assert(lua && semver); // return a semver table lua_createtable(lua, 0, 7); lua_pushstring(lua, semver->raw); lua_setfield(lua, -2, "raw"); lua_pushlstring(lua, semver->raw, semver->len); lua_setfield(lua, -2, "version"); lua_pushinteger(lua, semver->major); lua_setfield(lua, -2, "major"); lua_pushinteger(lua, semver->minor); lua_setfield(lua, -2, "minor"); lua_pushinteger(lua, semver->patch); lua_setfield(lua, -2, "patch"); // push prelease table lua_pushstring(lua, "prerelease"); lua_newtable(lua); tb_uchar_t i = 0; semver_id_t const *id = &semver->prerelease; while (id && id->len) { if (id->numeric) { lua_pushinteger(lua, id->num); } else { lua_pushlstring(lua, id->raw, id->len); } id = id->next; lua_rawseti(lua, -2, ++i); } lua_settable(lua, -3); // push the build table i = 0; lua_pushstring(lua, "build"); lua_newtable(lua); id = &semver->build; while (id && id->len) { if (id->numeric) { lua_pushinteger(lua, id->num); } else { lua_pushlstring(lua, id->raw, id->len); } id = id->next; lua_rawseti(lua, -2, ++i); } lua_settable(lua, -3); } ================================================ FILE: core/src/xmake/string/convert.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file convert.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "convert" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "../utils/charset.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* convert string * * @param str the string * @param ftype the from-charset type, e.g. ascii, gb2312, gbk, ios8859, ucs2, ucs4, utf8, utf16, utf32 * @param ttype the to-charset type * * @code * local result = string.convert(str, "gbk", "utf8") * local result = string.convert(str, "utf8", "gb2312") * @endcode */ tb_int_t xm_string_convert(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the string and charset types size_t src_size = 0; tb_char_t const *src_cstr = luaL_checklstring(lua, 1, &src_size); tb_char_t const *ftype_cstr = luaL_checkstring(lua, 2); tb_char_t const *ttype_cstr = luaL_checkstring(lua, 3); tb_check_return_val(src_cstr && ftype_cstr && ttype_cstr, 0); // find charsets xm_charset_entry_ref_t fcharset = xm_charset_find_by_name(ftype_cstr); xm_charset_entry_ref_t tcharset = xm_charset_find_by_name(ttype_cstr); luaL_argcheck(lua, fcharset, 2, "charset not found"); luaL_argcheck(lua, tcharset, 3, "charset not found"); tb_check_return_val(fcharset && tcharset, 0); // empty string? if (!src_size) { lua_pushstring(lua, ""); } else { // convert string tb_long_t dst_size = 0; tb_size_t dst_maxn = (tb_size_t)src_size << 2; tb_byte_t *dst_data = tb_malloc_bytes(dst_maxn); if (dst_data && dst_maxn && (dst_size = tb_charset_conv_data(fcharset->type, tcharset->type, (tb_byte_t const *)src_cstr, (tb_size_t)src_size, dst_data, dst_maxn)) >= 0 && dst_size < dst_maxn) { lua_pushlstring(lua, (tb_char_t const *)dst_data, dst_size); } else { lua_pushnil(lua); } tb_free(dst_data); } return 1; } ================================================ FILE: core/src/xmake/string/endswith.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file endswith.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "endswith" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_string_endswith(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the string and suffix size_t string_size = 0; size_t suffix_size = 0; tb_char_t const *string = luaL_checklstring(lua, 1, &string_size); tb_char_t const *suffix = luaL_checklstring(lua, 2, &suffix_size); tb_check_return_val(string && suffix, 0); // string:endswith(suffix)? lua_pushboolean(lua, string_size >= suffix_size && !tb_strcmp(string + string_size - suffix_size, suffix)); return 1; } ================================================ FILE: core/src/xmake/string/lastof.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file lastof.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "string_lastof" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "../utf8/utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* lastof string (only support plain text) * * @param str the string * @param substr the substring */ tb_int_t xm_string_lastof(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get string size_t nstr = 0; tb_char_t const *cstr = luaL_checklstring(lua, 1, &nstr); // get substring size_t nsubstr = 0; tb_char_t const *csubstr = luaL_checklstring(lua, 2, &nsubstr); // lastof it tb_long_t char_pos = xm_utf8_lastof_impl(cstr, nstr, csubstr, nsubstr); if (char_pos > 0) { lua_pushinteger(lua, char_pos); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/string/lower.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author luadebug, ruki * @file lower.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* string.lower * * @param str the string * * @code * local result = string.lower(str) * @endcode */ tb_int_t xm_string_lower(lua_State *lua) { // check tb_assert_and_check_return_val(lua, 0); // get string size_t size = 0; tb_char_t const* cstr = luaL_checklstring(lua, 1, &size); tb_check_return_val(cstr, 0); // empty? if (!size) { lua_pushstring(lua, ""); return 1; } // copy string to buffer tb_char_t* buffer = (tb_char_t*)tb_malloc_bytes(size + 1); if (buffer) { tb_memcpy(buffer, cstr, size); buffer[size] = '\0'; // to lower tb_long_t real_size = tb_charset_utf8_tolower(buffer, size); // push result if (real_size >= 0) { lua_pushlstring(lua, buffer, real_size); } else { lua_pushlstring(lua, cstr, size); } tb_free(buffer); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/string/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_STRING_PREFIX_H #define XM_STRING_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/string/split.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file split.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "string_split" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_string_split_str(lua_State *lua, tb_char_t const *cstr, tb_size_t nstr, tb_char_t const *cdls, tb_size_t ndls, tb_bool_t strict, tb_int_t limit) { tb_int_t num = 0; tb_char_t const *end = cstr + nstr; tb_char_t const *pos = tb_strstr(cstr, cdls); // faster than tb_strnstr() while (pos && pos < end) { if (pos > cstr || strict) { if (limit > 0 && num + 1 >= limit) { break; } lua_pushlstring(lua, cstr, pos - cstr); lua_rawseti(lua, -2, ++num); } cstr = pos + ndls; pos = tb_strstr(cstr, cdls); } if (cstr < end) { lua_pushlstring(lua, cstr, end - cstr); lua_rawseti(lua, -2, ++num); } else if (strict && (limit < 0 || num < limit) && cstr == end) { lua_pushliteral(lua, ""); lua_rawseti(lua, -2, ++num); } } static tb_void_t xm_string_split_chr( lua_State *lua, tb_char_t const *cstr, tb_size_t nstr, tb_char_t ch, tb_bool_t strict, tb_int_t limit) { tb_int_t num = 0; tb_char_t const *end = cstr + nstr; tb_char_t const *pos = tb_strchr(cstr, ch); // faster than tb_strnchr() while (pos && pos < end) { if (pos > cstr || strict) { if (limit > 0 && num + 1 >= limit) { break; } lua_pushlstring(lua, cstr, pos - cstr); lua_rawseti(lua, -2, ++num); } cstr = pos + 1; pos = tb_strchr(cstr, ch); } if (cstr < end) { lua_pushlstring(lua, cstr, end - cstr); lua_rawseti(lua, -2, ++num); } else if (strict && (limit < 0 || num < limit) && cstr == end) { lua_pushliteral(lua, ""); lua_rawseti(lua, -2, ++num); } } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* split string (only support plain text) * * @param str the string * @param delimiter the delimiter * @param strict is strict? * @param limit the limit count */ tb_int_t xm_string_split(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get string size_t nstr = 0; tb_char_t const *cstr = luaL_checklstring(lua, 1, &nstr); // get delimiter size_t ndls = 0; tb_char_t const *cdls = luaL_checklstring(lua, 2, &ndls); // is strict? tb_bool_t const strict = (tb_bool_t)lua_toboolean(lua, 3); // get limit count tb_int_t const limit = (tb_int_t)luaL_optinteger(lua, 4, -1); // split it lua_newtable(lua); if (ndls == 1) { xm_string_split_chr(lua, cstr, (tb_size_t)nstr, cdls[0], strict, limit); } else { xm_string_split_str(lua, cstr, (tb_size_t)nstr, cdls, ndls, strict, limit); } return 1; } ================================================ FILE: core/src/xmake/string/startswith.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file startswith.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "startswith" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_string_startswith(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the string and prefix size_t prefix_size = 0; tb_char_t const *string = luaL_checkstring(lua, 1); tb_char_t const *prefix = luaL_checklstring(lua, 2, &prefix_size); tb_check_return_val(string && prefix, 0); // string:startswith(prefix)? lua_pushboolean(lua, !tb_strncmp(string, prefix, (tb_size_t)prefix_size)); return 1; } ================================================ FILE: core/src/xmake/string/trim.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu * @file trim.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "string_trim" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_string_trim_space(tb_char_t const **psstr, tb_char_t const **pestr, tb_int_t mode) { tb_assert(psstr && pestr && *psstr && *pestr); tb_char_t const *p = *psstr; tb_char_t const *e = *pestr; // trim left? if (mode <= 0) { while (p < e && tb_isspace(*p)) { p++; } } // trim right if (mode >= 0) { e--; while (e >= p && tb_isspace(*e)) { e--; } e++; } // save trimed string *psstr = p; *pestr = e; } static tb_char_t const *xm_string_ltrim(tb_char_t const *sstr, tb_char_t const *estr, tb_char_t const *ctrim, size_t ntrim) { tb_assert(sstr && estr && ctrim); tb_char_t const *p = sstr; while (p < estr && tb_strnchr(ctrim, ntrim, *p)) { p++; } return p; } static tb_char_t const *xm_string_rtrim(tb_char_t const *sstr, tb_char_t const *estr, tb_char_t const *ctrim, size_t ntrim) { tb_assert(sstr && estr && ctrim); tb_char_t const *p = estr - 1; while (p >= sstr && tb_strnchr(ctrim, ntrim, *p)) { p--; } return p + 1; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* trim string * * @param str the string * @param trimchars the chars to trim * @param trimtype 0 to trim left and right, -1 to trim left, 1 to trim right * * @code * local result = string.trim(str, "\r\n \v\t", 0) * local result = string.trim(str, "(", -1) * @endcode */ tb_int_t xm_string_trim(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); size_t lstr, ltrim; tb_char_t const *sstr = luaL_checklstring(lua, 1, &lstr); tb_char_t const *estr = sstr + lstr; tb_char_t const *trimchars = luaL_optlstring(lua, 2, "", <rim); tb_int_t const trimtype = (tb_int_t)luaL_optinteger(lua, 3, 0); do { tb_assert_and_check_break(sstr && trimchars); tb_check_break(lstr != 0); tb_char_t const *const rsstr = sstr; tb_char_t const *const restr = estr; if (ltrim == 0) { xm_string_trim_space(&sstr, &estr, trimtype); } else { // trim chars if (trimtype <= 0) { sstr = xm_string_ltrim(sstr, estr, trimchars, ltrim); } if (trimtype >= 0) { estr = xm_string_rtrim(sstr, estr, trimchars, ltrim); } } // no trimed chars tb_check_break(sstr != rsstr || estr != restr); lua_pushlstring(lua, sstr, estr - sstr); return 1; } while (0); // return orignal value lua_settop(lua, 1); return 1; } ================================================ FILE: core/src/xmake/string/upper.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author luadebug, ruki * @file upper.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* string.upper * * @param str the string * * @code * local result = (str) * @endcode */ tb_int_t xm_string_upper(lua_State *lua) { // check tb_assert_and_check_return_val(lua, 0); // get string size_t size = 0; tb_char_t const* cstr = luaL_checklstring(lua, 1, &size); tb_check_return_val(cstr, 0); // empty? if (!size) { lua_pushstring(lua, ""); return 1; } // copy string to buffer tb_char_t* buffer = (tb_char_t*)tb_malloc_bytes(size + 1); if (buffer) { tb_memcpy(buffer, cstr, size); buffer[size] = '\0'; // to upper tb_long_t real_size = tb_charset_utf8_toupper(buffer, size); // push result if (real_size >= 0) { lua_pushlstring(lua, buffer, real_size); } else { lua_pushlstring(lua, cstr, size); } tb_free(buffer); } else { lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/thread/event_exit.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file event_exit.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_event" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_event_exit(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1); tb_assert_and_check_return_val(thread_event && thread_event->handle, 0); if (tb_atomic_fetch_and_sub(&thread_event->refn, 1) == 1) { if (thread_event->handle) { tb_event_exit(thread_event->handle); thread_event->handle = tb_null; } tb_free(thread_event); } lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/event_incref.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file event_incref.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_event" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_event_incref(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1); tb_assert_and_check_return_val(thread_event && thread_event->handle, 0); lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_event->refn, 1) >= 1); return 1; } ================================================ FILE: core/src/xmake/thread/event_init.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file event_init.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_event" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_event_init(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_bool_t ok = tb_false; xm_thread_event_t *thread_event = tb_null; do { thread_event = tb_malloc0_type(xm_thread_event_t); tb_assert_and_check_break(thread_event); thread_event->refn = 1; thread_event->handle = tb_event_init(); tb_assert_and_check_break(thread_event->handle); xm_lua_pushpointer(lua, (tb_pointer_t)thread_event); ok = tb_true; } while (0); if (!ok) { if (thread_event) { if (thread_event->handle) { tb_event_exit(thread_event->handle); thread_event->handle = tb_null; } tb_free(thread_event); } lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/thread/event_post.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file event_post.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_event" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_event_post(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1); tb_assert_and_check_return_val(thread_event && thread_event->handle, 0); lua_pushboolean(lua, tb_event_post(thread_event->handle)); return 1; } ================================================ FILE: core/src/xmake/thread/event_wait.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file event_wait.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_event" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_event_wait(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1); tb_assert_and_check_return_val(thread_event && thread_event->handle, 0); tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 2); lua_pushinteger(lua, tb_event_wait(thread_event->handle, timeout)); return 1; } ================================================ FILE: core/src/xmake/thread/mutex_exit.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mutex_exit.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_mutex" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_mutex_exit(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1); tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); if (tb_atomic_fetch_and_sub(&thread_mutex->refn, 1) == 1) { if (thread_mutex->handle) { tb_mutex_exit(thread_mutex->handle); thread_mutex->handle = tb_null; } tb_free(thread_mutex); } lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/mutex_incref.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mutex_incref.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_mutex" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_mutex_incref(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1); tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_mutex->refn, 1) >= 1); return 1; } ================================================ FILE: core/src/xmake/thread/mutex_init.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mutex_init.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_mutex" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_mutex_init(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_bool_t ok = tb_false; xm_thread_mutex_t *thread_mutex = tb_null; do { thread_mutex = tb_malloc0_type(xm_thread_mutex_t); tb_assert_and_check_break(thread_mutex); thread_mutex->refn = 1; thread_mutex->handle = tb_mutex_init(); tb_assert_and_check_break(thread_mutex->handle); xm_lua_pushpointer(lua, (tb_pointer_t)thread_mutex); ok = tb_true; } while (0); if (!ok) { if (thread_mutex) { if (thread_mutex->handle) { tb_mutex_exit(thread_mutex->handle); thread_mutex->handle = tb_null; } tb_free(thread_mutex); } lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/thread/mutex_lock.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mutex_lock.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_mutex" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_mutex_lock(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1); tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); lua_pushboolean(lua, tb_mutex_enter(thread_mutex->handle)); return 1; } ================================================ FILE: core/src/xmake/thread/mutex_trylock.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mutex_trylock.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_mutex" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_mutex_trylock(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1); tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); lua_pushboolean(lua, tb_mutex_enter_try(thread_mutex->handle)); return 1; } ================================================ FILE: core/src/xmake/thread/mutex_unlock.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file mutex_unlock.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_mutex" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_mutex_unlock(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1); tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); lua_pushboolean(lua, tb_mutex_leave(thread_mutex->handle)); return 1; } ================================================ FILE: core/src/xmake/thread/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_THREAD_PREFIX_H #define XM_THREAD_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the thread type typedef struct __xm_thread_t { tb_thread_ref_t handle; tb_string_t callback; tb_string_t callinfo; } xm_thread_t; // the thread value kind typedef enum __xm_thread_value_kind_e { XM_THREAD_VALUE_NIL = 0, XM_THREAD_VALUE_BOOL = 1, XM_THREAD_VALUE_INT = 2, XM_THREAD_VALUE_NUM = 3, XM_THREAD_VALUE_STR = 4 } xm_thread_value_kind_e; // the thread value type typedef struct __xm_thread_value_t { tb_uint32_t kind : 3; tb_uint32_t size : 29; union { tb_char_t *string; tb_bool_t boolean; lua_Integer integer; lua_Number number; } u; } xm_thread_value_t; // the thread event type typedef struct __xm_thread_event_t { tb_event_ref_t handle; tb_atomic_t refn; } xm_thread_event_t; // the thread mutex type typedef struct __xm_thread_mutex_t { tb_mutex_ref_t handle; tb_atomic_t refn; } xm_thread_mutex_t; // the thread semaphore type typedef struct __xm_thread_semaphore_t { tb_semaphore_ref_t handle; tb_atomic_t refn; } xm_thread_semaphore_t; // the thread queue type typedef struct __xm_thread_queue_t { tb_queue_ref_t handle; tb_atomic_t refn; } xm_thread_queue_t; // the thread sharedata type typedef struct __xm_thread_sharedata_t { xm_thread_value_t value; tb_buffer_t buffer; tb_atomic_t refn; } xm_thread_sharedata_t; // get the thread event from arguments static __tb_inline__ xm_thread_event_t *xm_thread_event_get(lua_State *lua, tb_int_t index) { xm_thread_event_t *thread_event = tb_null; if (xm_lua_isinteger(lua, index)) { thread_event = (xm_thread_event_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); } else if (xm_lua_ispointer(lua, index)) { thread_event = (xm_thread_event_t *)xm_lua_topointer(lua, index); } return thread_event; } // get the thread mutex from arguments static __tb_inline__ xm_thread_mutex_t *xm_thread_mutex_get(lua_State *lua, tb_int_t index) { xm_thread_mutex_t *thread_mutex = tb_null; if (xm_lua_isinteger(lua, index)) { thread_mutex = (xm_thread_mutex_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); } else if (xm_lua_ispointer(lua, index)) { thread_mutex = (xm_thread_mutex_t *)xm_lua_topointer(lua, index); } return thread_mutex; } // get the thread semaphore from arguments static __tb_inline__ xm_thread_semaphore_t *xm_thread_semaphore_get(lua_State *lua, tb_int_t index) { xm_thread_semaphore_t *thread_semaphore = tb_null; if (xm_lua_isinteger(lua, index)) { thread_semaphore = (xm_thread_semaphore_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); } else if (xm_lua_ispointer(lua, index)) { thread_semaphore = (xm_thread_semaphore_t *)xm_lua_topointer(lua, index); } return thread_semaphore; } // get the thread queue from arguments static __tb_inline__ xm_thread_queue_t *xm_thread_queue_get(lua_State *lua, tb_int_t index) { xm_thread_queue_t *thread_queue = tb_null; if (xm_lua_isinteger(lua, index)) { thread_queue = (xm_thread_queue_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); } else if (xm_lua_ispointer(lua, index)) { thread_queue = (xm_thread_queue_t *)xm_lua_topointer(lua, index); } return thread_queue; } // get the thread sharedata from arguments static __tb_inline__ xm_thread_sharedata_t *xm_thread_sharedata_get(lua_State *lua, tb_int_t index) { xm_thread_sharedata_t *thread_sharedata = tb_null; if (xm_lua_isinteger(lua, index)) { thread_sharedata = (xm_thread_sharedata_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); } else if (xm_lua_ispointer(lua, index)) { thread_sharedata = (xm_thread_sharedata_t *)xm_lua_topointer(lua, index); } return thread_sharedata; } #endif ================================================ FILE: core/src/xmake/thread/queue_clear.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file queue_clear.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_queue" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_queue_clear(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1); tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); tb_queue_clear(thread_queue->handle); lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/queue_exit.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file queue_exit.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_queue" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_queue_exit(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1); tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); if (tb_atomic_fetch_and_sub(&thread_queue->refn, 1) == 1) { if (thread_queue->handle) { tb_queue_exit(thread_queue->handle); thread_queue->handle = tb_null; } tb_free(thread_queue); } lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/queue_incref.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file queue_incref.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_queue" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_queue_incref(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1); tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_queue->refn, 1) >= 1); return 1; } ================================================ FILE: core/src/xmake/thread/queue_init.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file queue_init.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_queue" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_thread_value_free(tb_element_ref_t element, tb_pointer_t buff) { xm_thread_value_t *item = (xm_thread_value_t *)buff; if (item) { if (item->kind == XM_THREAD_VALUE_STR) { if (item->u.string) { tb_free((tb_pointer_t)item->u.string); } item->u.string = tb_null; } item->size = 0; } } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_queue_init(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_bool_t ok = tb_false; xm_thread_queue_t *thread_queue = tb_null; do { thread_queue = tb_malloc0_type(xm_thread_queue_t); tb_assert_and_check_break(thread_queue); thread_queue->refn = 1; thread_queue->handle = tb_queue_init(0, tb_element_mem(sizeof(xm_thread_value_t), xm_thread_value_free, tb_null)); tb_assert_and_check_break(thread_queue->handle); xm_lua_pushpointer(lua, (tb_pointer_t)thread_queue); ok = tb_true; } while (0); if (!ok) { if (thread_queue) { if (thread_queue->handle) { tb_queue_exit(thread_queue->handle); thread_queue->handle = tb_null; } tb_free(thread_queue); } lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/thread/queue_pop.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file queue_pop.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_queue" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_queue_pop(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1); tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); if (tb_queue_null(thread_queue->handle)) { lua_pushnil(lua); lua_pushliteral(lua, "the thread queue is empty"); return 2; } xm_thread_value_t *item = (xm_thread_value_t *)tb_queue_get(thread_queue->handle); tb_assert_and_check_return_val(item, 0); tb_bool_t ok = tb_false; switch (item->kind) { case XM_THREAD_VALUE_STR: if (item->size) { lua_pushlstring(lua, item->u.string, item->size); } else { lua_pushliteral(lua, ""); } ok = tb_true; break; case XM_THREAD_VALUE_INT: lua_pushinteger(lua, item->u.integer); ok = tb_true; break; case XM_THREAD_VALUE_NUM: lua_pushnumber(lua, item->u.number); ok = tb_true; break; case XM_THREAD_VALUE_BOOL: lua_pushboolean(lua, item->u.boolean); ok = tb_true; break; case XM_THREAD_VALUE_NIL: lua_pushnil(lua); ok = tb_true; break; default: break; } if (!ok) { lua_pushnil(lua); lua_pushliteral(lua, "invalid thread queue item"); return 2; } tb_queue_pop(thread_queue->handle); return 1; } ================================================ FILE: core/src/xmake/thread/queue_push.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file queue_push.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_queue" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_queue_push(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1); tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); if (tb_queue_full(thread_queue->handle)) { lua_pushboolean(lua, tb_false); lua_pushliteral(lua, "the thread queue is full"); return 2; } xm_thread_value_t item; if (lua_isstring(lua, 2)) { size_t data_size = 0; tb_char_t const *data = luaL_checklstring(lua, 2, &data_size); tb_assert_and_check_return_val(data, 0); item.kind = (tb_uint32_t)XM_THREAD_VALUE_STR; item.size = (tb_uint32_t)data_size; if (data_size) { item.u.string = tb_malloc_cstr(data_size); tb_assert_and_check_return_val(item.u.string, 0); tb_memcpy(item.u.string, data, data_size); } } else if (xm_lua_isinteger(lua, 2)) { item.kind = (tb_uint32_t)XM_THREAD_VALUE_INT; item.u.integer = lua_tointeger(lua, 2); } else if (lua_isnumber(lua, 2)) { item.kind = (tb_uint32_t)XM_THREAD_VALUE_NUM; item.u.number = lua_tonumber(lua, 2); } else if (lua_isboolean(lua, 2)) { item.kind = (tb_uint32_t)XM_THREAD_VALUE_BOOL; item.u.boolean = lua_toboolean(lua, 2); } else if (lua_isnil(lua, 2)) { item.kind = (tb_uint32_t)XM_THREAD_VALUE_NIL; } else { lua_pushboolean(lua, tb_false); lua_pushliteral(lua, "unsupported thread queue item"); return 2; } tb_queue_put(thread_queue->handle, &item); lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/queue_size.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file queue_size.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_queue" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_queue_size(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1); tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); lua_pushinteger(lua, (tb_int_t)tb_queue_size(thread_queue->handle)); return 1; } ================================================ FILE: core/src/xmake/thread/semaphore_exit.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file semaphore_exit.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_semaphore" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_semaphore_exit(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1); tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0); if (tb_atomic_fetch_and_sub(&thread_semaphore->refn, 1) == 1) { if (thread_semaphore->handle) { tb_semaphore_exit(thread_semaphore->handle); thread_semaphore->handle = tb_null; } tb_free(thread_semaphore); } lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/semaphore_incref.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file semaphore_incref.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_semaphore" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_semaphore_incref(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1); tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0); lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_semaphore->refn, 1) >= 1); return 1; } ================================================ FILE: core/src/xmake/thread/semaphore_init.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file semaphore_init.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_semaphore" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_semaphore_init(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_bool_t ok = tb_false; xm_thread_semaphore_t *thread_semaphore = tb_null; do { tb_long_t value = (tb_long_t)luaL_checknumber(lua, 1); thread_semaphore = tb_malloc0_type(xm_thread_semaphore_t); tb_assert_and_check_break(thread_semaphore); thread_semaphore->refn = 1; thread_semaphore->handle = tb_semaphore_init(value); tb_assert_and_check_break(thread_semaphore->handle); xm_lua_pushpointer(lua, (tb_pointer_t)thread_semaphore); ok = tb_true; } while (0); if (!ok) { if (thread_semaphore) { if (thread_semaphore->handle) { tb_semaphore_exit(thread_semaphore->handle); thread_semaphore->handle = tb_null; } tb_free(thread_semaphore); } lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/thread/semaphore_post.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file semaphore_post.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_semaphore" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_semaphore_post(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1); tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0); tb_long_t value = (tb_long_t)luaL_checknumber(lua, 2); lua_pushboolean(lua, tb_semaphore_post(thread_semaphore->handle, value)); return 1; } ================================================ FILE: core/src/xmake/thread/semaphore_wait.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file semaphore_wait.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_semaphore" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_semaphore_wait(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1); tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0); tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 2); lua_pushinteger(lua, tb_semaphore_wait(thread_semaphore->handle, timeout)); return 1; } ================================================ FILE: core/src/xmake/thread/sharedata_clear.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sharedata_clear.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_sharedata" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_sharedata_clear(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1); tb_assert_and_check_return_val(thread_sharedata, 0); thread_sharedata->value.kind = XM_THREAD_VALUE_NIL; tb_buffer_clear(&thread_sharedata->buffer); lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/sharedata_exit.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sharedata_exit.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_sharedata" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_sharedata_exit(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1); tb_assert_and_check_return_val(thread_sharedata, 0); if (tb_atomic_fetch_and_sub(&thread_sharedata->refn, 1) == 1) { tb_buffer_exit(&thread_sharedata->buffer); tb_free(thread_sharedata); } lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/sharedata_get.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sharedata_get.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_sharedata" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_sharedata_get_(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1); tb_assert_and_check_return_val(thread_sharedata, 0); tb_bool_t ok = tb_false; switch (thread_sharedata->value.kind) { case XM_THREAD_VALUE_STR: if (tb_buffer_size(&thread_sharedata->buffer) > 0) { lua_pushlstring(lua, (tb_char_t *)tb_buffer_data(&thread_sharedata->buffer), tb_buffer_size(&thread_sharedata->buffer)); } else { lua_pushliteral(lua, ""); } ok = tb_true; break; case XM_THREAD_VALUE_INT: lua_pushinteger(lua, thread_sharedata->value.u.integer); ok = tb_true; break; case XM_THREAD_VALUE_NUM: lua_pushnumber(lua, thread_sharedata->value.u.number); ok = tb_true; break; case XM_THREAD_VALUE_BOOL: lua_pushboolean(lua, thread_sharedata->value.u.boolean); ok = tb_true; break; case XM_THREAD_VALUE_NIL: lua_pushnil(lua); ok = tb_true; break; default: break; } if (!ok) { lua_pushnil(lua); lua_pushliteral(lua, "invalid thread sharedata thread_sharedata"); return 2; } return 1; } ================================================ FILE: core/src/xmake/thread/sharedata_incref.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sharedata_incref.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_sharedata" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_sharedata_incref(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1); tb_assert_and_check_return_val(thread_sharedata, 0); lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_sharedata->refn, 1) >= 1); return 1; } ================================================ FILE: core/src/xmake/thread/sharedata_init.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sharedata_init.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_sharedata" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_sharedata_init(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_bool_t ok = tb_false; xm_thread_sharedata_t *thread_sharedata = tb_null; do { thread_sharedata = tb_malloc0_type(xm_thread_sharedata_t); tb_assert_and_check_break(thread_sharedata); thread_sharedata->refn = 1; thread_sharedata->value.kind = XM_THREAD_VALUE_NIL; tb_buffer_init(&thread_sharedata->buffer); xm_lua_pushpointer(lua, (tb_pointer_t)thread_sharedata); ok = tb_true; } while (0); if (!ok) { if (thread_sharedata) { tb_buffer_exit(&thread_sharedata->buffer); tb_free(thread_sharedata); } lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/thread/sharedata_set.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sharedata_set.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread_sharedata" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_sharedata_set(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1); tb_assert_and_check_return_val(thread_sharedata, 0); if (lua_isstring(lua, 2)) { size_t data_size = 0; tb_char_t const *data = luaL_checklstring(lua, 2, &data_size); tb_assert_and_check_return_val(data, 0); thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_STR; if (data_size) { tb_buffer_memncpy(&thread_sharedata->buffer, (tb_byte_t const *)data, data_size); } else { tb_buffer_clear(&thread_sharedata->buffer); } } else if (xm_lua_isinteger(lua, 2)) { thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_INT; thread_sharedata->value.u.integer = lua_tointeger(lua, 2); } else if (lua_isnumber(lua, 2)) { thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_NUM; thread_sharedata->value.u.number = lua_tonumber(lua, 2); } else if (lua_isboolean(lua, 2)) { thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_BOOL; thread_sharedata->value.u.boolean = lua_toboolean(lua, 2); } else if (lua_isnil(lua, 2)) { thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_NIL; } else { lua_pushboolean(lua, tb_false); lua_pushliteral(lua, "unsupported thread sharedata item"); return 2; } lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/thread_exit.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file thread_exit.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_exit(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get thread xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1); tb_check_return_val(thread, 0); // exit thread if (thread) { tb_string_exit(&thread->callback); tb_string_exit(&thread->callinfo); if (thread->handle) { tb_thread_exit(thread->handle); thread->handle = tb_null; } tb_free(thread); } lua_pushboolean(lua, tb_true); return 1; } ================================================ FILE: core/src/xmake/thread/thread_init.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file thread_init.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "../engine.h" #include "../engine_pool.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_THREAD_ENGINE_NAME "xmake" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_int_t xm_thread_func(tb_cpointer_t priv) { xm_thread_t *thread = (xm_thread_t *)priv; tb_assert_and_check_return_val(thread, 0); xm_engine_ref_t engine = xm_engine_pool_alloc(xm_engine_pool()); if (!engine) { engine = xm_engine_init(XM_THREAD_ENGINE_NAME, tb_null); } if (engine) { lua_State *lua = xm_engine_lua(engine); tb_assert(lua); // pass callback tb_char_t const *callback_data = tb_string_cstr(&thread->callback); tb_size_t callback_size = tb_string_size(&thread->callback); if (callback_data && callback_size) { lua_pushlstring(lua, callback_data, callback_size); lua_setglobal(lua, "_THREAD_CALLBACK"); } // pass callinfo tb_char_t const *callinfo_data = tb_string_cstr(&thread->callinfo); tb_size_t callinfo_size = tb_string_size(&thread->callinfo); if (callinfo_data && callinfo_size) { lua_pushlstring(lua, callinfo_data, callinfo_size); lua_setglobal(lua, "_THREAD_CALLINFO"); } // start engine tb_char_t *argv[] = { XM_THREAD_ENGINE_NAME, tb_null }; xm_engine_main(engine, 1, argv, tb_null); if (!xm_engine_pool_free(xm_engine_pool(), engine)) { xm_engine_exit(engine); } } return 0; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_init(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_bool_t ok = tb_false; xm_thread_t *thread = tb_null; do { // get thread name tb_char_t const *name = luaL_checkstring(lua, 1); // get callback size_t callback_size = 0; tb_char_t const *callback_data = luaL_checklstring(lua, 2, &callback_size); tb_assert_and_check_break(callback_data && callback_size); // get callinfo size_t callinfo_size = 0; tb_char_t const *callinfo_data = luaL_checklstring(lua, 3, &callinfo_size); tb_assert_and_check_break(callinfo_data && callinfo_size); // get stack size tb_size_t stacksize = (tb_size_t)luaL_checkinteger(lua, 4); // init thread thread = tb_malloc0_type(xm_thread_t); tb_assert_and_check_break(thread); tb_string_init(&thread->callback); tb_string_cstrncpy(&thread->callback, callback_data, callback_size); tb_string_init(&thread->callinfo); tb_string_cstrncpy(&thread->callinfo, callinfo_data, callinfo_size); // create and start thread thread->handle = tb_thread_init(name, xm_thread_func, thread, stacksize); tb_assert_and_check_break(thread->handle); xm_lua_pushpointer(lua, (tb_pointer_t)thread); ok = tb_true; } while (0); if (!ok) { if (thread) { tb_string_exit(&thread->callback); tb_string_exit(&thread->callinfo); if (thread->handle) { tb_thread_exit(thread->handle); thread->handle = tb_null; } tb_free(thread); } lua_pushnil(lua); } return 1; } ================================================ FILE: core/src/xmake/thread/thread_resume.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file thread_resume.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_resume(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get thread xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1); tb_check_return_val(thread && thread->handle, 0); // resume thread lua_pushboolean(lua, tb_thread_resume(thread->handle)); return 1; } ================================================ FILE: core/src/xmake/thread/thread_suspend.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file thread_suspend.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_suspend(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get thread xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1); tb_check_return_val(thread && thread->handle, 0); // suspend thread lua_pushboolean(lua, tb_thread_suspend(thread->handle)); return 1; } ================================================ FILE: core/src/xmake/thread/thread_wait.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file thread_wait.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "thread" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_thread_wait(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // is pointer? if (!xm_lua_ispointer(lua, 1)) { return 0; } // get thread xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1); tb_check_return_val(thread->handle, 0); // get timeout tb_size_t timeout = (tb_size_t)luaL_checkinteger(lua, 2); // wait thread tb_int_t retval; lua_pushinteger(lua, (tb_int_t)tb_thread_wait(thread->handle, timeout, &retval)); return 1; } ================================================ FILE: core/src/xmake/tty/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_TTY_PREFIX_H #define XM_TTY_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/tty/session_id.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file session_id.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "session_id" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifdef TB_CONFIG_OS_WINDOWS #include #else #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // tty.session_id() tb_int_t xm_tty_session_id(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); #ifdef TB_CONFIG_OS_WINDOWS HWND hwnd = GetConsoleWindow(); if (hwnd) { // use hex string of hwnd as session id lua_pushfstring(lua, "%p", hwnd); return 1; } #else // we use the tty name as session id tb_char_t const* name = ttyname(STDIN_FILENO); if (name) { lua_pushstring(lua, name); return 1; } #endif // failed lua_pushnil(lua); return 1; } ================================================ FILE: core/src/xmake/tty/term_mode.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file term_mode.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "term_mode" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #ifdef TB_CONFIG_OS_WINDOWS #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* local oldmode = tty.term_mode(stdtype) * local oldmode = tty.term_mode(stdtype, newmode) */ tb_int_t xm_tty_term_mode(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); #ifdef TB_CONFIG_OS_WINDOWS // get std type, (stdin: 1, stdout: 2, stderr: 3) tb_int_t stdtype = (tb_int_t)luaL_checkinteger(lua, 1); // get and set terminal mode DWORD mode = 0; HANDLE console_handle = INVALID_HANDLE_VALUE; switch (stdtype) { case 1: console_handle = GetStdHandle(STD_INPUT_HANDLE); break; case 2: console_handle = GetStdHandle(STD_OUTPUT_HANDLE); break; case 3: console_handle = GetStdHandle(STD_ERROR_HANDLE); break; } GetConsoleMode(console_handle, &mode); if (lua_isnumber(lua, 2)) { tb_int_t newmode = (tb_int_t)lua_tointeger(lua, 2); if (console_handle != INVALID_HANDLE_VALUE) { SetConsoleMode(console_handle, (DWORD)newmode); } } #else tb_int_t mode = 0; #endif lua_pushinteger(lua, (tb_int_t)mode); return 1; } ================================================ FILE: core/src/xmake/utf8/byte.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file byte.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_utf8_byte_cb(xm_utf8_int_t code, tb_cpointer_t udata) { lua_State* lua = (lua_State*)udata; tb_assert_and_check_return_val(lua, tb_false); luaL_checkstack(lua, 1, "too many results"); lua_pushinteger(lua, code); return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* utf8.byte(s, i [, j]) */ tb_int_t xm_utf8_byte(lua_State* lua) { size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); lua_Integer i = luaL_optinteger(lua, 2, 1); lua_Integer j = luaL_optinteger(lua, 3, i); return (tb_int_t)xm_utf8_byte_impl(s, len, (tb_long_t)i, (tb_long_t)j, xm_utf8_byte_cb, lua); } ================================================ FILE: core/src/xmake/utf8/char.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file char.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static void xm_utf8_char_push(lua_State *lua, tb_int_t arg) { lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(lua, arg); luaL_argcheck(lua, code <= XM_UTF8_MAXUTF, arg, "value out of range"); tb_char_t buf[8]; tb_size_t n = xm_utf8_encode(buf, (xm_utf8_int_t)code); if (n > 0) { lua_pushlstring(lua, buf, n); } else { luaL_error(lua, "value out of range"); } } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* utfchar(n1, n2, ...) -> char(n1)..char(n2)... */ tb_int_t xm_utf8_char(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_int_t n = lua_gettop(lua); // number of arguments if (n == 1) { // optimize common case of single char xm_utf8_char_push(lua, 1); } else { tb_int_t i; luaL_Buffer b; luaL_buffinit(lua, &b); for (i = 1; i <= n; i++) { xm_utf8_char_push(lua, i); luaL_addvalue(&b); } luaL_pushresult(&b); } return 1; } ================================================ FILE: core/src/xmake/utf8/codepoint.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file codepoint.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_utf8_codepoint_cb(xm_utf8_int_t code, tb_cpointer_t udata) { lua_State* lua = (lua_State*)udata; tb_assert_and_check_return_val(lua, tb_false); lua_pushinteger(lua, code); return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* codepoint(s, [i, [j [, lax]]]) -> returns codepoints for all * characters that start in the range [i,j] */ tb_int_t xm_utf8_codepoint(lua_State *lua) { size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); lua_Integer posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 2, 1), len); lua_Integer pose = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, posi), len); tb_bool_t lax = lua_toboolean(lua, 4); luaL_argcheck(lua, posi >= 1, 2, "out of bounds"); luaL_argcheck(lua, pose <= (lua_Integer)len, 3, "out of bounds"); if (posi > pose) { return 0; // empty interval; return no values } if (pose - posi >= INT_MAX) { // (lua_Integer -> int) overflow? return luaL_error(lua, "string slice too long"); } tb_int_t n = (tb_int_t)(pose - posi) + 1; luaL_checkstack(lua, n, "string slice too long"); int nresults = lua_gettop(lua); if (!xm_utf8_codepoint_impl(s, len, (tb_long_t)posi, (tb_long_t)pose, !lax, xm_utf8_codepoint_cb, lua)) { return luaL_error(lua, XM_UTF8_MSGInvalid); } return lua_gettop(lua) - nresults; } ================================================ FILE: core/src/xmake/utf8/codes.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file codes.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_int_t xm_utf8_codes_iter(lua_State *lua, tb_bool_t strict) { tb_assert_and_check_return_val(lua, 0); size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); lua_Unsigned n = (lua_Unsigned)lua_tointeger(lua, 2); if (n < len) { while (n < len && xm_utf8_iscontp(s + n)) { n++; // go to next character } } if (n >= len) { // (also handles original 'n' being negative) return 0; // no more codepoints } else { xm_utf8_int_t code; tb_char_t const* next = xm_utf8_decode(s + n, &code, strict); if (next == NULL || (next < s + len && xm_utf8_iscontp(next))) { return luaL_error(lua, XM_UTF8_MSGInvalid); } lua_pushinteger(lua, n + 1); lua_pushinteger(lua, code); return 2; } } static int xm_utf8_codes_iter_strict(lua_State *lua) { return xm_utf8_codes_iter(lua, tb_true); } static int xm_utf8_codes_iter_lax(lua_State *lua) { return xm_utf8_codes_iter(lua, tb_false); } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_utf8_codes(lua_State *lua) { tb_bool_t lax = lua_toboolean(lua, 2); tb_char_t const* s = luaL_checkstring(lua, 1); luaL_argcheck(lua, !xm_utf8_iscontp(s), 1, XM_UTF8_MSGInvalid); lua_pushcfunction(lua, lax ? xm_utf8_codes_iter_lax : xm_utf8_codes_iter_strict); lua_pushvalue(lua, 1); lua_pushinteger(lua, 0); return 3; } ================================================ FILE: core/src/xmake/utf8/find.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file find.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_int_t xm_utf8_find_impl_plain(lua_State* lua, tb_char_t const* s, size_t len, tb_char_t const* sub, size_t sublen, lua_Integer init) { tb_long_t char_end = 0; tb_long_t char_start = xm_utf8_find_impl(s, len, sub, sublen, (tb_long_t)init, &char_end); if (char_start > 0) { lua_pushinteger(lua, char_start); lua_pushinteger(lua, char_end); return 2; } lua_pushnil(lua); return 1; } static tb_int_t xm_utf8_find_impl_pattern(lua_State* lua, tb_char_t const* s, size_t len, lua_Integer init) { int base = lua_gettop(lua); tb_long_t byte_init = 1; if (init > 0) { if (init > 1) { byte_init = xm_utf8_offset_impl(s, len, (tb_long_t)init, 1); if (byte_init <= 0) { lua_pushnil(lua); return 1; } } } else if (init < 0) { byte_init = xm_utf8_offset_impl(s, len, (tb_long_t)init, len + 1); if (byte_init <= 0) { lua_pushnil(lua); return 1; } } lua_getglobal(lua, "string"); lua_getfield(lua, -1, "find"); lua_pushvalue(lua, 1); // s lua_pushvalue(lua, 2); // pattern lua_pushinteger(lua, byte_init); // init (byte) lua_pushboolean(lua, 0); // plain lua_call(lua, 4, LUA_MULTRET); // Stack: [args, string_table, results...] int nres = lua_gettop(lua) - (base + 1); if (nres <= 0 || lua_isnil(lua, base + 2)) { lua_pushnil(lua); lua_remove(lua, base + 1); return 1; } lua_Integer b_start = lua_tointeger(lua, base + 2); lua_Integer b_end = lua_tointeger(lua, base + 3); tb_long_t char_start = 1; if (b_start > 1) { tb_long_t count = xm_utf8_len_impl(s, len, 1, (tb_long_t)b_start - 1, tb_true, tb_null); if (count < 0) { lua_pushnil(lua); lua_remove(lua, base + 1); return 1; } char_start = count + 1; } tb_long_t match_char_len = 0; if (b_end >= b_start) { match_char_len = xm_utf8_len_impl(s, len, (tb_long_t)b_start, (tb_long_t)b_end, tb_true, tb_null); if (match_char_len < 0) { lua_pushnil(lua); lua_remove(lua, base + 1); return 1; } } lua_pushinteger(lua, char_start); lua_replace(lua, base + 2); lua_pushinteger(lua, char_start + match_char_len - 1); lua_replace(lua, base + 3); lua_remove(lua, base + 1); return nres; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* utf8.find(s, target [, init [, plain]]) */ tb_int_t xm_utf8_find(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); size_t sublen; tb_char_t const* sub = luaL_checklstring(lua, 2, &sublen); lua_Integer init = luaL_optinteger(lua, 3, 1); tb_int_t plain = lua_toboolean(lua, 4); if (plain) { return xm_utf8_find_impl_plain(lua, s, len, sub, sublen, init); } else { return xm_utf8_find_impl_pattern(lua, s, len, init); } } ================================================ FILE: core/src/xmake/utf8/lastof.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file lastof.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* utf8.lastof(s, pattern, plain) */ tb_int_t xm_utf8_lastof(lua_State *lua) { size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); size_t sublen; tb_char_t const* sub = luaL_checklstring(lua, 2, &sublen); tb_int_t plain = lua_toboolean(lua, 3); tb_long_t byte_pos = 0; if (plain) { byte_pos = xm_utf8_lastof_impl(s, len, sub, sublen); } else { lua_getglobal(lua, "string"); lua_getfield(lua, -1, "lastof"); lua_pushvalue(lua, 1); // s lua_pushvalue(lua, 2); // pattern lua_pushboolean(lua, 0); // plain = false lua_call(lua, 3, 1); if (!lua_isnil(lua, -1)) { byte_pos = (tb_long_t)lua_tointeger(lua, -1); } } if (byte_pos > 0) { tb_long_t char_pos = xm_utf8_charpos(s, len, byte_pos); if (char_pos > 0) { lua_pushinteger(lua, char_pos); return 1; } } lua_pushnil(lua); return 1; } ================================================ FILE: core/src/xmake/utf8/len.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file len.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* utf8len(s [, i [, j [, lax]]]) --> number of characters that * start in the range [i,j], or nil + current position if 's' is not * well formed in that interval */ tb_int_t xm_utf8_len(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); lua_Integer posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 2, 1), len); lua_Integer posj = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, -1), len); tb_bool_t lax = lua_toboolean(lua, 4); luaL_argcheck(lua, 1 <= posi && --posi <= (lua_Integer)len, 2, "initial position out of bounds"); luaL_argcheck(lua, --posj < (lua_Integer)len, 3, "final position out of bounds"); tb_size_t errpos = 0; tb_long_t n = xm_utf8_len_impl(s, len, (tb_long_t)posi + 1, (tb_long_t)posj + 1, !lax, &errpos); if (n < 0) { lua_pushnil(lua); lua_pushinteger(lua, errpos); return 2; } lua_pushinteger(lua, n); return 1; } ================================================ FILE: core/src/xmake/utf8/offset.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file offset.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* offset(s, n, [i]) -> index where n-th character counting from * position 'i' starts; 0 means character at 'i'. */ tb_int_t xm_utf8_offset(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); lua_Integer n = luaL_checkinteger(lua, 2); lua_Integer posi = (n >= 0) ? 1 : len + 1; posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, posi), len); tb_long_t result = xm_utf8_offset_impl(s, len, (tb_long_t)n, (tb_long_t)posi); if (result == -1) { return luaL_argerror(lua, 3, "position out of bounds"); } if (result == -2) { return luaL_error(lua, "initial position is a continuation byte"); } if (result == 0) { lua_pushnil(lua); return 1; } lua_pushinteger(lua, result); return 1; } ================================================ FILE: core/src/xmake/utf8/prefix.h ================================================ #ifndef XM_UTF8_PREFIX_H #define XM_UTF8_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/utf8/reverse.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file reverse.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* utf8.reverse(s) */ tb_int_t xm_utf8_reverse(lua_State *lua) { size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); if (len == 0) { lua_pushliteral(lua, ""); return 1; } // do reverse if (len < 1024) { tb_char_t buf[1024 + 1]; xm_utf8_reverse_impl(s, len, buf); lua_pushlstring(lua, buf, len); } else { tb_char_t* buf = (tb_char_t*)tb_malloc_bytes(len + 1); if (buf) { xm_utf8_reverse_impl(s, len, buf); lua_pushlstring(lua, buf, len); tb_free(buf); } else { lua_pushnil(lua); } } return 1; } ================================================ FILE: core/src/xmake/utf8/sub.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file sub.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* utf8.sub(s, i [, j]) */ tb_int_t xm_utf8_sub(lua_State *lua) { size_t len; tb_char_t const* s = luaL_checklstring(lua, 1, &len); lua_Integer i = luaL_checkinteger(lua, 2); lua_Integer j = luaL_optinteger(lua, 3, -1); tb_size_t sublen = 0; tb_char_t const* sub = xm_utf8_sub_impl(s, len, (tb_long_t)i, (tb_long_t)j, &sublen); if (sub) { lua_pushlstring(lua, sub, sublen); } else { lua_pushliteral(lua, ""); } return 1; } ================================================ FILE: core/src/xmake/utf8/utf8.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file utf8.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_char_t const* xm_utf8_decode(tb_char_t const* s, xm_utf8_int_t* val, tb_bool_t strict) { static const xm_utf8_int_t limits[] = {~(xm_utf8_int_t)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u}; tb_uint32_t c = (tb_byte_t)s[0]; xm_utf8_int_t res = 0; if (c < 0x80) { res = c; } else { if (xm_utf8_iscont(c)) { return tb_null; } tb_int_t count = 0; for (; c & 0x40; c <<= 1) { tb_uint32_t cc = (tb_byte_t)s[++count]; if (!xm_utf8_iscont(cc)) { return tb_null; } res = (res << 6) | (cc & 0x3F); } res |= ((xm_utf8_int_t)(c & 0x7F) << (count * 5)); if (count > 5 || res > XM_UTF8_MAXUTF || res < limits[count]) { return tb_null; } s += count; } if (strict) { if (res > XM_UTF8_MAXUNICODE || (0xD800u <= res && res <= 0xDFFFu)) { return tb_null; } } if (val) { *val = res; } return s + 1; } tb_size_t xm_utf8_encode(tb_char_t* s, xm_utf8_int_t val) { tb_assert_and_check_return_val(s, 0); if (val < 0x80) { s[0] = (tb_char_t)val; return 1; } if (val < 0x800) { s[0] = (tb_char_t)(0xc0 | ((val >> 6) & 0x1f)); s[1] = (tb_char_t)(0x80 | (val & 0x3f)); return 2; } if (val < 0x10000) { s[0] = (tb_char_t)(0xe0 | ((val >> 12) & 0x0f)); s[1] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f)); s[2] = (tb_char_t)(0x80 | (val & 0x3f)); return 3; } if (val <= 0x10FFFF) { s[0] = (tb_char_t)(0xf0 | ((val >> 18) & 0x07)); s[1] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f)); s[2] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f)); s[3] = (tb_char_t)(0x80 | (val & 0x3f)); return 4; } if (val <= 0x3FFFFFF) { s[0] = (tb_char_t)(0xf8 | ((val >> 24) & 0x03)); s[1] = (tb_char_t)(0x80 | ((val >> 18) & 0x3f)); s[2] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f)); s[3] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f)); s[4] = (tb_char_t)(0x80 | (val & 0x3f)); return 5; } if (val <= 0x7FFFFFFF) { s[0] = (tb_char_t)(0xfc | ((val >> 30) & 0x01)); s[1] = (tb_char_t)(0x80 | ((val >> 24) & 0x3f)); s[2] = (tb_char_t)(0x80 | ((val >> 18) & 0x3f)); s[3] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f)); s[4] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f)); s[5] = (tb_char_t)(0x80 | (val & 0x3f)); return 6; } return 0; } tb_long_t xm_utf8_charpos(tb_char_t const* s, tb_size_t len, tb_long_t byte_pos) { if (byte_pos <= 0) return 0; if (byte_pos > len + 1) byte_pos = len + 1; // adjust byte_pos to the start of the character // // performance: // 0(1) complexity, because utf8 sequence is max 4 bytes while (byte_pos > 1 && xm_utf8_iscont(s[byte_pos - 1])) { byte_pos--; } // get character position tb_long_t count = xm_utf8_len_impl(s, len, 1, byte_pos - 1, tb_true, tb_null); return count >= 0? count + 1 : -1; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation interfaces */ static struct { xm_utf8_int_t first; xm_utf8_int_t last; } const g_non_spacing[] = { {0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489}, {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603}, {0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670}, {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902}, {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D}, {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981}, {0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, {0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC}, {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, {0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F}, {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, {0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD}, {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD}, {0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922}, {0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B}, {0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34}, {0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42}, {0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF}, {0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063}, {0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F}, {0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B}, {0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169}, {0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F}, {0xE0100, 0xE01EF} }; tb_long_t xm_utf8_charwidth(xm_utf8_int_t val) { // test for 8-bit control characters if (val == 0) return 0; if (val < 32 || (val >= 0x7f && val < 0xa0)) { if (val == 0x09) return 4; // TAB if (val == 0x08) return -1; // BS return 0; // other control chars } // binary search in table of non-spacing characters tb_long_t min = 0; tb_long_t max = tb_arrayn(g_non_spacing) - 1; if (val >= g_non_spacing[0].first && val <= g_non_spacing[max].last) { while (max >= min) { tb_long_t mid = (min + max) / 2; if (val > g_non_spacing[mid].last) { min = mid + 1; } else if (val < g_non_spacing[mid].first) { max = mid - 1; } else { return 0; } } } if (val >= 0x1100 && (val <= 0x115f || // Hangul Jamo init. consonants val == 0x2329 || val == 0x232a || (val >= 0x2e80 && val <= 0xa4cf && val != 0x303f) || // CJK ... Yi (val >= 0xac00 && val <= 0xd7a3) || // Hangul Syllables (val >= 0xf900 && val <= 0xfaff) || // CJK Compatibility Ideographs (val >= 0xfe10 && val <= 0xfe19) || // Vertical forms (val >= 0xfe30 && val <= 0xfe6f) || // CJK Compatibility Forms (val >= 0xff00 && val <= 0xff60) || // Fullwidth Forms (val >= 0xffe0 && val <= 0xffe6) || (val >= 0x20000 && val <= 0x2fffd) || (val >= 0x30000 && val <= 0x3fffd))) { return 2; } return 1; } tb_long_t xm_utf8_strwidth(tb_char_t const* s, tb_size_t len) { tb_assert_and_check_return_val(s, -1); tb_long_t width = 0; tb_char_t const* p = s; tb_char_t const* e = s + len; while (p < e) { xm_utf8_int_t val; tb_char_t const* next = xm_utf8_decode(p, &val, tb_true); if (next) { tb_long_t w = xm_utf8_charwidth(val); if (w < 0) return -1; width += w; p = next; } else { p++; // invalid byte, skip } } return width; } tb_long_t xm_utf8_len_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, tb_size_t* errpos) { tb_assert_and_check_return_val(s, -1); tb_long_t n = 0; while (posi <= posj) { tb_char_t const* s1 = xm_utf8_decode(s + posi - 1, tb_null, strict); if (s1 == tb_null) { if (errpos) { *errpos = posi; } return -1; } posi = s1 - s + 1; n++; } return n; } tb_long_t xm_utf8_offset_impl(tb_char_t const* s, tb_size_t len, tb_long_t n, tb_long_t posi) { tb_assert_and_check_return_val(s, -1); // check if (1 > posi || --posi > (tb_long_t)len) { return -1; // error: position out of bounds } if (n == 0) { // find beginning of current byte sequence while (posi > 0 && xm_utf8_iscontp(s + posi)) { posi--; } } else { if (xm_utf8_iscontp(s + posi)) { return -2; // error: initial position is a continuation byte } if (n < 0) { while (n < 0 && posi > 0) { do { posi--; } while (posi > 0 && xm_utf8_iscontp(s + posi)); n++; } } else { n--; while (n > 0 && posi < (tb_long_t)len) { do { posi++; } while (xm_utf8_iscontp(s + posi)); n--; } } } if (n == 0) { return posi + 1; } return 0; // nil } tb_bool_t xm_utf8_codepoint_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, xm_utf8_codepoint_func_t func, tb_cpointer_t udata) { tb_assert_and_check_return_val(s, tb_false); if (posi > posj) { return tb_true; } tb_char_t const* se = s + posj; for (s += posi - 1; s < se;) { xm_utf8_int_t code; s = xm_utf8_decode(s, &code, strict); if (s == tb_null) { return tb_false; } if (func && !func(code, udata)) { return tb_false; } } return tb_true; } tb_long_t xm_utf8_find_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen, tb_long_t init, tb_long_t* pchar_end) { tb_assert_and_check_return_val(s && sub, 0); if (sublen == 0) { if (init > (tb_long_t)len + 1) init = len + 1; tb_long_t start_byte = 1; if (init > 0) { start_byte = xm_utf8_offset_impl(s, len, init, 1); } else if (init < 0) { start_byte = xm_utf8_offset_impl(s, len, init, len + 1); } if (start_byte <= 0) start_byte = 1; tb_long_t char_pos = 1; if (start_byte > 1) { tb_long_t c = xm_utf8_len_impl(s, len, 1, start_byte - 1, tb_true, tb_null); if (c >= 0) char_pos = c + 1; } if (pchar_end) *pchar_end = char_pos - 1; return char_pos; } tb_long_t start_byte = 1; if (init > 0) { start_byte = xm_utf8_offset_impl(s, len, init, 1); } else if (init < 0) { start_byte = xm_utf8_offset_impl(s, len, init, len + 1); } if (start_byte <= 0) return 0; tb_char_t const* p = tb_strstr(s + start_byte - 1, sub); if (!p) return 0; tb_long_t found_byte_start = p - s + 1; tb_long_t char_start = 1; if (found_byte_start > 1) { tb_long_t c = xm_utf8_len_impl(s, len, 1, found_byte_start - 1, tb_true, tb_null); if (c < 0) return 0; char_start = c + 1; } if (pchar_end) { tb_long_t match_len = xm_utf8_len_impl(s, len, found_byte_start, found_byte_start + sublen - 1, tb_true, tb_null); if (match_len < 0) return 0; *pchar_end = char_start + match_len - 1; } return char_start; } tb_long_t xm_utf8_lastof_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen) { tb_assert_and_check_return_val(s && sub, 0); tb_check_return_val(sublen, 0); // optimize for single character search if (sublen == 1) { tb_char_t const* p = tb_strrchr(s, sub[0]); return p ? (tb_long_t)(p - s + 1) : 0; } tb_char_t const* p = s; tb_char_t const* last = tb_null; while (1) { p = tb_strstr(p, sub); if (!p) break; last = p; p += 1; } if (last) { return (tb_long_t)(last - s + 1); } return 0; } tb_long_t xm_utf8_byte_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, xm_utf8_codepoint_func_t func, tb_cpointer_t udata) { tb_size_t sublen = 0; tb_char_t const* sub = xm_utf8_sub_impl(s, len, i, j, &sublen); if (sub && sublen > 0) { // decode and push codepoints tb_long_t n = 0; tb_char_t const* p = sub; tb_char_t const* e = sub + sublen; while (p < e) { xm_utf8_int_t val; tb_char_t const* next = xm_utf8_decode(p, &val, tb_true); if (next) { if (func && !func(val, udata)) break; n++; p = next; } else { p++; } } return n; } return 0; } tb_char_t const* xm_utf8_sub_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, tb_size_t* psublen) { tb_assert_and_check_return_val(s && psublen, tb_null); *psublen = 0; // map i (char index) to byte offset tb_long_t start_byte = 0; if (i > 0) { start_byte = xm_utf8_offset_impl(s, len, i, 1); } else if (i < 0) { start_byte = xm_utf8_offset_impl(s, len, i, len + 1); } else { start_byte = 1; } if (start_byte == -1) { if (i > 0) { return ""; } else { start_byte = 1; } } else if (start_byte == 0) { if (i < 0) { start_byte = 1; } else { return ""; } } // map j (char index) to byte offset (end) tb_long_t end_byte = 0; if (j >= 0) { end_byte = xm_utf8_offset_impl(s, len, j + 1, 1); } else { end_byte = xm_utf8_offset_impl(s, len, j + 1, len + 1); } if (end_byte == -1) { if (j >= 0) end_byte = len + 1; else end_byte = 1; } else if (end_byte == 0) { if (j >= 0) end_byte = len + 1; else end_byte = 1; } if (end_byte <= start_byte) { return ""; } *psublen = end_byte - start_byte; return s + start_byte - 1; } tb_char_t* xm_utf8_reverse_impl(tb_char_t const* s, tb_size_t len, tb_char_t* buf) { tb_assert_and_check_return_val(s && len && buf, tb_null); tb_char_t const* p = s; tb_char_t const* e = s + len; tb_char_t* d = buf + len; while (p < e) { xm_utf8_int_t code; tb_char_t const* next = xm_utf8_decode(p, &code, tb_false); // invalid utf8? treat as 1 byte tb_size_t n = 1; if (next) { n = next - p; } // safety check if (p + n > e) n = e - p; d -= n; tb_memcpy(d, p, n); p += n; } buf[len] = '\0'; return buf; } ================================================ FILE: core/src/xmake/utf8/utf8.h ================================================ #ifndef XM_UTF8_UTF8_H #define XM_UTF8_UTF8_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define xm_utf8_iscont(c) (((c) & 0xC0) == 0x80) #define xm_utf8_iscontp(p) xm_utf8_iscont(*(p)) #define XM_UTF8_MAXUNICODE 0x10FFFFu #define XM_UTF8_MAXUTF 0x7FFFFFFFu #define XM_UTF8_MSGInvalid "invalid UTF-8 code" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ typedef tb_uint32_t xm_utf8_int_t; typedef tb_bool_t (*xm_utf8_codepoint_func_t)(xm_utf8_int_t code, tb_cpointer_t udata); /* ////////////////////////////////////////////////////////////////////////////////////// * inline interfaces */ static __tb_inline__ tb_long_t xm_utf8_posrelat(tb_long_t pos, tb_size_t len) { if (pos >= 0) { return pos; } else if (0u - (tb_size_t)pos > len) { return 0; } else { return (tb_long_t)len + pos + 1; } } /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_char_t const* xm_utf8_decode(tb_char_t const* s, xm_utf8_int_t* val, tb_bool_t strict); tb_size_t xm_utf8_encode(tb_char_t* s, xm_utf8_int_t val); tb_long_t xm_utf8_charpos(tb_char_t const* s, tb_size_t len, tb_long_t byte_pos); tb_long_t xm_utf8_charwidth(xm_utf8_int_t val); tb_long_t xm_utf8_strwidth(tb_char_t const* s, tb_size_t len); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation interfaces */ tb_long_t xm_utf8_len_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, tb_size_t* errpos); tb_long_t xm_utf8_offset_impl(tb_char_t const* s, tb_size_t len, tb_long_t n, tb_long_t posi); tb_bool_t xm_utf8_codepoint_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, xm_utf8_codepoint_func_t func, tb_cpointer_t udata); tb_long_t xm_utf8_find_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen, tb_long_t init, tb_long_t* pchar_end); tb_long_t xm_utf8_lastof_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen); tb_long_t xm_utf8_byte_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, xm_utf8_codepoint_func_t func, tb_cpointer_t udata); tb_char_t const* xm_utf8_sub_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, tb_size_t* psublen); tb_char_t* xm_utf8_reverse_impl(tb_char_t const* s, tb_size_t len, tb_char_t* buf); #endif ================================================ FILE: core/src/xmake/utf8/width.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file width.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "utf8.h" /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ /* utf8.width(char) * utf8.width(str) * utf8.width(codepoint) */ tb_int_t xm_utf8_width(lua_State* lua) { if (lua_isnumber(lua, 1)) { xm_utf8_int_t val = (xm_utf8_int_t)lua_tointeger(lua, 1); lua_pushinteger(lua, xm_utf8_charwidth(val)); } else { size_t len = 0; tb_char_t const* s = luaL_checklstring(lua, 1, &len); lua_pushinteger(lua, xm_utf8_strwidth(s, len)); } return 1; } ================================================ FILE: core/src/xmake/utils/charset.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file charset.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "charset" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "charset.h" /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ // the charsets, @note: type & name is sorted static xm_charset_entry_t g_charsets[] = { { TB_CHARSET_TYPE_ANSI, "ansi" }, { TB_CHARSET_TYPE_ASCII, "ascii" }, { TB_CHARSET_TYPE_GB2312, "gb2312" }, { TB_CHARSET_TYPE_GBK, "gbk" }, { TB_CHARSET_TYPE_ISO8859, "iso8859" }, { TB_CHARSET_TYPE_UCS2 | TB_CHARSET_TYPE_NE, "ucs2" }, { TB_CHARSET_TYPE_UCS4 | TB_CHARSET_TYPE_NE, "ucs4" }, { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE, "utf16" }, { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE, "utf16be" }, { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE, "utf16bom" }, { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE, "utf16le" }, { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE, "utf16lebom" }, { TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_NE, "utf32" }, { TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_BE, "utf32be" }, { TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_LE, "utf32le" }, { TB_CHARSET_TYPE_UTF8, "utf8" }, { TB_CHARSET_TYPE_UTF8, "utf8bom" }, }; /* ////////////////////////////////////////////////////////////////////////////////////// * finder */ static tb_long_t xm_charset_comp_by_name(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t name) { return tb_stricmp(((xm_charset_entry_ref_t)item)->name, (tb_char_t const *)name); } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ xm_charset_entry_ref_t xm_charset_find_by_name(tb_char_t const *name) { // make iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_mem(&array_iterator, g_charsets, tb_arrayn(g_charsets), sizeof(xm_charset_entry_t)); tb_assert_and_check_return_val(iterator, tb_null); // find it by the binary search tb_size_t itor = tb_binary_find_all_if(iterator, xm_charset_comp_by_name, name); if (itor != tb_iterator_tail(iterator)) { return (xm_charset_entry_ref_t)tb_iterator_item(iterator, itor); } else { return tb_null; } } ================================================ FILE: core/src/xmake/utils/charset.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file charset.h * */ #ifndef XM_UTILS_CHARSET_H #define XM_UTILS_CHARSET_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the charset entry type typedef struct __xm_charset_entry_t { // the charset type tb_size_t type; // the charset name tb_char_t const *name; } xm_charset_entry_t, *xm_charset_entry_ref_t; /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ /* find charset by name * * @param name the charset name * * @return the charset entry */ xm_charset_entry_ref_t xm_charset_find_by_name(tb_char_t const *name); #endif ================================================ FILE: core/src/xmake/utils/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_UTILS_PREFIX_H #define XM_UTILS_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #endif ================================================ FILE: core/src/xmake/winos/ansi.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu * @file ansi.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "ansi" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "ansi.h" #include /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_int_t xm_expand_cp(tb_int_t cp) { tb_assert_and_check_return_val(cp >= 0 && cp <= 65535, 0); if (cp == CP_OEMCP) { return GetOEMCP(); } if (cp == CP_ACP) { return GetACP(); } return cp; } tb_int_t xm_winos_console_cp(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_int_t n = lua_gettop(lua); if (n >= 1) { lua_Integer cp = luaL_checkinteger(lua, 1); luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page"); cp = xm_expand_cp((tb_uint_t)cp); luaL_argcheck(lua, SetConsoleCP((tb_uint_t)cp), 1, "failed to set code page"); lua_pushinteger(lua, cp); return 1; } else { tb_uint_t cp = GetConsoleCP(); lua_pushinteger(lua, (lua_Integer)cp); return 1; } } tb_int_t xm_winos_console_output_cp(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_int_t n = lua_gettop(lua); if (n >= 1) { lua_Integer cp = luaL_checkinteger(lua, 1); luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page"); cp = xm_expand_cp((tb_uint_t)cp); luaL_argcheck(lua, SetConsoleOutputCP((tb_uint_t)cp), 1, "failed to set code page"); lua_pushinteger(lua, cp); return 1; } else { tb_uint_t cp = GetConsoleOutputCP(); lua_pushinteger(lua, (lua_Integer)cp); return 1; } } tb_int_t xm_winos_cp_info(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); lua_Integer cp = luaL_checkinteger(lua, 1); luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page"); CPINFOEX cp_info; luaL_argcheck(lua, GetCPInfoEx((tb_uint_t)cp, 0, &cp_info), 1, "invalid code page"); lua_newtable(lua); lua_pushliteral(lua, "name"); tb_char_t *namebuf = tb_malloc_cstr(sizeof(cp_info.CodePageName) * 2); tb_assert_and_check_return_val(namebuf, 0); tb_size_t namelen = tb_wtoa(namebuf, (const tb_wchar_t *)cp_info.CodePageName, sizeof(cp_info.CodePageName) * 2); tb_assert_and_check_return_val(namelen < sizeof(cp_info.CodePageName) * 2, 0); lua_pushlstring(lua, namebuf, namelen); tb_free(namebuf); lua_settable(lua, -3); lua_pushliteral(lua, "max_char_size"); lua_pushinteger(lua, (lua_Integer)cp_info.MaxCharSize); lua_settable(lua, -3); lua_pushliteral(lua, "id"); lua_pushinteger(lua, (lua_Integer)cp_info.CodePage); lua_settable(lua, -3); lua_pushliteral(lua, "default_char"); lua_pushstring(lua, (tb_char_t const *)cp_info.DefaultChar); lua_settable(lua, -3); lua_pushliteral(lua, "lead_byte"); lua_createtable(lua, MAX_LEADBYTES / 2, 0); for (tb_size_t i = 0; i < MAX_LEADBYTES && cp_info.LeadByte[i] != 0 && cp_info.LeadByte[i + 1] != 0; i += 2) { lua_pushinteger(lua, (i / 2) + 1); lua_createtable(lua, 0, 2); lua_pushliteral(lua, "from"); lua_pushinteger(lua, cp_info.LeadByte[i]); lua_settable(lua, -3); lua_pushliteral(lua, "to"); lua_pushinteger(lua, cp_info.LeadByte[i + 1]); lua_settable(lua, -3); lua_settable(lua, -3); } lua_settable(lua, -3); return 1; } tb_int_t xm_winos_ansi_cp(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_uint_t cp = GetACP(); lua_pushinteger(lua, (lua_Integer)cp); return 1; } tb_int_t xm_winos_oem_cp(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); tb_uint_t cp = GetOEMCP(); lua_pushinteger(lua, (lua_Integer)cp); return 1; } ================================================ FILE: core/src/xmake/winos/ansi.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author OpportunityLiu * @file ansi.h * */ #ifndef XM_WINOS_ANSI_H #define XM_WINOS_ANSI_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #endif ================================================ FILE: core/src/xmake/winos/file_signature.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file file_signature.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_signature" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include #include #include #include /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the file signature info type typedef struct __tb_file_signature_info_t { // is the file digitally signed? tb_bool_t is_signed; // is the signature valid and trusted by the OS? tb_bool_t is_trusted; /* the name of the signer (e.g., "Microsoft Corporation") tbox uses UTF-8 by default for tb_char_t */ tb_char_t signer_name[256]; } tb_file_signature_info_t; /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t tb_file_get_signature_info(tb_char_t const* filepath, tb_file_signature_info_t* info) { tb_assert_and_check_return_val(filepath && info, tb_false); // init info tb_memset(info, 0, sizeof(tb_file_signature_info_t)); // convert path tb_wchar_t wide_path[TB_PATH_MAXN]; if (!tb_path_absolute_w(filepath, wide_path, TB_PATH_MAXN)) { return tb_false; } // init file info WINTRUST_FILE_INFO file_data = {0}; file_data.cbStruct = sizeof(file_data); file_data.pcwszFilePath = wide_path; file_data.hFile = NULL; file_data.pgKnownSubject = NULL; // init trust data WINTRUST_DATA trust_data = {0}; trust_data.cbStruct = sizeof(trust_data); trust_data.dwUIChoice = WTD_UI_NONE; trust_data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN; trust_data.dwUnionChoice = WTD_CHOICE_FILE; trust_data.dwStateAction = WTD_STATEACTION_VERIFY; trust_data.hWVTStateData = NULL; trust_data.pwszURLReference = NULL; trust_data.dwProvFlags = WTD_SAFER_FLAG; trust_data.dwUIContext = 0; trust_data.pFile = &file_data; // verify trust GUID guid_action = WINTRUST_ACTION_GENERIC_VERIFY_V2; LONG status = WinVerifyTrust(NULL, &guid_action, &trust_data); // clean up trust_data.dwStateAction = WTD_STATEACTION_CLOSE; WinVerifyTrust(NULL, &guid_action, &trust_data); // check status if (status == ERROR_SUCCESS) { info->is_signed = tb_true; info->is_trusted = tb_true; } else if (status == TRUST_E_NOSIGNATURE) { return tb_true; } else if (status == TRUST_E_EXPLICIT_DISTRUST || status == TRUST_E_SUBJECT_NOT_TRUSTED) { info->is_signed = tb_true; info->is_trusted = tb_false; } else { return tb_false; } // extract signer name if (info->is_signed) { HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; DWORD dwEncoding = 0; DWORD dwContentType = 0; DWORD dwFormatType = 0; PCMSG_SIGNER_INFO pSignerInfo = NULL; PCCERT_CONTEXT pCertContext = NULL; BOOL bResult = FALSE; bResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE, wide_path, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL); if (bResult) { DWORD cbSignerInfo = 0; if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &cbSignerInfo)) { pSignerInfo = (PCMSG_SIGNER_INFO)tb_malloc(cbSignerInfo); if (pSignerInfo) { if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (void*)pSignerInfo, &cbSignerInfo)) { CERT_INFO certInfo; certInfo.Issuer = pSignerInfo->Issuer; certInfo.SerialNumber = pSignerInfo->SerialNumber; pCertContext = CertFindCertificateInStore(hStore, (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING), 0, CERT_FIND_SUBJECT_CERT, (PVOID)&certInfo, NULL); if (pCertContext) { tb_wchar_t wName[256] = {0}; if (CertGetNameStringW(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, wName, 256)) { tb_wtoa(info->signer_name, wName, sizeof(info->signer_name)); } CertFreeCertificateContext(pCertContext); } } tb_free(pSignerInfo); } } } if (hStore) CertCloseStore(hStore, 0); if (hMsg) CryptMsgClose(hMsg); } return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* get the file signature info * * local info = winos.file_signature(filepath) * { * is_signed = true, * is_trusted = true, * signer_name = "Microsoft Corporation" * } */ tb_int_t xm_winos_file_signature(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the arguments tb_char_t const *filepath = luaL_checkstring(lua, 1); tb_check_return_val(filepath, 0); // get signature info tb_file_signature_info_t info = {0}; if (tb_file_get_signature_info(filepath, &info)) { lua_newtable(lua); lua_pushstring(lua, "is_signed"); lua_pushboolean(lua, info.is_signed); lua_settable(lua, -3); lua_pushstring(lua, "is_trusted"); lua_pushboolean(lua, info.is_trusted); lua_settable(lua, -3); if (info.is_signed) { lua_pushstring(lua, "signer_name"); lua_pushstring(lua, info.signer_name); lua_settable(lua, -3); } return 1; } return 0; } ================================================ FILE: core/src/xmake/winos/logical_drives.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file logical_drives.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "logical_drives" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ // get the logical drives tb_int_t xm_winos_logical_drives(lua_State *lua) { // init table lua_newtable(lua); // get logical drives tb_char_t *data = tb_null; do { // get buffer size DWORD size = GetLogicalDriveStringsA(0, tb_null); tb_assert_and_check_break(size); // make data buffer data = (tb_char_t *)tb_malloc0(size + 1); tb_assert_and_check_break(data); // get logical drives size = GetLogicalDriveStringsA(size, data); tb_assert_and_check_break(size); // parse logical drives tb_size_t i = 1; tb_char_t const *p = data; while (*p) { // save drive lua_pushinteger(lua, i++); lua_pushstring(lua, p); lua_settable(lua, -3); // next drive p += tb_strlen(p) + 1; } } while (0); // exit data if (data) { tb_free(data); } data = tb_null; return 1; } ================================================ FILE: core/src/xmake/winos/prefix.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_WINOS_PREFIX_H #define XM_WINOS_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #ifdef TB_CONFIG_OS_WINDOWS #include #endif #endif ================================================ FILE: core/src/xmake/winos/registry_keys.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file registry_keys.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "registry_keys" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the enum info type typedef struct __xm_winos_registry_enum_info_t { lua_State *lua; HKEY key; tb_int_t ok; tb_char_t const *error; tb_int_t count; tb_wchar_t key_name[1024]; tb_char_t key_path_a[TB_PATH_MAXN]; } xm_winos_registry_enum_info_t; /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_winos_registry_enum_keys(xm_winos_registry_enum_info_t *info, tb_wchar_t const *rootdir, tb_long_t recursion) { // enum keys HKEY keynew = tb_null; lua_State *lua = info->lua; tb_wchar_t *key_path = tb_null; tb_size_t key_path_maxn = TB_PATH_MAXN; do { // open registry key if (RegOpenKeyExW(info->key, rootdir, 0, KEY_READ, &keynew) != ERROR_SUCCESS && keynew) { info->ok = -1; info->error = "open registry key failed"; break; } // query keys DWORD key_name_num = 0; DWORD key_name_maxn = 0; if (RegQueryInfoKeyW(keynew, tb_null, tb_null, tb_null, &key_name_num, &key_name_maxn, tb_null, tb_null, tb_null, tb_null, tb_null, tb_null) != ERROR_SUCCESS) { // cannot query this key, we ignore it break; } key_name_maxn++; // add `\0` // ensure enough key path buffer if (key_name_maxn > tb_arrayn(info->key_name)) { info->ok = -1; info->error = "no enough key path buffer"; break; } // init key path key_path = (tb_wchar_t *)tb_malloc(key_path_maxn * sizeof(tb_wchar_t)); if (!key_path) { info->ok = -1; info->error = "no enough key path buffer"; break; } // get all keys DWORD i = 0; for (i = 0; i < key_name_num && info->ok > 0; i++) { // get key name info->key_name[0] = L'\0'; DWORD key_name_size = tb_arrayn(info->key_name); if (RegEnumKeyExW(keynew, i, info->key_name, &key_name_size, tb_null, tb_null, tb_null, tb_null) != ERROR_SUCCESS) { info->ok = -1; info->error = "get registry key failed"; break; } // get key path tb_swprintf(key_path, key_path_maxn, L"%s\\%s", rootdir, info->key_name); // get key path (mbs) tb_size_t key_path_a_size = tb_wtoa(info->key_path_a, key_path, sizeof(info->key_path_a)); if (key_path_a_size == -1) { info->ok = -1; info->error = "convert registry key path failed"; break; } // do callback(key_name) lua_pushvalue(lua, 4); lua_pushlstring(lua, info->key_path_a, key_path_a_size); lua_call(lua, 1, 1); info->count++; // is continue? tb_bool_t is_continue = lua_toboolean(lua, -1); lua_pop(lua, 1); if (!is_continue) { info->ok = 0; break; } // enum all subkeys if (recursion > 0 || recursion < 0) { xm_winos_registry_enum_keys(info, key_path, recursion > 0 ? recursion - 1 : recursion); } } } while (0); // exit registry key if (keynew) { RegCloseKey(keynew); } keynew = tb_null; // free key path if (key_path) { tb_free(key_path); } key_path = tb_null; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* get registry keys * * local count, errors = winos.registry_keys("HKEY_LOCAL_MACHINE", * "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", * function (key_path) * return true -- continue or break * end) */ tb_int_t xm_winos_registry_keys(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the arguments tb_char_t const *rootkey = luaL_checkstring(lua, 1); tb_char_t const *rootdir = luaL_checkstring(lua, 2); tb_long_t recursion = (tb_long_t)lua_tointeger(lua, 3); tb_bool_t is_function = lua_isfunction(lua, 4); tb_check_return_val(rootkey && rootdir && is_function, 0); // enum keys tb_bool_t ok = tb_false; tb_int_t count = 0; HKEY key = tb_null; do { // get registry rootkey if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) { key = HKEY_CLASSES_ROOT; } else if (!tb_strcmp(rootkey, "HKCR")) { key = HKEY_CLASSES_ROOT; } else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) { key = HKEY_CURRENT_CONFIG; } else if (!tb_strcmp(rootkey, "HKCC")) { key = HKEY_CURRENT_CONFIG; } else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) { key = HKEY_CURRENT_USER; } else if (!tb_strcmp(rootkey, "HKCU")) { key = HKEY_CURRENT_USER; } else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) { key = HKEY_LOCAL_MACHINE; } else if (!tb_strcmp(rootkey, "HKLM")) { key = HKEY_LOCAL_MACHINE; } else if (!tb_strcmp(rootkey, "HKEY_USERS")) { key = HKEY_USERS; } else { lua_pushnil(lua); lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey); break; } // do enum tb_wchar_t rootdir_w[TB_PATH_MAXN]; if (tb_atow(rootdir_w, rootdir, TB_PATH_MAXN) == -1) { lua_pushnil(lua); lua_pushfstring(lua, "rootdir is too long: %s", rootdir); break; } xm_winos_registry_enum_info_t info; info.lua = lua; info.key = key; info.count = 0; info.ok = tb_true; info.error = tb_null; xm_winos_registry_enum_keys(&info, rootdir_w, recursion); count = info.count; ok = info.ok >= 0; if (!ok) { lua_pushnil(lua); lua_pushfstring(lua, "%s: %s\\%s", info.error ? info.error : "enum registry keys failed", rootkey, rootdir); } } while (0); if (ok) { lua_pushinteger(lua, count); return 1; } else { return 2; } } ================================================ FILE: core/src/xmake/winos/registry_query.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author TitanSnow, ruki * @file registry_query.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "registry_query" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the RegGetValueW func type typedef BOOL(WINAPI *xm_RegGetValueW_t)( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* query registry * * local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", "Debugger") */ tb_int_t xm_winos_registry_query(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the arguments tb_char_t const *rootkey = luaL_checkstring(lua, 1); tb_char_t const *rootdir = luaL_checkstring(lua, 2); tb_char_t const *valuename = luaL_checkstring(lua, 3); tb_check_return_val(rootkey && rootdir && valuename, 0); // query key-value tb_bool_t ok = tb_false; HKEY key = tb_null; HKEY keynew = tb_null; tb_char_t *value = tb_null; tb_wchar_t *value_w = tb_null; tb_size_t value_n = (tb_size_t)-1; do { // get registry rootkey if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) { key = HKEY_CLASSES_ROOT; } else if (!tb_strcmp(rootkey, "HKCR")) { key = HKEY_CLASSES_ROOT; } else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) { key = HKEY_CURRENT_CONFIG; } else if (!tb_strcmp(rootkey, "HKCC")) { key = HKEY_CURRENT_CONFIG; } else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) { key = HKEY_CURRENT_USER; } else if (!tb_strcmp(rootkey, "HKCU")) { key = HKEY_CURRENT_USER; } else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) { key = HKEY_LOCAL_MACHINE; } else if (!tb_strcmp(rootkey, "HKLM")) { key = HKEY_LOCAL_MACHINE; } else if (!tb_strcmp(rootkey, "HKEY_USERS")) { key = HKEY_USERS; } else { lua_pushnil(lua); lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey); break; } // convert rootdir to wide characters tb_wchar_t rootdir_w[TB_PATH_MAXN]; if (tb_atow(rootdir_w, rootdir, TB_PATH_MAXN) == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "invalid registry rootkey:: %s", rootdir); break; } // convert valuename to wide characters tb_wchar_t valuename_w[TB_PATH_MAXN]; if (tb_atow(valuename_w, valuename, TB_PATH_MAXN) == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "invalid registry valuename: %s", valuename); break; } // attempt to load RegGetValueW static xm_RegGetValueW_t s_RegGetValueW = tb_null; if (!s_RegGetValueW) { // load the advapi32 module tb_dynamic_ref_t module = (tb_dynamic_ref_t)GetModuleHandleA("advapi32.dll"); if (!module) module = tb_dynamic_init("advapi32.dll"); if (module) s_RegGetValueW = (xm_RegGetValueW_t)tb_dynamic_func(module, "RegGetValueW"); } // get registry value DWORD type = 0; if (s_RegGetValueW) { // get registry value size DWORD valuesize_w = 0; if (s_RegGetValueW(key, rootdir_w, valuename_w, RRF_RT_ANY, 0, tb_null, &valuesize_w) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value size failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } // make value buffer DWORD valuesize = valuesize_w * 2; value = (tb_char_t *)tb_malloc0(valuesize); tb_assert_and_check_break(value); value_w = (tb_wchar_t *)tb_malloc0(valuesize_w); tb_assert_and_check_break(value_w); // get value result, we attempt to do not expand value if get failed type = 0; if (s_RegGetValueW(key, rootdir_w, valuename_w, RRF_RT_ANY, &type, (PVOID)value_w, &valuesize_w) != ERROR_SUCCESS && s_RegGetValueW( key, rootdir_w, valuename_w, RRF_RT_ANY | RRF_NOEXPAND, &type, (PVOID)value_w, &valuesize_w) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } value_n = tb_wtoa(value, value_w, valuesize); if (value_n == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "wtoa registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } } else { // open registry key if (RegOpenKeyExW(key, rootdir_w, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) { lua_pushnil(lua); lua_pushfstring(lua, "open registry key failed: %s\\%s", rootkey, rootdir); break; } // get registry value size DWORD valuesize_w = 0; if (RegQueryValueExW(keynew, valuename_w, tb_null, tb_null, tb_null, &valuesize_w) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value size failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } // make value buffer DWORD valuesize = valuesize_w * 2; value = (tb_char_t *)tb_malloc0(valuesize); tb_assert_and_check_break(value); value_w = (tb_wchar_t *)tb_malloc0(valuesize_w); tb_assert_and_check_break(value_w); // get value result type = 0; if (RegQueryValueExW(keynew, valuename_w, tb_null, &type, (LPBYTE)value_w, &valuesize_w) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } value_n = tb_wtoa(value, value_w, valuesize); if (value_n == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "wtoa registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } } // save result switch (type) { case REG_SZ: case REG_EXPAND_SZ: lua_pushlstring(lua, value, value_n); ok = tb_true; break; case REG_DWORD: lua_pushfstring(lua, "%d", *((tb_int_t *)value)); ok = tb_true; break; case REG_QWORD: lua_pushfstring(lua, "%lld", *((tb_int64_t *)value)); ok = tb_true; break; default: lua_pushnil(lua); lua_pushfstring(lua, "unsupported registry value type: %d", type); break; } } while (0); // exit registry key if (keynew) { RegCloseKey(keynew); } keynew = tb_null; // exit value if (value) { tb_free(value); } value = tb_null; if (value_w) { tb_free(value_w); } value_w = tb_null; return ok ? 1 : 2; } ================================================ FILE: core/src/xmake/winos/registry_values.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file registry_values.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "registry_values" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* get registry values * * local count, errors = winos.registry_values("HKEY_LOCAL_MACHINE", * "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", * function (value_name) * return true -- continue or break * end) */ tb_int_t xm_winos_registry_values(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the arguments tb_char_t const *rootkey = luaL_checkstring(lua, 1); tb_char_t const *rootdir = luaL_checkstring(lua, 2); tb_bool_t is_function = lua_isfunction(lua, 3); tb_check_return_val(rootkey && rootdir && is_function, 0); // enum values tb_bool_t ok = tb_false; tb_int_t count = 0; HKEY key = tb_null; HKEY keynew = tb_null; do { // get registry rootkey if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) { key = HKEY_CLASSES_ROOT; } else if (!tb_strcmp(rootkey, "HKCR")) { key = HKEY_CLASSES_ROOT; } else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) { key = HKEY_CURRENT_CONFIG; } else if (!tb_strcmp(rootkey, "HKCC")) { key = HKEY_CURRENT_CONFIG; } else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) { key = HKEY_CURRENT_USER; } else if (!tb_strcmp(rootkey, "HKCU")) { key = HKEY_CURRENT_USER; } else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) { key = HKEY_LOCAL_MACHINE; } else if (!tb_strcmp(rootkey, "HKLM")) { key = HKEY_LOCAL_MACHINE; } else if (!tb_strcmp(rootkey, "HKEY_USERS")) { key = HKEY_USERS; } else { lua_pushnil(lua); lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey); break; } // open registry key if (RegOpenKeyExA(key, rootdir, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) { lua_pushnil(lua); lua_pushfstring(lua, "open registry key failed: %s\\%s", rootkey, rootdir); break; } // query values DWORD value_name_num = 0; DWORD value_name_maxn = 0; if (RegQueryInfoKeyW(keynew, tb_null, tb_null, tb_null, tb_null, tb_null, tb_null, &value_name_num, &value_name_maxn, tb_null, tb_null, tb_null) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "query registry info failed: %s\\%s", rootkey, rootdir); break; } value_name_maxn++; // add `\0` // ensure enough value name buffer tb_wchar_t value_name[1024]; if (value_name_maxn > tb_arrayn(value_name)) { lua_pushnil(lua); lua_pushfstring(lua, "no enough value name buffer: %s\\%s", rootkey, rootdir); break; } // get all values DWORD i = 0; tb_char_t value_name_a[1024]; for (i = 0; i < value_name_num; i++) { // get value name value_name[0] = L'\0'; DWORD value_name_size = tb_arrayn(value_name); if (RegEnumValueW(keynew, i, value_name, &value_name_size, tb_null, tb_null, tb_null, tb_null) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value name(%d) failed: %s\\%s", i, rootkey, rootdir); break; } // get value name (mbs) tb_size_t value_name_a_size = tb_wtoa(value_name_a, value_name, sizeof(value_name_a)); if (value_name_a_size == -1) { lua_pushnil(lua); lua_pushfstring(lua, "convert registry value name(%d) failed: %s\\%s", i, rootkey, rootdir); break; } // do callback(value_name) lua_pushvalue(lua, 3); lua_pushlstring(lua, value_name_a, value_name_a_size); lua_call(lua, 1, 1); count++; // is continue? tb_bool_t is_continue = lua_toboolean(lua, -1); lua_pop(lua, 1); if (!is_continue) { ok = tb_true; break; } } if (i == value_name_num) ok = tb_true; } while (0); // exit registry key if (keynew) { RegCloseKey(keynew); } keynew = tb_null; if (ok) { lua_pushinteger(lua, count); return 1; } else { return 2; } } ================================================ FILE: core/src/xmake/winos/set_error_mode.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file set_error_mode.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "set_error_mode" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_winos_set_error_mode(lua_State *lua) { tb_size_t mode = (tb_size_t)luaL_checkinteger(lua, 1); lua_pushinteger(lua, (tb_int_t)SetErrorMode((UINT)mode)); return 1; } ================================================ FILE: core/src/xmake/winos/short_path.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file short_path.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "short_path" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* get windows short path from long path * * local short_path, errors = winos.short_path(long_path) */ tb_int_t xm_winos_short_path(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the arguments tb_char_t const *long_path = luaL_checkstring(lua, 1); tb_check_return_val(long_path, 0); // convert long path to wide characters tb_wchar_t long_path_w[TB_PATH_MAXN]; if (tb_atow(long_path_w, long_path, TB_PATH_MAXN) == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "invalid long path: %s", long_path); return 2; } // get short path tb_wchar_t short_path_w[TB_PATH_MAXN]; if (GetShortPathNameW(long_path_w, short_path_w, TB_PATH_MAXN) == 0) { lua_pushnil(lua); lua_pushfstring(lua, "cannot get short path from: %s", long_path); return 2; } // return result tb_char_t *short_path_a = (tb_char_t *)long_path_w; tb_size_t short_path_n = tb_wtoa(short_path_a, short_path_w, TB_PATH_MAXN); if (short_path_n == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "invalid short path from %s!", long_path); return 2; } lua_pushlstring(lua, short_path_a, short_path_n); return 1; } ================================================ FILE: core/src/xmake/xmake.c ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file xmake.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "xmake.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static __tb_inline__ tb_bool_t xm_check_mode(tb_size_t mode) { #ifdef __xm_debug__ if (!(mode & TB_MODE_DEBUG)) { tb_trace_e("libxmake.a has __tb_debug__ but xmake/xmake.h not"); return tb_false; } #else if (mode & TB_MODE_DEBUG) { tb_trace_e("xmake/xmake.h has __tb_debug__ but libxmake.a not"); return tb_false; } #endif #ifdef __xm_small__ if (!(mode & TB_MODE_SMALL)) { tb_trace_e("libxmake.a has __tb_small__ but xmake/xmake.h not"); return tb_false; } #else if (mode & TB_MODE_SMALL) { tb_trace_e("xmake/xmake.h has __tb_small__ but libxmake.a not"); return tb_false; } #endif return tb_true; } static __tb_inline__ tb_bool_t xm_version_check(tb_hize_t build) { // the version oly for link the static vtag string tb_version_t const *version = xm_version(); tb_used(version); if ((build / 100) == (XM_VERSION_BUILD / 100)) { tb_trace_d("version: %s", XM_VERSION_STRING); return tb_true; } else { tb_trace_w("version: %s != %llu", XM_VERSION_STRING, build); } // no return tb_false; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t xm_init_(tb_size_t mode, tb_hize_t build) { tb_trace_d("init: .."); // check mode if (!xm_check_mode(mode)) { return tb_false; } // check version xm_version_check(build); #if 0 // init tbox, we always use the tbox's default allocator if (!tb_init(tb_null, tb_default_allocator(tb_null, 0))) return tb_false; #else // init tbox, since small compilation mode is enabled, it still uses the native allocator if (!tb_init(tb_null, tb_null)) { return tb_false; } #endif tb_trace_d("init: ok"); return tb_true; } tb_void_t xm_exit() { // exit tbox tb_exit(); } tb_version_t const *xm_version() { // init version tag for binary search static __tb_volatile__ tb_char_t const *s_vtag = "[xmake]: [vtag]: " XM_VERSION_STRING; tb_used(s_vtag); // init version static tb_version_t s_version = { 0 }; if (!s_version.major) { s_version.major = XM_VERSION_MAJOR; s_version.minor = XM_VERSION_MINOR; s_version.alter = XM_VERSION_ALTER; s_version.build = (tb_hize_t)tb_atoll(XM_VERSION_BUILD_STRING); } return &s_version; } ================================================ FILE: core/src/xmake/xmake.config.h.in ================================================ #ifndef XM_CONFIG_H #define XM_CONFIG_H // version #define XM_CONFIG_VERSION "${VERSION}" #define XM_CONFIG_VERSION_MAJOR ${VERSION_MAJOR} #define XM_CONFIG_VERSION_MINOR ${VERSION_MINOR} #define XM_CONFIG_VERSION_ALTER ${VERSION_ALTER} #define XM_CONFIG_VERSION_BUILD ${VERSION_BUILD} #define XM_CONFIG_VERSION_BRANCH "${GIT_BRANCH}" #define XM_CONFIG_VERSION_COMMIT "${GIT_COMMIT}" #endif ================================================ FILE: core/src/xmake/xmake.h ================================================ /*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file xmake.h * */ #ifndef XM_XMAKE_H #define XM_XMAKE_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include "engine.h" /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ __tb_extern_c_enter__ /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #ifdef __xm_debug__ #define __xm_mode_debug__ TB_MODE_DEBUG #else #define __xm_mode_debug__ (0) #endif #ifdef __xm_small__ #define __xm_mode_small__ TB_MODE_SMALL #else #define __xm_mode_small__ (0) #endif /*! init xmake * * @return tb_true or tb_false * * @code #include "xmake/xmake.h" int main(int argc, char** argv) { // init xmake if (!xm_init()) return 0; // exit xmake xm_exit(); return 0; } * @endcode */ #define xm_init() xm_init_((tb_size_t)(__xm_mode_debug__ | __xm_mode_small__), XM_VERSION_BUILD) /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ /*! init the xmake library * * @param mode the compile mode for check __tb_small__ and __tb_debug__ * @param build the build version * * @return tb_true or tb_false */ tb_bool_t xm_init_(tb_size_t mode, tb_hize_t build); /// exit the xmake library tb_void_t xm_exit(tb_noarg_t); /*! the xmake version * * @return the xmake version */ tb_version_t const *xm_version(tb_noarg_t); /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ __tb_extern_c_leave__ #endif ================================================ FILE: core/src/xmake/xmake.lua ================================================ target("xmake") set_kind("static") -- add deps add_deps("sv", "lz4") if namespace then add_deps("tbox::tbox") else add_deps("tbox") end if is_config("runtime", "luajit") then add_deps("luajit") else add_deps("lua") end if has_config("lua_cjson") then add_deps("lua-cjson") end if is_plat("windows") and has_config("pdcurses") then add_deps("pdcurses") end -- add definitions add_defines("__tb_prefix__=\"xmake\"") if is_mode("debug") then add_defines("__tb_debug__", {public = true}) end -- set the auto-generated config.h set_configdir("$(builddir)/$(plat)/$(arch)/$(mode)") add_configfiles("xmake.config.h.in") -- add includes directory add_includedirs("..", {interface = true}) add_includedirs("$(builddir)/$(plat)/$(arch)/$(mode)", {public = true}) add_includedirs("../xxhash") add_includedirs("$(projectdir)/../xmake/scripts/module") -- add header files add_headerfiles("../(xmake/*.h)") add_headerfiles("../(xmake/prefix/*.h)") add_headerfiles("$(builddir)/$(plat)/$(arch)/$(mode)/xmake.config.h", {prefixdir = "xmake"}) -- add the common source files add_files("**.c|winos/*.c") if is_plat("windows", "msys", "mingw", "cygwin") then add_files("winos/*.c") end -- add options add_options("readline") if is_plat("windows") then add_options("pdcurses") else add_options("curses") end -- add definitions if is_plat("windows") then add_defines("UNICODE", "_UNICODE") end -- embed all script files add_rules("utils.bin2obj", {extensions = ".xmz"}) on_config(function (target) import("utils.archive.archive") if has_config("embed") then local archivefile = path.join(target:autogendir(), "bin2obj", "xmake.xmz") print("archiving %s ..", archivefile) os.tryrm(archivefile) local rootdir = path.normalize(path.join(os.projectdir(), "..", "xmake")) archive(archivefile, rootdir, {recurse = true, curdir = rootdir}) target:add("files", archivefile) target:add("defines", "XM_EMBED_ENABLE=1") end end) ================================================ FILE: core/src/xmake/xmake.sh ================================================ #!/bin/sh target "xmake" set_kind "static" set_default false # add deps if has_config "external"; then local libs="lz4 sv tbox" for lib in $libs; do if has_config "$lib"; then add_options "$lib" "{public}" fi done if is_config "runtime" "luajit"; then if has_config "luajit"; then add_options "luajit" "{public}" fi else if has_config "lua"; then add_options "lua" "{public}" fi fi else local libs="lua_cjson lz4 sv tbox" for lib in $libs; do add_deps "$lib" done if is_config "runtime" "luajit"; then add_deps "luajit" else add_deps "lua" fi fi # add options add_options "readline" "curses" "{public}" # add definitions add_defines "__tb_prefix__=\"xmake\"" if is_mode "debug"; then add_defines "__tb_debug__" "{public}" fi # set the auto-generated config.h set_configdir "${builddir}/${plat}/${arch}/${mode}" add_configfiles "xmake.config.h.in" # add includes directory add_includedirs ".." "{public}" add_includedirs "${builddir}/${plat}/${arch}/${mode}" "{public}" add_includedirs "../xxhash" add_includedirs "${projectdir}/xmake/scripts/module" # add the common source files add_files "*.c" add_files "base64/*.c" add_files "bloom_filter/*.c" add_files "curses/*.c" add_files "fwatcher/*.c" add_files "hash/*.c" add_files "io/*.c" add_files "libc/*.c" add_files "lz4/*.c" add_files "os/*.c" add_files "path/*.c" add_files "package/*.c" add_files "process/*.c" add_files "readline/*.c" add_files "sandbox/*.c" add_files "semver/*.c" add_files "string/*.c" add_files "utf8/*.c" add_files "utils/*.c" add_files "tty/*.c" add_files "binutils/*.c" add_files "binutils/coff/*.c" add_files "binutils/macho/*.c" add_files "binutils/elf/*.c" add_files "binutils/wasm/*.c" add_files "binutils/ar/*.c" add_files "binutils/mslib/*.c" add_files "thread/*.c" if is_plat "mingw"; then add_files "winos/*.c" fi ================================================ FILE: core/src/xxhash/xxhash/LICENSE ================================================ xxHash Library Copyright (c) 2012-2021 Yann Collet All rights reserved. BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: core/src/xxhash/xxhash/xxhash.h ================================================ /* * xxHash - Extremely Fast Hash algorithm * Header File * Copyright (C) 2012-2023 Yann Collet * * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You can contact the author at: * - xxHash homepage: https://www.xxhash.com * - xxHash source repository: https://github.com/Cyan4973/xxHash */ /*! * @mainpage xxHash * * xxHash is an extremely fast non-cryptographic hash algorithm, working at RAM speed * limits. * * It is proposed in four flavors, in three families: * 1. @ref XXH32_family * - Classic 32-bit hash function. Simple, compact, and runs on almost all * 32-bit and 64-bit systems. * 2. @ref XXH64_family * - Classic 64-bit adaptation of XXH32. Just as simple, and runs well on most * 64-bit systems (but _not_ 32-bit systems). * 3. @ref XXH3_family * - Modern 64-bit and 128-bit hash function family which features improved * strength and performance across the board, especially on smaller data. * It benefits greatly from SIMD and 64-bit without requiring it. * * Benchmarks * --- * The reference system uses an Intel i7-9700K CPU, and runs Ubuntu x64 20.04. * The open source benchmark program is compiled with clang v10.0 using -O3 flag. * * | Hash Name | ISA ext | Width | Large Data Speed | Small Data Velocity | * | -------------------- | ------- | ----: | ---------------: | ------------------: | * | XXH3_64bits() | @b AVX2 | 64 | 59.4 GB/s | 133.1 | * | MeowHash | AES-NI | 128 | 58.2 GB/s | 52.5 | * | XXH3_128bits() | @b AVX2 | 128 | 57.9 GB/s | 118.1 | * | CLHash | PCLMUL | 64 | 37.1 GB/s | 58.1 | * | XXH3_64bits() | @b SSE2 | 64 | 31.5 GB/s | 133.1 | * | XXH3_128bits() | @b SSE2 | 128 | 29.6 GB/s | 118.1 | * | RAM sequential read | | N/A | 28.0 GB/s | N/A | * | ahash | AES-NI | 64 | 22.5 GB/s | 107.2 | * | City64 | | 64 | 22.0 GB/s | 76.6 | * | T1ha2 | | 64 | 22.0 GB/s | 99.0 | * | City128 | | 128 | 21.7 GB/s | 57.7 | * | FarmHash | AES-NI | 64 | 21.3 GB/s | 71.9 | * | XXH64() | | 64 | 19.4 GB/s | 71.0 | * | SpookyHash | | 64 | 19.3 GB/s | 53.2 | * | Mum | | 64 | 18.0 GB/s | 67.0 | * | CRC32C | SSE4.2 | 32 | 13.0 GB/s | 57.9 | * | XXH32() | | 32 | 9.7 GB/s | 71.9 | * | City32 | | 32 | 9.1 GB/s | 66.0 | * | Blake3* | @b AVX2 | 256 | 4.4 GB/s | 8.1 | * | Murmur3 | | 32 | 3.9 GB/s | 56.1 | * | SipHash* | | 64 | 3.0 GB/s | 43.2 | * | Blake3* | @b SSE2 | 256 | 2.4 GB/s | 8.1 | * | HighwayHash | | 64 | 1.4 GB/s | 6.0 | * | FNV64 | | 64 | 1.2 GB/s | 62.7 | * | Blake2* | | 256 | 1.1 GB/s | 5.1 | * | SHA1* | | 160 | 0.8 GB/s | 5.6 | * | MD5* | | 128 | 0.6 GB/s | 7.8 | * @note * - Hashes which require a specific ISA extension are noted. SSE2 is also noted, * even though it is mandatory on x64. * - Hashes with an asterisk are cryptographic. Note that MD5 is non-cryptographic * by modern standards. * - Small data velocity is a rough average of algorithm's efficiency for small * data. For more accurate information, see the wiki. * - More benchmarks and strength tests are found on the wiki: * https://github.com/Cyan4973/xxHash/wiki * * Usage * ------ * All xxHash variants use a similar API. Changing the algorithm is a trivial * substitution. * * @pre * For functions which take an input and length parameter, the following * requirements are assumed: * - The range from [`input`, `input + length`) is valid, readable memory. * - The only exception is if the `length` is `0`, `input` may be `NULL`. * - For C++, the objects must have the *TriviallyCopyable* property, as the * functions access bytes directly as if it was an array of `unsigned char`. * * @anchor single_shot_example * **Single Shot** * * These functions are stateless functions which hash a contiguous block of memory, * immediately returning the result. They are the easiest and usually the fastest * option. * * XXH32(), XXH64(), XXH3_64bits(), XXH3_128bits() * * @code{.c} * #include * #include "xxhash.h" * * // Example for a function which hashes a null terminated string with XXH32(). * XXH32_hash_t hash_string(const char* string, XXH32_hash_t seed) * { * // NULL pointers are only valid if the length is zero * size_t length = (string == NULL) ? 0 : strlen(string); * return XXH32(string, length, seed); * } * @endcode * * * @anchor streaming_example * **Streaming** * * These groups of functions allow incremental hashing of unknown size, even * more than what would fit in a size_t. * * XXH32_reset(), XXH64_reset(), XXH3_64bits_reset(), XXH3_128bits_reset() * * @code{.c} * #include * #include * #include "xxhash.h" * // Example for a function which hashes a FILE incrementally with XXH3_64bits(). * XXH64_hash_t hashFile(FILE* f) * { * // Allocate a state struct. Do not just use malloc() or new. * XXH3_state_t* state = XXH3_createState(); * assert(state != NULL && "Out of memory!"); * // Reset the state to start a new hashing session. * XXH3_64bits_reset(state); * char buffer[4096]; * size_t count; * // Read the file in chunks * while ((count = fread(buffer, 1, sizeof(buffer), f)) != 0) { * // Run update() as many times as necessary to process the data * XXH3_64bits_update(state, buffer, count); * } * // Retrieve the finalized hash. This will not change the state. * XXH64_hash_t result = XXH3_64bits_digest(state); * // Free the state. Do not use free(). * XXH3_freeState(state); * return result; * } * @endcode * * Streaming functions generate the xxHash value from an incremental input. * This method is slower than single-call functions, due to state management. * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. * * An XXH state must first be allocated using `XXH*_createState()`. * * Start a new hash by initializing the state with a seed using `XXH*_reset()`. * * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. * * The function returns an error code, with 0 meaning OK, and any other value * meaning there is an error. * * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. * This function returns the nn-bits hash as an int or long long. * * It's still possible to continue inserting input into the hash state after a * digest, and generate new hash values later on by invoking `XXH*_digest()`. * * When done, release the state using `XXH*_freeState()`. * * * @anchor canonical_representation_example * **Canonical Representation** * * The default return values from XXH functions are unsigned 32, 64 and 128 bit * integers. * This the simplest and fastest format for further post-processing. * * However, this leaves open the question of what is the order on the byte level, * since little and big endian conventions will store the same number differently. * * The canonical representation settles this issue by mandating big-endian * convention, the same convention as human-readable numbers (large digits first). * * When writing hash values to storage, sending them over a network, or printing * them, it's highly recommended to use the canonical representation to ensure * portability across a wider range of systems, present and future. * * The following functions allow transformation of hash values to and from * canonical format. * * XXH32_canonicalFromHash(), XXH32_hashFromCanonical(), * XXH64_canonicalFromHash(), XXH64_hashFromCanonical(), * XXH128_canonicalFromHash(), XXH128_hashFromCanonical(), * * @code{.c} * #include * #include "xxhash.h" * * // Example for a function which prints XXH32_hash_t in human readable format * void printXxh32(XXH32_hash_t hash) * { * XXH32_canonical_t cano; * XXH32_canonicalFromHash(&cano, hash); * size_t i; * for(i = 0; i < sizeof(cano.digest); ++i) { * printf("%02x", cano.digest[i]); * } * printf("\n"); * } * * // Example for a function which converts XXH32_canonical_t to XXH32_hash_t * XXH32_hash_t convertCanonicalToXxh32(XXH32_canonical_t cano) * { * XXH32_hash_t hash = XXH32_hashFromCanonical(&cano); * return hash; * } * @endcode * * * @file xxhash.h * xxHash prototypes and implementation */ #if defined(__cplusplus) && !defined(XXH_NO_EXTERNC_GUARD) extern "C" { #endif /* **************************** * INLINE mode ******************************/ /*! * @defgroup public Public API * Contains details on the public xxHash functions. * @{ */ #ifdef XXH_DOXYGEN /*! * @brief Gives access to internal state declaration, required for static allocation. * * Incompatible with dynamic linking, due to risks of ABI changes. * * Usage: * @code{.c} * #define XXH_STATIC_LINKING_ONLY * #include "xxhash.h" * @endcode */ # define XXH_STATIC_LINKING_ONLY /* Do not undef XXH_STATIC_LINKING_ONLY for Doxygen */ /*! * @brief Gives access to internal definitions. * * Usage: * @code{.c} * #define XXH_STATIC_LINKING_ONLY * #define XXH_IMPLEMENTATION * #include "xxhash.h" * @endcode */ # define XXH_IMPLEMENTATION /* Do not undef XXH_IMPLEMENTATION for Doxygen */ /*! * @brief Exposes the implementation and marks all functions as `inline`. * * Use these build macros to inline xxhash into the target unit. * Inlining improves performance on small inputs, especially when the length is * expressed as a compile-time constant: * * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html * * It also keeps xxHash symbols private to the unit, so they are not exported. * * Usage: * @code{.c} * #define XXH_INLINE_ALL * #include "xxhash.h" * @endcode * Do not compile and link xxhash.o as a separate object, as it is not useful. */ # define XXH_INLINE_ALL # undef XXH_INLINE_ALL /*! * @brief Exposes the implementation without marking functions as inline. */ # define XXH_PRIVATE_API # undef XXH_PRIVATE_API /*! * @brief Emulate a namespace by transparently prefixing all symbols. * * If you want to include _and expose_ xxHash functions from within your own * library, but also want to avoid symbol collisions with other libraries which * may also include xxHash, you can use @ref XXH_NAMESPACE to automatically prefix * any public symbol from xxhash library with the value of @ref XXH_NAMESPACE * (therefore, avoid empty or numeric values). * * Note that no change is required within the calling program as long as it * includes `xxhash.h`: Regular symbol names will be automatically translated * by this header. */ # define XXH_NAMESPACE /* YOUR NAME HERE */ # undef XXH_NAMESPACE #endif #if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ && !defined(XXH_INLINE_ALL_31684351384) /* this section should be traversed only once */ # define XXH_INLINE_ALL_31684351384 /* give access to the advanced API, required to compile implementations */ # undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ # define XXH_STATIC_LINKING_ONLY /* make all functions private */ # undef XXH_PUBLIC_API # if defined(__GNUC__) # define XXH_PUBLIC_API static __inline __attribute__((__unused__)) # elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # define XXH_PUBLIC_API static inline # elif defined(_MSC_VER) # define XXH_PUBLIC_API static __inline # else /* note: this version may generate warnings for unused static functions */ # define XXH_PUBLIC_API static # endif /* * This part deals with the special case where a unit wants to inline xxHash, * but "xxhash.h" has previously been included without XXH_INLINE_ALL, * such as part of some previously included *.h header file. * Without further action, the new include would just be ignored, * and functions would effectively _not_ be inlined (silent failure). * The following macros solve this situation by prefixing all inlined names, * avoiding naming collision with previous inclusions. */ /* Before that, we unconditionally #undef all symbols, * in case they were already defined with XXH_NAMESPACE. * They will then be redefined for XXH_INLINE_ALL */ # undef XXH_versionNumber /* XXH32 */ # undef XXH32 # undef XXH32_createState # undef XXH32_freeState # undef XXH32_reset # undef XXH32_update # undef XXH32_digest # undef XXH32_copyState # undef XXH32_canonicalFromHash # undef XXH32_hashFromCanonical /* XXH64 */ # undef XXH64 # undef XXH64_createState # undef XXH64_freeState # undef XXH64_reset # undef XXH64_update # undef XXH64_digest # undef XXH64_copyState # undef XXH64_canonicalFromHash # undef XXH64_hashFromCanonical /* XXH3_64bits */ # undef XXH3_64bits # undef XXH3_64bits_withSecret # undef XXH3_64bits_withSeed # undef XXH3_64bits_withSecretandSeed # undef XXH3_createState # undef XXH3_freeState # undef XXH3_copyState # undef XXH3_64bits_reset # undef XXH3_64bits_reset_withSeed # undef XXH3_64bits_reset_withSecret # undef XXH3_64bits_update # undef XXH3_64bits_digest # undef XXH3_generateSecret /* XXH3_128bits */ # undef XXH128 # undef XXH3_128bits # undef XXH3_128bits_withSeed # undef XXH3_128bits_withSecret # undef XXH3_128bits_reset # undef XXH3_128bits_reset_withSeed # undef XXH3_128bits_reset_withSecret # undef XXH3_128bits_reset_withSecretandSeed # undef XXH3_128bits_update # undef XXH3_128bits_digest # undef XXH128_isEqual # undef XXH128_cmp # undef XXH128_canonicalFromHash # undef XXH128_hashFromCanonical /* Finally, free the namespace itself */ # undef XXH_NAMESPACE /* employ the namespace for XXH_INLINE_ALL */ # define XXH_NAMESPACE XXH_INLINE_ /* * Some identifiers (enums, type names) are not symbols, * but they must nonetheless be renamed to avoid redeclaration. * Alternative solution: do not redeclare them. * However, this requires some #ifdefs, and has a more dispersed impact. * Meanwhile, renaming can be achieved in a single place. */ # define XXH_IPREF(Id) XXH_NAMESPACE ## Id # define XXH_OK XXH_IPREF(XXH_OK) # define XXH_ERROR XXH_IPREF(XXH_ERROR) # define XXH_errorcode XXH_IPREF(XXH_errorcode) # define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) # define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) # define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) # define XXH32_state_s XXH_IPREF(XXH32_state_s) # define XXH32_state_t XXH_IPREF(XXH32_state_t) # define XXH64_state_s XXH_IPREF(XXH64_state_s) # define XXH64_state_t XXH_IPREF(XXH64_state_t) # define XXH3_state_s XXH_IPREF(XXH3_state_s) # define XXH3_state_t XXH_IPREF(XXH3_state_t) # define XXH128_hash_t XXH_IPREF(XXH128_hash_t) /* Ensure the header is parsed again, even if it was previously included */ # undef XXHASH_H_5627135585666179 # undef XXHASH_H_STATIC_13879238742 #endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ /* **************************************************************** * Stable API *****************************************************************/ #ifndef XXHASH_H_5627135585666179 #define XXHASH_H_5627135585666179 1 /*! @brief Marks a global symbol. */ #if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) # if defined(_WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) # ifdef XXH_EXPORT # define XXH_PUBLIC_API __declspec(dllexport) # elif XXH_IMPORT # define XXH_PUBLIC_API __declspec(dllimport) # endif # else # define XXH_PUBLIC_API /* do nothing */ # endif #endif #ifdef XXH_NAMESPACE # define XXH_CAT(A,B) A##B # define XXH_NAME2(A,B) XXH_CAT(A,B) # define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) /* XXH32 */ # define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) # define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) # define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) # define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) # define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) # define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) # define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) # define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) # define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) /* XXH64 */ # define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) # define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) # define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) # define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) # define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) # define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) # define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) # define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) # define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) /* XXH3_64bits */ # define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) # define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) # define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) # define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) # define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) # define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) # define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) # define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) # define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) # define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) # define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) # define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) # define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) # define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) # define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) /* XXH3_128bits */ # define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) # define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) # define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) # define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) # define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) # define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) # define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) # define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) # define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) # define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) # define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) # define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) # define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) # define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) # define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) #endif /* ************************************* * Compiler specifics ***************************************/ /* specific declaration modes for Windows */ #if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) # if defined(_WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) # ifdef XXH_EXPORT # define XXH_PUBLIC_API __declspec(dllexport) # elif XXH_IMPORT # define XXH_PUBLIC_API __declspec(dllimport) # endif # else # define XXH_PUBLIC_API /* do nothing */ # endif #endif #if defined (__GNUC__) # define XXH_CONSTF __attribute__((__const__)) # define XXH_PUREF __attribute__((__pure__)) # define XXH_MALLOCF __attribute__((__malloc__)) #else # define XXH_CONSTF /* disable */ # define XXH_PUREF # define XXH_MALLOCF #endif /* ************************************* * Version ***************************************/ #define XXH_VERSION_MAJOR 0 #define XXH_VERSION_MINOR 8 #define XXH_VERSION_RELEASE 3 /*! @brief Version number, encoded as two digits each */ #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) /*! * @brief Obtains the xxHash version. * * This is mostly useful when xxHash is compiled as a shared library, * since the returned value comes from the library, as opposed to header file. * * @return @ref XXH_VERSION_NUMBER of the invoked library. */ XXH_PUBLIC_API XXH_CONSTF unsigned XXH_versionNumber (void); /* **************************** * Common basic types ******************************/ #include /* size_t */ /*! * @brief Exit code for the streaming API. */ typedef enum { XXH_OK = 0, /*!< OK */ XXH_ERROR /*!< Error */ } XXH_errorcode; /*-********************************************************************** * 32-bit hash ************************************************************************/ #if defined(XXH_DOXYGEN) /* Don't show include */ /*! * @brief An unsigned 32-bit integer. * * Not necessarily defined to `uint32_t` but functionally equivalent. */ typedef uint32_t XXH32_hash_t; #elif !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # ifdef _AIX # include # else # include # endif typedef uint32_t XXH32_hash_t; #else # include # if UINT_MAX == 0xFFFFFFFFUL typedef unsigned int XXH32_hash_t; # elif ULONG_MAX == 0xFFFFFFFFUL typedef unsigned long XXH32_hash_t; # else # error "unsupported platform: need a 32-bit type" # endif #endif /*! * @} * * @defgroup XXH32_family XXH32 family * @ingroup public * Contains functions used in the classic 32-bit xxHash algorithm. * * @note * XXH32 is useful for older platforms, with no or poor 64-bit performance. * Note that the @ref XXH3_family provides competitive speed for both 32-bit * and 64-bit systems, and offers true 64/128 bit hash results. * * @see @ref XXH64_family, @ref XXH3_family : Other xxHash families * @see @ref XXH32_impl for implementation details * @{ */ /*! * @brief Calculates the 32-bit hash of @p input using xxHash32. * * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * @param seed The 32-bit seed to alter the hash's output predictably. * * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 32-bit xxHash32 value. * * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); #ifndef XXH_NO_STREAM /*! * @typedef struct XXH32_state_s XXH32_state_t * @brief The opaque state struct for the XXH32 streaming API. * * @see XXH32_state_s for details. * @see @ref streaming_example "Streaming Example" */ typedef struct XXH32_state_s XXH32_state_t; /*! * @brief Allocates an @ref XXH32_state_t. * * @return An allocated pointer of @ref XXH32_state_t on success. * @return `NULL` on failure. * * @note Must be freed with XXH32_freeState(). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_MALLOCF XXH32_state_t* XXH32_createState(void); /*! * @brief Frees an @ref XXH32_state_t. * * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). * * @return @ref XXH_OK. * * @note @p statePtr must be allocated with XXH32_createState(). * * @see @ref streaming_example "Streaming Example" * */ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); /*! * @brief Copies one @ref XXH32_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); /*! * @brief Resets an @ref XXH32_state_t to begin a new hash. * * @param statePtr The state struct to reset. * @param seed The 32-bit seed to alter the hash result predictably. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note This function resets and seeds a state. Call it before @ref XXH32_update(). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); /*! * @brief Consumes a block of @p input to an @ref XXH32_state_t. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note Call this to incrementally consume blocks of data. * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); /*! * @brief Returns the calculated hash value from an @ref XXH32_state_t. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated 32-bit xxHash32 value from that state. * * @note * Calling XXH32_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! * @brief Canonical (big endian) representation of @ref XXH32_hash_t. */ typedef struct { unsigned char digest[4]; /*!< Hash bytes, big endian */ } XXH32_canonical_t; /*! * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t. * * @param dst The @ref XXH32_canonical_t pointer to be stored to. * @param hash The @ref XXH32_hash_t to be converted. * * @pre * @p dst must not be `NULL`. * * @see @ref canonical_representation_example "Canonical Representation Example" */ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); /*! * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. * * @param src The @ref XXH32_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. * * @see @ref canonical_representation_example "Canonical Representation Example" */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); /*! @cond Doxygen ignores this part */ #ifdef __has_attribute # define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) #else # define XXH_HAS_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * C23 __STDC_VERSION__ number hasn't been specified yet. For now * leave as `201711L` (C17 + 1). * TODO: Update to correct value when its been specified. */ #define XXH_C23_VN 201711L /*! @endcond */ /*! @cond Doxygen ignores this part */ /* C-language Attributes are added in C23. */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) && defined(__has_c_attribute) # define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) #else # define XXH_HAS_C_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ #if defined(__cplusplus) && defined(__has_cpp_attribute) # define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) #else # define XXH_HAS_CPP_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute * introduced in CPP17 and C23. * CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough * C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough */ #if XXH_HAS_C_ATTRIBUTE(fallthrough) || XXH_HAS_CPP_ATTRIBUTE(fallthrough) # define XXH_FALLTHROUGH [[fallthrough]] #elif XXH_HAS_ATTRIBUTE(__fallthrough__) # define XXH_FALLTHROUGH __attribute__ ((__fallthrough__)) #else # define XXH_FALLTHROUGH /* fallthrough */ #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * Define XXH_NOESCAPE for annotated pointers in public API. * https://clang.llvm.org/docs/AttributeReference.html#noescape * As of writing this, only supported by clang. */ #if XXH_HAS_ATTRIBUTE(noescape) # define XXH_NOESCAPE __attribute__((__noescape__)) #else # define XXH_NOESCAPE #endif /*! @endcond */ /*! * @} * @ingroup public * @{ */ #ifndef XXH_NO_LONG_LONG /*-********************************************************************** * 64-bit hash ************************************************************************/ #if defined(XXH_DOXYGEN) /* don't include */ /*! * @brief An unsigned 64-bit integer. * * Not necessarily defined to `uint64_t` but functionally equivalent. */ typedef uint64_t XXH64_hash_t; #elif !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # ifdef _AIX # include # else # include # endif typedef uint64_t XXH64_hash_t; #else # include # if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL /* LP64 ABI says uint64_t is unsigned long */ typedef unsigned long XXH64_hash_t; # else /* the following type must have a width of 64-bit */ typedef unsigned long long XXH64_hash_t; # endif #endif /*! * @} * * @defgroup XXH64_family XXH64 family * @ingroup public * @{ * Contains functions used in the classic 64-bit xxHash algorithm. * * @note * XXH3 provides competitive speed for both 32-bit and 64-bit systems, * and offers true 64/128 bit hash results. * It provides better speed for systems with vector processing capabilities. */ /*! * @brief Calculates the 64-bit hash of @p input using xxHash64. * * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * @param seed The 64-bit seed to alter the hash's output predictably. * * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 64-bit xxHash64 value. * * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed); /******* Streaming *******/ #ifndef XXH_NO_STREAM /*! * @brief The opaque state struct for the XXH64 streaming API. * * @see XXH64_state_s for details. * @see @ref streaming_example "Streaming Example" */ typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ /*! * @brief Allocates an @ref XXH64_state_t. * * @return An allocated pointer of @ref XXH64_state_t on success. * @return `NULL` on failure. * * @note Must be freed with XXH64_freeState(). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_MALLOCF XXH64_state_t* XXH64_createState(void); /*! * @brief Frees an @ref XXH64_state_t. * * @param statePtr A pointer to an @ref XXH64_state_t allocated with @ref XXH64_createState(). * * @return @ref XXH_OK. * * @note @p statePtr must be allocated with XXH64_createState(). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); /*! * @brief Copies one @ref XXH64_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dst_state, const XXH64_state_t* src_state); /*! * @brief Resets an @ref XXH64_state_t to begin a new hash. * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the hash result predictably. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note This function resets and seeds a state. Call it before @ref XXH64_update(). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed); /*! * @brief Consumes a block of @p input to an @ref XXH64_state_t. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note Call this to incrementally consume blocks of data. * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated hash value from an @ref XXH64_state_t. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated 64-bit xxHash64 value from that state. * * @note * Calling XXH64_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_digest (XXH_NOESCAPE const XXH64_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! * @brief Canonical (big endian) representation of @ref XXH64_hash_t. */ typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; /*! * @brief Converts an @ref XXH64_hash_t to a big endian @ref XXH64_canonical_t. * * @param dst The @ref XXH64_canonical_t pointer to be stored to. * @param hash The @ref XXH64_hash_t to be converted. * * @pre * @p dst must not be `NULL`. * * @see @ref canonical_representation_example "Canonical Representation Example" */ XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash); /*! * @brief Converts an @ref XXH64_canonical_t to a native @ref XXH64_hash_t. * * @param src The @ref XXH64_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. * * @see @ref canonical_representation_example "Canonical Representation Example" */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src); #ifndef XXH_NO_XXH3 /*! * @} * ************************************************************************ * @defgroup XXH3_family XXH3 family * @ingroup public * @{ * * XXH3 is a more recent hash algorithm featuring: * - Improved speed for both small and large inputs * - True 64-bit and 128-bit outputs * - SIMD acceleration * - Improved 32-bit viability * * Speed analysis methodology is explained here: * * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html * * Compared to XXH64, expect XXH3 to run approximately * ~2x faster on large inputs and >3x faster on small ones, * exact differences vary depending on platform. * * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, * but does not require it. * Most 32-bit and 64-bit targets that can run XXH32 smoothly can run XXH3 * at competitive speeds, even without vector support. Further details are * explained in the implementation. * * XXH3 has a fast scalar implementation, but it also includes accelerated SIMD * implementations for many common platforms: * - AVX512 * - AVX2 * - SSE2 * - ARM NEON * - WebAssembly SIMD128 * - POWER8 VSX * - s390x ZVector * This can be controlled via the @ref XXH_VECTOR macro, but it automatically * selects the best version according to predefined macros. For the x86 family, an * automatic runtime dispatcher is included separately in @ref xxh_x86dispatch.c. * * XXH3 implementation is portable: * it has a generic C90 formulation that can be compiled on any platform, * all implementations generate exactly the same hash value on all platforms. * Starting from v0.8.0, it's also labelled "stable", meaning that * any future version will also generate the same hash value. * * XXH3 offers 2 variants, _64bits and _128bits. * * When only 64 bits are needed, prefer invoking the _64bits variant, as it * reduces the amount of mixing, resulting in faster speed on small inputs. * It's also generally simpler to manipulate a scalar return type than a struct. * * The API supports one-shot hashing, streaming mode, and custom secrets. */ /*! * @ingroup tuning * @brief Possible values for @ref XXH_VECTOR. * * Unless set explicitly, determined automatically. */ # define XXH_SCALAR 0 /*!< Portable scalar version */ # define XXH_SSE2 1 /*!< SSE2 for Pentium 4, Opteron, all x86_64. */ # define XXH_AVX2 2 /*!< AVX2 for Haswell and Bulldozer */ # define XXH_AVX512 3 /*!< AVX512 for Skylake and Icelake */ # define XXH_NEON 4 /*!< NEON for most ARMv7-A, all AArch64, and WASM SIMD128 */ # define XXH_VSX 5 /*!< VSX and ZVector for POWER8/z13 (64-bit) */ # define XXH_SVE 6 /*!< SVE for some ARMv8-A and ARMv9-A */ # define XXH_LSX 7 /*!< LSX (128-bit SIMD) for LoongArch64 */ # define XXH_LASX 8 /*!< LASX (256-bit SIMD) for LoongArch64 */ /*-********************************************************************** * XXH3 64-bit variant ************************************************************************/ /*! * @brief Calculates 64-bit unseeded variant of XXH3 hash of @p input. * * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 64-bit XXH3 hash value. * * @note * This is equivalent to @ref XXH3_64bits_withSeed() with a seed of `0`, however * it may have slightly better performance due to constant propagation of the * defaults. * * @see * XXH3_64bits_withSeed(), XXH3_64bits_withSecret(): other seeding variants * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length); /*! * @brief Calculates 64-bit seeded variant of XXH3 hash of @p input. * * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * @param seed The 64-bit seed to alter the hash result predictably. * * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 64-bit XXH3 hash value. * * @note * seed == 0 produces the same results as @ref XXH3_64bits(). * * This variant generates a custom secret on the fly based on default secret * altered using the @p seed value. * * While this operation is decently fast, note that it's not completely free. * * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed); /*! * The bare minimum size for a custom secret. * * @see * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). */ #define XXH3_SECRET_SIZE_MIN 136 /*! * @brief Calculates 64-bit variant of XXH3 with a custom "secret". * * @param data The block of data to be hashed, at least @p len bytes in size. * @param len The length of @p data, in bytes. * @param secret The secret data. * @param secretSize The length of @p secret, in bytes. * * @return The calculated 64-bit XXH3 hash value. * * @pre * The memory between @p data and @p data + @p len must be valid, * readable, contiguous memory. However, if @p length is `0`, @p data may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * It's possible to provide any blob of bytes as a "secret" to generate the hash. * This makes it more difficult for an external actor to prepare an intentional collision. * The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN). * However, the quality of the secret impacts the dispersion of the hash algorithm. * Therefore, the secret _must_ look like a bunch of random bytes. * Avoid "trivial" or structured data such as repeated sequences or a text document. * Whenever in doubt about the "randomness" of the blob of bytes, * consider employing @ref XXH3_generateSecret() instead (see below). * It will generate a proper high entropy secret derived from the blob of bytes. * Another advantage of using XXH3_generateSecret() is that * it guarantees that all bits within the initial blob of bytes * will impact every bit of the output. * This is not necessarily the case when using the blob of bytes directly * because, when hashing _small_ inputs, only a portion of the secret is employed. * * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize); /******* Streaming *******/ #ifndef XXH_NO_STREAM /* * Streaming requires state maintenance. * This operation costs memory and CPU. * As a consequence, streaming is slower than one-shot hashing. * For better performance, prefer one-shot functions whenever applicable. */ /*! * @brief The opaque state struct for the XXH3 streaming API. * * @see XXH3_state_s for details. * @see @ref streaming_example "Streaming Example" */ typedef struct XXH3_state_s XXH3_state_t; XXH_PUBLIC_API XXH_MALLOCF XXH3_state_t* XXH3_createState(void); XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); /*! * @brief Copies one @ref XXH3_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state); /*! * @brief Resets an @ref XXH3_state_t to begin a new hash. * * @param statePtr The state struct to reset. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note * - This function resets `statePtr` and generate a secret with default parameters. * - Call this function before @ref XXH3_64bits_update(). * - Digest will be equivalent to `XXH3_64bits()`. * * @see @ref streaming_example "Streaming Example" * */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr); /*! * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash. * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the hash result predictably. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note * - This function resets `statePtr` and generate a secret from `seed`. * - Call this function before @ref XXH3_64bits_update(). * - Digest will be equivalent to `XXH3_64bits_withSeed()`. * * @see @ref streaming_example "Streaming Example" * */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed); /*! * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash. * * @param statePtr The state struct to reset. * @param secret The secret data. * @param secretSize The length of @p secret, in bytes. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note * `secret` is referenced, it _must outlive_ the hash streaming session. * * Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN, * and the quality of produced hash values depends on secret's entropy * (secret's content should look like a bunch of random bytes). * When in doubt about the randomness of a candidate `secret`, * consider employing `XXH3_generateSecret()` instead (see below). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize); /*! * @brief Consumes a block of @p input to an @ref XXH3_state_t. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note Call this to incrementally consume blocks of data. * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated XXH3 64-bit hash value from an @ref XXH3_state_t. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated XXH3 64-bit hash value from that state. * * @note * Calling XXH3_64bits_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /* note : canonical representation of XXH3 is the same as XXH64 * since they both produce XXH64_hash_t values */ /*-********************************************************************** * XXH3 128-bit variant ************************************************************************/ /*! * @brief The return value from 128-bit hashes. * * Stored in little endian order, although the fields themselves are in native * endianness. */ typedef struct { XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ XXH64_hash_t high64; /*!< `value >> 64` */ } XXH128_hash_t; /*! * @brief Calculates 128-bit unseeded variant of XXH3 of @p data. * * @param data The block of data to be hashed, at least @p length bytes in size. * @param len The length of @p data, in bytes. * * @return The calculated 128-bit variant of XXH3 value. * * The 128-bit variant of XXH3 has more strength, but it has a bit of overhead * for shorter inputs. * * This is equivalent to @ref XXH3_128bits_withSeed() with a seed of `0`, however * it may have slightly better performance due to constant propagation of the * defaults. * * @see XXH3_128bits_withSeed(), XXH3_128bits_withSecret(): other seeding variants * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* data, size_t len); /*! @brief Calculates 128-bit seeded variant of XXH3 hash of @p data. * * @param data The block of data to be hashed, at least @p length bytes in size. * @param len The length of @p data, in bytes. * @param seed The 64-bit seed to alter the hash result predictably. * * @return The calculated 128-bit variant of XXH3 value. * * @note * seed == 0 produces the same results as @ref XXH3_64bits(). * * This variant generates a custom secret on the fly based on default secret * altered using the @p seed value. * * While this operation is decently fast, note that it's not completely free. * * @see XXH3_128bits(), XXH3_128bits_withSecret(): other seeding variants * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed); /*! * @brief Calculates 128-bit variant of XXH3 with a custom "secret". * * @param data The block of data to be hashed, at least @p len bytes in size. * @param len The length of @p data, in bytes. * @param secret The secret data. * @param secretSize The length of @p secret, in bytes. * * @return The calculated 128-bit variant of XXH3 value. * * It's possible to provide any blob of bytes as a "secret" to generate the hash. * This makes it more difficult for an external actor to prepare an intentional collision. * The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN). * However, the quality of the secret impacts the dispersion of the hash algorithm. * Therefore, the secret _must_ look like a bunch of random bytes. * Avoid "trivial" or structured data such as repeated sequences or a text document. * Whenever in doubt about the "randomness" of the blob of bytes, * consider employing @ref XXH3_generateSecret() instead (see below). * It will generate a proper high entropy secret derived from the blob of bytes. * Another advantage of using XXH3_generateSecret() is that * it guarantees that all bits within the initial blob of bytes * will impact every bit of the output. * This is not necessarily the case when using the blob of bytes directly * because, when hashing _small_ inputs, only a portion of the secret is employed. * * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize); /******* Streaming *******/ #ifndef XXH_NO_STREAM /* * Streaming requires state maintenance. * This operation costs memory and CPU. * As a consequence, streaming is slower than one-shot hashing. * For better performance, prefer one-shot functions whenever applicable. * * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). * Use already declared XXH3_createState() and XXH3_freeState(). * * All reset and streaming functions have same meaning as their 64-bit counterpart. */ /*! * @brief Resets an @ref XXH3_state_t to begin a new hash. * * @param statePtr The state struct to reset. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note * - This function resets `statePtr` and generate a secret with default parameters. * - Call it before @ref XXH3_128bits_update(). * - Digest will be equivalent to `XXH3_128bits()`. * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr); /*! * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash. * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the hash result predictably. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note * - This function resets `statePtr` and generate a secret from `seed`. * - Call it before @ref XXH3_128bits_update(). * - Digest will be equivalent to `XXH3_128bits_withSeed()`. * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed); /*! * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash. * * @param statePtr The state struct to reset. * @param secret The secret data. * @param secretSize The length of @p secret, in bytes. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * `secret` is referenced, it _must outlive_ the hash streaming session. * Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN, * and the quality of produced hash values depends on secret's entropy * (secret's content should look like a bunch of random bytes). * When in doubt about the randomness of a candidate `secret`, * consider employing `XXH3_generateSecret()` instead (see below). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize); /*! * @brief Consumes a block of @p input to an @ref XXH3_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @note * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated XXH3 128-bit hash value from an @ref XXH3_state_t. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated XXH3 128-bit hash value from that state. * * @note * Calling XXH3_128bits_digest() will not affect @p statePtr, so you can update, * digest, and update again. * */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /* Following helper functions make it possible to compare XXH128_hast_t values. * Since XXH128_hash_t is a structure, this capability is not offered by the language. * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ /*! * @brief Check equality of two XXH128_hash_t values * * @param h1 The 128-bit hash value. * @param h2 Another 128-bit hash value. * * @return `1` if `h1` and `h2` are equal. * @return `0` if they are not. */ XXH_PUBLIC_API XXH_PUREF int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); /*! * @brief Compares two @ref XXH128_hash_t * * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. * * @param h128_1 Left-hand side value * @param h128_2 Right-hand side value * * @return >0 if @p h128_1 > @p h128_2 * @return =0 if @p h128_1 == @p h128_2 * @return <0 if @p h128_1 < @p h128_2 */ XXH_PUBLIC_API XXH_PUREF int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2); /******* Canonical representation *******/ typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; /*! * @brief Converts an @ref XXH128_hash_t to a big endian @ref XXH128_canonical_t. * * @param dst The @ref XXH128_canonical_t pointer to be stored to. * @param hash The @ref XXH128_hash_t to be converted. * * @pre * @p dst must not be `NULL`. * @see @ref canonical_representation_example "Canonical Representation Example" */ XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash); /*! * @brief Converts an @ref XXH128_canonical_t to a native @ref XXH128_hash_t. * * @param src The @ref XXH128_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. * @see @ref canonical_representation_example "Canonical Representation Example" */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src); #endif /* !XXH_NO_XXH3 */ #endif /* XXH_NO_LONG_LONG */ /*! * @} */ #endif /* XXHASH_H_5627135585666179 */ #if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) #define XXHASH_H_STATIC_13879238742 /* **************************************************************************** * This section contains declarations which are not guaranteed to remain stable. * They may change in future versions, becoming incompatible with a different * version of the library. * These declarations should only be used with static linking. * Never use them in association with dynamic linking! ***************************************************************************** */ /* * These definitions are only present to allow static allocation * of XXH states, on stack or in a struct, for example. * Never **ever** access their members directly. */ /*! * @internal * @brief Structure for XXH32 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is * an opaque type. This allows fields to safely be changed. * * Typedef'd to @ref XXH32_state_t. * Do not access the members of this struct directly. * @see XXH64_state_s, XXH3_state_s */ struct XXH32_state_s { XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ XXH32_hash_t acc[4]; /*!< Accumulator lanes */ unsigned char buffer[16]; /*!< Internal buffer for partial reads. */ XXH32_hash_t bufferedSize; /*!< Amount of data in @ref buffer */ XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ }; /* typedef'd to XXH32_state_t */ #ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ /*! * @internal * @brief Structure for XXH64 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is * an opaque type. This allows fields to safely be changed. * * Typedef'd to @ref XXH64_state_t. * Do not access the members of this struct directly. * @see XXH32_state_s, XXH3_state_s */ struct XXH64_state_s { XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ XXH64_hash_t acc[4]; /*!< Accumulator lanes */ unsigned char buffer[32]; /*!< Internal buffer for partial reads.. */ XXH32_hash_t bufferedSize; /*!< Amount of data in @ref buffer */ XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ }; /* typedef'd to XXH64_state_t */ #ifndef XXH_NO_XXH3 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ # define XXH_ALIGN(n) _Alignas(n) #elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ /* In C++ alignas() is a keyword */ # define XXH_ALIGN(n) alignas(n) #elif defined(__GNUC__) # define XXH_ALIGN(n) __attribute__ ((aligned(n))) #elif defined(_MSC_VER) # define XXH_ALIGN(n) __declspec(align(n)) #else # define XXH_ALIGN(n) /* disabled */ #endif /* Old GCC versions only accept the attribute after the type in structures. */ #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ && defined(__GNUC__) # define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) #else # define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type #endif /*! * @internal * @brief The size of the internal XXH3 buffer. * * This is the optimal update size for incremental hashing. * * @see XXH3_64b_update(), XXH3_128b_update(). */ #define XXH3_INTERNALBUFFER_SIZE 256 /*! * @def XXH3_SECRET_DEFAULT_SIZE * @brief Default Secret's size * * This is the size of internal XXH3_kSecret * and is needed by XXH3_generateSecret_fromSeed(). * * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. */ #define XXH3_SECRET_DEFAULT_SIZE 192 /*! * @internal * @brief Structure for XXH3 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. * Otherwise it is an opaque type. * Never use this definition in combination with dynamic library. * This allows fields to safely be changed in the future. * * @note ** This structure has a strict alignment requirement of 64 bytes!! ** * Do not allocate this with `malloc()` or `new`, * it will not be sufficiently aligned. * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. * * Typedef'd to @ref XXH3_state_t. * Do never access the members of this struct directly. * * @see XXH3_INITSTATE() for stack initialization. * @see XXH3_createState(), XXH3_freeState(). * @see XXH32_state_s, XXH64_state_s */ struct XXH3_state_s { XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); /*!< The 8 accumulators. See @ref XXH32_state_s::acc and @ref XXH64_state_s::acc */ XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); /*!< Used to store a custom secret generated from a seed. */ XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); /*!< The internal buffer. @see XXH32_state_s::mem32 */ XXH32_hash_t bufferedSize; /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ XXH32_hash_t useSeed; /*!< Reserved field. Needed for padding on 64-bit. */ size_t nbStripesSoFar; /*!< Number or stripes processed. */ XXH64_hash_t totalLen; /*!< Total length hashed. 64-bit even on 32-bit targets. */ size_t nbStripesPerBlock; /*!< Number of stripes per block. */ size_t secretLimit; /*!< Size of @ref customSecret or @ref extSecret */ XXH64_hash_t seed; /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ XXH64_hash_t reserved64; /*!< Reserved field. */ const unsigned char* extSecret; /*!< Reference to an external secret for the _withSecret variants, NULL * for other variants. */ /* note: there may be some padding at the end due to alignment on 64 bytes */ }; /* typedef'd to XXH3_state_t */ #undef XXH_ALIGN_MEMBER /*! * @brief Initializes a stack-allocated `XXH3_state_s`. * * When the @ref XXH3_state_t structure is merely emplaced on stack, * it should be initialized with XXH3_INITSTATE() or a memset() * in case its first reset uses XXH3_NNbits_reset_withSeed(). * This init can be omitted if the first reset uses default or _withSecret mode. * This operation isn't necessary when the state is created with XXH3_createState(). * Note that this doesn't prepare the state for a streaming operation, * it's still necessary to use XXH3_NNbits_reset*() afterwards. */ #define XXH3_INITSTATE(XXH3_state_ptr) \ do { \ XXH3_state_t* tmp_xxh3_state_ptr = (XXH3_state_ptr); \ tmp_xxh3_state_ptr->seed = 0; \ tmp_xxh3_state_ptr->extSecret = NULL; \ } while(0) /*! * @brief Calculates the 128-bit hash of @p data using XXH3. * * @param data The block of data to be hashed, at least @p len bytes in size. * @param len The length of @p data, in bytes. * @param seed The 64-bit seed to alter the hash's output predictably. * * @pre * The memory between @p data and @p data + @p len must be valid, * readable, contiguous memory. However, if @p len is `0`, @p data may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 128-bit XXH3 value. * * @see @ref single_shot_example "Single Shot Example" for an example. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed); /* === Experimental API === */ /* Symbols defined below must be considered tied to a specific library version. */ /*! * @brief Derive a high-entropy secret from any user-defined content, named customSeed. * * @param secretBuffer A writable buffer for derived high-entropy secret data. * @param secretSize Size of secretBuffer, in bytes. Must be >= XXH3_SECRET_SIZE_MIN. * @param customSeed A user-defined content. * @param customSeedSize Size of customSeed, in bytes. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * The generated secret can be used in combination with `*_withSecret()` functions. * The `_withSecret()` variants are useful to provide a higher level of protection * than 64-bit seed, as it becomes much more difficult for an external actor to * guess how to impact the calculation logic. * * The function accepts as input a custom seed of any length and any content, * and derives from it a high-entropy secret of length @p secretSize into an * already allocated buffer @p secretBuffer. * * The generated secret can then be used with any `*_withSecret()` variant. * The functions @ref XXH3_128bits_withSecret(), @ref XXH3_64bits_withSecret(), * @ref XXH3_128bits_reset_withSecret() and @ref XXH3_64bits_reset_withSecret() * are part of this list. They all accept a `secret` parameter * which must be large enough for implementation reasons (>= @ref XXH3_SECRET_SIZE_MIN) * _and_ feature very high entropy (consist of random-looking bytes). * These conditions can be a high bar to meet, so @ref XXH3_generateSecret() can * be employed to ensure proper quality. * * @p customSeed can be anything. It can have any size, even small ones, * and its content can be anything, even "poor entropy" sources such as a bunch * of zeroes. The resulting `secret` will nonetheless provide all required qualities. * * @pre * - @p secretSize must be >= @ref XXH3_SECRET_SIZE_MIN * - When @p customSeedSize > 0, supplying NULL as customSeed is undefined behavior. * * Example code: * @code{.c} * #include * #include * #include * #define XXH_STATIC_LINKING_ONLY // expose unstable API * #include "xxhash.h" * // Hashes argv[2] using the entropy from argv[1]. * int main(int argc, char* argv[]) * { * char secret[XXH3_SECRET_SIZE_MIN]; * if (argv != 3) { return 1; } * XXH3_generateSecret(secret, sizeof(secret), argv[1], strlen(argv[1])); * XXH64_hash_t h = XXH3_64bits_withSecret( * argv[2], strlen(argv[2]), * secret, sizeof(secret) * ); * printf("%016llx\n", (unsigned long long) h); * } * @endcode */ XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize); /*! * @brief Generate the same secret as the _withSeed() variants. * * @param secretBuffer A writable buffer of @ref XXH3_SECRET_DEFAULT_SIZE bytes * @param seed The 64-bit seed to alter the hash result predictably. * * The generated secret can be used in combination with *`*_withSecret()` and `_withSecretandSeed()` variants. * * Example C++ `std::string` hash class: * @code{.cpp} * #include * #define XXH_STATIC_LINKING_ONLY // expose unstable API * #include "xxhash.h" * // Slow, seeds each time * class HashSlow { * XXH64_hash_t seed; * public: * HashSlow(XXH64_hash_t s) : seed{s} {} * size_t operator()(const std::string& x) const { * return size_t{XXH3_64bits_withSeed(x.c_str(), x.length(), seed)}; * } * }; * // Fast, caches the seeded secret for future uses. * class HashFast { * unsigned char secret[XXH3_SECRET_DEFAULT_SIZE]; * public: * HashFast(XXH64_hash_t s) { * XXH3_generateSecret_fromSeed(secret, seed); * } * size_t operator()(const std::string& x) const { * return size_t{ * XXH3_64bits_withSecret(x.c_str(), x.length(), secret, sizeof(secret)) * }; * } * }; * @endcode */ XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed); /*! * @brief Maximum size of "short" key in bytes. */ #define XXH3_MIDSIZE_MAX 240 /*! * @brief Calculates 64/128-bit seeded variant of XXH3 hash of @p data. * * @param data The block of data to be hashed, at least @p len bytes in size. * @param len The length of @p data, in bytes. * @param secret The secret data. * @param secretSize The length of @p secret, in bytes. * @param seed The 64-bit seed to alter the hash result predictably. * * These variants generate hash values using either: * - @p seed for "short" keys (< @ref XXH3_MIDSIZE_MAX = 240 bytes) * - @p secret for "large" keys (>= @ref XXH3_MIDSIZE_MAX). * * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. * `_withSeed()` has to generate the secret on the fly for "large" keys. * It's fast, but can be perceptible for "not so large" keys (< 1 KB). * `_withSecret()` has to generate the masks on the fly for "small" keys, * which requires more instructions than _withSeed() variants. * Therefore, _withSecretandSeed variant combines the best of both worlds. * * When @p secret has been generated by XXH3_generateSecret_fromSeed(), * this variant produces *exactly* the same results as `_withSeed()` variant, * hence offering only a pure speed benefit on "large" input, * by skipping the need to regenerate the secret for every large input. * * Another usage scenario is to hash the secret to a 64-bit hash value, * for example with XXH3_64bits(), which then becomes the seed, * and then employ both the seed and the secret in _withSecretandSeed(). * On top of speed, an added benefit is that each bit in the secret * has a 50% chance to swap each bit in the output, via its impact to the seed. * * This is not guaranteed when using the secret directly in "small data" scenarios, * because only portions of the secret are employed for small data. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed); /*! * @brief Calculates 128-bit seeded variant of XXH3 hash of @p data. * * @param input The memory segment to be hashed, at least @p len bytes in size. * @param length The length of @p data, in bytes. * @param secret The secret used to alter hash result predictably. * @param secretSize The length of @p secret, in bytes (must be >= XXH3_SECRET_SIZE_MIN) * @param seed64 The 64-bit seed to alter the hash result predictably. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @see XXH3_64bits_withSecretandSeed(): contract is the same. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); #ifndef XXH_NO_STREAM /*! * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash. * * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState(). * @param secret The secret data. * @param secretSize The length of @p secret, in bytes. * @param seed64 The 64-bit seed to alter the hash result predictably. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @see XXH3_64bits_withSecretandSeed(). Contract is identical. */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); /*! * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash. * * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState(). * @param secret The secret data. * @param secretSize The length of @p secret, in bytes. * @param seed64 The 64-bit seed to alter the hash result predictably. * * @return @ref XXH_OK on success. * @return @ref XXH_ERROR on failure. * * @see XXH3_64bits_withSecretandSeed(). Contract is identical. * * Note: there was a bug in an earlier version of this function (<= v0.8.2) * that would make it generate an incorrect hash value * when @p seed == 0 and @p length < XXH3_MIDSIZE_MAX * and @p secret is different from XXH3_generateSecret_fromSeed(). * As stated in the contract, the correct hash result must be * the same as XXH3_128bits_withSeed() when @p length <= XXH3_MIDSIZE_MAX. * Results generated by this older version are wrong, hence not comparable. */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); #endif /* !XXH_NO_STREAM */ #endif /* !XXH_NO_XXH3 */ #endif /* XXH_NO_LONG_LONG */ #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) # define XXH_IMPLEMENTATION #endif #endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ /* ======================================================================== */ /* ======================================================================== */ /* ======================================================================== */ /*-********************************************************************** * xxHash implementation *-********************************************************************** * xxHash's implementation used to be hosted inside xxhash.c. * * However, inlining requires implementation to be visible to the compiler, * hence be included alongside the header. * Previously, implementation was hosted inside xxhash.c, * which was then #included when inlining was activated. * This construction created issues with a few build and install systems, * as it required xxhash.c to be stored in /include directory. * * xxHash implementation is now directly integrated within xxhash.h. * As a consequence, xxhash.c is no longer needed in /include. * * xxhash.c is still available and is still useful. * In a "normal" setup, when xxhash is not inlined, * xxhash.h only exposes the prototypes and public symbols, * while xxhash.c can be built into an object file xxhash.o * which can then be linked into the final binary. ************************************************************************/ #if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) # define XXH_IMPLEM_13a8737387 /* ************************************* * Tuning parameters ***************************************/ /*! * @defgroup tuning Tuning parameters * @{ * * Various macros to control xxHash's behavior. */ #ifdef XXH_DOXYGEN /*! * @brief Define this to disable 64-bit code. * * Useful if only using the @ref XXH32_family and you have a strict C90 compiler. */ # define XXH_NO_LONG_LONG # undef XXH_NO_LONG_LONG /* don't actually */ /*! * @brief Controls how unaligned memory is accessed. * * By default, access to unaligned memory is controlled by `memcpy()`, which is * safe and portable. * * Unfortunately, on some target/compiler combinations, the generated assembly * is sub-optimal. * * The below switch allow selection of a different access method * in the search for improved performance. * * @par Possible options: * * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` * @par * Use `memcpy()`. Safe and portable. Note that most modern compilers will * eliminate the function call and treat it as an unaligned access. * * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((aligned(1)))` * @par * Depends on compiler extensions and is therefore not portable. * This method is safe _if_ your compiler supports it, * and *generally* as fast or faster than `memcpy`. * * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast * @par * Casts directly and dereferences. This method doesn't depend on the * compiler, but it violates the C standard as it directly dereferences an * unaligned pointer. It can generate buggy code on targets which do not * support unaligned memory accesses, but in some circumstances, it's the * only known way to get the most performance. * * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift * @par * Also portable. This can generate the best code on old compilers which don't * inline small `memcpy()` calls, and it might also be faster on big-endian * systems which lack a native byteswap instruction. However, some compilers * will emit literal byteshifts even if the target supports unaligned access. * * * @warning * Methods 1 and 2 rely on implementation-defined behavior. Use these with * care, as what works on one compiler/platform/optimization level may cause * another to read garbage data or even crash. * * See https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. * * Prefer these methods in priority order (0 > 3 > 1 > 2) */ # define XXH_FORCE_MEMORY_ACCESS 0 /*! * @def XXH_SIZE_OPT * @brief Controls how much xxHash optimizes for size. * * xxHash, when compiled, tends to result in a rather large binary size. This * is mostly due to heavy usage to forced inlining and constant folding of the * @ref XXH3_family to increase performance. * * However, some developers prefer size over speed. This option can * significantly reduce the size of the generated code. When using the `-Os` * or `-Oz` options on GCC or Clang, this is defined to 1 by default, * otherwise it is defined to 0. * * Most of these size optimizations can be controlled manually. * * This is a number from 0-2. * - `XXH_SIZE_OPT` == 0: Default. xxHash makes no size optimizations. Speed * comes first. * - `XXH_SIZE_OPT` == 1: Default for `-Os` and `-Oz`. xxHash is more * conservative and disables hacks that increase code size. It implies the * options @ref XXH_NO_INLINE_HINTS == 1, @ref XXH_FORCE_ALIGN_CHECK == 0, * and @ref XXH3_NEON_LANES == 8 if they are not already defined. * - `XXH_SIZE_OPT` == 2: xxHash tries to make itself as small as possible. * Performance may cry. For example, the single shot functions just use the * streaming API. */ # define XXH_SIZE_OPT 0 /*! * @def XXH_FORCE_ALIGN_CHECK * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() * and XXH64() only). * * This is an important performance trick for architectures without decent * unaligned memory access performance. * * It checks for input alignment, and when conditions are met, uses a "fast * path" employing direct 32-bit/64-bit reads, resulting in _dramatically * faster_ read speed. * * The check costs one initial branch per hash, which is generally negligible, * but not zero. * * Moreover, it's not useful to generate an additional code path if memory * access uses the same instruction for both aligned and unaligned * addresses (e.g. x86 and aarch64). * * In these cases, the alignment check can be removed by setting this macro to 0. * Then the code will always use unaligned memory access. * Align check is automatically disabled on x86, x64, ARM64, and some ARM chips * which are platforms known to offer good unaligned memory accesses performance. * * It is also disabled by default when @ref XXH_SIZE_OPT >= 1. * * This option does not affect XXH3 (only XXH32 and XXH64). */ # define XXH_FORCE_ALIGN_CHECK 0 /*! * @def XXH_NO_INLINE_HINTS * @brief When non-zero, sets all functions to `static`. * * By default, xxHash tries to force the compiler to inline almost all internal * functions. * * This can usually improve performance due to reduced jumping and improved * constant folding, but significantly increases the size of the binary which * might not be favorable. * * Additionally, sometimes the forced inlining can be detrimental to performance, * depending on the architecture. * * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the * compiler full control on whether to inline or not. * * When not optimizing (-O0), using `-fno-inline` with GCC or Clang, or if * @ref XXH_SIZE_OPT >= 1, this will automatically be defined. */ # define XXH_NO_INLINE_HINTS 0 /*! * @def XXH3_INLINE_SECRET * @brief Determines whether to inline the XXH3 withSecret code. * * When the secret size is known, the compiler can improve the performance * of XXH3_64bits_withSecret() and XXH3_128bits_withSecret(). * * However, if the secret size is not known, it doesn't have any benefit. This * happens when xxHash is compiled into a global symbol. Therefore, if * @ref XXH_INLINE_ALL is *not* defined, this will be defined to 0. * * Additionally, this defaults to 0 on GCC 12+, which has an issue with function pointers * that are *sometimes* force inline on -Og, and it is impossible to automatically * detect this optimization level. */ # define XXH3_INLINE_SECRET 0 /*! * @def XXH32_ENDJMP * @brief Whether to use a jump for `XXH32_finalize`. * * For performance, `XXH32_finalize` uses multiple branches in the finalizer. * This is generally preferable for performance, * but depending on exact architecture, a jmp may be preferable. * * This setting is only possibly making a difference for very small inputs. */ # define XXH32_ENDJMP 0 /*! * @internal * @brief Redefines old internal names. * * For compatibility with code that uses xxHash's internals before the names * were changed to improve namespacing. There is no other reason to use this. */ # define XXH_OLD_NAMES # undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ /*! * @def XXH_NO_STREAM * @brief Disables the streaming API. * * When xxHash is not inlined and the streaming functions are not used, disabling * the streaming functions can improve code size significantly, especially with * the @ref XXH3_family which tends to make constant folded copies of itself. */ # define XXH_NO_STREAM # undef XXH_NO_STREAM /* don't actually */ #endif /* XXH_DOXYGEN */ /*! * @} */ #ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ /* prefer __packed__ structures (method 1) for GCC * < ARMv7 with unaligned access (e.g. Raspbian armhf) still uses byte shifting, so we use memcpy * which for some reason does unaligned loads. */ # if defined(__GNUC__) && !(defined(__ARM_ARCH) && __ARM_ARCH < 7 && defined(__ARM_FEATURE_UNALIGNED)) # define XXH_FORCE_MEMORY_ACCESS 1 # endif #endif #ifndef XXH_SIZE_OPT /* default to 1 for -Os or -Oz */ # if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE_SIZE__) # define XXH_SIZE_OPT 1 # else # define XXH_SIZE_OPT 0 # endif #endif #ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ /* don't check on sizeopt, x86, aarch64, or arm when unaligned access is available */ # if XXH_SIZE_OPT >= 1 || \ defined(__i386) || defined(__x86_64__) || defined(__aarch64__) || defined(__ARM_FEATURE_UNALIGNED) \ || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) || defined(_M_ARM) /* visual */ # define XXH_FORCE_ALIGN_CHECK 0 # else # define XXH_FORCE_ALIGN_CHECK 1 # endif #endif #ifndef XXH_NO_INLINE_HINTS # if XXH_SIZE_OPT >= 1 || defined(__NO_INLINE__) /* -O0, -fno-inline */ # define XXH_NO_INLINE_HINTS 1 # else # define XXH_NO_INLINE_HINTS 0 # endif #endif #ifndef XXH3_INLINE_SECRET # if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12) \ || !defined(XXH_INLINE_ALL) # define XXH3_INLINE_SECRET 0 # else # define XXH3_INLINE_SECRET 1 # endif #endif #ifndef XXH32_ENDJMP /* generally preferable for performance */ # define XXH32_ENDJMP 0 #endif /*! * @defgroup impl Implementation * @{ */ /* ************************************* * Includes & Memory related functions ***************************************/ #if defined(XXH_NO_STREAM) /* nothing */ #elif defined(XXH_NO_STDLIB) /* When requesting to disable any mention of stdlib, * the library loses the ability to invoked malloc / free. * In practice, it means that functions like `XXH*_createState()` * will always fail, and return NULL. * This flag is useful in situations where * xxhash.h is integrated into some kernel, embedded or limited environment * without access to dynamic allocation. */ static XXH_CONSTF void* XXH_malloc(size_t s) { (void)s; return NULL; } static void XXH_free(void* p) { (void)p; } #else /* * Modify the local functions below should you wish to use * different memory routines for malloc() and free() */ #include /*! * @internal * @brief Modify this function to use a different routine than malloc(). */ static XXH_MALLOCF void* XXH_malloc(size_t s) { return malloc(s); } /*! * @internal * @brief Modify this function to use a different routine than free(). */ static void XXH_free(void* p) { free(p); } #endif /* XXH_NO_STDLIB */ #ifndef XXH_memcpy /*! * @internal * @brief XXH_memcpy() macro can be redirected at compile time */ # include # define XXH_memcpy memcpy #endif #ifndef XXH_memset /*! * @internal * @brief XXH_memset() macro can be redirected at compile time */ # include # define XXH_memset memset #endif #ifndef XXH_memcmp /*! * @internal * @brief XXH_memcmp() macro can be redirected at compile time * Note: only needed by XXH128. */ # include # define XXH_memcmp memcmp #endif #include /* ULLONG_MAX */ /* ************************************* * Compiler Specific Options ***************************************/ #ifdef _MSC_VER /* Visual Studio warning fix */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #endif #if XXH_NO_INLINE_HINTS /* disable inlining hints */ # if defined(__GNUC__) || defined(__clang__) # define XXH_FORCE_INLINE static __attribute__((__unused__)) # else # define XXH_FORCE_INLINE static # endif # define XXH_NO_INLINE static /* enable inlining hints */ #elif defined(__GNUC__) || defined(__clang__) # define XXH_FORCE_INLINE static __inline__ __attribute__((__always_inline__, __unused__)) # define XXH_NO_INLINE static __attribute__((__noinline__)) #elif defined(_MSC_VER) /* Visual Studio */ # define XXH_FORCE_INLINE static __forceinline # define XXH_NO_INLINE static __declspec(noinline) #elif defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ # define XXH_FORCE_INLINE static inline # define XXH_NO_INLINE static #else # define XXH_FORCE_INLINE static # define XXH_NO_INLINE static #endif #if defined(XXH_INLINE_ALL) # define XXH_STATIC XXH_FORCE_INLINE #else # define XXH_STATIC static #endif #if XXH3_INLINE_SECRET # define XXH3_WITH_SECRET_INLINE XXH_FORCE_INLINE #else # define XXH3_WITH_SECRET_INLINE XXH_NO_INLINE #endif #if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ # define XXH_RESTRICT /* disable */ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ # define XXH_RESTRICT restrict #elif (defined (__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \ || (defined (__clang__)) \ || (defined (_MSC_VER) && (_MSC_VER >= 1400)) \ || (defined (__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300)) /* * There are a LOT more compilers that recognize __restrict but this * covers the major ones. */ # define XXH_RESTRICT __restrict #else # define XXH_RESTRICT /* disable */ #endif /* ************************************* * Debug ***************************************/ /*! * @ingroup tuning * @def XXH_DEBUGLEVEL * @brief Sets the debugging level. * * XXH_DEBUGLEVEL is expected to be defined externally, typically via the * compiler's command line options. The value must be a number. */ #ifndef XXH_DEBUGLEVEL # ifdef DEBUGLEVEL /* backwards compat */ # define XXH_DEBUGLEVEL DEBUGLEVEL # else # define XXH_DEBUGLEVEL 0 # endif #endif #if (XXH_DEBUGLEVEL>=1) # include /* note: can still be disabled with NDEBUG */ # define XXH_ASSERT(c) assert(c) #else # if defined(__INTEL_COMPILER) # define XXH_ASSERT(c) XXH_ASSUME((unsigned char) (c)) # else # define XXH_ASSERT(c) XXH_ASSUME(c) # endif #endif /* note: use after variable declarations */ #ifndef XXH_STATIC_ASSERT # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { _Static_assert((c),m); } while(0) # elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) # else # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) # endif # define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) #endif /*! * @internal * @def XXH_COMPILER_GUARD(var) * @brief Used to prevent unwanted optimizations for @p var. * * It uses an empty GCC inline assembly statement with a register constraint * which forces @p var into a general purpose register (eg eax, ebx, ecx * on x86) and marks it as modified. * * This is used in a few places to avoid unwanted autovectorization (e.g. * XXH32_round()). All vectorization we want is explicit via intrinsics, * and _usually_ isn't wanted elsewhere. * * We also use it to prevent unwanted constant folding for AArch64 in * XXH3_initCustomSecret_scalar(). */ #if defined(__GNUC__) || defined(__clang__) # define XXH_COMPILER_GUARD(var) __asm__("" : "+r" (var)) #else # define XXH_COMPILER_GUARD(var) ((void)0) #endif /* Specifically for NEON vectors which use the "w" constraint, on * Clang. */ #if defined(__clang__) && defined(__ARM_ARCH) && !defined(__wasm__) # define XXH_COMPILER_GUARD_CLANG_NEON(var) __asm__("" : "+w" (var)) #else # define XXH_COMPILER_GUARD_CLANG_NEON(var) ((void)0) #endif /* ************************************* * Basic Types ***************************************/ #if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # ifdef _AIX # include # else # include # endif typedef uint8_t xxh_u8; #else typedef unsigned char xxh_u8; #endif typedef XXH32_hash_t xxh_u32; #ifdef XXH_OLD_NAMES # warning "XXH_OLD_NAMES is planned to be removed starting v0.9. If the program depends on it, consider moving away from it by employing newer type names directly" # define BYTE xxh_u8 # define U8 xxh_u8 # define U32 xxh_u32 #endif /* *** Memory access *** */ /*! * @internal * @fn xxh_u32 XXH_read32(const void* ptr) * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit native endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readLE32(const void* ptr) * @brief Reads an unaligned 32-bit little endian integer from @p ptr. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit little endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readBE32(const void* ptr) * @brief Reads an unaligned 32-bit big endian integer from @p ptr. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit big endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is * always @ref XXH_alignment::XXH_unaligned. * * @param ptr The pointer to read from. * @param align Whether @p ptr is aligned. * @pre * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte * aligned. * @return The 32-bit little endian integer from the bytes at @p ptr. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) /* * Manual byteshift. Best for old compilers which don't inline memcpy. * We actually directly use XXH_readLE32 and XXH_readBE32. */ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* * Force direct memory access. Only works on CPU which support unaligned memory * access in hardware. */ static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* * __attribute__((aligned(1))) is supported by gcc and clang. Originally the * documentation claimed that it only increased the alignment, but actually it * can decrease it on gcc, clang, and icc: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502, * https://gcc.godbolt.org/z/xYez1j67Y. */ #ifdef XXH_OLD_NAMES typedef union { xxh_u32 u32; } __attribute__((__packed__)) unalign; #endif static xxh_u32 XXH_read32(const void* ptr) { typedef __attribute__((__aligned__(1))) xxh_u32 xxh_unalign32; return *((const xxh_unalign32*)ptr); } #else /* * Portable and safe solution. Generally efficient. * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html */ static xxh_u32 XXH_read32(const void* memPtr) { xxh_u32 val; XXH_memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ /* *** Endianness *** */ /*! * @ingroup tuning * @def XXH_CPU_LITTLE_ENDIAN * @brief Whether the target is little endian. * * Defined to 1 if the target is little endian, or 0 if it is big endian. * It can be defined externally, for example on the compiler command line. * * If it is not defined, * a runtime check (which is usually constant folded) is used instead. * * @note * This is not necessarily defined to an integer constant. * * @see XXH_isLittleEndian() for the runtime check. */ #ifndef XXH_CPU_LITTLE_ENDIAN /* * Try to detect endianness automatically, to avoid the nonstandard behavior * in `XXH_isLittleEndian()` */ # if defined(_WIN32) /* Windows is always little endian */ \ || defined(__LITTLE_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) # define XXH_CPU_LITTLE_ENDIAN 1 # elif defined(__BIG_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) # define XXH_CPU_LITTLE_ENDIAN 0 # else /*! * @internal * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. * * Most compilers will constant fold this. */ static int XXH_isLittleEndian(void) { /* * Portable and well-defined behavior. * Don't use static: it is detrimental to performance. */ const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; return one.c[0]; } # define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() # endif #endif /* **************************************** * Compiler-specific Functions and Macros ******************************************/ #define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #ifdef __has_builtin # define XXH_HAS_BUILTIN(x) __has_builtin(x) #else # define XXH_HAS_BUILTIN(x) 0 #endif /* * C23 and future versions have standard "unreachable()". * Once it has been implemented reliably we can add it as an * additional case: * * ``` * #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) * # include * # ifdef unreachable * # define XXH_UNREACHABLE() unreachable() * # endif * #endif * ``` * * Note C++23 also has std::unreachable() which can be detected * as follows: * ``` * #if defined(__cpp_lib_unreachable) && (__cpp_lib_unreachable >= 202202L) * # include * # define XXH_UNREACHABLE() std::unreachable() * #endif * ``` * NB: `__cpp_lib_unreachable` is defined in the `` header. * We don't use that as including `` in `extern "C"` blocks * doesn't work on GCC12 */ #if XXH_HAS_BUILTIN(__builtin_unreachable) # define XXH_UNREACHABLE() __builtin_unreachable() #elif defined(_MSC_VER) # define XXH_UNREACHABLE() __assume(0) #else # define XXH_UNREACHABLE() #endif #if XXH_HAS_BUILTIN(__builtin_assume) # define XXH_ASSUME(c) __builtin_assume(c) #else # define XXH_ASSUME(c) if (!(c)) { XXH_UNREACHABLE(); } #endif /*! * @internal * @def XXH_rotl32(x,r) * @brief 32-bit rotate left. * * @param x The 32-bit integer to be rotated. * @param r The number of bits to rotate. * @pre * @p r > 0 && @p r < 32 * @note * @p x and @p r may be evaluated multiple times. * @return The rotated result. */ #if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ && XXH_HAS_BUILTIN(__builtin_rotateleft64) # define XXH_rotl32 __builtin_rotateleft32 # define XXH_rotl64 __builtin_rotateleft64 #elif XXH_HAS_BUILTIN(__builtin_stdc_rotate_left) # define XXH_rotl32 __builtin_stdc_rotate_left # define XXH_rotl64 __builtin_stdc_rotate_left /* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ #elif defined(_MSC_VER) # define XXH_rotl32(x,r) _rotl(x,r) # define XXH_rotl64(x,r) _rotl64(x,r) #else # define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) # define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) #endif /*! * @internal * @fn xxh_u32 XXH_swap32(xxh_u32 x) * @brief A 32-bit byteswap. * * @param x The 32-bit integer to byteswap. * @return @p x, byteswapped. */ #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap32 _byteswap_ulong #elif XXH_GCC_VERSION >= 403 # define XXH_swap32 __builtin_bswap32 #else static xxh_u32 XXH_swap32 (xxh_u32 x) { return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00 ) | ((x >> 24) & 0x000000ff ); } #endif /* *************************** * Memory reads *****************************/ /*! * @internal * @brief Enum to indicate whether a pointer is aligned. */ typedef enum { XXH_aligned, /*!< Aligned */ XXH_unaligned /*!< Possibly unaligned */ } XXH_alignment; /* * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. * * This is ideal for older compilers which don't inline memcpy. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[0] | ((xxh_u32)bytePtr[1] << 8) | ((xxh_u32)bytePtr[2] << 16) | ((xxh_u32)bytePtr[3] << 24); } XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[3] | ((xxh_u32)bytePtr[2] << 8) | ((xxh_u32)bytePtr[1] << 16) | ((xxh_u32)bytePtr[0] << 24); } #else XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); } static xxh_u32 XXH_readBE32(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); } #endif XXH_FORCE_INLINE xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) { if (align==XXH_unaligned) { return XXH_readLE32(ptr); } else { return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); } } /* ************************************* * Misc ***************************************/ /*! @ingroup public */ XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } /* ******************************************************************* * 32-bit hash functions *********************************************************************/ /*! * @} * @defgroup XXH32_impl XXH32 implementation * @ingroup impl * * Details on the XXH32 implementation. * @{ */ /* #define instead of static const, to be used as initializers */ #define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ #define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ #define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ #define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ #define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */ #ifdef XXH_OLD_NAMES # define PRIME32_1 XXH_PRIME32_1 # define PRIME32_2 XXH_PRIME32_2 # define PRIME32_3 XXH_PRIME32_3 # define PRIME32_4 XXH_PRIME32_4 # define PRIME32_5 XXH_PRIME32_5 #endif /*! * @internal * @brief Normal stripe processing routine. * * This shuffles the bits so that any bit from @p input impacts several bits in * @p acc. * * @param acc The accumulator lane. * @param input The stripe of input to mix. * @return The mixed accumulator lane. */ static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) { acc += input * XXH_PRIME32_2; acc = XXH_rotl32(acc, 13); acc *= XXH_PRIME32_1; #if (defined(__SSE4_1__) || defined(__aarch64__) || defined(__wasm_simd128__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) /* * UGLY HACK: * A compiler fence is used to prevent GCC and Clang from * autovectorizing the XXH32 loop (pragmas and attributes don't work for some * reason) without globally disabling SSE4.1. * * The reason we want to avoid vectorization is because despite working on * 4 integers at a time, there are multiple factors slowing XXH32 down on * SSE4: * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on * newer chips!) making it slightly slower to multiply four integers at * once compared to four integers independently. Even when pmulld was * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE * just to multiply unless doing a long operation. * * - Four instructions are required to rotate, * movqda tmp, v // not required with VEX encoding * pslld tmp, 13 // tmp <<= 13 * psrld v, 19 // x >>= 19 * por v, tmp // x |= tmp * compared to one for scalar: * roll v, 13 // reliably fast across the board * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason * * - Instruction level parallelism is actually more beneficial here because * the SIMD actually serializes this operation: While v1 is rotating, v2 * can load data, while v3 can multiply. SSE forces them to operate * together. * * This is also enabled on AArch64, as Clang is *very aggressive* in vectorizing * the loop. NEON is only faster on the A53, and with the newer cores, it is less * than half the speed. * * Additionally, this is used on WASM SIMD128 because it JITs to the same * SIMD instructions and has the same issue. */ XXH_COMPILER_GUARD(acc); #endif return acc; } /*! * @internal * @brief Mixes all bits to finalize the hash. * * The final mix ensures that all input bits have a chance to impact any bit in * the output digest, resulting in an unbiased distribution. * * @param hash The hash to avalanche. * @return The avalanched hash. */ static xxh_u32 XXH32_avalanche(xxh_u32 hash) { hash ^= hash >> 15; hash *= XXH_PRIME32_2; hash ^= hash >> 13; hash *= XXH_PRIME32_3; hash ^= hash >> 16; return hash; } #define XXH_get32bits(p) XXH_readLE32_align(p, align) /*! * @internal * @brief Sets up the initial accumulator state for XXH32(). */ XXH_FORCE_INLINE void XXH32_initAccs(xxh_u32 *acc, xxh_u32 seed) { XXH_ASSERT(acc != NULL); acc[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; acc[1] = seed + XXH_PRIME32_2; acc[2] = seed + 0; acc[3] = seed - XXH_PRIME32_1; } /*! * @internal * @brief Consumes a block of data for XXH32(). * * @return the end input pointer. */ XXH_FORCE_INLINE const xxh_u8 * XXH32_consumeLong( xxh_u32 *XXH_RESTRICT acc, xxh_u8 const *XXH_RESTRICT input, size_t len, XXH_alignment align ) { const xxh_u8* const bEnd = input + len; const xxh_u8* const limit = bEnd - 15; XXH_ASSERT(acc != NULL); XXH_ASSERT(input != NULL); XXH_ASSERT(len >= 16); do { acc[0] = XXH32_round(acc[0], XXH_get32bits(input)); input += 4; acc[1] = XXH32_round(acc[1], XXH_get32bits(input)); input += 4; acc[2] = XXH32_round(acc[2], XXH_get32bits(input)); input += 4; acc[3] = XXH32_round(acc[3], XXH_get32bits(input)); input += 4; } while (input < limit); return input; } /*! * @internal * @brief Merges the accumulator lanes together for XXH32() */ XXH_FORCE_INLINE XXH_PUREF xxh_u32 XXH32_mergeAccs(const xxh_u32 *acc) { XXH_ASSERT(acc != NULL); return XXH_rotl32(acc[0], 1) + XXH_rotl32(acc[1], 7) + XXH_rotl32(acc[2], 12) + XXH_rotl32(acc[3], 18); } /*! * @internal * @brief Processes the last 0-15 bytes of @p ptr. * * There may be up to 15 bytes remaining to consume from the input. * This final stage will digest them to ensure that all input bytes are present * in the final mix. * * @param hash The hash to finalize. * @param ptr The pointer to the remaining input. * @param len The remaining length, modulo 16. * @param align Whether @p ptr is aligned. * @return The finalized hash. * @see XXH64_finalize(). */ static XXH_PUREF xxh_u32 XXH32_finalize(xxh_u32 hash, const xxh_u8* ptr, size_t len, XXH_alignment align) { #define XXH_PROCESS1 do { \ hash += (*ptr++) * XXH_PRIME32_5; \ hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1; \ } while (0) #define XXH_PROCESS4 do { \ hash += XXH_get32bits(ptr) * XXH_PRIME32_3; \ ptr += 4; \ hash = XXH_rotl32(hash, 17) * XXH_PRIME32_4; \ } while (0) if (ptr==NULL) XXH_ASSERT(len == 0); /* Compact rerolled version; generally faster */ if (!XXH32_ENDJMP) { len &= 15; while (len >= 4) { XXH_PROCESS4; len -= 4; } while (len > 0) { XXH_PROCESS1; --len; } return XXH32_avalanche(hash); } else { switch(len&15) /* or switch(bEnd - p) */ { case 12: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 8: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 4: XXH_PROCESS4; return XXH32_avalanche(hash); case 13: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 9: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 5: XXH_PROCESS4; XXH_PROCESS1; return XXH32_avalanche(hash); case 14: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 10: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 6: XXH_PROCESS4; XXH_PROCESS1; XXH_PROCESS1; return XXH32_avalanche(hash); case 15: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 11: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 7: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 3: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 2: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 1: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 0: return XXH32_avalanche(hash); } XXH_ASSERT(0); return hash; /* reaching this point is deemed impossible */ } } #ifdef XXH_OLD_NAMES # define PROCESS1 XXH_PROCESS1 # define PROCESS4 XXH_PROCESS4 #else # undef XXH_PROCESS1 # undef XXH_PROCESS4 #endif /*! * @internal * @brief The implementation for @ref XXH32(). * * @param input , len , seed Directly passed from @ref XXH32(). * @param align Whether @p input is aligned. * @return The calculated hash. */ XXH_FORCE_INLINE XXH_PUREF xxh_u32 XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) { xxh_u32 h32; if (input==NULL) XXH_ASSERT(len == 0); if (len>=16) { xxh_u32 acc[4]; XXH32_initAccs(acc, seed); input = XXH32_consumeLong(acc, input, len, align); h32 = XXH32_mergeAccs(acc); } else { h32 = seed + XXH_PRIME32_5; } h32 += (xxh_u32)len; return XXH32_finalize(h32, input, len&15, align); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) { #if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH32_state_t state; XXH32_reset(&state, seed); XXH32_update(&state, (const xxh_u8*)input, len); return XXH32_digest(&state); #else if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); } } return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); #endif } /******* Hash streaming *******/ #ifndef XXH_NO_STREAM /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) { return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) { XXH_free(statePtr); return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) { XXH_memcpy(dstState, srcState, sizeof(*dstState)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) { XXH_ASSERT(statePtr != NULL); XXH_memset(statePtr, 0, sizeof(*statePtr)); XXH32_initAccs(statePtr->acc, seed); return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_update(XXH32_state_t* state, const void* input, size_t len) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } state->total_len_32 += (XXH32_hash_t)len; state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); XXH_ASSERT(state->bufferedSize < sizeof(state->buffer)); if (len < sizeof(state->buffer) - state->bufferedSize) { /* fill in tmp buffer */ XXH_memcpy(state->buffer + state->bufferedSize, input, len); state->bufferedSize += (XXH32_hash_t)len; return XXH_OK; } { const xxh_u8* xinput = (const xxh_u8*)input; const xxh_u8* const bEnd = xinput + len; if (state->bufferedSize) { /* non-empty buffer: complete first */ XXH_memcpy(state->buffer + state->bufferedSize, xinput, sizeof(state->buffer) - state->bufferedSize); xinput += sizeof(state->buffer) - state->bufferedSize; /* then process one round */ (void)XXH32_consumeLong(state->acc, state->buffer, sizeof(state->buffer), XXH_aligned); state->bufferedSize = 0; } XXH_ASSERT(xinput <= bEnd); if ((size_t)(bEnd - xinput) >= sizeof(state->buffer)) { /* Process the remaining data */ xinput = XXH32_consumeLong(state->acc, xinput, (size_t)(bEnd - xinput), XXH_unaligned); } if (xinput < bEnd) { /* Copy the leftover to the tmp buffer */ XXH_memcpy(state->buffer, xinput, (size_t)(bEnd-xinput)); state->bufferedSize = (unsigned)(bEnd-xinput); } } return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) { xxh_u32 h32; if (state->large_len) { h32 = XXH32_mergeAccs(state->acc); } else { h32 = state->acc[2] /* == seed */ + XXH_PRIME32_5; } h32 += state->total_len_32; return XXH32_finalize(h32, state->buffer, state->bufferedSize, XXH_aligned); } #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! @ingroup XXH32_family */ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); XXH_memcpy(dst, &hash, sizeof(*dst)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) { return XXH_readBE32(src); } #ifndef XXH_NO_LONG_LONG /* ******************************************************************* * 64-bit hash functions *********************************************************************/ /*! * @} * @ingroup impl * @{ */ /******* Memory access *******/ typedef XXH64_hash_t xxh_u64; #ifdef XXH_OLD_NAMES # define U64 xxh_u64 #endif #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) /* * Manual byteshift. Best for old compilers which don't inline memcpy. * We actually directly use XXH_readLE64 and XXH_readBE64. */ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ static xxh_u64 XXH_read64(const void* memPtr) { return *(const xxh_u64*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* * __attribute__((aligned(1))) is supported by gcc and clang. Originally the * documentation claimed that it only increased the alignment, but actually it * can decrease it on gcc, clang, and icc: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502, * https://gcc.godbolt.org/z/xYez1j67Y. */ #ifdef XXH_OLD_NAMES typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((__packed__)) unalign64; #endif static xxh_u64 XXH_read64(const void* ptr) { typedef __attribute__((__aligned__(1))) xxh_u64 xxh_unalign64; return *((const xxh_unalign64*)ptr); } #else /* * Portable and safe solution. Generally efficient. * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html */ static xxh_u64 XXH_read64(const void* memPtr) { xxh_u64 val; XXH_memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap64 _byteswap_uint64 #elif XXH_GCC_VERSION >= 403 # define XXH_swap64 __builtin_bswap64 #else static xxh_u64 XXH_swap64(xxh_u64 x) { return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) | ((x << 8) & 0x000000ff00000000ULL) | ((x >> 8) & 0x00000000ff000000ULL) | ((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 40) & 0x000000000000ff00ULL) | ((x >> 56) & 0x00000000000000ffULL); } #endif /* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[0] | ((xxh_u64)bytePtr[1] << 8) | ((xxh_u64)bytePtr[2] << 16) | ((xxh_u64)bytePtr[3] << 24) | ((xxh_u64)bytePtr[4] << 32) | ((xxh_u64)bytePtr[5] << 40) | ((xxh_u64)bytePtr[6] << 48) | ((xxh_u64)bytePtr[7] << 56); } XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[7] | ((xxh_u64)bytePtr[6] << 8) | ((xxh_u64)bytePtr[5] << 16) | ((xxh_u64)bytePtr[4] << 24) | ((xxh_u64)bytePtr[3] << 32) | ((xxh_u64)bytePtr[2] << 40) | ((xxh_u64)bytePtr[1] << 48) | ((xxh_u64)bytePtr[0] << 56); } #else XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); } static xxh_u64 XXH_readBE64(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); } #endif XXH_FORCE_INLINE xxh_u64 XXH_readLE64_align(const void* ptr, XXH_alignment align) { if (align==XXH_unaligned) return XXH_readLE64(ptr); else return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); } /******* xxh64 *******/ /*! * @} * @defgroup XXH64_impl XXH64 implementation * @ingroup impl * * Details on the XXH64 implementation. * @{ */ /* #define rather that static const, to be used as initializers */ #define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ #define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ #define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ #define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ #define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ #ifdef XXH_OLD_NAMES # define PRIME64_1 XXH_PRIME64_1 # define PRIME64_2 XXH_PRIME64_2 # define PRIME64_3 XXH_PRIME64_3 # define PRIME64_4 XXH_PRIME64_4 # define PRIME64_5 XXH_PRIME64_5 #endif /*! @copydoc XXH32_round */ static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) { acc += input * XXH_PRIME64_2; acc = XXH_rotl64(acc, 31); acc *= XXH_PRIME64_1; #if (defined(__AVX512F__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) /* * DISABLE AUTOVECTORIZATION: * A compiler fence is used to prevent GCC and Clang from * autovectorizing the XXH64 loop (pragmas and attributes don't work for some * reason) without globally disabling AVX512. * * Autovectorization of XXH64 tends to be detrimental, * though the exact outcome may change depending on exact cpu and compiler version. * For information, it has been reported as detrimental for Skylake-X, * but possibly beneficial for Zen4. * * The default is to disable auto-vectorization, * but you can select to enable it instead using `XXH_ENABLE_AUTOVECTORIZE` build variable. */ XXH_COMPILER_GUARD(acc); #endif return acc; } static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) { val = XXH64_round(0, val); acc ^= val; acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; return acc; } /*! @copydoc XXH32_avalanche */ static xxh_u64 XXH64_avalanche(xxh_u64 hash) { hash ^= hash >> 33; hash *= XXH_PRIME64_2; hash ^= hash >> 29; hash *= XXH_PRIME64_3; hash ^= hash >> 32; return hash; } #define XXH_get64bits(p) XXH_readLE64_align(p, align) /*! * @internal * @brief Sets up the initial accumulator state for XXH64(). */ XXH_FORCE_INLINE void XXH64_initAccs(xxh_u64 *acc, xxh_u64 seed) { XXH_ASSERT(acc != NULL); acc[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; acc[1] = seed + XXH_PRIME64_2; acc[2] = seed + 0; acc[3] = seed - XXH_PRIME64_1; } /*! * @internal * @brief Consumes a block of data for XXH64(). * * @return the end input pointer. */ XXH_FORCE_INLINE const xxh_u8 * XXH64_consumeLong( xxh_u64 *XXH_RESTRICT acc, xxh_u8 const *XXH_RESTRICT input, size_t len, XXH_alignment align ) { const xxh_u8* const bEnd = input + len; const xxh_u8* const limit = bEnd - 31; XXH_ASSERT(acc != NULL); XXH_ASSERT(input != NULL); XXH_ASSERT(len >= 32); do { /* reroll on 32-bit */ if (sizeof(void *) < sizeof(xxh_u64)) { size_t i; for (i = 0; i < 4; i++) { acc[i] = XXH64_round(acc[i], XXH_get64bits(input)); input += 8; } } else { acc[0] = XXH64_round(acc[0], XXH_get64bits(input)); input += 8; acc[1] = XXH64_round(acc[1], XXH_get64bits(input)); input += 8; acc[2] = XXH64_round(acc[2], XXH_get64bits(input)); input += 8; acc[3] = XXH64_round(acc[3], XXH_get64bits(input)); input += 8; } } while (input < limit); return input; } /*! * @internal * @brief Merges the accumulator lanes together for XXH64() */ XXH_FORCE_INLINE XXH_PUREF xxh_u64 XXH64_mergeAccs(const xxh_u64 *acc) { XXH_ASSERT(acc != NULL); { xxh_u64 h64 = XXH_rotl64(acc[0], 1) + XXH_rotl64(acc[1], 7) + XXH_rotl64(acc[2], 12) + XXH_rotl64(acc[3], 18); /* reroll on 32-bit */ if (sizeof(void *) < sizeof(xxh_u64)) { size_t i; for (i = 0; i < 4; i++) { h64 = XXH64_mergeRound(h64, acc[i]); } } else { h64 = XXH64_mergeRound(h64, acc[0]); h64 = XXH64_mergeRound(h64, acc[1]); h64 = XXH64_mergeRound(h64, acc[2]); h64 = XXH64_mergeRound(h64, acc[3]); } return h64; } } /*! * @internal * @brief Processes the last 0-31 bytes of @p ptr. * * There may be up to 31 bytes remaining to consume from the input. * This final stage will digest them to ensure that all input bytes are present * in the final mix. * * @param hash The hash to finalize. * @param ptr The pointer to the remaining input. * @param len The remaining length, modulo 32. * @param align Whether @p ptr is aligned. * @return The finalized hash * @see XXH32_finalize(). */ XXH_STATIC XXH_PUREF xxh_u64 XXH64_finalize(xxh_u64 hash, const xxh_u8* ptr, size_t len, XXH_alignment align) { if (ptr==NULL) XXH_ASSERT(len == 0); len &= 31; while (len >= 8) { xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); ptr += 8; hash ^= k1; hash = XXH_rotl64(hash,27) * XXH_PRIME64_1 + XXH_PRIME64_4; len -= 8; } if (len >= 4) { hash ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; ptr += 4; hash = XXH_rotl64(hash, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; len -= 4; } while (len > 0) { hash ^= (*ptr++) * XXH_PRIME64_5; hash = XXH_rotl64(hash, 11) * XXH_PRIME64_1; --len; } return XXH64_avalanche(hash); } #ifdef XXH_OLD_NAMES # define PROCESS1_64 XXH_PROCESS1_64 # define PROCESS4_64 XXH_PROCESS4_64 # define PROCESS8_64 XXH_PROCESS8_64 #else # undef XXH_PROCESS1_64 # undef XXH_PROCESS4_64 # undef XXH_PROCESS8_64 #endif /*! * @internal * @brief The implementation for @ref XXH64(). * * @param input , len , seed Directly passed from @ref XXH64(). * @param align Whether @p input is aligned. * @return The calculated hash. */ XXH_FORCE_INLINE XXH_PUREF xxh_u64 XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) { xxh_u64 h64; if (input==NULL) XXH_ASSERT(len == 0); if (len>=32) { /* Process a large block of data */ xxh_u64 acc[4]; XXH64_initAccs(acc, seed); input = XXH64_consumeLong(acc, input, len, align); h64 = XXH64_mergeAccs(acc); } else { h64 = seed + XXH_PRIME64_5; } h64 += (xxh_u64) len; return XXH64_finalize(h64, input, len, align); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH64_hash_t XXH64 (XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) { #if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH64_state_t state; XXH64_reset(&state, seed); XXH64_update(&state, (const xxh_u8*)input, len); return XXH64_digest(&state); #else if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); } } return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); #endif } /******* Hash Streaming *******/ #ifndef XXH_NO_STREAM /*! @ingroup XXH64_family*/ XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) { return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) { XXH_free(statePtr); return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dstState, const XXH64_state_t* srcState) { XXH_memcpy(dstState, srcState, sizeof(*dstState)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed) { XXH_ASSERT(statePtr != NULL); XXH_memset(statePtr, 0, sizeof(*statePtr)); XXH64_initAccs(statePtr->acc, seed); return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* state, XXH_NOESCAPE const void* input, size_t len) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } state->total_len += len; XXH_ASSERT(state->bufferedSize <= sizeof(state->buffer)); if (len < sizeof(state->buffer) - state->bufferedSize) { /* fill in tmp buffer */ XXH_memcpy(state->buffer + state->bufferedSize, input, len); state->bufferedSize += (XXH32_hash_t)len; return XXH_OK; } { const xxh_u8* xinput = (const xxh_u8*)input; const xxh_u8* const bEnd = xinput + len; if (state->bufferedSize) { /* non-empty buffer => complete first */ XXH_memcpy(state->buffer + state->bufferedSize, xinput, sizeof(state->buffer) - state->bufferedSize); xinput += sizeof(state->buffer) - state->bufferedSize; /* and process one round */ (void)XXH64_consumeLong(state->acc, state->buffer, sizeof(state->buffer), XXH_aligned); state->bufferedSize = 0; } XXH_ASSERT(xinput <= bEnd); if ((size_t)(bEnd - xinput) >= sizeof(state->buffer)) { /* Process the remaining data */ xinput = XXH64_consumeLong(state->acc, xinput, (size_t)(bEnd - xinput), XXH_unaligned); } if (xinput < bEnd) { /* Copy the leftover to the tmp buffer */ XXH_memcpy(state->buffer, xinput, (size_t)(bEnd-xinput)); state->bufferedSize = (unsigned)(bEnd-xinput); } } return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH64_hash_t XXH64_digest(XXH_NOESCAPE const XXH64_state_t* state) { xxh_u64 h64; if (state->total_len >= 32) { h64 = XXH64_mergeAccs(state->acc); } else { h64 = state->acc[2] /*seed*/ + XXH_PRIME64_5; } h64 += (xxh_u64) state->total_len; return XXH64_finalize(h64, state->buffer, (size_t)state->total_len, XXH_aligned); } #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! @ingroup XXH64_family */ XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); XXH_memcpy(dst, &hash, sizeof(*dst)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src) { return XXH_readBE64(src); } #ifndef XXH_NO_XXH3 /* ********************************************************************* * XXH3 * New generation hash designed for speed on small keys and vectorization ************************************************************************ */ /*! * @} * @defgroup XXH3_impl XXH3 implementation * @ingroup impl * @{ */ /* === Compiler specifics === */ #if (defined(__GNUC__) && (__GNUC__ >= 3)) \ || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ || defined(__clang__) # define XXH_likely(x) __builtin_expect(x, 1) # define XXH_unlikely(x) __builtin_expect(x, 0) #else # define XXH_likely(x) (x) # define XXH_unlikely(x) (x) #endif #ifndef XXH_HAS_INCLUDE # ifdef __has_include /* * Not defined as XXH_HAS_INCLUDE(x) (function-like) because * this causes segfaults in Apple Clang 4.2 (on Mac OS X 10.7 Lion) */ # define XXH_HAS_INCLUDE __has_include # else # define XXH_HAS_INCLUDE(x) 0 # endif #endif #if defined(__GNUC__) || defined(__clang__) # if defined(__ARM_FEATURE_SVE) # include # endif # if defined(__ARM_NEON__) || defined(__ARM_NEON) \ || (defined(_M_ARM) && _M_ARM >= 7) \ || defined(_M_ARM64) || defined(_M_ARM64EC) \ || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* WASM SIMD128 via SIMDe */ # define inline __inline__ /* circumvent a clang bug */ # include # undef inline # elif defined(__AVX2__) # include # elif defined(__SSE2__) # include # elif defined(__loongarch_asx) # include # include # elif defined(__loongarch_sx) # include # endif #endif #if defined(_MSC_VER) # include #endif /* * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while * remaining a true 64-bit/128-bit hash function. * * This is done by prioritizing a subset of 64-bit operations that can be * emulated without too many steps on the average 32-bit machine. * * For example, these two lines seem similar, and run equally fast on 64-bit: * * xxh_u64 x; * x ^= (x >> 47); // good * x ^= (x >> 13); // bad * * However, to a 32-bit machine, there is a major difference. * * x ^= (x >> 47) looks like this: * * x.lo ^= (x.hi >> (47 - 32)); * * while x ^= (x >> 13) looks like this: * * // note: funnel shifts are not usually cheap. * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); * x.hi ^= (x.hi >> 13); * * The first one is significantly faster than the second, simply because the * shift is larger than 32. This means: * - All the bits we need are in the upper 32 bits, so we can ignore the lower * 32 bits in the shift. * - The shift result will always fit in the lower 32 bits, and therefore, * we can ignore the upper 32 bits in the xor. * * Thanks to this optimization, XXH3 only requires these features to be efficient: * * - Usable unaligned access * - A 32-bit or 64-bit ALU * - If 32-bit, a decent ADC instruction * - A 32 or 64-bit multiply with a 64-bit result * - For the 128-bit variant, a decent byteswap helps short inputs. * * The first two are already required by XXH32, and almost all 32-bit and 64-bit * platforms which can run XXH32 can run XXH3 efficiently. * * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one * notable exception. * * First of all, Thumb-1 lacks support for the UMULL instruction which * performs the important long multiply. This means numerous __aeabi_lmul * calls. * * Second of all, the 8 functional registers are just not enough. * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need * Lo registers, and this shuffling results in thousands more MOVs than A32. * * A32 and T32 don't have this limitation. They can access all 14 registers, * do a 32->64 multiply with UMULL, and the flexible operand allowing free * shifts is helpful, too. * * Therefore, we do a quick sanity check. * * If compiling Thumb-1 for a target which supports ARM instructions, we will * emit a warning, as it is not a "sane" platform to compile for. * * Usually, if this happens, it is because of an accident and you probably need * to specify -march, as you likely meant to compile for a newer architecture. * * Credit: large sections of the vectorial and asm source code paths * have been contributed by @easyaspi314 */ #if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) # warning "XXH3 is highly inefficient without ARM or Thumb-2." #endif /* ========================================== * Vectorization detection * ========================================== */ #ifdef XXH_DOXYGEN /*! * @ingroup tuning * @brief Overrides the vectorization implementation chosen for XXH3. * * Can be defined to 0 to disable SIMD, * or any other authorized value of @ref XXH_VECTOR. * * If this is not defined, it uses predefined macros to determine the best * implementation. */ # define XXH_VECTOR XXH_SCALAR /*! * @ingroup tuning * @brief Selects the minimum alignment for XXH3's accumulators. * * When using SIMD, this should match the alignment required for said vector * type, so, for example, 32 for AVX2. * * Default: Auto detected. */ # define XXH_ACC_ALIGN 8 #endif /* Actual definition */ #ifndef XXH_DOXYGEN #endif #ifndef XXH_VECTOR /* can be defined on command line */ # if defined(__ARM_FEATURE_SVE) # define XXH_VECTOR XXH_SVE # elif ( \ defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* wasm simd128 via SIMDe */ \ ) && ( \ defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ ) # define XXH_VECTOR XXH_NEON # elif defined(__AVX512F__) # define XXH_VECTOR XXH_AVX512 # elif defined(__AVX2__) # define XXH_VECTOR XXH_AVX2 # elif defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) # define XXH_VECTOR XXH_SSE2 # elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ || (defined(__s390x__) && defined(__VEC__)) \ && defined(__GNUC__) /* TODO: IBM XL */ # define XXH_VECTOR XXH_VSX # elif defined(__loongarch_asx) # define XXH_VECTOR XXH_LASX # elif defined(__loongarch_sx) # define XXH_VECTOR XXH_LSX # else # define XXH_VECTOR XXH_SCALAR # endif #endif /* __ARM_FEATURE_SVE is only supported by GCC & Clang. */ #if (XXH_VECTOR == XXH_SVE) && !defined(__ARM_FEATURE_SVE) # ifdef _MSC_VER # pragma warning(once : 4606) # else # warning "__ARM_FEATURE_SVE isn't supported. Use SCALAR instead." # endif # undef XXH_VECTOR # define XXH_VECTOR XXH_SCALAR #endif /* * Controls the alignment of the accumulator, * for compatibility with aligned vector loads, which are usually faster. */ #ifndef XXH_ACC_ALIGN # if defined(XXH_X86DISPATCH) # define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ # elif XXH_VECTOR == XXH_SCALAR /* scalar */ # define XXH_ACC_ALIGN 8 # elif XXH_VECTOR == XXH_SSE2 /* sse2 */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_AVX2 /* avx2 */ # define XXH_ACC_ALIGN 32 # elif XXH_VECTOR == XXH_NEON /* neon */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_VSX /* vsx */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_AVX512 /* avx512 */ # define XXH_ACC_ALIGN 64 # elif XXH_VECTOR == XXH_SVE /* sve */ # define XXH_ACC_ALIGN 64 # elif XXH_VECTOR == XXH_LASX /* lasx */ # define XXH_ACC_ALIGN 64 # elif XXH_VECTOR == XXH_LSX /* lsx */ # define XXH_ACC_ALIGN 64 # endif #endif #if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 # define XXH_SEC_ALIGN XXH_ACC_ALIGN #elif XXH_VECTOR == XXH_SVE # define XXH_SEC_ALIGN XXH_ACC_ALIGN #else # define XXH_SEC_ALIGN 8 #endif #if defined(__GNUC__) || defined(__clang__) # define XXH_ALIASING __attribute__((__may_alias__)) #else # define XXH_ALIASING /* nothing */ #endif /* * UGLY HACK: * GCC usually generates the best code with -O3 for xxHash. * * However, when targeting AVX2, it is overzealous in its unrolling resulting * in code roughly 3/4 the speed of Clang. * * There are other issues, such as GCC splitting _mm256_loadu_si256 into * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which * only applies to Sandy and Ivy Bridge... which don't even support AVX2. * * That is why when compiling the AVX2 version, it is recommended to use either * -O2 -mavx2 -march=haswell * or * -O2 -mavx2 -mno-avx256-split-unaligned-load * for decent performance, or to use Clang instead. * * Fortunately, we can control the first one with a pragma that forces GCC into * -O2, but the other one we can't control without "failed to inline always * inline function due to target mismatch" warnings. */ #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */ # pragma GCC push_options # pragma GCC optimize("-O2") #endif #if XXH_VECTOR == XXH_NEON /* * UGLY HACK: While AArch64 GCC on Linux does not seem to care, on macOS, GCC -O3 * optimizes out the entire hashLong loop because of the aliasing violation. * * However, GCC is also inefficient at load-store optimization with vld1q/vst1q, * so the only option is to mark it as aliasing. */ typedef uint64x2_t xxh_aliasing_uint64x2_t XXH_ALIASING; /*! * @internal * @brief `vld1q_u64` but faster and alignment-safe. * * On AArch64, unaligned access is always safe, but on ARMv7-a, it is only * *conditionally* safe (`vld1` has an alignment bit like `movdq[ua]` in x86). * * GCC for AArch64 sees `vld1q_u8` as an intrinsic instead of a load, so it * prohibits load-store optimizations. Therefore, a direct dereference is used. * * Otherwise, `vld1q_u8` is used with `vreinterpretq_u8_u64` to do a safe * unaligned load. */ #if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) /* silence -Wcast-align */ { return *(xxh_aliasing_uint64x2_t const *)ptr; } #else XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) { return vreinterpretq_u64_u8(vld1q_u8((uint8_t const*)ptr)); } #endif /*! * @internal * @brief `vmlal_u32` on low and high halves of a vector. * * This is a workaround for AArch64 GCC < 11 which implemented arm_neon.h with * inline assembly and were therefore incapable of merging the `vget_{low, high}_u32` * with `vmlal_u32`. */ #if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 11 XXH_FORCE_INLINE uint64x2_t XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { /* Inline assembly is the only way */ __asm__("umlal %0.2d, %1.2s, %2.2s" : "+w" (acc) : "w" (lhs), "w" (rhs)); return acc; } XXH_FORCE_INLINE uint64x2_t XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { /* This intrinsic works as expected */ return vmlal_high_u32(acc, lhs, rhs); } #else /* Portable intrinsic versions */ XXH_FORCE_INLINE uint64x2_t XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { return vmlal_u32(acc, vget_low_u32(lhs), vget_low_u32(rhs)); } /*! @copydoc XXH_vmlal_low_u32 * Assume the compiler converts this to vmlal_high_u32 on aarch64 */ XXH_FORCE_INLINE uint64x2_t XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { return vmlal_u32(acc, vget_high_u32(lhs), vget_high_u32(rhs)); } #endif /*! * @ingroup tuning * @brief Controls the NEON to scalar ratio for XXH3 * * This can be set to 2, 4, 6, or 8. * * ARM Cortex CPUs are _very_ sensitive to how their pipelines are used. * * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but only 2 of those * can be NEON. If you are only using NEON instructions, you are only using 2/3 of the CPU * bandwidth. * * This is even more noticeable on the more advanced cores like the Cortex-A76 which * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. * * Therefore, to make the most out of the pipeline, it is beneficial to run 6 NEON lanes * and 2 scalar lanes, which is chosen by default. * * This does not apply to Apple processors or 32-bit processors, which run better with * full NEON. These will default to 8. Additionally, size-optimized builds run 8 lanes. * * This change benefits CPUs with large micro-op buffers without negatively affecting * most other CPUs: * * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | * |:----------------------|:--------------------|----------:|-----------:|------:| * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | * | Apple M1 | 4 NEON/8 micro-ops | 37.3 GB/s | 36.1 GB/s | ~-3% | * * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. * * When using WASM SIMD128, if this is 2 or 6, SIMDe will scalarize 2 of the lanes meaning * it effectively becomes worse 4. * * @see XXH3_accumulate_512_neon() */ # ifndef XXH3_NEON_LANES # if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ && !defined(__APPLE__) && XXH_SIZE_OPT <= 0 # define XXH3_NEON_LANES 6 # else # define XXH3_NEON_LANES XXH_ACC_NB # endif # endif #endif /* XXH_VECTOR == XXH_NEON */ /* * VSX and Z Vector helpers. * * This is very messy, and any pull requests to clean this up are welcome. * * There are a lot of problems with supporting VSX and s390x, due to * inconsistent intrinsics, spotty coverage, and multiple endiannesses. */ #if XXH_VECTOR == XXH_VSX /* Annoyingly, these headers _may_ define three macros: `bool`, `vector`, * and `pixel`. This is a problem for obvious reasons. * * These keywords are unnecessary; the spec literally says they are * equivalent to `__bool`, `__vector`, and `__pixel` and may be undef'd * after including the header. * * We use pragma push_macro/pop_macro to keep the namespace clean. */ # pragma push_macro("bool") # pragma push_macro("vector") # pragma push_macro("pixel") /* silence potential macro redefined warnings */ # undef bool # undef vector # undef pixel # if defined(__s390x__) # include # else # include # endif /* Restore the original macro values, if applicable. */ # pragma pop_macro("pixel") # pragma pop_macro("vector") # pragma pop_macro("bool") typedef __vector unsigned long long xxh_u64x2; typedef __vector unsigned char xxh_u8x16; typedef __vector unsigned xxh_u32x4; /* * UGLY HACK: Similar to aarch64 macOS GCC, s390x GCC has the same aliasing issue. */ typedef xxh_u64x2 xxh_aliasing_u64x2 XXH_ALIASING; # ifndef XXH_VSX_BE # if defined(__BIG_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) # define XXH_VSX_BE 1 # elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ # warning "-maltivec=be is not recommended. Please use native endianness." # define XXH_VSX_BE 1 # else # define XXH_VSX_BE 0 # endif # endif /* !defined(XXH_VSX_BE) */ # if XXH_VSX_BE # if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) # define XXH_vec_revb vec_revb # else /*! * A polyfill for POWER9's vec_revb(). */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) { xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; return vec_perm(val, val, vByteSwap); } # endif # endif /* XXH_VSX_BE */ /*! * Performs an unaligned vector load and byte swaps it on big endian. */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) { xxh_u64x2 ret; XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2)); # if XXH_VSX_BE ret = XXH_vec_revb(ret); # endif return ret; } /* * vec_mulo and vec_mule are very problematic intrinsics on PowerPC * * These intrinsics weren't added until GCC 8, despite existing for a while, * and they are endian dependent. Also, their meaning swap depending on version. * */ # if defined(__s390x__) /* s390x is always big endian, no issue on this platform */ # define XXH_vec_mulo vec_mulo # define XXH_vec_mule vec_mule # elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) && !defined(__ibmxl__) /* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ /* The IBM XL Compiler (which defined __clang__) only implements the vec_* operations */ # define XXH_vec_mulo __builtin_altivec_vmulouw # define XXH_vec_mule __builtin_altivec_vmuleuw # else /* gcc needs inline assembly */ /* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) { xxh_u64x2 result; __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); return result; } XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) { xxh_u64x2 result; __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); return result; } # endif /* XXH_vec_mulo, XXH_vec_mule */ #endif /* XXH_VECTOR == XXH_VSX */ #if XXH_VECTOR == XXH_SVE #define ACCRND(acc, offset) \ do { \ svuint64_t input_vec = svld1_u64(mask, xinput + offset); \ svuint64_t secret_vec = svld1_u64(mask, xsecret + offset); \ svuint64_t mixed = sveor_u64_x(mask, secret_vec, input_vec); \ svuint64_t swapped = svtbl_u64(input_vec, kSwap); \ svuint64_t mixed_lo = svextw_u64_x(mask, mixed); \ svuint64_t mixed_hi = svlsr_n_u64_x(mask, mixed, 32); \ svuint64_t mul = svmad_u64_x(mask, mixed_lo, mixed_hi, swapped); \ acc = svadd_u64_x(mask, acc, mul); \ } while (0) #endif /* XXH_VECTOR == XXH_SVE */ /* prefetch * can be disabled, by declaring XXH_NO_PREFETCH build macro */ #if defined(XXH_NO_PREFETCH) # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ #else # if XXH_SIZE_OPT >= 1 # define XXH_PREFETCH(ptr) (void)(ptr) # elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */ # include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # else # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ # endif #endif /* XXH_NO_PREFETCH */ /* ========================================== * XXH3 default settings * ========================================== */ #define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ #if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) # error "default keyset is not large enough" #endif /*! * @internal * @def XXH3_kSecret * @brief Pseudorandom secret taken directly from FARSH. */ XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, }; static const xxh_u64 PRIME_MX1 = 0x165667919E3779F9ULL; /*!< 0b0001011001010110011001111001000110011110001101110111100111111001 */ static const xxh_u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL; /*!< 0b1001111110110010000111000110010100011110100110001101111100100101 */ #ifdef XXH_OLD_NAMES # define kSecret XXH3_kSecret #endif #ifdef XXH_DOXYGEN /*! * @brief Calculates a 32-bit to 64-bit long multiply. * * Implemented as a macro. * * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't * need to (but it shouldn't need to anyways, it is about 7 instructions to do * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we * use that instead of the normal method. * * If you are compiling for platforms like Thumb-1 and don't have a better option, * you may also want to write your own long multiply routine here. * * @param x, y Numbers to be multiplied * @return 64-bit product of the low 32 bits of @p x and @p y. */ XXH_FORCE_INLINE xxh_u64 XXH_mult32to64(xxh_u64 x, xxh_u64 y) { return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); } #elif defined(_MSC_VER) && defined(_M_IX86) # define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) #else /* * Downcast + upcast is usually better than masking on older compilers like * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. * * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands * and perform a full 64x64 multiply -- entirely redundant on 32-bit. */ # define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) #endif /*! * @brief Calculates a 64->128-bit long multiply. * * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar * version. * * @param lhs , rhs The 64-bit integers to be multiplied * @return The 128-bit result represented in an @ref XXH128_hash_t. */ static XXH128_hash_t XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) { /* * GCC/Clang __uint128_t method. * * On most 64-bit targets, GCC and Clang define a __uint128_t type. * This is usually the best way as it usually uses a native long 64-bit * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. * * Usually. * * Despite being a 32-bit platform, Clang (and emscripten) define this type * despite not having the arithmetic for it. This results in a laggy * compiler builtin call which calculates a full 128-bit multiply. * In that case it is best to use the portable one. * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 */ #if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \ && defined(__SIZEOF_INT128__) \ || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; XXH128_hash_t r128; r128.low64 = (xxh_u64)(product); r128.high64 = (xxh_u64)(product >> 64); return r128; /* * MSVC for x64's _umul128 method. * * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); * * This compiles to single operand MUL on x64. */ #elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC) #ifndef _MSC_VER # pragma intrinsic(_umul128) #endif xxh_u64 product_high; xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); XXH128_hash_t r128; r128.low64 = product_low; r128.high64 = product_high; return r128; /* * MSVC for ARM64's __umulh method. * * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. */ #elif defined(_M_ARM64) || defined(_M_ARM64EC) #ifndef _MSC_VER # pragma intrinsic(__umulh) #endif XXH128_hash_t r128; r128.low64 = lhs * rhs; r128.high64 = __umulh(lhs, rhs); return r128; #else /* * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. * * This is a fast and simple grade school multiply, which is shown below * with base 10 arithmetic instead of base 0x100000000. * * 9 3 // D2 lhs = 93 * x 7 5 // D2 rhs = 75 * ---------- * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 * --------- * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 * --------- * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 * * The reasons for adding the products like this are: * 1. It avoids manual carry tracking. Just like how * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. * This avoids a lot of complexity. * * 2. It hints for, and on Clang, compiles to, the powerful UMAAL * instruction available in ARM's Digital Signal Processing extension * in 32-bit ARMv6 and later, which is shown below: * * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) * { * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); * *RdHi = (xxh_u32)(product >> 32); * } * * This instruction was designed for efficient long multiplication, and * allows this to be calculated in only 4 instructions at speeds * comparable to some 64-bit ALUs. * * 3. It isn't terrible on other platforms. Usually this will be a couple * of 32-bit ADD/ADCs. */ /* First calculate all of the cross products. */ xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); /* Now add the products together. These will never overflow. */ xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); XXH128_hash_t r128; r128.low64 = lower; r128.high64 = upper; return r128; #endif } /*! * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it. * * The reason for the separate function is to prevent passing too many structs * around by value. This will hopefully inline the multiply, but we don't force it. * * @param lhs , rhs The 64-bit integers to multiply * @return The low 64 bits of the product XOR'd by the high 64 bits. * @see XXH_mult64to128() */ static xxh_u64 XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) { XXH128_hash_t product = XXH_mult64to128(lhs, rhs); return product.low64 ^ product.high64; } /*! Seems to produce slightly better code on GCC for some reason. */ XXH_FORCE_INLINE XXH_CONSTF xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) { XXH_ASSERT(0 <= shift && shift < 64); return v64 ^ (v64 >> shift); } /* * This is a fast avalanche stage, * suitable when input bits are already partially mixed */ static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) { h64 = XXH_xorshift64(h64, 37); h64 *= PRIME_MX1; h64 = XXH_xorshift64(h64, 32); return h64; } /* * This is a stronger avalanche, * inspired by Pelle Evensen's rrmxmx * preferable when input has not been previously mixed */ static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) { /* this mix is inspired by Pelle Evensen's rrmxmx */ h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); h64 *= PRIME_MX2; h64 ^= (h64 >> 35) + len ; h64 *= PRIME_MX2; return XXH_xorshift64(h64, 28); } /* ========================================== * Short keys * ========================================== * One of the shortcomings of XXH32 and XXH64 was that their performance was * sub-optimal on short lengths. It used an iterative algorithm which strongly * favored lengths that were a multiple of 4 or 8. * * Instead of iterating over individual inputs, we use a set of single shot * functions which piece together a range of lengths and operate in constant time. * * Additionally, the number of multiplies has been significantly reduced. This * reduces latency, especially when emulating 64-bit multiplies on 32-bit. * * Depending on the platform, this may or may not be faster than XXH32, but it * is almost guaranteed to be faster than XXH64. */ /* * At very short lengths, there isn't enough input to fully hide secrets, or use * the entire secret. * * There is also only a limited amount of mixing we can do before significantly * impacting performance. * * Therefore, we use different sections of the secret and always mix two secret * samples with an XOR. This should have no effect on performance on the * seedless or withSeed variants because everything _should_ be constant folded * by modern compilers. * * The XOR mixing hides individual parts of the secret and increases entropy. * * This adds an extra layer of strength for custom secrets. */ XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(1 <= len && len <= 3); XXH_ASSERT(secret != NULL); /* * len = 1: combined = { input[0], 0x01, input[0], input[0] } * len = 2: combined = { input[1], 0x02, input[0], input[1] } * len = 3: combined = { input[2], 0x03, input[0], input[1] } */ { xxh_u8 const c1 = input[0]; xxh_u8 const c2 = input[len >> 1]; xxh_u8 const c3 = input[len - 1]; xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; return XXH64_avalanche(keyed); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(4 <= len && len <= 8); seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; { xxh_u32 const input1 = XXH_readLE32(input); xxh_u32 const input2 = XXH_readLE32(input + len - 4); xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); xxh_u64 const keyed = input64 ^ bitflip; return XXH3_rrmxmx(keyed, len); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(9 <= len && len <= 16); { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; xxh_u64 const acc = len + XXH_swap64(input_lo) + input_hi + XXH3_mul128_fold64(input_lo, input_hi); return XXH3_avalanche(acc); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(len <= 16); { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); if (len) return XXH3_len_1to3_64b(input, len, secret, seed); return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); } } /* * DISCLAIMER: There are known *seed-dependent* multicollisions here due to * multiplication by zero, affecting hashes of lengths 17 to 240. * * However, they are very unlikely. * * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all * unseeded non-cryptographic hashes, it does not attempt to defend itself * against specially crafted inputs, only random inputs. * * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes * cancelling out the secret is taken an arbitrary number of times (addressed * in XXH3_accumulate_512), this collision is very unlikely with random inputs * and/or proper seeding: * * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a * function that is only called up to 16 times per hash with up to 240 bytes of * input. * * This is not too bad for a non-cryptographic hash function, especially with * only 64 bit outputs. * * The 128-bit variant (which trades some speed for strength) is NOT affected * by this, although it is always a good idea to use a proper seed if you care * about strength. */ XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) { #if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ /* * UGLY HACK: * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in * slower code. * * By forcing seed64 into a register, we disrupt the cost model and * cause it to scalarize. See `XXH32_round()` * * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on * GCC 9.2, despite both emitting scalar code. * * GCC generates much better scalar code than Clang for the rest of XXH3, * which is why finding a more optimal codepath is an interest. */ XXH_COMPILER_GUARD(seed64); #endif { xxh_u64 const input_lo = XXH_readLE64(input); xxh_u64 const input_hi = XXH_readLE64(input+8); return XXH3_mul128_fold64( input_lo ^ (XXH_readLE64(secret) + seed64), input_hi ^ (XXH_readLE64(secret+8) - seed64) ); } } /* For mid range keys, XXH3 uses a Mum-hash variant. */ XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(16 < len && len <= 128); { xxh_u64 acc = len * XXH_PRIME64_1; #if XXH_SIZE_OPT >= 1 /* Smaller and cleaner, but slightly slower. */ unsigned int i = (unsigned int)(len - 1) / 32; do { acc += XXH3_mix16B(input+16 * i, secret+32*i, seed); acc += XXH3_mix16B(input+len-16*(i+1), secret+32*i+16, seed); } while (i-- != 0); #else if (len > 32) { if (len > 64) { if (len > 96) { acc += XXH3_mix16B(input+48, secret+96, seed); acc += XXH3_mix16B(input+len-64, secret+112, seed); } acc += XXH3_mix16B(input+32, secret+64, seed); acc += XXH3_mix16B(input+len-48, secret+80, seed); } acc += XXH3_mix16B(input+16, secret+32, seed); acc += XXH3_mix16B(input+len-32, secret+48, seed); } acc += XXH3_mix16B(input+0, secret+0, seed); acc += XXH3_mix16B(input+len-16, secret+16, seed); #endif return XXH3_avalanche(acc); } } XXH_NO_INLINE XXH_PUREF XXH64_hash_t XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); #define XXH3_MIDSIZE_STARTOFFSET 3 #define XXH3_MIDSIZE_LASTOFFSET 17 { xxh_u64 acc = len * XXH_PRIME64_1; xxh_u64 acc_end; unsigned int const nbRounds = (unsigned int)len / 16; unsigned int i; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); for (i=0; i<8; i++) { acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); } /* last bytes */ acc_end = XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); XXH_ASSERT(nbRounds >= 8); acc = XXH3_avalanche(acc); #if defined(__clang__) /* Clang */ \ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ /* * UGLY HACK: * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. * In everywhere else, it uses scalar code. * * For 64->128-bit multiplies, even if the NEON was 100% optimal, it * would still be slower than UMAAL (see XXH_mult64to128). * * Unfortunately, Clang doesn't handle the long multiplies properly and * converts them to the nonexistent "vmulq_u64" intrinsic, which is then * scalarized into an ugly mess of VMOV.32 instructions. * * This mess is difficult to avoid without turning autovectorization * off completely, but they are usually relatively minor and/or not * worth it to fix. * * This loop is the easiest to fix, as unlike XXH32, this pragma * _actually works_ because it is a loop vectorization instead of an * SLP vectorization. */ #pragma clang loop vectorize(disable) #endif for (i=8 ; i < nbRounds; i++) { /* * Prevents clang for unrolling the acc loop and interleaving with this one. */ XXH_COMPILER_GUARD(acc); acc_end += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); } return XXH3_avalanche(acc + acc_end); } } /* ======= Long Keys ======= */ #define XXH_STRIPE_LEN 64 #define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ #define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) #ifdef XXH_OLD_NAMES # define STRIPE_LEN XXH_STRIPE_LEN # define ACC_NB XXH_ACC_NB #endif #ifndef XXH_PREFETCH_DIST # ifdef __clang__ # define XXH_PREFETCH_DIST 320 # else # if (XXH_VECTOR == XXH_AVX512) # define XXH_PREFETCH_DIST 512 # else # define XXH_PREFETCH_DIST 384 # endif # endif /* __clang__ */ #endif /* XXH_PREFETCH_DIST */ /* * These macros are to generate an XXH3_accumulate() function. * The two arguments select the name suffix and target attribute. * * The name of this symbol is XXH3_accumulate_() and it calls * XXH3_accumulate_512_(). * * It may be useful to hand implement this function if the compiler fails to * optimize the inline function. */ #define XXH3_ACCUMULATE_TEMPLATE(name) \ void \ XXH3_accumulate_##name(xxh_u64* XXH_RESTRICT acc, \ const xxh_u8* XXH_RESTRICT input, \ const xxh_u8* XXH_RESTRICT secret, \ size_t nbStripes) \ { \ size_t n; \ for (n = 0; n < nbStripes; n++ ) { \ const xxh_u8* const in = input + n*XXH_STRIPE_LEN; \ XXH_PREFETCH(in + XXH_PREFETCH_DIST); \ XXH3_accumulate_512_##name( \ acc, \ in, \ secret + n*XXH_SECRET_CONSUME_RATE); \ } \ } XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) { if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); XXH_memcpy(dst, &v64, sizeof(v64)); } /* Several intrinsic functions below are supposed to accept __int64 as argument, * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . * However, several environments do not define __int64 type, * requiring a workaround. */ #if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) typedef int64_t xxh_i64; #else /* the following type must have a width of 64-bit */ typedef long long xxh_i64; #endif /* * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. * * It is a hardened version of UMAC, based off of FARSH's implementation. * * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD * implementations, and it is ridiculously fast. * * We harden it by mixing the original input to the accumulators as well as the product. * * This means that in the (relatively likely) case of a multiply by zero, the * original input is preserved. * * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve * cross-pollination, as otherwise the upper and lower halves would be * essentially independent. * * This doesn't matter on 64-bit hashes since they all get merged together in * the end, so we skip the extra step. * * Both XXH3_64bits and XXH3_128bits use this subroutine. */ #if (XXH_VECTOR == XXH_AVX512) \ || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) #ifndef XXH_TARGET_AVX512 # define XXH_TARGET_AVX512 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { __m512i* const xacc = (__m512i *) acc; XXH_ASSERT((((size_t)acc) & 63) == 0); XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); { /* data_vec = input[0]; */ __m512i const data_vec = _mm512_loadu_si512 (input); /* key_vec = secret[0]; */ __m512i const key_vec = _mm512_loadu_si512 (secret); /* data_key = data_vec ^ key_vec; */ __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m512i const data_key_lo = _mm512_srli_epi64 (data_key, 32); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); /* xacc[0] += swap(data_vec); */ __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); __m512i const sum = _mm512_add_epi64(*xacc, data_swap); /* xacc[0] += product; */ *xacc = _mm512_add_epi64(product, sum); } } XXH_FORCE_INLINE XXH_TARGET_AVX512 XXH3_ACCUMULATE_TEMPLATE(avx512) /* * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. * * Multiplication isn't perfect, as explained by Google in HighwayHash: * * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to * // varying degrees. In descending order of goodness, bytes * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. * // As expected, the upper and lower bytes are much worse. * * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 * * Since our algorithm uses a pseudorandom secret to add some variance into the * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. * * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid * extraction. * * Both XXH3_64bits and XXH3_128bits use this subroutine. */ XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 63) == 0); XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); { __m512i* const xacc = (__m512i*) acc; const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); /* xacc[0] ^= (xacc[0] >> 47) */ __m512i const acc_vec = *xacc; __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); /* xacc[0] ^= secret; */ __m512i const key_vec = _mm512_loadu_si512 (secret); __m512i const data_key = _mm512_ternarylogic_epi32(key_vec, acc_vec, shifted, 0x96 /* key_vec ^ acc_vec ^ shifted */); /* xacc[0] *= XXH_PRIME32_1; */ __m512i const data_key_hi = _mm512_srli_epi64 (data_key, 32); __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); } } XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); XXH_ASSERT(((size_t)customSecret & 63) == 0); (void)(&XXH_writeLE64); { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); __m512i const seed_pos = _mm512_set1_epi64((xxh_i64)seed64); __m512i const seed = _mm512_mask_sub_epi64(seed_pos, 0xAA, _mm512_set1_epi8(0), seed_pos); const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); __m512i* const dest = ( __m512i*) customSecret; int i; XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ XXH_ASSERT(((size_t)dest & 63) == 0); for (i=0; i < nbRounds; ++i) { dest[i] = _mm512_add_epi64(_mm512_load_si512(src + i), seed); } } } #endif #if (XXH_VECTOR == XXH_AVX2) \ || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) #ifndef XXH_TARGET_AVX2 # define XXH_TARGET_AVX2 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { __m256i* const xacc = (__m256i *) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xinput = (const __m256i *) input; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xsecret = (const __m256i *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { /* data_vec = xinput[i]; */ __m256i const data_vec = _mm256_loadu_si256 (xinput+i); /* key_vec = xsecret[i]; */ __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); /* data_key = data_vec ^ key_vec; */ __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m256i const data_key_lo = _mm256_srli_epi64 (data_key, 32); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = _mm256_add_epi64(product, sum); } } } XXH_FORCE_INLINE XXH_TARGET_AVX2 XXH3_ACCUMULATE_TEMPLATE(avx2) XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { __m256i* const xacc = (__m256i*) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xsecret = (const __m256i *) secret; const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m256i const acc_vec = xacc[i]; __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); /* xacc[i] ^= xsecret; */ __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ __m256i const data_key_hi = _mm256_srli_epi64 (data_key, 32); __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); } } } XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); (void)(&XXH_writeLE64); XXH_PREFETCH(customSecret); { __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); __m256i* dest = ( __m256i*) customSecret; # if defined(__GNUC__) || defined(__clang__) /* * On GCC & Clang, marking 'dest' as modified will cause the compiler: * - do not extract the secret from sse registers in the internal loop * - use less common registers, and avoid pushing these reg into stack */ XXH_COMPILER_GUARD(dest); # endif XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ XXH_ASSERT(((size_t)dest & 31) == 0); /* GCC -O2 need unroll loop manually */ dest[0] = _mm256_add_epi64(_mm256_load_si256(src+0), seed); dest[1] = _mm256_add_epi64(_mm256_load_si256(src+1), seed); dest[2] = _mm256_add_epi64(_mm256_load_si256(src+2), seed); dest[3] = _mm256_add_epi64(_mm256_load_si256(src+3), seed); dest[4] = _mm256_add_epi64(_mm256_load_si256(src+4), seed); dest[5] = _mm256_add_epi64(_mm256_load_si256(src+5), seed); } } #endif /* x86dispatch always generates SSE2 */ #if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) #ifndef XXH_TARGET_SSE2 # define XXH_TARGET_SSE2 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { /* SSE2 is just a half-scale version of the AVX2 version. */ XXH_ASSERT((((size_t)acc) & 15) == 0); { __m128i* const xacc = (__m128i *) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xinput = (const __m128i *) input; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xsecret = (const __m128i *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { /* data_vec = xinput[i]; */ __m128i const data_vec = _mm_loadu_si128 (xinput+i); /* key_vec = xsecret[i]; */ __m128i const key_vec = _mm_loadu_si128 (xsecret+i); /* data_key = data_vec ^ key_vec; */ __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); __m128i const sum = _mm_add_epi64(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = _mm_add_epi64(product, sum); } } } XXH_FORCE_INLINE XXH_TARGET_SSE2 XXH3_ACCUMULATE_TEMPLATE(sse2) XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { __m128i* const xacc = (__m128i*) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xsecret = (const __m128i *) secret; const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m128i const acc_vec = xacc[i]; __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ __m128i const key_vec = _mm_loadu_si128 (xsecret+i); __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); } } } XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); (void)(&XXH_writeLE64); { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); # if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */ XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) }; __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); # else __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); # endif int i; const void* const src16 = XXH3_kSecret; __m128i* dst16 = (__m128i*) customSecret; # if defined(__GNUC__) || defined(__clang__) /* * On GCC & Clang, marking 'dest' as modified will cause the compiler: * - do not extract the secret from sse registers in the internal loop * - use less common registers, and avoid pushing these reg into stack */ XXH_COMPILER_GUARD(dst16); # endif XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ XXH_ASSERT(((size_t)dst16 & 15) == 0); for (i=0; i < nbRounds; ++i) { dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); } } } #endif #if (XXH_VECTOR == XXH_NEON) /* forward declarations for the scalar routines */ XXH_FORCE_INLINE void XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, void const* XXH_RESTRICT secret, size_t lane); XXH_FORCE_INLINE void XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT secret, size_t lane); /*! * @internal * @brief The bulk processing loop for NEON and WASM SIMD128. * * The NEON code path is actually partially scalar when running on AArch64. This * is to optimize the pipelining and can have up to 15% speedup depending on the * CPU, and it also mitigates some GCC codegen issues. * * @see XXH3_NEON_LANES for configuring this and details about this optimization. * * NEON's 32-bit to 64-bit long multiply takes a half vector of 32-bit * integers instead of the other platforms which mask full 64-bit vectors, * so the setup is more complicated than just shifting right. * * Additionally, there is an optimization for 4 lanes at once noted below. * * Since, as stated, the most optimal amount of lanes for Cortexes is 6, * there needs to be *three* versions of the accumulate operation used * for the remaining 2 lanes. * * WASM's SIMD128 uses SIMDe's arm_neon.h polyfill because the intrinsics overlap * nearly perfectly. */ XXH_FORCE_INLINE void XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); { /* GCC for darwin arm64 does not like aliasing here */ xxh_aliasing_uint64x2_t* const xacc = (xxh_aliasing_uint64x2_t*) acc; /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ uint8_t const* xinput = (const uint8_t *) input; uint8_t const* xsecret = (const uint8_t *) secret; size_t i; #ifdef __wasm_simd128__ /* * On WASM SIMD128, Clang emits direct address loads when XXH3_kSecret * is constant propagated, which results in it converting it to this * inside the loop: * * a = v128.load(XXH3_kSecret + 0 + $secret_offset, offset = 0) * b = v128.load(XXH3_kSecret + 16 + $secret_offset, offset = 0) * ... * * This requires a full 32-bit address immediate (and therefore a 6 byte * instruction) as well as an add for each offset. * * Putting an asm guard prevents it from folding (at the cost of losing * the alignment hint), and uses the free offset in `v128.load` instead * of adding secret_offset each time which overall reduces code size by * about a kilobyte and improves performance. */ XXH_COMPILER_GUARD(xsecret); #endif /* Scalar lanes use the normal scalarRound routine */ for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { XXH3_scalarRound(acc, input, secret, i); } i = 0; /* 4 NEON lanes at a time. */ for (; i+1 < XXH3_NEON_LANES / 2; i+=2) { /* data_vec = xinput[i]; */ uint64x2_t data_vec_1 = XXH_vld1q_u64(xinput + (i * 16)); uint64x2_t data_vec_2 = XXH_vld1q_u64(xinput + ((i+1) * 16)); /* key_vec = xsecret[i]; */ uint64x2_t key_vec_1 = XXH_vld1q_u64(xsecret + (i * 16)); uint64x2_t key_vec_2 = XXH_vld1q_u64(xsecret + ((i+1) * 16)); /* data_swap = swap(data_vec) */ uint64x2_t data_swap_1 = vextq_u64(data_vec_1, data_vec_1, 1); uint64x2_t data_swap_2 = vextq_u64(data_vec_2, data_vec_2, 1); /* data_key = data_vec ^ key_vec; */ uint64x2_t data_key_1 = veorq_u64(data_vec_1, key_vec_1); uint64x2_t data_key_2 = veorq_u64(data_vec_2, key_vec_2); /* * If we reinterpret the 64x2 vectors as 32x4 vectors, we can use a * de-interleave operation for 4 lanes in 1 step with `vuzpq_u32` to * get one vector with the low 32 bits of each lane, and one vector * with the high 32 bits of each lane. * * The intrinsic returns a double vector because the original ARMv7-a * instruction modified both arguments in place. AArch64 and SIMD128 emit * two instructions from this intrinsic. * * [ dk11L | dk11H | dk12L | dk12H ] -> [ dk11L | dk12L | dk21L | dk22L ] * [ dk21L | dk21H | dk22L | dk22H ] -> [ dk11H | dk12H | dk21H | dk22H ] */ uint32x4x2_t unzipped = vuzpq_u32( vreinterpretq_u32_u64(data_key_1), vreinterpretq_u32_u64(data_key_2) ); /* data_key_lo = data_key & 0xFFFFFFFF */ uint32x4_t data_key_lo = unzipped.val[0]; /* data_key_hi = data_key >> 32 */ uint32x4_t data_key_hi = unzipped.val[1]; /* * Then, we can split the vectors horizontally and multiply which, as for most * widening intrinsics, have a variant that works on both high half vectors * for free on AArch64. A similar instruction is available on SIMD128. * * sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi */ uint64x2_t sum_1 = XXH_vmlal_low_u32(data_swap_1, data_key_lo, data_key_hi); uint64x2_t sum_2 = XXH_vmlal_high_u32(data_swap_2, data_key_lo, data_key_hi); /* * Clang reorders * a += b * c; // umlal swap.2d, dkl.2s, dkh.2s * c += a; // add acc.2d, acc.2d, swap.2d * to * c += a; // add acc.2d, acc.2d, swap.2d * c += b * c; // umlal acc.2d, dkl.2s, dkh.2s * * While it would make sense in theory since the addition is faster, * for reasons likely related to umlal being limited to certain NEON * pipelines, this is worse. A compiler guard fixes this. */ XXH_COMPILER_GUARD_CLANG_NEON(sum_1); XXH_COMPILER_GUARD_CLANG_NEON(sum_2); /* xacc[i] = acc_vec + sum; */ xacc[i] = vaddq_u64(xacc[i], sum_1); xacc[i+1] = vaddq_u64(xacc[i+1], sum_2); } /* Operate on the remaining NEON lanes 2 at a time. */ for (; i < XXH3_NEON_LANES / 2; i++) { /* data_vec = xinput[i]; */ uint64x2_t data_vec = XXH_vld1q_u64(xinput + (i * 16)); /* key_vec = xsecret[i]; */ uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16)); /* acc_vec_2 = swap(data_vec) */ uint64x2_t data_swap = vextq_u64(data_vec, data_vec, 1); /* data_key = data_vec ^ key_vec; */ uint64x2_t data_key = veorq_u64(data_vec, key_vec); /* For two lanes, just use VMOVN and VSHRN. */ /* data_key_lo = data_key & 0xFFFFFFFF; */ uint32x2_t data_key_lo = vmovn_u64(data_key); /* data_key_hi = data_key >> 32; */ uint32x2_t data_key_hi = vshrn_n_u64(data_key, 32); /* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi; */ uint64x2_t sum = vmlal_u32(data_swap, data_key_lo, data_key_hi); /* Same Clang workaround as before */ XXH_COMPILER_GUARD_CLANG_NEON(sum); /* xacc[i] = acc_vec + sum; */ xacc[i] = vaddq_u64 (xacc[i], sum); } } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(neon) XXH_FORCE_INLINE void XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { xxh_aliasing_uint64x2_t* xacc = (xxh_aliasing_uint64x2_t*) acc; uint8_t const* xsecret = (uint8_t const*) secret; size_t i; /* WASM uses operator overloads and doesn't need these. */ #ifndef __wasm_simd128__ /* { prime32_1, prime32_1 } */ uint32x2_t const kPrimeLo = vdup_n_u32(XXH_PRIME32_1); /* { 0, prime32_1, 0, prime32_1 } */ uint32x4_t const kPrimeHi = vreinterpretq_u32_u64(vdupq_n_u64((xxh_u64)XXH_PRIME32_1 << 32)); #endif /* AArch64 uses both scalar and neon at the same time */ for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { XXH3_scalarScrambleRound(acc, secret, i); } for (i=0; i < XXH3_NEON_LANES / 2; i++) { /* xacc[i] ^= (xacc[i] >> 47); */ uint64x2_t acc_vec = xacc[i]; uint64x2_t shifted = vshrq_n_u64(acc_vec, 47); uint64x2_t data_vec = veorq_u64(acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16)); uint64x2_t data_key = veorq_u64(data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1 */ #ifdef __wasm_simd128__ /* SIMD128 has multiply by u64x2, use it instead of expanding and scalarizing */ xacc[i] = data_key * XXH_PRIME32_1; #else /* * Expanded version with portable NEON intrinsics * * lo(x) * lo(y) + (hi(x) * lo(y) << 32) * * prod_hi = hi(data_key) * lo(prime) << 32 * * Since we only need 32 bits of this multiply a trick can be used, reinterpreting the vector * as a uint32x4_t and multiplying by { 0, prime, 0, prime } to cancel out the unwanted bits * and avoid the shift. */ uint32x4_t prod_hi = vmulq_u32 (vreinterpretq_u32_u64(data_key), kPrimeHi); /* Extract low bits for vmlal_u32 */ uint32x2_t data_key_lo = vmovn_u64(data_key); /* xacc[i] = prod_hi + lo(data_key) * XXH_PRIME32_1; */ xacc[i] = vmlal_u32(vreinterpretq_u64_u32(prod_hi), data_key_lo, kPrimeLo); #endif } } } #endif #if (XXH_VECTOR == XXH_VSX) XXH_FORCE_INLINE void XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { /* presumed aligned */ xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc; xxh_u8 const* const xinput = (xxh_u8 const*) input; /* no alignment restriction */ xxh_u8 const* const xsecret = (xxh_u8 const*) secret; /* no alignment restriction */ xxh_u64x2 const v32 = { 32, 32 }; size_t i; for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { /* data_vec = xinput[i]; */ xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + 16*i); /* key_vec = xsecret[i]; */ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i); xxh_u64x2 const data_key = data_vec ^ key_vec; /* shuffled = (data_key << 32) | (data_key >> 32); */ xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); /* acc_vec = xacc[i]; */ xxh_u64x2 acc_vec = xacc[i]; acc_vec += product; /* swap high and low halves */ #ifdef __s390x__ acc_vec += vec_permi(data_vec, data_vec, 2); #else acc_vec += vec_xxpermdi(data_vec, data_vec, 2); #endif xacc[i] = acc_vec; } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(vsx) XXH_FORCE_INLINE void XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc; const xxh_u8* const xsecret = (const xxh_u8*) secret; /* constants */ xxh_u64x2 const v32 = { 32, 32 }; xxh_u64x2 const v47 = { 47, 47 }; xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; size_t i; for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { /* xacc[i] ^= (xacc[i] >> 47); */ xxh_u64x2 const acc_vec = xacc[i]; xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); /* xacc[i] ^= xsecret[i]; */ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i); xxh_u64x2 const data_key = data_vec ^ key_vec; /* xacc[i] *= XXH_PRIME32_1 */ /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); xacc[i] = prod_odd + (prod_even << v32); } } } #endif #if (XXH_VECTOR == XXH_SVE) XXH_FORCE_INLINE void XXH3_accumulate_512_sve( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { uint64_t *xacc = (uint64_t *)acc; const uint64_t *xinput = (const uint64_t *)(const void *)input; const uint64_t *xsecret = (const uint64_t *)(const void *)secret; svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1); uint64_t element_count = svcntd(); if (element_count >= 8) { svbool_t mask = svptrue_pat_b64(SV_VL8); svuint64_t vacc = svld1_u64(mask, xacc); ACCRND(vacc, 0); svst1_u64(mask, xacc, vacc); } else if (element_count == 2) { /* sve128 */ svbool_t mask = svptrue_pat_b64(SV_VL2); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 2); svuint64_t acc2 = svld1_u64(mask, xacc + 4); svuint64_t acc3 = svld1_u64(mask, xacc + 6); ACCRND(acc0, 0); ACCRND(acc1, 2); ACCRND(acc2, 4); ACCRND(acc3, 6); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 2, acc1); svst1_u64(mask, xacc + 4, acc2); svst1_u64(mask, xacc + 6, acc3); } else { svbool_t mask = svptrue_pat_b64(SV_VL4); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 4); ACCRND(acc0, 0); ACCRND(acc1, 4); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 4, acc1); } } XXH_FORCE_INLINE void XXH3_accumulate_sve(xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT input, const xxh_u8* XXH_RESTRICT secret, size_t nbStripes) { if (nbStripes != 0) { uint64_t *xacc = (uint64_t *)acc; const uint64_t *xinput = (const uint64_t *)(const void *)input; const uint64_t *xsecret = (const uint64_t *)(const void *)secret; svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1); uint64_t element_count = svcntd(); if (element_count >= 8) { svbool_t mask = svptrue_pat_b64(SV_VL8); svuint64_t vacc = svld1_u64(mask, xacc + 0); do { /* svprfd(svbool_t, void *, enum svfprop); */ svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(vacc, 0); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, vacc); } else if (element_count == 2) { /* sve128 */ svbool_t mask = svptrue_pat_b64(SV_VL2); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 2); svuint64_t acc2 = svld1_u64(mask, xacc + 4); svuint64_t acc3 = svld1_u64(mask, xacc + 6); do { svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(acc0, 0); ACCRND(acc1, 2); ACCRND(acc2, 4); ACCRND(acc3, 6); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 2, acc1); svst1_u64(mask, xacc + 4, acc2); svst1_u64(mask, xacc + 6, acc3); } else { svbool_t mask = svptrue_pat_b64(SV_VL4); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 4); do { svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(acc0, 0); ACCRND(acc1, 4); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 4, acc1); } } } #endif #if (XXH_VECTOR == XXH_LSX) #define _LSX_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) XXH_FORCE_INLINE void XXH3_accumulate_512_lsx( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { __m128i* const xacc = (__m128i *) acc; const __m128i* const xinput = (const __m128i *) input; const __m128i* const xsecret = (const __m128i *) secret; for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) { /* data_vec = xinput[i]; */ __m128i const data_vec = __lsx_vld(xinput + i, 0); /* key_vec = xsecret[i]; */ __m128i const key_vec = __lsx_vld(xsecret + i, 0); /* data_key = data_vec ^ key_vec; */ __m128i const data_key = __lsx_vxor_v(data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m128i const data_key_lo = __lsx_vsrli_d(data_key, 32); // __m128i const data_key_lo = __lsx_vsrli_d(data_key, 32); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m128i const product = __lsx_vmulwev_d_wu(data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m128i const data_swap = __lsx_vshuf4i_w(data_vec, _LSX_SHUFFLE(1, 0, 3, 2)); __m128i const sum = __lsx_vadd_d(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = __lsx_vadd_d(product, sum); } } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(lsx) XXH_FORCE_INLINE void XXH3_scrambleAcc_lsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { __m128i* const xacc = (__m128i*) acc; const __m128i* const xsecret = (const __m128i *) secret; const __m128i prime32 = __lsx_vreplgr2vr_d(XXH_PRIME32_1); for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m128i const acc_vec = xacc[i]; __m128i const shifted = __lsx_vsrli_d(acc_vec, 47); __m128i const data_vec = __lsx_vxor_v(acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ __m128i const key_vec = __lsx_vld(xsecret + i, 0); __m128i const data_key = __lsx_vxor_v(data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ xacc[i] = __lsx_vmul_d(data_key, prime32); } } } #endif #if (XXH_VECTOR == XXH_LASX) #define _LASX_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) XXH_FORCE_INLINE void XXH3_accumulate_512_lasx( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { __m256i* const xacc = (__m256i *) acc; const __m256i* const xinput = (const __m256i *) input; const __m256i* const xsecret = (const __m256i *) secret; for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) { /* data_vec = xinput[i]; */ __m256i const data_vec = __lasx_xvld(xinput + i, 0); /* key_vec = xsecret[i]; */ __m256i const key_vec = __lasx_xvld(xsecret + i, 0); /* data_key = data_vec ^ key_vec; */ __m256i const data_key = __lasx_xvxor_v(data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m256i const data_key_lo = __lasx_xvsrli_d(data_key, 32); // __m256i const data_key_lo = __lasx_xvsrli_d(data_key, 32); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m256i const product = __lasx_xvmulwev_d_wu(data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m256i const data_swap = __lasx_xvshuf4i_w(data_vec, _LASX_SHUFFLE(1, 0, 3, 2)); __m256i const sum = __lasx_xvadd_d(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = __lasx_xvadd_d(product, sum); } } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(lasx) XXH_FORCE_INLINE void XXH3_scrambleAcc_lasx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { __m256i* const xacc = (__m256i*) acc; const __m256i* const xsecret = (const __m256i *) secret; const __m256i prime32 = __lasx_xvreplgr2vr_d(XXH_PRIME32_1); for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m256i const acc_vec = xacc[i]; __m256i const shifted = __lasx_xvsrli_d(acc_vec, 47); __m256i const data_vec = __lasx_xvxor_v(acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ __m256i const key_vec = __lasx_xvld(xsecret + i, 0); __m256i const data_key = __lasx_xvxor_v(data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ xacc[i] = __lasx_xvmul_d(data_key, prime32); } } } #endif /* scalar variants - universal */ #if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) /* * In XXH3_scalarRound(), GCC and Clang have a similar codegen issue, where they * emit an excess mask and a full 64-bit multiply-add (MADD X-form). * * While this might not seem like much, as AArch64 is a 64-bit architecture, only * big Cortex designs have a full 64-bit multiplier. * * On the little cores, the smaller 32-bit multiplier is used, and full 64-bit * multiplies expand to 2-3 multiplies in microcode. This has a major penalty * of up to 4 latency cycles and 2 stall cycles in the multiply pipeline. * * Thankfully, AArch64 still provides the 32-bit long multiply-add (UMADDL) which does * not have this penalty and does the mask automatically. */ XXH_FORCE_INLINE xxh_u64 XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc) { xxh_u64 ret; /* note: %x = 64-bit register, %w = 32-bit register */ __asm__("umaddl %x0, %w1, %w2, %x3" : "=r" (ret) : "r" (lhs), "r" (rhs), "r" (acc)); return ret; } #else XXH_FORCE_INLINE xxh_u64 XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc) { return XXH_mult32to64((xxh_u32)lhs, (xxh_u32)rhs) + acc; } #endif /*! * @internal * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). * * This is extracted to its own function because the NEON path uses a combination * of NEON and scalar. */ XXH_FORCE_INLINE void XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, void const* XXH_RESTRICT secret, size_t lane) { xxh_u64* xacc = (xxh_u64*) acc; xxh_u8 const* xinput = (xxh_u8 const*) input; xxh_u8 const* xsecret = (xxh_u8 const*) secret; XXH_ASSERT(lane < XXH_ACC_NB); XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); { xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ xacc[lane] = XXH_mult32to64_add64(data_key /* & 0xFFFFFFFF */, data_key >> 32, xacc[lane]); } } /*! * @internal * @brief Processes a 64 byte block of data using the scalar path. */ XXH_FORCE_INLINE void XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { size_t i; /* ARM GCC refuses to unroll this loop, resulting in a 24% slowdown on ARMv6. */ #if defined(__GNUC__) && !defined(__clang__) \ && (defined(__arm__) || defined(__thumb2__)) \ && defined(__ARM_FEATURE_UNALIGNED) /* no unaligned access just wastes bytes */ \ && XXH_SIZE_OPT <= 0 # pragma GCC unroll 8 #endif for (i=0; i < XXH_ACC_NB; i++) { XXH3_scalarRound(acc, input, secret, i); } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(scalar) /*! * @internal * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). * * This is extracted to its own function because the NEON path uses a combination * of NEON and scalar. */ XXH_FORCE_INLINE void XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT secret, size_t lane) { xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); XXH_ASSERT(lane < XXH_ACC_NB); { xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); xxh_u64 acc64 = xacc[lane]; acc64 = XXH_xorshift64(acc64, 47); acc64 ^= key64; acc64 *= XXH_PRIME32_1; xacc[lane] = acc64; } } /*! * @internal * @brief Scrambles the accumulators after a large chunk has been read */ XXH_FORCE_INLINE void XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { size_t i; for (i=0; i < XXH_ACC_NB; i++) { XXH3_scalarScrambleRound(acc, secret, i); } } XXH_FORCE_INLINE void XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { /* * We need a separate pointer for the hack below, * which requires a non-const pointer. * Any decent compiler will optimize this out otherwise. */ const xxh_u8* kSecretPtr = XXH3_kSecret; XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); #if defined(__GNUC__) && defined(__aarch64__) /* * UGLY HACK: * GCC and Clang generate a bunch of MOV/MOVK pairs for aarch64, and they are * placed sequentially, in order, at the top of the unrolled loop. * * While MOVK is great for generating constants (2 cycles for a 64-bit * constant compared to 4 cycles for LDR), it fights for bandwidth with * the arithmetic instructions. * * I L S * MOVK * MOVK * MOVK * MOVK * ADD * SUB STR * STR * By forcing loads from memory (as the asm line causes the compiler to assume * that XXH3_kSecretPtr has been changed), the pipelines are used more * efficiently: * I L S * LDR * ADD LDR * SUB STR * STR * * See XXH3_NEON_LANES for details on the pipsline. * * XXH3_64bits_withSeed, len == 256, Snapdragon 835 * without hack: 2654.4 MB/s * with hack: 3202.9 MB/s */ XXH_COMPILER_GUARD(kSecretPtr); #endif { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; int i; for (i=0; i < nbRounds; i++) { /* * The asm hack causes the compiler to assume that kSecretPtr aliases with * customSecret, and on aarch64, this prevented LDP from merging two * loads together for free. Putting the loads together before the stores * properly generates LDP. */ xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); } } } typedef void (*XXH3_f_accumulate)(xxh_u64* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, size_t); typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); #if (XXH_VECTOR == XXH_AVX512) #define XXH3_accumulate_512 XXH3_accumulate_512_avx512 #define XXH3_accumulate XXH3_accumulate_avx512 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 #elif (XXH_VECTOR == XXH_AVX2) #define XXH3_accumulate_512 XXH3_accumulate_512_avx2 #define XXH3_accumulate XXH3_accumulate_avx2 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 #elif (XXH_VECTOR == XXH_SSE2) #define XXH3_accumulate_512 XXH3_accumulate_512_sse2 #define XXH3_accumulate XXH3_accumulate_sse2 #define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 #define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 #elif (XXH_VECTOR == XXH_NEON) #define XXH3_accumulate_512 XXH3_accumulate_512_neon #define XXH3_accumulate XXH3_accumulate_neon #define XXH3_scrambleAcc XXH3_scrambleAcc_neon #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #elif (XXH_VECTOR == XXH_VSX) #define XXH3_accumulate_512 XXH3_accumulate_512_vsx #define XXH3_accumulate XXH3_accumulate_vsx #define XXH3_scrambleAcc XXH3_scrambleAcc_vsx #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #elif (XXH_VECTOR == XXH_SVE) #define XXH3_accumulate_512 XXH3_accumulate_512_sve #define XXH3_accumulate XXH3_accumulate_sve #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #elif (XXH_VECTOR == XXH_LASX) #define XXH3_accumulate_512 XXH3_accumulate_512_lasx #define XXH3_accumulate XXH3_accumulate_lasx #define XXH3_scrambleAcc XXH3_scrambleAcc_lasx #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #elif (XXH_VECTOR == XXH_LSX) #define XXH3_accumulate_512 XXH3_accumulate_512_lsx #define XXH3_accumulate XXH3_accumulate_lsx #define XXH3_scrambleAcc XXH3_scrambleAcc_lsx #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #else /* scalar */ #define XXH3_accumulate_512 XXH3_accumulate_512_scalar #define XXH3_accumulate XXH3_accumulate_scalar #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #endif #if XXH_SIZE_OPT >= 1 /* don't do SIMD for initialization */ # undef XXH3_initCustomSecret # define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #endif XXH_FORCE_INLINE void XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; size_t const nb_blocks = (len - 1) / block_len; size_t n; XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); for (n = 0; n < nb_blocks; n++) { f_acc(acc, input + n*block_len, secret, nbStripesPerBlock); f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); } /* last partial block */ XXH_ASSERT(len > XXH_STRIPE_LEN); { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); f_acc(acc, input + nb_blocks*block_len, secret, nbStripes); /* last stripe */ { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; #define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ XXH3_accumulate_512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); } } } XXH_FORCE_INLINE xxh_u64 XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) { return XXH3_mul128_fold64( acc[0] ^ XXH_readLE64(secret), acc[1] ^ XXH_readLE64(secret+8) ); } static XXH_PUREF XXH64_hash_t XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) { xxh_u64 result64 = start; size_t i = 0; for (i = 0; i < 4; i++) { result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); #if defined(__clang__) /* Clang */ \ && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ /* * UGLY HACK: * Prevent autovectorization on Clang ARMv7-a. Exact same problem as * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. * XXH3_64bits, len == 256, Snapdragon 835: * without hack: 2063.7 MB/s * with hack: 2560.7 MB/s */ XXH_COMPILER_GUARD(result64); #endif } return XXH3_avalanche(result64); } /* do not align on 8, so that the secret is different from the accumulator */ #define XXH_SECRET_MERGEACCS_START 11 static XXH_PUREF XXH64_hash_t XXH3_finalizeLong_64b(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 len) { return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, len * XXH_PRIME64_1); } #define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, const void* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc, f_scramble); /* converge into final hash */ XXH_STATIC_ASSERT(sizeof(acc) == 64); XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); return XXH3_finalizeLong_64b(acc, (const xxh_u8*)secret, (xxh_u64)len); } /* * It's important for performance to transmit secret's size (when it's static) * so that the compiler can properly optimize the vectorized loop. * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE * breaks -Og, this is XXH_NO_INLINE. */ XXH3_WITH_SECRET_INLINE XXH64_hash_t XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc); } /* * It's preferable for performance that XXH3_hashLong is not inlined, * as it results in a smaller function for small data, easier to the instruction cache. * Note that inside this no_inline function, we do inline the internal loop, * and provide a statically defined secret size to allow optimization of vector loop. */ XXH_NO_INLINE XXH_PUREF XXH64_hash_t XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; (void)secret; (void)secretLen; return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc); } /* * XXH3_hashLong_64b_withSeed(): * Generate a custom key based on alteration of default XXH3_kSecret with the seed, * and then use this key for long mode hashing. * * This operation is decently fast but nonetheless costs a little bit of time. * Try to avoid it whenever possible (typically when seed==0). * * It's important for performance that XXH3_hashLong is not inlined. Not sure * why (uop cache maybe?), but the difference is large and easily measurable. */ XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, XXH64_hash_t seed, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble, XXH3_f_initCustomSecret f_initSec) { #if XXH_SIZE_OPT <= 0 if (seed == 0) return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), f_acc, f_scramble); #endif { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; f_initSec(secret, seed); return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), f_acc, f_scramble); } } /* * It's important for performance that XXH3_hashLong is not inlined. */ XXH_NO_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)secret; (void)secretLen; return XXH3_hashLong_64b_withSeed_internal(input, len, seed, XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret); } typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); XXH_FORCE_INLINE XXH64_hash_t XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, XXH3_hashLong64_f f_hashLong) { XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); /* * If an action is to be taken if `secretLen` condition is not respected, * it should be done here. * For now, it's a contract pre-condition. * Adding a check and a branch here would cost performance at every hash. * Also, note that function signature doesn't offer room to return an error. */ if (len <= 16) return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); if (len <= 128) return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); } /* === Public entry point === */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length) { return XXH3_64bits_internal(input, length, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_64bits_internal(input, length, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed) { return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); } XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { if (length <= XXH3_MIDSIZE_MAX) return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); return XXH3_hashLong_64b_withSecret(input, length, seed, (const xxh_u8*)secret, secretSize); } /* === XXH3 streaming === */ #ifndef XXH_NO_STREAM /* * Malloc's a pointer that is always aligned to @align. * * This must be freed with `XXH_alignedFree()`. * * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. * * This underalignment previously caused a rather obvious crash which went * completely unnoticed due to XXH3_createState() not actually being tested. * Credit to RedSpah for noticing this bug. * * The alignment is done manually: Functions like posix_memalign or _mm_malloc * are avoided: To maintain portability, we would have to write a fallback * like this anyways, and besides, testing for the existence of library * functions without relying on external build tools is impossible. * * The method is simple: Overallocate, manually align, and store the offset * to the original behind the returned pointer. * * Align must be a power of 2 and 8 <= align <= 128. */ static XXH_MALLOCF void* XXH_alignedMalloc(size_t s, size_t align) { XXH_ASSERT(align <= 128 && align >= 8); /* range check */ XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ { /* Overallocate to make room for manual realignment and an offset byte */ xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); if (base != NULL) { /* * Get the offset needed to align this pointer. * * Even if the returned pointer is aligned, there will always be * at least one byte to store the offset to the original pointer. */ size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ /* Add the offset for the now-aligned pointer */ xxh_u8* ptr = base + offset; XXH_ASSERT((size_t)ptr % align == 0); /* Store the offset immediately before the returned pointer. */ ptr[-1] = (xxh_u8)offset; return ptr; } return NULL; } } /* * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. */ static void XXH_alignedFree(void* p) { if (p != NULL) { xxh_u8* ptr = (xxh_u8*)p; /* Get the offset byte we added in XXH_malloc. */ xxh_u8 offset = ptr[-1]; /* Free the original malloc'd pointer */ xxh_u8* base = ptr - offset; XXH_free(base); } } /*! @ingroup XXH3_family */ /*! * @brief Allocate an @ref XXH3_state_t. * * @return An allocated pointer of @ref XXH3_state_t on success. * @return `NULL` on failure. * * @note Must be freed with XXH3_freeState(). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) { XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); if (state==NULL) return NULL; XXH3_INITSTATE(state); return state; } /*! @ingroup XXH3_family */ /*! * @brief Frees an @ref XXH3_state_t. * * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState(). * * @return @ref XXH_OK. * * @note Must be allocated with XXH3_createState(). * * @see @ref streaming_example "Streaming Example" */ XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) { XXH_alignedFree(statePtr); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state) { XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); } static void XXH3_reset_internal(XXH3_state_t* statePtr, XXH64_hash_t seed, const void* secret, size_t secretSize) { size_t const initStart = offsetof(XXH3_state_t, bufferedSize); size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); XXH_ASSERT(statePtr != NULL); /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ XXH_memset((char*)statePtr + initStart, 0, initLength); statePtr->acc[0] = XXH_PRIME32_3; statePtr->acc[1] = XXH_PRIME64_1; statePtr->acc[2] = XXH_PRIME64_2; statePtr->acc[3] = XXH_PRIME64_3; statePtr->acc[4] = XXH_PRIME64_4; statePtr->acc[5] = XXH_PRIME32_2; statePtr->acc[6] = XXH_PRIME64_5; statePtr->acc[7] = XXH_PRIME32_1; statePtr->seed = seed; statePtr->useSeed = (seed != 0); statePtr->extSecret = (const unsigned char*)secret; XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr) { if (statePtr == NULL) return XXH_ERROR; XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize) { if (statePtr == NULL) return XXH_ERROR; XXH3_reset_internal(statePtr, 0, secret, secretSize); if (secret == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed) { if (statePtr == NULL) return XXH_ERROR; if (seed==0) return XXH3_64bits_reset(statePtr); if ((seed != statePtr->seed) || (statePtr->extSecret != NULL)) XXH3_initCustomSecret(statePtr->customSecret, seed); XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64) { if (statePtr == NULL) return XXH_ERROR; if (secret == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; XXH3_reset_internal(statePtr, seed64, secret, secretSize); statePtr->useSeed = 1; /* always, even if seed64==0 */ return XXH_OK; } /*! * @internal * @brief Processes a large input for XXH3_update() and XXH3_digest_long(). * * Unlike XXH3_hashLong_internal_loop(), this can process data that overlaps a block. * * @param acc Pointer to the 8 accumulator lanes * @param nbStripesSoFarPtr In/out pointer to the number of leftover stripes in the block* * @param nbStripesPerBlock Number of stripes in a block * @param input Input pointer * @param nbStripes Number of stripes to process * @param secret Secret pointer * @param secretLimit Offset of the last block in @p secret * @param f_acc Pointer to an XXH3_accumulate implementation * @param f_scramble Pointer to an XXH3_scrambleAcc implementation * @return Pointer past the end of @p input after processing */ XXH_FORCE_INLINE const xxh_u8 * XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, const xxh_u8* XXH_RESTRICT input, size_t nbStripes, const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { const xxh_u8* initialSecret = secret + *nbStripesSoFarPtr * XXH_SECRET_CONSUME_RATE; /* Process full blocks */ if (nbStripes >= (nbStripesPerBlock - *nbStripesSoFarPtr)) { /* Process the initial partial block... */ size_t nbStripesThisIter = nbStripesPerBlock - *nbStripesSoFarPtr; do { /* Accumulate and scramble */ f_acc(acc, input, initialSecret, nbStripesThisIter); f_scramble(acc, secret + secretLimit); input += nbStripesThisIter * XXH_STRIPE_LEN; nbStripes -= nbStripesThisIter; /* Then continue the loop with the full block size */ nbStripesThisIter = nbStripesPerBlock; initialSecret = secret; } while (nbStripes >= nbStripesPerBlock); *nbStripesSoFarPtr = 0; } /* Process a partial block */ if (nbStripes > 0) { f_acc(acc, input, initialSecret, nbStripes); input += nbStripes * XXH_STRIPE_LEN; *nbStripesSoFarPtr += nbStripes; } /* Return end pointer */ return input; } #ifndef XXH3_STREAM_USE_STACK # if XXH_SIZE_OPT <= 0 && !defined(__clang__) /* clang doesn't need additional stack space */ # define XXH3_STREAM_USE_STACK 1 # endif #endif /* This function accepts f_acc and f_scramble as function pointers, * making it possible to implement multiple variants with different acc & scramble stages. * This is notably useful to implement multiple vector variants with different intrinsics. */ XXH_FORCE_INLINE XXH_errorcode XXH3_update(XXH3_state_t* XXH_RESTRICT const state, const xxh_u8* XXH_RESTRICT input, size_t len, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } XXH_ASSERT(state != NULL); { const xxh_u8* const bEnd = input + len; const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; #if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 /* For some reason, gcc and MSVC seem to suffer greatly * when operating accumulators directly into state. * Operating into stack space seems to enable proper optimization. * clang, on the other hand, doesn't seem to need this trick */ XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; XXH_memcpy(acc, state->acc, sizeof(acc)); #else xxh_u64* XXH_RESTRICT const acc = state->acc; #endif state->totalLen += len; XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); /* small input : just fill in tmp buffer */ if (len <= XXH3_INTERNALBUFFER_SIZE - state->bufferedSize) { XXH_memcpy(state->buffer + state->bufferedSize, input, len); state->bufferedSize += (XXH32_hash_t)len; return XXH_OK; } /* total input is now > XXH3_INTERNALBUFFER_SIZE */ #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ /* * Internal buffer is partially filled (always, except at beginning) * Complete it, then consume it. */ if (state->bufferedSize) { size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); input += loadSize; XXH3_consumeStripes(acc, &state->nbStripesSoFar, state->nbStripesPerBlock, state->buffer, XXH3_INTERNALBUFFER_STRIPES, secret, state->secretLimit, f_acc, f_scramble); state->bufferedSize = 0; } XXH_ASSERT(input < bEnd); if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; input = XXH3_consumeStripes(acc, &state->nbStripesSoFar, state->nbStripesPerBlock, input, nbStripes, secret, state->secretLimit, f_acc, f_scramble); XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); } /* Some remaining input (always) : buffer it */ XXH_ASSERT(input < bEnd); XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); XXH_ASSERT(state->bufferedSize == 0); XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); state->bufferedSize = (XXH32_hash_t)(bEnd-input); #if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 /* save stack accumulators into state */ XXH_memcpy(state->acc, acc, sizeof(acc)); #endif } return XXH_OK; } /* * Both XXH3_64bits_update and XXH3_128bits_update use this routine. */ XXH_NO_INLINE XXH_errorcode XXH3_update_regular(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) { return XXH3_update(state, (const xxh_u8*)input, len, XXH3_accumulate, XXH3_scrambleAcc); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) { return XXH3_update_regular(state, input, len); } XXH_FORCE_INLINE void XXH3_digest_long (XXH64_hash_t* acc, const XXH3_state_t* state, const unsigned char* secret) { xxh_u8 lastStripe[XXH_STRIPE_LEN]; const xxh_u8* lastStripePtr; /* * Digest on a local copy. This way, the state remains unaltered, and it can * continue ingesting more input afterwards. */ XXH_memcpy(acc, state->acc, sizeof(state->acc)); if (state->bufferedSize >= XXH_STRIPE_LEN) { /* Consume remaining stripes then point to remaining data in buffer */ size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; size_t nbStripesSoFar = state->nbStripesSoFar; XXH3_consumeStripes(acc, &nbStripesSoFar, state->nbStripesPerBlock, state->buffer, nbStripes, secret, state->secretLimit, XXH3_accumulate, XXH3_scrambleAcc); lastStripePtr = state->buffer + state->bufferedSize - XXH_STRIPE_LEN; } else { /* bufferedSize < XXH_STRIPE_LEN */ /* Copy to temp buffer */ size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); lastStripePtr = lastStripe; } /* Last stripe */ XXH3_accumulate_512(acc, lastStripePtr, secret + state->secretLimit - XXH_SECRET_LASTACC_START); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* state) { const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; if (state->totalLen > XXH3_MIDSIZE_MAX) { XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; XXH3_digest_long(acc, state, secret); return XXH3_finalizeLong_64b(acc, secret, (xxh_u64)state->totalLen); } /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ if (state->useSeed) return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), secret, state->secretLimit + XXH_STRIPE_LEN); } #endif /* !XXH_NO_STREAM */ /* ========================================== * XXH3 128 bits (a.k.a XXH128) * ========================================== * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, * even without counting the significantly larger output size. * * For example, extra steps are taken to avoid the seed-dependent collisions * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). * * This strength naturally comes at the cost of some speed, especially on short * lengths. Note that longer hashes are about as fast as the 64-bit version * due to it using only a slight modification of the 64-bit loop. * * XXH128 is also more oriented towards 64-bit machines. It is still extremely * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). */ XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { /* A doubled version of 1to3_64b with different constants. */ XXH_ASSERT(input != NULL); XXH_ASSERT(1 <= len && len <= 3); XXH_ASSERT(secret != NULL); /* * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } */ { xxh_u8 const c1 = input[0]; xxh_u8 const c2 = input[len >> 1]; xxh_u8 const c3 = input[len - 1]; xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; XXH128_hash_t h128; h128.low64 = XXH64_avalanche(keyed_lo); h128.high64 = XXH64_avalanche(keyed_hi); return h128; } } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(4 <= len && len <= 8); seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; { xxh_u32 const input_lo = XXH_readLE32(input); xxh_u32 const input_hi = XXH_readLE32(input + len - 4); xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; xxh_u64 const keyed = input_64 ^ bitflip; /* Shift len to the left to ensure it is even, this avoids even multiplies. */ XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); m128.high64 += (m128.low64 << 1); m128.low64 ^= (m128.high64 >> 3); m128.low64 = XXH_xorshift64(m128.low64, 35); m128.low64 *= PRIME_MX2; m128.low64 = XXH_xorshift64(m128.low64, 28); m128.high64 = XXH3_avalanche(m128.high64); return m128; } } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(9 <= len && len <= 16); { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; xxh_u64 const input_lo = XXH_readLE64(input); xxh_u64 input_hi = XXH_readLE64(input + len - 8); XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); /* * Put len in the middle of m128 to ensure that the length gets mixed to * both the low and high bits in the 128x64 multiply below. */ m128.low64 += (xxh_u64)(len - 1) << 54; input_hi ^= bitfliph; /* * Add the high 32 bits of input_hi to the high 32 bits of m128, then * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to * the high 64 bits of m128. * * The best approach to this operation is different on 32-bit and 64-bit. */ if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ /* * 32-bit optimized version, which is more readable. * * On 32-bit, it removes an ADC and delays a dependency between the two * halves of m128.high64, but it generates an extra mask on 64-bit. */ m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); } else { /* * 64-bit optimized (albeit more confusing) version. * * Uses some properties of addition and multiplication to remove the mask: * * Let: * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) * c = XXH_PRIME32_2 * * a + (b * c) * Inverse Property: x + y - x == y * a + (b * (1 + c - 1)) * Distributive Property: x * (y + z) == (x * y) + (x * z) * a + (b * 1) + (b * (c - 1)) * Identity Property: x * 1 == x * a + b + (b * (c - 1)) * * Substitute a, b, and c: * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) * * Since input_hi.hi + input_hi.lo == input_hi, we get this: * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) */ m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); } /* m128 ^= XXH_swap64(m128 >> 64); */ m128.low64 ^= XXH_swap64(m128.high64); { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); h128.high64 += m128.high64 * XXH_PRIME64_2; h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = XXH3_avalanche(h128.high64); return h128; } } } /* * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN */ XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(len <= 16); { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); if (len) return XXH3_len_1to3_128b(input, len, secret, seed); { XXH128_hash_t h128; xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); h128.low64 = XXH64_avalanche(seed ^ bitflipl); h128.high64 = XXH64_avalanche( seed ^ bitfliph); return h128; } } } /* * A bit slower than XXH3_mix16B, but handles multiply by zero better. */ XXH_FORCE_INLINE XXH128_hash_t XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, const xxh_u8* secret, XXH64_hash_t seed) { acc.low64 += XXH3_mix16B (input_1, secret+0, seed); acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); acc.high64 += XXH3_mix16B (input_2, secret+16, seed); acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); return acc; } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(16 < len && len <= 128); { XXH128_hash_t acc; acc.low64 = len * XXH_PRIME64_1; acc.high64 = 0; #if XXH_SIZE_OPT >= 1 { /* Smaller, but slightly slower. */ unsigned int i = (unsigned int)(len - 1) / 32; do { acc = XXH128_mix32B(acc, input+16*i, input+len-16*(i+1), secret+32*i, seed); } while (i-- != 0); } #else if (len > 32) { if (len > 64) { if (len > 96) { acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); } acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); } acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); } acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); #endif { XXH128_hash_t h128; h128.low64 = acc.low64 + acc.high64; h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) + ((len - seed) * XXH_PRIME64_2); h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); return h128; } } } XXH_NO_INLINE XXH_PUREF XXH128_hash_t XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); { XXH128_hash_t acc; unsigned i; acc.low64 = len * XXH_PRIME64_1; acc.high64 = 0; /* * We set as `i` as offset + 32. We do this so that unchanged * `len` can be used as upper bound. This reaches a sweet spot * where both x86 and aarch64 get simple agen and good codegen * for the loop. */ for (i = 32; i < 160; i += 32) { acc = XXH128_mix32B(acc, input + i - 32, input + i - 16, secret + i - 32, seed); } acc.low64 = XXH3_avalanche(acc.low64); acc.high64 = XXH3_avalanche(acc.high64); /* * NB: `i <= len` will duplicate the last 32-bytes if * len % 32 was zero. This is an unfortunate necessity to keep * the hash result stable. */ for (i=160; i <= len; i += 32) { acc = XXH128_mix32B(acc, input + i - 32, input + i - 16, secret + XXH3_MIDSIZE_STARTOFFSET + i - 160, seed); } /* last bytes */ acc = XXH128_mix32B(acc, input + len - 16, input + len - 32, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, (XXH64_hash_t)0 - seed); { XXH128_hash_t h128; h128.low64 = acc.low64 + acc.high64; h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) + ((len - seed) * XXH_PRIME64_2); h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); return h128; } } } static XXH_PUREF XXH128_hash_t XXH3_finalizeLong_128b(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, xxh_u64 len) { XXH128_hash_t h128; h128.low64 = XXH3_finalizeLong_64b(acc, secret, len); h128.high64 = XXH3_mergeAccs(acc, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_MERGEACCS_START, ~(len * XXH_PRIME64_2)); return h128; } XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc, f_scramble); /* converge into final hash */ XXH_STATIC_ASSERT(sizeof(acc) == 64); XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); return XXH3_finalizeLong_128b(acc, secret, secretSize, (xxh_u64)len); } /* * It's important for performance that XXH3_hashLong() is not inlined. */ XXH_NO_INLINE XXH_PUREF XXH128_hash_t XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; (void)secret; (void)secretLen; return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc); } /* * It's important for performance to pass @p secretLen (when it's static) * to the compiler, so that it can properly optimize the vectorized loop. * * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE * breaks -Og, this is XXH_NO_INLINE. */ XXH3_WITH_SECRET_INLINE XXH128_hash_t XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc); } XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble, XXH3_f_initCustomSecret f_initSec) { if (seed64 == 0) return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), f_acc, f_scramble); { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; f_initSec(secret, seed64); return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), f_acc, f_scramble); } } /* * It's important for performance that XXH3_hashLong is not inlined. */ XXH_NO_INLINE XXH128_hash_t XXH3_hashLong_128b_withSeed(const void* input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)secret; (void)secretLen; return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret); } typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, XXH64_hash_t, const void* XXH_RESTRICT, size_t); XXH_FORCE_INLINE XXH128_hash_t XXH3_128bits_internal(const void* input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, XXH3_hashLong128_f f_hl128) { XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); /* * If an action is to be taken if `secret` conditions are not respected, * it should be done here. * For now, it's a contract pre-condition. * Adding a check and a branch here would cost performance at every hash. */ if (len <= 16) return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); if (len <= 128) return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); return f_hl128(input, len, seed64, secret, secretLen); } /* === Public XXH128 API === */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* input, size_t len) { return XXH3_128bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_default); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_128bits_internal(input, len, 0, (const xxh_u8*)secret, secretSize, XXH3_hashLong_128b_withSecret); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) { return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_withSeed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { if (len <= XXH3_MIDSIZE_MAX) return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH128(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) { return XXH3_128bits_withSeed(input, len, seed); } /* === XXH3 128-bit streaming === */ #ifndef XXH_NO_STREAM /* * All initialization and update functions are identical to 64-bit streaming variant. * The only difference is the finalization routine. */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr) { return XXH3_64bits_reset(statePtr); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed) { return XXH3_64bits_reset_withSeed(statePtr, seed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) { return XXH3_update_regular(state, input, len); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* state) { const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; if (state->totalLen > XXH3_MIDSIZE_MAX) { XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; XXH3_digest_long(acc, state, secret); XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); return XXH3_finalizeLong_128b(acc, secret, state->secretLimit + XXH_STRIPE_LEN, (xxh_u64)state->totalLen); } /* len <= XXH3_MIDSIZE_MAX : short code */ if (state->useSeed) return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), secret, state->secretLimit + XXH_STRIPE_LEN); } #endif /* !XXH_NO_STREAM */ /* 128-bit utility functions */ /* return : 1 is equal, 0 if different */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) { /* note : XXH128_hash_t is compact, it has no padding byte */ return !(XXH_memcmp(&h1, &h2, sizeof(h1))); } /* This prototype is compatible with stdlib's qsort(). * @return : >0 if *h128_1 > *h128_2 * <0 if *h128_1 < *h128_2 * =0 if *h128_1 == *h128_2 */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2) { XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); /* note : bets that, in most cases, hash values are different */ if (hcmp) return hcmp; return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); } /*====== Canonical representation ======*/ /*! @ingroup XXH3_family */ XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) { hash.high64 = XXH_swap64(hash.high64); hash.low64 = XXH_swap64(hash.low64); } XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src) { XXH128_hash_t h; h.high64 = XXH_readBE64(src); h.low64 = XXH_readBE64(src->digest + 8); return h; } /* ========================================== * Secret generators * ========================================== */ #define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) { XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize) { #if (XXH_DEBUGLEVEL >= 1) XXH_ASSERT(secretBuffer != NULL); XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); #else /* production mode, assert() are disabled */ if (secretBuffer == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; #endif if (customSeedSize == 0) { customSeed = XXH3_kSecret; customSeedSize = XXH_SECRET_DEFAULT_SIZE; } #if (XXH_DEBUGLEVEL >= 1) XXH_ASSERT(customSeed != NULL); #else if (customSeed == NULL) return XXH_ERROR; #endif /* Fill secretBuffer with a copy of customSeed - repeat as needed */ { size_t pos = 0; while (pos < secretSize) { size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); XXH_memcpy((char*)secretBuffer + pos, customSeed, toCopy); pos += toCopy; } } { size_t const nbSeg16 = secretSize / 16; size_t n; XXH128_canonical_t scrambler; XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); for (n=0; n/dev/null) option "curses" if test_nz "${ncurses_ldflags}"; then add_cflags `pkg-config --cflags ${ncurses} 2>/dev/null` add_ldflags "${ncurses_ldflags}" else add_links "curses" fi option_end } # the atomic option # @note some systems need link atomic, e.g. raspberrypi option "atomic" add_links "atomic" add_csnippets " void test() {\n int v;\n __atomic_load(&v,&v,0);\n }" option_end # the lua option option "lua" add_cfuncs "lua_pushstring" add_cincludes "lua.h" "lualib.h" "lauxlib.h" add_defines "LUA_COMPAT_5_1" "LUA_COMPAT_5_2" "LUA_COMPAT_5_3" before_check "option_find_lua" option_end option_find_lua() { local ldflags="" local cflags="" option "lua" # detect lua5.4 on debian cflags=`pkg-config --cflags lua5.4 2>/dev/null` ldflags=`pkg-config --libs lua5.4 2>/dev/null` # detect it on fedora if test_z "${cflags}"; then cflags=`pkg-config --cflags lua 2>/dev/null` fi if test_z "${ldflags}"; then ldflags=`pkg-config --libs lua 2>/dev/null` fi if test_z "${cflags}"; then cflags="-I/usr/include/lua5.4" fi if test_z "${ldflags}"; then ldflags="-llua5.4" fi add_cflags "${cflags}" add_ldflags "${ldflags}" option_end } # the luajit option option "luajit" add_cfuncs "lua_pushstring" add_cincludes "lua.h" "lualib.h" "lauxlib.h" add_defines "USE_LUAJIT" before_check "option_find_luajit" option_end option_find_luajit() { local ldflags="" local cflags="" option "luajit" cflags=`pkg-config --cflags luajit 2>/dev/null` ldflags=`pkg-config --libs luajit 2>/dev/null` if test_z "${cflags}"; then cflags="-I/usr/include/luajit-2.1" fi if test_z "${ldflags}"; then ldflags="-lluajit" fi add_cflags "${cflags}" add_ldflags "${ldflags}" option_end } # the lz4 option option "lz4" add_cfuncs "LZ4F_compressFrame" add_cincludes "lz4.h" "lz4frame.h" before_check "option_find_lz4" option_end option_find_lz4() { local ldflags="" local cflags="" option "lz4" cflags=`pkg-config --cflags liblz4 2>/dev/null` ldflags=`pkg-config --libs liblz4 2>/dev/null` if test_z "${cflags}"; then cflags="-I/usr/include" fi if test_z "${ldflags}"; then ldflags="-llz4" fi add_cflags "${cflags}" add_ldflags "${ldflags}" option_end } # the sv option option "sv" add_cfuncs "semver_tryn" add_cincludes "semver.h" add_links "sv" before_check "option_find_sv" option_end option_find_sv() { local ldflags="" local cflags="" option "sv" cflags=`pkg-config --cflags libsv 2>/dev/null` ldflags=`pkg-config --libs libsv 2>/dev/null` if test_z "${cflags}"; then cflags="-I/usr/include" fi if test_z "${ldflags}"; then ldflags="-lsv" fi add_cflags "${cflags}" add_ldflags "${ldflags}" option_end } # the tbox option option "tbox" add_cfuncs "tb_exit" "tb_md5_init" "tb_charset_conv_data" add_cincludes "tbox/tbox.h" add_links "tbox" before_check "option_find_tbox" option_end option_find_tbox() { local ldflags="" local cflags="" option "tbox" cflags=`pkg-config --cflags libtbox 2>/dev/null` ldflags=`pkg-config --libs libtbox 2>/dev/null` if test_z "${cflags}"; then cflags="-I/usr/include" fi if test_z "${ldflags}"; then ldflags="-ltbox" fi add_cflags "${cflags}" add_ldflags "${ldflags}" # ubuntu armv7/armel maybe need it if is_plat "linux" && is_arch "armv7" "arm"; then add_ldflags "-latomic" fi option_end } # add projects if ! has_config "external"; then if is_config "runtime" "luajit"; then includes "src/luajit" else includes "src/lua" fi includes "src/lua-cjson" includes "src/lz4" includes "src/sv" includes "src/tbox" fi includes "src/xmake" includes "src/cli" ================================================ FILE: core/xpack.lua ================================================ xpack("xmake") set_homepage("https://xmake.io") set_title("Xmake build utility ($(arch))") set_description("A cross-platform build utility based on Lua.") set_copyright("Copyright (C) 2015-present, Xmake Open Source Community") set_author("ruki ") set_licensefile("../LICENSE.md") set_formats("nsis", "wix", "zip") add_targets("cli") set_bindir(".") set_iconfile("src/cli/xmake.ico") add_components("LongPath") on_load(function (package) local arch = package:arch() if package:is_plat("windows") then if arch == "x64" then arch = "win64" elseif arch == "x86" then arch = "win32" end end package:set("basename", "xmake-v$(version)." .. arch) local format = package:format() if format == "zip" then package:set("prefixdir", "xmake") end end) before_package(function (package) import("net.http") import("utils.archive") import("core.base.global") local format = package:format() if package:is_plat("windows") and (format == "nsis" or format == "wix" or format == "zip") then local winenv = path.join(os.programdir(), "winenv") if false then -- os.isdir(winenv) then package:add("installfiles", path.join(winenv, "**"), {rootdir = path.directory(winenv)}) else local arch = package:arch() local url_7z = "https://github.com/xmake-mirror/7zip/releases/download/24.08/7z24.08-" .. arch .. ".zip" local curl_version = "8.11.0_4" local url_curl = "https://curl.se/windows/dl-" .. curl_version .. "/curl-" .. curl_version if package:is_arch("x64", "x86_64") then url_curl = url_curl .. "-win64-mingw.zip" elseif package:is_arch("arm64") then url_curl = url_curl .. "-win64a-mingw.zip" else url_curl = url_curl .. "-win32-mingw.zip" end local archive_7z = path.join(package:builddir(), "7z.zip") local archive_curl = path.join(package:builddir(), "curl.zip") local tmpdir_7z = path.join(package:builddir(), "7z") local tmpdir_curl = path.join(package:builddir(), "curl") local winenv_bindir = path.join(package:builddir(), "winenv", "bin") os.mkdir(winenv_bindir) http.download(url_7z, archive_7z, {insecure = global.get("insecure-ssl")}) archive.extract(archive_7z, tmpdir_7z) os.cp(path.join(tmpdir_7z, "*"), winenv_bindir) http.download(url_curl, archive_curl, {insecure = global.get("insecure-ssl")}) archive.extract(archive_curl, tmpdir_curl) os.cp(path.join(tmpdir_curl, "*", "bin", "*.exe"), winenv_bindir) os.cp(path.join(tmpdir_curl, "*", "bin", "*.crt"), winenv_bindir) winenv = path.directory(winenv_bindir) package:add("installfiles", path.join(winenv, "**"), {rootdir = path.directory(winenv)}) end end end) xpack_component("LongPath") set_title("Enable Long Path") set_description("Increases the maximum path length limit, up to 32,767 characters (before 256).") on_installcmd(function (component, batchcmds) batchcmds:rawcmd("nsis", [[ ${If} $NoAdmin == "false" ; Enable long path WriteRegDWORD ${HKLM} "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1 ${EndIf}]]) batchcmds:rawcmd("wix", [[ ]]) end) xpack("xmakesrc") set_homepage("https://xmake.io") set_title("Xmake build utility ($(arch))") set_description("A cross-platform build utility based on Lua.") set_copyright("Copyright (C) 2015-present, Xmake Open Source Community") set_author("ruki ") set_formats("srczip", "srctargz", "runself", "srpm", "deb") set_basename("xmake-v$(version)") set_prefixdir("xmake-$(version)") set_license("Apache-2.0") before_package(function (package) import("devel.git") local rootdir = path.join(os.tmpfile(package:basename() .. "_" .. package:format()) .. ".dir", "repo") if not os.isdir(rootdir) then os.tryrm(rootdir) os.cp(path.directory(os.projectdir()), rootdir) git.clean({repodir = rootdir, force = true, all = true}) git.reset({repodir = rootdir, hard = true}) if os.isfile(path.join(rootdir, ".gitmodules")) then git.submodule.clean({repodir = rootdir, force = true, all = true}) git.submodule.reset({repodir = rootdir, hard = true}) end end local extraconf = {rootdir = rootdir} package:add("sourcefiles", path.join(rootdir, "core/**|src/pdcurses/**|src/luajit/**|src/tbox/tbox/src/demo/**"), extraconf) package:add("sourcefiles", path.join(rootdir, "xmake/**|scripts/vsxmake/**"), extraconf) package:add("sourcefiles", path.join(rootdir, "*.md"), extraconf) package:add("sourcefiles", path.join(rootdir, "configure"), extraconf) package:add("sourcefiles", path.join(rootdir, "scripts/*.sh"), extraconf) package:add("sourcefiles", path.join(rootdir, "scripts/man/**"), extraconf) package:add("sourcefiles", path.join(rootdir, "scripts/debian/**"), extraconf) package:add("sourcefiles", path.join(rootdir, "scripts/msys/**"), extraconf) end) on_buildcmd(function (package, batchcmds) local format = package:format() if format == "srpm" or format == "deb" then batchcmds:runv("./configure") batchcmds:runv("make", {"-j4"}) end end) on_installcmd(function (package, batchcmds) local format = package:format() if format == "runself" then batchcmds:runv("./scripts/get.sh", {"__local__"}) elseif format == "srpm" or format == "deb" then batchcmds:runv("make", {"install", path(package:install_rootdir(), function (p) return "PREFIX=" .. p end)}) end end) ================================================ FILE: scripts/debian/README.Debian ================================================ xmake for Debian --------------- -- ruki Thu, 06 Apr 2017 21:22:12 +0800 ================================================ FILE: scripts/debian/README.source ================================================ xmake for Debian --------------- -- ruki Thu, 06 Apr 2017 21:22:12 +0800 ================================================ FILE: scripts/debian/changelog ================================================ xmake (2.3.6+2) xenial; urgency=medium * update 2.3.6 -- ruki Thu, 05 Aug 2020 21:22:12 +0800 ================================================ FILE: scripts/debian/compat ================================================ 9 ================================================ FILE: scripts/debian/control ================================================ Source: xmake Section: contrib/devel Priority: optional Maintainer: ruki Build-Depends: debhelper (>=9) Standards-Version: 3.9.7 Homepage: http://xmake.io #Vcs-Git: git@github.com:xmake-io/xmake.git #Vcs-Browser: https://github.com/xmake-io/xmake.git Package: xmake Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: A cross-platform build utility based on Lua xmake is a lightweight cross-platform build utility based on Lua. It uses xmake.lua to maintain project builds. Compared with makefile/CMakeLists.txt, the configuration syntax is more concise and intuitive. It is very friendly to novices and can quickly get started in a short time. Let users focus more on actual project development. ================================================ FILE: scripts/debian/copyright ================================================ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: xmake Source: https://github.com/xmake-io/xmake Files: * Copyright: 2015-present ruki License: Apache-2.0 . # Please also look if there are files or directories which have a # different copyright/license attached and list them here. # Please avoid picking licenses with terms that are more restrictive than the # packaged work, as it may make Debian's contributions unacceptable upstream. ================================================ FILE: scripts/debian/init.d.ex ================================================ #!/bin/sh # kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing. if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script fi ### BEGIN INIT INFO # Provides: xmake # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: # Description: # <...> # <...> ### END INIT INFO # Author: ruki DESC="xmake" DAEMON=/usr/bin/xmake # This is an example to start a single forking daemon capable of writing # a pid file. To get other behaviors, implement do_start(), do_stop() or # other functions to override the defaults in /lib/init/init-d-script. # See also init-d-script(5) ================================================ FILE: scripts/debian/manpage.1.ex ================================================ .\" Hey, EMACS: -*- nroff -*- .\" (C) Copyright 2017 ruki , .\" .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH Xmake SECTION "April 6 2017" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME xmake \- program to do something .SH SYNOPSIS .B xmake .RI [ options ] " files" ... .br .B bar .RI [ options ] " files" ... .SH DESCRIPTION This manual page documents briefly the .B xmake and .B bar commands. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBxmake\fP is a program that... .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. .TP .B \-h, \-\-help Show summary of options. .TP .B \-v, \-\-version Show version of program. .SH SEE ALSO .BR bar (1), .BR baz (1). .br The programs are documented fully by .IR "The Rise and Fall of a Fooish Bar" , available via the Info system. ================================================ FILE: scripts/debian/manpage.sgml.ex ================================================ manpage.1'. You may view the manual page with: `docbook-to-man manpage.sgml | nroff -man | less'. A typical entry in a Makefile or Makefile.am is: manpage.1: manpage.sgml docbook-to-man $< > $@ The docbook-to-man binary is found in the docbook-to-man package. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include docbook-to-man in your Build-Depends control field. --> FIRSTNAME"> SURNAME"> April 6 2017"> SECTION"> waruqi@gmail.com"> Xmake"> Debian"> GNU"> GPL"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2003 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; program to do something &dhpackage; DESCRIPTION This manual page documents briefly the &dhpackage; and bar commands. This manual page was written for the &debian; distribution because the original program does not have a manual page. Instead, it has documentation in the &gnu; Info format; see below. &dhpackage; is a program that... OPTIONS These programs follow the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. Show summary of options. Show version of program. SEE ALSO bar (1), baz (1). The programs are documented fully by The Rise and Fall of a Fooish Bar available via the Info system. AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
================================================ FILE: scripts/debian/manpage.xml.ex ================================================ .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname; Wrote this manpage for the Debian system.
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; program to do something &dhpackage; this this that &dhpackage; DESCRIPTION This manual page documents briefly the &dhpackage; and bar commands. This manual page was written for the Debian distribution because the original program does not have a manual page. Instead, it has documentation in the GNU info 1 format; see below. &dhpackage; is a program that... OPTIONS The program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the info 1 files. Does this and that. Show summary of options. Show version of program. FILES /etc/foo.conf The system-wide configuration file to control the behaviour of &dhpackage;. See foo.conf 5 for further details. ${HOME}/.foo.conf The per-user configuration file to control the behaviour of &dhpackage;. See foo.conf 5 for further details. ENVIRONMENT FOO_CONF If used, the defined file is used as configuration file (see also ). DIAGNOSTICS The following diagnostics may be issued on stderr: Bad configuration file. Exiting. The configuration file seems to contain a broken configuration line. Use the option, to get more info. &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 Program exited successfully. 1 The configuration file seems to be broken. BUGS The program is currently limited to only work with the foobar library. The upstreams BTS can be found at . SEE ALSO bar 1 , baz 1 , foo.conf 5 The programs are documented fully by The Rise and Fall of a Fooish Bar available via the info 1 system.
================================================ FILE: scripts/debian/menu.ex ================================================ ?package(xmake):needs="X11|text|vc|wm" section="Applications/see-menu-manual"\ title="xmake" command="/usr/bin/xmake" ================================================ FILE: scripts/debian/postinst.ex ================================================ #!/bin/sh # postinst script for xmake # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-remove' # * `abort-deconfigure' `in-favour' # `removing' # # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in configure) ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 ================================================ FILE: scripts/debian/postrm.ex ================================================ #!/bin/sh # postrm script for xmake # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' # # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 ================================================ FILE: scripts/debian/preinst.ex ================================================ #!/bin/sh # preinst script for xmake # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `install' # * `install' # * `upgrade' # * `abort-upgrade' # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in install|upgrade) ;; abort-upgrade) ;; *) echo "preinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 ================================================ FILE: scripts/debian/prerm.ex ================================================ #!/bin/sh # prerm script for xmake # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `upgrade' # * `failed-upgrade' # * `remove' `in-favour' # * `deconfigure' `in-favour' # `removing' # # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in remove|upgrade|deconfigure) ;; failed-upgrade) ;; *) echo "prerm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 ================================================ FILE: scripts/debian/rules ================================================ #!/usr/bin/make -f # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # prefix prefix=$(CURDIR)/debian/xmake/usr configure: configure-stamp configure-stamp: dh_testdir touch configure-stamp build: build-stamp build-stamp: configure-stamp dh_testdir ./configure make touch $@ clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs mkdir -p $(prefix)/bin mkdir -p $(prefix)/share cp -r $(CURDIR)/xmake $(prefix)/share cp -p $(CURDIR)/build/xmake $(prefix)/bin/xmake chmod 755 $(prefix)/bin/xmake cp -p $(CURDIR)/scripts/xrepo.sh $(prefix)/bin/xrepo chmod 755 $(prefix)/bin/xrepo distclean: clean uninstall: if [ -f /usr/bin/xmake ]; then rm /usr/bin/xmake; fi if [ -f /usr/bin/xrepo ]; then rm /usr/bin/xrepo; fi if [ -d /usr/share/xmake ]; then rm -rf /usr/share/xmake; fi binary-indep: build install # We have nothing to do by default. # # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot dh_installchangelogs $(CURDIR)/CHANGELOG.md dh_installdocs dh_installexamples dh_installman dh_link dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install uninstall configure ================================================ FILE: scripts/debian/source/format ================================================ 3.0 (quilt) ================================================ FILE: scripts/debian/watch.ex ================================================ # Example watch control file for uscan # Rename this file to "watch" and then you can run the "uscan" command # to check for upstream updates and more. # See uscan(1) for format # Compulsory line, this is a version 4 file version=4 # PGP signature mangle, so foo.tar.gz has foo.tar.gz.sig #opts="pgpsigurlmangle=s%$%.sig%" # HTTP site (basic) #http://example.com/downloads.html \ # files/xmake-([\d\.]+)\.tar\.gz debian uupdate # Uncommment to examine a FTP server #ftp://ftp.example.com/pub/xmake-(.*)\.tar\.gz debian uupdate # SourceForge hosted projects # http://sf.net/xmake/ xmake-(.*)\.tar\.gz debian uupdate # GitHub hosted projects #opts="filenamemangle="s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%-$1.tar.gz%" \ # https://github.com//xmake/tags \ # (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate # PyPI # https://pypi.python.org/packages/source//xmake/ \ # xmake-(.+)\.tar\.gz debian uupdate # Direct Git # opts="mode=git" http://git.example.com/xmake.git \ # refs/tags/v([\d\.]+) debian uupdate # Uncomment to find new files on GooglePages # http://example.googlepages.com/foo.html xmake-(.*)\.tar\.gz ================================================ FILE: scripts/debian/xmake-docs.docs ================================================ README.source README.Debian ================================================ FILE: scripts/debian/xmake.cron.d.ex ================================================ # # Regular cron jobs for the xmake package # 0 4 * * * root [ -x /usr/bin/xmake_maintenance ] && /usr/bin/xmake_maintenance ================================================ FILE: scripts/debian/xmake.default.ex ================================================ # Defaults for xmake initscript # sourced by /etc/init.d/xmake # installed at /etc/default/xmake by the maintainer scripts # # This is a POSIX shell fragment # # Additional options that are passed to the Daemon. DAEMON_OPTS="" ================================================ FILE: scripts/debian/xmake.doc-base.EX ================================================ Document: xmake Title: Debian xmake Manual Author: Abstract: This manual describes what xmake is and how it can be used to manage online manuals on Debian systems. Section: unknown Format: debiandoc-sgml Files: /usr/share/doc/xmake/xmake.sgml.gz Format: postscript Files: /usr/share/doc/xmake/xmake.ps.gz Format: text Files: /usr/share/doc/xmake/xmake.text.gz Format: HTML Index: /usr/share/doc/xmake/html/index.html Files: /usr/share/doc/xmake/html/*.html ================================================ FILE: scripts/get.ps1 ================================================ #!/usr/bin/env pwsh #Requires -version 5 # xmake getter # usage: (in powershell) # Invoke-Expression (Invoke-Webrequest -UseBasicParsing).Content param ( [string]$version = "master", [string]$installdir = "" ) & { $LastRelease = "v3.0.7" $ErrorActionPreference = 'Stop' function writeErrorTip($msg) { Write-Host $msg -BackgroundColor Red -ForegroundColor White } if (-not $env:CI) { $logo = @( ' _ ' ' __ ___ __ __ __ _| | ______ ' ' \ \/ / | \/ |/ _ | |/ / __ \ ' ' > < | \__/ | /_| | < ___/ ' ' /_/\_\_|_| |_|\__ \|_|\_\____| getter ' ' ' ' ') Write-Host $([string]::Join("`n", $logo)) -ForegroundColor Green } if ($IsLinux -or $IsMacOS) { writeErrorTip 'Install on *nix is not supported, try ' writeErrorTip '(Use curl) "curl -fsSL https://xmake.io/shget.text | bash"' writeErrorTip 'or' writeErrorTip '(Use wget) "wget https://xmake.io/shget.text -O - | bash"' throw 'Unsupported platform' } $temppath = ([System.IO.Path]::GetTempPath(), $env:TMP, $env:TEMP, "$(Get-Location)" -ne $null)[0] [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" if ($null -eq $installdir -or $installdir -match '^\s*$') { $installdir = & { # Install to old xmake path $oldXmake = Get-Command xmake -CommandType Application -ErrorAction SilentlyContinue if ($oldXmake) { return Split-Path $oldXmake.Path -Parent } if ($HOME) { return Join-Path $HOME 'xmake' } if ($env:APPDATA) { return Join-Path $env:APPDATA 'xmake' } if ($env:ProgramFiles) { return Join-Path $env:ProgramFiles 'xmake' } return 'C:\xmake' } } $installdir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($installdir) if ($null -eq $version -or $version -match '^\s*$') { $v = 'master' } else { $v = $version.Trim() if ($v.Contains('.')) { $v = [version]::Parse($version) $v = New-Object -TypeName version -ArgumentList $v.Major, $v.Minor, $v.Build } } function checkTempAccess { $outfile = Join-Path $temppath "$pid.tmp" try { Write-Output $pid | Out-File -FilePath $outfile Remove-Item $outfile } catch { writeErrorTip 'Cannot write to temp path' writeErrorTip 'Please set environment var "TMP" to another path' throw } } function xmakeInstall { $outfile = Join-Path $temppath "$pid-xmake-installer.exe" $x64arch = @('AMD64', 'IA64') $arch = if ($env:PROCESSOR_ARCHITECTURE -in $x64arch -or $env:PROCESSOR_ARCHITEW6432 -in $x64arch) { 'x64' } else { 'x86' } $winarch = if ($env:PROCESSOR_ARCHITECTURE -in $x64arch -or $env:PROCESSOR_ARCHITEW6432 -in $x64arch) { 'win64' } else { 'win32' } if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { Write-Host "Unsupported host architecture detected: ARM64." } $url = if ($v -is [version]) { "https://github.com/xmake-io/xmake/releases/download/v$v/xmake-v$v.$winarch.exe" } else { "https://github.com/xmake-io/xmake/releases/download/$LastRelease/xmake-$v.$winarch.exe" } Write-Host "Start downloading $url .." try { Invoke-Webrequest $url -OutFile $outfile -UseBasicParsing } catch { writeErrorTip 'Download failed!' writeErrorTip 'Check your network or... the news of S3 break' throw } Write-Host 'Start installation... Hope your antivirus doesn''t trouble' Write-Host "Install to $installdir" try { $adminflag = "/NOADMIN " try { $tempfolder = New-Item "$installdir-$PID-temp" -ItemType Directory Remove-Item $tempfolder.FullName } catch { $adminflag = "" } Start-Process -FilePath $outfile -ArgumentList "$adminflag/S /D=$installdir" -Wait } catch { writeErrorTip 'Install failed!' writeErrorTip 'Close your antivirus then try again' throw } finally { Remove-Item $outfile -ErrorAction SilentlyContinue } Write-Host 'Adding to PATH... almost done' $env:Path += ";$installdir" try { xmake --version } catch { writeErrorTip 'Everything is showing installation has finished' writeErrorTip 'But xmake could not run... Why?' throw } } function registerTabCompletion { # TODO: add --global --user choice Write-Host "Tab completion service" try { xmake update --integrate } catch { writeErrorTip "Failed to register tab completion!" writeErrorTip 'Please try "xmake update --integrate" to register manually.' return } Write-Host "Tab completion installed" } checkTempAccess xmakeInstall if (-not $env:CI) { registerTabCompletion } else { Write-Host "Tab completion registration has been skipped for CI" } } ================================================ FILE: scripts/get.sh ================================================ #!/usr/bin/env bash # xmake getter # usage: bash <(curl -s ) [branch|__local__|__run__] [commit/__install_only__] set -o pipefail #----------------------------------------------------------------------------- # some helper functions # raise() { echo "$@" 1>&2 ; exit 1 } test_z() { if test "x${1}" = "x"; then return 0 fi return 1 } test_nz() { if test "x${1}" != "x"; then return 0 fi return 1 } test_eq() { if test "x${1}" = "x${2}"; then return 0 fi return 1 } test_nq() { if test "x${1}" != "x${2}"; then return 0 fi return 1 } #----------------------------------------------------------------------------- # prepare # # print a LOGO! echo 'xmake, A cross-platform build utility based on Lua. ' echo 'Copyright (C) 2015-present Ruki Wang, https://xmake.io' echo ' _ ' echo ' __ ___ __ __ __ _| | ______ ' echo ' \ \/ / | \/ |/ _ | |/ / __ \ ' echo ' > < | \__/ | /_| | < ___/ ' echo ' /_/\_\_|_| |_|\__ \|_|\_\____| ' echo ' by ruki, xmake.io ' echo ' ' echo ' 👉 Manual: https://xmake.io/guide/quick-start ' echo ' 🙏 Donate: https://xmake.io/about/sponsor ' echo ' ' # has sudo? if [ 0 -ne "$(id -u)" ]; then if sudo --version >/dev/null 2>&1 then sudoprefix=sudo else sudoprefix= fi else export XMAKE_ROOT=y sudoprefix= fi # make tmpdir if [ -z "$TMPDIR" ]; then tmpdir=/tmp/.xmake_getter$$ else tmpdir=$TMPDIR/.xmake_getter$$ fi if [ -d $tmpdir ]; then rm -rf $tmpdir fi # get make if gmake --version >/dev/null 2>&1 then make=gmake else make=make fi remote_get_content() { if curl --version >/dev/null 2>&1 then curl -fSL "$1" elif wget --version >/dev/null 2>&1 || wget --help >/dev/null 2>&1 then wget "$1" -O - fi } get_host_speed() { if [ `uname` == "Darwin" ]; then ping -c 1 -t 1 $1 2>/dev/null | egrep -o 'time=\d+' | egrep -o "\d+" || echo "65535" else ping -c 1 -W 1 $1 2>/dev/null | grep -E -o 'time=[0-9]+' | grep -E -o "[0-9]+" || echo "65535" fi } get_fast_host() { if test_eq "$GITHUB_ACTIONS" "true" || test_eq "$GITHUB_ACTIONS" "1"; then echo "github.com" else speed_gitee=$(get_host_speed "gitee.com") speed_github=$(get_host_speed "github.com") if [ $speed_gitee -le $speed_github ]; then echo "gitee.com" else echo "github.com" fi fi } # get branch branch=__run__ if test_nz "$1"; then brancharr=($1) if [ ${#brancharr[@]} -eq 1 ] then branch=${brancharr[0]} fi echo "Branch: $branch" fi # get fasthost and git repository if test_nq "$branch" "__local__"; then fasthost=$(get_fast_host) if test_eq "$fasthost" "gitee.com"; then gitrepo="https://gitee.com/tboox/xmake.git" gitrepo_raw="https://gitee.com/tboox/xmake/raw/master" else gitrepo="https://github.com/xmake-io/xmake.git" #gitrepo_raw="https://github.com/xmake-io/xmake/raw/master" gitrepo_raw="https://fastly.jsdelivr.net/gh/xmake-io/xmake@master" fi fi #----------------------------------------------------------------------------- # install tools # test_tools() { prog='#include \nint main(){return 0;}' { git --version && $make --version && { echo -e "$prog" | cc -xc - -o /dev/null || echo -e "$prog" | gcc -xc - -o /dev/null || echo -e "$prog" | clang -xc - -o /dev/null || echo -e "$prog" | cc -xc -c - -o /dev/null -I/usr/include -I/usr/local/include || echo -e "$prog" | gcc -xc -c - -o /dev/null -I/usr/include -I/usr/local/include || echo -e "$prog" | clang -xc -c - -o /dev/null -I/usr/include -I/usr/local/include } } >/dev/null 2>&1 } install_tools() { { apt --version >/dev/null 2>&1 && $sudoprefix apt install -y git build-essential libreadline-dev; } || { dnf --version >/dev/null 2>&1 && $sudoprefix dnf install -y git readline-devel bzip2 @development-tools; } || { yum --version >/dev/null 2>&1 && $sudoprefix yum install -y git readline-devel bzip2 && $sudoprefix yum groupinstall -y 'Development Tools'; } || { zypper --version >/dev/null 2>&1 && $sudoprefix zypper --non-interactive install git readline-devel && $sudoprefix zypper --non-interactive install -t pattern devel_C_C++; } || { pacman -V >/dev/null 2>&1 && $sudoprefix pacman -S --noconfirm --needed git base-devel ncurses readline; } || { emerge -V >/dev/null 2>&1 && $sudoprefix emerge -atv dev-vcs/git; } || { pkg list-installed >/dev/null 2>&1 && $sudoprefix pkg install -y git getconf build-essential readline; } || # termux { pkg help >/dev/null 2>&1 && $sudoprefix pkg install -y git readline ncurses; } || # freebsd { nix-env --version >/dev/null 2>&1 && nix-env -i git gcc readline ncurses; } || # nixos { apk --version >/dev/null 2>&1 && $sudoprefix apk add git gcc g++ make readline-dev ncurses-dev libc-dev linux-headers; } || { xbps-install --version >/dev/null 2>&1 && $sudoprefix xbps-install -Sy git base-devel; } #void } test_tools || { install_tools && test_tools; } || raise "$(echo -e 'Dependencies Installation Fail\nThe getter currently only support these package managers\n\t* apt\n\t* dnf\n\t* yum\n\t* zypper\n\t* pacman\n\t* portage\n\t* xbps\n Please install following dependencies manually:\n\t* git\n\t* build essential like `make`, `gcc`, etc\n\t* libreadline-dev (readline-devel)')" 1 #----------------------------------------------------------------------------- # install xmake # projectdir=$tmpdir if test_eq "$branch" "__local__"; then if [ -d '.git' ]; then git submodule update --init --recursive fi cp -r . $projectdir elif test_eq "$branch" "__run__"; then version=$(git ls-remote --tags "$gitrepo" | tail -c7) pack=gz mkdir -p $projectdir runfile_url="https://fastly.jsdelivr.net/gh/xmake-mirror/xmake-releases@$version/xmake-$version.$pack.run" echo "downloading $runfile_url .." remote_get_content "$runfile_url" > $projectdir/xmake.run if [[ $? != 0 ]]; then runfile_url="https://github.com/xmake-io/xmake/releases/download/$version/xmake-$version.$pack.run" echo "downloading $runfile_url .." remote_get_content "$runfile_url" > $projectdir/xmake.run fi sh $projectdir/xmake.run --noexec --quiet --target $projectdir else echo "cloning $gitrepo $branch .." if test_nz "$2"; then git clone --filter=tree:0 --no-checkout -b "$branch" "$gitrepo" --recurse-submodules $projectdir || raise "clone failed, check your network or branch name" cd $projectdir || raise 'chdir failed!' git checkout -qf "$2" cd - || raise 'chdir failed!' else git clone --depth=1 -b "$branch" "$gitrepo" --recurse-submodules $projectdir || raise "clone failed, check your network or branch name" fi fi # do build if test_nq "$2" "__install_only__"; then if [ -f "$projectdir/configure" ]; then cd $projectdir || raise 'chdir failed!' ./configure || raise "configure failed!" cd - || raise 'chdir failed!' fi $make -C $projectdir --no-print-directory -j4 || raise "make failed!" fi # do install if test_z "$prefix"; then prefix=~/.local fi if test_nz "$prefix"; then $make -C $projectdir --no-print-directory install PREFIX="$prefix" || raise "install failed!" else $sudoprefix $make -C $projectdir --no-print-directory install || raise "install failed!" fi #----------------------------------------------------------------------------- # install profile # install_profile() { export XMAKE_ROOTDIR="$prefix/bin" [[ "$PATH" =~ (^|:)"$XMAKE_ROOTDIR"(:|$) ]] || export PATH="$XMAKE_ROOTDIR:$PATH" xmake --version xmake update --integrate } install_profile ================================================ FILE: scripts/makeppa ================================================ #!/usr/bin/env bash # check if [ $# -lt 1 ]; then echo "Usage: ./scripts/makeppa [serie] [patch]" exit fi # workdir workdir=./xmake-ppa if [ ! -d $workdir ]; then mkdir $workdir fi # version version=`cat ./core/xmake.lua | grep -E "^set_version" | grep -oE "[0-9]*\.[0-9]*\.[0-9]*"` # serie, e.g. groovy, focal, bionic, xenial, trusty, precise serie="$1" if [ -z $serie ]; then serie=xenial fi # patch number patch="$2" if [ -z $patch ]; then patch=1 fi # tarball basename=xmake-$version+$patch$serie tarball=$workdir/$basename.tar.gz if [ ! -f $tarball ]; then cd core xmake pack --autobuild=n -y --formats=srctargz --basename=xmake -o ../artifacts xmakesrc || exit -1 cd .. cp ./artifacts/xmake.tar.gz $tarball fi # extract tarball cd $workdir if [ -d xmakesrc ]; then rm -rf xmakesrc fi if [ ! -d $basename ]; then mkdir xmakesrc tar -xvf $basename.tar.gz -C xmakesrc mv xmakesrc/xmake-$version $basename fi # enter project directory cd $basename # make template echo "making template .." if [ -d debian ]; then rm -rf debian fi export USER=`id -u -n` dh_make -e waruqi@gmail.com -c apache -y -s -f ../$basename.tar.gz # copy debian echo "instaling debian .." if [ -d debian ]; then rm -rf debian fi cp -r ../../scripts/debian . # update changelog rm debian/changelog dch -v $version+$patch$serie "update $version" -D $serie --create --package xmake -M $USER cat debian/changelog # build package echo "building package .." debuild -S -k02713554FA2CE4AADA20AB23167A22F22C0C68C9 # check package echo "checking package .." lintian ../xmake_$version+$patch$serie.dsc # upload package echo "uploading package .." source=xmake_$version+"$patch$serie"_source if [ -f ../$source.ppa.upload ]; then rm ../$source.ppa.upload fi dput ppa:xmake-io/xmake ../$source.changes # remove workdir cd ../.. rm -rf xmake-ppa # install dh-make and gpg # sudo apt install dh-make rng-tools # # @see https://help.ubuntu.com/community/GnuPrivacyGuardHowto # # generate key # gpg --gen-key # # save public/private key # gpg -a --export 2C0C68C9 > /mnt/xmake_ppa_pgp.pub # gpg -a --export-secret-keys 2C0C68C9 > /mnt/xmake_ppa_pgp.sec # # submit to keykserver and import this key to launchpad.net # @see https://launchpad.net/+help-registry/import-pgp-key.html # gpg --send-keys --keyserver keyserver.ubuntu.com 2C0C68C9 # # recv email and validate this gpg key # gpg --decrypt file.txt # goto link # # show gpg # gpg --fingerprint # pub 2048R/2C0C68C9 2020-09-08 # Key fingerprint = 0271 3554 FA2C E4AA DA20 AB23 167A 22F2 2C0C 68C9 # # build package and upload ppa to launchpad.net # https://launchpad.net/~xmake-io/+archive/ubuntu/xmake # # recv and import key on ubuntu # gpg --keyserver keyserver.ubuntu.com --recv 2C0C68C9 # gpg --export --armor 2C0C68C9 | sudo apt-key add - # # show long key # gpg --keyid-format long --list-keys waruqi@gmail.com # ================================================ FILE: scripts/man/xmake.1 ================================================ .TH "xmake" "1" .SH NAME xmake \- cross-platform build utility based on Lua .SH SYNOPSIS .B xmake .RI [ task "] [" options "] [" target ] .SH DESCRIPTION .B xmake is a lightweight cross-platform build utility based on Lua. It uses .I xmake.lua to maintain project builds. Compared with .IR makefile / CMakeLists.txt , the configuration syntax is more concise and intuitive. It is very friendly to novices and can quickly get started in a short time. Let users focus more on actual project development. .SH ACTIONS .TP .B b, build Build targets if no given tasks. .TP .B u, uninstall Uninstall the project binary files. .TP .B p, package Package target. .TP .B r, run Run the project target. .TP .B g, global Configure the global options for xmake. .TP .B i, install Package and install the target binary files. .TP .B c, clean Remove all binary and temporary files. .TP .B create Create a new project. .TP .B q, require Install and update required packages. .TP .B update Update and uninstall the xmake program. .TP .B f, config Configure the project. .SH PLUGINS .TP .B plugin Manage plugins of xmake. .TP .B m, macro Run the given macro. .TP .B doxygen Generate the doxygen document. .TP .B l, lua Run the lua script. .TP .B repo Manage package repositories. .TP .B service Start service for remote or distributed compilation and etc. (Experimental, still in development) .TP .B project Generate the project file. .TP .B show Show the given project information. .SH OPTIONS .TP .B \-q, \-\-quiet Quiet operation. .TP .B \-y, \-\-yes Input yes by default if need user confirm. .TP .BR \-\-confirm =\fICONFIRM Input the given result if need user confirm. \- yes \- no \- def .TP .B \-v, \-\-verbose Print lots of verbose information for users. .TP .B \-\-root Allow one to run xmake as root. .TP .B \-D, \-\-diagnosis Print lots of diagnosis information (backtrace, check info ..) only for developers. And we can append \fB\-v\fR to get more whole information. e.g. $ xmake \-vD .TP .B \-\-version Print the version number and exit. .TP .B \-h, \-\-help Print this help message and exit. .TP .BI \-F " FILE" ", \-\-file\fR=" FILE Read a given .B xmake.lua file. .TP .BI \-P " PROJECT" ", \-\-project\fR=" PROJECT Change to the given project directory. Search priority: 1. The Given Command Argument 2. The Environment Variable: \fBXMAKE_PROJECT_DIR\fR 3. The Current Directory .SH BUILD OPTIONS .TP .B \-b, \-\-build Build target. This is default building mode and optional. .TP .B \-r, \-\-rebuild Rebuild the target. .TP .B \-a, \-\-all Build all targets. .TP .B \-\-dry\-run Dry run to build target. .TP .BI \-j " JOBS" ", \-\-jobs\fR=" JOBS Specifies the number of jobs to build simultaneously. (default: 6) .TP .B \-w, \-\-warning Enable the warnings output. .TP .BI \-\-files= FILES Build the given source files. e.g. .RS .EX \- xmake \-\-files=src/main.c \- xmake \-\-files='src/*.c' [target] \- xmake \-\-files='src/**c|excluded_file.c' \- xmake \-\-files='src/main.c:src/test.c' .EE .RE .TP .B target The target name. It will build all default targets if this parameter is not specified. .SH AUTHOR .B xmake is written by .MT waruqi@\:gmail.com ruki .ME . This manual page was written by .MT mmyangfl@\:gmail.com Yangfl .ME for the Debian Project (and may be used by others). ================================================ FILE: scripts/man/xrepo.1 ================================================ .TH "xrepo" "1" .SH NAME xrepo \- cross-platform build utility based on Lua .SH SYNOPSIS .B xrepo .RI [ action "] [" options ] .SH DESCRIPTION .B xrepo is a lightweight cross-platform build utility based on Lua. It uses .I xrepo.lua to maintain project builds. Compared with .IR makefile / CMakeLists.txt , the configuration syntax is more concise and intuitive. It is very friendly to novices and can quickly get started in a short time. Let users focus more on actual project development. .SH ACTIONS .TP .B clean Clear all package caches and remove all not\-referenced packages. .TP .B env Set environment and execute command, or print environment. .TP .B export Export the given packages. .TP .B fetch Fetch library information of the given installed packages. .TP .B import Import the given packages. .TP .B info Show information of the given packages. .TP .B install Install the given packages. .TP .B remove Remove the given packages. .TP .B scan Scan the given or all installed packages. .TP .B search Search the given packages. .TP .B add\-repo Add the given remote repository url. .TP .B list\-repo List all remote repositories. .TP .B rm\-repo Remove the given remote repository. .TP .B update\-repo Update all local repositories from remote. .SH OPTIONS .TP .B \-q, \-\-quiet Quiet operation. .TP .B \-y, \-\-yes Input yes by default if need user confirm. .TP .B \-\-root Allow one to run xrepo as root. .TP .B \-v, \-\-verbose Print lots of verbose information for users. .TP .B \-D, \-\-diagnosis Print lots of diagnosis information. .TP .B \-\-version Print the version number and exit. .TP .B \-h, \-\-help Print this help message and exit. .SH AUTHOR .B xrepo is written by .MT waruqi@\:gmail.com ruki .ME . This manual page was written by .MT mmyangfl@\:gmail.com Yangfl .ME for the Debian Project (and may be used by others). ================================================ FILE: scripts/msys/xmake.cmd ================================================ @echo off setlocal set BASEDIR=%~dp0 if exist "%BASEDIR%..\share\xmake\xmake.exe" ( "%BASEDIR%..\share\xmake\xmake.exe" %* ) endlocal ================================================ FILE: scripts/msys/xmake.ps1 ================================================ $BASEDIR = Split-Path -Parent $MyInvocation.MyCommand.Definition if (Test-Path "$BASEDIR\..\share\xmake\xmake.exe") { & "$BASEDIR\..\share\xmake\xmake.exe" @args } ================================================ FILE: scripts/msys/xmake.sh ================================================ #!/usr/bin/env bash BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ -f "$BASEDIR/../share/xmake/xmake.exe" ]; then $BASEDIR/../share/xmake/xmake.exe "$@" fi ================================================ FILE: scripts/rpmbuild/0001-use-static-libsv-and-tbox.patch ================================================ diff --git a/core/src/xmake/xmake.sh b/core/src/xmake/xmake.sh index dc45ecbca..d0e0d0069 100755 --- a/core/src/xmake/xmake.sh +++ b/core/src/xmake/xmake.sh @@ -6,6 +6,8 @@ target "xmake" # add deps if has_config "external"; then + add_deps "sv" + add_deps "tbox" local libs="lz4 sv tbox" for lib in $libs; do if has_config "$lib"; then diff --git a/core/xmake.sh b/core/xmake.sh index 2ae2e686b..6ea8c1b69 100755 --- a/core/xmake.sh +++ b/core/xmake.sh @@ -214,6 +214,9 @@ if ! has_config "external"; then includes "src/lz4" includes "src/sv" includes "src/tbox" +else + includes "src/sv" + includes "src/tbox" fi includes "src/xmake" includes "src/cli" ================================================ FILE: scripts/rpmbuild/xmake.spec ================================================ %global debug_package %{nil} %define use_luajit 0 %undefine __brp_mangle_shebangs Name: xmake Version: 3.0.7 Release: 1%{?dist} Summary: A cross-platform build utility based on Lua # Application and 3rd-party modules licensing: # * xmake - Apache-2.0 -- Main tarball; # * libsv - Public Domain -- static dependency; # * tbox - Apache-2.0 -- static dependency; # * xxHash - BSD -- static dependency; License: Apache-2.0 AND LicenseRef-Fedora-Public-Domain AND BSD URL: https://xmake.io Source0: https://github.com/xmake-io/xmake/releases/download/v%{version}/%{name}-v%{version}.tar.gz Patch0: 0001-use-static-libsv-and-tbox.patch BuildRequires: pkgconfig(ncurses) BuildRequires: pkgconfig(liblz4) %if %{use_luajit} BuildRequires: pkgconfig(luajit) %else BuildRequires: pkgconfig(lua) >= 5.4 %endif BuildRequires: gcc BuildRequires: gcc-c++ # Virtual provides for bundled libraries Provides: bundled(libsv) = 0.0.1 Provides: bundled(libtbox) = 1.7.3 %description xmake is a lightweight cross-platform build utility based on Lua. It uses xmake.lua to maintain project builds. Compared with makefile/CMakeLists.txt, the configuration syntax is more concise and intuitive. It is very friendly to novices and can quickly get started in a short time. Let users focus more on actual project development. It can compile the project directly like Make/Ninja, or generate project files like CMake/Meson, and it also has a built-in package management system to help users solve the integrated use of C/C++ dependent libraries. %prep %autosetup -n %{name}-%{version} -p1 # Cleanup bundled deps rm -rf core/src/{lua,luajit,lua-cjson,lz4,pdcurses}/*/ %build %set_build_flags %if %{use_luajit} %configure --external=y --runtime=luajit %else %configure --external=y --runtime=lua %endif %make_build %install mkdir -p %{buildroot}%{_mandir}/man1/ install -Dpm0755 build/xmake \ %{buildroot}%{_bindir}/%{name} install -Dpm0755 scripts/xrepo.sh \ %{buildroot}%{_bindir}/xrepo install -Dpm0644 scripts/man/*1 \ %{buildroot}%{_mandir}/man1/ install -Dpm0644 xmake/scripts/completions/register-completions.bash \ %{buildroot}%{_datadir}/bash-completion/completions/xmake install -Dpm0644 xmake/scripts/completions/register-completions.fish \ %{buildroot}%{_datadir}/fish/vendor_completions.d/xmake.fish install -Dpm0644 xmake/scripts/completions/register-completions.zsh \ %{buildroot}%{_datadir}/zsh/site-functions/xmake cp -rp xmake \ %{buildroot}%{_datadir}/xmake %check %{buildroot}%{_bindir}/%{name} --version %{buildroot}%{_bindir}/xrepo --version %files %doc README.md CHANGELOG.md %license LICENSE.md NOTICE.md %{_bindir}/%{name} %{_bindir}/xrepo %{_datadir}/%{name} %{_datadir}/bash-completion/completions/xmake %{_datadir}/zsh/site-functions/xmake %{_datadir}/fish/vendor_completions.d/xmake.fish %{_mandir}/man1/*.1* %changelog * Tue Jul 11 2023 Zephyr Lykos - 2.8.1-1 - Update to 2.8.1 * Sun Jun 04 2023 Zephyr Lykos - 2.7.9-1 - Switch to release tarball - Use system provided libs if possible - Fix docs & manpage installation - Install shell completions * Sun Oct 18 2020 Ruki Wang - 2.3.8-1 - v2.3.8 released * Mon Sep 14 2020 Ruki Wang - 2.3.7-1 - Initial Commit ================================================ FILE: scripts/srcenv.bat ================================================ @echo off setlocal set script_dir=%~dp0 set PATH=%script_dir%..\core\build;%cd%;%PATH% set XMAKE_PROGRAM_DIR=%script_dir%..\xmake set XMAKE_PROGRAM_FILE=%script_dir%..\core\build\xmake.exe start cmd /k cd %script_dir%..\ endlocal ================================================ FILE: scripts/srcenv.profile ================================================ # cd projectdir xmake_binaries=( "build/xmake" "build/xmake.exe" "core/build/xmake" "core/build/xmake.exe" ) export XMAKE_PROGRAM_DIR=`pwd`/xmake xmake_found=0 for xmake_binary in "${xmake_binaries[@]}"; do if [[ -x "$xmake_binary" ]] && ("$xmake_binary" --version); then xmake_found=1 break fi done if [ $xmake_found -eq 0 ]; then unset xmake_binaries xmake_binary xmake_found echo "Error: Cannot find a working xmake executable" return 1 fi alias xmake=`pwd`/$xmake_binary export XMAKE_PROGRAM_FILE=`pwd`/$xmake_binary alias xrepo=`pwd`/scripts/xrepo.sh unset xmake_binaries xmake_binary xmake_found xmake l xmake.programdir xmake l xmake.programfile ================================================ FILE: scripts/srcenv.ps1 ================================================ $xmake_root = (Split-Path $PSScriptRoot -Parent) $env:PATH = "$xmake_root\core\build;$pwd;$env:PATH" $env:XMAKE_PROGRAM_FILE = "$xmake_root\core\build\xmake.exe" $env:XMAKE_PROGRAM_DIR = "$xmake_root\xmake" Set-Location "$xmake_root" Start-Process powershell ================================================ FILE: scripts/xrepo.bat ================================================ @set "XMAKE_ROOTDIR=%~dp0" @if not defined XMAKE_PROGRAM_FILE ( @set "XMAKE_PROGRAM_FILE=%XMAKE_ROOTDIR%xmake.exe" ) @if [%1]==[env] ( if [%2]==[quit] ( if defined XMAKE_PROMPT_BACKUP ( call %XMAKE_ENV_BACKUP% setlocal EnableDelayedExpansion if !errorlevel! neq 0 exit /B !errorlevel! endlocal set "PROMPT=%XMAKE_PROMPT_BACKUP%" set XMAKE_ENV_BACKUP= set XMAKE_PROMPT_BACKUP= ) goto :ENDXREPO ) if [%2]==[shell] ( if defined XMAKE_PROMPT_BACKUP ( call %XMAKE_ENV_BACKUP% setlocal EnableDelayedExpansion if !errorlevel! neq 0 exit /B !errorlevel! "%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info config if !errorlevel! neq 0 ( exit /B !errorlevel! ) @"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info prompt 1>nul if !errorlevel! neq 0 ( echo error: xmake.lua not found^^! exit /B !errorlevel! ) endlocal set "PROMPT=%XMAKE_PROMPT_BACKUP%" set XMAKE_ENV_BACKUP= set XMAKE_PROMPT_BACKUP= echo Please rerun `xrepo env shell` to enter the environment. exit /B 1 ) else ( setlocal EnableDelayedExpansion "%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info config if !errorlevel! neq 0 ( exit /B !errorlevel! ) @"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env | findstr . && ( echo error: corrupt xmake.lua detected in the current directory^^! exit /B 1 ) @"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info prompt 1>nul if !errorlevel! neq 0 ( echo error: xmake.lua not found^^! exit /B !errorlevel! ) endlocal for /f %%i in ('@"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info prompt') do @( @set "PROMPT=%%i %PROMPT%" ) @set "XMAKE_PROMPT_BACKUP=%PROMPT%" ) for /f %%i in ('@"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info envfile') do @( @set "XMAKE_ENV_BACKUP=%%i.bat" @"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info backup.cmd 1>"%%i.bat" ) for /f %%i in ('@"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info envfile') do @( @"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info script.cmd 1>"%%i.bat" call "%%i.bat" ) goto :ENDXREPO ) set XREPO_BIND_FLAG= if [%2]==[-b] if [%4]==[shell] ( set XREPO_BIND_FLAG=1 ) if [%2]==[--bind] if [%4]==[shell] ( set XREPO_BIND_FLAG=1 ) if defined XREPO_BIND_FLAG ( set XREPO_BIND_FLAG= if defined XMAKE_PROMPT_BACKUP ( call %XMAKE_ENV_BACKUP% setlocal EnableDelayedExpansion if !errorlevel! neq 0 exit /B !errorlevel! endlocal set "PROMPT=%XMAKE_PROMPT_BACKUP%" set XMAKE_ENV_BACKUP= set XMAKE_PROMPT_BACKUP= echo Please rerun `xrepo env %2 %3 shell` to enter the environment. exit /B 1 ) else ( pushd %XMAKE_ROOTDIR% setlocal EnableDelayedExpansion %XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info config %3 if !errorlevel! neq 0 ( popd exit /B !errorlevel! ) @%XMAKE_PROGRAM_FILE% lua --quiet private.xrepo.action.env.info prompt %3 1>nul if !errorlevel! neq 0 ( popd echo error: environment not found^^! exit /B !errorlevel! ) endlocal for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua --quiet private.xrepo.action.env.info prompt %3') do @( @set "PROMPT=%%i %PROMPT%" ) @set "XMAKE_PROMPT_BACKUP=%PROMPT%" ) for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info envfile %3') do @( @set "XMAKE_ENV_BACKUP=%%i.bat" @"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info backup.cmd %3 1>"%%i.bat" ) for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info envfile %3') do @( @"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info script.cmd %3 1>"%%i.bat" call "%%i.bat" ) popd goto :ENDXREPO ) ) @call "%XMAKE_PROGRAM_FILE%" lua private.xrepo %* :ENDXREPO ================================================ FILE: scripts/xrepo.ps1 ================================================ $script:SCRIPT_PATH = $myinvocation.mycommand.path $script:BASE_DIR = Split-Path $SCRIPT_PATH -Parent $Env:XMAKE_PROGRAM_FILE = Join-Path $BASE_DIR xmake.exe if ($Args.Count -eq 0) { # No args, just call the underlying xmake executable. & $Env:XMAKE_PROGRAM_FILE lua private.xrepo; } else { $Command = $Args[0]; if (($Command -eq "env") -and ($Args.Count -ge 2)) { switch ($Args[1]) { "shell" { if (-not (Test-Path 'Env:XMAKE_ROOTDIR')) { $Env:XMAKE_ROOTDIR = $BASE_DIR; Import-Module "$Env:XMAKE_ROOTDIR\scripts\xrepo-hook.psm1"; Add-XrepoEnvironmentToPrompt; } if ((Test-Path 'Env:XMAKE_PROMPT_MODIFIER') -and ($Env:XMAKE_PROMPT_MODIFIER -ne "")) { Exit-XrepoEnvironment; } Enter-XrepoEnvironment $Null; return; } "quit" { Exit-XrepoEnvironment; return; } {$_ -in "-b", "--bind"} { if (($Args.Count -ge 4) -and ($Args[3] -eq "shell")) { if (-not (Test-Path 'Env:XMAKE_ROOTDIR')) { $Env:XMAKE_ROOTDIR = $BASE_DIR; Import-Module "$Env:XMAKE_ROOTDIR\scripts\xrepo-hook.psm1"; Add-XrepoEnvironmentToPrompt; } if ((Test-Path 'Env:XMAKE_PROMPT_MODIFIER') -and ($Env:XMAKE_PROMPT_MODIFIER -ne "")) { Exit-XrepoEnvironment; } Enter-XrepoEnvironment $Args[2]; return; } } } } & $Env:XMAKE_PROGRAM_FILE lua private.xrepo $Args; } ================================================ FILE: scripts/xrepo.sh ================================================ #!/usr/bin/env bash BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ -f "$BASEDIR/xmake" ]; then $BASEDIR/xmake lua private.xrepo "$@" else xmake lua private.xrepo "$@" fi ================================================ FILE: tests/actions/config/.gitignore ================================================ test ================================================ FILE: tests/actions/config/test.lua ================================================ function test_workdir(t) os.tryrm("test") os.tryrm("build") os.tryrm("build2") os.tryrm(".xmake") os.exec("xmake create test") os.exec("xmake config -P test") os.exec("xmake") t:require(os.isdir("build")) t:require(os.isdir(".xmake")) t:require_not(os.isdir("test/build")) t:require_not(os.isdir("test/.xmake")) os.exec("xmake config -o build2") os.exec("xmake") t:require(os.isdir("build2")) os.tryrm("build") os.tryrm("build2") os.tryrm(".xmake") os.cd("test") os.exec("xmake create -P subtest") os.cd("subtest") os.exec("xmake config -P .") os.exec("xmake") t:require(os.isdir("build")) t:require(os.isdir(".xmake")) t:require_not(os.isdir("../build")) t:require_not(os.isdir("../.xmake")) t:require_not(os.isdir("../../build")) t:require_not(os.isdir("../../.xmake")) end ================================================ FILE: tests/actions/install/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/actions/install/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/actions/install/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) # define __export __declspec(dllexport) #elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) # define __export __attribute__((visibility("default"))) #else # define __export #endif __export int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/actions/install/src/foo.txt ================================================ ================================================ FILE: tests/actions/install/src/main.cpp ================================================ #include "foo.h" #include int main(int argc, char** argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; return 0; } ================================================ FILE: tests/actions/install/test.lua ================================================ function main(t) if is_host("windows", "linux", "macosx") and os.arch():startswith("x") then os.vrun("xmake -y") os.vrun("xmake run app") os.vrun("xmake install -o build/usr") if not is_host("linux") then -- TODO, change rpath has been not supported yet on linux. os.vrun("./build/usr/app/bin/app" .. (is_host("windows") and ".exe" or "")) end end end ================================================ FILE: tests/actions/install/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_version("1.0.1", {soname = true}) add_requires("libzip", {system = false, configs = {shared = true}}) target("foo") set_kind("shared") add_files("src/foo.cpp") add_packages("libzip", {public = true}) add_headerfiles("src/foo.h", {public = true}) add_installfiles("src/foo.txt", {prefixdir = "assets", public = true}) set_prefixdir("/", {libdir = "foo_lib"}) target("app") set_kind("binary") add_deps("foo") add_files("src/main.cpp") set_prefixdir("app", {libdir = "app_lib"}) add_rpathdirs("@loader_path/../app_lib", {installonly = true}) includes("@builtin/xpack") xpack("test") add_targets("app") set_formats("zip") ================================================ FILE: tests/actions/package/localpkg/bar/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/actions/package/localpkg/bar/src/main.cpp ================================================ #include "foo.h" #include using namespace std; int main(int argc, char** argv) { cout << "foo(1, 2) = " << foo(1, 2) << endl; return 0; } ================================================ FILE: tests/actions/package/localpkg/bar/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_repositories("local-repo build") add_requires("foo") target("bar") set_kind("binary") add_files("src/*.cpp") add_packages("foo") ================================================ FILE: tests/actions/package/localpkg/libfoo/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/actions/package/localpkg/libfoo/src/add.cpp ================================================ #include "add.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/actions/package/localpkg/libfoo/src/add.h ================================================ #ifdef __cplusplus extern "C" { #endif /*! calculate add(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/actions/package/localpkg/libfoo/src/foo.cpp ================================================ #include "add.h" #include "sub.h" #include "foo.h" int foo(int a, int b) { return add(sub(a, b), sub(b, a)); } ================================================ FILE: tests/actions/package/localpkg/libfoo/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif /*! calculate foo(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ int foo(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/actions/package/localpkg/libfoo/src/sub.cpp ================================================ #include "sub.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/actions/package/localpkg/libfoo/src/sub.h ================================================ #ifdef __cplusplus extern "C" { #endif /*! calculate sub(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/actions/package/localpkg/libfoo/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_license("Apache-2.0") target("sub") set_kind("static") add_files("src/sub.cpp") add_headerfiles("src/sub.h") target("add") set_kind("static") add_files("src/add.cpp") add_headerfiles("src/add.h") target("foo") add_deps("add", "sub") set_kind("static") add_files("src/foo.cpp") add_headerfiles("src/foo.h") ================================================ FILE: tests/actions/package/localpkg/test.lua ================================================ function main(t) if (os.subarch():startswith("x") or os.subarch() == "i386") and not is_host("bsd", "solaris", "haiku") then os.cd("libfoo") os.exec("xmake package -D -o ../bar/build") os.cd("../bar") os.exec("xmake f -c -D") os.exec("xmake -D") os.exec("xmake run") end end ================================================ FILE: tests/actions/test/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/actions/test/outputs/fail_hello_xmake.txt ================================================ hello xmake ================================================ FILE: tests/actions/test/outputs/pass_hello_foo.txt ================================================ hello foo ================================================ FILE: tests/actions/test/src/compile_1.cpp ================================================ #include int main(int argc, char** argv) { static_assert(0, "error"); return 0; } ================================================ FILE: tests/actions/test/src/compile_2.cpp ================================================ #include int main(int argc, char** argv) { static_assert(0, "error"); return 0; } ================================================ FILE: tests/actions/test/src/run_timeout.cpp ================================================ #ifdef _MSC_VER # include #else # include #endif int main(int argc, char** argv) { #ifdef _MSC_VER Sleep(10 * 1000); #else usleep(10 * 100 * 1000); #endif return 0; } ================================================ FILE: tests/actions/test/src/test_1.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { char const* arg = argc > 1? argv[1] : "xmake"; cout << "hello " << arg << endl; return 0; } ================================================ FILE: tests/actions/test/src/test_2.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { char const* arg = argc > 1? argv[1] : "xmake"; cout << "hello " << arg << endl; return 0; } ================================================ FILE: tests/actions/test/src/test_3.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { char const* arg = argc > 1? argv[1] : "xmake"; cout << "hello " << arg << endl; return 0; } ================================================ FILE: tests/actions/test/src/test_4.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { char const* arg = argc > 1? argv[1] : "xmake"; cout << "hello " << arg << endl; return 0; } ================================================ FILE: tests/actions/test/src/test_5.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { char const* arg = argc > 1? argv[1] : "xmake"; cout << "hello2 " << arg << endl; return 0; } ================================================ FILE: tests/actions/test/src/test_6.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { char const* arg = argc > 1? argv[1] : "xmake"; cout << "hello " << arg << endl; return 0; } ================================================ FILE: tests/actions/test/src/test_7.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { char const* arg = argc > 1? argv[1] : "xmake"; cout << "hello " << arg << endl; return -1; } ================================================ FILE: tests/actions/test/src/test_8.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello xmake" << endl; return 0; } ================================================ FILE: tests/actions/test/src/test_9.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { char const* arg = argc > 1? argv[1] : "xmake"; cout << "hello " << arg << endl; return 0; } ================================================ FILE: tests/actions/test/test.lua ================================================ function main(t) os.exec("xmake test") end ================================================ FILE: tests/actions/test/tests/stub_1.cpp ================================================ #ifndef STUB_1 #error #endif ================================================ FILE: tests/actions/test/tests/stub_2.cpp ================================================ #ifndef STUB_2 #error #endif ================================================ FILE: tests/actions/test/tests/stub_n1.cpp ================================================ #ifndef STUB_N #error #endif ================================================ FILE: tests/actions/test/tests/stub_n2.cpp ================================================ #ifndef STUB_N #error #endif ================================================ FILE: tests/actions/test/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_policy("test.return_zero_on_failure", true) for _, file in ipairs(os.files("src/test_*.cpp")) do local name = path.basename(file) target(name) set_kind("binary") set_default(false) add_files("src/" .. name .. ".cpp") add_tests("default") add_tests("args", {runargs = {"foo", "bar"}}) add_tests("pass_output", {trim_output = true, runargs = "foo", pass_outputs = "hello foo"}) add_tests("fail_output", {fail_outputs = {"hello2 .*", "hello xmake"}}) end target("test_output_files") set_kind("binary") set_default(false) add_files("src/test_1.cpp") add_tests("pass_output_file", {trim_output = true, runargs = "foo", pass_output_files = "outputs/pass_hello_foo.txt"}) add_tests("fail_output_file", {trim_output = true, should_fail = true, fail_output_files = "outputs/fail_hello_xmake.txt"}) target("test_10") set_kind("binary") set_default(false) add_files("src/compile_1.cpp") add_tests("compile_fail", {build_should_fail = true}) target("test_11") set_kind("binary") set_default(false) add_files("src/compile_2.cpp") add_tests("compile_pass", {build_should_pass = true}) target("test_13") set_kind("binary") set_default(false) add_files("src/test_1.cpp") add_tests("stub_1", {files = "tests/stub_1.cpp", defines = "STUB_1"}) target("test_14") set_kind("binary") set_default(false) add_files("src/test_2.cpp") add_tests("stub_2", {files = "tests/stub_2.cpp", defines = "STUB_2"}) target("test_15") set_kind("binary") set_default(false) add_files("src/test_1.cpp") add_tests("stub_n", {realtime_output = true, files = "tests/stub_n*.cpp", defines = "STUB_N"}) target("test_timeout") set_kind("binary") set_default(false) add_files("src/run_timeout.cpp") add_tests("run_timeout", {run_timeout = 1000}) ================================================ FILE: tests/apis/add_allowedxxx/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/add_allowedxxx/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/apis/add_allowedxxx/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_defaultmode("releasedbg") set_defaultplat("linux") set_defaultarchs("macosx|arm64", "linux|i386", "armv7") set_allowedmodes("releasedbg", "debug") set_allowedplats("windows", "linux", "macosx") set_allowedarchs("macosx|arm64", "macosx|x86_64", "linux|i386", "linux|x86_64") target("test") set_kind("binary") add_files("src/*.cpp") ================================================ FILE: tests/apis/add_configfiles/config.h.in ================================================ #define HAVE_${module}_H #define HELLO "${hello} ${ARCH} ${PLAT}" ${define FOO_ENABLE} ${define FOO_ENABLE2} ${define FOO_STRING} ${define FOO_DEFINE} ${define FOO2_ENABLE} ${define FOO2_ENABLE2} ${define FOO2_STRING} ${define_export MYLIB} ${define_custom FOO_STRING arg1 arg2} #define HAVE_SSE2 ${default HAVE_SSE2 0} ================================================ FILE: tests/apis/add_configfiles/config2.h.in ================================================ #define HAVE_@module@_H #define HELLO2 "@hello@ @ARCH@ @PLAT@" @define FOO_ENABLE@ @define FOO_ENABLE2@ @define FOO_STRING@ @define FOO2_ENABLE@ @define FOO2_ENABLE2@ @define FOO2_STRING@ #define DEFAULT_TEST @default default_test 0@ ================================================ FILE: tests/apis/add_configfiles/hello.man ================================================ ${module} ${ARCH} ================================================ FILE: tests/apis/add_configfiles/main.c ================================================ #include #include #include "config.h" int main(int argc, char **argv) { printf("hello %s\n", HELLO); return 0; } ================================================ FILE: tests/apis/add_configfiles/main2.c ================================================ #include #include #include "config2.h" int main(int argc, char **argv) { printf("hello2 %s\n", HELLO2); return 0; } ================================================ FILE: tests/apis/add_configfiles/test.c.in ================================================ int test() { return 0; } ================================================ FILE: tests/apis/add_configfiles/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/add_configfiles/xmake.lua ================================================ option("foo") set_default("foo") set_description("The Foo Info") option_end() if has_config("foo") then set_configvar("FOO_ENABLE", 1) set_configvar("FOO_ENABLE2", false) set_configvar("FOO_STRING", get_config("foo")) set_configvar("FOO_DEFINE", get_config("foo"), {quote = false}) end option("foo2") set_default(true) set_description("Enable Foo2") set_configvar("FOO2_ENABLE", true) set_configvar("FOO2_STRING", "foo") option_end() target("test") set_kind("binary") add_files("main.c") set_configvar("module", "test") set_configdir("$(builddir)/config") add_configfiles("test.c.in", {filename = "mytest.c"}) add_configfiles("config.h.in", {variables = {hello = "xmake"}, prefixdir = "header", preprocessor = function (preprocessor_name, name, value, opt) if preprocessor_name == "define_custom" then return string.format("#define CUSTOM_%s %s", name, value) end end}) add_configfiles("*.man", {onlycopy = true, prefixdir = "man"}) add_includedirs("$(builddir)/config/header") target("test2") set_kind("binary") add_files("main2.c") set_configvar("module", "test2") set_configdir("$(builddir)/config2") add_configfiles("test.c.in", {filename = "mytest.c"}) add_configfiles("config2.h.in", {variables = {hello = "xmake2"}, pattern = "@([^\n]-)@", prefixdir = "header"}) add_configfiles("*.man", {onlycopy = true, prefixdir = "man"}) add_includedirs("$(builddir)/config2/header") add_options("foo2") ================================================ FILE: tests/apis/add_defines/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/add_defines/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << TEST1 << endl; cout << TEST2 << endl; cout << TEST3 << endl; cout << TEST4 << endl; cout << TEST5 << endl; cout << TEST6 << endl; return 0; } ================================================ FILE: tests/apis/add_defines/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/add_defines/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.cpp") add_defines("TEST1=\"hello\"") add_defines("TEST2=\"hello xmake\"") add_defines("TEST3=3") add_cxflags("-DTEST4=\"hello\"") add_cxflags("-DTEST5=\"hello xmake\" -DTEST6=3") ================================================ FILE: tests/apis/add_deps/inc1/stub.h ================================================ ================================================ FILE: tests/apis/add_deps/inc2/stub.h ================================================ ================================================ FILE: tests/apis/add_deps/inc3/stub.h ================================================ ================================================ FILE: tests/apis/add_deps/inc4/stub.h ================================================ ================================================ FILE: tests/apis/add_deps/src/interface.c ================================================ #include "interface.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/add_deps/src/interface.h ================================================ #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) #define __export __declspec(dllexport) #elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) #define __export __attribute__((visibility("default"))) #else #define __export #endif /*! calculate add(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ __export int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/add_deps/src/main.c ================================================ #include int main(int argc, char **argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/apis/add_deps/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/add_deps/xmake.lua ================================================ target("dep1") set_kind("static") add_files("src/*.c") add_cflags("-DFLAG1") add_cflags("-DFLAG2", {interface = true}) add_includedirs("inc1", {public = true}) add_defines("TEST1", {public = true}) target("dep2") set_kind("shared") add_deps("dep1") add_files("src/*.c") add_includedirs("inc2", {interface = true}) add_defines("TEST2", {interface = true}) on_load(function (target) print(target:extraconf("includedirs")) print(target:extraconf("defines", "TEST2")) print(target:extraconf("defines", "TEST2", "interface")) print(target:get("files")) print(target:get("files", {private = true})) print(target:get("files", {public = true})) print(target:get("files", {interface = true})) print(target:get("defines")) print(target:get("defines", {private = true})) print(target:get("defines", {public = true})) print(target:get("defines", {interface = true})) end) target("dep3") set_kind("static") add_files("src/*.c") add_includedirs("inc3") target("dep4") set_kind("static") add_files("src/*.c") add_includedirs("inc4", {public = true}) add_defines("TEST4", {public = true}) target("demo") set_kind("binary") add_deps("dep2", "dep3") add_deps("dep4", {inherit = false}) add_files("src/*.c") ================================================ FILE: tests/apis/add_imports/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/add_imports/xmake.lua ================================================ target("test") add_imports("core.base.option", "core.base.task") before_build(function (target) assert(option) assert(task) end) on_build(function (target) assert(option) assert(task) end) after_build(function (target) assert(option) assert(task) end) ================================================ FILE: tests/apis/add_xxx/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/add_xxx/xmake.lua ================================================ add_defines("TEST1") target("test") add_defines("TEST2") on_build(function (target) local defines = table.concat(target:get("defines"), " ") assert(defines:find("TEST1", 1, true)) assert(defines:find("TEST2", 1, true)) end) ================================================ FILE: tests/apis/check_xxx/config.h.in ================================================ ${define HAS_STRING_H} ${define HAS_STRING_AND_STDIO_H} ${define HAS_WCHAR_AND_FLOAT} ${define HAS_PTHREAD} ${define HAS_STATIC_ASSERT} ${define HAS_SETJMP} ${define HAS_CONSTEXPR} ${define HAS_CONSEXPR_AND_STATIC_ASSERT} ${define HAS_SSE2} ${define HAS_LONG_8} ${define HAS_CXX_STD_98} ${define HAS_CXX_STD_11} ${define HAS_CXX_STD_14} ${define HAS_CXX_STD_17} ${define HAS_CXX_STD_20} ${define HAS_C_STD_89} ${define HAS_C_STD_99} ${define HAS_C_STD_11} ${define HAS_C_STD_17} ${define HAS_GCC} ${define HAS_CXX20} ${define IS_BIG_ENDIAN} ${define NO_GCC} ${define PTR_SIZE} ${define HAVE_VISIBILITY} ${define CUSTOM_ASSERT} #define HAS_WCHAR ${default HAS_WCHAR 0} ================================================ FILE: tests/apis/check_xxx/foo.c ================================================ #include "config.h" int foo() { return 0; } ================================================ FILE: tests/apis/check_xxx/main.c ================================================ int main(int argc, char **argv) { return 0; } ================================================ FILE: tests/apis/check_xxx/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/check_xxx/xmake.lua ================================================ includes("@builtin/check") target("foo") set_kind("static") add_files("foo.c") add_includedirs("$(builddir)") add_configfiles("config.h.in") check_bigendian("IS_BIG_ENDIAN") check_ctypes("HAS_WCHAR", "wchar_t") check_cincludes("HAS_STRING_H", "string.h") check_csnippets("HAS_INT_4", "return (sizeof(int) == 4)? 0 : -1;", {tryrun = true}) check_csnippets("HAS_INT_4_IN_MAIN", [[ int test() { return (sizeof(int) == 4)? 0 : -1; } int main(int argc, char** argv) { return test(); }]], {tryrun = true}) check_csnippets("INT_SIZE", 'printf("%d", sizeof(int)); return 0;', {output = true, number = true}) check_sizeof("LONG_SIZE", "long") check_sizeof("STRING_SIZE", "std::string", {includes = "string"}) configvar_check_bigendian("IS_BIG_ENDIAN") configvar_check_cincludes("HAS_STRING_AND_STDIO_H", {"string.h", "stdio.h"}) configvar_check_ctypes("HAS_WCHAR_AND_FLOAT", {"wchar_t", "float"}) configvar_check_links("HAS_PTHREAD", {"pthread", "m", "dl"}) configvar_check_csnippets("HAS_STATIC_ASSERT", "_Static_assert(1, \"\");") configvar_check_cfuncs("HAS_SETJMP", "setjmp", {includes = {"signal.h", "setjmp.h"}}) configvar_check_features("HAS_CONSTEXPR", "cxx_constexpr", {languages = "c++11"}) configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"}) configvar_check_features("HAS_CXX_STD_98", "cxx_std_98") configvar_check_features("HAS_CXX_STD_11", "cxx_std_11", {languages = "c++11"}) configvar_check_features("HAS_CXX_STD_14", "cxx_std_14", {languages = "c++14"}) configvar_check_features("HAS_CXX_STD_17", "cxx_std_17", {languages = "c++17"}) configvar_check_features("HAS_CXX_STD_20", "cxx_std_20", {languages = "c++20"}) configvar_check_features("HAS_C_STD_89", "c_std_89") configvar_check_features("HAS_C_STD_99", "c_std_99") configvar_check_features("HAS_C_STD_11", "c_std_11", {languages = "c11"}) configvar_check_features("HAS_C_STD_17", "c_std_17", {languages = "c17"}) configvar_check_cflags("HAS_SSE2", "-msse2") configvar_check_csnippets("HAS_LONG_8", "return (sizeof(long) == 8)? 0 : -1;", {tryrun = true}) configvar_check_csnippets("PTR_SIZE", 'printf("%d", sizeof(void*)); return 0;', {output = true, number = true}) configvar_check_csnippets("HAVE_VISIBILITY", 'extern __attribute__((__visibility__("hidden"))) int hiddenvar;', {default = 0}) configvar_check_csnippets("CUSTOM_ASSERT=assert", 'assert(1);', {default = "", quote = false}) configvar_check_macros("HAS_GCC", "__GNUC__") configvar_check_macros("NO_GCC", "__GNUC__", {defined = false}) configvar_check_macros("HAS_CXX20", "__cplusplus >= 202002L", {languages = "c++20"}) local features_cxx17 = { "cxx_aggregate_bases", "cxx_aligned_new", "cxx_capture_star_this", "cxx_constexpr", "cxx_deduction_guides", "cxx_enumerator_attributes", "cxx_fold_expressions", "cxx_guaranteed_copy_elision", "cxx_hex_float", "cxx_if_constexpr", "cxx_inheriting_constructors", "cxx_inline_variables", "cxx_namespace_attributes", "cxx_noexcept_function_type", "cxx_nontype_template_args", "cxx_nontype_template_parameter_auto", "cxx_range_based_for", "cxx_static_assert", "cxx_structured_bindings", "cxx_template_template_args", "cxx_variadic_using"} for _, feature in ipairs(features_cxx17) do check_features("HAS_17_" .. feature:upper(), feature, {languages = "c++17"}) end local features_cxx20 = { "cxx_aggregate_paren_init", "cxx_char8_t", "cxx_concepts", "cxx_conditional_explicit", "cxx_consteval", "cxx_constexpr", "cxx_constexpr_dynamic_alloc", "cxx_constexpr_in_decltype", "cxx_constinit", "cxx_deduction_guides", "cxx_designated_initializers", "cxx_generic_lambdas", "cxx_impl_coroutine", "cxx_impl_destroying_delete", "cxx_impl_three_way_comparison", "cxx_init_captures", "cxx_modules", "cxx_nontype_template_args", "cxx_using_enum"} for _, feature in ipairs(features_cxx20) do check_features("HAS_20_" .. feature:upper(), feature, {languages = "c++20"}) end target("test") add_deps("foo") set_kind("binary") add_files("main.c") ================================================ FILE: tests/apis/clone_target/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/apis/clone_target/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/clone_target/xmake.lua ================================================ target("test") set_kind("binary") add_files("src/*.cpp") add_defines("TEST") after_load(function (target) import("core.project.project") local t = target:clone() t:name_set("test2") t:add("deps", "test") t:add("defines", "TEST2") t:set("link_before", function (target) print("link1", target:name()) assert(target:dep("test"):data("linked")) end) project.target_add(t) end) before_link(function (target) print("link2", target:name()) target:data_set("linked", true) end) ================================================ FILE: tests/apis/custom_scopeapis/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/custom_scopeapis/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/apis/custom_scopeapis/xmake.lua ================================================ add_rules("mode.debug", "mode.release") interp_add_scopeapis("myscope.set_name", "myscope.add_list", {kind = "values"}) interp_add_scopeapis("myscope.on_script", {kind = "script"}) myscope("hello") set_name("foo") add_list("value1", "value2") on_script(function () print("hello") end) target("test") set_kind("binary") add_files("src/*.cpp") on_config(function (target) import("core.project.project") local myscope = project.scope("myscope") for name, scope in pairs(myscope) do print("myscope(%s)", name) print(" name: %s", scope:get("name")) print(" list: %s", table.concat(scope:get("list"), ", ")) print(" script:") local script = scope:get("script") if script then script() end end end) ================================================ FILE: tests/apis/custom_toolchain/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/custom_toolchain/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/custom_toolchain/src/test.cpp ================================================ #include "foo.h" int main(int argc, char **argv) { return add(1, 2); } ================================================ FILE: tests/apis/custom_toolchain/xmake/modules/core/tools/ar6x.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file ar6x.lua -- inherit("core.tools.ar") -- init it function init(self) self:set("arflags", "-r") end ================================================ FILE: tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/has_flags.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file has_flags.lua -- -- imports import("core.cache.detectcache") import("core.language.language") -- is linker? function _islinker(flags, opt) local toolkind = opt.toolkind or "" return toolkind == "ld" or toolkind == "sh" or toolkind:endswith("ld") or toolkind:endswith("sh") end -- try running function _try_running(program, argv, opt) local errors = nil return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or ""):trim() end }}, errors end -- attempt to check it from known flags function _check_from_knownargs(flags, opt, islinker) local flag = flags[1] if not islinker then if flag:startswith("-D") or flag:startswith("-U") or flag:startswith("-I") then return true end end end -- attempt to check it from the argument list function _check_from_arglist(flags, opt, islinker) local key = "core.tools.cl6x." .. (islinker and "has_ldflags" or "has_cflags") local flagskey = opt.program .. "_" .. (opt.programver or "") local allflags = detectcache:get2(key, flagskey) if not allflags then allflags = {} local arglist = try {function () return os.iorunv(opt.program, {"--help"}, {envs = opt.envs}) end} if arglist then for arg in arglist:gmatch("%s+(%-[%-%a%d]+)%s+") do allflags[arg] = true end end detectcache:set2(key, flagskey, allflags) end local flag = flags[1] return allflags[flag] end -- get extension function _get_extension(opt) -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated] return (opt.program:endswith("++") or opt.flagkind == "cxxflags") and ".cpp" or (table.wrap(language.sourcekinds()[opt.toolkind or "cc"])[1] or ".c") end -- try running to check flags function _check_try_running(flags, opt, islinker) -- make an stub source file local snippet = opt.snippet or "int main(int argc, char** argv)\n{return 0;}\n" local sourcefile = os.tmpfile("cl6x_has_flags:" .. snippet) .. _get_extension(opt) if not os.isfile(sourcefile) then io.writefile(sourcefile, snippet) end -- check flags for linker local tmpfile = os.tmpfile() if islinker then return _try_running(opt.program, table.join(flags, "-z", "--output_file=" .. tmpfile, sourcefile), opt) end -- check flags for compiler -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage return _try_running(opt.program, table.join(flags, "-c", "--output_file=" .. tmpfile, sourcefile), opt) end -- has_flags(flags)? -- -- @param opt the argument options, e.g. {toolname = "", program = "", programver = "", toolkind = "[cc|cxx|ld|ar|sh|gc|mm|mxx]"} -- -- @return true or false -- function main(flags, opt) -- is linker? opt = opt or {} local islinker = _islinker(flags, opt) -- attempt to check it from the argument list if not opt.tryrun then if _check_from_arglist(flags, opt, islinker) then return true end if _check_from_knownargs(flags, opt, islinker) then return true end end -- try running to check it return _check_try_running(flags, opt, islinker) end ================================================ FILE: tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/parse_deps.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file parse_deps.lua -- -- imports import("core.project.config") import("core.project.project") import("core.base.hashset") -- normailize path of a dependecy function _normailize_dep(dep, projectdir) -- escape characters, e.g. \#Qt.Widget_pch.h -> #Qt.Widget_pch.h -- @see https://github.com/xmake-io/xmake/issues/4134 -- https://github.com/xmake-io/xmake/issues/4273 if not is_host("windows") then dep = dep:gsub("\\(.)", "%1") end if path.is_absolute(dep) then dep = path.translate(dep) else dep = path.absolute(dep, projectdir) end if dep:startswith(projectdir) then return path.relative(dep, projectdir) else -- we also need to check header files outside project -- https://github.com/xmake-io/xmake/issues/1154 return dep end end -- parse depsfiles from string -- -- parse_deps(io.readfile(depfile, {continuation = "\\"})) -- -- eg. -- -- build/.objs/foo/linux/x86_64/release/src/foo.c.o: src/foo.c -- build/.objs/foo/linux/x86_64/release/src/foo.c.o: src/foo.h -- -- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/main.c -- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/foo.h -- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/bar.h -- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/zoo.h -- function main(depsdata, opt) local results = hashset.new() local projectdir = os.projectdir() local line = depsdata:rtrim() -- maybe there will be an empty newline at the end. so we trim it first local plain = {plain = true} for _, includefile in ipairs(line:split('\n', plain)) do -- it will trim all internal spaces without `{strict = true}` includefile = includefile:split(": ", plain)[2] if includefile and #includefile > 0 then includefile = _normailize_dep(includefile, projectdir) if includefile then results:insert(includefile) end end end return results:to_array() end ================================================ FILE: tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file cl6x.lua -- -- imports import("core.base.option") import("core.base.global") import("core.project.policy") import("core.language.language") import("utils.progress") -- init it function init(self) end -- make the symbol flag function nf_symbol(self, level) -- only for source kind local kind = self:kind() if language.sourcekinds()[kind] then local maps = _g.symbol_maps if not maps then maps = { debug = "-g" } _g.symbol_maps = maps end return maps[level .. '_' .. kind] or maps[level] end end -- make the optimize flag function nf_optimize(self, level) local maps = { none = "-O0" , fast = "-O1" , faster = "-O2" , fastest = "-O3" , smallest = "-m3" , aggressive = "-O3" } return maps[level] end -- make the define flag function nf_define(self, macro) return "-D" .. macro end -- make the undefine flag function nf_undefine(self, macro) return "-U" .. macro end -- make the includedir flag function nf_includedir(self, dir) return {"-I" .. dir} end -- make the sysincludedir flag function nf_sysincludedir(self, dir) return nf_includedir(self, dir) end -- make the link flag function nf_link(self, lib) if not lib:endswith(".a") and not lib:endswith(".so") then lib = "lib" .. lib .. ".a" end return "-l" .. lib end -- make the syslink flag function nf_syslink(self, lib) return nf_link(self, lib) end -- make the linkdir flag function nf_linkdir(self, dir) return {"-i" .. path.translate(dir)} end -- make the rpathdir flag function nf_rpathdir(self, dir, opt) opt = opt or {} local extra = opt.extra if extra and extra.installonly then return end dir = path.translate(dir) return {"-rpath=" .. dir} end -- make the link arguments list function linkargv(self, objectfiles, targetkind, targetfile, flags, opt) local argv = table.join("-z", "--output_file=" .. targetfile, objectfiles, flags) return self:program(), argv end -- link the target file -- -- maybe we need to use os.vrunv() to show link output when enable verbose information -- @see https://github.com/xmake-io/xmake/discussions/2916 -- function link(self, objectfiles, targetkind, targetfile, flags, opt) opt = opt or {} os.mkdir(path.directory(targetfile)) local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags) if option.get("verbose") then os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell}) else os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell}) end end -- make the compile arguments list function compargv(self, sourcefile, objectfile, flags) return self:program(), table.join("-c", "--preproc_with_compile", flags, "--output_file=" .. objectfile, sourcefile) end -- compile the source file function compile(self, sourcefile, objectfile, dependinfo, flags, opt) os.mkdir(path.directory(objectfile)) local depfile = dependinfo and os.tmpfile() or nil try { function () local compflags = flags if depfile then compflags = table.join(compflags, "-ppd=" .. depfile) end local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, compflags)) return (outdata or "") .. (errdata or "") end, catch { function (errors) -- try removing the old object file for forcing to rebuild this source file os.tryrm(objectfile) -- find the start line of error local lines = tostring(errors):split("\n") local start = 0 for index, line in ipairs(lines) do if line:find("error:", 1, true) or line:find("错误:", 1, true) then start = index break end end -- get 16 lines of errors if start > 0 or not option.get("verbose") then if start == 0 then start = 1 end errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), "\n") end -- raise compiling errors raise(errors) end }, finally { function (ok, warnings) -- print some warnings if warnings and #warnings > 0 and policy.build_warnings(opt) then progress.show_output("${color.warning}%s", table.concat(table.slice(warnings:split('\n'), 1, 8), '\n')) end -- generate the dependent includes if depfile and os.isfile(depfile) then if dependinfo then dependinfo.depfiles_format = "cl6x" dependinfo.depfiles = io.readfile(depfile, {continuation = "\\"}) end -- remove the temporary dependent file os.tryrm(depfile) end end } } end ================================================ FILE: tests/apis/custom_toolchain/xmake/modules/detect/tools/find_ar6x.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file find_ar6x.lua -- -- imports import("lib.detect.find_program") -- check function _check(program) -- make a stub object file local libraryfile = os.tmpfile() .. ".a" local objectfile = os.tmpfile() .. ".o" io.writefile(objectfile, "") -- archive it os.execv(program, {"-r", libraryfile, objectfile}) -- remove files os.rm(objectfile) os.rm(libraryfile) end -- find ar -- -- @param opt the argument options, e.g. {version = true} -- -- @return program, version -- -- @code -- -- local ar = find_ar6x() -- local ar, version = find_ar6x({program = "xcrun -sdk macosx g++", version = true}) -- -- @endcode -- function main(opt) opt = opt or {} opt.check = opt.check or _check return find_program(opt.program or "ar6x", opt) end ================================================ FILE: tests/apis/custom_toolchain/xmake/modules/detect/tools/find_cl6x.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file find_cl6x.lua -- -- imports import("lib.detect.find_program") import("lib.detect.find_programver") -- find cl6x -- -- @param opt the argument options, e.g. {version = true} -- -- @return program, version -- -- @code -- -- local cl6x = find_cl6x() -- local cl6x, version = find_cl6x({program = "cl6x", version = true}) -- -- @endcode -- function main(opt) opt = opt or {} opt.check = "--help" opt.command = "--help" local program = find_program(opt.program or "cl6x", opt) local version = nil if program and opt.version then version = find_programver(program, opt) end return program, version end ================================================ FILE: tests/apis/custom_toolchain/xmake/toolchains/my-c6000/xmake.lua ================================================ toolchain("my-c6000") set_kind("standalone") set_homepage("https://www.ti.com") set_description("TI-CGT C6000 compiler") set_toolset("cc", "cl6x") set_toolset("cxx", "cl6x") set_toolset("ld", "cl6x") set_toolset("sh", "cl6x") set_toolset("ar", "ar6x") set_toolset("strip", "strip6x") set_toolset("as", "cl6x") on_check(function (toolchain) return import("lib.detect.find_tool")("cl6x") end) on_load(function (toolchain) toolchain:add("cxflags", "-Dxxx") end) ================================================ FILE: tests/apis/custom_toolchain/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_moduledirs("xmake/modules") add_toolchaindirs("xmake/toolchains") set_toolchains("my-c6000") target("test") set_kind("static") add_files("src/foo.cpp") target("demo") set_kind("binary") add_deps("test") add_files("src/test.cpp") ================================================ FILE: tests/apis/namespace/basic/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/basic/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/basic/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/basic/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/basic/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/basic/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/basic/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/namespace/basic/xmake.lua ================================================ add_rules("mode.debug", "mode.release") namespace("ns1", function () target("foo") set_kind("static") add_files("src/foo.cpp") end) namespace("ns2") target("bar") set_kind("static") add_files("src/bar.cpp") namespace_end() target("test") set_kind("binary") add_deps("ns1::foo", "ns2::bar") add_files("src/main.cpp") ================================================ FILE: tests/apis/namespace/includes/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/includes/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/includes/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/includes/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/includes/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/includes/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/includes/src/xmake.lua ================================================ namespace("ns2", function () add_defines("NS2_ROOT") target("bar") set_kind("static") add_files("bar.cpp") add_defines("BAR") end) ================================================ FILE: tests/apis/namespace/includes/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/namespace/includes/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_defines("ROOT") namespace("ns1", function () add_defines("NS1_ROOT") target("foo") set_kind("static") add_files("src/foo.cpp") add_defines("FOO") includes("src") end) target("test") set_kind("binary") add_deps("ns1::foo", "ns1::ns2::bar") add_files("src/main.cpp") add_defines("TEST") ================================================ FILE: tests/apis/namespace/inner/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/inner/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/inner/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/inner/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/inner/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/inner/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/inner/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/namespace/inner/xmake.lua ================================================ add_rules("mode.debug", "mode.release") namespace("ns1", function () target("foo") set_kind("static") add_files("src/foo.cpp") namespace("ns2", function() target("bar") set_kind("static") add_files("src/bar.cpp") end) target("test") set_kind("binary") add_deps("foo", "ns2::bar") add_files("src/main.cpp") end) ================================================ FILE: tests/apis/namespace/nested/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/nested/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/nested/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/nested/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/nested/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/nested/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/nested/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/namespace/nested/xmake.lua ================================================ add_rules("mode.debug", "mode.release") namespace("ns1", function () target("foo") set_kind("static") add_files("src/foo.cpp") namespace("ns2") target("bar") set_kind("static") add_files("src/bar.cpp") namespace_end() end) target("test") set_kind("binary") add_deps("ns1::foo", "ns1::ns2::bar") add_files("src/main.cpp") ================================================ FILE: tests/apis/namespace/option/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/option/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/option/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/option/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/option/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/option/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/option/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/namespace/option/xmake.lua ================================================ add_rules("mode.debug", "mode.release") option("opt0", {default = true, defines = "OPT0", description = "option0"}) namespace("ns1", function () option("opt1", {default = true, defines = "NS1_OPT1", description = "option1"}) target("foo") set_kind("static") add_files("src/foo.cpp") add_options("opt1") if has_config("opt1") then add_defines("HAS_NS1_OPT1") end namespace("ns2", function() option("opt2", {default = true, defines = "NS2_OPT2", description = "option2"}) target("bar") set_kind("static") add_files("src/bar.cpp") add_options("opt2") if has_config("opt2") then add_defines("HAS_NS2_OPT2") end end) target("test") set_kind("binary") add_deps("foo", "ns2::bar") add_files("src/main.cpp") add_options("opt0", "opt1", "ns2::opt2") on_load(function (target) if has_config("opt0") then target:add("defines", "HAS_OPT0") end if has_config("opt1") then target:add("defines", "HAS_NS1_OPT1") end if has_config("ns2::opt2") then target:add("defines", "HAS_NS2_OPT2") end end) end) ================================================ FILE: tests/apis/namespace/package/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/package/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/package/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/package/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/package/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/package/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/package/test.lua ================================================ function main() if is_host("bsd", "solaris", "haiku") then return end os.exec("xmake -vD -y") end ================================================ FILE: tests/apis/namespace/package/xmake.lua ================================================ add_requires("package0", {system = false}) package("package0") on_load(function (package) package:add("defines", "PACKAGE0") end) on_install(function (package) end) namespace("ns1", function () add_requires("package1", {system = false}) package("package1") on_load(function (package) package:add("defines", "NS1_PACKAGE1") end) on_install(function (package) end) target("foo") set_kind("static") add_files("src/foo.cpp") add_packages("package1") if has_package("package1") then add_defines("HAS_PACKAGE1") end namespace("ns2", function() add_requires("package2", {system = false}) package("package2") on_load(function (package) package:add("defines", "NS2_PACKAGE2") end) on_install(function (package) end) target("bar") set_kind("static") add_files("src/bar.cpp") add_packages("package2") if has_package("package2") then add_defines("HAS_PACKAGE2") end end) target("test") set_kind("binary") add_deps("foo", "ns2::bar") add_files("src/main.cpp") add_packages("package0", "package1", "ns2::package2") on_load(function (target) if has_package("package0") then target:add("defines", "HAS_PACKAGE0") end if has_package("package1") then target:add("defines", "HAS_PACKAGE1") end if has_package("ns2::package2") then target:add("defines", "HAS_PACKAGE2") end end) end) ================================================ FILE: tests/apis/namespace/root/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/root/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/root/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/root/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/root/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/root/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/root/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/namespace/root/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_defines("ROOT") namespace("ns1", function () add_defines("NS1_ROOT") target("foo") set_kind("static") add_files("src/foo.cpp") add_defines("FOO") namespace("ns2", function () add_defines("NS2_ROOT") target("bar") set_kind("static") add_files("src/bar.cpp") add_defines("BAR") end) end) target("test") set_kind("binary") add_deps("ns1::foo", "ns1::ns2::bar") add_files("src/main.cpp") add_defines("TEST") ================================================ FILE: tests/apis/namespace/rule/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/rule/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/rule/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/rule/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/rule/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/rule/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/rule/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/namespace/rule/xmake.lua ================================================ add_rules("mode.debug", "mode.release") rule("rule0") on_load(function (target) target:add("defines", "RULE0") end) namespace("ns1", function () rule("rule1") on_load(function (target) target:add("defines", "NS1_RULE1") end) target("foo") set_kind("static") add_files("src/foo.cpp") add_rules("rule1") namespace("ns2", function() rule("rule2") on_load(function (target) target:add("defines", "NS2_RULE2") end) target("bar") set_kind("static") add_files("src/bar.cpp") add_rules("rule2") end) target("test") set_kind("binary") add_deps("foo", "ns2::bar") add_files("src/main.cpp") add_rules("rule0", "rule1", "ns2::rule2") end) ================================================ FILE: tests/apis/namespace/task/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/task/test.lua ================================================ function main() os.exec("xmake task0") os.exec("xmake ns1::task1") os.exec("xmake ns1::ns2::task2") end ================================================ FILE: tests/apis/namespace/task/xmake.lua ================================================ task("task0") set_menu {options = {}} on_run(function () print("task0") end) namespace("ns1", function () task("task1") set_menu {options = {}} on_run(function () print("NS1_TASK1") end) namespace("ns2", function() task("task2") set_menu {options = {}} on_run(function () print("NS2_TASK2") end) end) end) ================================================ FILE: tests/apis/namespace/toolchain/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/namespace/toolchain/src/bar.cpp ================================================ #include "bar.h" int sub(int a, int b) { return a - b; } ================================================ FILE: tests/apis/namespace/toolchain/src/bar.h ================================================ #ifdef __cplusplus extern "C" { #endif int sub(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/toolchain/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/namespace/toolchain/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/namespace/toolchain/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; return 0; } ================================================ FILE: tests/apis/namespace/toolchain/test.lua ================================================ function main() os.exec("xmake -vD") end ================================================ FILE: tests/apis/namespace/toolchain/xmake.lua ================================================ toolchain("toolchain0") on_load(function (toolchain) toolchain:add("defines", "TOOLCHAIN0") end) namespace("ns1", function () toolchain("toolchain1") on_load(function (toolchain) toolchain:add("defines", "NS1_TOOLCHAIN1") end) target("foo") set_kind("static") add_files("src/foo.cpp") set_toolchains("toolchain1") namespace("ns2", function() toolchain("toolchain2") on_load(function (toolchain) toolchain:add("defines", "NS2_TOOLCHAIN2") end) target("bar") set_kind("static") add_files("src/bar.cpp") set_toolchains("toolchain2") end) target("test") set_kind("binary") add_deps("foo", "ns2::bar") add_files("src/main.cpp") set_toolchains("toolchain0", "toolchain1", "ns2::toolchain2") end) ================================================ FILE: tests/apis/rules/src/empty.stub ================================================ ================================================ FILE: tests/apis/rules/src/index.md ================================================ ## hello xmake ================================================ FILE: tests/apis/rules/src/main.c ================================================ #include extern int test(int a, int b); int main(int argc, char **argv) { printf("1 + 1 = %d\n", test(1, 1)); return 0; } ================================================ FILE: tests/apis/rules/src/main2.c ================================================ #include extern int test(int a, int b); int main(int argc, char **argv) { printf("1 + 1 = %d\n", test(1, 1)); return 0; } ================================================ FILE: tests/apis/rules/src/man/man1.in ================================================ hello [name]! ================================================ FILE: tests/apis/rules/src/man/man2.in ================================================ hello [name]! ================================================ FILE: tests/apis/rules/src/man/man3.in ================================================ hello [name]! ================================================ FILE: tests/apis/rules/src/test.c.in ================================================ int test(int a, int b) { return a + b; } ================================================ FILE: tests/apis/rules/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/rules/xmake.lua ================================================ -- define rule: markdown rule("markdown") set_extensions(".md", ".markdown") on_load(function (target) print("markdown: on_load") end) on_build_file(function (target, sourcefile) print("compile %s", sourcefile) os.cp(sourcefile, path.join(target:targetdir(), path.basename(sourcefile) .. ".html")) end) -- define rule: man rule("man") add_imports("core.project.rule") on_build_files(function (target, sourcefiles) for _, sourcefile in ipairs(sourcefiles) do print("generating man: %s", sourcefile) end end) -- define rule: c code rule("c code") add_imports("core.tool.compiler") before_build_file(function (target, sourcefile) print("before_build_file: ", sourcefile) end) on_build_file(function (target, sourcefile, opt) import("core.theme.theme") import("utils.progress") progress.show(opt.progress, "compiling.$(mode) %s", sourcefile) local objectfile_o = os.tmpfile() .. ".o" local sourcefile_c = os.tmpfile() .. ".c" os.cp(sourcefile, sourcefile_c) compiler.compile(sourcefile_c, objectfile_o) table.insert(target:objectfiles(), objectfile_o) end) after_build_file(function (target, sourcefile) print("after_build_file: ", sourcefile) end) -- define rule: stub3 rule("stub3") add_deps("markdown") on_load(function (target) print("rule(stub3): on_load") end) -- define rule: stub2 rule("stub2") add_deps("stub3") on_load(function (target) print("rule(stub2): on_load") end) before_build(function (target) print("rule(stub2): before_build") end) after_build(function (target) print("rule(stub2): after_build") end) before_build_files(function (target) print("rule(stub2): before_build_files") end) after_build_files(function (target) print("rule(stub2): after_build_files") end) -- define rule: stub1 rule("stub1") add_deps("stub2") on_load(function (target) print("rule(stub1): on_load") end) before_build(function (target) print("rule(stub1): before_build") end) after_build(function (target) print("rule(stub1): after_build") end) before_clean(function (target) print("rule(stub1): before_clean") end) after_clean(function (target) print("rule(stub1): after_clean") end) before_install(function (target) print("rule(stub1): before_install") end) on_install(function (target) print("rule(stub1): on_install") end) after_install(function (target) print("rule(stub1): after_install") end) before_uninstall(function (target) print("rule(stub1): before_uninstall") end) on_uninstall(function (target) print("rule(stub1): on_uninstall") end) after_uninstall(function (target) print("rule(stub1): after_uninstall") end) before_package(function (target) print("rule(stub1): before_package") end) on_package(function (target) print("rule(stub1): on_package") end) after_package(function (target) print("rule(stub1): after_package") end) before_run(function (target) print("rule(stub1): before_run") end) on_run(function (target) print("rule(stub1): on_run") end) after_run(function (target) print("rule(stub1): after_run") end) -- define rule: stub0b rule("stub0b") before_build_file(function (target, sourcefile) print("rule(stub0b): before_build_file", sourcefile) end) -- define rule: stub0a rule("stub0a") after_build_file(function (target, sourcefile) print("rule(stub0a): after_build_file", sourcefile) end) -- define target target("test") -- set kind set_kind("binary") -- add rules add_rules("stub1") -- add files add_files("src/*.c|main2.c", {rules = {"stub0a", "stub0b"}}) add_files("src/main2.c", {rules = {"stub0a", "stub0b", override = true}}) add_files("src/man/*.in", {rules = "man"}) add_files("src/index.md") add_files("src/test.c.in", {rules = "c code"}) before_build(function (target) print("target: before_build") end) after_build(function (target) print("target: after_build") end) ================================================ FILE: tests/apis/rules_inject_deps/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/apis/rules_inject_deps/src/main.cpp2 ================================================ ================================================ FILE: tests/apis/rules_inject_deps/test.lua ================================================ function main() os.exec("xmake -j1") end ================================================ FILE: tests/apis/rules_inject_deps/xmake.lua ================================================ rule("cppfront") set_extensions(".cpp2") add_orders("cppfront", "c++.build") on_build_file(function (target, sourcefile, opt) print("build cppfront file") local objectfile = target:objectfile(sourcefile:gsub("cpp2", "cpp")) assert(not os.isfile(objectfile), "invalid rule order!") end) target("test") set_kind("binary") add_rules("cppfront") add_files("src/*.cpp") add_files("src/*.cpp2") before_build_file(function (target, sourcefile, opt) local objectfile = target:objectfile(sourcefile) os.tryrm(objectfile) end) ================================================ FILE: tests/apis/rules_order/src/main.c ================================================ #include int main(int argc, char **argv) { return 0; } ================================================ FILE: tests/apis/rules_order/src/test.man ================================================ ## hello xmake ================================================ FILE: tests/apis/rules_order/src/test.md ================================================ ## hello xmake ================================================ FILE: tests/apis/rules_order/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/rules_order/xmake.lua ================================================ rule("markdown") set_extensions(".md", ".markdown") add_orders("man", "markdown") before_build(function (target) print("before_build: markdown") end) after_build(function (target) print("after_build: markdown") end) before_build_file(function (target, sourcefile) print("before_build_file: %s", sourcefile) end) on_build_file(function (target, sourcefile) print("on_build_file: %s", sourcefile) end) after_build_file(function (target, sourcefile) print("after_build_file: %s", sourcefile) end) rule("man") set_extensions(".man") before_build(function (target) print("before_build: man") end) after_build(function (target) print("after_build: man") end) before_build_file(function (target, sourcefile) print("before_build_file: %s", sourcefile) end) on_build_file(function (target, sourcefile) print("on_build_file: %s", sourcefile) end) after_build_file(function (target, sourcefile) print("after_build_file: %s", sourcefile) end) target("test") set_kind("binary") add_rules("markdown", "man") add_files("src/*.c") add_files("src/*.md") add_files("src/*.man") before_build_file(function (target, sourcefile) print("target.before_build_file: %s", sourcefile) end) --[[ on_build_file(function (target, sourcefile) print("target.on_build_file: %s", sourcefile) end)]] after_build_file(function (target, sourcefile) print("target.after_build_file: %s", sourcefile) end) ================================================ FILE: tests/apis/rules_override_cxx/src/main.xx ================================================ #include int main(int argc, char** argv) { return 0; } ================================================ FILE: tests/apis/rules_override_cxx/src/test.cc ================================================ ================================================ FILE: tests/apis/rules_override_cxx/test.lua ================================================ function main() os.exec("xmake") end ================================================ FILE: tests/apis/rules_override_cxx/xmake.lua ================================================ rule("xx") add_deps("c++") on_load(function (target) -- add .xx local rule = target:rule("c++.build"):clone() rule:set("extensions", ".xx") target:rule_add(rule) -- patch sourcebatch for .xx local sourcebatch = target:sourcebatches()["c++.build"] sourcebatch.sourcekind = "cxx" sourcebatch.objectfiles = {} sourcebatch.dependfiles = {} for _, sourcefile in ipairs(sourcebatch.sourcefiles) do local objectfile = target:objectfile(sourcefile) local dependfile = target:dependfile(objectfile) table.insert(sourcebatch.objectfiles, objectfile) table.insert(sourcebatch.dependfiles, dependfile) end -- force as c++ source file if target:is_plat("windows") then target:add("cxxflags", "/TP") else target:add("cxxflags", "-x c++") end end) target("test") set_kind("binary") add_rules("xx") add_files("src/*.xx", "src/*.cc") ================================================ FILE: tests/apis/set_toolchains/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/set_toolchains/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/set_toolchains/src/test.cpp ================================================ #include "foo.h" #include using namespace std; int main(int argc, char **argv) { cout << "add(1, 2) = " << add(1, 2) << endl; return 0; } ================================================ FILE: tests/apis/set_toolchains/xmake.lua ================================================ toolchain("myclang") set_kind("standalone") set_toolset("cc", "clang") set_toolset("cxx", "clang", "clang++") set_toolset("ld", "clang++", "clang") set_toolset("sh", "clang++", "clang") set_toolset("ar", "ar") set_toolset("strip", "strip") set_toolset("mm", "clang") set_toolset("mxx", "clang", "clang++") set_toolset("as", "clang") add_defines("MYCLANG") toolchain_end() add_rules("mode.debug", "mode.release") target("test") set_kind("static") add_files("src/foo.cpp") set_toolset("ar", "ar") target("demo") set_kind("binary") add_deps("test") add_files("src/test.cpp") set_toolchains("myclang") ================================================ FILE: tests/apis/target_get_from/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/apis/target_get_from/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/apis/target_get_from/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/apis/target_get_from/src/main.cpp ================================================ #include "foo.h" #include using namespace std; int main(int argc, char **argv) { cout << "add(1, 2) = " << add(1, 2) << endl; return 0; } ================================================ FILE: tests/apis/target_get_from/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("zlib") option("bar") set_default(true) add_defines("BAR") target("foo") set_kind("static") add_files("src/foo.cpp") add_defines("foo") add_defines("FOO", {public = true}) add_options("bar") add_linkgroups("m", "pthread", {group = true}) target("test") set_kind("binary") add_deps("foo") add_files("src/main.cpp") add_defines("TEST") add_packages("zlib") on_config(function (target) print("self", target:get_from("defines", "self")) print("dep::foo", target:get_from("defines", "dep::foo")) print("dep::*", target:get_from("defines", "dep::*")) print("dep::foo/option::bar", target:get_from("defines", "dep::foo/option::bar")) print("dep::foo/option::*", target:get_from("defines", "dep::foo/option::*")) print("*", target:get_from("defines", "*")) print("package::zlib", target:get_from("links", "package::zlib")) print("extraconf(dep::foo)", target:extraconf_from("linkgroups", "dep::foo")) end) ================================================ FILE: tests/apis/xxx_script/test.lua ================================================ function main() os.exec("xmake f -c") os.exec("xmake") if os.host() == "macosx" then os.exec("xmake f -p iphoneos") os.exec("xmake") os.exec("xmake f -p iphoneos -a arm64") os.exec("xmake") end end ================================================ FILE: tests/apis/xxx_script/xmake.lua ================================================ target("test") before_build("iphoneos|arm64", "macosx", function (target) assert(target:is_plat("macosx") or (target:is_plat("iphoneos") and target:is_arch("arm64"))) end) before_build(function (target) print("before_build") end) on_build("macosx|native", function (target) print("build macosx:native") end) on_build(function (target) print("build") end) after_build(function (target) print("after_build") end) after_build("!macosx", function (target) print("after_build !macosx") end) after_build("!linux", function (target) print("after_build !linux") end) after_build("!iphoneos", function (target) print("after_build !iphoneos") end) after_build("linux|*", function (target) assert(target:is_plat("linux")) end) ================================================ FILE: tests/benchmarks/async/runjobs.lua ================================================ import("async.runjobs") function test_run(total, comax) local f = function () end local t1 = os.mclock() runjobs("test", f, {total = total, comax = comax}) t1 = os.mclock() - t1 local n = total local t2 = os.mclock() while n ~= 0 do f() n = n - 1 end t2 = os.mclock() - t2 print("runjobs(%d/%d): %d ms, plain: %d ms", total, comax, t1, t2) end function test_run_proc(total, comax) local f = function () os.runv(os.programfile(), {"--version"}) end local t1 = os.mclock() runjobs("test", f, {total = total, comax = comax}) t1 = os.mclock() - t1 print("runjobs_proc(%d/%d): %d ms", total, comax, t1) end function main() test_run(10000, 1) test_run(10000, 10) test_run(10000, 100) test_run_proc(1000, 10) end ================================================ FILE: tests/benchmarks/build_targets/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/benchmarks/build_targets/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) project(test) foreach(i RANGE 1 30) add_executable(test${i} src/test_${i}.cpp) endforeach() ================================================ FILE: tests/benchmarks/build_targets/meson.build ================================================ project('test', 'cpp') foreach i : range(1, 31) executable('test' + i.to_string(), 'src/test_' + i.to_string() + '.cpp') endforeach ================================================ FILE: tests/benchmarks/build_targets/src/test_1.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_10.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_11.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_12.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_13.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_14.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_15.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_16.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_17.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_18.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_19.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_2.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_20.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_21.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_22.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_23.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_24.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_25.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_26.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_27.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_28.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_29.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_3.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_30.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_4.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_5.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_6.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_7.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_8.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/src/test_9.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/build_targets/test.lua ================================================ import("lib.detect.find_tool") import("core.tool.toolchain") function run_test(func) local dt = os.mclock() local n = 2 local delta = 0 for i = 1, n do local e = func() delta = delta + e end dt = os.mclock() - dt - delta return math.floor(dt / n) end function test_build(t) -- 20% random trigger if math.random() > 0.2 then return end if xmake.is_embed() then return end local jobs = tostring(os.default_njob()) -- xmake local xmake_dt = run_test(function() local dt = os.mclock() os.tryrm("build") os.tryrm(".xmake") dt = os.mclock() - dt os.runv("xmake", {"-j" .. jobs}) return dt end) print("build targets/30: xmake: %d ms", xmake_dt) -- cmake local cmake = find_tool("cmake") if cmake then local cmake_default_dt = run_test(function() local dt = os.mclock() os.tryrm("build") os.mkdir("build") dt = os.mclock() - dt os.runv(cmake.program, {".."}, {curdir = "build"}) os.runv(cmake.program, {"--build", ".", "-j" .. jobs}, {curdir = "build"}) return dt end) print("build targets/30: cmake/default: %d ms", cmake_default_dt) t:require((cmake_default_dt > xmake_dt) or (cmake_default_dt + 3000 > xmake_dt)) local ninja = find_tool("ninja") if ninja then local configs = {} local envs if is_host("windows") then table.insert(configs, "-DCMAKE_MAKE_PROGRAM=" .. ninja.program) local msvc = toolchain.load("msvc") if msvc:check() then table.insert(configs, "-DCMAKE_CXX_COMPILER=" .. (msvc:tool("cxx"))) table.insert(configs, "-DCMAKE_C_COMPILER=" .. (msvc:tool("cc"))) envs = os.joinenvs(msvc:runenvs()) end end local cmake_ninja_dt = run_test(function () local dt = os.mclock() os.tryrm("build") os.mkdir("build") dt = os.mclock() - dt os.runv(cmake.program, table.join("..", "-G", "Ninja", configs), {curdir = "build", envs = envs}) os.runv(cmake.program, {"--build", ".", "-j" .. jobs}, {curdir = "build", envs = envs}) return dt end) print("build targets/30: cmake/ninja: %d ms", cmake_ninja_dt) t:require((cmake_ninja_dt > xmake_dt) or (cmake_ninja_dt + 3000 > xmake_dt)) end local make = find_tool("make") if make and not is_subhost("windows") then local cmake_makefile_dt = run_test(function() local dt = os.mclock() os.tryrm("build") os.mkdir("build") dt = os.mclock() - dt os.runv(cmake.program, {"..", "-G", "Unix Makefiles"}, {curdir = "build"}) os.runv(cmake.program, {"--build", ".", "-j" .. jobs}, {curdir = "build"}) return dt end) print("build targets/30: cmake/makefile: %d ms", cmake_makefile_dt) t:require((cmake_makefile_dt > xmake_dt) or (cmake_makefile_dt + 3000 > xmake_dt)) end end -- meson local meson = find_tool("meson") if meson then local meson_dt = run_test(function() local dt1 = os.mclock() os.tryrm("build") dt1 = os.mclock() - dt1 os.runv(meson.program, {"setup", "build"}) -- ccache will cache object files globally, which may affect the results of the second run. local dt2 = os.mclock() io.replace("build/build.ninja", "ccache", "") dt2 = os.mclock() - dt2 os.runv(meson.program, {"compile", "-j", jobs, "-C", "build"}) return dt1 + dt2 end) print("build targets/30: meson: %d ms", meson_dt) t:require((meson_dt > xmake_dt) or (meson_dt + 3000 > xmake_dt)) end end ================================================ FILE: tests/benchmarks/build_targets/xmake.lua ================================================ add_rules("mode.debug", "mode.release") for i = 1, 30 do target("test" .. i) set_kind("binary") add_files("src/test_" .. tostring(i) .. ".cpp") end ================================================ FILE: tests/benchmarks/config_targets/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/benchmarks/config_targets/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) project(test) foreach(i RANGE 1 1000) add_executable(test${i} src/main.cpp) endforeach() ================================================ FILE: tests/benchmarks/config_targets/meson.build ================================================ project('test', 'cpp') foreach i : range(1, 1001) executable('test' + i.to_string(), 'src/main.cpp') endforeach ================================================ FILE: tests/benchmarks/config_targets/src/main.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/benchmarks/config_targets/test.lua ================================================ import("lib.detect.find_tool") import("core.tool.toolchain") function run_test(func) local dt = os.mclock() local n = 2 local delta = 0 for i = 1, n do local e = func() delta = delta + e end dt = os.mclock() - dt - delta return math.floor(dt / n) end function test_config(t) -- 20% random trigger if math.random() > 0.2 then return end if xmake.is_embed() then return end -- xmake local xmake_dt = run_test(function () local dt = os.mclock() os.tryrm("build") os.tryrm(".xmake") dt = os.mclock() - dt os.runv("xmake", {"config", "-c"}) return dt end) print("config targets/1k: xmake: %d ms", xmake_dt) -- cmake local cmake = find_tool("cmake") if cmake then local cmake_default_dt = run_test(function() local dt = os.mclock() os.tryrm("build") os.mkdir("build") dt = os.mclock() - dt os.runv(cmake.program, {".."}, {curdir = "build"}) return dt end) print("config targets/1k: cmake/default: %d ms", cmake_default_dt) t:require((cmake_default_dt > xmake_dt) or (cmake_default_dt + 2000 > xmake_dt)) local ninja = find_tool("ninja") if ninja then local configs = {} local envs if is_host("windows") then table.insert(configs, "-DCMAKE_MAKE_PROGRAM=" .. ninja.program) local msvc = toolchain.load("msvc") if msvc:check() then table.insert(configs, "-DCMAKE_CXX_COMPILER=" .. (msvc:tool("cxx"))) table.insert(configs, "-DCMAKE_C_COMPILER=" .. (msvc:tool("cc"))) envs = os.joinenvs(msvc:runenvs()) end end local cmake_ninja_dt = run_test(function() local dt = os.mclock() os.tryrm("build") os.mkdir("build") dt = os.mclock() - dt os.runv(cmake.program, table.join("..", "-G", "Ninja", configs), {curdir = "build", envs = envs}) return dt end) print("config targets/1k: cmake/ninja: %d ms", cmake_ninja_dt) t:require((cmake_ninja_dt > xmake_dt) or (cmake_ninja_dt + 2000 > xmake_dt)) end if find_tool("make") and not is_subhost("windows") then local cmake_makefile_dt = run_test(function () local dt = os.mclock() os.tryrm("build") os.mkdir("build") dt = os.mclock() - dt os.runv(cmake.program, {"..", "-G", "Unix Makefiles"}, {curdir = "build"}) return dt end) print("config targets/1k: cmake/makefile: %d ms", cmake_makefile_dt) t:require((cmake_makefile_dt > xmake_dt) or (cmake_makefile_dt + 2000 > xmake_dt)) end end -- meson local meson = find_tool("meson") if meson then local meson_dt = run_test(function() local dt = os.mclock() os.tryrm("build") dt = os.mclock() - dt os.runv(meson.program, {"setup", "build"}) return dt end) print("config targets/1k: meson: %d ms", meson_dt) t:require((meson_dt > xmake_dt) or (meson_dt + 2000 > xmake_dt)) end end ================================================ FILE: tests/benchmarks/config_targets/xmake.lua ================================================ add_rules("mode.debug", "mode.release") for i = 1, 1000 do target("test" .. i) set_kind("binary") add_files("src/main.cpp") end ================================================ FILE: tests/benchmarks/hash.lua ================================================ import("core.base.bytes") local COUNT = 1000000 function test_md5(data) data = bytes(data) local h local n = COUNT / 10000 local t = os.mclock() for i = 1, n do h = hash.md5(data) end t = os.mclock() - t print("md5(%d): %d ms, hash: %s", COUNT, t * 10000, h) end function test_sha1(data) data = bytes(data) local h local n = COUNT / 10000 local t = os.mclock() for i = 1, n do h = hash.sha1(data) end t = os.mclock() - t print("sha1(%d): %d ms, hash: %s", COUNT, t * 10000, h) end function test_sha256(data) data = bytes(data) local h local n = COUNT / 10000 local t = os.mclock() for i = 1, n do h = hash.sha256(data) end t = os.mclock() - t print("sha256(%d): %d ms, hash: %s", COUNT, t * 10000, h) end function test_uuid(data) local h local n = COUNT / 10000 local t = os.mclock() for i = 1, n do h = hash.uuid(data) end t = os.mclock() - t print("uuid(%d): %d ms, hash: %s", COUNT, t * 10000, h) end function test_xxhash32(data) data = bytes(data) local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.xxhash32(data) end t = os.mclock() - t print("xxhash32(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_xxhash64(data) data = bytes(data) local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.xxhash64(data) end t = os.mclock() - t print("xxhash64(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_xxhash128(data) data = bytes(data) local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.xxhash128(data) end t = os.mclock() - t print("xxhash128(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_strhash32(data) local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.strhash32(data) end t = os.mclock() - t print("strhash32(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_strhash64(data) local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.strhash64(data) end t = os.mclock() - t print("strhash64(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_strhash128(data) local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.strhash128(data) end t = os.mclock() - t print("strhash128(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_random_uuid() local h local n = COUNT / 1000 local t = os.mclock() for i = 1, n do h = hash.uuid() end t = os.mclock() - t print("uuid(%d): %d ms, hash: %s", COUNT, t * 1000, h) end function test_rand32() local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.rand32() end t = os.mclock() - t print("rand32(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_rand64() local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.rand64() end t = os.mclock() - t print("rand64(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_rand128() local h local n = COUNT / 10 local t = os.mclock() for i = 1, n do h = hash.rand128() end t = os.mclock() - t print("rand128(%d): %d ms, hash: %s", COUNT, t * 10, h) end function test_longstr() print("========================================== test long string ==========================================") local data = "" for i = 1, 10000 do data = data .. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" end test_md5(data) test_sha1(data) test_sha256(data) test_uuid(data) test_xxhash32(data) test_xxhash64(data) test_xxhash128(data) test_strhash32(data) test_strhash64(data) test_strhash128(data) end function test_shortstr() print("========================================== test short string ==========================================") COUNT = COUNT * 100 local data = "" for i = 1, 10 do data = data .. "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" end test_md5(data) test_sha1(data) test_sha256(data) test_uuid(data) test_xxhash32(data) test_xxhash64(data) test_xxhash128(data) test_strhash32(data) test_strhash64(data) test_strhash128(data) end function test_random() print("========================================== test random ==========================================") test_random_uuid() test_rand32() test_rand64() test_rand128() end function main() test_longstr() test_shortstr() test_random() end ================================================ FILE: tests/cli/test.lua ================================================ import("core.base.cli") function test_args(t) local parsed = cli.parse("abc def") t:are_equal(#parsed, 2) t:are_equal(parsed[1].type, "arg") t:are_equal(parsed[1].value, "abc") t:are_equal(parsed[2].type, "arg") t:are_equal(parsed[2].value, "def") end function test_args_escaped(t) local parsed = cli.parse([[a\\bc "def \"g"]]) t:are_equal(#parsed, 2) t:are_equal(parsed[1].type, "arg") t:are_equal(parsed[1].value, "a\\bc") t:are_equal(parsed[2].type, "arg") t:are_equal(parsed[2].value, "def \"g") end function test_long(t) local parsed = cli.parse([[--long-flag --long-option="1 3" --long-option:=2 args]]) t:are_equal(#parsed, 4) t:are_equal(parsed[1].type, "flag") t:are_equal(parsed[1].key, "long-flag") t:are_equal(parsed[2].type, "option") t:are_equal(parsed[2].key, "long-option") t:are_equal(parsed[2].value, "1 3") t:are_equal(parsed[3].type, "option") t:are_equal(parsed[3].key, "long-option") t:are_equal(parsed[3].value, "=2") end function test_raw(t) local parsed = cli.parse([[--long-flag -- --long-option="1 3" --long-option:=2 args -rx]]) t:are_equal(#parsed, 6) t:are_equal(parsed[1].type, "flag") t:are_equal(parsed[1].key, "long-flag") t:are_equal(parsed[2].type, "sep") t:are_equal(parsed[3].type, "arg") t:are_equal(parsed[3].value, "--long-option=1 3") t:are_equal(parsed[4].type, "arg") t:are_equal(parsed[4].value, "--long-option:=2") t:are_equal(parsed[5].type, "arg") t:are_equal(parsed[5].value, "args") t:are_equal(parsed[6].type, "arg") t:are_equal(parsed[6].value, "-rx") end function test_short1(t) local parsed = cli.parse([[-rx args -args]], {}) t:are_equal(#parsed, 3) t:are_equal(parsed[1].type, "option") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[1].value, "x") t:are_equal(parsed[3].type, "arg") t:are_equal(parsed[3].value, "-args") end function test_short2(t) local parsed = cli.parse([[-r x args args]], {}) t:are_equal(#parsed, 3) t:are_equal(parsed[1].type, "option") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[1].value, "x") end function test_short3(t) local parsed = cli.parse([[-r"x d" args args]], {}) t:are_equal(#parsed, 3) t:are_equal(parsed[1].type, "option") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[1].value, "x d") end function test_short4(t) local parsed = cli.parse([["-rx d" args args]], {}) t:are_equal(#parsed, 3) t:are_equal(parsed[1].type, "option") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[1].value, "x d") end function test_short5(t) local parsed = cli.parse([[-r "x d" args args]], {}) t:are_equal(#parsed, 3) t:are_equal(parsed[1].type, "option") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[1].value, "x d") end function test_short_flags1(t) local parsed = cli.parse([[-rx args args]], {"r"}) t:are_equal(#parsed, 3) t:are_equal(parsed[1].type, "flag") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[2].type, "option") t:are_equal(parsed[2].key, "x") t:are_equal(parsed[2].value, "args") end function test_short_flags2(t) local parsed = cli.parse([[-r x args args]], {"r"}) t:are_equal(#parsed, 4) t:are_equal(parsed[1].type, "flag") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[2].type, "arg") t:are_equal(parsed[2].value, "x") end function test_short_flags3(t) local parsed = cli.parse([[-r"x d" args args]], {"r"}) t:are_equal(#parsed, 4) t:are_equal(parsed[1].type, "flag") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[2].type, "option") t:are_equal(parsed[2].key, "x") t:are_equal(parsed[2].value, " d") end function test_short_flags4(t) local parsed = cli.parse([["-rx d" args args]], {"r"}) t:are_equal(#parsed, 4) t:are_equal(parsed[1].type, "flag") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[2].type, "option") t:are_equal(parsed[2].key, "x") t:are_equal(parsed[2].value, " d") end function test_short_flags5(t) local parsed = cli.parse([[-r "x d" args args]], {"r"}) t:are_equal(#parsed, 4) t:are_equal(parsed[1].type, "flag") t:are_equal(parsed[1].key, "r") t:are_equal(parsed[2].type, "arg") t:are_equal(parsed[2].value, "x d") end ================================================ FILE: tests/cli/utils/test.lua ================================================ function test_version(t) local output = os.iorunv("xmake", {"--version"}) local vstr = output:match("xmake v(.-),") t:are_equal(vstr, tostring(xmake.version())) end function test_help(t) import("core.base.task") for _, taskname in ipairs(task.names()) do os.runv("xmake", {taskname, "--help"}) end end ================================================ FILE: tests/modules/async/run_callback.lua ================================================ import("core.base.scheduler") import("async.runjobs") function _jobfunc(index, total, opt) print("%s: run job (%d/%d)", scheduler.co_running(), index, total) local dt = os.mclock() os.sleep(1000) dt = os.mclock() - dt print("%s: run job (%d/%d) end, progress: %s, dt: %d ms", scheduler.co_running(), index, total, opt.progress, dt) end function main() print("==================================== test callback ====================================") local t = os.mclock() runjobs("test", _jobfunc, {total = 100, comax = 6, timeout = 1000, timer = function (running_jobs_indices) print("%s: timeout (%d ms), running: %s", scheduler.co_running(), os.mclock() - t, table.concat(running_jobs_indices, ",")) end}) end ================================================ FILE: tests/modules/async/run_jobgraph.lua ================================================ import("core.base.scheduler") import("async.jobgraph") import("async.runjobs") function _jobfunc(index, total, opt) print("%s: run job (%d/%d)", scheduler.co_running(), index, total) local dt = os.mclock() os.sleep(1000) dt = os.mclock() - dt print("%s: run job (%d/%d) end, progress: %s, dt: %d ms", scheduler.co_running(), index, total, opt.progress, dt) end function _test_basic() print("==================================== test basic ====================================") local jobs = jobgraph.new() jobs:add("job/root", _jobfunc) for i = 1, 3 do jobs:add("job/" .. i, _jobfunc) for j = 1, 50 do jobs:add("job/" .. i .. "/" .. j, _jobfunc) jobs:add_orders("job/" .. i .. "/" .. j, "job/" .. i, "job/root") end end t = os.mclock() runjobs("test", jobs, {comax = 6, timeout = 1000, timer = function (running_jobs_indices) print("%s: timeout (%d ms), running: %s", scheduler.co_running(), os.mclock() - t, table.concat(running_jobs_indices, ",")) end}) end function _test_group() print("==================================== test group ====================================") local jobs = jobgraph.new() jobs:add("job/root", _jobfunc) for i = 1, 3 do jobs:add("job/" .. i, _jobfunc, {groups = "bar"}) jobs:group("foo", function () for j = 1, 50 do jobs:add("job/" .. i .. "/" .. j, _jobfunc) end end) end jobs:add_orders("foo", "bar", "job/root") t = os.mclock() runjobs("test", jobs, {comax = 6, timeout = 1000, timer = function (running_jobs_indices) print("%s: timeout (%d ms), running: %s", scheduler.co_running(), os.mclock() - t, table.concat(running_jobs_indices, ",")) end}) end function main() _test_basic() _test_group() end ================================================ FILE: tests/modules/async/run_jobpool.lua ================================================ import("core.base.scheduler") import("private.async.jobpool") import("async.runjobs") function _jobfunc(index, total, opt) print("%s: run job (%d/%d)", scheduler.co_running(), index, total) local dt = os.mclock() os.sleep(1000) dt = os.mclock() - dt print("%s: run job (%d/%d) end, progress: %s, dt: %d ms", scheduler.co_running(), index, total, opt.progress, dt) end function main() print("==================================== test jobpool ====================================") local jobs = jobpool.new() local root = jobs:addjob("job/root", _jobfunc) for i = 1, 3 do local job = jobs:addjob("job/" .. i, _jobfunc, {rootjob = root}) for j = 1, 50 do jobs:addjob("job/" .. i .. "/" .. j, _jobfunc, {rootjob = job}) end end t = os.mclock() runjobs("test", jobs, {comax = 6, timeout = 1000, timer = function (running_jobs_indices) print("%s: timeout (%d ms), running: %s", scheduler.co_running(), os.mclock() - t, table.concat(running_jobs_indices, ",")) end}) end ================================================ FILE: tests/modules/binutils/test.lua ================================================ import("core.base.binutils") function test_format(t) local tempdir = "temp/binutils_format" os.tryrm(tempdir) os.mkdir(tempdir) local unknown = path.join(tempdir, "unknown.bin") io.writefile(unknown, "12345678") local format = binutils.format(unknown) t:are_equal(format, "unknown") local scriptfile = path.join(tempdir, "a.sh") io.writefile(scriptfile, "#!/bin/sh\nexit 0\n") t:are_equal(binutils.format(scriptfile), "shebang") local apefile = path.join(tempdir, "a.ape") io.writefile(apefile, "MZqFpD00") t:are_equal(binutils.format(apefile), "ape") local apecom = path.join(tempdir, "a.com") io.writefile(apecom, "MZqFpD00") t:are_equal(binutils.format(apecom), "ape") local comfile = path.join(tempdir, "b.com") io.writefile(comfile, "12345678") t:are_equal(binutils.format(comfile), "unknown") local programfile = os.programfile() if programfile then local expected = "elf" if is_host("windows") then expected = "pe" elseif is_host("macosx", "iphoneos", "watchos", "appletvos") then expected = "macho" end local format = binutils.format(programfile) if format ~= "ape" then t:are_equal(format, expected) end end local ar = path.join(tempdir, "a.a") io.writefile(ar, "!\n") t:are_equal(binutils.format(ar), "ar") local wasmso = path.join(tempdir, "libfoo.so") io.writefile(wasmso, string.char(0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)) t:are_equal(binutils.format(wasmso), "wasm") local elf = path.join(tempdir, "a.elf") io.writefile(elf, string.char(0x7f, string.byte("E"), string.byte("L"), string.byte("F"), 0, 0, 0, 0)) t:are_equal(binutils.format(elf), "elf") local macho = path.join(tempdir, "a.macho") io.writefile(macho, string.char(0xfe, 0xed, 0xfa, 0xcf, 0, 0, 0, 0)) t:are_equal(binutils.format(macho), "macho") local coff = path.join(tempdir, "a.obj") io.writefile(coff, string.char(0x4c, 0x01, 0, 0, 0, 0, 0, 0)) t:are_equal(binutils.format(coff), "coff") local pefile = path.join(tempdir, "a.exe") local pe = {} for _ = 1, 0x44 do table.insert(pe, 0) end pe[1] = string.byte("M") pe[2] = string.byte("Z") pe[0x3c + 1] = 0x40 pe[0x3c + 2] = 0 pe[0x3c + 3] = 0 pe[0x3c + 4] = 0 pe[0x40 + 1] = string.byte("P") pe[0x40 + 2] = string.byte("E") pe[0x40 + 3] = 0 pe[0x40 + 4] = 0 io.writefile(pefile, string.char(table.unpack(pe))) t:are_equal(binutils.format(pefile), "pe") os.tryrm(tempdir) end function test_deplibs(t) local tempdir = "temp/binutils_deplibs" os.tryrm(tempdir) os.mkdir(tempdir) local wasmso = path.join(tempdir, "libfoo.so") io.writefile(wasmso, string.char(0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)) local libs = binutils.deplibs(wasmso) t:are_equal(#libs, 0) os.tryrm(tempdir) end function test_readsyms(t) local tempdir = "temp/binutils_readsyms" os.tryrm(tempdir) os.mkdir(tempdir) local function _writebin(filepath, data) io.writefile(filepath, data, {encoding = "binary"}) end local wasmso = path.join(tempdir, "libfoo.so") _writebin(wasmso, string.char( 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0b, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x03, 0x62, 0x61, 0x72, 0x00, 0x00, 0x07, 0x07, 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x00, 0x00)) local results = binutils.readsyms(wasmso) t:are_equal(#results, 1) t:are_equal(results[1].objectfile, "libfoo.so") t:are_equal(#results[1].symbols, 2) t:are_equal(results[1].symbols[1].name, "bar") t:are_equal(results[1].symbols[1].type, "U") t:are_equal(results[1].symbols[2].name, "foo") t:are_equal(results[1].symbols[2].type, "T") local wasmso64 = path.join(tempdir, "libfoo64.so") _writebin(wasmso64, string.char( 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0c, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x03, 0x6d, 0x65, 0x6d, 0x02, 0x04, 0x01, 0x07, 0x07, 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x00, 0x00)) local results64 = binutils.readsyms(wasmso64) t:are_equal(#results64, 1) t:are_equal(results64[1].objectfile, "libfoo64.so") t:are_equal(#results64[1].symbols, 2) t:are_equal(results64[1].symbols[1].name, "mem") t:are_equal(results64[1].symbols[1].type, "U") t:are_equal(results64[1].symbols[2].name, "foo") t:are_equal(results64[1].symbols[2].type, "T") local wasmlink = path.join(tempdir, "liblink.so") _writebin(wasmlink, string.char( 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b, 0x00, 0x13, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x69, 0x6e, 0x67, 0x02, 0x08, 0x08, 0x01, 0x00, 0x00, 0x00, 0x03, 0x61, 0x64, 0x64)) local resultslink = binutils.readsyms(wasmlink) t:are_equal(#resultslink, 1) t:are_equal(resultslink[1].objectfile, "liblink.so") t:are_equal(#resultslink[1].symbols, 1) t:are_equal(resultslink[1].symbols[1].name, "add") t:are_equal(resultslink[1].symbols[1].type, "T") local wasmar = path.join(tempdir, "libbar.a") local function _pad(str, n) if #str < n then return str .. string.rep(" ", n - #str) end return str:sub(1, n) end local function _ar_header(name, size) return _pad(name, 16) .. _pad("0", 12) .. _pad("0", 6) .. _pad("0", 6) .. _pad("644", 8) .. _pad(tostring(size), 10) .. "`\n" end local wasmobj = string.char( 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b, 0x00, 0x13, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x69, 0x6e, 0x67, 0x02, 0x08, 0x08, 0x01, 0x00, 0x00, 0x00, 0x03, 0x61, 0x64, 0x64) local symtab = string.char(0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50) .. "add\0" local ardata = "!\n" .. _ar_header("/", #symtab) .. symtab .. ((#symtab % 2 == 1) and "\n" or "") .. _ar_header("foo.cpp.o/", #wasmobj) .. wasmobj .. ((#wasmobj % 2 == 1) and "\n" or "") _writebin(wasmar, ardata) local resultsar = binutils.readsyms(wasmar) t:are_equal(#resultsar, 1) t:are_equal(resultsar[1].objectfile, "foo.cpp.o") t:are_equal(#resultsar[1].symbols, 1) t:are_equal(resultsar[1].symbols[1].name, "add") t:are_equal(resultsar[1].symbols[1].type, "T") os.tryrm(tempdir) end ================================================ FILE: tests/modules/bloom_filter/test.lua ================================================ import("core.base.bloom_filter") function test_bloom_filter(t) local filter = bloom_filter.new() t:are_equal(filter:set("hello"), true) -- not found t:are_equal(filter:set("hello"), false) t:are_equal(filter:set("hello"), false) t:are_equal(filter:get("hello"), true) t:are_equal(filter:set("xmake"), true) -- not found t:are_equal(filter:set("xmake"), false) t:are_equal(filter:set("xmake"), false) t:are_equal(filter:get("xmake"), true) t:are_equal(filter:get("not exists"), false) local data = filter:data() local filter2 = bloom_filter.new() filter2:data_set(data) t:are_equal(filter2:get("hello"), true) t:are_equal(filter2:get("xmake"), true) t:are_equal(filter2:get("not exists"), false) end ================================================ FILE: tests/modules/bytes/test.lua ================================================ import("core.base.bytes") function test_ctor(t) t:are_equal(bytes("123456789"):str(), "123456789") t:are_equal(bytes(bytes("123456789")):str(), "123456789") t:are_equal(bytes(bytes("123456789"), 3, 5):str(), "345") t:are_equal(bytes("123456789"):size(), 9) t:are_equal(bytes(10):size(), 10) t:are_equal(bytes(bytes("123"), bytes("456"), bytes("789")):str(), "123456789") t:are_equal(bytes({bytes("123"), bytes("456"), bytes("789")}):str(), "123456789") end function test_clone(t) t:are_equal(bytes(10):clone():size(), 10) t:are_equal(bytes("123456789"):clone():str(), "123456789") end function test_slice(t) t:are_equal(bytes(10):slice(1, 2):size(), 2) t:are_equal(bytes("123456789"):slice(1, 4):str(), "1234") end function test_index(t) local b = bytes("123456789") t:are_equal(b[{1, 4}]:str(), "1234") t:will_raise(function() b[1] = string.byte('2') end) b = bytes(9) b[{1, 9}] = bytes("123456789") t:are_equal(b:str(), "123456789") b[1] = string.byte('2') t:are_equal(b:str(), "223456789") t:will_raise(function() b[100] = string.byte('2') end) end function test_concat(t) t:are_equal((bytes("123") .. bytes("456")):str(), "123456") t:are_equal(bytes(bytes("123"), bytes("456")):str(), "123456") end function test_copy(t) t:are_equal(bytes(9):copy("123456789"):str(), "123456789") t:are_equal(bytes(5):copy("123456789", 5, 9):str(), "56789") end function test_copy2(t) t:are_equal(bytes(18):copy("123456789"):copy2(10, "123456789"):str(), "123456789123456789") t:are_equal(bytes(14):copy("123456789"):copy2(10, "123456789", 5, 9):str(), "12345678956789") end function test_move(t) t:are_equal(bytes(9):copy("123456789"):move(5, 9):str(), "567896789") t:are_equal(bytes(9):copy("123456789"):move2(2, 5, 9):str(), "156789789") end function test_int(t) t:are_equal(bytes(1):u8_set(1, 1):u8(1), 1) t:are_equal(bytes(10):u8_set(5, 255):u8(5), 255) t:are_equal(bytes(10):u16le_set(5, 12346):u16le(5), 12346) t:are_equal(bytes(10):u16be_set(5, 12346):u16be(5), 12346) t:are_equal(bytes(20):u32le_set(5, 12345678):u32le(5), 12345678) t:are_equal(bytes(20):u32be_set(5, 12345678):u32be(5), 12345678) end ================================================ FILE: tests/modules/cache/test.lua ================================================ import("core.cache.memcache") import("core.cache.localcache") import("core.cache.globalcache") function test_memcache(t) memcache.set("mycache", "xyz", {1, 2, 3}) memcache.set2("mycache", "foo", "bar", "1") t:are_equal(memcache.get("mycache", "xyz"), {1, 2, 3}) t:are_equal(memcache.get2("mycache", "foo", "bar"), "1") memcache.clear("mycache") t:are_equal(memcache.get2("mycache", "foo", "bar"), nil) memcache.set2("mycache", "foo", "bar", "1") memcache.clear() t:are_equal(memcache.get("mycache", "xyz"), nil) t:are_equal(memcache.get2("mycache", "foo", "bar"), nil) end function test_localcache(t) localcache.set("mycache", "xyz", {1, 2, 3}) localcache.set2("mycache", "foo", "bar", "1") t:are_equal(localcache.get("mycache", "xyz"), {1, 2, 3}) t:are_equal(localcache.get2("mycache", "foo", "bar"), "1") localcache.clear("mycache") t:are_equal(localcache.get2("mycache", "foo", "bar"), nil) localcache.set2("mycache", "foo", "bar", "1") localcache.clear() t:are_equal(localcache.get("mycache", "xyz"), nil) t:are_equal(localcache.get2("mycache", "foo", "bar"), nil) end function test_globalcache(t) globalcache.set("mycache", "xyz", {1, 2, 3}) globalcache.set2("mycache", "foo", "bar", "1") t:are_equal(globalcache.get("mycache", "xyz"), {1, 2, 3}) t:are_equal(globalcache.get2("mycache", "foo", "bar"), "1") globalcache.clear("mycache") t:are_equal(globalcache.get2("mycache", "foo", "bar"), nil) globalcache.set2("mycache", "foo", "bar", "1") globalcache.clear() t:are_equal(globalcache.get("mycache", "xyz"), nil) t:are_equal(globalcache.get2("mycache", "foo", "bar"), nil) end ================================================ FILE: tests/modules/compress/test.lua ================================================ import("core.compress.lz4") function test_lz4(t) t:are_equal(lz4.decompress(lz4.compress("hello world")):str(), "hello world") t:are_equal(lz4.block_decompress(lz4.block_compress("hello world"), 11):str(), "hello world") local srcfile = os.tmpfile() .. ".src" local dstfile = os.tmpfile() .. ".dst" local dstfile2 = os.tmpfile() .. ".dst2" io.writefile(srcfile, "hello world") lz4.compress_file(srcfile, dstfile) lz4.decompress_file(dstfile, dstfile2) t:are_equal(io.readfile(srcfile), io.readfile(dstfile2)) end ================================================ FILE: tests/modules/devel/git/test.lua ================================================ import("devel.git") function test_asgiturl(t) t:are_equal(git.asgiturl("http://github.com/a/b"), "https://github.com/a/b.git") t:are_equal(git.asgiturl("http://github.com/a/b/"), "https://github.com/a/b.git") t:are_equal(git.asgiturl("HTTP://github.com//a/b/"), "https://github.com/a/b.git") t:are_equal(git.asgiturl("http://github.com//a/b/s"), nil) t:are_equal(git.asgiturl("https://github.com/a/b"), "https://github.com/a/b.git") t:are_equal(git.asgiturl("https://github.com/a/b.git"), "https://github.com/a/b.git") t:are_equal(git.asgiturl("HTTPS://GITHUB.com/a/b.git.git"), "https://github.com/a/b.git.git") t:are_equal(git.asgiturl("github:a/b"), "https://github.com/a/b.git") t:are_equal(git.asgiturl("github:a/b.git"), "https://github.com/a/b.git.git") t:are_equal(git.asgiturl("GitHub://a/b/"), "https://github.com/a/b.git") t:are_equal(git.asgiturl("github:a/b/c"), nil) end ================================================ FILE: tests/modules/fwatcher/on_created.lua ================================================ import("core.base.fwatcher") function main(watchdir) print("watch %s ..", watchdir) fwatcher.on_created(watchdir, function (filepath) print(filepath, "created") end) end ================================================ FILE: tests/modules/fwatcher/on_deleted.lua ================================================ import("core.base.fwatcher") function main(watchdir) print("watch %s ..", watchdir) fwatcher.on_deleted(watchdir, function (filepath) print(filepath, "deleted") end) end ================================================ FILE: tests/modules/fwatcher/on_modified.lua ================================================ import("core.base.fwatcher") function main(watchdir) print("watch %s ..", watchdir) fwatcher.on_modified(watchdir, function (filepath) print(filepath, "modified") end) end ================================================ FILE: tests/modules/fwatcher/sched_watchdir.lua ================================================ import("core.base.fwatcher") import("core.base.scheduler") function _watch(watchdir) print("watch %s ..", watchdir) fwatcher.add(watchdir) while true do local ok, event = fwatcher.wait(-1) if ok > 0 then print(event) end end end function _sleep() while true do print("sleep ..") os.sleep(1000) end end function main(watchdir) scheduler.co_start(_watch, watchdir) scheduler.co_start(_sleep) end ================================================ FILE: tests/modules/fwatcher/watchdir.lua ================================================ import("core.base.fwatcher") function main(watchdir) print("watch %s ..", watchdir) fwatcher.add(watchdir) while true do local ok, event = fwatcher.wait(-1) if ok > 0 then print(event) end end end ================================================ FILE: tests/modules/fwatcher/watchdirs.lua ================================================ import("core.base.fwatcher") function main(watchdir) print("watch %s ..", watchdir) fwatcher.watchdirs(watchdir, function (event) local status if event.type == fwatcher.ET_CREATE then status = "created" elseif event.type == fwatcher.ET_MODIFY then status = "modified" elseif event.type == fwatcher.ET_DELETE then status = "deleted" end print(event.path, status) end) end ================================================ FILE: tests/modules/graph/test.lua ================================================ import("core.base.graph") function test_topo_sort(t) local edges = { {0, 5}, {0, 2}, {0, 1}, {3, 6}, {3, 5}, {3, 4}, {5, 4}, {6, 4}, {6, 0}, {3, 2}, {1, 4}, } local dag = graph.new(true) for _, e in ipairs(edges) do dag:add_edge(e[1], e[2]) end local order_path = dag:topo_sort() local orders = {} for i, v in ipairs(order_path) do orders[v] = i end for _, e in ipairs(edges) do t:require(orders[e[1]] < orders[e[2]]) end dag = dag:reverse() order_path = dag:topo_sort() orders = {} for i, v in ipairs(order_path) do orders[v] = i end for _, e in ipairs(edges) do t:require(orders[e[1]] > orders[e[2]]) end end function test_paritail_topo_sort(t) local function partiail_topo_sort(dag) dag:partial_topo_sort_reset() local node, has_cycle local order_vertices = {} while true do node, has_cycle = dag:partial_topo_sort_next() if node then table.insert(order_vertices, node) dag:partial_topo_sort_remove(node) else if has_cycle then raise("has cycle!") end break end end return order_vertices, has_cycle end local edges = { {0, 5}, {0, 2}, {0, 1}, {3, 6}, {3, 5}, {3, 4}, {5, 4}, {6, 4}, {6, 0}, {3, 2}, {1, 4}, {2, 9}, } local dag = graph.new(true) for _, e in ipairs(edges) do dag:add_edge(e[1], e[2]) end local order_path = partiail_topo_sort(dag) local orders = {} for i, v in ipairs(order_path) do orders[v] = i end for _, e in ipairs(edges) do t:require(orders[e[1]] < orders[e[2]]) end dag = dag:reverse() order_path = partiail_topo_sort(dag) orders = {} for i, v in ipairs(order_path) do orders[v] = i end for _, e in ipairs(edges) do t:require(orders[e[1]] > orders[e[2]]) end end function test_paritail_topo_sort_dynamic(t) local function partiail_topo_sort(dag) dag:partial_topo_sort_reset() local node, has_cycle local order_vertices = {} local dynamic_adjust = false while true do node, has_cycle = dag:partial_topo_sort_next() if node then if not dynamic_adjust then dag:add_edge(1, 4) dag:remove_vertex(6) end table.insert(order_vertices, node) dag:partial_topo_sort_remove(node) if not dynamic_adjust then dag:add_edge(2, 9) dynamic_adjust = true end else if has_cycle then raise("has cycle!") end break end end assert(#order_vertices == #dag:vertices(), "vertices count not matched, %d != %d", #order_vertices, #dag:vertices()) return order_vertices, has_cycle end local edges = { {0, 5}, {0, 2}, {0, 1}, {3, 6}, {3, 5}, {3, 4}, {5, 4}, {6, 4}, {6, 0}, {3, 2}, } local dag = graph.new(true) for _, e in ipairs(edges) do dag:add_edge(e[1], e[2]) end local order_path = partiail_topo_sort(dag) local orders = {} for i, v in ipairs(order_path) do orders[v] = i end edges = { {0, 5}, {0, 2}, {0, 1}, -- {3, 6}, {3, 5}, {3, 4}, {5, 4}, -- {6, 4}, -- {6, 0}, {3, 2}, {1, 4}, {2, 9} } for _, e in ipairs(edges) do t:require(orders[e[1]] < orders[e[2]]) end end function test_remove_edge_and_vertex(t) local gh = graph.new(true) gh:add_edge("a", "b") gh:add_edge("b", "c") gh:add_edge("c", "d") gh:add_edge("a", "d") t:require(gh:has_edge("a", "b")) gh:remove_edge("a", "b") t:require(not gh:has_edge("a", "b")) t:require(gh:has_edge("a", "d")) gh:remove_vertex("c") t:require(not gh:has_edge("b", "c")) t:require(not gh:has_edge("c", "d")) t:are_equal(#gh:vertices(), 3) local order = gh:topo_sort() t:require(#order == 3) gh:add_edge("b", "a") gh:add_edge("d", "b") local _, has_cycle = gh:topo_sort() t:require(has_cycle) end function test_clone_reverse_undirected(t) local ug = graph.new(false) ug:add_edge(1, 2) ug:add_edge(2, 3) ug:add_edge(3, 1) local clone = ug:clone() t:require(#clone:edges() == #ug:edges()) t:require(clone:has_edge(1, 2)) t:require(clone:has_edge(2, 1)) local rev = ug:reverse() t:require(rev:has_edge(1, 2)) t:require(rev:has_edge(2, 1)) t:require(#rev:edges() == #ug:edges()) end function test_find_cycle(t) local edges = { {9, 1}, {1, 6}, {6, 0}, {0, 1}, {4, 5} } local dag = graph.new(true) for _, e in ipairs(edges) do dag:add_edge(e[1], e[2]) end local cycle = dag:find_cycle() t:are_equal(cycle, {1, 6, 0}) local _, has_cycle = dag:topo_sort() t:require(has_cycle) end ================================================ FILE: tests/modules/hash/test.lua ================================================ function test_rand32(t) local set = {} for i = 1, 1000 do local r = hash.rand32() t:require(set[r] == nil) set[r] = r end end function test_rand64(t) local set = {} for i = 1, 100000 do local r = hash.rand64() t:require(set[r] == nil) set[r] = r end end function test_rand128(t) local set = {} for i = 1, 100000 do local r = hash.rand128() t:require(set[r] == nil) set[r] = r end end ================================================ FILE: tests/modules/hashset/test.lua ================================================ import("core.base.hashset") function test_hashset(t) local h = hashset.of(1, 2, 3, 5, 5, 7, 1, 9, 4, 6, 8, 0) t:require(h:size() == 10) t:require_not(h:empty()) for item in h:items() do t:require(h:has(item)) t:require_not(h:has(item + 10)) end local prev = -1 for item in h:orderitems() do t:require(item > prev) prev = item end local h2 = h:clone() t:require(h == h2) h2:insert(11) t:require_not(h == h2) h2:remove(11) t:require(h == h2) h2:clear() t:require(h2:empty()) t:require(h == hashset.from(h:to_array())) end ================================================ FILE: tests/modules/heap/test.lua ================================================ import("core.base.heap") function test_cdataheap(t) if not xmake.luajit() then return end local h = heap.cdataheap{ size = 100, ctype = [[ struct { int priority; int order; } ]], cmp = function(a, b) if a.priority == b.priority then return a.order > b.order end return a.priority < b.priority end} h:push{priority = 20, order = 1} h:push{priority = 10, order = 2} h:push{priority = 10, order = 3} h:push{priority = 20, order = 4} t:are_equal(h:pop().order, 3) t:are_equal(h:pop().order, 2) t:are_equal(h:pop().order, 4) t:are_equal(h:pop().order, 1) end function test_valueheap(t) local h = heap.valueheap{cmp = function(a, b) return a.priority < b.priority end} h:push{priority = 20, etc = 'bar'} h:push{priority = 10, etc = 'foo'} t:are_equal(h:pop().priority, 10) t:are_equal(h:pop().priority, 20) end ================================================ FILE: tests/modules/hello/test.lua ================================================ function test_hello(context) print("hello") end ================================================ FILE: tests/modules/io/files/.gitattributes ================================================ * binary ================================================ FILE: tests/modules/io/files/utf8-crlf-neleof ================================================ 123\ 456 789 ================================================ FILE: tests/modules/io/files/utf8-longline-eleof ================================================ 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 ================================================ FILE: tests/modules/io/files/utf8-longline-neleof ================================================ 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 ================================================ FILE: tests/modules/io/files/utf8bom-lf-eleof ================================================ 123\ 456 789 ================================================ FILE: tests/modules/io/test.lua ================================================ function test_read(t) t:are_equal(io.readfile("files/utf8bom-lf-eleof"), "123\\\n456\n789\n") t:are_equal(io.readfile("files/utf8-crlf-neleof"), "123\\\n456\n789") t:are_equal(io.readfile("files/utf8-crlf-neleof", {encoding = "binary"}), "123\\\r\n456\r\n789") t:are_equal(io.readfile("files/utf8-crlf-neleof", {continuation = "\\"}), "123456\n789") t:are_equal(io.readfile("files/utf16be-lf-eleof"), "123\\\n456\n789\n") t:are_equal(io.readfile("files/utf16le-crlf-neleof"), "123\\\n456\n789") local data1 = io.readfile("files/utf8-longline-neleof") t:are_equal(#data1, 10000) t:require(data1:endswith("1234567890")) local data2 = io.readfile("files/utf8-longline-eleof") t:are_equal(#data2, 10001) t:require(data2:endswith("1234567890\n")) end function test_lines(t) t:are_equal(table.to_array(io.lines("files/utf8bom-lf-eleof")), {"123\\", "456", "789"}) t:are_equal(table.to_array(io.lines("files/utf8-crlf-neleof")), {"123\\", "456", "789"}) t:are_equal(table.to_array(io.lines("files/utf8-crlf-neleof", {encoding = "binary"})), {"123\\\r\n", "456\r\n", "789"}) t:are_equal(table.to_array(io.lines("files/utf8-crlf-neleof", {continuation = "\\"})), {"123456", "789"}) t:are_equal(table.to_array(io.lines("files/utf16be-lf-eleof")), {"123\\", "456", "789"}) t:are_equal(table.to_array(io.lines("files/utf16le-crlf-neleof")), {"123\\", "456", "789"}) end function test_readlines(t) function get_all_keep_crlf(file, opt) local fp = io.open(file, "r", opt) local r = {} while true do local l = fp:read("L", opt) if l == nil then break end table.insert(r, l) end t:require(fp:close()) return r end function get_all_without_crlf(file, opt) local r = {} local fp = io.open(file, "r", opt) for l in fp:lines(opt) do table.insert(r, l) end t:require(fp:close()) return r end t:are_equal(get_all_keep_crlf("files/utf8bom-lf-eleof"), {"123\\\n", "456\n", "789\n"}) t:are_equal(get_all_keep_crlf("files/utf8-crlf-neleof"), {"123\\\n", "456\n", "789"}) t:are_equal(get_all_keep_crlf("files/utf8-crlf-neleof", {encoding = "binary"}), {"123\\\r\n", "456\r\n", "789"}) t:are_equal(get_all_keep_crlf("files/utf8-crlf-neleof", {continuation = "\\"}), {"123456\n", "789"}) t:are_equal(get_all_keep_crlf("files/utf16be-lf-eleof"), {"123\\\n", "456\n", "789\n"}) t:are_equal(get_all_keep_crlf("files/utf16le-crlf-neleof"), {"123\\\n", "456\n", "789"}) t:are_equal(get_all_without_crlf("files/utf8bom-lf-eleof"), {"123\\", "456", "789"}) t:are_equal(get_all_without_crlf("files/utf8-crlf-neleof"), {"123\\", "456", "789"}) t:are_equal(get_all_without_crlf("files/utf8-crlf-neleof", {encoding = "binary"}), {"123\\\r\n", "456\r\n", "789"}) t:are_equal(get_all_without_crlf("files/utf8-crlf-neleof", {continuation = "\\"}), {"123456", "789"}) t:are_equal(get_all_without_crlf("files/utf16be-lf-eleof"), {"123\\", "456", "789"}) t:are_equal(get_all_without_crlf("files/utf16le-crlf-neleof"), {"123\\", "456", "789"}) end function test_prop(t) t:are_equal(io.open("files/utf8bom-lf-eleof"):size(), 16) t:are_equal(io.open("files/utf8-crlf-neleof"):size(), 14) t:are_equal(io.open("files/utf16be-lf-eleof"):size(), 28) t:are_equal(io.open("files/utf16le-crlf-neleof"):size(), 30) t:are_equal(io.open("files/utf8bom-lf-eleof"):path(), path.absolute("files/utf8bom-lf-eleof")) t:are_equal(io.open("files/utf8-crlf-neleof"):path(), path.absolute("files/utf8-crlf-neleof")) t:are_equal(io.open("files/utf16be-lf-eleof"):path(), path.absolute("files/utf16be-lf-eleof")) t:are_equal(io.open("files/utf16le-crlf-neleof"):path(), path.absolute("files/utf16le-crlf-neleof")) end function test_write(t) function write(fname, opt) local f = io.open(fname, "w", opt) f:write(123, "abc", 456, "def", "\n") f:close() -- give encoding info t:are_equal(io.readfile(fname, opt), "123abc456def\n") -- auto detect encoding t:are_equal(io.readfile(fname), "123abc456def\n") end write("temp/path/not/exist/utf8", {encoding = "utf8"}) write("temp/path/not/exist/utf16", {encoding = "utf16"}) write("temp/path/not/exist/utf16le", {encoding = "utf16le"}) write("temp/path/not/exist/utf16be", {encoding = "utf16be"}) os.tryrm("temp") end function test_convert(t) local src = "files/utf8bom-lf-eleof" local dst = "temp/convert_test.txt" os.mkdir("temp") -- utf8 to gbk (strip bom) io.convert(src, dst, {from = "utf8", to = "gbk"}) local content = io.readfile(dst, {encoding = "binary"}) t:are_equal(content, "123\\\n456\n789\n") -- gbk to utf8 local src_gbk = dst local dst_utf8 = "temp/convert_test_utf8.txt" io.convert(src_gbk, dst_utf8, {from = "gbk", to = "utf8"}) content = io.readfile(dst_utf8, {encoding = "binary"}) t:are_equal(content, "123\\\n456\n789\n") -- utf8 to utf8bom local dst_utf8bom = "temp/convert_test_utf8bom.txt" io.convert(src, dst_utf8bom, {from = "utf8", to = "utf8bom"}) content = io.readfile(dst_utf8bom, {encoding = "binary"}) t:are_equal(content:sub(1, 3), "\239\187\191") t:are_equal(content:sub(4), "123\\\n456\n789\n") -- utf16le to utf8 local src_utf16le = "files/utf16le-crlf-neleof" local dst_utf16le_to_utf8 = "temp/convert_test_utf16le_to_utf8.txt" io.convert(src_utf16le, dst_utf16le_to_utf8, {from = "utf16le", to = "utf8"}) content = io.readfile(dst_utf16le_to_utf8, {encoding = "binary"}) t:are_equal(content, "123\\\r\n456\r\n789") -- utf16be to utf8 local src_utf16be = "files/utf16be-lf-eleof" local dst_utf16be_to_utf8 = "temp/convert_test_utf16be_to_utf8.txt" io.convert(src_utf16be, dst_utf16be_to_utf8, {from = "utf16be", to = "utf8"}) content = io.readfile(dst_utf16be_to_utf8, {encoding = "binary"}) t:are_equal(content, "123\\\n456\n789\n") -- utf8 to utf16le local dst_utf8_to_utf16le = "temp/convert_test_utf8_to_utf16le.txt" io.convert(src, dst_utf8_to_utf16le, {from = "utf8", to = "utf16le"}) content = io.readfile(dst_utf8_to_utf16le, {encoding = "binary"}) t:are_equal(content:sub(1, 2), "1\0") -- utf8 to utf16be local dst_utf8_to_utf16be = "temp/convert_test_utf8_to_utf16be.txt" io.convert(src, dst_utf8_to_utf16be, {from = "utf8", to = "utf16be"}) content = io.readfile(dst_utf8_to_utf16be, {encoding = "binary"}) t:are_equal(content:sub(1, 2), "\0001") -- utf8 to utf16lebom local dst_utf8_to_utf16lebom = "temp/convert_test_utf8_to_utf16lebom.txt" io.convert(src, dst_utf8_to_utf16lebom, {from = "utf8", to = "utf16lebom"}) content = io.readfile(dst_utf8_to_utf16lebom, {encoding = "binary"}) t:are_equal(content:sub(1, 2), "\255\254") -- utf8 to utf16bom local dst_utf8_to_utf16bom = "temp/convert_test_utf8_to_utf16bom.txt" io.convert(src, dst_utf8_to_utf16bom, {from = "utf8", to = "utf16bom"}) content = io.readfile(dst_utf8_to_utf16bom, {encoding = "binary"}) local bom = content:sub(1, 2) t:require(bom == "\255\254" or bom == "\254\255") os.tryrm("temp") end function test_read_proc_cpuinfo(t) if not is_host("linux") then return t:skip("wrong host platform") end if not os.isfile("/proc/cpuinfo") then return t:skip("missing /proc/cpuinfo") end local data = io.readfile("/proc/cpuinfo", {encoding = "binary"}) t:require(data and #data > 0) local data2 = io.readfile("/proc/cpuinfo") t:require(data2 and #data2 > 0) end ================================================ FILE: tests/modules/jobgraph/test.lua ================================================ import("async.jobgraph") local function dummy_job() end function test_group_bridge_reuse(t) local jobs = jobgraph.new() jobs:group("foo", function () jobs:add("foo/1", dummy_job) jobs:add("foo/2", dummy_job) end) jobs:group("bar", function () jobs:add("bar/1", dummy_job) end) jobs:add_orders("foo", "bar") local vertices_before = #jobs._dag:vertices() jobs:add_orders("foo", "bar") local vertices_after = #jobs._dag:vertices() t:are_equal(vertices_before, vertices_after) end function test_group_bridge_updates_with_new_job(t) local jobs = jobgraph.new() jobs:group("foo", function () jobs:add("foo/1", dummy_job) end) jobs:group("bar", function () jobs:add("bar/1", dummy_job) end) jobs:add_orders("foo", "bar") jobs:group("foo", function () jobs:add("foo/2", dummy_job) end) local queue = jobs:build() local first = queue:getfree() t:require(first.name == "foo/1" or first.name == "foo/2") queue:remove(first) local second = queue:getfree() t:require(second.name == "foo/1" or second.name == "foo/2") t:require(second.name ~= first.name) queue:remove(second) local third = queue:getfree() t:are_equal(third.name, "bar/1") end ================================================ FILE: tests/modules/json/test.lua ================================================ import("core.base.json") local json_null = json.null local json_pure_null = json.purenull function json_decode(jsonstr, opt) return json.decode(jsonstr, opt) end function json_encode(luatable, opt) return json.encode(luatable, opt) end function json_pure_decode(jsonstr, opt) opt = opt or {} opt.pure = true return json.decode(jsonstr, opt) end function json_pure_encode(luatable, opt) opt = opt or {} opt.pure = true return json.encode(luatable, opt) end function test_json_decode(t) t:are_equal(json_decode('{}'), {}) t:are_equal(json_decode('[]'), {}) t:are_equal(json.is_marked_as_array(json_decode('[]')), true) t:are_equal(not json.is_marked_as_array(json_decode('{}')), true) t:are_equal(json_decode('{"a":1, "b":"2", "c":true, "d":false, "e":null, "f":[]}'), {a = 1, b = "2", c = true, d = false, e = json_null, f = {}}) t:are_equal(json_decode('{"a":[], "b":[1,2], "c":{"a":1}}'), {a = {}, b = {1,2}, c = {a = 1}}) t:are_equal(json_decode('[1,"2"]'), {1, "2"}) t:are_equal(json_decode('[1,"2", {"a":1, "b":true}]'), {1, "2", {a = 1, b = true}}) t:are_equal(json_decode('[1,0xa,0xdeadbeef, 0xffffffff,-1]'), {1, 0xa, 0xdeadbeef, 0xffffffff, -1}) end function test_json_encode(t) t:are_equal(json_encode({}), '{}') t:are_equal(json_encode(json.mark_as_array({})), '[]') t:are_equal(json_encode({json_null, 1, "2", false, true}), '[null,1,"2",false,true]') t:are_equal(json_encode({1, "2", {a = 1}}), '[1,"2",{"a":1}]') t:are_equal(json_encode({1, "2", {b = true}}), '[1,"2",{"b":true}]') t:are_equal(json_encode(json.mark_as_array({1, 0xa, 0xdeadbeef, 0xffffffff, -1})), '[1,10,3735928559,4294967295,-1]') local pretty_expected = table.concat({ "{", " \"name\": \"xmake\",", " \"targets\": [", " \"foo\",", " \"bar\"", " ]", "}" }, "\n") t:are_equal(json_encode({name = "xmake", targets = {"foo", "bar"}}, {pretty = true, indent = 4}), pretty_expected) end function test_pure_json_decode(t) t:are_equal(json_pure_decode('{}'), {}) t:are_equal(json_pure_decode('[]'), {}) t:are_equal(json.is_marked_as_array(json_pure_decode('[]')), true) t:are_equal(not json.is_marked_as_array(json_pure_decode('{}')), true) t:are_equal(json_pure_decode('{"a":1, "b":"2", "c":true, "d":false, "e":null, "f":[]}'), {a = 1, b = "2", c = true, d = false, e = json_pure_null, f = {}}) t:are_equal(json_pure_decode('{"a":[], "b":[1,2], "c":{"a":1}}'), {a = {}, b = {1,2}, c = {a = 1}}) t:are_equal(json_pure_decode('[1,"2"]'), {1, "2"}) t:are_equal(json_pure_decode('[1,"2", {"a":1, "b":true}]'), {1, "2", {a = 1, b = true}}) t:are_equal(json_pure_decode('[1,0xa,0xdeadbeef, 0xffffffff,-1]'), {1, 0xa, 0xdeadbeef, 0xffffffff, -1}) end function test_pure_json_encode(t) t:are_equal(json_pure_encode({}), '{}') t:are_equal(json_pure_encode(json.mark_as_array({})), '[]') t:are_equal(json_pure_encode({json_pure_null, 1, "2", false, true}), '[null,1,"2",false,true]') t:are_equal(json_pure_encode({1, "2", {a = 1}}), '[1,"2",{"a":1}]') t:are_equal(json_pure_encode({1, "2", {b = true}}), '[1,"2",{"b":true}]') t:are_equal(json_pure_encode(json.mark_as_array({1, 0xa, 0xdeadbeef, 0xffffffff, -1})), '[1,10,3735928559,4294967295,-1]') local pretty_expected = table.concat({ "{", " \"name\": \"xmake\",", " \"targets\": [", " \"foo\",", " \"bar\"", " ]", "}" }, "\n") t:are_equal(json_pure_encode({name = "xmake", targets = {"foo", "bar"}}, {pretty = true, indent = 4}), pretty_expected) end ================================================ FILE: tests/modules/lib/detect/test.lua ================================================ import("lib.detect.find_toolname") function test_find_toolname(t) t:are_equal(find_toolname("xcrun -sdk macosx clang"), "clang") t:are_equal(find_toolname("xcrun -sdk macosx clang++"), "clangxx") t:are_equal(find_toolname("/usr/bin/arm-linux-gcc"), "gcc") t:are_equal(find_toolname("/usr/bin/arm-linux-g++"), "gxx") t:are_equal(find_toolname("/usr/bin/arm-linux-ar"), "ar") t:are_equal(find_toolname("link.exe -lib"), "link") t:are_equal(find_toolname("arm-android-clang++"), "clangxx") t:are_equal(find_toolname("pkg-config"), "pkg_config") t:are_equal(find_toolname("gcc-5"), "gcc") end ================================================ FILE: tests/modules/list/test.lua ================================================ import("core.base.list") function test_push(t) local d = list.new() d:push({v = 1}) d:push({v = 2}) d:push({v = 3}) d:push({v = 4}) d:push({v = 5}) t:are_equal(d:first().v, 1) t:are_equal(d:last().v, 5) local idx = 1 for item in d:items() do t:are_equal(item.v, idx) idx = idx + 1 end end function test_insert(t) local d = list.new() local v3 = {v = 3} d:insert({v = 1}) d:insert({v = 2}) d:insert(v3) d:insert({v = 5}) d:insert({v = 4}, v3) t:are_equal(d:first().v, 1) t:are_equal(d:last().v, 5) local idx = 1 for item in d:items() do t:are_equal(item.v, idx) idx = idx + 1 end end function test_remove(t) local d = list.new() local v3 = {v = 3} d:insert({v = 1}) d:insert({v = 2}) d:insert(v3) d:insert({v = 3}) d:insert({v = 4}) d:insert({v = 5}) d:remove(v3) t:are_equal(d:first().v, 1) t:are_equal(d:last().v, 5) local idx = 1 for item in d:items() do t:are_equal(item.v, idx) idx = idx + 1 end end function test_remove_first(t) local d = list.new() d:push({v = 1}) d:push({v = 2}) d:push({v = 3}) d:push({v = 4}) d:push({v = 5}) d:remove_first() t:are_equal(d:first().v, 2) t:are_equal(d:last().v, 5) local idx = 2 for item in d:items() do t:are_equal(item.v, idx) idx = idx + 1 end end function test_remove_last(t) local d = list.new() d:push({v = 1}) d:push({v = 2}) d:push({v = 3}) d:push({v = 4}) d:push({v = 5}) d:remove_last() t:are_equal(d:first().v, 1) t:are_equal(d:last().v, 4) local idx = 1 for item in d:items() do t:are_equal(item.v, idx) idx = idx + 1 end end function test_for_remove(t) local d = list.new() d:push({v = 1}) d:push({v = 2}) d:push({v = 3}) d:push({v = 4}) d:push({v = 5}) t:are_equal(d:first().v, 1) t:are_equal(d:last().v, 5) local idx = 1 local item = d:first() while item ~= nil do local next = d:next(item) t:are_equal(item.v, idx) d:remove(item) item = next idx = idx + 1 end t:require(d:empty()) end function test_rfor_remove(t) local d = list.new() d:push({v = 1}) d:push({v = 2}) d:push({v = 3}) d:push({v = 4}) d:push({v = 5}) t:are_equal(d:first().v, 1) t:are_equal(d:last().v, 5) local idx = 5 local item = d:last() while item ~= nil do local prev = d:prev(item) t:are_equal(item.v, idx) d:remove(item) item = prev idx = idx - 1 end t:require(d:empty()) end function test_insert_first(t) local d = list.new() d:push({v = 2}) d:push({v = 3}) d:push({v = 4}) d:push({v = 5}) d:insert_first({v = 1}) t:are_equal(d:first().v, 1) t:are_equal(d:last().v, 5) local idx = 1 for item in d:items() do t:are_equal(item.v, idx) idx = idx + 1 end end function test_insert_last(t) local d = list.new() d:push({v = 1}) d:push({v = 2}) d:push({v = 3}) d:push({v = 4}) d:insert_last({v = 5}) t:are_equal(d:first().v, 1) t:are_equal(d:last().v, 5) local idx = 1 for item in d:items() do t:are_equal(item.v, idx) idx = idx + 1 end end ================================================ FILE: tests/modules/math/test.lua ================================================ function test_isinf(t) t:will_raise(function() math.isinf(nil) end) t:will_raise(function() math.isinf(true) end) t:require_not(math.isinf(0)) t:require_not(math.isinf(math.nan)) t:are_same(math.isinf(math.inf), 1) t:are_same(math.isinf(-math.inf), -1) end function test_isnan(t) t:will_raise(function() math.isinf(nil) end) t:will_raise(function() math.isinf(true) end) t:require_not(math.isnan(0)) t:require(math.isnan(math.nan)) t:require_not(math.isnan(math.huge)) t:require_not(math.isnan(-math.huge)) end function test_isint(t) t:will_raise(function() math.isint(nil) end) t:will_raise(function() math.isint(true) end) t:require(math.isint(0)) t:require(math.isint(-10)) t:require(math.isint(123456)) t:require_not(math.isint(123456.1)) t:require_not(math.isint(-9.99)) t:require_not(math.isint(math.nan)) t:require_not(math.isint(math.huge)) t:require_not(math.isint(-math.huge)) end ================================================ FILE: tests/modules/os/async_copy.lua ================================================ local function _prepare_source(dir) os.mkdir(dir) io.writefile(path.join(dir, "foo.txt"), "foo") io.writefile(path.join(dir, "bar.txt"), "bar") end function main() local root = os.tmpfile() .. ".os_async_copy" local srcdir = path.join(root, "src") local dstdir = path.join(root, "dst") _prepare_source(srcdir) print("source prepared: %s", srcdir) local files = os.files(path.join(srcdir, "*.txt"), {async = true}) assert(files and #files == 2) print("async enumerate: %d files", #files) os.cp(srcdir, dstdir, {async = true}) assert(os.isdir(dstdir)) print("async copy done: %s", dstdir) files = os.files(path.join(dstdir, "*.txt"), {async = true}) assert(files and #files == 2) os.rm(dstdir, {async = true}) assert(not os.isdir(dstdir)) print("dst removed async") os.rm(srcdir, {async = true}) os.tryrm(root) print("async copy test finished") end ================================================ FILE: tests/modules/os/async_scheduler.lua ================================================ import("core.base.scheduler") local function _prepare_workspace(root) os.mkdir(root) for idx = 1, 4 do io.writefile(path.join(root, string.format("file%d.txt", idx)), "xmake") end end function main() local root = os.tmpfile() .. ".os_async_sched" _prepare_workspace(root) print("workspace prepared: %s", root) local group = "os_async_scheduler" scheduler.co_group_begin(group, function () for idx = 1, 4 do scheduler.co_start(function () local matches = os.files(path.join(root, string.format("file%d.txt", idx)), {async = true}) assert(matches and #matches == 1) print("async match %d finished", idx) end) end scheduler.co_start(function () print("async find all files in programdir...") local files = os.files(path.join(os.programdir(), "**"), {async = true}) print("files: %d", #files) print("async find all finished") end) end) end ================================================ FILE: tests/modules/os/cpuinfo.lua ================================================ function main() print(os.cpuinfo()) while true do print("total: %d%%", math.floor(os.cpuinfo("usagerate") * 100)) os.sleep(1000) end end ================================================ FILE: tests/modules/os/meminfo.lua ================================================ function main() while true do print("%d%%", math.floor(os.meminfo("usagerate") * 100)) os.sleep(1000) end end ================================================ FILE: tests/modules/os/test.lua ================================================ function test_cpdir(t) -- get mclock local tm = os.mclock() -- test cpdir os.mkdir("test1") t:require(os.exists("test1")) os.cp("test1","test2") t:require(os.exists("test2")) os.rmdir("test1") t:require_not(os.exists("test1")) io.writefile("test2/awd","awd") os.rmdir("test2") t:require_not(os.exists("test2")) -- assert mclock t:require(os.mclock() >= tm) end function test_rename(t) -- get mclock local tm = os.mclock() -- test rename os.mkdir("test1") t:require(os.exists("test1")) os.mv("test1","test2") t:require_not(os.exists("test1")) t:require(os.exists("test2")) os.rmdir("test2") t:require_not(os.exists("test2")) -- assert mclock t:require(os.mclock() >= tm) end function test_cp_mvdir_into_another_dir(t) -- get mclock local tm = os.mclock() -- test cp/mvdir into another dir os.mkdir("test1") os.mkdir("test2") t:require(os.exists("test1")) t:require(os.exists("test2")) os.cp("test1","test2") t:require(os.exists("test2/test1")) os.mv("test1","test2/test1") t:require_not(os.exists("test1")) t:require(os.exists("test2/test1/test1")) os.rmdir("test2") t:require_not(os.exists("test2")) -- assert mclock t:require(os.mclock() >= tm) end function test_cp_symlink(t) if is_host("windows") then return end os.touch("test1") os.ln("test1", "test2") t:require(os.isfile("test1")) t:require(os.isfile("test2")) t:require(os.islink("test2")) os.cp("test2", "test3") t:require(os.isfile("test3")) t:require(not os.islink("test3")) os.cp("test2", "test4", {symlink = true}) t:require(os.isfile("test4")) t:require(os.islink("test4")) os.mkdir("dir") os.touch("dir/test1") os.cd("dir") os.ln("test1", "test2") os.cd("-") t:require(os.islink("dir/test2")) os.cp("dir", "dir2") t:require(not os.islink("dir2/test2")) os.cp("dir", "dir3", {symlink = true}) t:require(os.islink("dir3/test2")) os.tryrm("test1") os.tryrm("test2") os.tryrm("test3") os.tryrm("test4") os.tryrm("dir") os.tryrm("dir2") os.tryrm("dir3") t:require(not os.exists("test1")) t:require(not os.exists("test2")) t:require(not os.exists("dir")) end function test_setenv(t) -- get mclock local tm = os.mclock() -- test setenv os.setenv("__AWD","DWA") t:are_equal(os.getenv("__AWD"), "DWA") os.setenv("__AWD","DWA2") t:are_equal(os.getenv("__AWD"), "DWA2") -- assert mclock t:require(os.mclock() >= tm) end function test_argv(t) t:are_equal(os.argv(""), {}) -- $cli aa bb cc t:are_equal(os.argv("aa bb cc"), {"aa", "bb", "cc"}) -- $cli aa --bb=bbb -c t:are_equal(os.argv("aa --bb=bbb -c"), {"aa", "--bb=bbb", "-c"}) -- $cli "aa bb cc" dd t:are_equal(os.argv('"aa bb cc" dd'), {"aa bb cc", "dd"}) -- $cli aa(bb)cc dd t:are_equal(os.argv('aa(bb)cc dd'), {"aa(bb)cc", "dd"}) -- $cli aa\\bb/cc dd t:are_equal(os.argv('aa\\bb/cc dd'), {"aa\\bb/cc", "dd"}) -- $cli "aa\\bb/cc dd" ee t:are_equal(os.argv('"aa\\\\bb/cc dd" ee'), {"aa\\bb/cc dd", "ee"}) -- $cli "aa\\bb/cc (dd)" ee t:are_equal(os.argv('"aa\\\\bb/cc (dd)" ee'), {"aa\\bb/cc (dd)", "ee"}) -- $cli -DTEST=\"hello\" t:are_equal(os.argv('-DTEST=\\"hello\\"'), {'-DTEST="hello"'}) -- $cli -DTEST=\"hello\" -DTEST=\"hello\" t:are_equal(os.argv('-DTEST=\\"hello\\" -DTEST2=\\"hello\\"'), {'-DTEST="hello"', '-DTEST2="hello"'}) -- $cli -DTEST="hello" t:are_equal(os.argv('-DTEST="hello"'), {'-DTEST=hello'}) -- $cli -DTEST="hello world" t:are_equal(os.argv('-DTEST="hello world"'), {'-DTEST=hello world'}) -- $cli -DTEST=\"hello world\" t:are_equal(os.argv('-DTEST=\\"hello world\\"'), {'-DTEST="hello', 'world\"'}) -- $cli "-DTEST=\"hello world\"" "-DTEST2="\hello world2\"" t:are_equal(os.argv('"-DTEST=\\\"hello world\\\"" "-DTEST2=\\\"hello world2\\\""'), {'-DTEST="hello world"', '-DTEST2="hello world2"'}) -- $cli '-DTEST="hello world"' '-DTEST2="hello world2"' t:are_equal(os.argv("'-DTEST=\"hello world\"' '-DTEST2=\"hello world2\"'"), {'-DTEST="hello world"', '-DTEST2="hello world2"'}) -- only split t:are_equal(os.argv('-DTEST="hello world"', {splitonly = true}), {'-DTEST="hello world"'}) t:are_equal(os.argv('-DTEST="hello world" -DTEST2="hello world2"', {splitonly = true}), {'-DTEST="hello world"', '-DTEST2="hello world2"'}) end function test_args(t) t:are_equal(os.args({}), "") t:are_equal(os.args({"aa", "bb", "cc"}), "aa bb cc") t:are_equal(os.args({"aa", "--bb=bbb", "-c"}), "aa --bb=bbb -c") t:are_equal(os.args({"aa bb cc", "dd"}), '"aa bb cc" dd') t:are_equal(os.args({"aa(bb)cc", "dd"}), 'aa(bb)cc dd') t:are_equal(os.args({"aa\\bb/cc", "dd"}), "aa\\bb/cc dd") t:are_equal(os.args({"aa\\bb/cc dd", "ee"}), '"aa\\\\bb/cc dd" ee') t:are_equal(os.args({"aa\\bb/cc (dd)", "ee"}), '"aa\\\\bb/cc (dd)" ee') t:are_equal(os.args({"aa\\bb/cc", "dd"}, {escape = true}), "aa\\\\bb/cc dd") t:are_equal(os.args('-DTEST="hello"'), '-DTEST=\\"hello\\"') t:are_equal(os.args({'-DTEST="hello"', '-DTEST2="hello"'}), '-DTEST=\\"hello\\" -DTEST2=\\"hello\\"') t:are_equal(os.args('-DTEST=hello'), '-DTEST=hello') -- irreversible t:are_equal(os.args({'-DTEST="hello world"', '-DTEST2="hello world2"'}), '"-DTEST=\\\"hello world\\\"" "-DTEST2=\\\"hello world2\\\""') end function test_async(t) local tmpdir = os.tmpfile() .. ".dir" local tmpdir2 = os.tmpfile() .. ".dir" io.writefile(path.join(tmpdir, "foo.txt"), "foo") io.writefile(path.join(tmpdir, "bar.txt"), "bar") local files = os.files(path.join(tmpdir, "*.txt"), {async = true}) t:require(files and #files == 2) os.cp(tmpdir, tmpdir2, {async = true, detach = true}) os.cp(tmpdir, tmpdir2, {async = true}) t:require(os.isdir(tmpdir2)) t:require(os.isdir(tmpdir)) os.rm(tmpdir, {async = true}) t:require(not os.isdir(tmpdir)) t:require(os.isdir(tmpdir2)) os.rm(tmpdir2, {async = true, detach = true}) end function test_isexec(t) local tempdir = "temp/isexec" os.tryrm(tempdir) os.mkdir(tempdir) local programfile = os.programfile() if programfile then t:require(os.isexec(programfile)) end local filepath = path.join(tempdir, "script") io.writefile(filepath, "echo test\n") if is_host("windows") then local batfile = path.join(tempdir, "a.bat") io.writefile(batfile, "echo test\r\n") t:require(os.isexec(batfile)) local comfile = path.join(tempdir, "a.com") io.writefile(comfile, "12345678") t:require(os.isexec(comfile)) local suffix = path.join(tempdir, "prog") io.writefile(suffix .. ".exe", "") t:require(os.isexec(suffix)) local suffix2 = path.join(tempdir, "prog2") io.writefile(suffix2 .. ".com", "") t:require(os.isexec(suffix2)) else os.vrunv("chmod", {"-x", filepath}) t:require_not(os.isexec(filepath)) os.vrunv("chmod", {"+x", filepath}) t:require(os.isexec(filepath)) end os.tryrm(tempdir) end ================================================ FILE: tests/modules/path/test.lua ================================================ function test_splitenv_win(t) if not is_host("windows") then return t:skip("wrong host platform") end t:are_equal(path.splitenv(""), {}) t:are_equal(path.splitenv("a"), {'a'}) t:are_equal(path.splitenv("a;b"), {'a','b'}) t:are_equal(path.splitenv(";;a;;b;"), {'a','b'}) t:are_equal(path.splitenv('c:/a;c:\\b'), {'c:/a', 'c:\\b'}) t:are_equal(path.splitenv('"a;aa;aa;;"'), {"a;aa;aa;;"}) t:are_equal(path.splitenv('"a;aa;aa;;";bb;;'), {"a;aa;aa;;", 'bb'}) t:are_equal(path.splitenv('"a;aa;aa;;";"a;cc;aa;;";bb;"d";'), {"a;aa;aa;;","a;cc;aa;;", 'bb', 'd' }) end function test_splitenv_unix(t) if is_host("windows") then return t:skip("wrong host platform") end t:are_equal(path.splitenv(""), {}) t:are_equal(path.splitenv("a"), {'a'}) t:are_equal(path.splitenv("a:b"), {'a','b'}) t:are_equal(path.splitenv("::a::b:"), {'a','b'}) t:are_equal(path.splitenv('a%tag:b'), {'a','b'}) t:are_equal(path.splitenv('a%tag:b%tag'), {'a','b'}) t:are_equal(path.splitenv('a%tag:b%%tag%%'), {'a','b'}) t:are_equal(path.splitenv('a%tag:b:%tag:'), {'a','b'}) end function test_extension(t) t:are_equal(path.extension("1.1/abc"), "") t:are_equal(path.extension("1.1\\abc"), "") t:are_equal(path.extension("foo.so"), ".so") t:are_equal(path.extension("/home/foo.so"), ".so") t:are_equal(path.extension("\\home\\foo.so"), ".so") end function test_filename(t) t:are_equal(path.filename("foo"), "foo") t:are_equal(path.filename("foo.so"), "foo.so") t:are_equal(path.filename("/tmp/foo.so"), "foo.so") t:are_equal(path.filename("c:\\tmp\\foo.so"), "foo.so") t:are_equal(path.filename("/tmp/.."), "..") t:are_equal(path.filename("/tmp/."), ".") t:are_equal(path.filename("/"), "") t:are_equal(path.filename(""), "") -- unicode t:are_equal(path.filename("Unicode 测试/test.lua"), "test.lua") t:are_equal(path.filename("Unicode 测试/foo/test.lua"), "test.lua") t:are_equal(path.filename("测试/test.lua"), "test.lua") t:are_equal(path.filename("测试\\test.lua"), "test.lua") end function test_directory(t) t:are_equal(path.directory(""), nil) t:are_equal(path.directory("."), nil) t:are_equal(path.directory("foo"), ".") if is_host("windows") then t:are_equal(path.directory("c:"), nil) t:are_equal(path.directory("c:\\"), nil) t:are_equal(path.directory("c:\\xxx"), "c:") t:are_equal(path.directory("c:\\xxx\\yyy"), "c:\\xxx") else t:are_equal(path.directory("/tmp"), "/") t:are_equal(path.directory("/tmp/"), "/") t:are_equal(path.directory("/tmp/xxx"), "/tmp") t:are_equal(path.directory("/tmp/xxx/"), "/tmp") t:are_equal(path.directory("/"), nil) end end function test_absolute(t) t:are_equal(path.absolute("", ""), nil) t:are_equal(path.absolute(".", "."), ".") if is_host("windows") then t:are_equal(path.absolute("foo", "c:"), "c:\\foo") t:are_equal(path.absolute("foo", "c:\\"), "c:\\foo") t:are_equal(path.absolute("foo", "c:\\tmp"), "c:\\tmp\\foo") t:are_equal(path.absolute("foo", "c:\\tmp\\"), "c:\\tmp\\foo") else t:are_equal(path.absolute("", "/"), nil) t:are_equal(path.absolute("/", "/"), "/") t:are_equal(path.absolute(".", "/"), "/") t:are_equal(path.absolute("foo", "/tmp/"), "/tmp/foo") t:are_equal(path.absolute("foo", "/tmp"), "/tmp/foo") end end function test_relative(t) t:are_equal(path.relative("", ""), nil) t:are_equal(path.relative(".", "."), ".") if is_host("windows") then t:are_equal(path.relative("c:", "c:\\"), ".") t:are_equal(path.relative("c:\\foo", "c:\\foo"), ".") t:are_equal(path.relative("c:\\foo", "c:\\"), "foo") t:are_equal(path.relative("c:\\tmp\\foo", "c:\\tmp"), "foo") t:are_equal(path.relative("c:\\tmp\\foo", "c:\\tmp\\"), "foo") else t:are_equal(path.relative("", "/"), nil) t:are_equal(path.relative("/", "/"), ".") t:are_equal(path.relative("/tmp/foo", "/tmp/"), "foo") t:are_equal(path.relative("/tmp/foo", "/tmp"), "foo") end end function test_translate(t) t:are_equal(path.translate(""), nil) t:are_equal(path.translate("."), ".") t:are_equal(path.translate(".."), "..") if is_host("windows") then t:are_equal(path.translate("c:"), "c:") t:are_equal(path.translate("c:\\"), "c:") t:are_equal(path.translate("c:\\foo\\\\\\"), "c:\\foo") t:are_equal(path.translate("c:\\foo\\..\\.."), "c:\\foo\\..\\..") else t:are_equal(path.translate("/"), "/"); t:are_equal(path.translate("////"), "/"); t:are_equal(path.translate("/foo//////"), "/foo"); t:are_equal(path.translate("/foo/../.."), "/foo/../.."); t:are_equal(path.translate("/foo/../../"), "/foo/../.."); end end function test_normalize(t) t:are_equal(path.normalize("././."), ".") t:are_equal(path.normalize("../foo/.."), "..") t:are_equal(path.normalize("../foo/bar/../.."), "..") if is_host("windows") then t:are_equal(path.normalize("c:\\foo\\.\\.\\"), "c:\\foo") t:are_equal(path.normalize("c:\\foo\\bar\\.\\..\\xyz"), "c:\\foo\\xyz") t:are_equal(path.normalize("c:\\foo\\.\\.."), "c:") t:are_equal(path.normalize("../.."), "..\\..") t:are_equal(path.normalize("../foo/bar/.."), "..\\foo") t:are_equal(path.normalize("../foo/bar/../../.."), "..\\..") else t:are_equal(path.normalize("/foo/././"), "/foo"); t:are_equal(path.normalize("/./././"), "/"); t:are_equal(path.normalize("/foo/bar/.//..//xyz"), "/foo/xyz"); t:are_equal(path.normalize("/foo/../.."), "/"); t:are_equal(path.normalize("/foo/bar../.."), "/foo"); t:are_equal(path.normalize("../.."), "../.."); t:are_equal(path.normalize("../foo/bar/.."), "../foo"); t:are_equal(path.normalize("../foo/bar/../../.."), "../.."); end end function test_instance(t) t:are_equal(path("/tmp/a"):str(), "/tmp/a") t:are_equal(path("/tmp/a"):directory():str(), "/tmp") t:are_equal(path("/tmp/a", function (p) return "--key=" .. p end):str(), "--key=/tmp/a") t:are_equal(path("/tmp/a", function (p) return "--key=" .. p end):rawstr(), "/tmp/a") t:are_equal(path("/tmp/a", function (p) return "--key=" .. p end):clone():set("/tmp/b"):str(), "--key=/tmp/b") end ================================================ FILE: tests/modules/pipe/echo_client.lua ================================================ import("core.base.pipe") function main(name) local pipefile = pipe.open(name or "test", 'w') local count = 0 while count < 10000 do local write = pipefile:write("hello world..", {block = true}) if write <= 0 then break end count = count + 1 end print("%s: write ok, count: %d!", pipefile, count) pipefile:close() end ================================================ FILE: tests/modules/pipe/echo_server.lua ================================================ import("core.base.pipe") import("core.base.bytes") function main(name) local buff = bytes(8192) local pipefile = pipe.open(name or "test", 'r') if pipefile:connect() > 0 then print("%s: connected", pipefile) local count = 0 local result = nil while count < 10000 do local read, data = pipefile:read(buff, 13, {block = true}) if read > 0 then result = data count = count + 1 else break end end print("%s: read: %d, count: %d", pipefile, result and result:size() or 0, count) result:dump() end pipefile:close() end ================================================ FILE: tests/modules/pipe/pipe_pair.lua ================================================ import("core.base.pipe") import("core.base.bytes") function main() local buff = bytes(8192) local rpipe, wpipe = pipe.openpair() wpipe:write("hello xmake!", {block = true}) local read, data = rpipe:read(buff, 13) if read > 0 and data then data:dump() end rpipe:close() wpipe:close() end ================================================ FILE: tests/modules/pipe/sched_echo_client.lua ================================================ import("core.base.pipe") import("core.base.scheduler") function _session(id) local pipefile = pipe.open("test" .. id, 'w') local count = 0 while count < 10000 do local write = pipefile:write("hello world..", {block = true}) if write <= 0 then break end count = count + 1 end print("%s/%d: write ok, count: %d!", pipefile, id, count) pipefile:close() end function main(count) count = count and tonumber(count) or 1 for i = 1, count do scheduler.co_start(_session, i) end end ================================================ FILE: tests/modules/pipe/sched_echo_server.lua ================================================ import("core.base.pipe") import("core.base.bytes") import("core.base.scheduler") function _session(id) local pipefile = pipe.open("test" .. id, 'r') if pipefile:connect() > 0 then print("%s/%d: connected", pipefile, id) local count = 0 local result = nil local buff = bytes(8192) while count < 10000 do local read, data = pipefile:read(buff, 13, {block = true}) if read > 0 then result = data count = count + 1 else break end end print("%s/%d: read: %d, count: %d", pipefile, id, result and result:size() or 0, count) result:dump() end pipefile:close() end function main(count) count = count and tonumber(count) or 1 for i = 1, count do scheduler.co_start(_session, i) end end ================================================ FILE: tests/modules/pipe/sched_pipe_pair.lua ================================================ import("core.base.pipe") import("core.base.bytes") import("core.base.scheduler") function _session_read(id, pipefile) print("%s/%d: read ..", pipefile, id) local result = nil local buff = bytes(8192) for i = 1, 10000 do local read, data = pipefile:read(buff, 12, {block = true}) if read > 0 and data then result = data:str() end end print("%s/%d: read ok, data: %s", pipefile, id, result and result or "") pipefile:close() end function _session_write(id, pipefile) print("%s/%d: write ..", pipefile, id) for i = 1, 10000 do pipefile:write("hello xmake!", {block = true}) end print("%s/%d: write ok", pipefile, id) pipefile:close() end function _session(id) local rpipe, wpipe = pipe.openpair() scheduler.co_start(_session_read, id, rpipe) scheduler.co_start(_session_write, id, wpipe) end function main(count) count = count and tonumber(count) or 1 for i = 1, count do scheduler.co_start(_session, i) end end ================================================ FILE: tests/modules/private/select_script/test.lua ================================================ import("private.core.base.select_script") function _match_patterns(patterns, opt) local scripts = {} for _, pattern in ipairs(patterns) do pattern = pattern:gsub("([%+%.%-%^%$%%])", "%%%1") pattern = pattern:gsub("%*", "\001") pattern = pattern:gsub("\001", ".*") scripts[pattern] = true end return select_script(scripts, opt) == true end function test_plat_only(t) t:require(_match_patterns("*", {plat = "macosx"})) t:require(_match_patterns("macosx", {plat = "macosx"})) t:require(_match_patterns("macosx,linux", {plat = "macosx"})) t:require(_match_patterns("mac*", {plat = "macosx"})) t:require_not(_match_patterns("macosx", {plat = "linux"})) t:require_not(_match_patterns("linux", {plat = "macosx"})) t:require_not(_match_patterns("!macosx", {plat = "macosx"})) t:require_not(_match_patterns("!mac*", {plat = "macosx"})) t:require(_match_patterns("!macosx", {plat = "linux"})) t:require(_match_patterns("!macosx,!android", {plat = "linux"})) t:require(_match_patterns("!mac*", {plat = "linux"})) end function test_plat_arch(t) t:require(_match_patterns("!wasm|!arm*", {plat = "linux", arch = "x86_64"})) t:require_not(_match_patterns("!wasm|!arm*", {plat = "linux", arch = "arm64"})) t:require(_match_patterns("*|x86_64", {plat = "macosx", arch = "x86_64"})) t:require(_match_patterns("macosx|x86_64", {plat = "macosx", arch = "x86_64"})) t:require(_match_patterns("macosx|x86_64,linux|x86_64", {plat = "macosx", arch = "x86_64"})) t:require(_match_patterns("macosx|x86_*", {plat = "macosx", arch = "x86_64"})) t:require_not(_match_patterns("macosx|x86_64", {plat = "linux", arch = "x86_64"})) t:require_not(_match_patterns("macosx|i386", {plat = "macosx", arch = "x86_64"})) t:require_not(_match_patterns("!macosx|x86_64", {plat = "macosx", arch = "x86_64"})) t:require_not(_match_patterns("!mac*|x86_64", {plat = "macosx", arch = "x86_64"})) t:require(_match_patterns("!macosx|x86_64", {plat = "linux", arch = "x86_64"})) t:require(_match_patterns("!mac*|x86_64", {plat = "linux", arch = "x86_64"})) t:require(_match_patterns("macosx|!i386", {plat = "macosx", arch = "x86_64"})) t:require(_match_patterns("!macosx|!i386", {plat = "linux", arch = "x86_64"})) t:require(_match_patterns("windows|!x86", {plat = "windows", arch = "x64"})) t:require_not(_match_patterns("windows|!x86", {plat = "android", arch = "arm64-v8a"})) t:require(_match_patterns("macosx|native", {plat = "macosx", arch = "x86_64", subarch = "x86_64"})) t:require(_match_patterns("macosx|!native", {plat = "macosx", arch = "arm64", subarch = "x86_64"})) t:require_not(_match_patterns("macosx|!native", {plat = "macosx", arch = "x86_64", subarch = "x86_64"})) t:require_not(_match_patterns("windows|native", {plat = "macosx", arch = "x86_64", subarch = "x86_64"})) end function test_subhost_only(t) t:require(_match_patterns("@*", {subhost = "macosx"})) t:require(_match_patterns("@macosx", {subhost = "macosx"})) t:require(_match_patterns("@mac*", {subhost = "macosx"})) t:require_not(_match_patterns("@macosx", {subhost = "linux"})) t:require_not(_match_patterns("@linux", {subhost = "macosx"})) t:require_not(_match_patterns("@!macosx", {subhost = "macosx"})) t:require_not(_match_patterns("@!mac*", {subhost = "macosx"})) t:require(_match_patterns("@!macosx", {subhost = "linux"})) t:require(_match_patterns("@!mac*", {subhost = "linux"})) end function test_subhost_subarch(t) t:require(_match_patterns("@*|x86_64", {subhost = "macosx", subarch = "x86_64"})) t:require(_match_patterns("@macosx|x86_64", {subhost = "macosx", subarch = "x86_64"})) t:require(_match_patterns("@macosx|x86_*", {subhost = "macosx", subarch = "x86_64"})) t:require_not(_match_patterns("@macosx|x86_64", {subhost = "linux", subarch = "x86_64"})) t:require_not(_match_patterns("@macosx|i386", {subhost = "macosx", subarch = "x86_64"})) t:require_not(_match_patterns("@!macosx|x86_64", {subhost = "macosx", subarch = "x86_64"})) t:require_not(_match_patterns("@!mac*|x86_64", {subhost = "macosx", subarch = "x86_64"})) t:require(_match_patterns("@!macosx|x86_64", {subhost = "linux", subarch = "x86_64"})) t:require(_match_patterns("@!mac*|x86_64", {subhost = "linux", subarch = "x86_64"})) t:require(_match_patterns("@macosx|!i386", {subhost = "macosx", subarch = "x86_64"})) t:require(_match_patterns("@!macosx|!i386", {subhost = "linux", subarch = "x86_64"})) t:require(_match_patterns("@windows|!x86", {subhost = "windows", subarch = "x64"})) t:require_not(_match_patterns("@windows|!x86", {subhost = "android", subarch = "arm64-v8a"})) t:require(_match_patterns("@macosx|native", {subhost = "macosx", subarch = "x86_64"})) t:require(_match_patterns("@macosx|native", {subhost = "macosx", subarch = "arm64"})) t:require_not(_match_patterns("@macosx|!native", {subhost = "macosx", subarch = "x86_64"})) t:require_not(_match_patterns("@windows|native", {subhost = "macosx", subarch = "x86_64"})) end function test_plat_subhost(t) t:require(_match_patterns("*@macosx", {plat = "macosx", subhost = "macosx"})) t:require(_match_patterns("android@macosx", {plat = "android", subhost = "macosx"})) t:require(_match_patterns("android@macosx,linux", {plat = "android", subhost = "linux"})) t:require(_match_patterns("android@mac*", {plat = "android", subhost = "macosx"})) t:require(_match_patterns("android@!macosx", {plat = "android", subhost = "linux"})) t:require_not(_match_patterns("!android@macosx", {plat = "android", subhost = "macosx"})) t:require(_match_patterns("!iphon*@macosx", {plat = "linux", subhost = "macosx"})) end function test_plat_arch_subhost(t) t:require(_match_patterns("*|x86_64@macosx", {plat = "macosx", subhost = "macosx", arch = "x86_64"})) t:require(_match_patterns("android|arm64-v8a@macosx", {plat = "android", subhost = "macosx", arch = "arm64-v8a"})) t:require(_match_patterns("android|x86_64@macosx,linux", {plat = "android", subhost = "linux", arch = "x86_64"})) t:require(_match_patterns("android|x86_64@mac*", {plat = "android", subhost = "macosx", arch = "x86_64"})) t:require(_match_patterns("android|x86_64@!macosx", {plat = "android", subhost = "linux", arch = "x86_64"})) t:require_not(_match_patterns("!android|x86_64@macosx", {plat = "android", subhost = "macosx", arch = "x86_64"})) t:require(_match_patterns("!iphon*|x86_64@macosx", {plat = "linux", subhost = "macosx", arch = "x86_64"})) t:require(_match_patterns("iphon*|arm64@macosx", {plat = "iphoneos", subhost = "macosx", arch = "arm64"})) t:require_not(_match_patterns("iphon*|arm64@macosx", {plat = "iphoneos", subhost = "linux", arch = "arm64"})) end function test_plat_arch_subhost_subarch(t) t:require(_match_patterns("*|x86_64@macosx|x86_64", {plat = "macosx", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) t:require(_match_patterns("android|arm64-v8a@macosx|x86_64", {plat = "android", subhost = "macosx", arch = "arm64-v8a", subarch = "x86_64"})) t:require(_match_patterns("android|x86_64@macosx|x86_64,linux|x86_64", {plat = "android", subhost = "linux", arch = "x86_64", subarch = "x86_64"})) t:require(_match_patterns("android|x86_64@mac*|x86_64", {plat = "android", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) t:require(_match_patterns("android|x86_64@!macosx|x86_64", {plat = "android", subhost = "linux", arch = "x86_64", subarch = "x86_64"})) t:require_not(_match_patterns("!android|x86_64@macosx|x86_64", {plat = "android", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) t:require(_match_patterns("!iphon*|x86_64@macosx|x86_64", {plat = "linux", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) t:require(_match_patterns("iphon*|arm64@macosx|x86_64", {plat = "iphoneos", subhost = "macosx", arch = "arm64", subarch = "x86_64"})) t:require_not(_match_patterns("iphon*|arm64@macosx|x86_64", {plat = "iphoneos", subhost = "linux", arch = "arm64", subarch = "x86_64"})) t:require(_match_patterns("android|native@macosx|x86_64", {plat = "android", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) end function test_logical_expr(t) t:require(_match_patterns("!macosx|x86_64,!iphoneos|arm64", {plat = "linux", arch = "x86_64"})) t:require(_match_patterns("!wasm|!arm* and !cross|!arm*", {plat = "linux", arch = "x86_64"})) t:require_not(_match_patterns("!wasm|!arm* and !cross|!arm*", {plat = "linux", arch = "arm64"})) t:require_not(_match_patterns("!wasm|!arm* and !cross|!arm*", {plat = "wasm", arch = "x86_64"})) t:require(_match_patterns("!macosx|x86_64 or !iphoneos|arm64", {plat = "linux", arch = "x86_64"})) t:require_not(_match_patterns("!android@macosx or !android@linux", {plat = "android", subhost = "macosx"})) t:require(_match_patterns("@macosx|x86_64 or @linux|x86_64", {subhost = "macosx", subarch = "x86_64"})) t:require(_match_patterns("@macosx or @linux", {subhost = "macosx"})) t:require(_match_patterns("!wasm|!arm* or (!cross|!arm* or linux)", {plat = "linux", arch = "arm64"})) t:require_not(_match_patterns("!wasm|!arm* or (!cross|!arm* and !linux)", {plat = "linux", arch = "arm64"})) t:require_not(_match_patterns("!macosx|x86_64 and !linux|x86_64", {plat = "linux", arch = "x86_64"})) t:require_not(_match_patterns("!macosx and !android", {plat = "android"})) t:require_not(_match_patterns("!macosx and !android", {plat = "macosx"})) end ================================================ FILE: tests/modules/process/process_autoexit.lua ================================================ import("core.base.process") import("core.base.scheduler") function main(cmd) for i = 1, 10 do scheduler.co_start(function () process.open(cmd or "xmake l os.sleep 60000") --process.openv("xmake", {"l", "os.sleep", "60000"}, {detach = true}):close() end) end -- check processes status after exiting -- we need to terminate all unclosed processes automatically after parent process is exited -- ps aux | grep sleep end ================================================ FILE: tests/modules/process/process_killed.lua ================================================ import("core.base.process") import("core.base.scheduler") function main(cmd) for i = 1, 10 do scheduler.co_start(function () -- @note we need test xx.bat cmd on windows local proc = process.open(cmd or "xmake l os.sleep 60000") print("%s: wait ..", proc) -- we need to terminate all unclosed processes automatically after parent process is exited after do ctrl-c proc:wait(-1) print("%s: wait ok", proc) proc:close() end) end end ================================================ FILE: tests/modules/process/sched_process.lua ================================================ import("core.base.process") import("core.base.scheduler") function _session(id, program, ...) local proc = process.openv(program, table.pack(...)) local ok, status = proc:wait(-1) print("%s/%d: %d, status: %d", proc, id, ok, status) proc:close() end function main(program, ...) for i = 1, 10 do scheduler.co_start(_session, i, program, ...) end end ================================================ FILE: tests/modules/process/sched_process_pipe.lua ================================================ import("core.base.pipe") import("core.base.bytes") import("core.base.process") import("core.base.scheduler") function _session_read_pipe(id, rpipeopt) local buff = bytes(8192) local rpipe = rpipeopt.rpipe print("%s/%d: read ..", rpipe, id) local read = 0 while not rpipeopt.stop do local real, data = rpipe:read(buff, 8192 - read, {start = read + 1}) if real > 0 then read = read + real elseif real == 0 then if rpipe:wait(pipe.EV_READ, -1) < 0 then break end else break end end local results = bytes(buff, 1, read) print("%s/%d: read ok, size: %d", rpipe, id, results:size()) if results:size() > 0 then results:dump() end rpipe:close() end function _session(id, program, ...) local rpipe, wpipe = pipe.openpair() local rpipeopt = {rpipe = rpipe, stop = false} scheduler.co_start(_session_read_pipe, id, rpipeopt) local proc = process.openv(program, table.pack(...), {stdout = wpipe}) local ok, status = proc:wait(-1) rpipeopt.stop = true print("%s/%d: %d, status: %d", proc, id, ok, status) proc:close() wpipe:close() end function main(program, ...) for i = 1, 10 do scheduler.co_start(_session, i, program, ...) end end ================================================ FILE: tests/modules/process/test.lua ================================================ import("core.base.process") import("core.base.scheduler") local inftimeout = 5000 function test_single_process(t) local stdout = os.tmpfile() local stderr = os.tmpfile() local proc = process.openv("xmake", {"lua", "print", "xmake"}, {stdout = stdout, stderr = stderr}) proc:wait(inftimeout) proc:close() t:are_equal(io.readfile(stdout):trim(), "xmake") end function test_sched_process(t) local count = 0 local _session = function () local stdout = io.open(os.tmpfile(), 'w') local stderr = io.open(os.tmpfile(), 'w') local proc = process.openv("xmake", {"lua", "print", "xmake"}, {stdout = stdout, stderr = stderr}) local ok, status = proc:wait(inftimeout) proc:close() stdout:close() stderr:close() count = count + 1 end scheduler.co_group_begin("test", function () for i = 1, 3 do scheduler.co_start(_session) end end) scheduler.co_group_wait("test") t:are_equal(count, 3) end ================================================ FILE: tests/modules/queue/test.lua ================================================ import("core.base.queue") function test_push(t) local d = queue.new() d:push(1) d:push(2) d:push(3) d:push(4) d:push(5) t:are_equal(d:first(), 1) t:are_equal(d:last(), 5) local idx = 1 for item in d:items() do t:are_equal(item, idx) idx = idx + 1 end end function test_pop(t) local d = queue.new() d:push(1) d:push(2) d:push(3) d:push(4) d:push(5) d:pop() t:are_equal(d:first(), 2) t:are_equal(d:last(), 5) local idx = 2 for item in d:items() do t:are_equal(item, idx) idx = idx + 1 end end ================================================ FILE: tests/modules/scheduler/semaphore.lua ================================================ import("core.base.scheduler") function _loop(semaphore, id) print("[%d]: start", id) while true do print("[%d]: wait ..", id) local value = semaphore:wait(-1) print("[%d]: -> triggered, value: %d ..", id, value) end end function _input(semaphore) while true do if io.readable() then local ch = io.read() print(" -> post semaphore") if ch then semaphore:post(2) end else os.sleep(1000) end end end function main() local semaphore = scheduler.co_semaphore("", 1) for i = 1, 10 do scheduler.co_start(_loop, semaphore, i) end scheduler.co_start(_input, semaphore) end ================================================ FILE: tests/modules/scheduler/sleep.lua ================================================ import("core.base.scheduler") function _session2(id) print("session2: %d ..", id) local dt = os.mclock() os.sleep(1000) dt = os.mclock() - dt print("session2: %d end, dt: %d ms", id, dt) end function _session1(id) print("session1: %d ..", id) local dt = os.mclock() scheduler.co_sleep(1000) dt = os.mclock() - dt print("session1: %d end, dt: %d ms", id, dt) end function main() for i = 1, 10 do scheduler.co_start(_session1, i) scheduler.co_start(_session2, i) end end ================================================ FILE: tests/modules/scheduler/spinner.lua ================================================ import("async.runjobs") function main() printf("testing .. ") runjobs("test", function () os.sleep(10000) end, {waiting_indicator = true}) print("ok") end ================================================ FILE: tests/modules/scheduler/test.lua ================================================ import("core.base.scheduler") function test_group(t) local count = 0 local task = function (a) t:are_equal(a, "xmake!") count = count + 1 end scheduler.co_group_begin("test", function () for i = 1, 100 do scheduler.co_start(task, "xmake!") end end) scheduler.co_group_wait("test") t:are_equal(count, 100) end function test_sleep(t) local count = 0 local task = function (a) local dt = os.mclock() os.sleep(500) dt = os.mclock() - dt t:require(dt > 100 and dt < 1000) count = count + 1 end for i = 1, 3 do scheduler.co_start(task) end end function test_yield(t) local count = 0 local task = function (a) scheduler.co_yield() count = count + 1 end scheduler.co_group_begin("test", function () for i = 1, 10 do scheduler.co_start(task) end end) scheduler.co_group_wait("test") t:are_equal(count, 10) end function test_runjobs(t) import("async.runjobs") local total = 100 local comax = 6 local count = 0 runjobs("test", function (index) t:require(index >= 1 and index <= total) count = count + 1 end, {total = total, comax = comax}) t:are_equal(count, total) end ================================================ FILE: tests/modules/scheduler/yield.lua ================================================ import("core.base.scheduler") function _session(id) print("test: %d ..", id) scheduler.co_yield() print("test: %d end", id) end function main() for i = 1, 10 do scheduler.co_start(_session, i) end end ================================================ FILE: tests/modules/semver/test.lua ================================================ import("core.base.semver") -- select version function _check_semver_select(t, results, required_ver, versions, tags, branches) local version, source = semver.select(required_ver, versions or {}, tags or {}, branches or {}) t:are_equal((version.version or version), results[1]) t:are_equal(source, results[2]) end -- test select version function test_semver_select(t) _check_semver_select(t, {"1.5.1", "version"} , ">=1.5.0 <1.6.0" , {"1.4.0", "1.5.0", "1.5.1"}) _check_semver_select(t, {"1.5.1", "version"} , "^1.5.0" ,{"1.4.0", "1.5.0", "1.5.1"}) _check_semver_select(t, {"master", "branch"} , "master" , {"1.4.0", "1.5.0", "1.5.1"} , {"v1.2.0", "v1.6.0"} , {"master", "dev"}) _check_semver_select(t, {"1.5.1", "version"} , "latest" , {"1.4.0", "1.5.0", "1.5.1"}) end -- select version function _check_semver_satisfies(t, expected, version, range) local result = semver.satisfies(version, range) t:are_equal(result, expected) end -- test satisfies version function test_semver_satisfies(t) _check_semver_satisfies(t, true, "1.5.1", ">=1.5.0 <1.6.0") _check_semver_satisfies(t, true, "1.5.1", "^1.5.0") _check_semver_satisfies(t, true, "1.5.1", "~1.5.0") _check_semver_satisfies(t, true, "1.6.0", "^1.5.0") _check_semver_satisfies(t, true, "1.6.0", "v1.6.0") _check_semver_satisfies(t, false, "1.6.1", "~1.5.0") _check_semver_satisfies(t, false, "2.5.1", "^1.5.0") _check_semver_satisfies(t, false, "1.4.1", ">=1.5.0 <1.6.0") _check_semver_satisfies(t, false, "1.6.0", "v1.6.1") end -- parse version function _check_semver_parse(t, version_str, major, minor, patch, prerelease, build) local version = semver.new(version_str) t:require(version) t:are_equal(version:major(), major) t:are_equal(version:minor(), minor) t:are_equal(version:patch(), patch) t:are_equal(version:prerelease(), prerelease or {}) t:are_equal(version:build(), build or {}) end -- match version function _check_semver_match(t, str, version_str, major, minor, patch, prerelease, build) local version = semver.match(str) t:require(version) t:are_equal(version:rawstr(), version_str) t:are_equal(version:major(), major) t:are_equal(version:minor(), minor) t:are_equal(version:patch(), patch) t:are_equal(version:prerelease(), prerelease or {}) t:are_equal(version:build(), build or {}) end -- test parse version function test_semver_parse(t) _check_semver_parse(t, "1.2.3", 1, 2, 3) _check_semver_parse(t, "1.2.3-beta", 1, 2, 3, {"beta"}) _check_semver_parse(t, "1.2.3-beta+77", 1, 2, 3, {"beta"}, {77}) _check_semver_parse(t, "v1.2.3-alpha.1+77", 1, 2, 3, {"alpha", 1}, {77}) _check_semver_parse(t, "v3.2.1-alpha.1+77.foo", 3, 2, 1, {"alpha", 1}, {77, "foo"}) end -- test match version string function test_semver_match(t) _check_semver_match(t, "gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0", "7.4.0-1ubuntu1", 7, 4, 0, {"1ubuntu1"}) _check_semver_match(t, "gcc (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 8.1.0", "8.1.0", 8, 1, 0) _check_semver_match(t, "DMD64 D Compiler v2.090.0", "2.090.0", 2, 90, 0) _check_semver_match(t, "Apple clang version 11.0.0 (clang-1100.0.33.12)", "11.0.0", 11, 0, 0) _check_semver_match(t, "curl 7.54.0 (x86_64-apple-darwin18.0) libcurl/7.54.0 LibreSSL/2.6.5 zlib/1.2.11 nghttp2/1.24.1", "7.54.0", 7, 54, 0) end ================================================ FILE: tests/modules/signal/sigint.lua ================================================ import("core.base.signal") function main() signal.register(signal.SIGINT, function (signo) print("signal.SIGINT(%d)", signo) end) io.read() end ================================================ FILE: tests/modules/socket/sched_tcp/echo_client.lua ================================================ import("core.base.bytes") import("core.base.socket") import("core.base.scheduler") function _session_recv(sock) print("%s: recv ..", sock) local count = 0 local result = nil local buff = bytes(8192) while count < 100000 do local recv, data = sock:recv(buff, 13, {block = true}) if recv > 0 then result = data count = count + 1 else break end end print("%s: recv ok, count: %d!", sock, count) if result then result:dump() end end function _session_send(sock) print("%s: send ..", sock) local count = 0 while count < 100000 do local send = sock:send("hello world..", {block = true}) if send > 0 then count = count + 1 else break end end print("%s: send ok, count: %d!", sock, count) end local socks = {} function _session(addr, port) print("connect %s:%d ..", addr, port) local sock = socket.connect(addr, port) if sock then print("%s: connected!", sock) table.insert(socks, sock) sock:ctrl(socket.CTRL_SET_SENDBUFF, 6000000) sock:ctrl(socket.CTRL_SET_RECVBUFF, 6000000) scheduler.co_group_begin("test", function () scheduler.co_start(_session_recv, sock) scheduler.co_start(_session_send, sock) end) else print("connect %s:%d failed", addr, port) end end function main(count) count = count and tonumber(count) or 1 scheduler.co_group_begin("test", function () for i = 1, count do scheduler.co_start(_session, "127.0.0.1", 9091) end end) scheduler.co_group_wait("test") for _, sock in ipairs(socks) do sock:close() end end ================================================ FILE: tests/modules/socket/sched_tcp/echo_server.lua ================================================ import("core.base.bytes") import("core.base.socket") import("core.base.scheduler") function _session_recv(sock) print("%s: recv ..", sock) local count = 0 local result = nil local buff = bytes(8192) while count < 100000 do local recv, data = sock:recv(buff, 13, {block = true}) if recv > 0 then result = data count = count + 1 else break end end print("%s: recv ok, count: %d!", sock, count) if result then result:dump() end end function _session_send(sock) print("%s: send ..", sock) local count = 0 while count < 100000 do local send = sock:send("hello world..", {block = true}) if send > 0 then count = count + 1 else break end end print("%s: send ok, count: %d!", sock, count) end function _listen(addr, port) local sock_clients = {} local sock = socket.bind(addr, port) sock:listen(100) print("%s: listening %s:%d ..", sock, addr, port) while true do local sock_client = sock:accept() if sock_client then print("%s: accepted", sock_client) table.insert(sock_clients, sock_client) sock_client:ctrl(socket.CTRL_SET_SENDBUFF, 6000000) sock_client:ctrl(socket.CTRL_SET_RECVBUFF, 6000000) scheduler.co_start(_session_recv, sock_client) scheduler.co_start(_session_send, sock_client) end end for _, sock_client in ipairs(sock_clients) do sock_client:close() end sock:close() end function main() scheduler.co_start(_listen, "127.0.0.1", 9091) end ================================================ FILE: tests/modules/socket/sched_tcp/file_client.lua ================================================ import("core.base.socket") import("core.base.scheduler") import("core.base.bytes") function _session(addr, port) print("connect %s:%d ..", addr, port) local sock = socket.connect(addr, port) print("%s: connected!", sock) local real = 0 local recv = 0 local data = nil local wait = false local buff = bytes(8192) while true do real, data = sock:recv(buff, 8192) if real > 0 then recv = recv + real wait = false elseif real == 0 and not wait then if sock:wait(socket.EV_RECV, -1) == socket.EV_RECV then wait = true else break end else break end end print("%s: recv ok, size: %d!", sock, recv) sock:close() end function main(count) count = count and tonumber(count) or 1 for i = 1, count do scheduler.co_start(_session, "127.0.0.1", 9092) end end ================================================ FILE: tests/modules/socket/sched_tcp/file_server.lua ================================================ import("core.base.socket") import("core.base.scheduler") function _session(sock, filepath) local file = io.open(filepath, 'rb') if file then local send = sock:sendfile(file, {block = true}) print("%s: send %s %d bytes!", sock, filepath, send) file:close() end sock:close() end function _listen(addr, port, filepath) local sock = socket.bind(addr, port) sock:listen(100) print("%s: listening %s:%d ..", sock, addr, port) while true do local sock_client = sock:accept() if sock_client then print("%s: accepted", sock_client) scheduler.co_start(_session, sock_client, filepath) end end sock:close() end function main(filepath) scheduler.co_start(_listen, "127.0.0.1", 9092, filepath) end ================================================ FILE: tests/modules/socket/sched_udp/echo_client.lua ================================================ import("core.base.bytes") import("core.base.socket") import("core.base.scheduler") function _session(addr, port, data) local buff = bytes(8192) local sock = socket.udp() local send = sock:sendto(data or "hello xmake!", addr, port, {block = true}) print("%s: send to %s:%d %d bytes!", sock, addr, port, send) local recv, data, peer_addr, peer_port = sock:recvfrom(buff, 8112, {block = true}) if recv > 0 then print("%s: recv %d bytes from %s:%d", sock, recv, peer_addr, peer_port) data:dump() end sock:close() end function main(data) scheduler.co_start(_session, "127.0.0.1", 9091, data) end ================================================ FILE: tests/modules/socket/sched_udp/echo_server.lua ================================================ import("core.base.bytes") import("core.base.socket") import("core.base.scheduler") function _listen(addr, port) local buff = bytes(8192) local sock = socket.udp() sock:bind(addr, port) while true do print("%s: recv in %s:%d ..", sock, addr, port) local recv, data, peer_addr, peer_port = sock:recvfrom(buff, 8192, {block = true}) print("%s: recv %d bytes from: %s:%d", sock, recv, peer_addr, peer_port) if data then data:dump() sock:sendto(data, peer_addr, peer_port) end end sock:close() end function main() scheduler.co_start(_listen, "127.0.0.1", 9091) end ================================================ FILE: tests/modules/socket/tcp/echo_client.lua ================================================ import("core.base.bytes") import("core.base.socket") function main() local addr = "127.0.0.1" local port = 9091 print("connect %s:%d ..", addr, port) local sock = socket.connect(addr, port) if sock then print("%s: connected!", sock) local count = 0 local buff = bytes(8192) while count < 10000 do local send = sock:send("hello world..", {block = true}) if send > 0 then sock:recv(buff, 13, {block = true}) else break end count = count + 1 end print("%s: send ok, count: %d!", sock, count) sock:close() end end ================================================ FILE: tests/modules/socket/tcp/echo_server.lua ================================================ import("core.base.bytes") import("core.base.socket") function main() local addr = "127.0.0.1" local port = 9091 local sock = socket.bind(addr, port) sock:listen(20) print("%s: listening %s:%d ..", sock, addr, port) while true do local sock_client = sock:accept() if sock_client then print("%s: accepted", sock_client) local count = 0 local result = nil local buff = bytes(8192) while true do local recv, data = sock_client:recv(buff, 13, {block = true}) if recv > 0 then result = data sock_client:send(data, {block = true}) count = count + 1 else break end end print("%s: recv: %d, count: %d", sock_client, result and result:size() or 0, count) if result then result:dump() end sock_client:close() end end sock:close() end ================================================ FILE: tests/modules/socket/tcp/file_client.lua ================================================ import("core.base.socket") import("core.base.bytes") function main() local addr = "127.0.0.1" local port = 9092 print("connect %s:%d ..", addr, port) local sock = socket.connect(addr, port) print("%s: connected!", sock) local real = 0 local recv = 0 local data = nil local wait = false local buff = bytes(8192) while true do real, data = sock:recv(buff, 8192) if real > 0 then recv = recv + real wait = false elseif real == 0 and not wait then if sock:wait(socket.EV_RECV, -1) == socket.EV_RECV then wait = true else break end else break end end print("%s: recv ok, size: %d!", sock, recv) sock:close() end ================================================ FILE: tests/modules/socket/tcp/file_server.lua ================================================ import("core.base.socket") function main(filepath) local addr = "127.0.0.1" local port = 9092 local sock = socket.bind(addr, port) sock:listen(20) print("%s: listening %s:%d ..", sock, addr, port) while true do local sock_client = sock:accept() if sock_client then print("%s: accepted", sock_client) local file = io.open(filepath, 'rb') if file then local send = sock_client:sendfile(file, {block = true}) print("%s: send %s %d bytes!", sock_client, filepath, send) file:close() end sock_client:close() end end sock:close() end ================================================ FILE: tests/modules/socket/udp/echo_client.lua ================================================ import("core.base.bytes") import("core.base.socket") function main(data) local addr = "127.0.0.1" local port = 9091 local buff = bytes(8192) local sock = socket.udp() local send = sock:sendto(data or "hello xmake!", addr, port, {block = true}) print("%s: send to %s:%d %d bytes!", sock, addr, port, send) local recv, data, peer_addr, peer_port = sock:recvfrom(buff, 8112, {block = true}) if recv > 0 then print("%s: recv %d bytes from %s:%d", sock, recv, peer_addr, peer_port) data:dump() end sock:close() end ================================================ FILE: tests/modules/socket/udp/echo_server.lua ================================================ import("core.base.bytes") import("core.base.socket") function main() local addr = "127.0.0.1" local port = 9091 local sock = socket.udp() local buff = bytes(8192) sock:bind(addr, port) while true do print("%s: recv in %s:%d ..", sock, addr, port) local recv, data, peer_addr, peer_port = sock:recvfrom(buff, 8192, {block = true}) print("%s: recv %d bytes from: %s:%d", sock, recv, peer_addr, peer_port) if data then data:dump() sock:sendto(data, peer_addr, peer_port) end end sock:close() end ================================================ FILE: tests/modules/socket/unix_tcp/echo_client.lua ================================================ import("core.base.bytes") import("core.base.socket") function main(addr) addr = addr or path.join(os.tmpdir(), "echo.socket") print("connect %s ..", addr) local buff = bytes(8192) local sock = socket.connect_unix(addr) if sock then print("%s: connected!", sock) local count = 0 while count < 10000 do local send = sock:send("hello world..", {block = true}) if send > 0 then sock:recv(buff, 13, {block = true}) else break end count = count + 1 end print("%s: send ok, count: %d!", sock, count) sock:close() end end ================================================ FILE: tests/modules/socket/unix_tcp/echo_server.lua ================================================ import("core.base.bytes") import("core.base.socket") function main(addr) addr = addr or path.join(os.tmpdir(), "echo.socket") os.tryrm(addr) local sock = socket.bind_unix(addr) sock:listen(20) print("%s: listening %s ..", sock, addr) while true do local sock_client = sock:accept() if sock_client then print("%s: accepted", sock_client) local count = 0 local result = nil local buff = bytes(8192) while true do local recv, data = sock_client:recv(buff, 13, {block = true}) if recv > 0 then result = data sock_client:send(data, {block = true}) count = count + 1 else break end end print("%s: recv: %d, count: %d", sock_client, result and result:size() or 0, count) if result then result:dump() end sock_client:close() end end sock:close() end ================================================ FILE: tests/modules/socket/unix_tcp/file_client.lua ================================================ import("core.base.socket") import("core.base.bytes") function main(addr) addr = addr or path.join(os.tmpdir(), "file.socket") print("connect %s ..", addr) local sock = socket.connect_unix(addr) print("%s: connected!", sock) local real = 0 local recv = 0 local data = nil local wait = false local buff = bytes(8192) while true do real, data = sock:recv(buff, 8192) if real > 0 then recv = recv + real wait = false elseif real == 0 and not wait then if sock:wait(socket.EV_RECV, -1) == socket.EV_RECV then wait = true else break end else break end end print("%s: recv ok, size: %d!", sock, recv) sock:close() end ================================================ FILE: tests/modules/socket/unix_tcp/file_server.lua ================================================ import("core.base.socket") function main(filepath, addr) addr = addr or path.join(os.tmpdir(), "file.socket") local sock = socket.bind_unix(addr) sock:listen(20) print("%s: listening %s ..", sock, addr) while true do local sock_client = sock:accept() if sock_client then print("%s: accepted", sock_client) local file = io.open(filepath, 'rb') if file then local send = sock_client:sendfile(file, {block = true}) print("%s: send %s %d bytes!", sock_client, filepath, send) file:close() end sock_client:close() end end sock:close() end ================================================ FILE: tests/modules/stdin/test.lua ================================================ import("lib.detect.find_tool") function _run_sh(t, name, cmd, expect) if not is_host("windows") then local xmake = path.translate(os.programfile()) local run_stdin = string.format('"%s" l --stdin', xmake) local outdata = os.iorunv("sh", {"-c", cmd .. " | " .. run_stdin}) or "" t:are_equal(outdata:trim(), expect) end end function _run_cmd(t, name, cmd, expect) if is_host("windows") then local xmake = path.translate(os.programfile()) local run_stdin = string.format('%s l --stdin', xmake) local outdata = os.iorunv("cmd", {"/c", cmd .. " | " .. run_stdin}) or "" t:are_equal(outdata:trim(), expect) end end function _run_pwsh(t, name, cmd, expect) if is_host("windows") then local xmake = path.translate(os.programfile()) local run_stdin = string.format('%s l --stdin', xmake) local pwsh = find_tool("powershell") if pwsh then local outdata = os.iorunv(pwsh.program, {"-c", cmd .. " | " .. run_stdin}) or "" t:are_equal(outdata:trim(), expect) end end end function test_sh(t) _run_sh(t, "sh_single", "echo \"print('hello_sh')\"", "hello_sh") _run_sh(t, "sh_calc", "echo \"local f = 1+1; print(f)\"", "2") _run_sh(t, "sh_main", "echo \"function main() print('in_sh_main') end\"", "in_sh_main") _run_sh(t, "sh_multi", "printf \"print('shell_line1')\\nprint('shell_line2')\"", "shell_line1\nshell_line2") end function test_cmd(t) _run_cmd(t, "cmd_single", "echo print 'hello_cmd'", "hello_cmd") _run_cmd(t, "cmd_calc", "echo local f = 1+1; print(f)", "2") _run_cmd(t, "cmd_multi_lines", "(echo print 'line1' && echo print 'line2')", "line1\nline2") _run_cmd(t, "cmd_multi_semicolon", "echo print('semi1'); print('semi2')", "semi1\nsemi2") end function test_pwsh(t) _run_pwsh(t, "pwsh_single", "echo \"print('hello_pwsh')\"", "hello_pwsh") _run_pwsh(t, "pwsh_calc", "echo \"local f = 1+1; print(f)\"", "2") _run_pwsh(t, "pwsh_main", "echo \"function main() print('in_pwsh_main') end\"", "in_pwsh_main") _run_pwsh(t, "pwsh_multi", "echo \"print('pline1')\" \"print('pline2')\"", "pline1\npline2") end ================================================ FILE: tests/modules/string/lastof_perf.lua ================================================ function _lastof_perf(str, pattern, opt) local plain = opt and opt.plain local dt = os.mclock() for i = 0, 1000000 do str:lastof(pattern, plain) end dt = os.mclock() - dt print("lastof(%s .., %s, %s): %d ms", str:sub(1, 16), pattern, string.serialize(opt or {}, {strip = true, indent = false}), dt) end function main() local str = "shortstr: 123abc123123xyz[123]+abc123" _lastof_perf(str, "1") _lastof_perf(str, "123") _lastof_perf(str, "[123]+") print("") _lastof_perf(str, "1", {plain = true}) _lastof_perf(str, "123", {plain = true}) _lastof_perf(str, "[123]+", {plain = true}) print("") str = "longstr: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" for i = 0, 100 do str = str .. "[123]+" end _lastof_perf(str, "1") _lastof_perf(str, "123") _lastof_perf(str, "[123]+") print("") _lastof_perf(str, "1", {plain = true}) _lastof_perf(str, "123", {plain = true}) _lastof_perf(str, "[123]+", {plain = true}) print("") end ================================================ FILE: tests/modules/string/serialize/test.lua ================================================ function roundtripimpl(value, opt) local s, serr = string.serialize(value, opt) if serr then raise(serr) end local v, verr = s:deserialize() if verr then raise(verr) end return v end function roundtrip(round0) local round1 = roundtripimpl(round0, false) local round2 = roundtripimpl(round1, true) local round3 = roundtripimpl(round2, {binary=true}) local round4 = roundtripimpl(round3, {indent=16}) local round5 = roundtripimpl(round4, {indent=" \r\n\t"}) return round5 end function test_number(t) t:are_equal(roundtrip(12), 12) t:are_equal(roundtrip(0), 0) t:are_equal(roundtrip(-1), -1) t:are_equal(roundtrip(7.25), 7.25) t:are_equal(roundtrip(math.huge), math.huge) t:are_equal(roundtrip(-math.huge), -math.huge) t:are_equal(roundtrip(math.nan), math.nan) end function test_boolean(t) t:are_equal(roundtrip(true), true) t:are_equal(roundtrip(false), false) end function test_nil(t) t:are_equal(roundtrip(nil), nil) end function test_table(t) t:are_equal(roundtrip({}), {}) t:are_equal(roundtrip({{},{1}}), {{},{1}}) t:are_equal(roundtrip({["true"] = true}), {["true"] = true}) t:are_equal(roundtrip({1, 2, 3}), {1, 2, 3}) t:are_equal(roundtrip({1, "", 3}), {1, "", 3}) t:are_equal(roundtrip({{1, 2, 3, nil, 4}}), {{1, 2, 3, nil, 4}}) t:are_equal(roundtrip({{1, 2, 3, nil, 4, [100]=5}}), {{1, 2, 3, nil, 4, [100]=5}}) t:are_equal(roundtrip({{a=1, b=2, c=3, nil, 4}}), {{a=1, b=2, c=3, nil, 4}}) end function test_function(t) t:are_equal(roundtrip(function() return {} end)(), {}) t:are_equal(roundtrip(function() return {1, 2, 3} end)(), {1, 2, 3}) t:are_equal(roundtrip(function() return {{1, 2, 3, nil, 4}} end)(), {{1, 2, 3, nil, 4}}) t:are_equal(roundtrip({function() return {{1, 2, 3, nil, 4}} end})[1](), {{1, 2, 3, nil, 4}}) t:are_equal(roundtrip({{function() return {{1, 2, 3, nil, 4}} end}})[1][1](), {{1, 2, 3, nil, 4}}) -- x in fenv x = {} -- return x in fenv function f() return x end -- fenv will restore if xmake.luajit() then -- TODO we need to fix it for lua backend t:are_same(roundtrip(f)(), x) end y = {} -- y in fenv local g_y = y -- y in upvalue local y = {} -- return y in upvalue function g() return y end -- upvalue will not restore if striped t:are_same(roundtrip(g)(), nil) -- upvalue will be restored by fenv, so y in fenv is returned t:are_same(roundtripimpl(g)(), g_y) end function test_refloop(t) local l1 = {} l1.l = l1 local r1 = roundtrip(l1) t:are_same(r1.l, r1) local l2 = {{1}, {2}, {3}} l2[1].l = { root = l2, a = l2[1], b = l2[2], c = l2[3] } local r2 = roundtrip(l2) t:are_same(r2[1].l.root, r2) t:are_same(r2[1].l.a, r2[1]) t:are_same(r2[1].l.b, r2[2]) t:are_same(r2[1].l.c, r2[3]) end ================================================ FILE: tests/modules/string/split_perf.lua ================================================ function _split_perf(str, delimiter, opt) local dt = os.mclock() for i = 0, 1000000 do str:split(delimiter, opt) end dt = os.mclock() - dt print("split(%s .., %s, %s): %d ms", str:sub(1, 16), delimiter, string.serialize(opt or {}, {strip = true, indent = false}), dt) end function main() local str = "shortstr: 123abc123123xyz[123]+abc123" _split_perf(str, "1") _split_perf(str, "123") _split_perf(str, "[123]+") print("") _split_perf(str, "1", {plain = true}) _split_perf(str, "123", {plain = true}) _split_perf(str, "[123]+", {plain = true}) print("") str = "longstr: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" for i = 0, 100 do str = str .. "[123]+" end _split_perf(str, "1") _split_perf(str, "123") _split_perf(str, "[123]+") print("") _split_perf(str, "1", {plain = true}) _split_perf(str, "123", {plain = true}) _split_perf(str, "[123]+", {plain = true}) print("") end ================================================ FILE: tests/modules/string/test.lua ================================================ function test_endswith(t) t:require(("aaaccc"):endswith("ccc")) t:require(("aaaccc"):endswith("aaaccc")) t:require_not(("rc"):endswith("xcadas")) t:require_not(("aaaccc "):endswith("%s")) end function test_startswith(t) t:require(("aaaccc"):startswith("aaa")) t:require(("aaaccc"):startswith("aaaccc")) t:require_not(("rc"):startswith("xcadas")) t:require_not((" aaaccc"):startswith("%s")) end function test_trim(t) t:are_equal((""):trim(), "") t:are_equal((" "):trim(), "") t:are_equal((""):trim(""), "") t:are_equal((" "):trim(""), "") t:are_equal((" aaa ccc "):trim(), "aaa ccc") t:are_equal(("aaa ccc "):trim(), "aaa ccc") t:are_equal((" aaa ccc"):trim(), "aaa ccc") t:are_equal(("aaa ccc"):trim(), "aaa ccc") t:are_equal(("\t\naaa ccc\r\n"):trim(), "aaa ccc") t:are_equal(("aba"):trim("a"), "b") end function test_ltrim(t) t:are_equal((""):ltrim(), "") t:are_equal((" "):ltrim(), "") t:are_equal((""):ltrim(""), "") t:are_equal((" "):ltrim(""), "") t:are_equal((" aaa ccc "):ltrim(), "aaa ccc ") t:are_equal(("aaa ccc "):ltrim(), "aaa ccc ") t:are_equal((" aaa ccc"):ltrim(), "aaa ccc") t:are_equal(("aaa ccc"):ltrim(), "aaa ccc") t:are_equal(("\t\naaa ccc\r\n"):ltrim(), "aaa ccc\r\n") t:are_equal(("aba"):ltrim("a"), "ba") end function test_rtrim(t) t:are_equal((""):rtrim(), "") t:are_equal((" "):rtrim(), "") t:are_equal((""):rtrim(""), "") t:are_equal((" "):rtrim(""), "") t:are_equal((" aaa ccc "):rtrim(), " aaa ccc") t:are_equal(("aaa ccc "):rtrim(), "aaa ccc") t:are_equal((" aaa ccc"):rtrim(), " aaa ccc") t:are_equal(("aaa ccc"):rtrim(), "aaa ccc") t:are_equal(("\t\naaa ccc\r\n"):rtrim(), "\t\naaa ccc") t:are_equal(("aba"):rtrim("a"), "ab") end function test_split(t) -- pattern match and ignore empty string t:are_equal(("1\n\n2\n3"):split('\n'), {"1", "2", "3"}) t:are_equal(("abc123123xyz123abc"):split('123'), {"abc", "xyz", "abc"}) t:are_equal(("abc123123xyz123abc"):split('[123]+'), {"abc", "xyz", "abc"}) -- plain match and ignore empty string t:are_equal(("1\n\n2\n3"):split('\n', {plain = true}), {"1", "2", "3"}) t:are_equal(("abc123123xyz123abc"):split('123', {plain = true}), {"abc", "xyz", "abc"}) -- pattern match and contains empty string t:are_equal(("1\n\n2\n3"):split('\n', {strict = true}), {"1", "", "2", "3"}) t:are_equal(("abc123123xyz123abc"):split('123', {strict = true}), {"abc", "", "xyz", "abc"}) t:are_equal(("abc123123xyz123abc"):split('[123]+', {strict = true}), {"abc", "xyz", "abc"}) t:are_equal(("123abc123123xyz123abc123"):split('[123]+', {strict = true}), {"", "abc", "xyz", "abc", ""}) t:are_equal(("123123"):split('[123]+', {strict = true}), {"", ""}) t:are_equal((""):split('[123]+', {strict = true}), {""}) -- plain match and contains empty string t:are_equal(("1\n\n2\n3"):split('\n', {plain = true, strict = true}), {"1", "", "2", "3"}) t:are_equal(("abc123123xyz123abc"):split('123', {plain = true, strict = true}), {"abc", "", "xyz", "abc"}) t:are_equal(("123abc123123xyz123abc123"):split('123', {plain = true, strict = true}), {"", "abc", "", "xyz", "abc", ""}) t:are_equal(("123"):split('123', {plain = true, strict = true}), {"", ""}) t:are_equal((""):split('123', {plain = true, strict = true}), {""}) -- limit split count t:are_equal(("1\n\n2\n3"):split('\n', {limit = 2}), {"1", "2\n3"}) t:are_equal(("1\n\n2\n3"):split('\n', {limit = 2, strict = true}), {"1", "\n2\n3"}) t:are_equal(("\n1\n\n2\n3"):split('\n', {limit = 2, strict = true}), {"", "1\n\n2\n3"}) t:are_equal(("1.2.3.4.5"):split('%.', {limit = 3}), {"1", "2", "3.4.5"}) t:are_equal(("123.45"):split('%.', {limit = 3}), {"123", "45"}) t:are_equal((""):split('123', {plain = true, limit = 2, strict = true}), {""}) t:are_equal(("123123"):split('123', {plain = true, limit = 2, strict = true}), {"", "123"}) end function test_lastof(t) t:are_equal(("1.2.3.4.5"):lastof('%.'), 8) t:are_equal(("1.2.3.4.5"):lastof('.', true), 8) t:are_equal(("/home/file.txt"):lastof('[/\\]'), 6) t:are_equal(("/home/file.txt"):lastof('/', true), 6) t:are_equal(("/home/file.txt"):lastof('/home', true), 1) t:are_equal(("/home/file.txt"):lastof('[/\\]home'), 1) -- long string local longstr = ("a"):rep(1000) .. "b" t:are_equal(longstr:lastof("b"), 1001) t:are_equal(longstr:lastof("a"), 1000) t:are_equal(longstr:lastof("b", true), 1001) t:are_equal(longstr:lastof("a", true), 1000) end function test_replace(t) t:are_equal(("123xyz456xyz789xyz"):replace("123", "000"), "000xyz456xyz789xyz") t:are_equal(("123xyz456xyz789xyz"):replace("xyz", "000"), "123000456000789000") t:are_equal(("123xyz456xyz789xyz"):replace("123", "000", {plain = true}), "000xyz456xyz789xyz") t:are_equal(("123xyz456xyz789xyz"):replace("xyz", "000", {plain = true}), "123000456000789000") t:are_equal(("123$xyz456xyz789xyz"):replace("123$", "000"), "123$xyz456xyz789xyz") t:are_equal(("123xyz$456xyz$789xyz$"):replace("xyz$", "000"), "123xyz$456xyz$789xyz$") t:are_equal(("123$xyz456xyz789xyz"):replace("123$", "000", {plain = true}), "000xyz456xyz789xyz") t:are_equal(("123xyz$456xyz$789xyz$"):replace("xyz$", "000", {plain = true}), "123000456000789000") end function test_case(t) t:are_equal(("Hello"):lower(), "hello") t:are_equal(("Hello"):upper(), "HELLO") t:are_equal(("Звезда Хэнсин"):lower(), "звезда хэнсин") t:are_equal(("Звезда Хэнсин"):upper(), "ЗВЕЗДА ХЭНСИН") t:are_equal(("Test 源文件🎆 Message"):lower(), "test 源文件🎆 message") t:are_equal(("Test 源文件🎆 Message"):upper(), "TEST 源文件🎆 MESSAGE") end ================================================ FILE: tests/modules/table/test.lua ================================================ function test_remove_if(t) t:are_equal(table.remove_if({1, 2, 3, 4, 5, 6}, function (i, v) return (v % 2) == 0 end), {1, 3, 5}) t:are_equal(table.remove_if({a = 1, b = 2, c = 3}, function (i, v) return (v % 2) == 0 end), {a = 1, c = 3}) end function test_find_if(t) t:are_equal(table.find_if({1, 2, 3, 4, 5, 6}, function (i, v) return (v % 2) == 0 end), {2, 4, 6}) t:are_equal(table.find_first_if({1, 2, 3, 4, 5, 6}, function (i, v) return (v % 2) == 0 end), 2) t:are_equal(table.find({1, 2, 4, 4, 5, 6}, 4), {3, 4}) t:are_equal(table.find_first({1, 2, 3, 4, 5, 6}, 4), 4) end function test_wrap(t) t:are_equal(table.wrap(1), {1}) t:are_equal(table.wrap(nil), {}) t:are_equal(table.wrap({}), {}) t:are_equal(table.wrap({1}), {1}) t:are_equal(table.wrap({{}}), {{}}) local a = table.wrap_lock({1}) t:are_equal(table.wrap({a}), {a}) end function test_unwrap(t) t:are_equal(table.unwrap(1), 1) t:are_equal(table.unwrap(nil), nil) t:are_equal(table.unwrap({}), {}) t:are_equal(table.unwrap({1}), 1) t:are_equal(table.unwrap({{}}), {}) local a = table.wrap_lock({1}) t:are_equal(table.unwrap(a), a) end function test_orderkeys(t) -- sort by modulo 2 then from the smallest to largest local f = function(a, b) if a % 2 == 0 and b % 2 ~= 0 then return true elseif b % 2 == 0 and a % 2 ~= 0 then return false end return a < b end t:are_equal(table.orderkeys({[2] = 2, [1] = 1, [4] = 4, [3] = 3}, f), {2, 4, 1, 3}) t:are_equal(table.orderkeys({[1] = 1, [2] = 2, [3] = 3, [4] = 4}), {1, 2 , 3, 4}) end ================================================ FILE: tests/modules/thread/coroutine.lua ================================================ import("core.base.thread") import("core.base.scheduler") function thread_loop() import("core.base.thread") print("%s: starting ..", thread.running()) local dt = os.mclock() for i = 1, 10 do print("%s: %d", thread.running(), i) os.sleep(1000) end dt = os.mclock() - dt print("%s: end, dt: %d ms", thread.running(), dt) end function coroutine_loop() print("%s: starting ..", scheduler.co_running()) local dt = os.mclock() for i = 1, 10 do print("%s: %d", scheduler.co_running(), i) os.sleep(1000) end dt = os.mclock() - dt print("%s: end, dt: %d ms", scheduler.co_running(), dt) end function main() scheduler.co_start_named("coroutine", coroutine_loop) local t = thread.start_named("thread", thread_loop) t:wait(-1) end ================================================ FILE: tests/modules/thread/event.lua ================================================ import("core.base.thread") function callback(event) import("core.base.thread") print("%s: starting ..", thread.running()) while true do print("%s: waiting ..", thread.running()) if event:wait(-1) > 0 then print("%s: triggered", thread.running()) end end end function main() local event = thread.event() local t = thread.start_named("keyboard", callback, event) while true do local ch = io.read() if ch then event:post() end end t:wait(-1) end ================================================ FILE: tests/modules/thread/mutex.lua ================================================ import("core.base.thread") function callback(mutex) import("core.base.thread") print("%s: starting ..", thread.running()) local dt = os.mclock() for i = 1, 10 do mutex:lock() print("%s: %d", thread.running(), i) mutex:unlock() os.sleep(1000) end dt = os.mclock() - dt print("%s: end, dt: %d ms", thread.running(), dt) end function main() local mutex = thread.mutex() local t0 = thread.start_named("thread_0", callback, mutex) local t1 = thread.start_named("thread_1", callback, mutex) t0:wait(-1) t1:wait(-1) end ================================================ FILE: tests/modules/thread/queue.lua ================================================ import("core.base.thread") function callback(event, queue) print("starting ..") while true do print("waiting ..") if event:wait(-1) > 0 then while not queue:empty() do print(" -> %s", queue:pop()) end end end end function main() local event = thread.event() local queue = thread.queue() local t = thread.start_named("", callback, event, queue) while true do local ch = io.read() if ch then queue:push(ch) event:post() end end t:wait(-1) end ================================================ FILE: tests/modules/thread/semaphore.lua ================================================ import("core.base.thread") function callback(semaphore) import("core.base.thread") print("%s: starting ..", thread.running()) while true do print("%s: waiting ..", thread.running()) if semaphore:wait(-1) > 0 then print("%s: triggered", thread.running()) end end end function main() local semaphore = thread.semaphore("", 1) local t = thread.start_named("keyboard", callback, semaphore) while true do local ch = io.read() if ch then semaphore:post(2) end end t:wait(-1) end ================================================ FILE: tests/modules/thread/sharedata.lua ================================================ import("core.base.thread") function callback(event, sharedata) print("starting ..") while true do print("waiting ..") if event:wait(-1) > 0 then print(" -> %s", sharedata:get()) end end end function main() local event = thread.event() local sharedata = thread.sharedata() local t = thread.start_named("", callback, event, sharedata) while true do local ch = io.read() if ch then sharedata:set(ch) event:post() end end t:wait(-1) end ================================================ FILE: tests/modules/thread/sleep.lua ================================================ import("core.base.thread") function callback(id) import("core.base.thread") print("%s: %d starting ..", thread.running(), id) local dt = os.mclock() for i = 1, 10 do print("%s: %d", thread.running(), i) os.sleep(1000) end dt = os.mclock() - dt print("%s: %d end, dt: %d ms", thread.running(), id, dt) end function main() local t0 = thread.start_named("thread_0", callback, 0) local t1 = thread.start_named("thread_1", callback, 1) t0:wait(-1) t1:wait(-1) end ================================================ FILE: tests/modules/tty/cursor_control.lua ================================================ import("core.base.tty") -- Demo TTY cursor position control features -- Implement partial screen refresh function _progress_bar_inline(label, progress) local bar_width = 40 local filled = math.floor(progress * bar_width) local bar = string.rep("█", filled) .. string.rep("░", bar_width - filled) -- Clear the line and output content tty.cr() tty.erase_line() io.write(string.format("%s: [%s] %3d%%", label, bar, math.floor(progress * 100))) io.flush() end function main() -- Check if ANSI control codes are supported if not tty.has_vtansi() then print("Terminal does not support ANSI control codes") return end print("=== TTY Cursor Control Demo ===") print("This demo shows partial screen refresh using cursor positioning") print("") -- Hide cursor for smoother display tty.cursor_hide() print("\nDemo 1: Multiple Progress Bars (Parallel Updates)") print("------------------------------------------------") -- Reserve lines for progress bars io.write("Task 1: Downloading\n") io.write("Task 2: Compiling \n") io.write("Task 3: Linking \n") io.flush() -- Simulate three parallel task progress bars for step = 1, 100 do -- Move to Task 1 line (3 lines up from current position) tty.cursor_move_up(3) -- Update Task 1 progress local progress1 = step / 100 _progress_bar_inline("Task 1: Downloading", progress1) io.write("\n") -- Update Task 2 progress (starts later, progresses faster) local progress2 = math.max(0, math.min(1.0, (step - 10) / 80)) _progress_bar_inline("Task 2: Compiling ", progress2) io.write("\n") -- Update Task 3 progress (starts even later) local progress3 = math.max(0, math.min(1.0, (step - 30) / 60)) _progress_bar_inline("Task 3: Linking ", progress3) io.write("\n") io.flush() os.sleep(30) -- 30ms delay end print("\n\nDemo 2: Dynamic Status Updates") print("--------------------------------") -- Print initial status and counter io.write("Status: Waiting...\n") io.write("Counter: 0\n") io.flush() local statuses = { "Initializing...", "Loading configuration...", "Parsing files...", "Building dependencies...", "Compiling sources...", "Linking executable...", "Done!" } for i, status in ipairs(statuses) do -- Move to status line (2 lines up) tty.cursor_move_up(2) -- Update status line tty.cr() tty.erase_line() io.write(string.format("Status: %s", status)) io.write("\n") -- Update counter line tty.cr() tty.erase_line() io.write(string.format("Counter: %d", i * 100)) io.write("\n") io.flush() os.sleep(500) end -- Restore cursor visibility tty.cursor_show() print("\n\nDemo 3: Erase and Update Specific Line") print("----------------------------------------") io.write("Line 1: This line will stay\n") io.write("Line 2: This line will be updated...\n") io.write("Line 3: This line will stay too\n") io.flush() os.sleep(1000) -- Update only the middle line (2 lines up) tty.cursor_move_up(2) tty.cr() tty.erase_line() io.write("Line 2: Updated content! ✓\n") io.flush() -- Move cursor to end tty.cursor_move_down(1) print("\n\nAll demos completed!") print("\nKey features demonstrated:") print(" - cursor_move_up/down/left/right: Move cursor relatively") print(" - cursor_save/restore: Save and restore cursor position") print(" - erase_line(): Clear current line") print(" - cursor_hide()/cursor_show(): Control cursor visibility") print(" - Partial screen refresh without clearing entire screen") end ================================================ FILE: tests/modules/tty/live_dashboard.lua ================================================ import("core.base.tty") import("core.base.scheduler") -- Demo advanced usage: Live updating dashboard -- Similar to build tool real-time output function simulate_build_process() if not tty.has_vtansi() then print("Terminal does not support ANSI control codes") return end print("\nBuild Dashboard - Live Updates") print(string.rep("=", 60)) -- Hide cursor tty.cursor_hide() -- Print task list io.write("⏸ Parse project files [" .. string.rep("░", 30) .. "] 0%\n") io.write("⏸ Resolve dependencies [" .. string.rep("░", 30) .. "] 0%\n") io.write("⏸ Compile sources [" .. string.rep("░", 30) .. "] 0%\n") io.write("⏸ Link executable [" .. string.rep("░", 30) .. "] 0%\n") io.write("⏸ Create package [" .. string.rep("░", 30) .. "] 0%\n") io.write("\nRecent logs:\n") io.flush() local log_count = 0 local function update_task_line(task_index, icon, name, progress) -- Move to the task line (from current cursor position) -- We need to go up: log_count lines + 1 separator line + (5 - task_index) task lines local lines_up = log_count + 1 + (5 - task_index + 1) tty.cursor_move_up(lines_up) tty.cr() tty.erase_line() local bar_width = 30 local filled = math.floor(progress * bar_width) local bar = string.rep("█", filled) .. string.rep("░", bar_width - filled) io.write(string.format("%s %-24s [%s] %3d%%\n", icon, name, bar, math.floor(progress * 100))) -- Move back down tty.cursor_move_down(lines_up - 1) io.flush() end local function add_log(message) io.write(string.format("[%s] %s\n", os.date("%H:%M:%S"), message)) io.flush() log_count = log_count + 1 end scheduler.co_start(function() -- Task 1: Parse (index 1, top task) add_log("Starting project parsing...") for i = 1, 20 do update_task_line(1, "▶", "Parse project files", i / 20) os.sleep(50) end update_task_line(1, "✓", "Parse project files", 1.0) add_log("Project parsed successfully") os.sleep(200) -- Task 2: Dependencies (index 2) add_log("Resolving dependencies...") for i = 1, 15 do update_task_line(2, "▶", "Resolve dependencies", i / 15) os.sleep(80) end update_task_line(2, "✓", "Resolve dependencies", 1.0) add_log("Dependencies resolved: 12 packages") os.sleep(200) -- Task 3: Compile (index 3) add_log("Compiling source files...") local source_files = {"main.cpp", "utils.cpp", "config.cpp", "parser.cpp", "builder.cpp"} for i = 1, #source_files do update_task_line(3, "▶", "Compile sources", i / #source_files) add_log("Compiling " .. source_files[i]) os.sleep(300) end update_task_line(3, "✓", "Compile sources", 1.0) add_log("Compilation completed: 5 files") os.sleep(200) -- Task 4: Link (index 4) add_log("Linking executable...") for i = 1, 10 do update_task_line(4, "▶", "Link executable", i / 10) os.sleep(100) end update_task_line(4, "✓", "Link executable", 1.0) add_log("Executable created: build/myapp") os.sleep(200) -- Task 5: Package (index 5, bottom task) add_log("Creating package...") for i = 1, 8 do update_task_line(5, "▶", "Create package", i / 8) os.sleep(120) end update_task_line(5, "✓", "Create package", 1.0) add_log("Package created: dist/myapp-1.0.0.tar.gz") -- Done os.sleep(500) add_log("Build completed successfully! 🎉") -- Restore cursor os.sleep(1000) tty.cursor_show() print("\nBuild process completed!") end) end function demo_spinner() if not tty.has_vtansi() then return end print("\n\n=== Spinner Demo ===") io.write("Loading\n") io.flush() local frames = {"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"} tty.cursor_hide() for round = 1, 3 do for _, frame in ipairs(frames) do tty.cursor_move_up(1) tty.cr() tty.erase_line() io.write(string.format("Loading %s [round %d/3]\n", frame, round)) io.flush() os.sleep(80) end end tty.cursor_move_up(1) tty.cr() tty.erase_line() io.write("Loading ✓ Complete!\n") io.flush() tty.cursor_show() end function main() print("\n" .. string.rep("=", 60)) print("TTY Live Dashboard Demo") print(string.rep("=", 60)) -- Demo 1: Spinner demo_spinner() os.sleep(1000) -- Demo 2: Build Dashboard simulate_build_process() end ================================================ FILE: tests/modules/tty/quick_example.lua ================================================ -- Quick example: Demonstrates the most common use cases import("core.base.tty") function example1_simple_progress() print("\n=== Example 1: Simple Progress Bar ===\n") if not tty.has_vtansi() then print("ANSI not supported") return end print("Downloading file...") for i = 0, 100, 5 do local width = 40 local filled = math.floor(i / 100 * width) local bar = string.rep("█", filled) .. string.rep("░", width - filled) -- Move to start of line, clear it, and redraw tty.cr() tty.erase_line() io.write(string.format("[%s] %3d%%", bar, i)) io.flush() os.sleep(50) end print("") -- New line after progress end function example2_update_previous_line() print("\n=== Example 2: Update Previous Line ===\n") if not tty.has_vtansi() then print("ANSI not supported") return end io.write("Building project...\n") io.write("Status: Starting...\n") io.flush() os.sleep(1000) -- Go back and update the status line tty.cursor_move_up(1) tty.cr() tty.erase_line() io.write("Status: Compiling files...\n") io.flush() os.sleep(1000) tty.cursor_move_up(1) tty.cr() tty.erase_line() io.write("Status: Done! ✓\n") io.flush() end function example3_multi_line_update() print("\n=== Example 3: Multi-line Updates ===\n") if not tty.has_vtansi() then print("ANSI not supported") return end -- Create a simple status board io.write("Task 1: Waiting...\n") io.write("Task 2: Waiting...\n") io.write("Task 3: Waiting...\n") io.flush() tty.cursor_hide() -- Update Task 1 to Running tty.cursor_move_up(3) tty.cr() tty.erase_line() io.write("Task 1: Running... \n") io.flush() os.sleep(500) -- Update Task 1 to Done tty.cursor_move_up(1) tty.cr() tty.erase_line() io.write("Task 1: Done ✓\n") io.flush() -- Update Task 2 to Running tty.cr() tty.erase_line() io.write("Task 2: Running... \n") io.flush() os.sleep(500) -- Update Task 2 to Done tty.cursor_move_up(1) tty.cr() tty.erase_line() io.write("Task 2: Done ✓\n") io.flush() -- Update Task 3 to Running tty.cr() tty.erase_line() io.write("Task 3: Running... \n") io.flush() os.sleep(500) -- Update Task 3 to Done tty.cursor_move_up(1) tty.cr() tty.erase_line() io.write("Task 3: Done ✓\n") io.flush() tty.cursor_show() end function main() print(string.rep("=", 60)) print("TTY Cursor Control - Quick Examples") print(string.rep("=", 60)) example1_simple_progress() example2_update_previous_line() example3_multi_line_update() print("\n" .. string.rep("=", 60)) print("All examples completed!") print("Check test.lua, cursor_control.lua, and live_dashboard.lua") print("for more advanced examples.") print(string.rep("=", 60)) end ================================================ FILE: tests/modules/tty/test.lua ================================================ import("core.base.tty") function test_cursor_move() if not tty.has_vtansi() then print("Terminal does not support ANSI control codes, skipping test") return end print("\n=== Test: cursor_move ===") io.write("Line 1\n") io.write("Line 2\n") io.write("Line 3\n") io.write("Line 4\n") io.write("Line 5\n") io.flush() os.sleep(1000) -- Move to line 3 and update content tty.cursor_move_up(3) tty.cr() tty.erase_line() io.write("Line 3 - UPDATED!\n") io.flush() -- Move cursor back to end tty.cursor_move_down(2) print("\n✓ cursor_move_up test passed") end function test_cursor_move_directions() if not tty.has_vtansi() then return end print("\n=== Test: cursor movement directions ===") -- Create a small coordinate system for i = 1, 5 do io.write(string.rep(" ", 60) .. "\n") end io.flush() -- Move to starting position tty.cursor_move_up(5) tty.cursor_move_right(10) io.write("START") io.flush() os.sleep(500) -- Move right tty.cursor_move_right(10) io.write("RIGHT") io.flush() os.sleep(500) -- Move down tty.cursor_move_down(2) io.write("DOWN") io.flush() os.sleep(500) -- Move left tty.cursor_move_left(5) io.write("LEFT") io.flush() os.sleep(500) -- Move up tty.cursor_move_up(1) io.write("UP") io.flush() -- Move to end tty.cursor_move_down(3) io.write("\n") io.flush() print("✓ cursor movement directions test passed") end function test_cursor_hide_show() if not tty.has_vtansi() then return end print("\n=== Test: cursor hide/show ===") print("Cursor is visible now...") os.sleep(1000) tty.cursor_hide() print("Cursor is hidden now (you shouldn't see it blinking)...") os.sleep(2000) tty.cursor_show() print("Cursor is visible again!") print("✓ cursor hide/show test passed") end function test_erase_operations() if not tty.has_vtansi() then return end print("\n=== Test: erase operations ===") -- Test erase_line_to_end io.write("This is a long line that will be partially erased") io.flush() os.sleep(1000) tty.cursor_move_left(30) tty.erase_line_to_end() io.write("<- erased to end\n") io.flush() os.sleep(1000) -- Test full line erase io.write("This entire line will be erased") io.flush() os.sleep(1000) tty.cr() tty.erase_line() io.write("Replaced!\n") io.flush() print("✓ erase operations test passed") end function test_partial_screen_update() if not tty.has_vtansi() then return end print("\n=== Test: partial screen update ===") -- Create a table io.write("┌────────────────────────────────┐\n") io.write("│ Task │ Status │\n") io.write("├────────────────────────────────┤\n") io.write("│ Compile │ Pending... │\n") io.write("│ Link │ Pending... │\n") io.write("│ Package │ Pending... │\n") io.write("└────────────────────────────────┘\n") io.flush() os.sleep(1000) tty.cursor_hide() -- Update first task status tty.cursor_move_up(4) tty.cursor_move_to_col(32) tty.erase_line_to_end() io.write("│ Running... │\n") io.flush() os.sleep(800) tty.cursor_move_up(1) tty.cursor_move_to_col(32) tty.erase_line_to_end() io.write("│ Done! ✓ │\n") io.flush() os.sleep(500) -- Update second task status tty.cursor_move_to_col(32) tty.erase_line_to_end() io.write("│ Running... │\n") io.flush() os.sleep(800) tty.cursor_move_up(1) tty.cursor_move_to_col(32) tty.erase_line_to_end() io.write("│ Done! ✓ │\n") io.flush() os.sleep(500) -- Update third task status tty.cursor_move_to_col(32) tty.erase_line_to_end() io.write("│ Running... │\n") io.flush() os.sleep(800) tty.cursor_move_up(1) tty.cursor_move_to_col(32) tty.erase_line_to_end() io.write("│ Done! ✓ │\n") io.flush() tty.cursor_show() tty.cursor_move_down(1) print("\n✓ partial screen update test passed") end function main(...) -- Run all tests test_cursor_move() test_cursor_move_directions() test_cursor_hide_show() test_erase_operations() test_partial_screen_update() print("\n" .. string.rep("=", 50)) print("All TTY cursor control tests completed!") print(string.rep("=", 50)) end ================================================ FILE: tests/modules/utf8/test.lua ================================================ function test_len(t) t:are_equal(utf8.len("A"), 1) t:are_equal(utf8.len("¢"), 1) t:are_equal(utf8.len("€"), 1) t:are_equal(utf8.len("𐍈"), 1) t:are_equal(utf8.len("ab"), 2) t:are_equal(utf8.len("A€B"), 3) t:are_equal(utf8.len("你好"), 2) end function test_char(t) t:are_equal(utf8.char(65), "A") t:are_equal(utf8.char(0x20AC), "€") t:are_equal(utf8.char(65, 66, 67), "ABC") end function test_codepoint(t) t:are_equal(utf8.codepoint("A"), 65) t:are_equal(utf8.codepoint("€"), 0x20AC) local c1, c2, c3 = utf8.codepoint("ABC", 1, 3) t:are_equal(c1, 65) t:are_equal(c2, 66) t:are_equal(c3, 67) -- test range t:are_equal(utf8.codepoint("ABC", 2), 66) t:are_equal(utf8.codepoint("ABC", 2, 2), 66) end function test_offset(t) t:are_equal(utf8.offset("ABC", 1), 1) t:are_equal(utf8.offset("ABC", 2), 2) t:are_equal(utf8.offset("ABC", 4), 4) t:are_equal(utf8.offset("ABC", 5), nil) -- "€" is 3 bytes (0xE2 0x82 0xAC) t:are_equal(utf8.offset("€BC", 1), 1) t:are_equal(utf8.offset("€BC", 2), 4) t:are_equal(utf8.offset("€BC", 3), 5) t:are_equal(utf8.offset("你好", 1), 1) t:are_equal(utf8.offset("你好", 2), 4) t:are_equal(utf8.offset("你好", 3), 7) end function test_codes(t) local s = "A€" local codes = {} for p, c in utf8.codes(s) do table.insert(codes, {p, c}) end t:are_equal(#codes, 2) t:are_equal(codes[1][1], 1) t:are_equal(codes[1][2], 65) -- "€" starts at 2? No, byte offset. -- "A" is 1 byte. "€" starts at 2. t:are_equal(codes[2][1], 2) t:are_equal(codes[2][2], 0x20AC) end function test_charpattern(t) t:require(utf8.charpattern) end function test_sub(t) t:are_equal(utf8.sub("ABC", 1, 1), "A") t:are_equal(utf8.sub("ABC", 2, 2), "B") t:are_equal(utf8.sub("ABC", 1, 2), "AB") t:are_equal(utf8.sub("你好", 1, 1), "你") t:are_equal(utf8.sub("你好", 2, 2), "好") t:are_equal(utf8.sub("你好", 1, 2), "你好") -- mixed t:are_equal(utf8.sub("A你好B", 2, 3), "你好") t:are_equal(utf8.sub("A你好B", 1, 3), "A你好") t:are_equal(utf8.sub("A你好B", 2, 4), "你好B") -- negative t:are_equal(utf8.sub("ABC", -1), "C") t:are_equal(utf8.sub("ABC", -2), "BC") t:are_equal(utf8.sub("你好", -1), "好") t:are_equal(utf8.sub("你好", -2), "你好") t:are_equal(utf8.sub("你好", 1, -1), "你好") t:are_equal(utf8.sub("你好", 1, -2), "你") -- out of bounds t:are_equal(utf8.sub("ABC", 4), "") t:are_equal(utf8.sub("ABC", 1, 5), "ABC") t:are_equal(utf8.sub("ABC", 0), "ABC") t:are_equal(utf8.sub("ABC", -10), "ABC") end function test_lastof(t) t:are_equal(utf8.lastof("ABC", "A"), 1) t:are_equal(utf8.lastof("ABC", "B"), 2) t:are_equal(utf8.lastof("ABC", "C"), 3) t:are_equal(utf8.lastof("ABCA", "A"), 4) t:are_equal(utf8.lastof("你好", "你"), 1) t:are_equal(utf8.lastof("你好", "好"), 2) t:are_equal(utf8.lastof("你好你", "你"), 3) t:are_equal(utf8.lastof("A你好A", "A"), 4) t:are_equal(utf8.lastof("A你好A", "好"), 3) t:are_equal(utf8.lastof("ABC", "D"), nil) -- plain t:are_equal(utf8.lastof("ABC", "A", true), 1) t:are_equal(utf8.lastof("ABC", "B", true), 2) t:are_equal(utf8.lastof("ABC", ".", true), nil) t:are_equal(utf8.lastof("你好", "好", true), 2) t:are_equal(utf8.lastof("C你好D", "好", true), 3) t:are_equal(utf8.lastof("C你好D", "D", true), 4) -- long string local longstr = ("你"):rep(1000) .. "好" t:are_equal(utf8.lastof(longstr, "好"), 1001) t:are_equal(utf8.lastof(longstr, "你"), 1000) t:are_equal(utf8.lastof(longstr, "好", true), 1001) t:are_equal(utf8.lastof(longstr, "你", true), 1000) -- pattern t:are_equal(utf8.lastof("ABC", "."), 3) t:are_equal(utf8.lastof("你好", "."), 2) end function test_find(t) -- plain t:are_equal({utf8.find("你好", "你", 1, true)}, {1, 1}) t:are_equal({utf8.find("你好你", "你", 2, true)}, {3, 3}) t:are_equal({utf8.find("A你好A", "A", 2, true)}, {4, 4}) t:are_equal(utf8.find("ABC", "D", 1, true), nil) t:are_equal({utf8.find("ABC", "", 1, true)}, {1, 0}) -- pattern matching (default) t:are_equal({utf8.find("ABC", "B")}, {2, 2}) t:are_equal({utf8.find("ABC", "([BC])")}, {2, 2, "B"}) -- Capture t:are_equal({utf8.find("ABC", "(.)(.)")}, {1, 2, "A", "B"}) -- UTF-8 pattern matching (byte-based) -- "你" is 3 bytes. "." matches first byte. t:are_equal({utf8.find("你好", ".")}, {1, 1}) -- "你好", "好" -> bytes 4-6. t:are_equal({utf8.find("你好", "好")}, {2, 2}) -- "你好", "..." (3 dots) -> matches 3 bytes (whole "你"). t:are_equal({utf8.find("你好", "...")}, {1, 1}) -- "A你好", "%w" -> matches "A". t:are_equal({utf8.find("A你好", "%w")}, {1, 1}) end function test_width(t) -- char/codepoint width t:are_equal(utf8.width(string.byte("A")), 1) t:are_equal(utf8.width(utf8.codepoint("€")), 1) t:are_equal(utf8.width(utf8.codepoint("你")), 2) t:are_equal(utf8.width(0), 0) t:are_equal(utf8.width(0x09), 4) -- TAB -- string width t:are_equal(utf8.width("A"), 1) t:are_equal(utf8.width("ABC"), 3) t:are_equal(utf8.width("你好"), 4) t:are_equal(utf8.width("A你好"), 5) t:are_equal(utf8.width("A\tB"), 6) -- 1 + 4 + 1 end function test_byte(t) t:are_equal({utf8.byte("A")}, {65}) t:are_equal({utf8.byte("€")}, {0x20AC}) t:are_equal({utf8.byte("ABC")}, {65}) t:are_equal({utf8.byte("ABC", 2)}, {66}) t:are_equal({utf8.byte("ABC", 2, 2)}, {66}) t:are_equal({utf8.byte("ABC", 1, 3)}, {65, 66, 67}) t:are_equal({utf8.byte("你好")}, {utf8.codepoint("你好", 1, 1)}) t:are_equal({utf8.byte("你好", 1, 2)}, {20320, 22909}) -- negative indices t:are_equal({utf8.byte("ABC", -1)}, {67}) t:are_equal({utf8.byte("ABC", -2)}, {66}) t:are_equal({utf8.byte("ABC", -2, -1)}, {66, 67}) t:are_equal({utf8.byte("ABC", 1, -1)}, {65, 66, 67}) -- out of bounds t:are_equal({utf8.byte("ABC", 4)}, {}) t:are_equal({utf8.byte("ABC", 1, 0)}, {}) end function test_reverse(t) t:are_equal(utf8.reverse("hello"), "olleh") t:are_equal(utf8.reverse("你好"), "好你") t:are_equal(utf8.reverse("hello 你好"), "好你 olleh") end ================================================ FILE: tests/modules/xml/test.lua ================================================ import("core.base.xml") function test_decode_basic(t) local doc = xml.decode([[foo]]) t:are_equal(doc.kind, "element") t:are_equal(doc.name, "root") t:are_equal(doc.attrs.id, "1") t:are_equal(#doc.children, 2) t:are_equal(doc.children[1].name, "item") t:are_equal(xml.text_of(doc.children[1]), "foo") t:are_equal(doc.children[1].attrs, nil) t:are_equal(doc.children[2].attrs.id, "2") end function test_decode_unquoted_attrs(t) local doc = xml.decode("") t:are_equal(doc.attrs.flag, "true") t:are_equal(doc.attrs.count, "42") t:are_equal(doc.attrs.path, "/tmp/file") t:are_equal(doc.children[1].attrs.data, "abc") end function test_decode_mixed_attrs(t) local xmltext = [[]] local doc = xml.decode(xmltext) t:are_equal(doc.attrs.a, "1 2") t:are_equal(doc.attrs.b, "foo & bar") t:are_equal(doc.attrs.c, "bare") t:are_equal(doc.attrs["data-id"], "abc123") t:are_equal(doc.attrs["ns:flag"], "true") t:are_equal(doc.attrs["dashed-name"], "hello-world") end function test_encode_basic(t) local doc = xml.new({ name = "root", attrs = {id = "1"}, children = { xml.new({name = "item", children = {xml.text("foo")}}), xml.new({name = "item", attrs = {id = "2"}}) } }) local compact = xml.encode(doc) t:are_equal(compact, 'foo') local pretty = xml.encode(doc, {pretty = true, indent = 2}) local expected = table.concat({ '', ' foo', ' ', '' }, "\n") t:are_equal(pretty, expected) end function test_encode_special_nodes(t) t:are_equal(xml.encode(xml.comment("note")), "") t:are_equal(xml.encode(xml.cdata("a < b")), "") t:are_equal(xml.encode(xml.doctype("note SYSTEM \"note.dtd\"")), "") t:are_equal(xml.encode(xml.empty("br")), "
") end function test_decode_special_nodes(t) local doc = xml.decode([=[]=]) t:are_equal(doc.children[1].kind, "comment") t:are_equal(doc.children[1].text, "note") t:are_equal(doc.children[2].kind, "cdata") t:are_equal(doc.children[2].text, "a < b") t:are_equal(doc.children[3].name, "child") local nodes = xml.decode([=[]=]) t:are_equal(nodes.kind, "element") t:are_equal(nodes.name, "root") t:are_equal(nodes.prolog[1].kind, "doctype") end function test_load_save(t) local tmpdir = os.tmpdir() local filepath = path.join(tmpdir, "xml_test.xml") local doc = xml.new({ name = "root", attrs = {id = "1"}, children = {xml.text("hello")} }) assert(xml.savefile(filepath, doc, {pretty = true})) local reloaded = xml.loadfile(filepath) t:are_equal(reloaded.name, "root") t:are_equal(xml.text_of(reloaded), "hello") os.tryrm(filepath) end function test_plist_sample(t) local plist = [[ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. NSSupportsAutomaticTermination ]] local doc = xml.decode(plist) t:are_equal(doc.name, "plist") t:are_equal(doc.attrs.version, "1.0") t:are_equal(doc.prolog[1].kind, "doctype") local dict = xml.find(doc, "plist/dict") t:are_equal(dict.kind, "element") local first_key = dict.children[1] t:are_equal(first_key.name, "key") t:are_equal(xml.text_of(first_key), "CFBundleDevelopmentRegion") local first_value = dict.children[2] t:are_equal(first_value.name, "string") t:are_equal(xml.text_of(first_value), "$(DEVELOPMENT_LANGUAGE)") local last_flag = dict.children[#dict.children] t:are_equal(last_flag.name, "true") end function test_scan_stop(t) local plist = [[ CFBundleExecutable $(EXECUTABLE_NAME) NSPrincipalClass NSApplication ]] local found xml.scan(plist, function(node) if node.name == "key" and xml.text_of(node) == "NSPrincipalClass" then found = node return false end end) t:are_equal(found ~= nil, true) t:are_equal(xml.text_of(found), "NSPrincipalClass") end function test_find_xpath(t) local doc = xml.decode([[ foo bar ]]) local second = xml.find(doc, "root/items/item[2]") t:are_equal(second.attrs.id, "b") local descendant = xml.find(doc, "//item[@id='c']") t:are_equal(descendant.attrs.id, "c") local value = xml.find(doc, "//value[text()='bar']") t:are_equal(xml.text_of(value), "bar") end function test_find_update(t) local doc = xml.decode("foo") local target = xml.find(doc, "//item[@id='a']") t:are_not_equal(target, nil) target.attrs.lang = "en" target.children = {xml.text("bar")} local new_item = xml.new({name = "item", attrs = {id = "c"}, children = {xml.text("baz")}}) table.insert(doc.children, new_item) local encoded = xml.encode(doc) t:are_equal(encoded, 'barbaz') end function test_decode_trim_text(t) local doc = xml.decode(" foo ") t:are_equal(xml.text_of(doc), " foo ") local trimmed = xml.decode(" foo ", {trim_text = true}) t:are_equal(xml.text_of(trimmed), "foo") local formatted = "\n \n" local default = xml.decode(formatted) t:are_equal(#default.children, 1) local keep_ws = xml.decode(formatted, {keep_whitespace_nodes = true}) t:are_equal(#keep_ws.children, 3) t:are_equal(keep_ws.children[1].kind, "text") end ================================================ FILE: tests/plugins/create/test.lua ================================================ function main () os.tryrm("$(tmpdir)/test_create") os.exec("xmake create -P $(tmpdir)/test_create/test") os.exec("xmake -vD -P $(tmpdir)/test_create/test") os.exec("xmake create -l c++ -P $(tmpdir)/test_create/test_cpp") os.exec("xmake -vD -P $(tmpdir)/test_create/test_cpp") os.exec("xmake create -l c++ -t static -P $(tmpdir)/test_create/test_cpp2") os.exec("xmake -vD -P $(tmpdir)/test_create/test_cpp2") os.exec("xmake create -l c++ -t shared -P $(tmpdir)/test_create/test_cpp3") os.exec("xmake -vD -P $(tmpdir)/test_create/test_cpp3") end ================================================ FILE: tests/plugins/macro/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/plugins/macro/src/main.cpp ================================================ #include int main(int argc, char **argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/plugins/macro/test.lua ================================================ function test_macro(t) -- we force to enable ccache to test it on ci os.exec("xmake f --mode=debug --policies=build.ccache:y -D -y") os.exec("xmake m -b") os.exec("xmake -r -a -D") os.exec("xmake m -e buildtest") os.exec("xmake m -l") os.exec("xmake m buildtest") os.exec("xmake m -d buildtest") end ================================================ FILE: tests/plugins/macro/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("macro") set_kind("binary") add_files("src/*.cpp") ================================================ FILE: tests/plugins/pack/console/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/plugins/pack/console/LICENSE.md ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015-present Xmake Open Source Community Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: tests/plugins/pack/console/include/foo/foo.h ================================================ ================================================ FILE: tests/plugins/pack/console/include/test.h ================================================ ================================================ FILE: tests/plugins/pack/console/src/assets/file1.txt ================================================ hello ================================================ FILE: tests/plugins/pack/console/src/assets/file2.txt ================================================ hello ================================================ FILE: tests/plugins/pack/console/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/plugins/pack/console/src/xmake.rc ================================================ IDI_APP ICON DISCARDABLE "assets/xmake.ico" ================================================ FILE: tests/plugins/pack/console/xmake.lua ================================================ set_version("1.0.0") add_rules("mode.debug", "mode.release") includes("@builtin/xpack") add_requires("zlib", {configs = {shared = true}}) target("test") set_kind("binary") add_files("src/*.cpp") if is_plat("windows") then add_files("src/*.rc") end target("foo") set_kind("shared") add_files("src/*.cpp") add_headerfiles("include/(*.h)") add_packages("zlib") xpack("test") set_formats("nsis", "srpm", "rpm", "deb", "zip", "targz", "tarxz", "srczip", "srctargz", "srctarxz", "runself", "wix", "dmg", "appimage") set_title("hello") set_author("ruki ") set_description("A test installer.") set_homepage("https://xmake.io") set_license("Apache-2.0") set_licensefile("LICENSE.md") add_targets("test", "foo") add_installfiles("src/(assets/*.png)", {prefixdir = "images"}) add_sourcefiles("(src/**)") add_sourcefiles("xmake.lua") add_components("LongPath") on_load(function (package) if package:with_source() then package:set("basename", "test-$(plat)-src-v$(version)") else package:set("basename", "test-$(plat)-$(arch)-v$(version)") end -- set icon file based on format (use PNG for appimage, ICO for other formats) local scriptdir = os.scriptdir() if package:format() == "appimage" then package:set("iconfile", path.join(scriptdir, "src/assets/xmake.png")) else package:set("iconfile", path.join(scriptdir, "src/assets/xmake.ico")) end end) after_installcmd(function (package, batchcmds) if package:format() == "runself" then batchcmds:runv("echo", {"hello"}) else batchcmds:mkdir(package:installdir("resources")) batchcmds:cp("src/assets/*.txt", package:installdir("resources"), {rootdir = "src"}) batchcmds:mkdir(package:installdir("stub")) end end) after_uninstallcmd(function (package, batchcmds) batchcmds:rmdir(package:installdir("resources")) batchcmds:rmdir(package:installdir("stub")) end) xpack_component("LongPath") set_default(false) set_title("Enable Long Path") set_description("Increases the maximum path length limit, up to 32,767 characters (before 256).") on_installcmd(function (component, batchcmds) batchcmds:rawcmd("wix", [[ ]]) batchcmds:rawcmd("nsis", [[ ${If} $NoAdmin == "false" ; Enable long path WriteRegDWORD ${HKLM} "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1 ${EndIf}]]) end) ================================================ FILE: tests/plugins/pack/macapp/src/AppDelegate.h ================================================ // // AppDelegate.h // macapp // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import @interface AppDelegate : NSObject @end ================================================ FILE: tests/plugins/pack/macapp/src/AppDelegate.m ================================================ // // AppDelegate.m // macapp // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application } - (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application } @end ================================================ FILE: tests/plugins/pack/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "filename" : "icon_16x16.png", "idiom" : "mac", "size" : "16x16", "scale" : "1x" }, { "filename" : "icon_16x16@2x.png", "idiom" : "mac", "size" : "16x16", "scale" : "2x" }, { "filename" : "icon_32x32.png", "idiom" : "mac", "size" : "32x32", "scale" : "1x" }, { "filename" : "icon_32x32@2x.png", "idiom" : "mac", "size" : "32x32", "scale" : "2x" }, { "filename" : "icon_128x128.png", "idiom" : "mac", "size" : "128x128", "scale" : "1x" }, { "filename" : "icon_128x128@2x.png", "idiom" : "mac", "size" : "128x128", "scale" : "2x" }, { "filename" : "icon_256x256.png", "idiom" : "mac", "size" : "256x256", "scale" : "1x" }, { "filename" : "icon_256x256@2x.png", "idiom" : "mac", "size" : "256x256", "scale" : "2x" }, { "filename" : "icon_512x512.png", "idiom" : "mac", "size" : "512x512", "scale" : "1x" }, { "filename" : "icon_512x512@2x.png", "idiom" : "mac", "size" : "512x512", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/plugins/pack/macapp/src/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/plugins/pack/macapp/src/Base.lproj/Main.storyboard ================================================ ================================================ FILE: tests/plugins/pack/macapp/src/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile AppIcon CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundleDisplayName $(PRODUCT_DISPLAY_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass NSApplication NSSupportsAutomaticTermination NSSupportsSuddenTermination ================================================ FILE: tests/plugins/pack/macapp/src/ViewController.h ================================================ // // ViewController.h // macapp // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import @interface ViewController : NSViewController @end ================================================ FILE: tests/plugins/pack/macapp/src/ViewController.m ================================================ // // ViewController.m // macapp // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import "ViewController.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)setRepresentedObject:(id)representedObject { [super setRepresentedObject:representedObject]; // Update the view, if already loaded. } @end ================================================ FILE: tests/plugins/pack/macapp/src/main.m ================================================ // // main.m // macapp // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import int main(int argc, const char * argv[]) { @autoreleasepool { // Setup code that might create autoreleased objects goes here. } return NSApplicationMain(argc, argv); } ================================================ FILE: tests/plugins/pack/macapp/xmake.lua ================================================ set_version("1.0.0") add_rules("mode.debug", "mode.release") includes("@builtin/xpack") target("macapp") add_rules("xcode.application") add_files("src/*.m", "src/**.storyboard", "src/*.xcassets") add_files("src/Info.plist") xpack("macapp") set_formats("dmg") set_title("MacApp Test") set_author("ruki ") set_description("A test macOS application installer.") set_homepage("https://xmake.io") set_license("Apache-2.0") add_targets("macapp") ================================================ FILE: tests/plugins/pack/qtapp/src/main.cpp ================================================ #include "mainwindow.h" #include #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); qDebug() << "zlib version:" << zlibVersion(); MainWindow w; w.show(); return a.exec(); } ================================================ FILE: tests/plugins/pack/qtapp/src/mainwindow.cpp ================================================ #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); setWindowTitle("Qt Widget App"); } MainWindow::~MainWindow() { delete ui; } ================================================ FILE: tests/plugins/pack/qtapp/src/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H ================================================ FILE: tests/plugins/pack/qtapp/src/mainwindow.ui ================================================ MainWindow 0 0 640 480 Qt Widget App Welcome to Qt Widget App! Qt::AlignCenter 0 0 640 22 ================================================ FILE: tests/plugins/pack/qtapp/xmake.lua ================================================ set_version("1.0.0") add_rules("mode.debug", "mode.release") includes("@builtin/xpack") add_requires("zlib", {configs = {shared = true}, system = false}) target("qtapp") add_rules("qt.widgetapp") add_headerfiles("src/*.h") add_files("src/*.cpp") add_files("src/mainwindow.ui") add_files("src/mainwindow.h") add_packages("zlib") xpack("qtapp") set_formats("nsis", "dmg", "appimage", "zip", "targz") set_title("Qt Widget App") set_author("ruki ") set_description("A Qt Widget Application example for xpack.") set_homepage("https://xmake.io") set_license("Apache-2.0") set_licensefile("LICENSE.md") add_targets("qtapp") on_load(function (package) package:set("basename", "qtapp-$(plat)-$(arch)-v$(version)") -- set icon file based on format (use PNG for appimage, ICO for other formats) local scriptdir = os.scriptdir() if package:format() == "appimage" then package:set("iconfile", path.join(scriptdir, "src/assets/xmake.png")) else package:set("iconfile", path.join(scriptdir, "src/assets/xmake.ico")) end end) ================================================ FILE: tests/plugins/project/test.lua ================================================ import("core.project.config") import("core.platform.platform") import("core.tool.toolchain") import("lib.detect.find_tool") function test_vsxmake(t) if not is_subhost("windows") then return t:skip("wrong host platform") end local projname = "testproj" local tempdir = os.tmpfile() os.mkdir(tempdir) os.cd(tempdir) -- create project os.vrunv("xmake", {"create", projname}) os.cd(projname) -- set config local arch = os.getenv("platform") or "x86" config.set("arch", arch, {readonly = true, force = true}) platform.load(config.plat(), arch):check() -- create sln & vcxproj local vs = config.get("vs") local vstype = "vsxmake" .. vs os.execv("xmake", {"project", "-k", vstype, "-a", arch}) os.cd(vstype) -- run msbuild try { function () local runenvs = toolchain.load("msvc"):runenvs() local msbuild = find_tool("msbuild", {envs = runenvs}) os.execv(msbuild.program, {"/P:XmakeDiagnosis=true", "/P:XmakeVerbose=true"}, {envs = runenvs}) end, catch { function () print("--- sln file ---") io.cat(projname .. ".sln") print("--- vcx file ---") io.cat(projname .. "/" .. projname .. ".vcxproj") print("--- filter file ---") io.cat(projname .. "/" .. projname .. ".vcxproj.filters") raise("msbuild failed") end } } -- clean up os.cd(os.scriptdir()) os.tryrm(tempdir) end function test_compile_commands(t) local projname = "testproj" local tempdir = os.tmpfile() os.mkdir(tempdir) os.cd(tempdir) -- create project os.vrunv("xmake", {"create", projname}) os.cd(projname) -- generate compile_commands os.vrunv("xmake", {"project", "-k", "compile_commands"}) -- test autoupdate io.insert("xmake.lua", 1, 'add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode", lsp = "clangd"})') os.vrun("xmake") -- clean up os.cd(os.scriptdir()) os.tryrm(tempdir) end function test_cmake(t) local cmake = find_tool("cmake") if not cmake then return t:skip("cmake not found") end local projname = "testproj" local tempdir = os.tmpfile() os.mkdir(tempdir) os.cd(tempdir) -- create project os.vrunv("xmake", {"create", projname}) os.cd(projname) -- generate compile_commands os.vrunv("xmake", {"project", "-k", "cmake"}) -- test build os.mkdir("build") os.cd("build") os.vrunv(cmake.program, {".."}) os.vrunv(cmake.program, {"--build", "."}) -- clean up os.cd(os.scriptdir()) os.tryrm(tempdir) end ================================================ FILE: tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml ================================================ ================================================ FILE: tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml ================================================ Lvgl Basic ================================================ FILE: tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml ================================================ ================================================ FILE: tests/projects/android/native_app/lvgl_basic/src/main.c ================================================ #include #include #include #include #include #include #include #define LOG_TAG "lvgl_basic" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) static lv_display_t * display = NULL; static lv_indev_t * indev = NULL; static void * disp_buf = NULL; static ANativeWindow * native_window = NULL; static int32_t window_width = 0; static int32_t window_height = 0; static lv_obj_t * label_fps = NULL; static bool touch_down = false; static int32_t touch_x = 0; static int32_t touch_y = 0; static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) { if (!native_window) { lv_display_flush_ready(disp); return; } ANativeWindow_Buffer buffer; if (ANativeWindow_lock(native_window, &buffer, NULL) < 0) { lv_display_flush_ready(disp); return; } int32_t width = lv_area_get_width(area); int32_t height = lv_area_get_height(area); // Assume 32-bit RGBA uint32_t * dst_base = (uint32_t *)buffer.bits; uint32_t * src = (uint32_t *)px_map; int stride = buffer.stride; for (int y = 0; y < height; y++) { uint32_t * dst_line = dst_base + (area->y1 + y) * stride + area->x1; memcpy(dst_line, src + y * width, width * sizeof(uint32_t)); } ANativeWindow_unlockAndPost(native_window); lv_display_flush_ready(disp); } static void my_input_read(lv_indev_t * indev, lv_indev_data_t * data) { data->point.x = touch_x; data->point.y = touch_y; data->state = touch_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; } static void create_ui(void) { lv_obj_t * label = lv_label_create(lv_screen_active()); lv_label_set_text(label, "Hello Xmake + LVGL!"); lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0); lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 50); // FPS label label_fps = lv_label_create(lv_screen_active()); lv_label_set_text(label_fps, "FPS: 0"); lv_obj_set_style_text_font(label_fps, &lv_font_montserrat_14, 0); lv_obj_align(label_fps, LV_ALIGN_TOP_MID, 0, 100); } static void handle_cmd(struct android_app* app, int32_t cmd) { switch (cmd) { case APP_CMD_INIT_WINDOW: LOGI("Init Window"); native_window = app->window; window_width = ANativeWindow_getWidth(native_window); window_height = ANativeWindow_getHeight(native_window); ANativeWindow_setBuffersGeometry(native_window, window_width, window_height, WINDOW_FORMAT_RGBA_8888); if (!display) { display = lv_display_create(window_width, window_height); lv_display_set_color_format(display, LV_COLOR_FORMAT_ARGB8888); lv_display_set_flush_cb(display, my_flush_cb); size_t buf_size = window_width * window_height * 4; disp_buf = malloc(buf_size); lv_display_set_buffers(display, disp_buf, NULL, buf_size, LV_DISPLAY_RENDER_MODE_FULL); indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); lv_indev_set_read_cb(indev, my_input_read); create_ui(); } else { lv_display_set_resolution(display, window_width, window_height); lv_obj_invalidate(lv_scr_act()); } break; case APP_CMD_TERM_WINDOW: native_window = NULL; break; case APP_CMD_DESTROY: if (display) { lv_display_delete(display); display = NULL; } if (indev) { lv_indev_delete(indev); indev = NULL; } if (disp_buf) { free(disp_buf); disp_buf = NULL; } break; } } static int32_t handle_input(struct android_app* app, AInputEvent* event) { if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { int action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; touch_x = AMotionEvent_getX(event, 0); touch_y = AMotionEvent_getY(event, 0); if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) { touch_down = true; } else { touch_down = false; } return 1; } return 0; } void android_main(struct android_app* app) { lv_init(); app->onAppCmd = handle_cmd; app->onInputEvent = handle_input; int frame_count = 0; time_t last_time = time(NULL); while (1) { int ident; int events; struct android_poll_source* source; uint32_t timeout = lv_timer_handler(); if (timeout > 50) timeout = 50; while ((ident = ALooper_pollAll(timeout, NULL, &events, (void**)&source)) >= 0) { if (source != NULL) source->process(app, source); if (app->destroyRequested != 0) return; } lv_tick_inc(timeout); frame_count++; time_t current_time = time(NULL); if (current_time - last_time >= 1) { if (label_fps) { lv_label_set_text_fmt(label_fps, "FPS: %d", frame_count); } frame_count = 0; last_time = current_time; } } } ================================================ FILE: tests/projects/android/native_app/lvgl_basic/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("lvgl 9.1.0") target("lvgl_basic") set_kind("binary") set_languages("c99") add_files("src/main.c") add_syslinks("log", "android", "EGL", "GLESv2") add_packages("lvgl") -- define LV_CONF_INCLUDE_SIMPLE to include lv_conf.h add_defines("LV_CONF_INCLUDE_SIMPLE") add_rules("android.native_app", { android_sdk_version = "35", android_manifest = "android/AndroidManifest.xml", android_res = "android/res", keystore = "android/debug.jks", keystore_pass = "123456", package_name = "com.lvgl.basic", logcat_filters = {"lvgl_basic", "lvgl"} }) ================================================ FILE: tests/projects/android/native_app/lvgl_particles/android/AndroidManifest.xml ================================================ ================================================ FILE: tests/projects/android/native_app/lvgl_particles/android/res/values/strings.xml ================================================ Lvgl Particles ================================================ FILE: tests/projects/android/native_app/lvgl_particles/android/res/values/styles.xml ================================================ ================================================ FILE: tests/projects/android/native_app/lvgl_particles/src/main.c ================================================ #include #include #include #include #include #include #include #define LOG_TAG "lvgl_particles" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) static lv_display_t * display = NULL; static lv_indev_t * indev = NULL; static void * disp_buf = NULL; static ANativeWindow * native_window = NULL; static int32_t window_width = 0; static int32_t window_height = 0; static lv_obj_t * label_fps = NULL; static bool touch_down = false; static int32_t touch_x = 0; static int32_t touch_y = 0; static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) { if (!native_window) { lv_display_flush_ready(disp); return; } ANativeWindow_Buffer buffer; if (ANativeWindow_lock(native_window, &buffer, NULL) < 0) { lv_display_flush_ready(disp); return; } int32_t width = lv_area_get_width(area); int32_t height = lv_area_get_height(area); // Assume 32-bit RGBA uint32_t * dst_base = (uint32_t *)buffer.bits; uint32_t * src = (uint32_t *)px_map; int stride = buffer.stride; for (int y = 0; y < height; y++) { uint32_t * dst_line = dst_base + (area->y1 + y) * stride + area->x1; memcpy(dst_line, src + y * width, width * sizeof(uint32_t)); } ANativeWindow_unlockAndPost(native_window); lv_display_flush_ready(disp); } static void my_input_read(lv_indev_t * indev, lv_indev_data_t * data) { data->point.x = touch_x; data->point.y = touch_y; data->state = touch_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; } #include typedef struct { int32_t x; int32_t y; int32_t vx; int32_t vy; lv_color_t color; int32_t size; int32_t life; } Particle; #define MAX_PARTICLES 100 static Particle particles[MAX_PARTICLES]; static int particle_count = 0; static void create_particle(int32_t x, int32_t y) { if (particle_count < MAX_PARTICLES) { Particle *p = &particles[particle_count++]; p->x = x; p->y = y; p->vx = (rand() % 10) - 5; p->vy = (rand() % 10) - 5; p->color = lv_color_make(rand() % 255, rand() % 255, rand() % 255); p->size = (rand() % 15) + 5; p->life = 100; } } static void update_particles(void) { for (int i = 0; i < particle_count; i++) { Particle *p = &particles[i]; p->x += p->vx; p->y += p->vy; p->life--; if (p->life <= 0 || p->x < 0 || p->x > window_width || p->y < 0 || p->y > window_height) { *p = particles[--particle_count]; i--; } } } static void draw_particles(lv_layer_t * layer) { lv_draw_rect_dsc_t draw_dsc; lv_draw_rect_dsc_init(&draw_dsc); draw_dsc.radius = LV_RADIUS_CIRCLE; for (int i = 0; i < particle_count; i++) { Particle *p = &particles[i]; draw_dsc.bg_color = p->color; draw_dsc.bg_opa = (p->life * 255) / 100; lv_area_t area; area.x1 = p->x - p->size / 2; area.y1 = p->y - p->size / 2; area.x2 = area.x1 + p->size; area.y2 = area.y1 + p->size; lv_draw_rect(layer, &draw_dsc, &area); } } static void particle_timer_cb(lv_timer_t * timer) { if (touch_down) { for (int i = 0; i < 5; i++) { create_particle(touch_x, touch_y); } } else { // Auto emit static float t = 0; t += 0.1f; int cx = window_width / 2 + cos(t) * (window_width / 4); int cy = window_height / 2 + sin(t) * (window_height / 4); create_particle(cx, cy); } update_particles(); lv_obj_invalidate(lv_scr_act()); // Force redraw } static void canvas_draw_event_cb(lv_event_t * e) { lv_layer_t * layer = lv_event_get_layer(e); draw_particles(layer); } static void create_ui(void) { lv_obj_t * label = lv_label_create(lv_screen_active()); lv_label_set_text(label, "Touch to create particles!"); lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0); lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 50); // FPS label label_fps = lv_label_create(lv_screen_active()); lv_label_set_text(label_fps, "FPS: 0"); lv_obj_set_style_text_font(label_fps, &lv_font_montserrat_14, 0); lv_obj_align(label_fps, LV_ALIGN_TOP_MID, 0, 100); // Add draw event to screen for particles lv_obj_add_event_cb(lv_screen_active(), canvas_draw_event_cb, LV_EVENT_DRAW_POST, NULL); lv_timer_create(particle_timer_cb, 16, NULL); } static void handle_cmd(struct android_app* app, int32_t cmd) { switch (cmd) { case APP_CMD_INIT_WINDOW: LOGI("Init Window"); native_window = app->window; window_width = ANativeWindow_getWidth(native_window); window_height = ANativeWindow_getHeight(native_window); ANativeWindow_setBuffersGeometry(native_window, window_width, window_height, WINDOW_FORMAT_RGBA_8888); if (!display) { display = lv_display_create(window_width, window_height); lv_display_set_color_format(display, LV_COLOR_FORMAT_ARGB8888); lv_display_set_flush_cb(display, my_flush_cb); size_t buf_size = window_width * window_height * 4; disp_buf = malloc(buf_size); lv_display_set_buffers(display, disp_buf, NULL, buf_size, LV_DISPLAY_RENDER_MODE_FULL); indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); lv_indev_set_read_cb(indev, my_input_read); create_ui(); } else { lv_display_set_resolution(display, window_width, window_height); lv_obj_invalidate(lv_scr_act()); } break; case APP_CMD_TERM_WINDOW: native_window = NULL; break; case APP_CMD_DESTROY: if (display) { lv_display_delete(display); display = NULL; } if (indev) { lv_indev_delete(indev); indev = NULL; } if (disp_buf) { free(disp_buf); disp_buf = NULL; } break; } } static int32_t handle_input(struct android_app* app, AInputEvent* event) { if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { int action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; touch_x = AMotionEvent_getX(event, 0); touch_y = AMotionEvent_getY(event, 0); if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) { touch_down = true; } else { touch_down = false; } return 1; } return 0; } void android_main(struct android_app* app) { srand(time(NULL)); lv_init(); app->onAppCmd = handle_cmd; app->onInputEvent = handle_input; int frame_count = 0; time_t last_time = time(NULL); while (1) { int ident; int events; struct android_poll_source* source; uint32_t timeout = lv_timer_handler(); if (timeout > 50) timeout = 50; while ((ident = ALooper_pollAll(timeout, NULL, &events, (void**)&source)) >= 0) { if (source != NULL) source->process(app, source); if (app->destroyRequested != 0) return; } lv_tick_inc(timeout); frame_count++; time_t current_time = time(NULL); if (current_time - last_time >= 1) { if (label_fps) { lv_label_set_text_fmt(label_fps, "FPS: %d", frame_count); } frame_count = 0; last_time = current_time; } } } ================================================ FILE: tests/projects/android/native_app/lvgl_particles/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("lvgl 9.1.0") target("lvgl_particles") set_kind("binary") set_languages("c99") add_files("src/main.c") add_syslinks("log", "android", "EGL", "GLESv2") add_packages("lvgl") -- define LV_CONF_INCLUDE_SIMPLE to include lv_conf.h add_defines("LV_CONF_INCLUDE_SIMPLE") add_rules("android.native_app", { android_sdk_version = "35", android_manifest = "android/AndroidManifest.xml", android_res = "android/res", keystore = "android/debug.jks", keystore_pass = "123456", package_name = "com.lvgl.particles", logcat_filters = {"lvgl_particles", "lvgl"} }) ================================================ FILE: tests/projects/android/native_app/raylib_basic/android/AndroidManifest.xml ================================================ ================================================ FILE: tests/projects/android/native_app/raylib_basic/android/res/values/strings.xml ================================================ Raylib Basic ================================================ FILE: tests/projects/android/native_app/raylib_basic/android/res/values/styles.xml ================================================ ================================================ FILE: tests/projects/android/native_app/raylib_basic/src/main.cpp ================================================ #include #include #define LOG_TAG "raydemo_basic" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) int main(int argc, char** argv) { InitWindow(0, 0, "Hello, xmake for raylib android!"); SetTargetFPS(60); LOGI("raylib application is running!"); while (!WindowShouldClose()) { BeginDrawing(); ClearBackground(BLACK); // Draw FPS const char* fpsText = TextFormat("%2i FPS", GetFPS()); int fpsWidth = MeasureText(fpsText, 40); DrawText(fpsText, GetScreenWidth() / 2 - fpsWidth / 2, 30, 40, GREEN); // Draw centered text int fontSize = 50; const char* text = "Hello, xmake for raylib android!"; int textWidth = MeasureText(text, fontSize); DrawText(text, GetScreenWidth() / 2 - textWidth / 2, 100, fontSize, BLUE); EndDrawing(); } CloseWindow(); return 0; } ================================================ FILE: tests/projects/android/native_app/raylib_basic/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("raylib 5.5.0") target("raydemo_basic") set_kind("binary") set_languages("c++17") add_files("src/main.cpp") add_syslinks("log") add_packages("raylib") add_rules("android.native_app", { android_sdk_version = "35", android_manifest = "android/AndroidManifest.xml", android_res = "android/res", keystore = "android/debug.jks", keystore_pass = "123456", package_name = "com.raylib.basic", logcat_filters = {"raydemo_basic", "raylib"} }) ================================================ FILE: tests/projects/android/native_app/raylib_custom_glue/android/AndroidManifest.xml ================================================ ================================================ FILE: tests/projects/android/native_app/raylib_custom_glue/android/res/values/strings.xml ================================================ Raylib Basic ================================================ FILE: tests/projects/android/native_app/raylib_custom_glue/android/res/values/styles.xml ================================================ ================================================ FILE: tests/projects/android/native_app/raylib_custom_glue/src/android_native_app_glue.c ================================================ #include #include #include #include #include #include #include #include "android_native_app_glue.h" #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "raydemo_custom_glue", __VA_ARGS__)) #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "raydemo_custom_glue", __VA_ARGS__)) #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "raydemo_custom_glue", __VA_ARGS__)) #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "raydemo_custom_glue", __VA_ARGS__)) static void free_saved_state(struct android_app* android_app) { pthread_mutex_lock(&android_app->mutex); if (android_app->savedState != NULL) { free(android_app->savedState); android_app->savedState = NULL; android_app->savedStateSize = 0; } pthread_mutex_unlock(&android_app->mutex); } int8_t android_app_read_cmd(struct android_app* android_app) { int8_t cmd; if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { switch (cmd) { case APP_CMD_SAVE_STATE: free_saved_state(android_app); break; } return cmd; } else { LOGE("No data on command pipe!"); } return -1; } static void print_cur_config(struct android_app* android_app) { char lang[2], country[2]; AConfiguration_getLanguage(android_app->config, lang); AConfiguration_getCountry(android_app->config, country); LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " "modetype=%d modenight=%d", AConfiguration_getMcc(android_app->config), AConfiguration_getMnc(android_app->config), lang[0], lang[1], country[0], country[1], AConfiguration_getOrientation(android_app->config), AConfiguration_getTouchscreen(android_app->config), AConfiguration_getDensity(android_app->config), AConfiguration_getKeyboard(android_app->config), AConfiguration_getNavigation(android_app->config), AConfiguration_getKeysHidden(android_app->config), AConfiguration_getNavHidden(android_app->config), AConfiguration_getSdkVersion(android_app->config), AConfiguration_getScreenSize(android_app->config), AConfiguration_getScreenLong(android_app->config), AConfiguration_getUiModeType(android_app->config), AConfiguration_getUiModeNight(android_app->config)); } void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { switch (cmd) { case APP_CMD_INPUT_CHANGED: LOGV("APP_CMD_INPUT_CHANGED\n"); pthread_mutex_lock(&android_app->mutex); if (android_app->inputQueue != NULL) { AInputQueue_detachLooper(android_app->inputQueue); } android_app->inputQueue = android_app->pendingInputQueue; if (android_app->inputQueue != NULL) { LOGV("Attaching input queue to looper"); AInputQueue_attachLooper(android_app->inputQueue, android_app->looper, LOOPER_ID_EVENT, NULL, &android_app->inputPollSource); } pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_INIT_WINDOW: LOGV("APP_CMD_INIT_WINDOW\n"); pthread_mutex_lock(&android_app->mutex); android_app->window = android_app->pendingWindow; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_TERM_WINDOW: LOGV("APP_CMD_TERM_WINDOW\n"); pthread_cond_broadcast(&android_app->cond); break; case APP_CMD_RESUME: case APP_CMD_START: case APP_CMD_PAUSE: case APP_CMD_STOP: LOGV("activityState=%d\n", cmd); pthread_mutex_lock(&android_app->mutex); android_app->activityState = cmd; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_CONFIG_CHANGED: LOGV("APP_CMD_CONFIG_CHANGED\n"); AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); print_cur_config(android_app); break; case APP_CMD_DESTROY: LOGV("APP_CMD_DESTROY\n"); android_app->destroyRequested = 1; break; } } void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) { switch (cmd) { case APP_CMD_TERM_WINDOW: LOGV("APP_CMD_TERM_WINDOW\n"); pthread_mutex_lock(&android_app->mutex); android_app->window = NULL; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_SAVE_STATE: LOGV("APP_CMD_SAVE_STATE\n"); pthread_mutex_lock(&android_app->mutex); android_app->stateSaved = 1; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_RESUME: free_saved_state(android_app); break; } } void app_dummy() { } static void android_app_destroy(struct android_app* android_app) { LOGV("android_app_destroy!"); free_saved_state(android_app); pthread_mutex_lock(&android_app->mutex); if (android_app->inputQueue != NULL) { AInputQueue_detachLooper(android_app->inputQueue); } AConfiguration_delete(android_app->config); android_app->destroyed = 1; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); // Can't touch android_app object after this. } static void process_input(struct android_app* app, struct android_poll_source* source) { AInputEvent* event = NULL; while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { LOGV("New input event: type=%d\n", AInputEvent_getType(event)); if (AInputQueue_preDispatchEvent(app->inputQueue, event)) { continue; } int32_t handled = 0; if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event); AInputQueue_finishEvent(app->inputQueue, event, handled); } } static void process_cmd(struct android_app* app, struct android_poll_source* source) { int8_t cmd = android_app_read_cmd(app); android_app_pre_exec_cmd(app, cmd); if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); android_app_post_exec_cmd(app, cmd); } static void* android_app_entry(void* param) { struct android_app* android_app = (struct android_app*)param; android_app->config = AConfiguration_new(); AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); print_cur_config(android_app); android_app->cmdPollSource.id = LOOPER_ID_MAIN; android_app->cmdPollSource.app = android_app; android_app->cmdPollSource.process = process_cmd; android_app->inputPollSource.id = LOOPER_ID_EVENT; android_app->inputPollSource.app = android_app; android_app->inputPollSource.process = process_input; ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, &android_app->cmdPollSource); android_app->looper = looper; pthread_mutex_lock(&android_app->mutex); android_app->running = 1; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); android_main(android_app); android_app_destroy(android_app); return NULL; } // -------------------------------------------------------------------- // Native activity interaction (called from main thread) // -------------------------------------------------------------------- static struct android_app* android_app_create(ANativeActivity* activity, void* savedState, size_t savedStateSize) { struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); memset(android_app, 0, sizeof(struct android_app)); android_app->activity = activity; pthread_mutex_init(&android_app->mutex, NULL); pthread_cond_init(&android_app->cond, NULL); if (savedState != NULL) { android_app->savedState = malloc(savedStateSize); android_app->savedStateSize = savedStateSize; memcpy(android_app->savedState, savedState, savedStateSize); } int msgpipe[2]; if (pipe(msgpipe)) { LOGE("could not create pipe: %s", strerror(errno)); return NULL; } android_app->msgread = msgpipe[0]; android_app->msgwrite = msgpipe[1]; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&android_app->thread, &attr, android_app_entry, android_app); // Wait for thread to start. pthread_mutex_lock(&android_app->mutex); while (!android_app->running) { pthread_cond_wait(&android_app->cond, &android_app->mutex); } pthread_mutex_unlock(&android_app->mutex); return android_app; } static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { LOGE("Failure writing android_app cmd: %s\n", strerror(errno)); } } static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) { pthread_mutex_lock(&android_app->mutex); android_app->pendingInputQueue = inputQueue; android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED); while (android_app->inputQueue != android_app->pendingInputQueue) { pthread_cond_wait(&android_app->cond, &android_app->mutex); } pthread_mutex_unlock(&android_app->mutex); } static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { pthread_mutex_lock(&android_app->mutex); if (android_app->pendingWindow != NULL) { android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); } android_app->pendingWindow = window; if (window != NULL) { android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); } while (android_app->window != android_app->pendingWindow) { pthread_cond_wait(&android_app->cond, &android_app->mutex); } pthread_mutex_unlock(&android_app->mutex); } static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { pthread_mutex_lock(&android_app->mutex); android_app_write_cmd(android_app, cmd); while (android_app->activityState != cmd) { pthread_cond_wait(&android_app->cond, &android_app->mutex); } pthread_mutex_unlock(&android_app->mutex); } static void android_app_free(struct android_app* android_app) { pthread_mutex_lock(&android_app->mutex); android_app_write_cmd(android_app, APP_CMD_DESTROY); while (!android_app->destroyed) { pthread_cond_wait(&android_app->cond, &android_app->mutex); } pthread_mutex_unlock(&android_app->mutex); close(android_app->msgread); close(android_app->msgwrite); pthread_cond_destroy(&android_app->cond); pthread_mutex_destroy(&android_app->mutex); free(android_app); } static void onDestroy(ANativeActivity* activity) { LOGV("Destroy: %p\n", activity); android_app_free((struct android_app*)activity->instance); } static void onStart(ANativeActivity* activity) { LOGV("Start: %p\n", activity); android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START); } static void onResume(ANativeActivity* activity) { LOGV("Resume: %p\n", activity); android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME); } static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { struct android_app* android_app = (struct android_app*)activity->instance; void* savedState = NULL; LOGV("SaveInstanceState: %p\n", activity); pthread_mutex_lock(&android_app->mutex); android_app->stateSaved = 0; android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); while (!android_app->stateSaved) { pthread_cond_wait(&android_app->cond, &android_app->mutex); } if (android_app->savedState != NULL) { savedState = android_app->savedState; *outLen = android_app->savedStateSize; android_app->savedState = NULL; android_app->savedStateSize = 0; } pthread_mutex_unlock(&android_app->mutex); return savedState; } static void onPause(ANativeActivity* activity) { LOGV("Pause: %p\n", activity); android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE); } static void onStop(ANativeActivity* activity) { LOGV("Stop: %p\n", activity); android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP); } static void onConfigurationChanged(ANativeActivity* activity) { struct android_app* android_app = (struct android_app*)activity->instance; LOGV("ConfigurationChanged: %p\n", activity); android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED); } static void onLowMemory(ANativeActivity* activity) { struct android_app* android_app = (struct android_app*)activity->instance; LOGV("LowMemory: %p\n", activity); android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY); } static void onWindowFocusChanged(ANativeActivity* activity, int focused) { LOGV("WindowFocusChanged: %p -- %d\n", activity, focused); android_app_write_cmd((struct android_app*)activity->instance, focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); } static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { LOGV("NativeWindowCreated: %p -- %p\n", activity, window); android_app_set_window((struct android_app*)activity->instance, window); } static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window); android_app_set_window((struct android_app*)activity->instance, NULL); } static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { LOGV("InputQueueCreated: %p -- %p\n", activity, queue); android_app_set_input((struct android_app*)activity->instance, queue); } static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue); android_app_set_input((struct android_app*)activity->instance, NULL); } void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize) { LOGV("Creating: %p\n", activity); activity->callbacks->onDestroy = onDestroy; activity->callbacks->onStart = onStart; activity->callbacks->onResume = onResume; activity->callbacks->onSaveInstanceState = onSaveInstanceState; activity->callbacks->onPause = onPause; activity->callbacks->onStop = onStop; activity->callbacks->onConfigurationChanged = onConfigurationChanged; activity->callbacks->onLowMemory = onLowMemory; activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; activity->callbacks->onInputQueueCreated = onInputQueueCreated; activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; activity->instance = android_app_create(activity, savedState, savedStateSize); } ================================================ FILE: tests/projects/android/native_app/raylib_custom_glue/src/android_native_app_glue.h ================================================ #ifndef _ANDROID_NATIVE_APP_GLUE_H #define _ANDROID_NATIVE_APP_GLUE_H #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * The native activity interface provided by * is based on a set of application-provided callbacks that will be called * by the Activity's main thread when certain events occur. * * This means that each one of this callbacks _should_ _not_ block, or they * risk having the system force-close the application. This programming * model is direct, lightweight, but constraining. * * The 'threaded_native_app' static library is used to provide a different * execution model where the application can implement its own main event * loop in a different thread instead. Here's how it works: * * 1/ The application must provide a function named "android_main()" that * will be called when the activity is created, in a new thread that is * distinct from the activity's main thread. * * 2/ android_main() receives a pointer to a valid "android_app" structure * that contains references to other important objects, e.g. the * ANativeActivity obejct instance the application is running in. * * 3/ the "android_app" object holds an ALooper instance that already * listens to two important things: * * - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX * declarations below. * * - input events coming from the AInputQueue attached to the activity. * * Each of these correspond to an ALooper callback that returns a "data" * value of LOOPER_ID_MAIN and LOOPER_ID_EVENT, respectively. * * Your application can use the same ALooper to listen to additionnal * file-descriptors. * * 4/ Whenever you receive a LOOPER_ID_MAIN event from the ALooper, your * code should call the function android_app_read_cmd() to read the * command value and act upon it. This is normally done by calling * android_app_exec_cmd() directly. * * XXX: MAKE THIS STUFF MORE CLEAR !! * * 5/ Whenever you receive a LOOPER_ID_EVENT event from the ALooper, you * should read one event from the AInputQueue with AInputQueue_getEvent(). * * See the sample named "native-activity" that comes with the NDK with a * full usage example. * */ /** * Data associated with an ALooper fd that will be returned as the "outData" * when that source has data ready. */ struct android_poll_source { // The identifier of this source. May be LOOPER_ID_MAIN or // LOOPER_ID_EVENT. int32_t id; // The android_app structure associated with this source. struct android_app* app; // Function to call to process this source when data is available. void (*process)(struct android_app* app, struct android_poll_source* source); }; struct android_app { // The application can place a pointer to its own state object // here if it likes. void* userData; // Fill this in with the function to process main app commands (APP_CMD_*) void (*onAppCmd)(struct android_app* app, int32_t cmd); // Fill this in with the function to process input events. At this point // the event has already been pre-dispatched, and it will be finished upon // return. Return 1 if you have handled the event, 0 for any default // dispatching. int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event); // The ANativeActivity object instance that this app is running in. ANativeActivity* activity; // The current configuration the app is running in. AConfiguration* config; // The last saved state that was given at creation time. void* savedState; size_t savedStateSize; // The ALooper associated with the app's thread. ALooper* looper; // When non-NULL, this is the input queue from which the app will // receive user input events. AInputQueue* inputQueue; // When non-NULL, this is the window surface that the app can draw in. ANativeWindow* window; // Current content rectangle of the window; this is the area where the // window's content should be placed to be seen by the user. ARect contentRect; // Current state of the app's activity. May be either APP_CMD_START, // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. int activityState; // This is non-zero when the application's NativeActivity is being // destroyed and waiting for the app thread to complete. int destroyRequested; // ------------------------------------------------- // Below are "private" implementation of the glue code. pthread_mutex_t mutex; pthread_cond_t cond; int msgread; int msgwrite; pthread_t thread; struct android_poll_source cmdPollSource; struct android_poll_source inputPollSource; int running; int stateSaved; int destroyed; int redrawNeeded; AInputQueue* pendingInputQueue; ANativeWindow* pendingWindow; ARect pendingContentRect; }; enum { /** * Looper data ID of commands coming from the app's main thread. * These can be retrieved and processed with android_app_read_cmd() * and android_app_exec_cmd(). */ LOOPER_ID_MAIN = 1, /** * Looper data ID of events coming from the AInputQueue of the * application's window. These can be read via the inputQueue * object of android_app. */ LOOPER_ID_EVENT = 2, /** * Looper data ID of events coming from the AInputQueue of the * application's window. These can be read via the inputQueue * object of android_app. */ LOOPER_ID_USER = 3, }; enum { APP_CMD_INPUT_CHANGED, APP_CMD_INIT_WINDOW, APP_CMD_TERM_WINDOW, APP_CMD_WINDOW_RESIZED, APP_CMD_WINDOW_REDRAW_NEEDED, APP_CMD_CONTENT_RECT_CHANGED, APP_CMD_GAINED_FOCUS, APP_CMD_LOST_FOCUS, APP_CMD_CONFIG_CHANGED, APP_CMD_LOW_MEMORY, APP_CMD_START, APP_CMD_RESUME, APP_CMD_SAVE_STATE, APP_CMD_PAUSE, APP_CMD_STOP, APP_CMD_DESTROY, }; /** * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next * app command message. */ int8_t android_app_read_cmd(struct android_app* android_app); /** * Call with the command returned by android_app_read_cmd() to do the * initial pre-processing of the given command. You can use this for * your own normal default behavior for the command, and then inspect * it yourself to do your own processing. This function may block for * certain commands (e.g. to wait for the app's graphics context to be * initialized) and will returns true if it blocked. */ void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd); /** * Call with the command returned by android_app_read_cmd() to do the * final post-processing of the given command. You must have first called * android_app_pre_exec_cmd() before calling this function. */ void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd); /** * Dummy function you can call to ensure glue code isn't stripped. */ void app_dummy(); /** * This is the function that application code must implement, representing * the main entry to the app. */ extern void android_main(struct android_app* app); #ifdef __cplusplus } #endif #endif /* _ANDROID_NATIVE_APP_GLUE_H */ ================================================ FILE: tests/projects/android/native_app/raylib_custom_glue/src/main.cpp ================================================ #include #include #define LOG_TAG "raydemo_custom_glue" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) int main(int argc, char** argv) { InitWindow(0, 0, "Hello, xmake for raylib android!"); SetTargetFPS(60); LOGI("raylib application is running!"); while (!WindowShouldClose()) { BeginDrawing(); ClearBackground(BLACK); // Draw FPS const char* fpsText = TextFormat("%2i FPS", GetFPS()); int fpsWidth = MeasureText(fpsText, 40); DrawText(fpsText, GetScreenWidth() / 2 - fpsWidth / 2, 30, 40, GREEN); // Draw centered text int fontSize = 50; const char* text = "Hello, xmake for raylib android!"; int textWidth = MeasureText(text, fontSize); DrawText(text, GetScreenWidth() / 2 - textWidth / 2, 100, fontSize, BLUE); EndDrawing(); } CloseWindow(); return 0; } ================================================ FILE: tests/projects/android/native_app/raylib_custom_glue/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("raylib 5.5.0") target("raydemo_custom_glue") set_kind("binary") set_languages("c++17") add_files("src/main.cpp", "src/android_native_app_glue.c") add_syslinks("log") add_packages("raylib") add_rules("android.native_app", { android_sdk_version = "35", android_manifest = "android/AndroidManifest.xml", android_res = "android/res", keystore = "android/debug.jks", keystore_pass = "123456", package_name = "com.raylib.custom_glue", native_app_glue = false, logcat_filters = {"raydemo_custom_glue", "raylib"} }) ================================================ FILE: tests/projects/android/native_app/raylib_particles/android/AndroidManifest.xml ================================================ ================================================ FILE: tests/projects/android/native_app/raylib_particles/android/res/values/strings.xml ================================================ Raylib Particles ================================================ FILE: tests/projects/android/native_app/raylib_particles/android/res/values/styles.xml ================================================ ================================================ FILE: tests/projects/android/native_app/raylib_particles/src/main.cpp ================================================ #include #include #include #include #define LOG_TAG "raydemo_particles" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) struct Particle { Vector2 position; Vector2 velocity; Color color; float size; float life; }; int main(int argc, char** argv) { InitWindow(0, 0, "Raylib Particles"); SetTargetFPS(60); LOGD("raylib particles starting!"); std::vector particles; while (!WindowShouldClose()) { // Update bool inputActive = IsMouseButtonDown(MOUSE_BUTTON_LEFT) || GetTouchPointCount() > 0; Vector2 pos; if (inputActive) { pos = GetMousePosition(); if (GetTouchPointCount() > 0) pos = GetTouchPosition(0); } else { // Auto emit when idle double time = GetTime(); pos.x = GetScreenWidth() / 2.0f + cos(time * 3.0f) * (GetScreenWidth() / 4.0f); pos.y = GetScreenHeight() / 2.0f + sin(time * 2.0f) * (GetScreenHeight() / 4.0f); } if (inputActive || GetRandomValue(0, 100) < 50) { int count = inputActive ? 5 : 2; for (int i = 0; i < count; i++) { Particle p; p.position = pos; p.velocity = {(float)GetRandomValue(-200, 200) / 100.0f, (float)GetRandomValue(-200, 200) / 100.0f}; p.color = (Color){(unsigned char)GetRandomValue(0, 255), (unsigned char)GetRandomValue(0, 255), (unsigned char)GetRandomValue(0, 255), 255}; p.size = (float)GetRandomValue(5, 20); p.life = 1.0f; particles.push_back(p); } } for (auto it = particles.begin(); it != particles.end();) { it->position.x += it->velocity.x * 5.0f; it->position.y += it->velocity.y * 5.0f; it->life -= 0.02f; it->size *= 0.99f; if (it->life <= 0) { it = particles.erase(it); } else { ++it; } } // Draw BeginDrawing(); ClearBackground(BLACK); for (const auto& p : particles) { DrawCircleV(p.position, p.size, Fade(p.color, p.life)); } // Draw FPS const char* fpsText = TextFormat("%2i FPS", GetFPS()); int fpsWidth = MeasureText(fpsText, 40); DrawText(fpsText, GetScreenWidth() / 2 - fpsWidth / 2, 30, 40, GREEN); // Draw centered instructions int fontSize = 40; const char* text = "Touch to create particles!"; int textWidth = MeasureText(text, fontSize); DrawText(text, GetScreenWidth() / 2 - textWidth / 2, 80, fontSize, WHITE); EndDrawing(); } CloseWindow(); return 0; } ================================================ FILE: tests/projects/android/native_app/raylib_particles/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("raylib 5.5.0") target("raydemo_particles") set_kind("binary") set_languages("c++17") add_files("src/main.cpp") add_syslinks("log") add_packages("raylib") add_rules("android.native_app", { android_sdk_version = "35", android_manifest = "android/AndroidManifest.xml", android_res = "android/res", keystore = "android/debug.jks", keystore_pass = "123456", package_name = "com.raylib.particles", logcat_filters = {"raydemo_particles", "raylib"} }) ================================================ FILE: tests/projects/asm/fasm/src/main.S ================================================ format MZ entry main:start ; program entry point stack 100h ; stack size segment main ; main program segment start: mov ax,text mov ds,ax mov dx,hello call extra:write_text mov ax,4C00h int 21h segment text hello db 'Hello world!',24h segment extra write_text: mov ah,9 int 21h retf ================================================ FILE: tests/projects/asm/fasm/xmake.lua ================================================ target("test") set_kind("binary") add_files("src/*.S") ================================================ FILE: tests/projects/asm/gas/src/main.S ================================================ .global main .text main: # This is called by C library's startup code mov $message, %rdi # First integer (or pointer) parameter in %rdi call puts # puts(message) ret # Return to C library code message: .asciz "Hola, mundo" # asciz puts a 0 byte at the end ================================================ FILE: tests/projects/asm/gas/xmake.lua ================================================ target("test") set_kind("binary") add_files("src/*.S") ================================================ FILE: tests/projects/asm/masm32/src/generic.asm ================================================ ; ######################################################################### ; ; GENERIC.ASM is a roadmap around a standard 32 bit ; windows application skeleton written in MASM32. ; ; ######################################################################### ; Assembler specific instructions for 32 bit ASM code .386 ; minimum processor needed for 32 bit .model flat, stdcall ; FLAT memory model & STDCALL calling option casemap :none ; set code to case sensitive ; ######################################################################### ; --------------------------------------------- ; main include file with equates and structures ; --------------------------------------------- include windows.inc ; ------------------------------------------------------------- ; In MASM32, each include file created by the L2INC.EXE utility ; has a matching library file. If you need functions from a ; specific library, you use BOTH the include file and library ; file for that library. ; ------------------------------------------------------------- include user32.inc include kernel32.inc ; ######################################################################### ; ------------------------------------------------------------------------ ; MACROS are a method of expanding text at assembly time. This allows the ; programmer a tidy and convenient way of using COMMON blocks of code with ; the capacity to use DIFFERENT parameters in each block. ; ------------------------------------------------------------------------ ; 1. szText ; A macro to insert TEXT into the code section for convenient and ; more intuitive coding of functions that use byte data as text. szText MACRO Name, Text:VARARG LOCAL lbl jmp lbl Name db Text,0 lbl: ENDM ; 2. m2m ; There is no mnemonic to copy from one memory location to another, ; this macro saves repeated coding of this process and is easier to ; read in complex code. m2m MACRO M1, M2 push M2 pop M1 ENDM ; 3. return ; Every procedure MUST have a "ret" to return the instruction ; pointer EIP back to the next instruction after the call that ; branched to it. This macro puts a return value in eax and ; makes the "ret" instruction on one line. It is mainly used ; for clear coding in complex conditionals in large branching ; code such as the WndProc procedure. return MACRO arg mov eax, arg ret ENDM ; ######################################################################### ; ---------------------------------------------------------------------- ; Prototypes are used in conjunction with the MASM "invoke" syntax for ; checking the number and size of parameters passed to a procedure. This ; improves the reliability of code that is written where errors in ; parameters are caught and displayed at assembly time. ; ---------------------------------------------------------------------- WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD TopXY PROTO :DWORD,:DWORD ; ######################################################################### ; ------------------------------------------------------------------------ ; This is the INITIALISED data section meaning that data declared here has ; an initial value. You can also use an UNINIALISED section if you need ; data of that type [ .data? ]. Note that they are different and occur in ; different sections. ; ------------------------------------------------------------------------ .data szDisplayName db "Generic",0 CommandLine dd 0 hWnd dd 0 hInstance dd 0 ; ######################################################################### ; ------------------------------------------------------------------------ ; This is the start of the code section where executable code begins. This ; section ending with the ExitProcess() API function call is the only ; GLOBAL section of code and it provides access to the WinMain function ; with the necessary parameters, the instance handle and the command line ; address. ; ------------------------------------------------------------------------ .code ; ----------------------------------------------------------------------- ; The label "start:" is the address of the start of the code section and ; it has a matching "end start" at the end of the file. All procedures in ; this module must be written between these two. ; ----------------------------------------------------------------------- start: invoke GetModuleHandle, NULL ; provides the instance handle mov hInstance, eax invoke GetCommandLine ; provides the command line address mov CommandLine, eax invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT invoke ExitProcess,eax ; cleanup & return to operating system ; ######################################################################### WinMain proc hInst :DWORD, hPrevInst :DWORD, CmdLine :DWORD, CmdShow :DWORD ;==================== ; Put LOCALs on stack ;==================== LOCAL wc :WNDCLASSEX LOCAL msg :MSG LOCAL Wwd :DWORD LOCAL Wht :DWORD LOCAL Wtx :DWORD LOCAL Wty :DWORD szText szClassName,"Generic_Class" ;================================================== ; Fill WNDCLASSEX structure with required variables ;================================================== mov wc.cbSize, sizeof WNDCLASSEX mov wc.style, CS_HREDRAW or CS_VREDRAW \ or CS_BYTEALIGNWINDOW mov wc.lpfnWndProc, offset WndProc ; address of WndProc mov wc.cbClsExtra, NULL mov wc.cbWndExtra, NULL m2m wc.hInstance, hInst ; instance handle mov wc.hbrBackground, COLOR_BTNFACE+1 ; system color mov wc.lpszMenuName, NULL mov wc.lpszClassName, offset szClassName ; window class name invoke LoadIcon,hInst,500 ; icon ID ; resource icon mov wc.hIcon, eax invoke LoadCursor,NULL,IDC_ARROW ; system cursor mov wc.hCursor, eax mov wc.hIconSm, 0 invoke RegisterClassEx, ADDR wc ; register the window class ;================================ ; Centre window at following size ;================================ mov Wwd, 500 mov Wht, 350 invoke GetSystemMetrics,SM_CXSCREEN ; get screen width in pixels invoke TopXY,Wwd,eax mov Wtx, eax invoke GetSystemMetrics,SM_CYSCREEN ; get screen height in pixels invoke TopXY,Wht,eax mov Wty, eax ; ================================== ; Create the main application window ; ================================== invoke CreateWindowEx,WS_EX_OVERLAPPEDWINDOW, ADDR szClassName, ADDR szDisplayName, WS_OVERLAPPEDWINDOW, Wtx,Wty,Wwd,Wht, NULL,NULL, hInst,NULL mov hWnd,eax ; copy return value into handle DWORD invoke LoadMenu,hInst,600 ; load resource menu invoke SetMenu,hWnd,eax ; set it to main window invoke ShowWindow,hWnd,SW_SHOWNORMAL ; display the window invoke UpdateWindow,hWnd ; update the display ;=================================== ; Loop until PostQuitMessage is sent ;=================================== StartLoop: invoke GetMessage,ADDR msg,NULL,0,0 ; get each message cmp eax, 0 ; exit if GetMessage() je ExitLoop ; returns zero invoke TranslateMessage, ADDR msg ; translate it invoke DispatchMessage, ADDR msg ; send it to message proc jmp StartLoop ExitLoop: return msg.wParam WinMain endp ; ######################################################################### WndProc proc hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD ; ------------------------------------------------------------------------- ; Message are sent by the operating system to an application through the ; WndProc proc. Each message can have additional values associated with it ; in the two parameters, wParam & lParam. The range of additional data that ; can be passed to an application is determined by the message. ; ------------------------------------------------------------------------- .if uMsg == WM_COMMAND ;---------------------------------------------------------------------- ; The WM_COMMAND message is sent by menus, buttons and toolbar buttons. ; Processing the wParam parameter of it is the method of obtaining the ; control's ID number so that the code for each operation can be ; processed. NOTE that the ID number is in the LOWORD of the wParam ; passed with the WM_COMMAND message. There may be some instances where ; an application needs to seperate the high and low words of wParam. ; --------------------------------------------------------------------- ;======== menu commands ======== .if wParam == 1000 invoke SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL .elseif wParam == 1900 szText TheMsg,"Assembler, Pure & Simple" invoke MessageBox,hWin,ADDR TheMsg,ADDR szDisplayName,MB_OK .endif ;====== end menu commands ====== .elseif uMsg == WM_CREATE ; -------------------------------------------------------------------- ; This message is sent to WndProc during the CreateWindowEx function ; call and is processed before it returns. This is used as a position ; to start other items such as controls. IMPORTANT, the handle for the ; CreateWindowEx call in the WinMain does not yet exist so the HANDLE ; passed to the WndProc [ hWin ] must be used here for any controls ; or child windows. ; -------------------------------------------------------------------- .elseif uMsg == WM_CLOSE ; ------------------------------------------------------------------- ; This is the place where various requirements are performed before ; the application exits to the operating system such as deleting ; resources and testing if files have been saved. You have the option ; of returning ZERO if you don't wish the application to close which ; exits the WndProc procedure without passing this message to the ; default window processing done by the operating system. ; ------------------------------------------------------------------- szText TheText,"Please Confirm Exit" invoke MessageBox,hWin,ADDR TheText,ADDR szDisplayName,MB_YESNO .if eax == IDNO return 0 .endif .elseif uMsg == WM_DESTROY ; ---------------------------------------------------------------- ; This message MUST be processed to cleanly exit the application. ; Calling the PostQuitMessage() function makes the GetMessage() ; function in the WinMain() main loop return ZERO which exits the ; application correctly. If this message is not processed properly ; the window disappears but the code is left in memory. ; ---------------------------------------------------------------- invoke PostQuitMessage,NULL return 0 .endif invoke DefWindowProc,hWin,uMsg,wParam,lParam ; -------------------------------------------------------------------- ; Default window processing is done by the operating system for any ; message that is not processed by the application in the WndProc ; procedure. If the application requires other than default processing ; it executes the code when the message is trapped and returns ZERO ; to exit the WndProc procedure before the default window processing ; occurs with the call to DefWindowProc(). ; -------------------------------------------------------------------- ret WndProc endp ; ######################################################################## TopXY proc wDim:DWORD, sDim:DWORD ; ---------------------------------------------------- ; This procedure calculates the top X & Y co-ordinates ; for the CreateWindowEx call in the WinMain procedure ; ---------------------------------------------------- shr sDim, 1 ; divide screen dimension by 2 shr wDim, 1 ; divide window dimension by 2 mov eax, wDim ; copy window dimension into eax sub sDim, eax ; sub half win dimension from half screen dimension return sDim TopXY endp ; ######################################################################## end start ================================================ FILE: tests/projects/asm/masm32/src/rsrc.rc ================================================ 500 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "MAINICON.ICO" 600 MENUEX MOVEABLE IMPURE LOADONCALL DISCARDABLE BEGIN POPUP "&File", , , 0 BEGIN MENUITEM "&Exit", 1000 END POPUP "&Help", , , 0 BEGIN MENUITEM "&About", 1900 END END ================================================ FILE: tests/projects/asm/masm32/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_allowedplats("windows") set_defaultarchs("x86") target("test") set_kind("binary") add_files("src/*.asm") add_files("src/*.rc") set_toolchains("masm32") ================================================ FILE: tests/projects/asm/nasm/src/main.S ================================================ global _main section .text _main: mov rax, 0x2000004 ; write mov rdi, 1 ; stdout mov rsi, msg mov rdx, msg.len syscall mov rax, 0x2000001 ; exit mov rdi, 0 syscall section .data msg: db "hello xmake!", 10 .len: equ $ - msg ================================================ FILE: tests/projects/asm/nasm/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.S") ================================================ FILE: tests/projects/asm/yasm/src/main.S ================================================ bits 64 extern _puts section .data message: db 'hello xmake!', 0 section .text global _main _main: push rbp mov rbp, rsp lea rdi, [rel message] call _puts xor rax, rax pop rbp ret ================================================ FILE: tests/projects/asm/yasm/src/main_elf.S ================================================ bits 64 extern puts section .data message: db 'hello xmake!', 0 section .text global main main: push rbp mov rbp, rsp lea rdi, [rel message] call puts xor rax, rax pop rbp ret ================================================ FILE: tests/projects/asm/yasm/src/stub.c ================================================ ================================================ FILE: tests/projects/asm/yasm/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.c") if is_plat("linux") then add_files("src/main_elf.S") else add_files("src/main.S") end ================================================ FILE: tests/projects/c/Unicode 测试/test.lua ================================================ -- main entry function main(t) -- build project, xmake does not support unicode for msys2/mingw if not is_subhost("msys", "cygwin") then t:build() end end ================================================ FILE: tests/projects/c/Unicode 测试/xmake.lua ================================================ -- this file saved with utf-16 le for test purpose add_rules("mode.debug", "mode.release") target("程序") set_kind("binary") add_files("源文件🎆/*.c") add_includedirs("头文件✨") before_build(function() print("开始编译😊") end) after_build(function() print("结束编译🎉") end) ================================================ FILE: tests/projects/c/Unicode 测试/头文件✨/标头🎟.h ================================================ #pragma once void hello(); ================================================ FILE: tests/projects/c/Unicode 测试/源文件🎆/中文.c ================================================ #include <标头🎟.h> int main(int argc, char** argv) { hello(); return 0; } ================================================ FILE: tests/projects/c/Unicode 测试/源文件🎆/😘.c ================================================ #include #include #include <标头🎟.h> void hello() { printf("你好\n"); } ================================================ FILE: tests/projects/c/asn1c/src/main.c ================================================ #include #include #include /* Rectangle ASN.1 type */ /* * This is a custom function which writes the * encoded output into some FILE stream. */ static int write_out(const void *buffer, size_t size, void *app_key) { FILE *out_fp = app_key; size_t wrote; wrote = fwrite(buffer, 1, size, out_fp); return (wrote == size) ? 0 : -1; } int main(int ac, char **av) { Rectangle_t *rectangle; /* Type to encode */ asn_enc_rval_t ec; /* Encoder return value */ /* Allocate the Rectangle_t */ rectangle = calloc(1, sizeof(Rectangle_t)); /* not malloc! */ if(!rectangle) { perror("calloc() failed"); exit(71); /* better, EX_OSERR */ } /* * Initialize the Rectangle members */ /* height */ rectangle->height = 42; /* width */ rectangle->width = 23; /* BER encode the data if filename is given */ if(ac < 2) { fprintf(stderr, "Specify filename for BER output\n"); } else { const char *filename = av[1]; FILE *fp = fopen(filename, "wb"); /* for BER output */ if(!fp) { perror(filename); exit(71); /* better, EX_OSERR */ } /* Encode the Rectangle type as BER (DER) */ ec = der_encode(&asn_DEF_Rectangle, rectangle, write_out, fp); fclose(fp); if(ec.encoded == -1) { fprintf(stderr, "Could not encode Rectangle (at %s)\n", ec.failed_type ? ec.failed_type->name : "unknown"); exit(65); /* better, EX_DATAERR */ } else { fprintf(stderr, "Created %s with BER encoded Rectangle\n", filename); } } /* Also print the constructed Rectangle XER encoded (XML) */ xer_fprint(stdout, &asn_DEF_Rectangle, rectangle); return 0; /* Encoding finished successfully */ } ================================================ FILE: tests/projects/c/asn1c/src/rectangle.asn1 ================================================ RectangleModule1 DEFINITIONS ::= BEGIN Rectangle ::= SEQUENCE { height INTEGER, width INTEGER } END ================================================ FILE: tests/projects/c/asn1c/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("asn1c") target("test") set_kind("binary") add_files("src/*.c") add_files("src/*.asn1") add_rules("asn1c") add_packages("asn1c") ================================================ FILE: tests/projects/c/console/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/c/console/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.c") ================================================ FILE: tests/projects/c/cosmocc/console/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world\n"); return 0; } ================================================ FILE: tests/projects/c/cosmocc/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("cosmocc") target("test") set_kind("binary") add_files("src/*.c") set_toolchains("@cosmocc") ================================================ FILE: tests/projects/c/cosmocc/static_library/src/foo.c ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c/cosmocc/static_library/src/foo.h ================================================ int add(int a, int b); ================================================ FILE: tests/projects/c/cosmocc/static_library/src/main.c ================================================ #include "foo.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/c/cosmocc/static_library/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("cosmocc") set_toolchains("@cosmocc") target("foo") set_kind("static") add_files("src/foo.c") target("demo") set_kind("binary") add_deps("foo") add_files("src/main.c") ================================================ FILE: tests/projects/c/embeddirs/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/c/embeddirs/assets/message.txt ================================================ Hello from an embedded C23 file! ================================================ FILE: tests/projects/c/embeddirs/src/main.c ================================================ #include #include static const unsigned char message_data[] = { #embed "message.txt" , '\0' }; int main(int argc, char** argv) { printf("Embedded message: %s\n", (const char*)message_data); printf("Size of embedded data (including null terminator): %zu bytes\n", sizeof(message_data)); printf("Length of embedded string: %zu characters\n", strlen((const char*)message_data)); return 0; } ================================================ FILE: tests/projects/c/embeddirs/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c23") target("embeddirs") set_kind("binary") add_files("src/*.c") add_embeddirs("assets") ================================================ FILE: tests/projects/c/headeronly/src/foo.h ================================================ /*! calculate add(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ int add(int a, int b); ================================================ FILE: tests/projects/c/headeronly/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/headeronly/xmake.lua ================================================ add_rules("mode.release", "mode.debug") target("foo") set_kind("headeronly") add_headerfiles("src/foo.h") add_rules("utils.install.cmake_importfiles") add_rules("utils.install.pkgconfig_importfiles") ================================================ FILE: tests/projects/c/library_with_cmakelists/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/c/library_with_cmakelists/foo/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.13.0) project(foo LANGUAGES C CXX ASM) add_library(foo STATIC "") target_sources(foo PRIVATE src/foo.c ) set_target_properties(foo PROPERTIES PUBLIC_HEADER src/foo.h) include(GNUInstallDirs) install(TARGETS foo LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) ================================================ FILE: tests/projects/c/library_with_cmakelists/foo/src/foo.c ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c/library_with_cmakelists/foo/src/foo.h ================================================ int add(int a, int b); ================================================ FILE: tests/projects/c/library_with_cmakelists/src/main.c ================================================ #include "foo.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/c/library_with_cmakelists/test.lua ================================================ -- main entry function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/c/library_with_cmakelists/xmake.lua ================================================ add_rules("mode.debug", "mode.release") package("foo") add_deps("cmake") set_sourcedir(path.join(os.scriptdir(), "foo")) set_policy("package.install_always", true) on_install(function (package) local configs = {} table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release")) table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF")) import("package.tools.cmake").install(package, configs) end) on_test(function (package) assert(package:has_cfuncs("add", {includes = "foo.h"})) end) package_end() add_requires("foo") target("demo") set_kind("binary") add_files("src/main.c") add_packages("foo") ================================================ FILE: tests/projects/c/linker_scripts/src/foo.c ================================================ #include void foo() { printf("hello world!\n"); } ================================================ FILE: tests/projects/c/linker_scripts/src/foo.def ================================================ EXPORTS foo ================================================ FILE: tests/projects/c/linker_scripts/src/main.c ================================================ #include void foo(); int main(int argc, char** argv) { foo(); return 0; } ================================================ FILE: tests/projects/c/linker_scripts/src/main.lds ================================================ SECTIONS { . = 0x10000; .text : { *(.text) } .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array*)) PROVIDE_HIDDEN (__init_array_end = .); } . = 0x8000000; .data : { *(.data) } .bss : { *(.bss) } } ================================================ FILE: tests/projects/c/linker_scripts/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/linker_scripts/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") add_deps("foo") set_kind("binary") add_files("src/main.c") if is_plat("linux") and is_arch("x86_64") then add_files("src/main.lds") end target("foo") set_kind("shared") add_files("src/foo.c") if is_plat("windows", "mingw") then add_files("src/foo.def") else add_files("src/foo.map") end ================================================ FILE: tests/projects/c/llvm_compiler_rt/src/main.c ================================================ int main(int argc, char **argv) { __int128 a = 123; __int128 b = 1; return a / b; } ================================================ FILE: tests/projects/c/llvm_compiler_rt/test.lua ================================================ import("lib.detect.find_tool") import("core.tool.toolchain") import("utils.ci.is_running", {alias = "ci_is_running"}) function run_test(toolchain_name) local flags = "" if ci_is_running() then flags = "-vD" end local plat = os.host() local arch = os.arch() if is_subhost("msys") then plat = "mingw" end local toolchain_inst = toolchain.load(toolchain_name, {plat = plat, arch = arch}) if not toolchain_inst or not toolchain_inst:check() then wprint(toolchain_name .. " not found, skipping tests") return end os.exec("xmake clean -a") os.exec("xmake f --toolchain=" .. toolchain_name .. " -c --yes " .. flags) os.run("xmake -r " .. flags) end function main(t) run_test("llvm") run_test("clang") end ================================================ FILE: tests/projects/c/llvm_compiler_rt/xmake.lua ================================================ target("foo") set_kind("binary") add_files("src/main.c") ================================================ FILE: tests/projects/c/precompiled_header/src/header.h ================================================ // header.h #ifndef HEADER_H #define HEADER_H #include #include #include #endif ================================================ FILE: tests/projects/c/precompiled_header/src/main.c ================================================ #include "header.h" int main(int argc, char** argv) { printf("hello xmake!\n"); return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test.c ================================================ // main.cpp #include "header.h" int test() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test.cpp ================================================ int test_cpp() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test2.c ================================================ // main.cpp #include "header.h" int test2() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test3.c ================================================ // main.cpp #include "header.h" int test3() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test4.c ================================================ // main.cpp #include "header.h" int test4() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test5.c ================================================ // main.cpp #include "header.h" int test5() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test6.c ================================================ // main.cpp #include "header.h" int test6() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test7.c ================================================ // main.cpp #include "header.h" int test7() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/src/test8.c ================================================ // main.cpp #include "header.h" int test8() { return 0; } ================================================ FILE: tests/projects/c/precompiled_header/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/precompiled_header/xmake.lua ================================================ target("main") set_kind("binary") set_pcheader("src/header.h") add_files("src/*.c", "src/*.cpp") ================================================ FILE: tests/projects/c/protobuf/src/main.c ================================================ #include #include "test.pb-c.h" #include "subdir/test2.pb-c.h" int main(int argc, char** argv) { return 0; } ================================================ FILE: tests/projects/c/protobuf/src/subdir/test2.proto ================================================ syntax = "proto3"; package test2; message TestCase2 { string name = 4; } message Test2 { repeated TestCase2 case = 1; } ================================================ FILE: tests/projects/c/protobuf/src/test.proto ================================================ syntax = "proto3"; import "subdir/test2.proto"; package test; message TestCase { string name = 4; } message Test { repeated TestCase case = 1; repeated test2.TestCase2 case2 = 2; } ================================================ FILE: tests/projects/c/protobuf/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("protobuf-c") target("test") set_kind("binary") add_packages("protobuf-c") add_rules("protobuf.c") add_files("src/*.c") add_files("src/**.proto", {proto_rootdir = "src"}) ================================================ FILE: tests/projects/c/shared_library/src/foo.c ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c/shared_library/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) # define __export __declspec(dllexport) #elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) # define __export __attribute__((visibility("default"))) #else # define __export #endif __export int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/c/shared_library/src/main.c ================================================ #include "foo.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/c/shared_library/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/shared_library/xmake.lua ================================================ add_rules("mode.release", "mode.debug") target("foo") set_kind("shared") add_files("src/foo.c") target("test") set_kind("binary") add_deps("foo") add_files("src/main.c") ================================================ FILE: tests/projects/c/shared_library_export_all/src/bar.cpp ================================================ #include class bar { bar() {} ~bar() {} void test() {} }; void test(bar& b) { printf("test\n"); } ================================================ FILE: tests/projects/c/shared_library_export_all/src/foo.c ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c/shared_library_export_all/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/c/shared_library_export_all/src/main.c ================================================ #include "foo.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/c/shared_library_export_all/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/shared_library_export_all/xmake.lua ================================================ add_rules("mode.release", "mode.debug") target("foo") set_kind("shared") add_files("src/foo.c", "src/bar.cpp") add_rules("utils.symbols.export_all", {export_classes = true}) target("test") set_kind("binary") add_deps("foo") add_files("src/main.c") ================================================ FILE: tests/projects/c/shared_library_export_list/src/foo.c ================================================ #include "foo.h" #include void stub() { printf("stub\n"); } int sub(int a, int b) { return a - b; } int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c/shared_library_export_list/src/foo.export.txt ================================================ add sub ================================================ FILE: tests/projects/c/shared_library_export_list/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/c/shared_library_export_list/src/main.c ================================================ #include "foo.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/c/shared_library_export_list/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/shared_library_export_list/xmake.lua ================================================ add_rules("mode.release", "mode.debug") target("foo") set_kind("shared") add_files("src/foo.c") add_rules("utils.symbols.export_list", {symbols = { "add", "sub"}}) target("foo2") set_kind("shared") add_files("src/foo.c") add_files("src/foo.export.txt") add_rules("utils.symbols.export_list") target("test") set_kind("binary") add_deps("foo") add_files("src/main.c") ================================================ FILE: tests/projects/c/static library with spaces/i n c/interface.h ================================================ /*! calculate add(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ int add(int a, int b); ================================================ FILE: tests/projects/c/static library with spaces/i n c/stdafx.h ================================================ ================================================ FILE: tests/projects/c/static library with spaces/s r c/interface.c ================================================ #include "interface.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c/static library with spaces/s r c/test.c ================================================ #include "interface.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/c/static library with spaces/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/static library with spaces/xmake.lua ================================================ add_rules("mode.release", "mode.debug") target("test") set_kind("static") add_files("s r c/interface.c") add_sysincludedirs("$(projectdir)/i n c", {public = true}) target("demo") set_kind("binary") add_deps("test") add_files("s r c/test.c") set_pcheader("$(projectdir)/i n c/stdafx.h") ================================================ FILE: tests/projects/c/static_library/src/foo.c ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c/static_library/src/foo.h ================================================ int add(int a, int b); ================================================ FILE: tests/projects/c/static_library/src/main.c ================================================ #include "foo.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/c/static_library/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/static_library/xmake.lua ================================================ add_rules("mode.release", "mode.debug") target("foo") set_kind("static") add_files("src/foo.c") target("demo") set_kind("binary") add_deps("foo") add_files("src/main.c") ================================================ FILE: tests/projects/c/unity_build/src/bar/test4.c ================================================ // main.cpp #include "header.h" int test4() { return 0; } ================================================ FILE: tests/projects/c/unity_build/src/bar/test5.c ================================================ // main.cpp #include "header.h" int test5() { return 0; } ================================================ FILE: tests/projects/c/unity_build/src/foo/test1.c ================================================ // main.cpp #include "header.h" int test() { return 0; } ================================================ FILE: tests/projects/c/unity_build/src/foo/test2.c ================================================ // main.cpp #include "header.h" int test3() { return 0; } ================================================ FILE: tests/projects/c/unity_build/src/header.h ================================================ // header.h #ifndef HEADER_H #define HEADER_H #include #include #include #endif ================================================ FILE: tests/projects/c/unity_build/src/main.c ================================================ #include "header.h" int main(int argc, char** argv) { printf("hello xmake!\n"); return 0; } ================================================ FILE: tests/projects/c/unity_build/src/test.cpp ================================================ int test_cpp() { return 0; } ================================================ FILE: tests/projects/c/unity_build/src/test2.c ================================================ // main.cpp #include "header.h" int test2() { return 0; } ================================================ FILE: tests/projects/c/unity_build/src/test6.c ================================================ // main.cpp #include "header.h" int test6() { return 0; } ================================================ FILE: tests/projects/c/unity_build/src/test7.c ================================================ // main.cpp #include "header.h" int test7() { return 0; } ================================================ FILE: tests/projects/c/unity_build/src/test8.c ================================================ // main.cpp #include "header.h" int test8() { return 0; } ================================================ FILE: tests/projects/c/unity_build/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c/unity_build/xmake.lua ================================================ target("test") set_kind("binary") add_includedirs("src") add_rules("c.unity_build", {batchsize = 2}) add_files("src/*.c", "src/*.cpp") add_files("src/foo/*.c", {unity_group = "foo"}) add_files("src/bar/*.c", {unity_group = "bar"}) ================================================ FILE: tests/projects/c++/capnproto/proto/message.capnp ================================================ @0xd30600b3651feef7; using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("test::proto"); struct Message { text @0 :Text; } ================================================ FILE: tests/projects/c++/capnproto/src/main.cc ================================================ #include #include "message.capnp.h" int main() { capnp::MallocMessageBuilder builder; // test::proto::Message msg; } ================================================ FILE: tests/projects/c++/capnproto/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("capnproto") target("test") set_kind("binary") set_languages("c++14") add_packages("capnproto") add_files("src/**.cc") add_files("proto/*.capnp", {rules = "capnproto.cpp", capnp_rootdir = "proto"}) ================================================ FILE: tests/projects/c++/console/src/main.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/projects/c++/console/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.cpp") ================================================ FILE: tests/projects/c++/console_zig_cxx/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/c++/console_zig_cxx/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/c++/console_zig_cxx/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("zig") target("test") set_kind("binary") add_files("src/*.cpp") set_toolchains("zig@zigcc") ================================================ FILE: tests/projects/c++/doctest/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/c++/doctest/src/foo.cpp ================================================ void foo() { } ================================================ FILE: tests/projects/c++/doctest/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/c++/doctest/tests/test_1.cpp ================================================ #include "doctest/doctest.h" static int factorial(int number) { return number <= 1 ? number : factorial(number - 1) * number; } TEST_CASE("testing the factorial function") { CHECK(factorial(1) == 10); CHECK(factorial(2) == 2); CHECK(factorial(3) == 6); CHECK(factorial(10) == 3628800); } ================================================ FILE: tests/projects/c++/doctest/tests/test_2.cpp ================================================ #include "doctest/doctest.h" static int factorial(int number) { return number <= 1 ? number : factorial(number - 1) * number; } TEST_CASE("testing the factorial function") { CHECK(factorial(1) == 1); CHECK(factorial(2) == 2); CHECK(factorial(3) == 6); CHECK(factorial(10) == 3628800); } ================================================ FILE: tests/projects/c++/doctest/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("doctest") target("doctest") set_kind("binary") add_files("src/*.cpp") for _, testfile in ipairs(os.files("tests/*.cpp")) do add_tests(path.basename(testfile), { files = testfile, remove_files = "src/main.cpp", languages = "c++11", packages = "doctest", defines = "DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN"}) end target("doctest_shared") set_kind("shared") add_files("src/foo.cpp") for _, testfile in ipairs(os.files("tests/*.cpp")) do add_tests(path.basename(testfile), { kind = "binary", files = testfile, languages = "c++11", packages = "doctest", defines = "DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN"}) end ================================================ FILE: tests/projects/c++/linkorders/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c++/linkorders/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/c++/linkorders/src/main.cpp ================================================ #include "foo.h" #include using namespace std; int main(int argc, char** argv) { cout << "add(1, 2) = " << add(1, 2) << endl; return 0; } ================================================ FILE: tests/projects/c++/linkorders/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/c++/linkorders/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("libpng") target("bar") set_kind("shared") add_files("src/foo.cpp") add_linkgroups("m", "pthread", {whole = true}) target("foo") set_kind("static") add_files("src/foo.cpp") add_packages("libpng", {public = true}) target("demo") set_kind("binary") add_deps("foo") add_files("src/main.cpp") if is_plat("linux", "macosx") then add_syslinks("pthread", "m", "dl") end if is_plat("macosx") then add_frameworks("Foundation", "CoreFoundation") end add_linkorders("framework::Foundation", "png16", "foo") add_linkorders("dl", "linkgroup::syslib") add_linkgroups("m", "pthread", {name = "syslib", group = true}) ================================================ FILE: tests/projects/c++/manifest/src/main.cpp ================================================ #include using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/c++/manifest/src/main.manifest ================================================ ================================================ FILE: tests/projects/c++/manifest/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test1") set_kind("binary") add_files("src/*.cpp") add_files("src/*.manifest") target("test2") set_kind("binary") add_files("src/*.cpp") set_policy("windows.manifest.uac", "admin") ================================================ FILE: tests/projects/c++/modules/add_move_remove_module/src/foo.mpp ================================================ export module foo; export { inline int foo() { return 1; } } ================================================ FILE: tests/projects/c++/modules/add_move_remove_module/test.lua ================================================ inherit(".test_base") import("utils.ci.is_running", {alias = "ci_is_running"}) CLANG_MIN_VER = is_subhost("windows") and "19" or "17" GCC_MIN_VER = "11" MSVC_MIN_VER = "14.29" function _build(_) local flags = "" if ci_is_running() then flags = "-vD" end os.run("xmake -r " .. flags) io.writefile("src/bar.mpp", "export module bar;\n export {\n inline int bar() { return 0; }\n}") os.run("xmake " .. flags) os.rm("src/bar.mpp") os.run("xmake " .. flags) os.mv("src/foo.mpp", "src/bar.mpp") os.run("xmake " .. flags) os.mv("src/bar.mpp", "src/foo.mpp") end function main(_) local clang_options = {compiler = "clang", version = CLANG_MIN_VER, build = _build} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER, build = _build} local msvc_options = {version = MSVC_MIN_VER, build = _build} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/add_move_remove_module/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("mod") set_kind("static") add_files("src/*.mpp", {public = true}) ================================================ FILE: tests/projects/c++/modules/aliased_headerunit/src/foo/hello.mpp ================================================ module; #include export module hello; import "../header.hpp"; export namespace hello { void say(const char *arg) { printf("%s: %s\n", FOO, arg); } } ================================================ FILE: tests/projects/c++/modules/aliased_headerunit/src/header.hpp ================================================ #pragma once namespace hello { inline constexpr auto FOO = "Hello"; } ================================================ FILE: tests/projects/c++/modules/aliased_headerunit/src/main.cpp ================================================ import hello; import "header.hpp"; int main() { hello::say(hello::FOO); return 0; } ================================================ FILE: tests/projects/c++/modules/aliased_headerunit/test.lua ================================================ inherit(".test_headerunits") ================================================ FILE: tests/projects/c++/modules/aliased_headerunit/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") -- header.hpp should be built only one time target("aliased_headerunit") set_kind("binary") add_headerfiles("src/*.hpp") add_files("src/*.cpp", "src/foo/*.mpp") ================================================ FILE: tests/projects/c++/modules/circular_dependency/src/hello.mpp ================================================ export module hello; import hello3; export namespace hello { class say { public: say(int data); void hello(); private: int data_; }; } ================================================ FILE: tests/projects/c++/modules/circular_dependency/src/hello2.mpp ================================================ export module hello2; import hello; ================================================ FILE: tests/projects/c++/modules/circular_dependency/src/hello3.mpp ================================================ export module hello3; import hello2; ================================================ FILE: tests/projects/c++/modules/circular_dependency/src/main.cpp ================================================ import hello; int main() { hello::say s(sizeof(hello::say)); s.hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/circular_dependency/test.lua ================================================ import(".test_base", {alias = "test_build"}) function main(t) if test_build.can_build() then t:will_raise(test_build, "circular modules dependency detected") end end ================================================ FILE: tests/projects/c++/modules/circular_dependency/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("circular_dependency") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/class/src/hello.mpp ================================================ export module hello; export namespace hello { class say { public: say(int data); void hello(); private: int data_; }; } ================================================ FILE: tests/projects/c++/modules/class/src/hello_impl.cpp ================================================ module; #include module hello; using namespace std; namespace hello { say::say(int data) : data_(data) { } void say::hello() { cout << "hello, say class: " << data_ << endl; } } // namespace hello ================================================ FILE: tests/projects/c++/modules/class/src/main.cpp ================================================ import hello; int main() { hello::say s(sizeof(hello::say)); s.hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/class/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/class/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("class") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/class_cmake/src/hello.mpp ================================================ export module hello; export namespace hello { class say { public: say(int data); void hello(); private: int data_; }; } ================================================ FILE: tests/projects/c++/modules/class_cmake/src/hello_impl.cpp ================================================ module; #include module hello; using namespace std; namespace hello { say::say(int data) : data_(data) { } void say::hello() { cout << "hello, say class: " << data_ << endl; } } // namespace hello ================================================ FILE: tests/projects/c++/modules/class_cmake/src/main.cpp ================================================ import hello; int main() { hello::say s(sizeof(hello::say)); s.hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/class_cmake/test.lua ================================================ inherit(".test_cmake") ================================================ FILE: tests/projects/c++/modules/class_cmake/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("class") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/cpp_with_moduledeps/src/main.cpp ================================================ // main.cpp import mod; int main() { f(); return 0; } ================================================ FILE: tests/projects/c++/modules/cpp_with_moduledeps/src/mod.cpp ================================================ module mod; void f() { } ================================================ FILE: tests/projects/c++/modules/cpp_with_moduledeps/src/mod.mpp ================================================ export module mod; export void f(); ================================================ FILE: tests/projects/c++/modules/cpp_with_moduledeps/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/cpp_with_moduledeps/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("mod") set_kind("static") add_files("src/mod.mpp", {public = true}) add_files("src/mod.cpp") target("cpp_with_moduledeps") set_kind("binary") add_deps("mod") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/modules/culling/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { void say(const char* str) { printf("%s\n", str); } } ================================================ FILE: tests/projects/c++/modules/culling/test.lua ================================================ inherit(".test_culling") ================================================ FILE: tests/projects/c++/modules/culling/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("culling") set_kind("static") add_files("src/*.mpp") set_policy("build.c++.modules.culling", false) ================================================ FILE: tests/projects/c++/modules/culling2/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { void say(const char* str) { printf("%s\n", str); } } ================================================ FILE: tests/projects/c++/modules/culling2/test.lua ================================================ inherit(".test_culling") ================================================ FILE: tests/projects/c++/modules/culling2/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("culling") set_kind("static") add_files("src/*.mpp", {cull = false}) ================================================ FILE: tests/projects/c++/modules/culling3/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { void say(const char* str) { printf("%s\n", str); } } ================================================ FILE: tests/projects/c++/modules/culling3/test.lua ================================================ inherit(".test_culling") ================================================ FILE: tests/projects/c++/modules/culling3/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("culling") set_kind("static") add_files("src/*.mpp") ================================================ FILE: tests/projects/c++/modules/dependence/src/hello.mpp ================================================ export module hello; export namespace hello { extern int data__; void say_hello(); class say { public: say(int data); void hello(); private: int data_; }; } ================================================ FILE: tests/projects/c++/modules/dependence/src/hello_impl.cpp ================================================ module; #include module hello; import mod; void inner() { std::cout << "hello world! data: " << mod::foo() << std::endl; } namespace hello { int data__; void say_hello() { ::inner(); } say::say(int data) : data_{ data } { } void say::hello() { hello::data__ = data_; ::inner(); } } // namespace hello ================================================ FILE: tests/projects/c++/modules/dependence/src/main.cpp ================================================ import hello; int main() { hello::data__ = 123; hello::say_hello(); hello::say(sizeof(hello::say)).hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/dependence/src/mod.mpp ================================================ export module mod; export namespace mod { int foo(); } ================================================ FILE: tests/projects/c++/modules/dependence/src/mod_impl.cpp ================================================ module mod; import hello; namespace mod { int foo() { return hello::data__; } } // namespace mod ================================================ FILE: tests/projects/c++/modules/dependence/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/dependence/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("dependence") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/dependence2/src/bar.mpp ================================================ export module bar; import zoo; export namespace bar { int add(int a, int b) { return zoo::add(a, b); } } ================================================ FILE: tests/projects/c++/modules/dependence2/src/cat.mpp ================================================ export module cat; export namespace cat { int sub(int a, int b) { return a - b; } } ================================================ FILE: tests/projects/c++/modules/dependence2/src/foo.mpp ================================================ export module foo; import bar; import cat; export namespace foo { int add(int a, int b) { return bar::add(a, b); } int sub(int a, int b) { return cat::sub(a, b); } } ================================================ FILE: tests/projects/c++/modules/dependence2/src/main.cpp ================================================ #include import foo; int main() { printf("add(1, 2): %d\n", foo::add(1, 2)); printf("sub(1, 2): %d\n", foo::sub(1, 2)); return 0; } ================================================ FILE: tests/projects/c++/modules/dependence2/src/zoo.mpp ================================================ export module zoo; export namespace zoo { int add(int a, int b) { return a + b; } } ================================================ FILE: tests/projects/c++/modules/dependence2/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/dependence2/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("dependence2") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/dependency_flag_update/src/bar.mpp ================================================ module; #include export module bar; namespace bar { export void hello() { std::cout << "Hello world2" << std::endl; } } // namespace bar ================================================ FILE: tests/projects/c++/modules/dependency_flag_update/src/foo.mpp ================================================ module; #include export module foo; namespace foo { export void hello() { std::cout << "Hello world" << std::endl; } } // namespace foo ================================================ FILE: tests/projects/c++/modules/dependency_flag_update/src/main.cpp ================================================ #if defined(FOO) import foo; using namespace foo; #else import bar; using namespace bar; #endif int main() { hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/dependency_flag_update/test.lua ================================================ inherit(".test_dependency_scanner") ================================================ FILE: tests/projects/c++/modules/dependency_flag_update/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") option("foo") set_default("true") add_defines("FOO") target("dependency_flag_update") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") add_options("foo") ================================================ FILE: tests/projects/c++/modules/dependency_flag_update2/src/bar.mpp ================================================ module; #include export module bar; namespace bar { export void hello() { std::cout << "Hello world2" << std::endl; } } // namespace bar ================================================ FILE: tests/projects/c++/modules/dependency_flag_update2/src/foo.mpp ================================================ module; #include export module foo; namespace foo { export void hello() { std::cout << "Hello world" << std::endl; } } // namespace foo ================================================ FILE: tests/projects/c++/modules/dependency_flag_update2/src/foobar.mpp ================================================ export module foobar; #if defined(FOO) import foo; namespace impl = foo; #else import bar; namespace impl = bar; #endif export void hello() { impl::hello(); } ================================================ FILE: tests/projects/c++/modules/dependency_flag_update2/src/main.cpp ================================================ import foobar; int main() { hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/dependency_flag_update2/test.lua ================================================ inherit(".test_dependency_scanner") ================================================ FILE: tests/projects/c++/modules/dependency_flag_update2/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") option("foo") set_default("true") add_defines("FOO") target("dependency_flag_update3") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") add_options("foo") ================================================ FILE: tests/projects/c++/modules/duplicate_name_detection/src/bar.mpp ================================================ export module foo; export int value() { return 1; } ================================================ FILE: tests/projects/c++/modules/duplicate_name_detection/src/foo.mpp ================================================ export module foo; export int value() { return 0; } ================================================ FILE: tests/projects/c++/modules/duplicate_name_detection/src/main.cpp ================================================ import foo; int main() { return value(); } ================================================ FILE: tests/projects/c++/modules/duplicate_name_detection/test.lua ================================================ inherit(".test_duplicate_modules") ================================================ FILE: tests/projects/c++/modules/duplicate_name_detection/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("foo") set_kind("moduleonly") add_files("src/foo.mpp") target("bar") set_kind("moduleonly") add_files("src/bar.mpp") target("duplicate_name_detection_1") set_kind("binary") add_deps("foo", "bar") add_files("src/main.cpp") target("duplicate_name_detection_2") set_kind("binary") add_deps("bar", "foo") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/modules/headerunits_person/src/Person.mpp ================================================ module; #include export module person; import ; export class Person { public: Person(std::string firstName, std::string lastName) : m_firstName{std::move(firstName)}, m_lastName{std::move(lastName)} {} const std::string &getFirstName() const { return m_firstName; } const std::string &getLastName() const { return m_lastName; } private: std::string m_firstName; std::string m_lastName; }; ================================================ FILE: tests/projects/c++/modules/headerunits_person/src/test.cpp ================================================ import person; import ; import ; // For operator<< for std::string using namespace std; int main() { Person person{ "Kole", "Webb" }; cout << person.getLastName() << ", " << person.getFirstName() << endl; } ================================================ FILE: tests/projects/c++/modules/headerunits_person/test.lua ================================================ inherit(".test_headerunits") ================================================ FILE: tests/projects/c++/modules/headerunits_person/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("headerunits_person") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/hello/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { void say(const char* str) { printf("%s\n", str); } } ================================================ FILE: tests/projects/c++/modules/hello/src/main.cpp ================================================ import hello; int main() { hello::say("hello module!"); return 0; } ================================================ FILE: tests/projects/c++/modules/hello/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/hello/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("hello") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/hello with spaces/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { void say(const char* str) { printf("%s\n", str); } } ================================================ FILE: tests/projects/c++/modules/hello with spaces/src/main.cpp ================================================ import hello; int main() { hello::say("hello module!"); return 0; } ================================================ FILE: tests/projects/c++/modules/hello with spaces/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/hello with spaces/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("hello with spaces") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/hello_mpp/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { void say(const char* str) { printf("%s\n", str); } } ================================================ FILE: tests/projects/c++/modules/hello_mpp/src/main.mpp ================================================ #include int main() { std::printf("Hello world\n"); return 0; } ================================================ FILE: tests/projects/c++/modules/hello_mpp/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/hello_mpp/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++23") target("hello") set_kind("binary") add_files("src/*.mpp") ================================================ FILE: tests/projects/c++/modules/hello_with_pch/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { void say(const char* str) { printf("%s\n", str); } } ================================================ FILE: tests/projects/c++/modules/hello_with_pch/src/main.cpp ================================================ #include "test.h" import hello; int main() { hello::say("hello module!"); return 0; } ================================================ FILE: tests/projects/c++/modules/hello_with_pch/src/test.h ================================================ #include ================================================ FILE: tests/projects/c++/modules/hello_with_pch/test.lua ================================================ inherit(".test_base") CLANG_MIN_VER = is_subhost("windows") and "19" or "17" GCC_MIN_VER = "11" MSVC_MIN_VER = "14.29" function main(_) -- clang-cl doesn't support mixing pch and C++ module atm local clang_options = {compiler = "clang", version = CLANG_MIN_VER, disable_clang_cl = true} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER} local msvc_options = {version = MSVC_MIN_VER} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/hello_with_pch/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("hello") set_kind("binary") set_pcxxheader("src/test.h") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/hide_dependency_flags/src/bar.mpp ================================================ export module bar; import zoo; export namespace bar { int add(int a, int b) { return zoo::add(a, b); } } ================================================ FILE: tests/projects/c++/modules/hide_dependency_flags/src/cat.mpp ================================================ export module cat; export namespace cat { int sub(int a, int b) { return a - b; } } ================================================ FILE: tests/projects/c++/modules/hide_dependency_flags/src/foo.mpp ================================================ export module foo; import bar; import cat; export namespace foo { int add(int a, int b) { return bar::add(a, b); } int sub(int a, int b) { return cat::sub(a, b); } } ================================================ FILE: tests/projects/c++/modules/hide_dependency_flags/src/main.cpp ================================================ #include import foo; int main(int argc, char **argv) { printf("add(1, 2): %d\n", foo::add(1, 2)); printf("sub(1, 2): %d\n", foo::sub(1, 2)); return 0; } ================================================ FILE: tests/projects/c++/modules/hide_dependency_flags/src/zoo.mpp ================================================ export module zoo; export namespace zoo { int add(int a, int b) { return a + b; } } ================================================ FILE: tests/projects/c++/modules/hide_dependency_flags/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/hide_dependency_flags/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("dependence2") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") set_policy("build.c++.modules.hide_dependencies", true) ================================================ FILE: tests/projects/c++/modules/ifdef_module/src/main.cpp ================================================ #ifdef FOO import hello; #endif int main() { return 0; } ================================================ FILE: tests/projects/c++/modules/ifdef_module/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/ifdef_module/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("ifdef_module") set_kind("binary") add_files("src/*.cpp") set_policy("build.c++.modules", true) ================================================ FILE: tests/projects/c++/modules/impl_unit/src/hello.mpp ================================================ export module hello; namespace hello { void say_hi(); } export namespace hello { void say_hello(); void say_xz(); } ================================================ FILE: tests/projects/c++/modules/impl_unit/src/hello_impl.cpp ================================================ module; #include module hello; using namespace std; namespace hello { void say_hi() { cout << "hello hi!" << endl; } void say_hello() { cout << "hello world!" << endl; } void say_xz() { cout << "hello xz!" << endl; } } // namespace hello ================================================ FILE: tests/projects/c++/modules/impl_unit/src/main.cpp ================================================ import hello; int main() { hello::say_hello(); hello::say_xz(); // hello::say_hi(); return 0; } ================================================ FILE: tests/projects/c++/modules/impl_unit/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/impl_unit/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("impl_unit") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/include-dirs/include/foo.h ================================================ inline int foo() { return 0; } ================================================ FILE: tests/projects/c++/modules/include-dirs/src/hello.mpp ================================================ module; #include "foo.h" export module bar; export int bar() { return foo(); } ================================================ FILE: tests/projects/c++/modules/include-dirs/src/main.cpp ================================================ import bar; int main() { return bar(); } ================================================ FILE: tests/projects/c++/modules/include-dirs/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/include-dirs/xmake.lua ================================================ add_rules("mode.debug", "mode.release") rule("include") before_config(function (target) target:add("includedirs", "$(projectdir)/include") end) target("src1") set_kind("static") add_rules("include") add_files("src/*.mpp", {public = true}) add_defines("A") target("src2") set_kind("binary") add_deps("src1") add_files("src/*.cpp") ================================================ FILE: tests/projects/c++/modules/inline_and_template/src/foo.mpp ================================================ export module foo; export { template struct foo { constexpr const char* hello(void) const { return "hello typename!"; } }; // template <> // struct foo { // constexpr const char* hello(void) const { // return "hello typename int!"; // } // }; } ================================================ FILE: tests/projects/c++/modules/inline_and_template/src/foo_impl.cpp ================================================ module foo; template <> struct foo { constexpr const char* hello(void) const { return "hello int!"; } }; ================================================ FILE: tests/projects/c++/modules/inline_and_template/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { inline void say_hello() { std::printf("hello world!\n"); } } ================================================ FILE: tests/projects/c++/modules/inline_and_template/src/main.cpp ================================================ #include import hello; import say; import foo; int main() { hello::say_hello(); say{}.hello(); std::cout << foo{}.hello() << std::endl; return 0; } ================================================ FILE: tests/projects/c++/modules/inline_and_template/src/say.mpp ================================================ module; #include export module say; export class say { public: template void hello() { std::printf("hello, say class: %d\n", N); } }; ================================================ FILE: tests/projects/c++/modules/inline_and_template/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/inline_and_template/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("inline_and_template") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/install_with_false_default/src/foo.mpp ================================================ export module foo; export namespace foo { void foo() {} } ================================================ FILE: tests/projects/c++/modules/install_with_false_default/src/main.cpp ================================================ import foo; int main() { foo::foo(); return 0; } ================================================ FILE: tests/projects/c++/modules/install_with_false_default/test.lua ================================================ inherit(".test_base") import("utils.ci.is_running", {alias = "ci_is_running"}) CLANG_MIN_VER = is_subhost("windows") and "19" or "17" GCC_MIN_VER = "11" MSVC_MIN_VER = "14.29" function _build(check_outdata) local flags = "" if ci_is_running() then flags = "-vD" end os.run("xmake -r " .. flags) os.run("xmake b -r " .. flags .. " module_test1") os.run("xmake install " .. flags .. " --installdir=out") end function main(_) local clang_options = {compiler = "clang", version = CLANG_MIN_VER, build = _build} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER, build = _build} local msvc_options = {version = MSVC_MIN_VER, build = _build} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/install_with_false_default/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("module_test") set_kind("moduleonly") add_files("src/*.mpp") target("module_test1") set_kind("binary") set_default(false) add_deps("module_test") add_files("src/*.cpp") ================================================ FILE: tests/projects/c++/modules/internal_partition/src/hello.mpp ================================================ export module hello; import :part_internal; export namespace hello { void say(const char* str) { say_internal(str); } } ================================================ FILE: tests/projects/c++/modules/internal_partition/src/hello_internal.mpp ================================================ module; #include module hello:part_internal; namespace hello { void say_internal(const char *str) { printf("%s\n", str); } } ================================================ FILE: tests/projects/c++/modules/internal_partition/src/main.cpp ================================================ import hello; int main() { hello::say("hello module!"); return 0; } ================================================ FILE: tests/projects/c++/modules/internal_partition/test.lua ================================================ inherit(".test_partitions") ================================================ FILE: tests/projects/c++/modules/internal_partition/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("internal_partition") set_kind("binary") add_files("src/*.cpp", "src/hello.mpp") add_files("src/hello_internal.mpp") ================================================ FILE: tests/projects/c++/modules/moduleonly/src/mod.mpp ================================================ export module hello; export int foo() { return 0; } ================================================ FILE: tests/projects/c++/modules/moduleonly/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/moduleonly/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("mod") set_kind("moduleonly") add_files("src/mod.mpp") ================================================ FILE: tests/projects/c++/modules/moduleonly_private_dep/src/main.cpp ================================================ import B; int main() { return func(); } ================================================ FILE: tests/projects/c++/modules/moduleonly_private_dep/src/modA.mpp ================================================ export module A; export inline constexpr auto foo = 1; ================================================ FILE: tests/projects/c++/modules/moduleonly_private_dep/src/modB.cpp ================================================ module B; import A; int func() { return foo; } ================================================ FILE: tests/projects/c++/modules/moduleonly_private_dep/src/modB.mpp ================================================ export module B; export int func(); ================================================ FILE: tests/projects/c++/modules/moduleonly_private_dep/xmake.lua ================================================ set_languages("c++20") target("A") set_kind("moduleonly") add_files("src/modA.mpp") target("B") add_deps("A") set_kind("static") add_files("src/modB.mpp", { public = true }) add_files("src/modB.cpp") target("test") set_kind("binary") add_deps("B") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/modules/multiple_runtimes/src/main.cpp ================================================ import std; int main() { std::println("Hello world"); return 0; } ================================================ FILE: tests/projects/c++/modules/multiple_runtimes/test.lua ================================================ import("lib.detect.find_tool") import("core.base.semver") import("core.tool.toolchain") import("utils.ci.is_running", {alias = "ci_is_running"}) CLANG_MIN_VER = "19" GCC_MIN_VER = "15" MSVC_MIN_VER = "14.35" function _check_tool_version(name, min_ver) local tool = find_tool(name, {version = true}) if not (tool and tool.version and semver.compare(tool.version, min_ver) >= 0) then return false end return true end function _check_msvc_version(min_ver) local msvc = toolchain.load("msvc") if not msvc or not msvc:check() then return false end local vcvars = msvc:config("vcvars") if not vcvars or not vcvars.VCInstallDir or not vcvars.VCToolsVersion then return false end local version = vcvars.VCToolsVersion if not version or not (semver.compare(version, min_ver) >= 0) then return false end return true end function main(_) if is_subhost("windows") then if not _check_msvc_version(MSVC_MIN_VER) then return end -- on windows, llvm libc++ std module is currently not supported, uncommend when supported -- if not check_tool_version("clang", CLANG_MIN_VER) then -- return -- end elseif is_host("linux") then if not _check_tool_version("gcc", GCC_MIN_VER) or not _check_tool_version("clang", CLANG_MIN_VER) then return end else return end local cl_str = "modules\\std.ixx" local clang_str = is_host("windows") and "v1\\std.cppm" or "v1/std.cppm" local gcc_str = "v1/std.cppm" local flags = true and "-vD" or "" local outdata outdata = os.iorun("xmake b " .. flags) if outdata then local success = false -- on windows, llvm libc++ std module is currently not supported, uncommend when supported if is_subhost("windows") then success = outdata:find(cl_str, 1, true) -- and outdata:find(clang_str, 1, true) else success = outdata:find(gcc_str, 1, true) and outdata:find(clang_str, 1, true) end if not success then raise("Multiple runtimes doesn't work\n%s", outdata) end end end ================================================ FILE: tests/projects/c++/modules/multiple_runtimes/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c++23") set_encodings("utf-8") if is_plat("windows") then -- on windows, llvm libc++ std module is currently not supported, uncommend when supported -- target("llvm") -- set_kind("binary") -- set_toolchains("clang") -- set_runtimes("c++_shared") -- set_policy("build.c++.modules", true) -- add_files("src/main.cpp") target("llvm-msvc") set_kind("binary") set_toolchains("clang") set_policy("build.c++.modules", true) add_files("src/main.cpp") target("msvc") set_kind("binary") set_toolchains("msvc") set_policy("build.c++.modules", true) add_files("src/main.cpp") else target("llvm") set_kind("binary") set_toolchains("clang") set_runtimes("c++_shared") set_policy("build.c++.modules", true) add_files("src/main.cpp") target("gnu") set_kind("binary") set_toolchains("gcc") set_runtimes("stdc++_shared") set_policy("build.c++.modules", true) set_policy("build.c++.modules.gcc.cxx11abi", true) add_files("src/main.cpp") end ================================================ FILE: tests/projects/c++/modules/namespace/src/hello.mpp ================================================ export module hello; export namespace hello { extern int data__; void say_hello(); class say { public: say(int data); void hello(); private: int data_; }; } ================================================ FILE: tests/projects/c++/modules/namespace/src/hello_impl.cpp ================================================ module; #include module hello; import mod; void inner() { std::cout << "hello world! data: " << mod::foo() << std::endl; } namespace hello { int data__; void say_hello() { ::inner(); } say::say(int data) : data_{ data } { } void say::hello() { hello::data__ = data_; ::inner(); } } // namespace hello ================================================ FILE: tests/projects/c++/modules/namespace/src/main.cpp ================================================ import hello; int main() { hello::data__ = 123; hello::say_hello(); hello::say(sizeof(hello::say)).hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/namespace/src/mod.mpp ================================================ export module mod; export namespace mod { int foo(); } ================================================ FILE: tests/projects/c++/modules/namespace/src/mod_impl.cpp ================================================ module mod; import hello; namespace mod { int foo() { return hello::data__; } } // namespace mod ================================================ FILE: tests/projects/c++/modules/namespace/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/namespace/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") namespace("foo", function() target("dep") set_kind("static") add_files("src/hello.mpp", "src/mod.mpp", {public = true}) add_files("src/hello_impl.cpp", "src/mod_impl.cpp") target("binary") set_kind("binary") add_files("src/main.cpp") add_deps("dep") end) ================================================ FILE: tests/projects/c++/modules/namespace2/src/hello.mpp ================================================ export module hello; export namespace hello { extern int data__; void say_hello(); class say { public: say(int data); void hello(); private: int data_; }; } ================================================ FILE: tests/projects/c++/modules/namespace2/src/hello_impl.cpp ================================================ module; #include module hello; import mod; void inner() { std::cout << "hello world! data: " << mod::foo() << std::endl; } namespace hello { int data__; void say_hello() { ::inner(); } say::say(int data) : data_{ data } { } void say::hello() { hello::data__ = data_; ::inner(); } } // namespace hello ================================================ FILE: tests/projects/c++/modules/namespace2/src/main.cpp ================================================ import hello; int main() { hello::data__ = 123; hello::say_hello(); hello::say(sizeof(hello::say)).hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/namespace2/src/mod.mpp ================================================ export module mod; export namespace mod { int foo(); } ================================================ FILE: tests/projects/c++/modules/namespace2/src/mod_impl.cpp ================================================ module mod; import hello; namespace mod { int foo() { return hello::data__; } } // namespace mod ================================================ FILE: tests/projects/c++/modules/namespace2/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/namespace2/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") namespace("bar", function() target("dep") set_kind("static") add_files("src/hello.mpp", "src/mod.mpp", {public = true}) add_files("src/hello_impl.cpp", "src/mod_impl.cpp") end) namespace("foo", function() target("binary") set_kind("binary") add_files("src/main.cpp") add_deps("bar::dep") end) ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.cpp ================================================ #include const char *hello() { return "Hello world"; } ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.mpp ================================================ module; #include export module bar; export namespace bar { const char *hello() { return ::hello(); } } ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/include/a.hpp ================================================ #ifndef A_HPP #define A_HPP [[gnu::visibility("default")]] const char *hello(); #endif ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("bar") set_kind("static") add_headerfiles("include/(**.hpp)") add_includedirs("include") add_files("*.cpp") add_files("*.mpp", { public = true }) ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/b/bar/xmake.lua ================================================ package("bar") set_sourcedir(path.join(os.scriptdir(), "src")) on_install(function(package) import("package.tools.xmake").install(package, {}) end) ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/bar.mpp ================================================ export module bar2; export namespace bar { const char *hello2() { return "Hello world"; } } ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("bar2") set_kind("moduleonly") add_files("*.mpp") ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/b/bar2/xmake.lua ================================================ package("bar2") set_kind("library", {moduleonly = true}) set_sourcedir(path.join(os.scriptdir(), "src")) on_install(function(package) import("package.tools.xmake").install(package, {}) end) ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.cpp ================================================ module foo; namespace foo { void say(const char *msg) { } } // namespace foo ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.mpp ================================================ export module foo; export namespace foo { #ifdef FOO_EXPORT void say(const char *); #endif } ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("foo") set_kind("static") add_files("*.cpp") add_files("*.mpp", {defines = "FOO_EXPORT", public = true}) ================================================ FILE: tests/projects/c++/modules/packages/my-repo/packages/f/foo/xmake.lua ================================================ package("foo") set_sourcedir(path.join(os.scriptdir(), "src")) on_install(function(package) import("package.tools.xmake").install(package, {}) end) ================================================ FILE: tests/projects/c++/modules/packages/src/main.cpp ================================================ import foo; import bar; import bar2; int main() { foo::say(bar::hello()); foo::say(bar::hello2()); return 0; } ================================================ FILE: tests/projects/c++/modules/packages/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/packages/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") add_repositories("my-repo my-repo") add_requires("foo", "bar", "bar2") target("packages") set_kind("binary") add_files("src/*.cpp") add_packages("foo", "bar", "bar2") set_policy("build.c++.modules", true) ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/src/bar.cpp ================================================ #include const char *hello() { return "Hello world"; } ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/src/bar.mpp ================================================ module; #include export module bar; export namespace bar { const char *hello() { return ::hello(); } } ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/src/include/a.hpp ================================================ #ifndef A_HPP #define A_HPP [[gnu::visibility("default")]] const char *hello(); #endif ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/src/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("bar") set_kind("static") add_headerfiles("include/(**.hpp)") add_includedirs("include") add_files("*.cpp") add_files("*.mpp", { public = true }) ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/xmake.lua ================================================ package("bar") set_sourcedir(path.join(os.scriptdir(), "src")) on_install(function(package) import("package.tools.xmake").install(package, {}) end) ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar2/src/bar.mpp ================================================ export module bar2; export namespace bar { const char *hello2() { return "Hello world"; } } ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar2/src/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("bar2") set_kind("moduleonly") add_files("*.mpp") ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar2/xmake.lua ================================================ package("bar2") set_kind("library", {moduleonly = true}) set_sourcedir(path.join(os.scriptdir(), "src")) on_install(function(package) import("package.tools.xmake").install(package, {}) end) ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/f/foo/src/foo.cpp ================================================ module foo; namespace foo { void say(const char *msg) { } } // namespace foo ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/f/foo/src/foo.mpp ================================================ export module foo; export namespace foo { #ifdef FOO_EXPORT void say(const char *); #endif } ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/f/foo/src/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("foo") set_kind("static") add_files("*.cpp") add_files("*.mpp", {defines = "FOO_EXPORT", public = true}) ================================================ FILE: tests/projects/c++/modules/packages-subtarget/my-repo/packages/f/foo/xmake.lua ================================================ package("foo") set_sourcedir(path.join(os.scriptdir(), "src")) on_install(function(package) import("package.tools.xmake").install(package, {}) end) ================================================ FILE: tests/projects/c++/modules/packages-subtarget/src/main.cpp ================================================ import foobar; import bar2; int main() { foo::say(bar::hello()); foo::say(bar::hello2()); return 0; } ================================================ FILE: tests/projects/c++/modules/packages-subtarget/src/mod.mpp ================================================ export module foobar; export import foo; export import bar; ================================================ FILE: tests/projects/c++/modules/packages-subtarget/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/packages-subtarget/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") add_repositories("my-repo my-repo") add_requires("foo", "bar", "bar2") target("dep") set_kind("static") add_packages("foo", "bar") add_files("src/*.mpp", {public = true}) target("packages") set_kind("binary") add_files("src/*.cpp") add_deps("dep") add_packages("foo", "bar", "bar2") set_policy("build.c++.modules", true) ================================================ FILE: tests/projects/c++/modules/partitions/src/main.cpp ================================================ #include import math; int main() { std::cout << std::endl; std::cout << "add(3, 4): " << add(3, 4) << std::endl; std::cout << "mul(3, 4): " << mul(3, 4) << std::endl; } ================================================ FILE: tests/projects/c++/modules/partitions/src/math.math1.mpp ================================================ export module math:math1; export int add(int fir, int sec) { return fir + sec; } ================================================ FILE: tests/projects/c++/modules/partitions/src/math.math2.mpp ================================================ export module math:math2; export { int mul(int fir, int sec) { return fir * sec; } } ================================================ FILE: tests/projects/c++/modules/partitions/src/math.mpp ================================================ export module math; export import :math1; export import :math2; ================================================ FILE: tests/projects/c++/modules/partitions/test.lua ================================================ inherit(".test_partitions") ================================================ FILE: tests/projects/c++/modules/partitions/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("partition") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/partitions_implunit/src/foo.cpp ================================================ // Foo.cpp module Foo; // Impl is implictly imported here void foo() { bar(); } ================================================ FILE: tests/projects/c++/modules/partitions_implunit/src/foo.mpp ================================================ // Foo.mpp export module Foo; import :Impl; // can't export import Impl because Impl is a implementation partition unit export void foo(); ================================================ FILE: tests/projects/c++/modules/partitions_implunit/src/foo_impl.mpp ================================================ module; #include // Foo-Impl.mpp // can only be imported by module Foo, and visibility of bar is only public to module Foo module Foo:Impl; void bar() { std::cout << "Hello world" << std::endl; } ================================================ FILE: tests/projects/c++/modules/partitions_implunit/src/main.cpp ================================================ import Foo; int main(int argc, char **argv) { foo(); return 0; } ================================================ FILE: tests/projects/c++/modules/partitions_implunit/test.lua ================================================ inherit(".test_partitions") ================================================ FILE: tests/projects/c++/modules/partitions_implunit/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("test") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/partitions_implunit2/src/foo.mpp ================================================ // Foo.mpp export module Foo; import :Impl; // can't export import Impl because Impl is a implementation partition unit export void foo() { bar(); } ================================================ FILE: tests/projects/c++/modules/partitions_implunit2/src/foo_impl.mpp ================================================ module; #include // Foo-Impl.mpp // can only be imported by module Foo, and visibility of bar is only public to module Foo module Foo:Impl; void bar() { std::cout << "Hello world" << std::endl; } ================================================ FILE: tests/projects/c++/modules/partitions_implunit2/src/main.cpp ================================================ import Foo; int main(int argc, char **argv) { foo(); return 0; } ================================================ FILE: tests/projects/c++/modules/partitions_implunit2/test.lua ================================================ inherit(".test_partitions") ================================================ FILE: tests/projects/c++/modules/partitions_implunit2/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("test") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/phony/src/hello.cpp ================================================ module; #include module hello; using namespace std; namespace hello { say::say(int data) : data_(data) { } void say::hello() { cout << "hello, say class: " << data_ << endl; } } // namespace hello ================================================ FILE: tests/projects/c++/modules/phony/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { class say { public: say(int data); void hello(); private: int data_; }; } // namespace hello ================================================ FILE: tests/projects/c++/modules/phony/src/main.cpp ================================================ import hello; int main() { hello::say s(sizeof(hello::say)); s.hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/phony/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/phony/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("test-phony") set_kind("phony") add_files("src/*.mpp", {public = true}) target("class") set_kind("binary") add_files("src/*.cpp") add_deps("test-phony") ================================================ FILE: tests/projects/c++/modules/phony2/include/foo.h ================================================ inline int foo() { return 5; } ================================================ FILE: tests/projects/c++/modules/phony2/src/hello.cpp ================================================ module; #include module hello; using namespace std; namespace hello { say::say(int data) : data_(data) { } void say::hello() { cout << "hello, say class: " << data_ << endl; } } // namespace hello ================================================ FILE: tests/projects/c++/modules/phony2/src/hello.mpp ================================================ module; #include export module hello; export namespace hello { class say { public: say(int data); void hello(); private: int data_; }; } // namespace hello ================================================ FILE: tests/projects/c++/modules/phony2/src/main.cpp ================================================ import hello; int main() { hello::say s(sizeof(hello::say)); s.hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/phony2/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/phony2/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("test") set_kind("static") add_includedirs("include") add_files("src/*.mpp", {public = true}) target("test-phony") set_kind("phony") add_deps("test") target("class") set_kind("binary") add_files("src/*.cpp") add_deps("test-phony") ================================================ FILE: tests/projects/c++/modules/private_module/src/dep1.mpp ================================================ export module dep1; export int m() { return 0; } ================================================ FILE: tests/projects/c++/modules/private_module/src/dep2.mpp ================================================ export module dep2; import dep1; export int i() { return m(); } ================================================ FILE: tests/projects/c++/modules/private_module/src/use.cpp ================================================ module use; import dep1; import dep2; int lib() { return m() + i(); } ================================================ FILE: tests/projects/c++/modules/private_module/src/use.mpp ================================================ export module use; export int lib(); ================================================ FILE: tests/projects/c++/modules/private_module/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/private_module/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("private_module") add_rules("c++") set_kind("$(kind)") add_files("src/*.mpp") add_files("src/*.cpp") ================================================ FILE: tests/projects/c++/modules/staticlib/src/main.cpp ================================================ #include import mod; int main() { printf("%d\n", mod::foo()); return 0; } ================================================ FILE: tests/projects/c++/modules/staticlib/src/mod.cpp ================================================ module mod; namespace mod { int foo() { return 2; } } // namespace mod ================================================ FILE: tests/projects/c++/modules/staticlib/src/mod.mpp ================================================ export module mod; export namespace mod { int foo(); } ================================================ FILE: tests/projects/c++/modules/staticlib/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/staticlib/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("mod") set_kind("static") add_files("src/mod.mpp", {public = true}) add_files("src/mod.cpp") target("hello") set_kind("binary") add_deps("mod") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/modules/staticlib2/src/bar.cpp ================================================ module bar; namespace bar { int hello() { return 2; } } // namespace bar ================================================ FILE: tests/projects/c++/modules/staticlib2/src/bar.mpp ================================================ export module bar; export namespace bar { int hello(); } ================================================ FILE: tests/projects/c++/modules/staticlib2/src/foo.cpp ================================================ module foo; import bar; namespace foo { int hello() { return bar::hello(); } } // namespace foo ================================================ FILE: tests/projects/c++/modules/staticlib2/src/foo.mpp ================================================ export module foo; export namespace foo { int hello(); } ================================================ FILE: tests/projects/c++/modules/staticlib2/src/main.cpp ================================================ #include import foo; int main() { printf("%d\n", foo::hello()); return 0; } ================================================ FILE: tests/projects/c++/modules/staticlib2/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/staticlib2/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("bar") set_kind("static") add_files("src/bar.mpp", {public = true}) add_files("src/bar.cpp") target("foo") set_kind("static") add_deps("bar") add_files("src/foo.mpp", {public = true}) add_files("src/foo.cpp") target("hello") set_kind("binary") add_deps("foo") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/modules/stdmodules/src/my_module.cpp ================================================ module my_module; import std; auto my_sum(std::size_t a, std::size_t b) -> std::size_t { return a + b; } ================================================ FILE: tests/projects/c++/modules/stdmodules/src/my_module.mpp ================================================ export module my_module; import std; export auto my_sum(std::size_t a, std::size_t b) -> std::size_t; ================================================ FILE: tests/projects/c++/modules/stdmodules/test/test.cpp ================================================ import std; import my_module; using namespace std; int main(int argc, char **argv) { cout << my_sum(1, 1) << endl; } ================================================ FILE: tests/projects/c++/modules/stdmodules/test.lua ================================================ inherit(".test_stdmodules") ================================================ FILE: tests/projects/c++/modules/stdmodules/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c++latest") target("mod") set_kind("static") add_files("src/*.cpp") add_files("src/*.mpp", {public = true}) target("stdmodules") set_kind("binary") add_files("test/*.cpp") add_deps("mod") ================================================ FILE: tests/projects/c++/modules/stdmodules_cpp_only/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/c++/modules/stdmodules_cpp_only/src/main.cpp ================================================ import std; using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/c++/modules/stdmodules_cpp_only/test.lua ================================================ inherit(".test_stdmodules") ================================================ FILE: tests/projects/c++/modules/stdmodules_cpp_only/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c++latest") target("stdmodules_cpp_only") set_kind("binary") add_files("src/*.cpp") set_policy("build.c++.modules", true) ================================================ FILE: tests/projects/c++/modules/stdmodules_deps/src/bar.mpp ================================================ export module bar; import std; export auto my_sum2(std::size_t a, std::size_t b) -> std::size_t; #if defined(__GNUC__) && !defined(__clang__) inline #else module :private; #endif auto my_sum2(std::size_t a, std::size_t b) -> std::size_t { return a + a + b + b; } ================================================ FILE: tests/projects/c++/modules/stdmodules_deps/src/foo.cpp ================================================ module foo; auto my_sum(std::size_t a, std::size_t b) -> std::size_t { return a + b; } ================================================ FILE: tests/projects/c++/modules/stdmodules_deps/src/foo.mpp ================================================ export module foo; import std; export auto my_sum(std::size_t a, std::size_t b) -> std::size_t; ================================================ FILE: tests/projects/c++/modules/stdmodules_deps/src/main.cpp ================================================ import foo; import bar; import std; int main() { std::cout << my_sum(1, 2) << ":" << my_sum2(1, 2) << std::endl; return 0; } ================================================ FILE: tests/projects/c++/modules/stdmodules_deps/test.lua ================================================ inherit(".test_stdmodules") ================================================ FILE: tests/projects/c++/modules/stdmodules_deps/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c++latest") target("foo") set_kind("static") add_files("src/foo.cpp") add_files("src/foo.mpp", {public = true}) target("bar") set_kind("moduleonly") add_files("src/bar.mpp") target("main") set_kind("binary") add_deps("foo", "bar") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/modules/stdmodules_multiple_targets/src/my_module.cpp ================================================ module my_module; import std; auto my_sum(std::size_t a, std::size_t b) -> std::size_t { return a + b; } ================================================ FILE: tests/projects/c++/modules/stdmodules_multiple_targets/src/my_module.mpp ================================================ export module my_module; import std; export auto my_sum(std::size_t a, std::size_t b) -> std::size_t; ================================================ FILE: tests/projects/c++/modules/stdmodules_multiple_targets/test.lua ================================================ inherit(".test_stdmodules") ================================================ FILE: tests/projects/c++/modules/stdmodules_multiple_targets/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c++latest") target("mod") set_kind("static") add_files("src/*.cpp", "src/*.mpp") target("mod2") set_kind("static") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/stl_headerunit/src/hello.mpp ================================================ module; export module hello; import ; export namespace hello { void say(const char* str) { std::cout << str << std::endl; } } ================================================ FILE: tests/projects/c++/modules/stl_headerunit/src/main.cpp ================================================ import hello; int main() { hello::say("hello module!"); return 0; } ================================================ FILE: tests/projects/c++/modules/stl_headerunit/test.lua ================================================ inherit(".test_headerunits") ================================================ FILE: tests/projects/c++/modules/stl_headerunit/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("stl_headerunit") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/stl_headerunit_cpp_only/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/c++/modules/stl_headerunit_cpp_only/src/main.cpp ================================================ import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/c++/modules/stl_headerunit_cpp_only/test.lua ================================================ inherit(".test_headerunits") ================================================ FILE: tests/projects/c++/modules/stl_headerunit_cpp_only/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("stl_headerunit_cpp_only") set_kind("binary") add_files("src/*.cpp") set_policy("build.c++.modules", true) ================================================ FILE: tests/projects/c++/modules/submodules/src/main.cpp ================================================ #include import math; int main() { std::cout << std::endl; std::cout << "add(3, 4): " << add(3, 4) << std::endl; std::cout << "mul(3, 4): " << mul(3, 4) << std::endl; } ================================================ FILE: tests/projects/c++/modules/submodules/src/math.math1.mpp ================================================ export module math.math1; export int add(int fir, int sec) { return fir + sec; } ================================================ FILE: tests/projects/c++/modules/submodules/src/math.math2.mpp ================================================ export module math.math2; export { int mul(int fir, int sec) { return fir * sec; } } ================================================ FILE: tests/projects/c++/modules/submodules/src/math.mpp ================================================ export module math; export import math.math1; export import math.math2; ================================================ FILE: tests/projects/c++/modules/submodules/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/submodules/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("submodule") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/submodules2/src/main.cpp ================================================ import main_module; int main(int argc, char **argv) { hello(); return 0; } ================================================ FILE: tests/projects/c++/modules/submodules2/src/main_module.mpp ================================================ export module main_module; import main_module.module1; import main_module.module2; export void hello() { hello1(); hello2(); } ================================================ FILE: tests/projects/c++/modules/submodules2/src/module1.cpp ================================================ module; #include module main_module.module1; void hello1(void) { printf("hello1\n"); } ================================================ FILE: tests/projects/c++/modules/submodules2/src/module1.mpp ================================================ export module main_module.module1; export void hello1(void); ================================================ FILE: tests/projects/c++/modules/submodules2/src/module2.cpp ================================================ module; #include module main_module.module2; void hello2(void) { printf("hello2\n"); } ================================================ FILE: tests/projects/c++/modules/submodules2/src/module2.mpp ================================================ export module main_module.module2; export void hello2(void); ================================================ FILE: tests/projects/c++/modules/submodules2/test.lua ================================================ inherit(".test_base") ================================================ FILE: tests/projects/c++/modules/submodules2/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("submodules2") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/test_base.lua ================================================ import("lib.detect.find_tool") import("core.base.semver") import("core.tool.toolchain") import("utils.ci.is_running", {alias = "ci_is_running"}) CLANG_MIN_VER = is_subhost("windows") and "19" or "17" CLANG_CL_MIN_VER = "19" GCC_MIN_VER = "11" MSVC_MIN_VER = "14.29" function _build(check_outdata) local flags = "" if ci_is_running() then flags = "-vD" end if check_outdata then local outdata outdata = os.iorun("xmake -r " .. flags) if outdata then if outdata:find(check_outdata.str, 1, true) then raise(check_outdata.format_string .. "\n%s", outdata) end end else os.run("xmake -r " .. flags) end local outdata = os.iorun("xmake " .. flags) if outdata then if outdata:find("compiling", 1, true) or outdata:find("linking", 1, true) or outdata:find("generating", 1, true) then raise("Modules incremental compilation does not work\n%s", outdata) end end end function can_build() if is_subhost("windows") then return true elseif is_subhost("msys") then return true elseif is_host("linux") then local gcc = find_tool("gcc", {version = true}) if gcc and gcc.version and semver.compare(gcc.version, GCC_MIN_VER) >= 0 then return true end local clang = find_tool("clang", {version = true}) if clang and clang.version and semver.compare(clang.version, CLANG_MIN_VER) >= 0 then return true end end end function build_tests(toolchain_name, opt) assert(opt and opt.version) local version if is_subhost("windows") then local msvc = toolchain.load("msvc") if not msvc or not msvc:check() then wprint("msvc not found, skipping tests") return end local vcvars = msvc:config("vcvars") if not vcvars or not vcvars.VCInstallDir or not vcvars.VCToolsVersion then wprint("msvc not found, skipping tests") return end version = vcvars.VCToolsVersion end if opt.compiler then local cc = find_tool(opt.compiler, {version = true}) if not cc then wprint(opt.compiler .. " not found, skipping tests") return end version = cc.version end local compiler = toolchain_name == "msvc" and "cl" or opt.compiler if not version or not (semver.compare(version, opt.version) >= 0) then local version_str = compiler .. " >= " .. opt.version .. (version and " (found " .. version .. ")" or "") .. " " wprint(version_str .. "not found, skipping tests") return end local two_phases = (opt.two_phases == nil or opt.two_phases == true) local policies = "--policies=build.c++.modules.std:" .. (opt.stdmodule and "y" or "n") policies = policies .. ",build.c++.modules.fallbackscanner:" .. (opt.fallbackscanner and "y" or "n") policies = policies .. ",build.c++.modules.two_phases:" .. (two_phases and "y" or "n") local platform = " " if opt.platform then platform = " -p " .. opt.platform .. " " end local runtimes = " " if opt.runtimes then runtimes = " --runtimes=" .. opt.runtimes .. " " end print("running with config: (toolchain: %s, compiler: %s, version: %s, runtimes: %s, stdmodule: %s, fallback scanner: %s, two phases: %s)", toolchain_name, compiler, version, opt.runtimes or "default", opt.stdmodule or false, opt.fallbackscanner or false, two_phases) local flags = "" if opt.flags then flags = " " .. table.concat(opt.flags, " ") end if ci_is_running() then flags = flags .. " -vD" end os.exec("xmake clean -a") os.exec("xmake f" .. platform .. "--toolchain=" .. toolchain_name .. runtimes .. "-c --yes " .. policies .. flags) if opt.build then opt.build() else _build(opt.check_outdata) end if opt.after_build then opt.after_build(platform, toolchain_name, runtimes, policies, flags) end end function run_tests(clang_options, gcc_options, msvc_options) local clang_libcpp_options if clang_options then clang_libcpp_options = table.clone(clang_options) clang_libcpp_options.runtimes = "c++_shared" end if is_subhost("windows") then if clang_options then build_tests("llvm", clang_options) build_tests("clang", clang_options) build_tests("clang", table.join(clang_options, {two_phases = false})) if not clang_options.disable_clang_cl then local clang_cl_options = table.clone(clang_options) clang_cl_options.compiler = "clang-cl" clang_cl_options.version = CLANG_CL_MIN_VER build_tests("clang-cl", clang_cl_options) build_tests("clang-cl", table.join(clang_options, {two_phases = false})) end if clang_options.stdmodule then wprint("std modules tests skipped for Windows clang libc++ as it's not currently supported officially") else build_tests("llvm", clang_libcpp_options) build_tests("clang", clang_libcpp_options) build_tests("clang", table.join(clang_libcpp_options, {two_phases = false})) end end if msvc_options then build_tests("msvc", msvc_options) build_tests("msvc", table.join(msvc_options, {two_phases = false})) end elseif is_subhost("macosx") then if clang_options then -- macOS doesn't ship clang-scan-deps currently if is_subhost("macosx") then -- check if normal clang is avalaible local regular_clang_available = false local outdata = os.iorun("clang --version") if outdata then regular_clang_available = true if outdata:find("Apple") then regular_clang_available = false end end if not regular_clang_available then wprint("Appleclang isn't shipped with clang-scan-deps, disabling modules tests") return end end build_tests("llvm", clang_options) build_tests("clang", clang_options) build_tests("clang", table.join(clang_options, {two_phases = false})) end elseif is_subhost("msys") then if clang_options then clang_options.platform = "mingw" clang_libcpp_options.platform = "mingw" build_tests("llvm", clang_options) build_tests("clang", clang_options) build_tests("clang", table.join(clang_options, {two_phases = false})) build_tests("llvm", clang_libcpp_options) build_tests("clang", clang_libcpp_options) build_tests("clang", table.join(clang_libcpp_options, {two_phases = false})) end if gcc_options then gcc_options.platform = "mingw" build_tests("gcc", gcc_options) build_tests("gcc", table.join(gcc_options, {two_phases = false})) end elseif is_host("linux") then if clang_options then build_tests("llvm", clang_options) build_tests("clang", clang_options) build_tests("clang", table.join(clang_options, {two_phases = false})) build_tests("llvm", clang_libcpp_options) build_tests("clang", clang_libcpp_options) build_tests("clang", table.join(clang_libcpp_options, {two_phases = false})) end if gcc_options then build_tests("gcc", gcc_options) build_tests("gcc", table.join(gcc_options, {two_phases = false})) end end end function main(_) local clang_options = {compiler = "clang", version = CLANG_MIN_VER} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER} local msvc_options = {version = MSVC_MIN_VER} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/test_cmake.lua ================================================ import("lib.detect.find_tool") import("core.base.semver") import("core.tool.toolchain") import("utils.ci.is_running", {alias = "ci_is_running"}) function _gen_cmakelist() if not os.isfile("CMakeLists.txt") then os.vrunv("xmake project -k cmake") end end function _build(name, opt) opt = opt or {} local build_args = {} if ci_is_running() then table.insert(build_args, "-vD") end os.rm(".xmake", "build") os.mv("xmake.lua", "xmake.lua_") os.vrunv("xmake", table.join({"f", "--trybuild=cmake", "--toolchain=" .. name}, build_args), {shell = true, envs = opt.envs}) os.vrunv("xmake", table.join({"b"}, build_args), {shell = true, envs = opt.envs}) os.mv("xmake.lua_", "xmake.lua") end function _build_with(name, minver) if name == "msvc" then local _toolchain = toolchain.load(name, {plat = os.host(), arch = os.arch()}) if _toolchain and _toolchain:check() then local vcvars = _toolchain:config("vcvars") if vcvars and vcvars.VCToolsVersion and semver.compare(vcvars.VCToolsVersion, minver) >= 0 then _build(name, {envs = vcvars}) end end else local tool = find_tool(name, {version = true}) if tool and tool.version and semver.compare(tool.version, minver) >= 0 then local _toolchain = toolchain.load(name, {plat = os.host(), arch = os.arch()}) if _toolchain and _toolchain:check() then _build(name) end end end end function main(t) os.setenv("CMAKE_GENERATOR", "Ninja") local cmake = find_tool("cmake", {version = true}) local ninja = find_tool("ninja") if ninja and cmake and cmake.version and semver.compare(cmake.version, "3.28") >= 0 then _gen_cmakelist() if is_subhost("windows") then _build_with("clang", "19") _build_with("msvc", "14.35") elseif is_subhost("linux") then _build_with("gcc", "14") _build_with("clang", "19") elseif is_subhost("macosx") then -- macOS doesn't ship clang-scan-deps currently -- check if normal clang is avalaible local regular_clang_available = false local outdata = os.iorun("clang --version") if outdata then regular_clang_available = true if outdata:find("Apple") then regular_clang_available = false end end if not regular_clang_available then wprint("Appleclang isn't shipped with clang-scan-deps, disabling modules tests") return end _build_with("clang", "19") end end end ================================================ FILE: tests/projects/c++/modules/test_culling.lua ================================================ inherit("test_base") CLANG_MIN_VER = is_subhost("windows") and "19" or "17" GCC_MIN_VER = "11" MSVC_MIN_VER = "14.29" function main(_) local check_outdata = {str = "culled", format_string = "Modules culling does not work"} local clang_options = {compiler = "clang", version = CLANG_MIN_VER, check_outdata = check_outdata} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER, check_outdata = check_outdata} local msvc_options = {version = MSVC_MIN_VER, check_outdata = check_outdata} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/test_dependency_scanner.lua ================================================ inherit("test_base") import("utils.ci.is_running", {alias = "ci_is_running"}) CLANG_MIN_VER = is_subhost("windows") and "19" or "17" GCC_MIN_VER = "11" MSVC_MIN_VER = "14.29" function _build(platform, toolchain_name, runtimes, policies, flags) local flags = "" if ci_is_running() then flags = "-vD" end os.exec("xmake f" .. platform .. "--toolchain=" .. toolchain_name .. runtimes .. "-c --yes " .. policies .. " --foo=n" .. " " .. flags) local outdata outdata = os.iorun("xmake -r " .. flags) if outdata then if outdata:find("FOO") then raise("Modules dependency scanner update does not work\n%s", outdata) end end end function main(t) local clang_options = {compiler = "clang", version = CLANG_MIN_VER, flags = {"--foo=y"}, after_build = _build} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER, flags = {"--foo=y"}, after_build = _build} local msvc_options = {version = MSVC_MIN_VER, flags = {"--foo=y"}, after_build = _build} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/test_duplicate_modules.lua ================================================ inherit("test_base") import("utils.ci.is_running", {alias = "ci_is_running"}) CLANG_MIN_VER = is_subhost("windows") and "19" or "17" GCC_MIN_VER = "11" MSVC_MIN_VER = "14.29" function _build() local flags = "" if ci_is_running() then flags = "-vD" end try { function () os.run("xmake -r " .. flags) end, catch { function (errors) errors = tostring(errors) if not errors:find("duplicate module name detected", 1, true) then raise("Modules duplicate name detection does not work\n%s", errors) end end } } end function main(_) local clang_options = {compiler = "clang", version = CLANG_MIN_VER, build = _build} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER, build = _build} local msvc_options = {version = MSVC_MIN_VER, build = _build} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/test_headerunits.lua ================================================ inherit("test_base") GCC_MIN_VER = "11" MSVC_MIN_VER = "14.30" function main(t) local gcc_options = {fallbackscanner = true, compiler = "gcc", version = GCC_MIN_VER} -- gcc/arm64: internal compiler error: in core_vals, at cp/module.cc:6108 -- on windows, mingw modulemapper doesn't handle headeunit path correctly, but it's working with mingw on macOS / Linux if os.arch() == "arm64" or is_subhost("msys") then gcc_options = nil end local msvc_options = {version = MSVC_MIN_VER} -- skip clang tests, headerunits with clang is not stable run_tests(nil, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/test_partitions.lua ================================================ inherit("test_base") CLANG_MIN_VER = is_subhost("windows") and "19" or "18" GCC_MIN_VER = "13" MSVC_MIN_VER = "14.30" function main(_) local clang_options = {compiler = "clang", version = CLANG_MIN_VER} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER} local msvc_options = {version = MSVC_MIN_VER} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/test_stdmodules.lua ================================================ inherit("test_base") CLANG_MIN_VER = "19" GCC_MIN_VER = "15" MSVC_MIN_VER = "14.35" function main(_) local clang_options = {stdmodule = true, compiler = "clang", version = CLANG_MIN_VER} local gcc_options = {stdmodule = true, compiler = "gcc", version = GCC_MIN_VER} -- latest mingw gcc 15.1 is broken -- error: F:/msys64/mingw64/include/c++/15.1.0/shared_mutex:105:3: error: 'int std::__glibcxx_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' exposes TU-local entity 'int pthread_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' -- 105 | __glibcxx_rwlock_timedrdlock (pthread_rwlock_t *__rwlock, -- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- In file included from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/gthr-default.h:35, -- from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/gthr.h:157, -- from F:/msys64/mingw64/include/c++/15.1.0/ext/atomicity.h:37, -- from F:/msys64/mingw64/include/c++/15.1.0/bits/ios_base.h:41, -- from F:/msys64/mingw64/include/c++/15.1.0/streambuf:45, -- from F:/msys64/mingw64/include/c++/15.1.0/bits/streambuf_iterator.h:37, -- from F:/msys64/mingw64/include/c++/15.1.0/iterator:68, -- from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/stdc++.h:56: -- F:/msys64/mingw64/include/pthread.h:296:28: note: 'int pthread_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' declared with internal linkage -- 296 | WINPTHREAD_RWLOCK_DECL int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts) -- | ^~~~~~~~~~~~~~~~~~~~~~~~~~ -- F:/msys64/mingw64/include/c++/15.1.0/shared_mutex:115:3: error: 'int std::__glibcxx_rwlock_timedwrlock(pthread_rwlock_t*, const timespec*)' exposes TU-local entity 'int pthread_rwlock_timedwrlock(pthread_rwlock_t*, const timespec*)' -- 115 | __glibcxx_rwlock_timedwrlock (pthread_rwlock_t *__rwlock, local gcc_options = {stdmodule = true, compiler = "gcc", version = GCC_MIN_VER} if is_subhost("msys") then gcc_options = nil end local msvc_options = {stdmodule = true, version = MSVC_MIN_VER} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/test_xmake_test.lua ================================================ inherit("test_base") import("utils.ci.is_running", {alias = "ci_is_running"}) CLANG_MIN_VER = is_subhost("windows") and "19" or "17" GCC_MIN_VER = "11" MSVC_MIN_VER = "14.29" function run_xmake_test(...) local flags = "" if ci_is_running() then flags = "-vD" end local outdata, errdata = os.iorun("xmake test " .. flags) assert(outdata, errdata) end function main(t) local clang_options = {compiler = "clang", version = CLANG_MIN_VER, after_build = run_xmake_test} local gcc_options = {compiler = "gcc", version = GCC_MIN_VER, after_build = run_xmake_test} local msvc_options = {version = MSVC_MIN_VER, after_build = run_xmake_test} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/test_xmake_test_stdmodules.lua ================================================ inherit("test_base") import("utils.ci.is_running", {alias = "ci_is_running"}) CLANG_MIN_VER = "19" GCC_MIN_VER = "15" MSVC_MIN_VER = "14.35" function run_xmake_test(...) local flags = "" if ci_is_running() then flags = "-vD" end local outdata, errdata = os.iorun("xmake test " .. flags) assert(outdata, errdata) end function main(_) local clang_options = {stdmodule = true, compiler = "clang", version = CLANG_MIN_VER, after_build = run_xmake_test} local gcc_options = {stdmodule = true, compiler = "gcc", version = GCC_MIN_VER, after_build = run_xmake_test} -- latest mingw gcc 15.1 is broken -- error: F:/msys64/mingw64/include/c++/15.1.0/shared_mutex:105:3: error: 'int std::__glibcxx_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' exposes TU-local entity 'int pthread_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' -- 105 | __glibcxx_rwlock_timedrdlock (pthread_rwlock_t *__rwlock, -- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- In file included from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/gthr-default.h:35, -- from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/gthr.h:157, -- from F:/msys64/mingw64/include/c++/15.1.0/ext/atomicity.h:37, -- from F:/msys64/mingw64/include/c++/15.1.0/bits/ios_base.h:41, -- from F:/msys64/mingw64/include/c++/15.1.0/streambuf:45, -- from F:/msys64/mingw64/include/c++/15.1.0/bits/streambuf_iterator.h:37, -- from F:/msys64/mingw64/include/c++/15.1.0/iterator:68, -- from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/stdc++.h:56: -- F:/msys64/mingw64/include/pthread.h:296:28: note: 'int pthread_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' declared with internal linkage -- 296 | WINPTHREAD_RWLOCK_DECL int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts) -- | ^~~~~~~~~~~~~~~~~~~~~~~~~~ -- F:/msys64/mingw64/include/c++/15.1.0/shared_mutex:115:3: error: 'int std::__glibcxx_rwlock_timedwrlock(pthread_rwlock_t*, const timespec*)' exposes TU-local entity 'int pthread_rwlock_timedwrlock(pthread_rwlock_t*, const timespec*)' -- 115 | __glibcxx_rwlock_timedwrlock (pthread_rwlock_t *__rwlock, local gcc_options = {stdmodule = true, compiler = "gcc", version = GCC_MIN_VER} if is_subhost("msys") then gcc_options = nil end local msvc_options = {stdmodule = true, version = MSVC_MIN_VER} run_tests(clang_options, gcc_options, msvc_options) end ================================================ FILE: tests/projects/c++/modules/user_headerunit/src/header.hpp ================================================ #pragma once namespace hello { inline constexpr auto FOO = "Hello"; } ================================================ FILE: tests/projects/c++/modules/user_headerunit/src/hello.mpp ================================================ module; #include export module hello; import "header.hpp"; export namespace hello { void say(const char *arg) { printf("%s: %s\n", FOO, arg); } } ================================================ FILE: tests/projects/c++/modules/user_headerunit/src/main.cpp ================================================ import hello; import "header.hpp"; int main() { hello::say(hello::FOO); return 0; } ================================================ FILE: tests/projects/c++/modules/user_headerunit/test.lua ================================================ inherit(".test_headerunits") ================================================ FILE: tests/projects/c++/modules/user_headerunit/xmake.lua ================================================ add_rules("mode.release", "mode.debug") set_languages("c++20") target("user_headerunit") set_kind("binary") add_headerfiles("src/*.hpp") add_files("src/*.cpp", "src/*.mpp") ================================================ FILE: tests/projects/c++/modules/user_headerunit2/a/a.mpp ================================================ export module A; import "c.hpp"; import "d.hpp"; ================================================ FILE: tests/projects/c++/modules/user_headerunit2/a/c.hpp ================================================ #pragma once ================================================ FILE: tests/projects/c++/modules/user_headerunit2/a/d.hpp ================================================ #pragma once ================================================ FILE: tests/projects/c++/modules/user_headerunit2/a/xmake.lua ================================================ target("a") set_kind("moduleonly") add_headerfiles("*.hpp") add_files("a.mpp") set_languages("cxxlatest") ================================================ FILE: tests/projects/c++/modules/user_headerunit2/b/b.mpp ================================================ export module B; import A; import "../a/c.hpp"; ================================================ FILE: tests/projects/c++/modules/user_headerunit2/b/xmake.lua ================================================ target("b") add_deps("a") set_kind("moduleonly") add_files("b.mpp") set_languages("cxxlatest") ================================================ FILE: tests/projects/c++/modules/user_headerunit2/test.lua ================================================ inherit(".test_headerunits") ================================================ FILE: tests/projects/c++/modules/user_headerunit2/xmake.lua ================================================ includes("a", "b") target("test") add_deps("a", "b") set_kind("phony") ================================================ FILE: tests/projects/c++/modules/xmake_tests1/src/foo.cppm ================================================ export module Foo; export inline int foo() { return 0; } ================================================ FILE: tests/projects/c++/modules/xmake_tests1/src/main.cpp ================================================ import Foo; int main() { return foo(); } ================================================ FILE: tests/projects/c++/modules/xmake_tests1/test.lua ================================================ inherit(".test_xmake_test") ================================================ FILE: tests/projects/c++/modules/xmake_tests1/xmake.lua ================================================ add_rules('mode.debug', 'mode.release') set_languages('c++23') set_policy('build.c++.modules.std', false) target('module_dep') set_kind('moduleonly') add_files('src/*.cppm') target('module_target') set_kind('moduleonly') add_files('src/*.cppm') add_deps('module_dep') add_tests('test', { kind = 'binary', files = 'src/main.cpp', build_should_pass = true }) add_tests('test2', { kind = 'binary', files = 'src/main.cpp', build_should_pass = true }) ================================================ FILE: tests/projects/c++/modules/xmake_tests2/src/foo.cppm ================================================ export module Foo; export inline int foo() { return 0; } ================================================ FILE: tests/projects/c++/modules/xmake_tests2/src/main.cpp ================================================ import Foo; int main() { return foo(); } ================================================ FILE: tests/projects/c++/modules/xmake_tests2/test.lua ================================================ inherit(".test_xmake_test") ================================================ FILE: tests/projects/c++/modules/xmake_tests2/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c++23") set_policy("build.c++.modules.std", false) target("module_dep") set_kind("moduleonly") add_files("src/*.cppm") target("module_target1") set_kind("moduleonly") add_files("src/*.cppm") add_deps("module_dep") add_tests("tests", {kind = "binary", files = "src/main.cpp", build_should_pass = true}) target("module_target2") set_kind("moduleonly") add_files("src/*.cppm") add_deps("module_dep") add_tests("tests", {kind = "binary", files = "src/main.cpp", build_should_pass = true}) ================================================ FILE: tests/projects/c++/modules/xmake_tests3/src/foo.cppm ================================================ export module Foo; import std; export void foo() { std::printf("Hello from Foo\n"); } ================================================ FILE: tests/projects/c++/modules/xmake_tests3/src/main.cpp ================================================ import std; import Foo; int main() { foo(); std::printf("Hello from main\n"); return 0; } ================================================ FILE: tests/projects/c++/modules/xmake_tests3/test.lua ================================================ inherit(".test_xmake_test_stdmodules") ================================================ FILE: tests/projects/c++/modules/xmake_tests3/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c++23") target("module_dep") set_kind("moduleonly") add_files("src/*.cppm") target("module_target1") set_kind("moduleonly") add_files("src/*.cppm") add_deps("module_dep") add_tests("tests", {kind = "binary", files = "src/main.cpp", build_should_pass = true, run_should_pass = true}) ================================================ FILE: tests/projects/c++/modules/xmake_tests4/.gitignore ================================================ .xmake/ .vscode/ build/ uselocalxmake.sh ================================================ FILE: tests/projects/c++/modules/xmake_tests4/src/main.cpp ================================================ import work; int main() { do_work(); } ================================================ FILE: tests/projects/c++/modules/xmake_tests4/src/work.mpp ================================================ export module work; import std; export template void do_work() { if constexpr (std::is_same_v) { std::println("Hello world!"); } else if constexpr (std::is_same_v) { std::println("Hello test!"); } else { std::println("Hello unknown type!"); } } ================================================ FILE: tests/projects/c++/modules/xmake_tests4/test/test.cpp ================================================ import work; int main() { do_work(); } ================================================ FILE: tests/projects/c++/modules/xmake_tests4/test.lua ================================================ inherit(".test_xmake_test_stdmodules") ================================================ FILE: tests/projects/c++/modules/xmake_tests4/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("c++23") target("llvm") set_kind("binary") add_files("src/*.cpp", "src/*.mpp") add_tests("test", { files = "test/test.cpp", remove_files = "src/main.cpp" }) ================================================ FILE: tests/projects/c++/package_linkgroups/3rd/dpdk/src/add.cc ================================================ #include "add.h" int add(int x, int y) { return x + y; } ================================================ FILE: tests/projects/c++/package_linkgroups/3rd/dpdk/src/add.h ================================================ #pragma once int add(int x, int y); ================================================ FILE: tests/projects/c++/package_linkgroups/3rd/dpdk/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("dpdk_add") set_kind("static") add_files("src/add.cc") add_headerfiles("src/*.h") ================================================ FILE: tests/projects/c++/package_linkgroups/3rd/spdk/src/mul.cc ================================================ #include "mul.h" #include "add.h" int mul(int x, int y) { int result = 0; for (int i = 0; i < y; i++) { result = add(result, x); } return result; } ================================================ FILE: tests/projects/c++/package_linkgroups/3rd/spdk/src/mul.h ================================================ #pragma once int mul(int x, int y); ================================================ FILE: tests/projects/c++/package_linkgroups/3rd/spdk/xmake.lua ================================================ add_rules("mode.debug", "mode.release") package("dpdk") set_sourcedir(path.join(os.scriptdir(), "../../3rd/dpdk")) on_install("linux", function (package) import("package.tools.xmake").install(package) end) on_test(function (package) assert(package:has_cxxincludes("add.h")) end) package_end() add_includedirs("src") add_requires("dpdk") target("spdk_mul") set_kind("static") add_files("src/mul.cc") add_headerfiles("src/*.h") add_packages("dpdk") ================================================ FILE: tests/projects/c++/package_linkgroups/src/main.cc ================================================ #include #include "mul.h" int main(int argc, char** argv) { int s = mul(3, 4); std::cout << "hello world! " << s << std::endl; return 0; } ================================================ FILE: tests/projects/c++/package_linkgroups/test.lua ================================================ function main(t) if not is_host("linux") then return end t:build() end ================================================ FILE: tests/projects/c++/package_linkgroups/xmake.lua ================================================ add_rules("mode.debug", "mode.release") package("dpdk") set_sourcedir(path.join(os.scriptdir(), "3rd/dpdk")) add_links("dpdk_add") add_linkgroups("dpdk_add", {name = "dpdk", whole = true, group = true}) on_install("linux", function (package) import("package.tools.xmake").install(package) end) on_test(function (package) assert(package:has_cxxincludes("add.h")) end) package_end() package("spdk") set_sourcedir(path.join(os.scriptdir(), "3rd/spdk")) add_deps("dpdk") add_links("spdk_mul") add_linkgroups("spdk_mul", {name = "dpdk", whole = true, group = true}) on_install("linux", function (package) import("package.tools.xmake").install(package) end) on_test(function (package) assert(package:has_cxxincludes("mul.h")) end) package_end() add_requires("spdk") target("test") set_kind("binary") add_files("src/main.cc") add_packages("spdk") add_includedirs("src") ================================================ FILE: tests/projects/c++/precompiled_header/src/header.h ================================================ // header.h #ifndef HEADER_H #define HEADER_H #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif ================================================ FILE: tests/projects/c++/precompiled_header/src/header2.h ================================================ ================================================ FILE: tests/projects/c++/precompiled_header/src/main.cpp ================================================ #include "header.h" int main(int argc, char **argv) { std::string s("xmake"); printf("hello %s!\n", s.c_str()); return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/src/test.c ================================================ void test_c(void) { } ================================================ FILE: tests/projects/c++/precompiled_header/src/test.cpp ================================================ // main.cpp #include "header.h" int test() { return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/src/test2.cpp ================================================ // main.cpp #include "header.h" int test2() { return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/src/test4.cpp ================================================ // main.cpp #include "header.h" int test4() { return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/src/test5.cpp ================================================ // main.cpp #include "header.h" int test5() { return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/src/test6.cpp ================================================ // main.cpp #include "header.h" int test6() { return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/src/test7.cpp ================================================ // main.cpp #include "header.h" int test7() { return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/src/test8.cpp ================================================ // main.cpp #include "header.h" int test8() { return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/precompiled_header/test3.cpp ================================================ #include "src/header.h" #include "src/header2.h" int test3() { return 0; } ================================================ FILE: tests/projects/c++/precompiled_header/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("main") set_kind("binary") set_languages("cxx11") set_pcxxheader("src/header.h") add_files("src/*.cpp", "src/*.c", "*.cpp") ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/common.h ================================================ #include #include #include ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/consumer.cpp ================================================ #include // Declare the function from lib1 int lib1_function(); int main() { std::cout << "Consumer program without PCH" << std::endl; int result = lib1_function(); std::cout << "lib1 result: " << result << std::endl; return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/lib1.cpp ================================================ #include "lib1_pch.h" int lib1_function() { std::vector numbers = {1, 2, 3, 4, 5}; int sum = std::accumulate(numbers.begin(), numbers.end(), 0); return sum; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/lib1_pch.h ================================================ #include #include #include ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/lib2.cpp ================================================ #include "lib2_pch.h" int lib2_function() { std::map data = {{1, "one"}, {2, "two"}, {3, "three"}}; std::set keys; for (const auto& pair : data) { keys.insert(pair.first); } return keys.size(); } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/lib2_pch.h ================================================ #include #include #include ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/main.cpp ================================================ #include "common.h" int lib1_function(); int lib2_function(); int main() { std::cout << "Main program started" << std::endl; int result1 = lib1_function(); int result2 = lib2_function(); std::cout << "lib1 result: " << result1 << std::endl; std::cout << "lib2 result: " << result2 << std::endl; std::vector vec = {result1, result2}; std::cout << "Combined result: " << vec[0] + vec[1] << std::endl; return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inc ================================================ #pragma once #include #include #include // PCH with .inc extension #define APP_NAME "PCH Test" #define VERSION "1.0" inline void hello_from_inc() { std::cout << "Hello from .inc PCH!" << std::endl; } template class INCMap { private: std::map data; public: void insert(const K& key, const V& value) { data[key] = value; } V get(const K& key) const { auto it = data.find(key); return (it != data.end()) ? it->second : V(); } void print_info() const { std::cout << APP_NAME << " v" << VERSION << std::endl; std::cout << "Map contains " << data.size() << " items" << std::endl; } }; ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inl ================================================ #pragma once #include #include #include // PCH with .inl extension inline void hello_from_inl() { std::cout << "Hello from .inl PCH!" << std::endl; } template class INLProcessor { private: std::vector items; public: void add(const T& item) { items.push_back(item); } void sort() { std::sort(items.begin(), items.end()); } T max() const { if (items.empty()) return T(); return *std::max_element(items.begin(), items.end()); } T min() const { if (items.empty()) return T(); return *std::min_element(items.begin(), items.end()); } void print() const { for (const auto& item : items) { std::cout << item << " "; } std::cout << std::endl; } }; ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.ipp ================================================ #pragma once #include #include #include // PCH with .ipp extension inline void hello_from_ipp() { std::cout << "Hello from .ipp PCH!" << std::endl; } template class IPPContainer { private: std::vector data; public: void add(const T& item) { data.push_back(item); } void print() const { for (const auto& item : data) { std::cout << item << " "; } std::cout << std::endl; } }; ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tcc ================================================ #pragma once #include #include #include // PCH with .tcc extension inline void hello_from_tcc() { std::cout << "Hello from .tcc PCH!" << std::endl; } template class TCCCalculator { private: std::list values; public: void add(const T& value) { values.push_back(value); } T sum() const { return std::accumulate(values.begin(), values.end(), T(0)); } double average() const { if (values.empty()) return 0.0; return static_cast(sum()) / values.size(); } void clear() { values.clear(); } void print() const { std::cout << "Values: "; for (const auto& value : values) { std::cout << value << " "; } std::cout << std::endl; } }; ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tpl ================================================ #pragma once #include #include #include // PCH with .tpl extension inline void hello_from_tpl() { std::cout << "Hello from .tpl PCH!" << std::endl; } template class TPLProcessor { private: std::queue input_queue; std::stack output_stack; public: void enqueue(const T& item) { input_queue.push(item); } T dequeue() { if (input_queue.empty()) return T(); T item = input_queue.front(); input_queue.pop(); return item; } void push_to_stack(const T& item) { output_stack.push(item); } T pop_from_stack() { if (output_stack.empty()) return T(); T item = output_stack.top(); output_stack.pop(); return item; } void transfer_to_stack() { while (!input_queue.empty()) { push_to_stack(dequeue()); } } void print_queue() const { std::queue temp = input_queue; std::cout << "Queue: "; while (!temp.empty()) { std::cout << temp.front() << " "; temp.pop(); } std::cout << std::endl; } void print_stack() const { std::stack temp = output_stack; std::cout << "Stack: "; while (!temp.empty()) { std::cout << temp.top() << " "; temp.pop(); } std::cout << std::endl; } }; ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/simple.cpp ================================================ #include #include int main() { std::string message = "Simple program without PCH"; std::cout << message << std::endl; return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/test_inc.cpp ================================================ #include "pch_test.inc" int main() { hello_from_inc(); INCMap scores; scores.insert("alice", 95); scores.insert("bob", 87); scores.insert("charlie", 92); scores.print_info(); std::cout << "Alice's score: " << scores.get("alice") << std::endl; std::cout << "Bob's score: " << scores.get("bob") << std::endl; return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/test_inl.cpp ================================================ #include "pch_test.inl" int main() { hello_from_inl(); INLProcessor processor; processor.add(42); processor.add(17); processor.add(89); processor.add(3); processor.add(56); std::cout << "Original: "; processor.print(); processor.sort(); std::cout << "Sorted: "; processor.print(); std::cout << "Min: " << processor.min() << std::endl; std::cout << "Max: " << processor.max() << std::endl; return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/test_ipp.cpp ================================================ #include "pch_test.ipp" int main() { hello_from_ipp(); IPPContainer container; container.add(1); container.add(2); container.add(3); std::cout << "Container contents: "; container.print(); return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/test_tcc.cpp ================================================ #include "pch_test.tcc" int main() { hello_from_tcc(); TCCCalculator calc; calc.add(3.5); calc.add(7.2); calc.add(1.8); calc.add(9.6); calc.add(4.1); calc.print(); std::cout << "Sum: " << calc.sum() << std::endl; std::cout << "Average: " << calc.average() << std::endl; // Test with integers TCCCalculator int_calc; int_calc.add(10); int_calc.add(20); int_calc.add(30); int_calc.print(); std::cout << "Sum: " << int_calc.sum() << std::endl; std::cout << "Average: " << int_calc.average() << std::endl; return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/test_tpl.cpp ================================================ #include "pch_test.tpl" int main() { hello_from_tpl(); TPLProcessor processor; // Add items to queue processor.enqueue("first"); processor.enqueue("second"); processor.enqueue("third"); processor.print_queue(); // Transfer to stack processor.transfer_to_stack(); processor.print_queue(); processor.print_stack(); // Pop from stack (LIFO order) std::cout << "Popping from stack:" << std::endl; while (true) { std::string item = processor.pop_from_stack(); if (item.empty()) break; std::cout << " " << item << std::endl; } // Test with integers TPLProcessor int_processor; int_processor.enqueue(100); int_processor.enqueue(200); int_processor.enqueue(300); int_processor.transfer_to_stack(); std::cout << "Integer stack pop:" << std::endl; while (true) { int item = int_processor.pop_from_stack(); if (item == 0) break; std::cout << " " << item << std::endl; } return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/tool.cpp ================================================ #include "tool_pch.h" int main() { std::stringstream ss; ss << "Tool program output"; std::ofstream outfile("tool_output.txt"); if (outfile.is_open()) { outfile << ss.str() << std::endl; outfile.close(); } std::cout << "Tool completed successfully" << std::endl; return 0; } ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/src/tool_pch.h ================================================ #include #include #include ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/precompiled_header_multiple_targets/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_languages("cxx11") -- Target 1: main executable target("main") set_kind("binary") set_pcxxheader("src/common.h") add_files("src/main.cpp") add_deps("lib1", "lib2") -- Target 2: static library 1 target("lib1") set_kind("static") set_pcxxheader("src/lib1_pch.h") add_files("src/lib1.cpp") -- Target 3: static library 2 target("lib2") set_kind("static") set_pcxxheader("src/lib2_pch.h") add_files("src/lib2.cpp") -- Target 4: another executable with different PCH target("tool") set_kind("binary") set_pcxxheader("src/tool_pch.h") add_files("src/tool.cpp") -- Target 5: executable without PCH target("simple") set_kind("binary") add_files("src/simple.cpp") -- Target 6: executable without PCH but depends on PCH library target("consumer") set_kind("binary") add_files("src/consumer.cpp") add_deps("lib1") -- Target 7: PCH with .ipp extension target("test_ipp_pch") set_kind("binary") set_pcxxheader("src/pch_test.ipp") add_files("src/test_ipp.cpp") -- Target 8: PCH with .inc extension target("test_inc_pch") set_kind("binary") set_pcxxheader("src/pch_test.inc") add_files("src/test_inc.cpp") -- Target 9: PCH with .inl extension target("test_inl_pch") set_kind("binary") set_pcxxheader("src/pch_test.inl") add_files("src/test_inl.cpp") -- Target 10: PCH with .tcc extension target("test_tcc_pch") set_kind("binary") set_pcxxheader("src/pch_test.tcc") add_files("src/test_tcc.cpp") -- Target 11: PCH with .tpl extension target("test_tpl_pch") set_kind("binary") set_pcxxheader("src/pch_test.tpl") add_files("src/test_tpl.cpp") ================================================ FILE: tests/projects/c++/protobuf/src/main.cpp ================================================ #include #include "test.pb.h" #include "subdir/test2.pb.h" using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/c++/protobuf/src/subdir/test2.proto ================================================ syntax = "proto3"; package test2; message TestCase2 { string name2 = 4; } message Test2 { repeated TestCase2 case2 = 1; } ================================================ FILE: tests/projects/c++/protobuf/src/test.proto ================================================ syntax = "proto3"; import "subdir/test2.proto"; package test; message TestCase { string name = 4; } message Test { repeated TestCase case = 1; repeated test2.TestCase2 case2 = 2; } ================================================ FILE: tests/projects/c++/protobuf/xmake.lua ================================================ add_rules("mode.debug", "mode.release") local language = "17" add_requires("protoc", "protobuf-cpp") -- add_requireconfs("protoc.protobuf-cpp", {override = true, version = "1.0.0"}) add_requireconfs("**.abseil", {override = true, configs = {cxx_standard = language}}) target("test") set_kind("binary") set_languages("c++" .. language) add_rules("protobuf.cpp") add_files("src/*.cpp") add_files("src/**.proto", {proto_rootdir = "src"}) add_packages("protoc", "protobuf-cpp") ================================================ FILE: tests/projects/c++/protobuf_grpc_cpp_plugin/src/main.cpp ================================================ #include #include "test.pb.h" #include "subdir/test2.pb.h" using namespace std; int main(int argc, char **argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/c++/protobuf_grpc_cpp_plugin/src/subdir/test2.proto ================================================ syntax = "proto3"; package test2; message TestCase2 { string name2 = 4; } message Test2 { repeated TestCase2 case2 = 1; } ================================================ FILE: tests/projects/c++/protobuf_grpc_cpp_plugin/src/test.proto ================================================ syntax = "proto3"; import "subdir/test2.proto"; package test; message TestCase { string name = 4; } message Test { repeated TestCase case = 1; repeated test2.TestCase2 case2 = 2; } message EchoRequest { string data = 1; } message EchoResponse { string data = 1; } service EchoServer { rpc Echo(EchoRequest) returns (EchoResponse); } ================================================ FILE: tests/projects/c++/protobuf_grpc_cpp_plugin/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("protobuf-cpp") add_requires("grpc", {system = false}) target("test") set_kind("binary") set_languages("c++17") add_packages("protobuf-cpp") add_packages("grpc") add_rules("protobuf.cpp") add_files("src/*.cpp") add_files("src/test.proto", {proto_rootdir = "src", proto_grpc_cpp_plugin = true}) add_files("src/subdir/test2.proto", {proto_rootdir = "src"}) ================================================ FILE: tests/projects/c++/shared_library/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c++/shared_library/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) #define __export __declspec(dllexport) #elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) #define __export __attribute__((visibility("default"))) #else #define __export #endif __export int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/c++/shared_library/src/main.cpp ================================================ #include "foo.h" #include using namespace std; int main(int argc, char **argv) { cout << "add(1, 2) = " << add(1, 2) << endl; return 0; } ================================================ FILE: tests/projects/c++/shared_library/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("shared") add_files("src/foo.cpp") target("demo") set_kind("binary") add_deps("foo") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/shared_library_export_all/src/bar.cpp ================================================ #include "bar.h" int bar::add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c++/shared_library_export_all/src/bar.h ================================================ class bar { public: static int add(int a, int b); }; ================================================ FILE: tests/projects/c++/shared_library_export_all/src/foo.cpp ================================================ #include "foo.h" int foo::add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c++/shared_library_export_all/src/foo.h ================================================ class foo { public: static int add(int a, int b); }; ================================================ FILE: tests/projects/c++/shared_library_export_all/src/main.cpp ================================================ #include "foo.h" #include "bar.h" #include int main(int argc, char **argv) { std::cout << "foo::add(1, 2) = " << foo::add(1, 2) << std::endl; std::cout << "bar::add(1, 2) = " << bar::add(1, 2) << std::endl; return 0; } ================================================ FILE: tests/projects/c++/shared_library_export_all/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/shared_library_export_all/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("shared") add_files("src/foo.cpp") add_rules("utils.symbols.export_all", {export_classes = true}) target("bar") set_kind("shared") add_files("src/bar.cpp") add_rules("utils.symbols.export_all", {export_filter = function (symbol, opt) local filepath = opt.sourcefile or opt.objectfile if filepath and filepath:find("bar.cpp", 1, true) and symbol:find("add", 1, true) then print("export: %s at %s", symbol, filepath) return true end end}) target("demo") set_kind("binary") add_deps("foo", "bar") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/shared_library_with_soname/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/c++/shared_library_with_soname/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c++/shared_library_with_soname/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) #define __export __declspec(dllexport) #elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) #define __export __attribute__((visibility("default"))) #else #define __export #endif __export int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/c++/shared_library_with_soname/src/main.cpp ================================================ #include "foo.h" #include using namespace std; int main(int argc, char **argv) { cout << "add(1, 2) = " << add(1, 2) << endl; return 0; } ================================================ FILE: tests/projects/c++/shared_library_with_soname/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/shared_library_with_soname/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_version("1.0.1", {soname = true}) target("foo") set_kind("shared") add_files("src/foo.cpp") after_build(function (target) print(target:soname()) end) target("tests") set_kind("binary") add_deps("foo") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/snippet_runtimes/my-repo/packages/b/bar/src/include/bar.hpp ================================================ #ifndef BAR_HPP #define BAR_HPP #include std::string foo(); #endif ================================================ FILE: tests/projects/c++/snippet_runtimes/my-repo/packages/b/bar/src/src/bar.cpp ================================================ #include std::string foo() { return "bar"; } ================================================ FILE: tests/projects/c++/snippet_runtimes/my-repo/packages/b/bar/src/xmake.lua ================================================ target("bar") set_kind("$(kind)") add_files("src/*.cpp") add_headerfiles("include/(**.hpp)") add_includedirs("include") ================================================ FILE: tests/projects/c++/snippet_runtimes/my-repo/packages/b/bar/xmake.lua ================================================ package("bar") set_sourcedir(path.join(os.scriptdir(), "src")) on_install(function(package) import("package.tools.xmake").install(package, {}) end) on_test(function(package) assert(package:check_cxxsnippets({test = [[ #include void test() { std::cout << _LIBCPP_VERSION << std::endl; } ]]}, {configs = {languages = "c++17"}})) end) ================================================ FILE: tests/projects/c++/snippet_runtimes/src/main.cpp ================================================ #include #include int main() { std::cout << foo(); return 0; } ================================================ FILE: tests/projects/c++/snippet_runtimes/test.lua ================================================ import("lib.detect.find_tool") import("core.base.semver") import("utils.ci.is_running", {alias = "ci_is_running"}) function _build() if ci_is_running() then assert(os.iorun("xmake -rvD")) else assert(os.iorun("xmake -r")) end end function main(t) local clang = find_tool("clang") if clang and not is_subhost("windows") and not is_subhost("bsd", "solaris", "haiku") then os.exec("xmake f --toolchain=clang --runtimes=c++_shared --yes") _build() end end ================================================ FILE: tests/projects/c++/snippet_runtimes/xmake.lua ================================================ add_repositories("my-repo my-repo") add_requires("bar") target("foo") set_kind("binary") add_files("src/*.cpp") add_packages("bar") on_config(function(target) assert(target:check_cxxsnippets({test = [[ #include void test() { std::cout << _LIBCPP_VERSION << std::endl; } ]]}, {configs = {languages = "c++17"}})) end) ================================================ FILE: tests/projects/c++/static_library/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/c++/static_library/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/c++/static_library/src/main.cpp ================================================ #include "foo.h" #include using namespace std; int main(int argc, char **argv) { cout << "add(1, 2) = " << add(1, 2) << endl; return 0; } ================================================ FILE: tests/projects/c++/static_library/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("static") add_files("src/foo.cpp") target("demo") set_kind("binary") add_deps("foo") add_files("src/main.cpp") ================================================ FILE: tests/projects/c++/test(brackets)/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/c++/test(brackets)/inc(brackets)/test.h ================================================ #define TEST "hello" ================================================ FILE: tests/projects/c++/test(brackets)/src/main.cpp ================================================ #include #include "test.h" using namespace std; int main(int argc, char **argv) { cout << TEST " " WORD "!" << endl; return 0; } ================================================ FILE: tests/projects/c++/test(brackets)/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/test(brackets)/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") set_kind("binary") add_files("src/*.cpp") add_includedirs("inc(brackets)") add_defines("WORD=\"(world)\"") ================================================ FILE: tests/projects/c++/unity_build/src/bar/test4.cpp ================================================ // main.cpp #include "header.h" namespace MY_UNITY_ID { int i = 42; } int test4() { return MY_UNITY_ID::i; } ================================================ FILE: tests/projects/c++/unity_build/src/bar/test5.cpp ================================================ // main.cpp #include "header.h" namespace MY_UNITY_ID { int i = 42; } int test5() { return MY_UNITY_ID::i; } ================================================ FILE: tests/projects/c++/unity_build/src/bar/test6.cpp ================================================ // main.cpp #include "header.h" int test6() { return 0; } ================================================ FILE: tests/projects/c++/unity_build/src/foo/test.cpp ================================================ // main.cpp #include "header.h" int test() { return 0; } ================================================ FILE: tests/projects/c++/unity_build/src/foo/test2.cpp ================================================ // main.cpp #include "header.h" int test2() { return 0; } ================================================ FILE: tests/projects/c++/unity_build/src/header.h ================================================ // header.h #ifndef HEADER_H #define HEADER_H #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif ================================================ FILE: tests/projects/c++/unity_build/src/header2.h ================================================ ================================================ FILE: tests/projects/c++/unity_build/src/main.cpp ================================================ #include "header.h" int main(int argc, char **argv) { std::string s("xmake"); printf("hello %s!\n", s.c_str()); return 0; } ================================================ FILE: tests/projects/c++/unity_build/src/test.c ================================================ void test_c(void) { } ================================================ FILE: tests/projects/c++/unity_build/src/test7.cpp ================================================ // main.cpp #include "header.h" int test7() { return 0; } ================================================ FILE: tests/projects/c++/unity_build/src/test8.cpp ================================================ // main.cpp #include "header.h" int test8() { return 0; } ================================================ FILE: tests/projects/c++/unity_build/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/c++/unity_build/xmake.lua ================================================ target("test") set_kind("binary") add_includedirs("src") add_rules("c++.unity_build", {batchsize = 2, uniqueid = "MY_UNITY_ID"}) add_files("src/*.c", "src/*.cpp") add_files("src/foo/*.cpp", {unity_group = "foo"}) add_files("src/bar/*.cpp", {unity_group = "bar"}) ================================================ FILE: tests/projects/cppfront/console/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/cppfront/console/src/main.cpp2 ================================================ #include "println.h2" main: () -> int = println("Hello world!\n"); ================================================ FILE: tests/projects/cppfront/console/src/println.h2 ================================================ println: (msg: _) -> int = { std::cout << msg; return 0; } ================================================ FILE: tests/projects/cppfront/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("cppfront") target("test") add_rules("cppfront") set_kind("binary") add_files("src/*.cpp2") add_files("src/*.h2") add_packages("cppfront") ================================================ FILE: tests/projects/csharp/console/.gitignore ================================================ .xmake/ build/ bin/ obj/ vsxmake*/ .vs/ ================================================ FILE: tests/projects/csharp/console/src/Program.cs ================================================ Console.WriteLine("hello xmake!"); ================================================ FILE: tests/projects/csharp/console/test.lua ================================================ import("detect.sdks.find_dotnet") function test_build(t) if is_subhost("msys") then return t:skip("csharp not supported on msys") end local dotnet = find_dotnet() if dotnet and dotnet.sdkver then t:build() else return t:skip("dotnet sdk not found") end end ================================================ FILE: tests/projects/csharp/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/Program.cs") ================================================ FILE: tests/projects/csharp/console_with_runtime_json/.gitignore ================================================ .xmake/ build/ bin/ obj/ vsxmake*/ .vs/ ================================================ FILE: tests/projects/csharp/console_with_runtime_json/src/Program.cs ================================================ using System.Text.Json; var runtimeFile = Path.Combine(Directory.GetCurrentDirectory(), "runtime.json"); if (!File.Exists(runtimeFile)) { Console.WriteLine("runtime.json missing"); return; } var json = File.ReadAllText(runtimeFile); using var doc = JsonDocument.Parse(json); var runtime = doc.RootElement.TryGetProperty("runtime", out var value) ? value.GetString() : "unknown"; Console.WriteLine($"runtime={runtime}"); ================================================ FILE: tests/projects/csharp/console_with_runtime_json/src/runtime.json ================================================ { "runtime": "xmake", "featureFlags": { "sample": true } } ================================================ FILE: tests/projects/csharp/console_with_runtime_json/test.lua ================================================ import("detect.sdks.find_dotnet") function test_build(t) if is_subhost("msys") then return t:skip("csharp not supported on msys") end local dotnet = find_dotnet() if dotnet and dotnet.sdkver then t:build() else return t:skip("dotnet sdk not found") end end ================================================ FILE: tests/projects/csharp/console_with_runtime_json/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("app") set_kind("binary") add_files("src/Program.cs") set_rundir("src") ================================================ FILE: tests/projects/csharp/multiple_library/.gitignore ================================================ .xmake/ build/ bin/ obj/ vsxmake*/ .vs/ ================================================ FILE: tests/projects/csharp/multiple_library/src/libalpha/Alpha.cs ================================================ namespace LibAlpha; public static class Alpha { public static string Message() { return "alpha"; } } ================================================ FILE: tests/projects/csharp/multiple_library/src/libbeta/Beta.cs ================================================ using LibAlpha; namespace LibBeta; public static class Beta { public static string Message() { return Alpha.Message() + "+beta"; } } ================================================ FILE: tests/projects/csharp/multiple_library/src/sample/Program.cs ================================================ using LibBeta; Console.WriteLine(Beta.Message()); ================================================ FILE: tests/projects/csharp/multiple_library/test.lua ================================================ import("detect.sdks.find_dotnet") function test_build(t) if is_subhost("msys") then return t:skip("csharp not supported on msys") end local dotnet = find_dotnet() if dotnet and dotnet.sdkver then t:build() else return t:skip("dotnet sdk not found") end end ================================================ FILE: tests/projects/csharp/multiple_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("libalpha") set_kind("shared") add_files("src/libalpha/*.cs") target("libbeta") set_kind("shared") add_deps("libalpha") add_files("src/libbeta/*.cs") target("sample") set_kind("binary") add_deps("libbeta") add_files("src/sample/*.cs") ================================================ FILE: tests/projects/csharp/nuget_package/.gitignore ================================================ .xmake/ build/ bin/ obj/ vsxmake*/ .vs/ ================================================ FILE: tests/projects/csharp/nuget_package/src/Program.cs ================================================ using Humanizer; Console.WriteLine(1234.ToWords()); ================================================ FILE: tests/projects/csharp/nuget_package/test.lua ================================================ import("detect.sdks.find_dotnet") function test_build(t) if is_subhost("msys") then return t:skip("csharp not supported on msys") end local dotnet = find_dotnet() if dotnet and dotnet.sdkver then t:build() else return t:skip("dotnet sdk not found") end end ================================================ FILE: tests/projects/csharp/nuget_package/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("nuget::Humanizer.Core 2.14.1") target("app") set_kind("binary") add_files("src/Program.cs") add_packages("nuget::Humanizer.Core") ================================================ FILE: tests/projects/csharp/pinvoke/src/app/Program.cs ================================================ using System.Runtime.InteropServices; int sum = NativeMethods.add(3, 4); int product = NativeMethods.multiply(5, 6); Console.WriteLine($"add(3,4)={sum}"); Console.WriteLine($"multiply(5,6)={product}"); internal static class NativeMethods { private const string NativeLib = "mathlib"; [DllImport(NativeLib)] internal static extern int add(int a, int b); [DllImport(NativeLib)] internal static extern int multiply(int a, int b); } ================================================ FILE: tests/projects/csharp/pinvoke/src/native/mathlib.c ================================================ #ifdef _WIN32 #define EXPORT __declspec(dllexport) #else #define EXPORT __attribute__((visibility("default"))) #endif EXPORT int add(int a, int b) { return a + b; } EXPORT int multiply(int a, int b) { return a * b; } ================================================ FILE: tests/projects/csharp/pinvoke/test.lua ================================================ import("detect.sdks.find_dotnet") function test_build(t) if is_subhost("msys") then return t:skip("csharp not supported on msys") end local dotnet = find_dotnet() if dotnet and dotnet.sdkver then t:build() else return t:skip("dotnet sdk not found") end end ================================================ FILE: tests/projects/csharp/pinvoke/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("mathlib") set_kind("shared") add_files("src/native/*.c") target("app") set_kind("binary") add_deps("mathlib") add_files("src/app/*.cs") ================================================ FILE: tests/projects/csharp/shared_library/.gitignore ================================================ .xmake/ build/ bin/ obj/ vsxmake*/ .vs/ ================================================ FILE: tests/projects/csharp/shared_library/src/app/Program.cs ================================================ using MyLib; Console.WriteLine(Greeter.Greet("xmake")); ================================================ FILE: tests/projects/csharp/shared_library/src/lib/Greeter.cs ================================================ namespace MyLib; public static class Greeter { public static string Greet(string name) { return $"hello {name}!"; } } ================================================ FILE: tests/projects/csharp/shared_library/test.lua ================================================ import("detect.sdks.find_dotnet") function test_build(t) if is_subhost("msys") then return t:skip("csharp not supported on msys") end local dotnet = find_dotnet() if dotnet and dotnet.sdkver then t:build() else return t:skip("dotnet sdk not found") end end ================================================ FILE: tests/projects/csharp/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("mylib") set_kind("shared") add_files("src/lib/*.cs") target("app") set_kind("binary") add_deps("mylib") add_files("src/app/*.cs") ================================================ FILE: tests/projects/csharp/web_project/.gitignore ================================================ .xmake/ build/ bin/ obj/ vsxmake*/ .vs/ ================================================ FILE: tests/projects/csharp/web_project/src/Program.cs ================================================ var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "hello web xmake!"); app.MapGet("/health", () => Results.Ok(new { status = "ok" })); app.Run(); ================================================ FILE: tests/projects/csharp/web_project/test.lua ================================================ import("detect.sdks.find_dotnet") function test_build(t) if is_subhost("msys") then return t:skip("csharp not supported on msys") end local dotnet = find_dotnet() if dotnet and dotnet.sdkver then t:build() else return t:skip("dotnet sdk not found") end end ================================================ FILE: tests/projects/csharp/web_project/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("webapp") set_kind("binary") add_values("csharp.sdk", "Microsoft.NET.Sdk.Web") add_files("src/Program.cs") ================================================ FILE: tests/projects/cuda/console/inc/cuda_drvapi_dynlink.c ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // With these flags defined, this source file will dynamically // load the corresponding functions. Disabled by default. //#define CUDA_INIT_D3D9 //#define CUDA_INIT_D3D10 //#define CUDA_INIT_D3D11 //#define CUDA_INIT_OPENGL #include #include "cuda_drvapi_dynlink.h" tcuInit *_cuInit; tcuDriverGetVersion *cuDriverGetVersion; tcuDeviceGet *cuDeviceGet; tcuDeviceGetCount *cuDeviceGetCount; tcuDeviceGetName *cuDeviceGetName; tcuDeviceComputeCapability *cuDeviceComputeCapability; tcuDeviceTotalMem *cuDeviceTotalMem; tcuDeviceGetProperties *cuDeviceGetProperties; tcuDeviceGetAttribute *cuDeviceGetAttribute; tcuCtxCreate *cuCtxCreate; tcuCtxDestroy *cuCtxDestroy; tcuCtxAttach *cuCtxAttach; tcuCtxDetach *cuCtxDetach; tcuCtxPushCurrent *cuCtxPushCurrent; tcuCtxPopCurrent *cuCtxPopCurrent; tcuCtxGetCurrent *cuCtxGetCurrent; tcuCtxSetCurrent *cuCtxSetCurrent; tcuCtxGetDevice *cuCtxGetDevice; tcuCtxSynchronize *cuCtxSynchronize; tcuModuleLoad *cuModuleLoad; tcuModuleLoadData *cuModuleLoadData; tcuModuleLoadDataEx *cuModuleLoadDataEx; tcuModuleLoadFatBinary *cuModuleLoadFatBinary; tcuModuleUnload *cuModuleUnload; tcuModuleGetFunction *cuModuleGetFunction; tcuModuleGetGlobal *cuModuleGetGlobal; tcuModuleGetTexRef *cuModuleGetTexRef; tcuModuleGetSurfRef *cuModuleGetSurfRef; tcuMemGetInfo *cuMemGetInfo; tcuMemAlloc *cuMemAlloc; tcuMemAllocPitch *cuMemAllocPitch; tcuMemFree *cuMemFree; tcuMemGetAddressRange *cuMemGetAddressRange; tcuMemAllocHost *cuMemAllocHost; tcuMemFreeHost *cuMemFreeHost; tcuMemHostAlloc *cuMemHostAlloc; tcuMemHostGetDevicePointer *cuMemHostGetDevicePointer; tcuMemHostRegister *cuMemHostRegister; tcuMemHostUnregister *cuMemHostUnregister; tcuMemcpyHtoD *cuMemcpyHtoD; tcuMemcpyDtoH *cuMemcpyDtoH; tcuMemcpyDtoD *cuMemcpyDtoD; tcuMemcpyDtoA *cuMemcpyDtoA; tcuMemcpyAtoD *cuMemcpyAtoD; tcuMemcpyHtoA *cuMemcpyHtoA; tcuMemcpyAtoH *cuMemcpyAtoH; tcuMemcpyAtoA *cuMemcpyAtoA; tcuMemcpy2D *cuMemcpy2D; tcuMemcpy2DUnaligned *cuMemcpy2DUnaligned; tcuMemcpy3D *cuMemcpy3D; tcuMemcpyHtoDAsync *cuMemcpyHtoDAsync; tcuMemcpyDtoHAsync *cuMemcpyDtoHAsync; tcuMemcpyDtoDAsync *cuMemcpyDtoDAsync; tcuMemcpyHtoAAsync *cuMemcpyHtoAAsync; tcuMemcpyAtoHAsync *cuMemcpyAtoHAsync; tcuMemcpy2DAsync *cuMemcpy2DAsync; tcuMemcpy3DAsync *cuMemcpy3DAsync; tcuMemcpy *cuMemcpy; tcuMemcpyPeer *cuMemcpyPeer; tcuMemsetD8 *cuMemsetD8; tcuMemsetD16 *cuMemsetD16; tcuMemsetD32 *cuMemsetD32; tcuMemsetD2D8 *cuMemsetD2D8; tcuMemsetD2D16 *cuMemsetD2D16; tcuMemsetD2D32 *cuMemsetD2D32; tcuFuncSetBlockShape *cuFuncSetBlockShape; tcuFuncSetSharedSize *cuFuncSetSharedSize; tcuFuncGetAttribute *cuFuncGetAttribute; tcuFuncSetCacheConfig *cuFuncSetCacheConfig; tcuLaunchKernel *cuLaunchKernel; tcuArrayCreate *cuArrayCreate; tcuArrayGetDescriptor *cuArrayGetDescriptor; tcuArrayDestroy *cuArrayDestroy; tcuArray3DCreate *cuArray3DCreate; tcuArray3DGetDescriptor *cuArray3DGetDescriptor; tcuTexRefCreate *cuTexRefCreate; tcuTexRefDestroy *cuTexRefDestroy; tcuTexRefSetArray *cuTexRefSetArray; tcuTexRefSetAddress *cuTexRefSetAddress; tcuTexRefSetAddress2D *cuTexRefSetAddress2D; tcuTexRefSetFormat *cuTexRefSetFormat; tcuTexRefSetAddressMode *cuTexRefSetAddressMode; tcuTexRefSetFilterMode *cuTexRefSetFilterMode; tcuTexRefSetFlags *cuTexRefSetFlags; tcuTexRefGetAddress *cuTexRefGetAddress; tcuTexRefGetArray *cuTexRefGetArray; tcuTexRefGetAddressMode *cuTexRefGetAddressMode; tcuTexRefGetFilterMode *cuTexRefGetFilterMode; tcuTexRefGetFormat *cuTexRefGetFormat; tcuTexRefGetFlags *cuTexRefGetFlags; tcuSurfRefSetArray *cuSurfRefSetArray; tcuSurfRefGetArray *cuSurfRefGetArray; tcuParamSetSize *cuParamSetSize; tcuParamSeti *cuParamSeti; tcuParamSetf *cuParamSetf; tcuParamSetv *cuParamSetv; tcuParamSetTexRef *cuParamSetTexRef; tcuLaunch *cuLaunch; tcuLaunchGrid *cuLaunchGrid; tcuLaunchGridAsync *cuLaunchGridAsync; tcuEventCreate *cuEventCreate; tcuEventRecord *cuEventRecord; tcuEventQuery *cuEventQuery; tcuEventSynchronize *cuEventSynchronize; tcuEventDestroy *cuEventDestroy; tcuEventElapsedTime *cuEventElapsedTime; tcuStreamCreate *cuStreamCreate; tcuStreamQuery *cuStreamQuery; tcuStreamSynchronize *cuStreamSynchronize; tcuStreamDestroy *cuStreamDestroy; tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource; tcuGraphicsSubResourceGetMappedArray *cuGraphicsSubResourceGetMappedArray; tcuGraphicsResourceGetMappedPointer *cuGraphicsResourceGetMappedPointer; tcuGraphicsResourceSetMapFlags *cuGraphicsResourceSetMapFlags; tcuGraphicsMapResources *cuGraphicsMapResources; tcuGraphicsUnmapResources *cuGraphicsUnmapResources; tcuGetExportTable *cuGetExportTable; tcuCtxSetLimit *cuCtxSetLimit; tcuCtxGetLimit *cuCtxGetLimit; tcuMemHostGetFlags *cuMemHostGetFlags; #ifdef CUDA_INIT_D3D9 // D3D9/CUDA interop (CUDA 1.x compatible API). These functions // are deprecated; please use the ones below tcuD3D9Begin *cuD3D9Begin; tcuD3D9End *cuD3DEnd; tcuD3D9RegisterVertexBuffer *cuD3D9RegisterVertexBuffer; tcuD3D9MapVertexBuffer *cuD3D9MapVertexBuffer; tcuD3D9UnmapVertexBuffer *cuD3D9UnmapVertexBuffer; tcuD3D9UnregisterVertexBuffer *cuD3D9UnregisterVertexBuffer; // D3D9/CUDA interop (CUDA 2.x compatible) tcuD3D9GetDirect3DDevice *cuD3D9GetDirect3DDevice; tcuD3D9RegisterResource *cuD3D9RegisterResource; tcuD3D9UnregisterResource *cuD3D9UnregisterResource; tcuD3D9MapResources *cuD3D9MapResources; tcuD3D9UnmapResources *cuD3D9UnmapResources; tcuD3D9ResourceSetMapFlags *cuD3D9ResourceSetMapFlags; tcuD3D9ResourceGetSurfaceDimensions *cuD3D9ResourceGetSurfaceDimensions; tcuD3D9ResourceGetMappedArray *cuD3D9ResourceGetMappedArray; tcuD3D9ResourceGetMappedPointer *cuD3D9ResourceGetMappedPointer; tcuD3D9ResourceGetMappedSize *cuD3D9ResourceGetMappedSize; tcuD3D9ResourceGetMappedPitch *cuD3D9ResourceGetMappedPitch; // D3D9/CUDA interop (CUDA 2.0+) tcuD3D9GetDevice *cuD3D9GetDevice; tcuD3D9CtxCreate *cuD3D9CtxCreate; tcuGraphicsD3D9RegisterResource *cuGraphicsD3D9RegisterResource; #endif #ifdef CUDA_INIT_D3D10 // D3D10/CUDA interop (CUDA 3.0+) tcuD3D10GetDevice *cuD3D10GetDevice; tcuD3D10CtxCreate *cuD3D10CtxCreate; tcuGraphicsD3D10RegisterResource *cuGraphicsD3D10RegisterResource; #endif #ifdef CUDA_INIT_D3D11 // D3D11/CUDA interop (CUDA 3.0+) tcuD3D11GetDevice *cuD3D11GetDevice; tcuD3D11CtxCreate *cuD3D11CtxCreate; tcuGraphicsD3D11RegisterResource *cuGraphicsD3D11RegisterResource; #endif // GL/CUDA interop #ifdef CUDA_INIT_OPENGL tcuGLCtxCreate *cuGLCtxCreate; tcuGraphicsGLRegisterBuffer *cuGraphicsGLRegisterBuffer; tcuGraphicsGLRegisterImage *cuGraphicsGLRegisterImage; #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) tcuWGLGetDevice *cuWGLGetDevice; #endif #endif #define STRINGIFY(X) #X #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #include #ifdef UNICODE static LPCWSTR __CudaLibName = L"nvcuda.dll"; #else static LPCSTR __CudaLibName = "nvcuda.dll"; #endif typedef HMODULE CUDADRIVER; static CUresult LOAD_LIBRARY(CUDADRIVER *pInstance) { *pInstance = LoadLibrary(__CudaLibName); if (*pInstance == NULL) { printf("LoadLibrary \"%s\" failed!\n", __CudaLibName); return CUDA_ERROR_UNKNOWN; } return CUDA_SUCCESS; } #define GET_PROC_EX(name, alias, required) \ alias = (t##name *)GetProcAddress(CudaDrvLib, #name); \ if (alias == NULL && required) { \ printf("Failed to find required function \"%s\" in %s\n", \ #name, __CudaLibName); \ return CUDA_ERROR_UNKNOWN; \ } #define GET_PROC_EX_V2(name, alias, required) \ alias = (t##name *)GetProcAddress(CudaDrvLib, STRINGIFY(name##_v2));\ if (alias == NULL && required) { \ printf("Failed to find required function \"%s\" in %s\n", \ STRINGIFY(name##_v2), __CudaLibName); \ return CUDA_ERROR_UNKNOWN; \ } #elif defined(__unix__) || defined(__APPLE__) || defined(__MACOSX) #include #if defined(__APPLE__) || defined(__MACOSX) static char __CudaLibName[] = "/usr/local/cuda/lib/libcuda.dylib"; #else static char __CudaLibName[] = "libcuda.so"; #endif typedef void *CUDADRIVER; static CUresult LOAD_LIBRARY(CUDADRIVER *pInstance) { *pInstance = dlopen(__CudaLibName, RTLD_NOW); if (*pInstance == NULL) { printf("dlopen \"%s\" failed!\n", __CudaLibName); return CUDA_ERROR_UNKNOWN; } return CUDA_SUCCESS; } #define GET_PROC_EX(name, alias, required) \ alias = (t##name *)dlsym(CudaDrvLib, #name); \ if (alias == NULL && required) { \ printf("Failed to find required function \"%s\" in %s\n", \ #name, __CudaLibName); \ return CUDA_ERROR_UNKNOWN; \ } #define GET_PROC_EX_V2(name, alias, required) \ alias = (t##name *)dlsym(CudaDrvLib, STRINGIFY(name##_v2)); \ if (alias == NULL && required) { \ printf("Failed to find required function \"%s\" in %s\n", \ STRINGIFY(name##_v2), __CudaLibName); \ return CUDA_ERROR_UNKNOWN; \ } #else #error unsupported platform #endif #define CHECKED_CALL(call) \ do { \ CUresult result = (call); \ if (CUDA_SUCCESS != result) { \ return result; \ } \ } while(0) #define GET_PROC_REQUIRED(name) GET_PROC_EX(name,name,1) #define GET_PROC_OPTIONAL(name) GET_PROC_EX(name,name,0) #define GET_PROC(name) GET_PROC_REQUIRED(name) #define GET_PROC_V2(name) GET_PROC_EX_V2(name,name,1) CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion) { CUDADRIVER CudaDrvLib; int driverVer = 1000; CHECKED_CALL(LOAD_LIBRARY(&CudaDrvLib)); // cuInit is required; alias it to _cuInit GET_PROC_EX(cuInit, _cuInit, 1); CHECKED_CALL(_cuInit(Flags)); // available since 2.2. if not present, version 1.0 is assumed GET_PROC_OPTIONAL(cuDriverGetVersion); if (cuDriverGetVersion) { CHECKED_CALL(cuDriverGetVersion(&driverVer)); } // fetch all function pointers GET_PROC(cuDeviceGet); GET_PROC(cuDeviceGetCount); GET_PROC(cuDeviceGetName); GET_PROC(cuDeviceComputeCapability); GET_PROC(cuDeviceGetProperties); GET_PROC(cuDeviceGetAttribute); GET_PROC(cuCtxDestroy); GET_PROC(cuCtxAttach); GET_PROC(cuCtxDetach); GET_PROC(cuCtxPushCurrent); GET_PROC(cuCtxPopCurrent); GET_PROC(cuCtxGetDevice); GET_PROC(cuCtxSynchronize); GET_PROC(cuModuleLoad); GET_PROC(cuModuleLoadData); GET_PROC(cuModuleUnload); GET_PROC(cuModuleGetFunction); GET_PROC(cuModuleGetTexRef); GET_PROC(cuMemFreeHost); GET_PROC(cuMemHostAlloc); GET_PROC(cuFuncSetBlockShape); GET_PROC(cuFuncSetSharedSize); GET_PROC(cuFuncGetAttribute); GET_PROC(cuArrayDestroy); GET_PROC(cuTexRefCreate); GET_PROC(cuTexRefDestroy); GET_PROC(cuTexRefSetArray); GET_PROC(cuTexRefSetFormat); GET_PROC(cuTexRefSetAddressMode); GET_PROC(cuTexRefSetFilterMode); GET_PROC(cuTexRefSetFlags); GET_PROC(cuTexRefGetArray); GET_PROC(cuTexRefGetAddressMode); GET_PROC(cuTexRefGetFilterMode); GET_PROC(cuTexRefGetFormat); GET_PROC(cuTexRefGetFlags); GET_PROC(cuParamSetSize); GET_PROC(cuParamSeti); GET_PROC(cuParamSetf); GET_PROC(cuParamSetv); GET_PROC(cuParamSetTexRef); GET_PROC(cuLaunch); GET_PROC(cuLaunchGrid); GET_PROC(cuLaunchGridAsync); GET_PROC(cuEventCreate); GET_PROC(cuEventRecord); GET_PROC(cuEventQuery); GET_PROC(cuEventSynchronize); GET_PROC(cuEventDestroy); GET_PROC(cuEventElapsedTime); GET_PROC(cuStreamCreate); GET_PROC(cuStreamQuery); GET_PROC(cuStreamSynchronize); GET_PROC(cuStreamDestroy); // These could be _v2 interfaces if (cudaVersion >= 4000 && __CUDA_API_VERSION >= 4000) { GET_PROC_V2(cuCtxDestroy); GET_PROC_V2(cuCtxPopCurrent); GET_PROC_V2(cuCtxPushCurrent); GET_PROC_V2(cuStreamDestroy); GET_PROC_V2(cuEventDestroy); } if (cudaVersion >= 3020 && __CUDA_API_VERSION >= 3020) { GET_PROC_V2(cuDeviceTotalMem); GET_PROC_V2(cuCtxCreate); GET_PROC_V2(cuModuleGetGlobal); GET_PROC_V2(cuMemGetInfo); GET_PROC_V2(cuMemAlloc); GET_PROC_V2(cuMemAllocPitch); GET_PROC_V2(cuMemFree); GET_PROC_V2(cuMemGetAddressRange); GET_PROC_V2(cuMemAllocHost); GET_PROC_V2(cuMemHostGetDevicePointer); GET_PROC_V2(cuMemcpyHtoD); GET_PROC_V2(cuMemcpyDtoH); GET_PROC_V2(cuMemcpyDtoD); GET_PROC_V2(cuMemcpyDtoA); GET_PROC_V2(cuMemcpyAtoD); GET_PROC_V2(cuMemcpyHtoA); GET_PROC_V2(cuMemcpyAtoH); GET_PROC_V2(cuMemcpyAtoA); GET_PROC_V2(cuMemcpy2D); GET_PROC_V2(cuMemcpy2DUnaligned); GET_PROC_V2(cuMemcpy3D); GET_PROC_V2(cuMemcpyHtoDAsync); GET_PROC_V2(cuMemcpyDtoHAsync); GET_PROC_V2(cuMemcpyHtoAAsync); GET_PROC_V2(cuMemcpyAtoHAsync); GET_PROC_V2(cuMemcpy2DAsync); GET_PROC_V2(cuMemcpy3DAsync); GET_PROC_V2(cuMemsetD8); GET_PROC_V2(cuMemsetD16); GET_PROC_V2(cuMemsetD32); GET_PROC_V2(cuMemsetD2D8); GET_PROC_V2(cuMemsetD2D16); GET_PROC_V2(cuMemsetD2D32); GET_PROC_V2(cuArrayCreate); GET_PROC_V2(cuArrayGetDescriptor); GET_PROC_V2(cuArray3DCreate); GET_PROC_V2(cuArray3DGetDescriptor); GET_PROC_V2(cuTexRefSetAddress); GET_PROC_V2(cuTexRefSetAddress2D); GET_PROC_V2(cuTexRefGetAddress); } else { GET_PROC(cuDeviceTotalMem); GET_PROC(cuCtxCreate); GET_PROC(cuModuleGetGlobal); GET_PROC(cuMemGetInfo); GET_PROC(cuMemAlloc); GET_PROC(cuMemAllocPitch); GET_PROC(cuMemFree); GET_PROC(cuMemGetAddressRange); GET_PROC(cuMemAllocHost); GET_PROC(cuMemHostGetDevicePointer); GET_PROC(cuMemcpyHtoD); GET_PROC(cuMemcpyDtoH); GET_PROC(cuMemcpyDtoD); GET_PROC(cuMemcpyDtoA); GET_PROC(cuMemcpyAtoD); GET_PROC(cuMemcpyHtoA); GET_PROC(cuMemcpyAtoH); GET_PROC(cuMemcpyAtoA); GET_PROC(cuMemcpy2D); GET_PROC(cuMemcpy2DUnaligned); GET_PROC(cuMemcpy3D); GET_PROC(cuMemcpyHtoDAsync); GET_PROC(cuMemcpyDtoHAsync); GET_PROC(cuMemcpyHtoAAsync); GET_PROC(cuMemcpyAtoHAsync); GET_PROC(cuMemcpy2DAsync); GET_PROC(cuMemcpy3DAsync); GET_PROC(cuMemsetD8); GET_PROC(cuMemsetD16); GET_PROC(cuMemsetD32); GET_PROC(cuMemsetD2D8); GET_PROC(cuMemsetD2D16); GET_PROC(cuMemsetD2D32); GET_PROC(cuArrayCreate); GET_PROC(cuArrayGetDescriptor); GET_PROC(cuArray3DCreate); GET_PROC(cuArray3DGetDescriptor); GET_PROC(cuTexRefSetAddress); GET_PROC(cuTexRefSetAddress2D); GET_PROC(cuTexRefGetAddress); } // The following functions are specific to CUDA versions if (driverVer >= 2010) { GET_PROC(cuModuleLoadDataEx); GET_PROC(cuModuleLoadFatBinary); #ifdef CUDA_INIT_OPENGL GET_PROC(cuGLCtxCreate); GET_PROC(cuGraphicsGLRegisterBuffer); GET_PROC(cuGraphicsGLRegisterImage); # ifdef WIN32 GET_PROC(cuWGLGetDevice); # endif #endif #ifdef CUDA_INIT_D3D9 GET_PROC(cuD3D9GetDevice); GET_PROC(cuD3D9CtxCreate); GET_PROC(cuGraphicsD3D9RegisterResource); #endif } if (driverVer >= 2030) { GET_PROC(cuMemHostGetFlags); #ifdef CUDA_INIT_D3D10 GET_PROC(cuD3D10GetDevice); GET_PROC(cuD3D10CtxCreate); GET_PROC(cuGraphicsD3D10RegisterResource); #endif #ifdef CUDA_INIT_OPENGL GET_PROC(cuGraphicsGLRegisterBuffer); GET_PROC(cuGraphicsGLRegisterImage); #endif } if (driverVer >= 3000) { GET_PROC(cuMemcpyDtoDAsync); GET_PROC(cuFuncSetCacheConfig); #ifdef CUDA_INIT_D3D11 GET_PROC(cuD3D11GetDevice); GET_PROC(cuD3D11CtxCreate); GET_PROC(cuGraphicsD3D11RegisterResource); #endif GET_PROC(cuGraphicsUnregisterResource); GET_PROC(cuGraphicsSubResourceGetMappedArray); if (cudaVersion >= 3020 && __CUDA_API_VERSION >= 3020) { GET_PROC_V2(cuGraphicsResourceGetMappedPointer); } else { GET_PROC(cuGraphicsResourceGetMappedPointer); } GET_PROC(cuGraphicsResourceSetMapFlags); GET_PROC(cuGraphicsMapResources); GET_PROC(cuGraphicsUnmapResources); GET_PROC(cuGetExportTable); } if (driverVer >= 3010) { GET_PROC(cuModuleGetSurfRef); GET_PROC(cuSurfRefSetArray); GET_PROC(cuSurfRefGetArray); GET_PROC(cuCtxSetLimit); GET_PROC(cuCtxGetLimit); } if (driverVer >= 4000) { GET_PROC(cuCtxSetCurrent); GET_PROC(cuCtxGetCurrent); GET_PROC(cuMemHostRegister); GET_PROC(cuMemHostUnregister); GET_PROC(cuMemcpy); GET_PROC(cuMemcpyPeer); GET_PROC(cuLaunchKernel); } return CUDA_SUCCESS; } ================================================ FILE: tests/projects/cuda/console/inc/drvapi_error_string.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef _DRVAPI_ERROR_STRING_H_ #define _DRVAPI_ERROR_STRING_H_ #include #include #include #ifdef __cuda_cuda_h__ // check to see if CUDA_H is included above // Error Code string definitions here typedef struct { char const *error_string; int error_id; } s_CudaErrorStr; /** * Error codes */ static s_CudaErrorStr sCudaDrvErrorString[] = { /** * The API call returned with no errors. In the case of query calls, this * can also mean that the operation being queried is complete (see * ::cuEventQuery() and ::cuStreamQuery()). */ { "CUDA_SUCCESS", 0 }, /** * This indicates that one or more of the parameters passed to the API call * is not within an acceptable range of values. */ { "CUDA_ERROR_INVALID_VALUE", 1 }, /** * The API call failed because it was unable to allocate enough memory to * perform the requested operation. */ { "CUDA_ERROR_OUT_OF_MEMORY", 2 }, /** * This indicates that the CUDA driver has not been initialized with * ::cuInit() or that initialization has failed. */ { "CUDA_ERROR_NOT_INITIALIZED", 3 }, /** * This indicates that the CUDA driver is in the process of shutting down. */ { "CUDA_ERROR_DEINITIALIZED", 4 }, /** * This indicates profiling APIs are called while application is running * in visual profiler mode. */ { "CUDA_ERROR_PROFILER_DISABLED", 5 }, /** * This indicates profiling has not been initialized for this context. * Call cuProfilerInitialize() to resolve this. */ { "CUDA_ERROR_PROFILER_NOT_INITIALIZED", 6 }, /** * This indicates profiler has already been started and probably * cuProfilerStart() is incorrectly called. */ { "CUDA_ERROR_PROFILER_ALREADY_STARTED", 7 }, /** * This indicates profiler has already been stopped and probably * cuProfilerStop() is incorrectly called. */ { "CUDA_ERROR_PROFILER_ALREADY_STOPPED", 8 }, /** * This indicates that no CUDA-capable devices were detected by the installed * CUDA driver. */ { "CUDA_ERROR_NO_DEVICE (no CUDA-capable devices were detected)", 100 }, /** * This indicates that the device ordinal supplied by the user does not * correspond to a valid CUDA device. */ { "CUDA_ERROR_INVALID_DEVICE (device specified is not a valid CUDA device)", 101 }, /** * This indicates that the device kernel image is invalid. This can also * indicate an invalid CUDA module. */ { "CUDA_ERROR_INVALID_IMAGE", 200 }, /** * This most frequently indicates that there is no context bound to the * current thread. This can also be returned if the context passed to an * API call is not a valid handle (such as a context that has had * ::cuCtxDestroy() invoked on it). This can also be returned if a user * mixes different API versions (i.e. 3010 context with 3020 API calls). * See ::cuCtxGetApiVersion() for more details. */ { "CUDA_ERROR_INVALID_CONTEXT", 201 }, /** * This indicated that the context being supplied as a parameter to the * API call was already the active context. * \deprecated * This error return is deprecated as of CUDA 3.2. It is no longer an * error to attempt to push the active context via ::cuCtxPushCurrent(). */ { "CUDA_ERROR_CONTEXT_ALREADY_CURRENT", 202 }, /** * This indicates that a map or register operation has failed. */ { "CUDA_ERROR_MAP_FAILED", 205 }, /** * This indicates that an unmap or unregister operation has failed. */ { "CUDA_ERROR_UNMAP_FAILED", 206 }, /** * This indicates that the specified array is currently mapped and thus * cannot be destroyed. */ { "CUDA_ERROR_ARRAY_IS_MAPPED", 207 }, /** * This indicates that the resource is already mapped. */ { "CUDA_ERROR_ALREADY_MAPPED", 208 }, /** * This indicates that there is no kernel image available that is suitable * for the device. This can occur when a user specifies code generation * options for a particular CUDA source file that do not include the * corresponding device configuration. */ { "CUDA_ERROR_NO_BINARY_FOR_GPU", 209 }, /** * This indicates that a resource has already been acquired. */ { "CUDA_ERROR_ALREADY_ACQUIRED", 210 }, /** * This indicates that a resource is not mapped. */ { "CUDA_ERROR_NOT_MAPPED", 211 }, /** * This indicates that a mapped resource is not available for access as an * array. */ { "CUDA_ERROR_NOT_MAPPED_AS_ARRAY", 212 }, /** * This indicates that a mapped resource is not available for access as a * pointer. */ { "CUDA_ERROR_NOT_MAPPED_AS_POINTER", 213 }, /** * This indicates that an uncorrectable ECC error was detected during * execution. */ { "CUDA_ERROR_ECC_UNCORRECTABLE", 214 }, /** * This indicates that the ::CUlimit passed to the API call is not * supported by the active device. */ { "CUDA_ERROR_UNSUPPORTED_LIMIT", 215 }, /** * This indicates that the ::CUcontext passed to the API call can * only be bound to a single CPU thread at a time but is already * bound to a CPU thread. */ { "CUDA_ERROR_CONTEXT_ALREADY_IN_USE", 216 }, /** * This indicates that peer access is not supported across the given * devices. */ { "CUDA_ERROR_PEER_ACCESS_UNSUPPORTED", 217 }, /** * This indicates that a PTX JIT compilation failed. */ { "CUDA_ERROR_INVALID_PTX", 218 }, /** * This indicates an error with OpenGL or DirectX context. */ { "CUDA_ERROR_INVALID_GRAPHICS_CONTEXT", 219 }, /** * This indicates that an uncorrectable NVLink error was detected during the * execution. */ { "CUDA_ERROR_NVLINK_UNCORRECTABLE", 220 }, /** * This indicates that the PTX JIT compiler library was not found. */ { "CUDA_ERROR_JIT_COMPILER_NOT_FOUND", 221 }, /** * This indicates that the device kernel source is invalid. */ { "CUDA_ERROR_INVALID_SOURCE", 300 }, /** * This indicates that the file specified was not found. */ { "CUDA_ERROR_FILE_NOT_FOUND", 301 }, /** * This indicates that a link to a shared object failed to resolve. */ { "CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND", 302 }, /** * This indicates that initialization of a shared object failed. */ { "CUDA_ERROR_SHARED_OBJECT_INIT_FAILED", 303 }, /** * This indicates that an OS call failed. */ { "CUDA_ERROR_OPERATING_SYSTEM", 304 }, /** * This indicates that a resource handle passed to the API call was not * valid. Resource handles are opaque types like ::CUstream and ::CUevent. */ { "CUDA_ERROR_INVALID_HANDLE", 400 }, /** * This indicates that a named symbol was not found. Examples of symbols * are global/constant variable names, texture names }, and surface names. */ { "CUDA_ERROR_NOT_FOUND", 500 }, /** * This indicates that asynchronous operations issued previously have not * completed yet. This result is not actually an error, but must be indicated * differently than ::CUDA_SUCCESS (which indicates completion). Calls that * may return this value include ::cuEventQuery() and ::cuStreamQuery(). */ { "CUDA_ERROR_NOT_READY", 600 }, /** * While executing a kernel, the device encountered a * load or store instruction on an invalid memory address. * This leaves the process in an inconsistent state and any further CUDA work * will return the same error. To continue using CUDA, the process must be terminated * and relaunched. */ { "CUDA_ERROR_ILLEGAL_ADDRESS", 700 }, /** * This indicates that a launch did not occur because it did not have * appropriate resources. This error usually indicates that the user has * attempted to pass too many arguments to the device kernel, or the * kernel launch specifies too many threads for the kernel's register * count. Passing arguments of the wrong size (i.e. a 64-bit pointer * when a 32-bit int is expected) is equivalent to passing too many * arguments and can also result in this error. */ { "CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES", 701 }, /** * This indicates that the device kernel took too long to execute. This can * only occur if timeouts are enabled - see the device attribute * ::CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT for more information. The * context cannot be used (and must be destroyed similar to * ::CUDA_ERROR_LAUNCH_FAILED). All existing device memory allocations from * this context are invalid and must be reconstructed if the program is to * continue using CUDA. */ { "CUDA_ERROR_LAUNCH_TIMEOUT", 702 }, /** * This error indicates a kernel launch that uses an incompatible texturing * mode. */ { "CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING", 703 }, /** * This error indicates that a call to ::cuCtxEnablePeerAccess() is * trying to re-enable peer access to a context which has already * had peer access to it enabled. */ { "CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED", 704 }, /** * This error indicates that ::cuCtxDisablePeerAccess() is * trying to disable peer access which has not been enabled yet * via ::cuCtxEnablePeerAccess(). */ { "CUDA_ERROR_PEER_ACCESS_NOT_ENABLED", 705 }, /** * This error indicates that the primary context for the specified device * has already been initialized. */ { "CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE", 708 }, /** * This error indicates that the context current to the calling thread * has been destroyed using ::cuCtxDestroy }, or is a primary context which * has not yet been initialized. */ { "CUDA_ERROR_CONTEXT_IS_DESTROYED", 709 }, /** * A device-side assert triggered during kernel execution. The context * cannot be used anymore, and must be destroyed. All existing device * memory allocations from this context are invalid and must be * reconstructed if the program is to continue using CUDA. */ { "CUDA_ERROR_ASSERT", 710 }, /** * This error indicates that the hardware resources required to enable * peer access have been exhausted for one or more of the devices * passed to ::cuCtxEnablePeerAccess(). */ { "CUDA_ERROR_TOO_MANY_PEERS", 711 }, /** * This error indicates that the memory range passed to ::cuMemHostRegister() * has already been registered. */ { "CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED", 712 }, /** * This error indicates that the pointer passed to ::cuMemHostUnregister() * does not correspond to any currently registered memory region. */ { "CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED", 713 }, /** * While executing a kernel, the device encountered a stack error. * This can be due to stack corruption or exceeding the stack size limit. * This leaves the process in an inconsistent state and any further CUDA work * will return the same error. To continue using CUDA, the process must be terminated * and relaunched. */ { "CUDA_ERROR_HARDWARE_STACK_ERROR", 714 }, /** * While executing a kernel, the device encountered an illegal instruction. * This leaves the process in an inconsistent state and any further CUDA work * will return the same error. To continue using CUDA, the process must be terminated * and relaunched. */ { "CUDA_ERROR_ILLEGAL_INSTRUCTION", 715 }, /** * While executing a kernel, the device encountered a load or store instruction * on a memory address which is not aligned. * This leaves the process in an inconsistent state and any further CUDA work * will return the same error. To continue using CUDA, the process must be terminated * and relaunched. */ { "CUDA_ERROR_MISALIGNED_ADDRESS", 716 }, /** * While executing a kernel, the device encountered an instruction * which can only operate on memory locations in certain address spaces * (global, shared, or local), but was supplied a memory address not * belonging to an allowed address space. * This leaves the process in an inconsistent state and any further CUDA work * will return the same error. To continue using CUDA, the process must be terminated * and relaunched. */ { "CUDA_ERROR_INVALID_ADDRESS_SPACE", 717 }, /** * While executing a kernel, the device program counter wrapped its address space. * This leaves the process in an inconsistent state and any further CUDA work * will return the same error. To continue using CUDA, the process must be terminated * and relaunched. */ { "CUDA_ERROR_INVALID_PC", 718 }, /** * An exception occurred on the device while executing a kernel. Common * causes include dereferencing an invalid device pointer and accessing * out of bounds shared memory. The context cannot be used }, so it must * be destroyed (and a new one should be created). All existing device * memory allocations from this context are invalid and must be * reconstructed if the program is to continue using CUDA. */ { "CUDA_ERROR_LAUNCH_FAILED", 719 }, /** * This error indicates that the number of blocks launched per grid for a kernel that was * launched via either ::cuLaunchCooperativeKernel or ::cuLaunchCooperativeKernelMultiDevice * exceeds the maximum number of blocks as allowed by ::cuOccupancyMaxActiveBlocksPerMultiprocessor * or ::cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags times the number of multiprocessors * as specified by the device attribute ::CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT. */ { "CUDA_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE", 720 }, /** * This error indicates that the attempted operation is not permitted. */ { "CUDA_ERROR_NOT_PERMITTED", 800 }, /** * This error indicates that the attempted operation is not supported * on the current system or device. */ { "CUDA_ERROR_NOT_SUPPORTED", 801 }, /** * This indicates that an unknown internal error has occurred. */ { "CUDA_ERROR_UNKNOWN", 999 }, { NULL, -1 } }; // This is just a linear search through the array, since the error_id's are not // always ocurring consecutively inline const char *getCudaDrvErrorString(CUresult error_id) { int index = 0; while (sCudaDrvErrorString[index].error_id != error_id && sCudaDrvErrorString[index].error_id != -1) { index++; } if (sCudaDrvErrorString[index].error_id == error_id) return (const char *)sCudaDrvErrorString[index].error_string; else return (const char *)"CUDA_ERROR not found!"; } #endif // __cuda_cuda_h__ #endif ================================================ FILE: tests/projects/cuda/console/inc/dynlink/cuda_drvapi_dynlink.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef __cuda_drvapi_dynlink_h__ #define __cuda_drvapi_dynlink_h__ #include "cuda_drvapi_dynlink_cuda.h" #if defined(CUDA_INIT_D3D9)||defined(CUDA_INIT_D3D10)||defined(CUDA_INIT_D3D11) #include "cuda_drvapi_dynlink_d3d.h" #endif #ifdef CUDA_INIT_OPENGL #include "cuda_drvapi_dynlink_gl.h" #endif #endif //__cuda_drvapi_dynlink_h__ ================================================ FILE: tests/projects/cuda/console/inc/dynlink/cuda_drvapi_dynlink_cuda.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef __cuda_drvapi_dynlink_cuda_h__ #define __cuda_drvapi_dynlink_cuda_h__ #include /** * CUDA API versioning support */ #define __CUDA_API_VERSION 4000 /** * \defgroup CUDA_DRIVER CUDA Driver API * * This section describes the low-level CUDA driver application programming * interface. * * @{ */ /** * \defgroup CUDA_TYPES Data types used by CUDA driver * @{ */ /** * CUDA API version number */ #define CUDA_VERSION 3020 /* 3.2 */ #ifdef __cplusplus extern "C" { #endif /** * CUDA device pointer */ #if __CUDA_API_VERSION >= 3020 #if defined(_WIN64) || defined(__LP64__) typedef unsigned long long CUdeviceptr; #else typedef unsigned int CUdeviceptr; #endif #endif /* __CUDA_API_VERSION >= 3020 */ typedef int CUdevice; /**< CUDA device */ typedef struct CUctx_st *CUcontext; /**< CUDA context */ typedef struct CUmod_st *CUmodule; /**< CUDA module */ typedef struct CUfunc_st *CUfunction; /**< CUDA function */ typedef struct CUarray_st *CUarray; /**< CUDA array */ typedef struct CUtexref_st *CUtexref; /**< CUDA texture reference */ typedef struct CUsurfref_st *CUsurfref; /**< CUDA surface reference */ typedef struct CUevent_st *CUevent; /**< CUDA event */ typedef struct CUstream_st *CUstream; /**< CUDA stream */ typedef struct CUgraphicsResource_st *CUgraphicsResource; /**< CUDA graphics interop resource */ typedef struct CUuuid_st /**< CUDA definition of UUID */ { char bytes[16]; } CUuuid; /** * Context creation flags */ typedef enum CUctx_flags_enum { CU_CTX_SCHED_AUTO = 0x00, /**< Automatic scheduling */ CU_CTX_SCHED_SPIN = 0x01, /**< Set spin as default scheduling */ CU_CTX_SCHED_YIELD = 0x02, /**< Set yield as default scheduling */ CU_CTX_SCHED_BLOCKING_SYNC = 0x04, /**< Set blocking synchronization as default scheduling */ CU_CTX_BLOCKING_SYNC = 0x04, /**< Set blocking synchronization as default scheduling \deprecated */ CU_CTX_MAP_HOST = 0x08, /**< Support mapped pinned allocations */ CU_CTX_LMEM_RESIZE_TO_MAX = 0x10, /**< Keep local memory allocation after launch */ #if __CUDA_API_VERSION < 4000 CU_CTX_SCHED_MASK = 0x03, CU_CTX_FLAGS_MASK = 0x1f #else CU_CTX_SCHED_MASK = 0x07, CU_CTX_PRIMARY = 0x20, /**< Initialize and return the primary context */ CU_CTX_FLAGS_MASK = 0x3f #endif } CUctx_flags; /** * Event creation flags */ typedef enum CUevent_flags_enum { CU_EVENT_DEFAULT = 0, /**< Default event flag */ CU_EVENT_BLOCKING_SYNC = 1, /**< Event uses blocking synchronization */ CU_EVENT_DISABLE_TIMING = 2 /**< Event will not record timing data */ } CUevent_flags; /** * Array formats */ typedef enum CUarray_format_enum { CU_AD_FORMAT_UNSIGNED_INT8 = 0x01, /**< Unsigned 8-bit integers */ CU_AD_FORMAT_UNSIGNED_INT16 = 0x02, /**< Unsigned 16-bit integers */ CU_AD_FORMAT_UNSIGNED_INT32 = 0x03, /**< Unsigned 32-bit integers */ CU_AD_FORMAT_SIGNED_INT8 = 0x08, /**< Signed 8-bit integers */ CU_AD_FORMAT_SIGNED_INT16 = 0x09, /**< Signed 16-bit integers */ CU_AD_FORMAT_SIGNED_INT32 = 0x0a, /**< Signed 32-bit integers */ CU_AD_FORMAT_HALF = 0x10, /**< 16-bit floating point */ CU_AD_FORMAT_FLOAT = 0x20 /**< 32-bit floating point */ } CUarray_format; /** * Texture reference addressing modes */ typedef enum CUaddress_mode_enum { CU_TR_ADDRESS_MODE_WRAP = 0, /**< Wrapping address mode */ CU_TR_ADDRESS_MODE_CLAMP = 1, /**< Clamp to edge address mode */ CU_TR_ADDRESS_MODE_MIRROR = 2, /**< Mirror address mode */ CU_TR_ADDRESS_MODE_BORDER = 3 /**< Border address mode */ } CUaddress_mode; /** * Texture reference filtering modes */ typedef enum CUfilter_mode_enum { CU_TR_FILTER_MODE_POINT = 0, /**< Point filter mode */ CU_TR_FILTER_MODE_LINEAR = 1 /**< Linear filter mode */ } CUfilter_mode; /** * Device properties */ typedef enum CUdevice_attribute_enum { CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK = 1, /**< Maximum number of threads per block */ CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X = 2, /**< Maximum block dimension X */ CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y = 3, /**< Maximum block dimension Y */ CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z = 4, /**< Maximum block dimension Z */ CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X = 5, /**< Maximum grid dimension X */ CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y = 6, /**< Maximum grid dimension Y */ CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z = 7, /**< Maximum grid dimension Z */ CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK = 8, /**< Maximum shared memory available per block in bytes */ CU_DEVICE_ATTRIBUTE_SHARED_MEMORY_PER_BLOCK = 8, /**< Deprecated, use CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK */ CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY = 9, /**< Memory available on device for __constant__ variables in a CUDA C kernel in bytes */ CU_DEVICE_ATTRIBUTE_WARP_SIZE = 10, /**< Warp size in threads */ CU_DEVICE_ATTRIBUTE_MAX_PITCH = 11, /**< Maximum pitch in bytes allowed by memory copies */ CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK = 12, /**< Maximum number of 32-bit registers available per block */ CU_DEVICE_ATTRIBUTE_REGISTERS_PER_BLOCK = 12, /**< Deprecated, use CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK */ CU_DEVICE_ATTRIBUTE_CLOCK_RATE = 13, /**< Peak clock frequency in kilohertz */ CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT = 14, /**< Alignment requirement for textures */ CU_DEVICE_ATTRIBUTE_GPU_OVERLAP = 15, /**< Device can possibly copy memory and execute a kernel concurrently */ CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT = 16, /**< Number of multiprocessors on device */ CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT = 17, /**< Specifies whether there is a run time limit on kernels */ CU_DEVICE_ATTRIBUTE_INTEGRATED = 18, /**< Device is integrated with host memory */ CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY = 19, /**< Device can map host memory into CUDA address space */ CU_DEVICE_ATTRIBUTE_COMPUTE_MODE = 20, /**< Compute mode (See ::CUcomputemode for details) */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_WIDTH = 21, /**< Maximum 1D texture width */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_WIDTH = 22, /**< Maximum 2D texture width */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_HEIGHT = 23, /**< Maximum 2D texture height */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_WIDTH = 24, /**< Maximum 3D texture width */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_HEIGHT = 25, /**< Maximum 3D texture height */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_DEPTH = 26, /**< Maximum 3D texture depth */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_WIDTH = 27, /**< Maximum texture array width */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_HEIGHT = 28, /**< Maximum texture array height */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_NUMSLICES = 29, /**< Maximum slices in a texture array */ CU_DEVICE_ATTRIBUTE_SURFACE_ALIGNMENT = 30, /**< Alignment requirement for surfaces */ CU_DEVICE_ATTRIBUTE_CONCURRENT_KERNELS = 31, /**< Device can possibly execute multiple kernels concurrently */ CU_DEVICE_ATTRIBUTE_ECC_ENABLED = 32, /**< Device has ECC support enabled */ CU_DEVICE_ATTRIBUTE_PCI_BUS_ID = 33, /**< PCI bus ID of the device */ CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID = 34, /**< PCI device ID of the device */ CU_DEVICE_ATTRIBUTE_TCC_DRIVER = 35 /**< Device is using TCC driver model */ #if __CUDA_API_VERSION >= 4000 , CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE = 36, /**< Peak memory clock frequency in kilohertz */ CU_DEVICE_ATTRIBUTE_GLOBAL_MEMORY_BUS_WIDTH = 37, /**< Global memory bus width in bits */ CU_DEVICE_ATTRIBUTE_L2_CACHE_SIZE = 38, /**< Size of L2 cache in bytes */ CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR = 39, /**< Maximum resident threads per multiprocessor */ CU_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT = 40, /**< Number of asynchronous engines */ CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING = 41, /**< Device uses shares a unified address space with the host */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_LAYERED_WIDTH = 42, /**< Maximum 1D layered texture width */ CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_LAYERED_LAYERS = 43 /**< Maximum layers in a 1D layered texture */ #endif } CUdevice_attribute; /** * Legacy device properties */ typedef struct CUdevprop_st { int maxThreadsPerBlock; /**< Maximum number of threads per block */ int maxThreadsDim[3]; /**< Maximum size of each dimension of a block */ int maxGridSize[3]; /**< Maximum size of each dimension of a grid */ int sharedMemPerBlock; /**< Shared memory available per block in bytes */ int totalConstantMemory; /**< Constant memory available on device in bytes */ int SIMDWidth; /**< Warp size in threads */ int memPitch; /**< Maximum pitch in bytes allowed by memory copies */ int regsPerBlock; /**< 32-bit registers available per block */ int clockRate; /**< Clock frequency in kilohertz */ int textureAlign; /**< Alignment requirement for textures */ } CUdevprop; /** * Function properties */ typedef enum CUfunction_attribute_enum { /** * The maximum number of threads per block, beyond which a launch of the * function would fail. This number depends on both the function and the * device on which the function is currently loaded. */ CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK = 0, /** * The size in bytes of statically-allocated shared memory required by * this function. This does not include dynamically-allocated shared * memory requested by the user at runtime. */ CU_FUNC_ATTRIBUTE_SHARED_SIZE_BYTES = 1, /** * The size in bytes of user-allocated constant memory required by this * function. */ CU_FUNC_ATTRIBUTE_CONST_SIZE_BYTES = 2, /** * The size in bytes of local memory used by each thread of this function. */ CU_FUNC_ATTRIBUTE_LOCAL_SIZE_BYTES = 3, /** * The number of registers used by each thread of this function. */ CU_FUNC_ATTRIBUTE_NUM_REGS = 4, /** * The PTX virtual architecture version for which the function was * compiled. This value is the major PTX version * 10 + the minor PTX * version, so a PTX version 1.3 function would return the value 13. * Note that this may return the undefined value of 0 for cubins * compiled prior to CUDA 3.0. */ CU_FUNC_ATTRIBUTE_PTX_VERSION = 5, /** * The binary architecture version for which the function was compiled. * This value is the major binary version * 10 + the minor binary version, * so a binary version 1.3 function would return the value 13. Note that * this will return a value of 10 for legacy cubins that do not have a * properly-encoded binary architecture version. */ CU_FUNC_ATTRIBUTE_BINARY_VERSION = 6, CU_FUNC_ATTRIBUTE_MAX } CUfunction_attribute; /** * Function cache configurations */ typedef enum CUfunc_cache_enum { CU_FUNC_CACHE_PREFER_NONE = 0x00, /**< no preference for shared memory or L1 (default) */ CU_FUNC_CACHE_PREFER_SHARED = 0x01, /**< prefer larger shared memory and smaller L1 cache */ CU_FUNC_CACHE_PREFER_L1 = 0x02 /**< prefer larger L1 cache and smaller shared memory */ } CUfunc_cache; /** * Memory types */ typedef enum CUmemorytype_enum { CU_MEMORYTYPE_HOST = 0x01, /**< Host memory */ CU_MEMORYTYPE_DEVICE = 0x02, /**< Device memory */ CU_MEMORYTYPE_ARRAY = 0x03 /**< Array memory */ #if __CUDA_API_VERSION >= 4000 , CU_MEMORYTYPE_UNIFIED = 0x04 /**< Unified device or host memory */ #endif } CUmemorytype; /** * Compute Modes */ typedef enum CUcomputemode_enum { CU_COMPUTEMODE_DEFAULT = 0, /**< Default compute mode (Multiple contexts allowed per device) */ CU_COMPUTEMODE_EXCLUSIVE = 1, /**< Compute-exclusive-thread mode (Only one context used by a single thread can be present on this device at a time) */ CU_COMPUTEMODE_PROHIBITED = 2 /**< Compute-prohibited mode (No contexts can be created on this device at this time) */ #if __CUDA_API_VERSION >= 4000 , CU_COMPUTEMODE_EXCLUSIVE_PROCESS = 3 /**< Compute-exclusive-process mode (Only one context used by a single process can be present on this device at a time) */ #endif } CUcomputemode; /** * Online compiler options */ typedef enum CUjit_option_enum { /** * Max number of registers that a thread may use.\n * Option type: unsigned int */ CU_JIT_MAX_REGISTERS = 0, /** * IN: Specifies minimum number of threads per block to target compilation * for\n * OUT: Returns the number of threads the compiler actually targeted. * This restricts the resource utilization fo the compiler (e.g. max * registers) such that a block with the given number of threads should be * able to launch based on register limitations. Note, this option does not * currently take into account any other resource limitations, such as * shared memory utilization.\n * Option type: unsigned int */ CU_JIT_THREADS_PER_BLOCK, /** * Returns a float value in the option of the wall clock time, in * milliseconds, spent creating the cubin\n * Option type: float */ CU_JIT_WALL_TIME, /** * Pointer to a buffer in which to print any log messsages from PTXAS * that are informational in nature (the buffer size is specified via * option ::CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES) \n * Option type: char* */ CU_JIT_INFO_LOG_BUFFER, /** * IN: Log buffer size in bytes. Log messages will be capped at this size * (including null terminator)\n * OUT: Amount of log buffer filled with messages\n * Option type: unsigned int */ CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES, /** * Pointer to a buffer in which to print any log messages from PTXAS that * reflect errors (the buffer size is specified via option * ::CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES)\n * Option type: char* */ CU_JIT_ERROR_LOG_BUFFER, /** * IN: Log buffer size in bytes. Log messages will be capped at this size * (including null terminator)\n * OUT: Amount of log buffer filled with messages\n * Option type: unsigned int */ CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES, /** * Level of optimizations to apply to generated code (0 - 4), with 4 * being the default and highest level of optimizations.\n * Option type: unsigned int */ CU_JIT_OPTIMIZATION_LEVEL, /** * No option value required. Determines the target based on the current * attached context (default)\n * Option type: No option value needed */ CU_JIT_TARGET_FROM_CUCONTEXT, /** * Target is chosen based on supplied ::CUjit_target_enum.\n * Option type: unsigned int for enumerated type ::CUjit_target_enum */ CU_JIT_TARGET, /** * Specifies choice of fallback strategy if matching cubin is not found. * Choice is based on supplied ::CUjit_fallback_enum.\n * Option type: unsigned int for enumerated type ::CUjit_fallback_enum */ CU_JIT_FALLBACK_STRATEGY } CUjit_option; /** * Online compilation targets */ typedef enum CUjit_target_enum { CU_TARGET_COMPUTE_10 = 0, /**< Compute device class 1.0 */ CU_TARGET_COMPUTE_11, /**< Compute device class 1.1 */ CU_TARGET_COMPUTE_12, /**< Compute device class 1.2 */ CU_TARGET_COMPUTE_13, /**< Compute device class 1.3 */ CU_TARGET_COMPUTE_20, /**< Compute device class 2.0 */ CU_TARGET_COMPUTE_21 /**< Compute device class 2.1 */ } CUjit_target; /** * Cubin matching fallback strategies */ typedef enum CUjit_fallback_enum { CU_PREFER_PTX = 0, /**< Prefer to compile ptx */ CU_PREFER_BINARY /**< Prefer to fall back to compatible binary code */ } CUjit_fallback; /** * Flags to register a graphics resource */ typedef enum CUgraphicsRegisterFlags_enum { CU_GRAPHICS_REGISTER_FLAGS_NONE = 0x00, CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY = 0x01, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD = 0x02, CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LDST = 0x04 } CUgraphicsRegisterFlags; /** * Flags for mapping and unmapping interop resources */ typedef enum CUgraphicsMapResourceFlags_enum { CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE = 0x00, CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY = 0x01, CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD = 0x02 } CUgraphicsMapResourceFlags; /** * Array indices for cube faces */ typedef enum CUarray_cubemap_face_enum { CU_CUBEMAP_FACE_POSITIVE_X = 0x00, /**< Positive X face of cubemap */ CU_CUBEMAP_FACE_NEGATIVE_X = 0x01, /**< Negative X face of cubemap */ CU_CUBEMAP_FACE_POSITIVE_Y = 0x02, /**< Positive Y face of cubemap */ CU_CUBEMAP_FACE_NEGATIVE_Y = 0x03, /**< Negative Y face of cubemap */ CU_CUBEMAP_FACE_POSITIVE_Z = 0x04, /**< Positive Z face of cubemap */ CU_CUBEMAP_FACE_NEGATIVE_Z = 0x05 /**< Negative Z face of cubemap */ } CUarray_cubemap_face; /** * Limits */ typedef enum CUlimit_enum { CU_LIMIT_STACK_SIZE = 0x00, /**< GPU thread stack size */ CU_LIMIT_PRINTF_FIFO_SIZE = 0x01, /**< GPU printf FIFO size */ CU_LIMIT_MALLOC_HEAP_SIZE = 0x02 /**< GPU malloc heap size */ } CUlimit; /** * Error codes */ typedef enum cudaError_enum { /** * The API call returned with no errors. In the case of query calls, this * can also mean that the operation being queried is complete (see * ::cuEventQuery() and ::cuStreamQuery()). */ CUDA_SUCCESS = 0, /** * This indicates that one or more of the parameters passed to the API call * is not within an acceptable range of values. */ CUDA_ERROR_INVALID_VALUE = 1, /** * The API call failed because it was unable to allocate enough memory to * perform the requested operation. */ CUDA_ERROR_OUT_OF_MEMORY = 2, /** * This indicates that the CUDA driver has not been initialized with * ::cuInit() or that initialization has failed. */ CUDA_ERROR_NOT_INITIALIZED = 3, /** * This indicates that the CUDA driver is in the process of shutting down. */ CUDA_ERROR_DEINITIALIZED = 4, /** * This indicates profiling APIs are called while application is running * in visual profiler mode. */ CUDA_ERROR_PROFILER_DISABLED = 5, /** * This indicates profiling has not been initialized for this context. * Call cuProfilerInitialize() to resolve this. */ CUDA_ERROR_PROFILER_NOT_INITIALIZED = 6, /** * This indicates profiler has already been started and probably * cuProfilerStart() is incorrectly called. */ CUDA_ERROR_PROFILER_ALREADY_STARTED = 7, /** * This indicates profiler has already been stopped and probably * cuProfilerStop() is incorrectly called. */ CUDA_ERROR_PROFILER_ALREADY_STOPPED = 8, /** * This indicates that no CUDA-capable devices were detected by the installed * CUDA driver. */ CUDA_ERROR_NO_DEVICE = 100, /** * This indicates that the device ordinal supplied by the user does not * correspond to a valid CUDA device. */ CUDA_ERROR_INVALID_DEVICE = 101, /** * This indicates that the device kernel image is invalid. This can also * indicate an invalid CUDA module. */ CUDA_ERROR_INVALID_IMAGE = 200, /** * This most frequently indicates that there is no context bound to the * current thread. This can also be returned if the context passed to an * API call is not a valid handle (such as a context that has had * ::cuCtxDestroy() invoked on it). This can also be returned if a user * mixes different API versions (i.e. 3010 context with 3020 API calls). * See ::cuCtxGetApiVersion() for more details. */ CUDA_ERROR_INVALID_CONTEXT = 201, /** * This indicated that the context being supplied as a parameter to the * API call was already the active context. * \deprecated * This error return is deprecated as of CUDA 3.2. It is no longer an * error to attempt to push the active context via ::cuCtxPushCurrent(). */ CUDA_ERROR_CONTEXT_ALREADY_CURRENT = 202, /** * This indicates that a map or register operation has failed. */ CUDA_ERROR_MAP_FAILED = 205, /** * This indicates that an unmap or unregister operation has failed. */ CUDA_ERROR_UNMAP_FAILED = 206, /** * This indicates that the specified array is currently mapped and thus * cannot be destroyed. */ CUDA_ERROR_ARRAY_IS_MAPPED = 207, /** * This indicates that the resource is already mapped. */ CUDA_ERROR_ALREADY_MAPPED = 208, /** * This indicates that there is no kernel image available that is suitable * for the device. This can occur when a user specifies code generation * options for a particular CUDA source file that do not include the * corresponding device configuration. */ CUDA_ERROR_NO_BINARY_FOR_GPU = 209, /** * This indicates that a resource has already been acquired. */ CUDA_ERROR_ALREADY_ACQUIRED = 210, /** * This indicates that a resource is not mapped. */ CUDA_ERROR_NOT_MAPPED = 211, /** * This indicates that a mapped resource is not available for access as an * array. */ CUDA_ERROR_NOT_MAPPED_AS_ARRAY = 212, /** * This indicates that a mapped resource is not available for access as a * pointer. */ CUDA_ERROR_NOT_MAPPED_AS_POINTER = 213, /** * This indicates that an uncorrectable ECC error was detected during * execution. */ CUDA_ERROR_ECC_UNCORRECTABLE = 214, /** * This indicates that the ::CUlimit passed to the API call is not * supported by the active device. */ CUDA_ERROR_UNSUPPORTED_LIMIT = 215, /** * This indicates that the ::CUcontext passed to the API call can * only be bound to a single CPU thread at a time but is already * bound to a CPU thread. */ CUDA_ERROR_CONTEXT_ALREADY_IN_USE = 216, /** * This indicates that the device kernel source is invalid. */ CUDA_ERROR_INVALID_SOURCE = 300, /** * This indicates that the file specified was not found. */ CUDA_ERROR_FILE_NOT_FOUND = 301, /** * This indicates that a link to a shared object failed to resolve. */ CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND = 302, /** * This indicates that initialization of a shared object failed. */ CUDA_ERROR_SHARED_OBJECT_INIT_FAILED = 303, /** * This indicates that an OS call failed. */ CUDA_ERROR_OPERATING_SYSTEM = 304, /** * This indicates that a resource handle passed to the API call was not * valid. Resource handles are opaque types like ::CUstream and ::CUevent. */ CUDA_ERROR_INVALID_HANDLE = 400, /** * This indicates that a named symbol was not found. Examples of symbols * are global/constant variable names, texture names, and surface names. */ CUDA_ERROR_NOT_FOUND = 500, /** * This indicates that asynchronous operations issued previously have not * completed yet. This result is not actually an error, but must be indicated * differently than ::CUDA_SUCCESS (which indicates completion). Calls that * may return this value include ::cuEventQuery() and ::cuStreamQuery(). */ CUDA_ERROR_NOT_READY = 600, /** * An exception occurred on the device while executing a kernel. Common * causes include dereferencing an invalid device pointer and accessing * out of bounds shared memory. The context cannot be used, so it must * be destroyed (and a new one should be created). All existing device * memory allocations from this context are invalid and must be * reconstructed if the program is to continue using CUDA. */ CUDA_ERROR_LAUNCH_FAILED = 700, /** * This indicates that a launch did not occur because it did not have * appropriate resources. This error usually indicates that the user has * attempted to pass too many arguments to the device kernel, or the * kernel launch specifies too many threads for the kernel's register * count. Passing arguments of the wrong size (i.e. a 64-bit pointer * when a 32-bit int is expected) is equivalent to passing too many * arguments and can also result in this error. */ CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES = 701, /** * This indicates that the device kernel took too long to execute. This can * only occur if timeouts are enabled - see the device attribute * ::CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT for more information. The * context cannot be used (and must be destroyed similar to * ::CUDA_ERROR_LAUNCH_FAILED). All existing device memory allocations from * this context are invalid and must be reconstructed if the program is to * continue using CUDA. */ CUDA_ERROR_LAUNCH_TIMEOUT = 702, /** * This error indicates a kernel launch that uses an incompatible texturing * mode. */ CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING = 703, /** * This error indicates that a call to ::cuCtxEnablePeerAccess() is * trying to re-enable peer access to a context which has already * had peer access to it enabled. */ CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED = 704, /** * This error indicates that a call to ::cuMemPeerRegister is trying to * register memory from a context which has not had peer access * enabled yet via ::cuCtxEnablePeerAccess(), or that * ::cuCtxDisablePeerAccess() is trying to disable peer access * which has not been enabled yet. */ CUDA_ERROR_PEER_ACCESS_NOT_ENABLED = 705, /** * This error indicates that a call to ::cuMemPeerRegister is trying to * register already-registered memory. */ CUDA_ERROR_PEER_MEMORY_ALREADY_REGISTERED = 706, /** * This error indicates that a call to ::cuMemPeerUnregister is trying to * unregister memory that has not been registered. */ CUDA_ERROR_PEER_MEMORY_NOT_REGISTERED = 707, /** * This error indicates that ::cuCtxCreate was called with the flag * ::CU_CTX_PRIMARY on a device which already has initialized its * primary context. */ CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE = 708, /** * This error indicates that the context current to the calling thread * has been destroyed using ::cuCtxDestroy, or is a primary context which * has not yet been initialized. */ CUDA_ERROR_CONTEXT_IS_DESTROYED = 709, /** * This indicates that an unknown internal error has occurred. */ CUDA_ERROR_UNKNOWN = 999 } CUresult; #if __CUDA_API_VERSION >= 4000 /** * If set, host memory is portable between CUDA contexts. * Flag for ::cuMemHostAlloc() */ #define CU_MEMHOSTALLOC_PORTABLE 0x01 /** * If set, host memory is mapped into CUDA address space and * ::cuMemHostGetDevicePointer() may be called on the host pointer. * Flag for ::cuMemHostAlloc() */ #define CU_MEMHOSTALLOC_DEVICEMAP 0x02 /** * If set, host memory is allocated as write-combined - fast to write, * faster to DMA, slow to read except via SSE4 streaming load instruction * (MOVNTDQA). * Flag for ::cuMemHostAlloc() */ #define CU_MEMHOSTALLOC_WRITECOMBINED 0x04 /** * If set, host memory is portable between CUDA contexts. * Flag for ::cuMemHostRegister() */ #define CU_MEMHOSTREGISTER_PORTABLE 0x01 /** * If set, host memory is mapped into CUDA address space and * ::cuMemHostGetDevicePointer() may be called on the host pointer. * Flag for ::cuMemHostRegister() */ #define CU_MEMHOSTREGISTER_DEVICEMAP 0x02 /** * If set, peer memory is mapped into CUDA address space and * ::cuMemPeerGetDevicePointer() may be called on the host pointer. * Flag for ::cuMemPeerRegister() */ #define CU_MEMPEERREGISTER_DEVICEMAP 0x02 #endif #if __CUDA_API_VERSION >= 3020 /** * 2D memory copy parameters */ typedef struct CUDA_MEMCPY2D_st { size_t srcXInBytes; /**< Source X in bytes */ size_t srcY; /**< Source Y */ CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */ const void *srcHost; /**< Source host pointer */ CUdeviceptr srcDevice; /**< Source device pointer */ CUarray srcArray; /**< Source array reference */ size_t srcPitch; /**< Source pitch (ignored when src is array) */ size_t dstXInBytes; /**< Destination X in bytes */ size_t dstY; /**< Destination Y */ CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */ void *dstHost; /**< Destination host pointer */ CUdeviceptr dstDevice; /**< Destination device pointer */ CUarray dstArray; /**< Destination array reference */ size_t dstPitch; /**< Destination pitch (ignored when dst is array) */ size_t WidthInBytes; /**< Width of 2D memory copy in bytes */ size_t Height; /**< Height of 2D memory copy */ } CUDA_MEMCPY2D; /** * 3D memory copy parameters */ typedef struct CUDA_MEMCPY3D_st { size_t srcXInBytes; /**< Source X in bytes */ size_t srcY; /**< Source Y */ size_t srcZ; /**< Source Z */ size_t srcLOD; /**< Source LOD */ CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */ const void *srcHost; /**< Source host pointer */ CUdeviceptr srcDevice; /**< Source device pointer */ CUarray srcArray; /**< Source array reference */ void *reserved0; /**< Must be NULL */ size_t srcPitch; /**< Source pitch (ignored when src is array) */ size_t srcHeight; /**< Source height (ignored when src is array; may be 0 if Depth==1) */ size_t dstXInBytes; /**< Destination X in bytes */ size_t dstY; /**< Destination Y */ size_t dstZ; /**< Destination Z */ size_t dstLOD; /**< Destination LOD */ CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */ void *dstHost; /**< Destination host pointer */ CUdeviceptr dstDevice; /**< Destination device pointer */ CUarray dstArray; /**< Destination array reference */ void *reserved1; /**< Must be NULL */ size_t dstPitch; /**< Destination pitch (ignored when dst is array) */ size_t dstHeight; /**< Destination height (ignored when dst is array; may be 0 if Depth==1) */ size_t WidthInBytes; /**< Width of 3D memory copy in bytes */ size_t Height; /**< Height of 3D memory copy */ size_t Depth; /**< Depth of 3D memory copy */ } CUDA_MEMCPY3D; /** * 3D memory cross-context copy parameters */ typedef struct CUDA_MEMCPY3D_PEER_st { size_t srcXInBytes; /**< Source X in bytes */ size_t srcY; /**< Source Y */ size_t srcZ; /**< Source Z */ size_t srcLOD; /**< Source LOD */ CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */ const void *srcHost; /**< Source host pointer */ CUdeviceptr srcDevice; /**< Source device pointer */ CUarray srcArray; /**< Source array reference */ CUcontext srcContext; /**< Source context (ignored with srcMemoryType is ::CU_MEMORYTYPE_ARRAY) */ size_t srcPitch; /**< Source pitch (ignored when src is array) */ size_t srcHeight; /**< Source height (ignored when src is array; may be 0 if Depth==1) */ size_t dstXInBytes; /**< Destination X in bytes */ size_t dstY; /**< Destination Y */ size_t dstZ; /**< Destination Z */ size_t dstLOD; /**< Destination LOD */ CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */ void *dstHost; /**< Destination host pointer */ CUdeviceptr dstDevice; /**< Destination device pointer */ CUarray dstArray; /**< Destination array reference */ CUcontext dstContext; /**< Destination context (ignored with dstMemoryType is ::CU_MEMORYTYPE_ARRAY) */ size_t dstPitch; /**< Destination pitch (ignored when dst is array) */ size_t dstHeight; /**< Destination height (ignored when dst is array; may be 0 if Depth==1) */ size_t WidthInBytes; /**< Width of 3D memory copy in bytes */ size_t Height; /**< Height of 3D memory copy */ size_t Depth; /**< Depth of 3D memory copy */ } CUDA_MEMCPY3D_PEER; /** * Array descriptor */ typedef struct CUDA_ARRAY_DESCRIPTOR_st { size_t Width; /**< Width of array */ size_t Height; /**< Height of array */ CUarray_format Format; /**< Array format */ unsigned int NumChannels; /**< Channels per array element */ } CUDA_ARRAY_DESCRIPTOR; /** * 3D array descriptor */ typedef struct CUDA_ARRAY3D_DESCRIPTOR_st { size_t Width; /**< Width of 3D array */ size_t Height; /**< Height of 3D array */ size_t Depth; /**< Depth of 3D array */ CUarray_format Format; /**< Array format */ unsigned int NumChannels; /**< Channels per array element */ unsigned int Flags; /**< Flags */ } CUDA_ARRAY3D_DESCRIPTOR; #endif /* __CUDA_API_VERSION >= 3020 */ /** * If set, the CUDA array is a collection of layers, where each layer is either a 1D * or a 2D array and the Depth member of CUDA_ARRAY3D_DESCRIPTOR specifies the number * of layers, not the depth of a 3D array. */ #define CUDA_ARRAY3D_LAYERED 0x01 /** * Deprecated, use CUDA_ARRAY3D_LAYERED */ #define CUDA_ARRAY3D_2DARRAY 0x01 /** * This flag must be set in order to bind a surface reference * to the CUDA array */ #define CUDA_ARRAY3D_SURFACE_LDST 0x02 /** * Override the texref format with a format inferred from the array. * Flag for ::cuTexRefSetArray() */ #define CU_TRSA_OVERRIDE_FORMAT 0x01 /** * Read the texture as integers rather than promoting the values to floats * in the range [0,1]. * Flag for ::cuTexRefSetFlags() */ #define CU_TRSF_READ_AS_INTEGER 0x01 /** * Use normalized texture coordinates in the range [0,1) instead of [0,dim). * Flag for ::cuTexRefSetFlags() */ #define CU_TRSF_NORMALIZED_COORDINATES 0x02 /** * Perform sRGB->linear conversion during texture read. * Flag for ::cuTexRefSetFlags() */ #define CU_TRSF_SRGB 0x10 /** * End of array terminator for the \p extra parameter to * ::cuLaunchKernel */ #define CU_LAUNCH_PARAM_END ((void*)0x00) /** * Indicator that the next value in the \p extra parameter to * ::cuLaunchKernel will be a pointer to a buffer containing all kernel * parameters used for launching kernel \p f. This buffer needs to * honor all alignment/padding requirements of the individual parameters. * If ::CU_LAUNCH_PARAM_BUFFER_SIZE is not also specified in the * \p extra array, then ::CU_LAUNCH_PARAM_BUFFER_POINTER will have no * effect. */ #define CU_LAUNCH_PARAM_BUFFER_POINTER ((void*)0x01) /** * Indicator that the next value in the \p extra parameter to * ::cuLaunchKernel will be a pointer to a size_t which contains the * size of the buffer specified with ::CU_LAUNCH_PARAM_BUFFER_POINTER. * It is required that ::CU_LAUNCH_PARAM_BUFFER_POINTER also be specified * in the \p extra array if the value associated with * ::CU_LAUNCH_PARAM_BUFFER_SIZE is not zero. */ #define CU_LAUNCH_PARAM_BUFFER_SIZE ((void*)0x02) /** * For texture references loaded into the module, use default texunit from * texture reference. */ #define CU_PARAM_TR_DEFAULT -1 /** * CUDA API made obselete at API version 3020 */ #if defined(__CUDA_API_VERSION_INTERNAL) #define CUdeviceptr CUdeviceptr_v1 #define CUDA_MEMCPY2D_st CUDA_MEMCPY2D_v1_st #define CUDA_MEMCPY2D CUDA_MEMCPY2D_v1 #define CUDA_MEMCPY3D_st CUDA_MEMCPY3D_v1_st #define CUDA_MEMCPY3D CUDA_MEMCPY3D_v1 #define CUDA_ARRAY_DESCRIPTOR_st CUDA_ARRAY_DESCRIPTOR_v1_st #define CUDA_ARRAY_DESCRIPTOR CUDA_ARRAY_DESCRIPTOR_v1 #define CUDA_ARRAY3D_DESCRIPTOR_st CUDA_ARRAY3D_DESCRIPTOR_v1_st #define CUDA_ARRAY3D_DESCRIPTOR CUDA_ARRAY3D_DESCRIPTOR_v1 #endif /* CUDA_FORCE_LEGACY32_INTERNAL */ #if defined(__CUDA_API_VERSION_INTERNAL) || __CUDA_API_VERSION < 3020 typedef unsigned int CUdeviceptr; typedef struct CUDA_MEMCPY2D_st { unsigned int srcXInBytes; /**< Source X in bytes */ unsigned int srcY; /**< Source Y */ CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */ const void *srcHost; /**< Source host pointer */ CUdeviceptr srcDevice; /**< Source device pointer */ CUarray srcArray; /**< Source array reference */ unsigned int srcPitch; /**< Source pitch (ignored when src is array) */ unsigned int dstXInBytes; /**< Destination X in bytes */ unsigned int dstY; /**< Destination Y */ CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */ void *dstHost; /**< Destination host pointer */ CUdeviceptr dstDevice; /**< Destination device pointer */ CUarray dstArray; /**< Destination array reference */ unsigned int dstPitch; /**< Destination pitch (ignored when dst is array) */ unsigned int WidthInBytes; /**< Width of 2D memory copy in bytes */ unsigned int Height; /**< Height of 2D memory copy */ } CUDA_MEMCPY2D; typedef struct CUDA_MEMCPY3D_st { unsigned int srcXInBytes; /**< Source X in bytes */ unsigned int srcY; /**< Source Y */ unsigned int srcZ; /**< Source Z */ unsigned int srcLOD; /**< Source LOD */ CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */ const void *srcHost; /**< Source host pointer */ CUdeviceptr srcDevice; /**< Source device pointer */ CUarray srcArray; /**< Source array reference */ void *reserved0; /**< Must be NULL */ unsigned int srcPitch; /**< Source pitch (ignored when src is array) */ unsigned int srcHeight; /**< Source height (ignored when src is array; may be 0 if Depth==1) */ unsigned int dstXInBytes; /**< Destination X in bytes */ unsigned int dstY; /**< Destination Y */ unsigned int dstZ; /**< Destination Z */ unsigned int dstLOD; /**< Destination LOD */ CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */ void *dstHost; /**< Destination host pointer */ CUdeviceptr dstDevice; /**< Destination device pointer */ CUarray dstArray; /**< Destination array reference */ void *reserved1; /**< Must be NULL */ unsigned int dstPitch; /**< Destination pitch (ignored when dst is array) */ unsigned int dstHeight; /**< Destination height (ignored when dst is array; may be 0 if Depth==1) */ unsigned int WidthInBytes; /**< Width of 3D memory copy in bytes */ unsigned int Height; /**< Height of 3D memory copy */ unsigned int Depth; /**< Depth of 3D memory copy */ } CUDA_MEMCPY3D; typedef struct CUDA_ARRAY_DESCRIPTOR_st { unsigned int Width; /**< Width of array */ unsigned int Height; /**< Height of array */ CUarray_format Format; /**< Array format */ unsigned int NumChannels; /**< Channels per array element */ } CUDA_ARRAY_DESCRIPTOR; typedef struct CUDA_ARRAY3D_DESCRIPTOR_st { unsigned int Width; /**< Width of 3D array */ unsigned int Height; /**< Height of 3D array */ unsigned int Depth; /**< Depth of 3D array */ CUarray_format Format; /**< Array format */ unsigned int NumChannels; /**< Channels per array element */ unsigned int Flags; /**< Flags */ } CUDA_ARRAY3D_DESCRIPTOR; #endif /* (__CUDA_API_VERSION_INTERNAL) || __CUDA_API_VERSION < 3020 */ /* * If set, the CUDA array contains an array of 2D slices * and the Depth member of CUDA_ARRAY3D_DESCRIPTOR specifies * the number of slices, not the depth of a 3D array. */ #define CUDA_ARRAY3D_2DARRAY 0x01 /** * This flag must be set in order to bind a surface reference * to the CUDA array */ #define CUDA_ARRAY3D_SURFACE_LDST 0x02 /** * Override the texref format with a format inferred from the array. * Flag for ::cuTexRefSetArray() */ #define CU_TRSA_OVERRIDE_FORMAT 0x01 /** * Read the texture as integers rather than promoting the values to floats * in the range [0,1]. * Flag for ::cuTexRefSetFlags() */ #define CU_TRSF_READ_AS_INTEGER 0x01 /** * Use normalized texture coordinates in the range [0,1) instead of [0,dim). * Flag for ::cuTexRefSetFlags() */ #define CU_TRSF_NORMALIZED_COORDINATES 0x02 /** * Perform sRGB->linear conversion during texture read. * Flag for ::cuTexRefSetFlags() */ #define CU_TRSF_SRGB 0x10 /** * For texture references loaded into the module, use default texunit from * texture reference. */ #define CU_PARAM_TR_DEFAULT -1 /** @} */ /* END CUDA_TYPES */ #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #define CUDAAPI __stdcall #else #define CUDAAPI #endif /** * \defgroup CUDA_INITIALIZE Initialization * * This section describes the initialization functions of the low-level CUDA * driver application programming interface. * * @{ */ /********************************* ** Initialization *********************************/ typedef CUresult CUDAAPI tcuInit(unsigned int Flags); /********************************* ** Driver Version Query *********************************/ typedef CUresult CUDAAPI tcuDriverGetVersion(int *driverVersion); /************************************ ** ** Device management ** ***********************************/ typedef CUresult CUDAAPI tcuDeviceGet(CUdevice *device, int ordinal); typedef CUresult CUDAAPI tcuDeviceGetCount(int *count); typedef CUresult CUDAAPI tcuDeviceGetName(char *name, int len, CUdevice dev); typedef CUresult CUDAAPI tcuDeviceComputeCapability(int *major, int *minor, CUdevice dev); #if __CUDA_API_VERSION >= 3020 typedef CUresult CUDAAPI tcuDeviceTotalMem(size_t *bytes, CUdevice dev); #else typedef CUresult CUDAAPI tcuDeviceTotalMem(unsigned int *bytes, CUdevice dev); #endif typedef CUresult CUDAAPI tcuDeviceGetProperties(CUdevprop *prop, CUdevice dev); typedef CUresult CUDAAPI tcuDeviceGetAttribute(int *pi, CUdevice_attribute attrib, CUdevice dev); /************************************ ** ** Context management ** ***********************************/ typedef CUresult CUDAAPI tcuCtxCreate(CUcontext *pctx, unsigned int flags, CUdevice dev); typedef CUresult CUDAAPI tcuCtxDestroy(CUcontext ctx); typedef CUresult CUDAAPI tcuCtxAttach(CUcontext *pctx, unsigned int flags); typedef CUresult CUDAAPI tcuCtxDetach(CUcontext ctx); typedef CUresult CUDAAPI tcuCtxPushCurrent(CUcontext ctx); typedef CUresult CUDAAPI tcuCtxPopCurrent(CUcontext *pctx); typedef CUresult CUDAAPI tcuCtxSetCurrent(CUcontext ctx); typedef CUresult CUDAAPI tcuCtxGetCurrent(CUcontext *pctx); typedef CUresult CUDAAPI tcuCtxGetDevice(CUdevice *device); typedef CUresult CUDAAPI tcuCtxSynchronize(void); /************************************ ** ** Module management ** ***********************************/ typedef CUresult CUDAAPI tcuModuleLoad(CUmodule *module, const char *fname); typedef CUresult CUDAAPI tcuModuleLoadData(CUmodule *module, const void *image); typedef CUresult CUDAAPI tcuModuleLoadDataEx(CUmodule *module, const void *image, unsigned int numOptions, CUjit_option *options, void **optionValues); typedef CUresult CUDAAPI tcuModuleLoadFatBinary(CUmodule *module, const void *fatCubin); typedef CUresult CUDAAPI tcuModuleUnload(CUmodule hmod); typedef CUresult CUDAAPI tcuModuleGetFunction(CUfunction *hfunc, CUmodule hmod, const char *name); #if __CUDA_API_VERSION >= 3020 typedef CUresult CUDAAPI tcuModuleGetGlobal(CUdeviceptr *dptr, size_t *bytes, CUmodule hmod, const char *name); #else typedef CUresult CUDAAPI tcuModuleGetGlobal(CUdeviceptr *dptr, unsigned int *bytes, CUmodule hmod, const char *name); #endif typedef CUresult CUDAAPI tcuModuleGetTexRef(CUtexref *pTexRef, CUmodule hmod, const char *name); typedef CUresult CUDAAPI tcuModuleGetSurfRef(CUsurfref *pSurfRef, CUmodule hmod, const char *name); /************************************ ** ** Memory management ** ***********************************/ #if __CUDA_API_VERSION >= 3020 typedef CUresult CUDAAPI tcuMemGetInfo(size_t *free, size_t *total); typedef CUresult CUDAAPI tcuMemAlloc(CUdeviceptr *dptr, size_t bytesize); typedef CUresult CUDAAPI tcuMemGetAddressRange(CUdeviceptr *pbase, size_t *psize, CUdeviceptr dptr); typedef CUresult CUDAAPI tcuMemAllocPitch(CUdeviceptr *dptr, size_t *pPitch, size_t WidthInBytes, size_t Height, // size of biggest r/w to be performed by kernels on this memory // 4, 8 or 16 bytes unsigned int ElementSizeBytes ); #else typedef CUresult CUDAAPI tcuMemGetInfo(unsigned int *free, unsigned int *total); typedef CUresult CUDAAPI tcuMemAlloc(CUdeviceptr *dptr, unsigned int bytesize); typedef CUresult CUDAAPI tcuMemGetAddressRange(CUdeviceptr *pbase, unsigned int *psize, CUdeviceptr dptr); typedef CUresult CUDAAPI tcuMemAllocPitch(CUdeviceptr *dptr, unsigned int *pPitch, unsigned int WidthInBytes, unsigned int Height, // size of biggest r/w to be performed by kernels on this memory // 4, 8 or 16 bytes unsigned int ElementSizeBytes ); #endif typedef CUresult CUDAAPI tcuMemFree(CUdeviceptr dptr); #if __CUDA_API_VERSION >= 3020 typedef CUresult CUDAAPI tcuMemAllocHost(void **pp, size_t bytesize); #else typedef CUresult CUDAAPI tcuMemAllocHost(void **pp, unsigned int bytesize); #endif typedef CUresult CUDAAPI tcuMemFreeHost(void *p); typedef CUresult CUDAAPI tcuMemHostAlloc(void **pp, size_t bytesize, unsigned int Flags); typedef CUresult CUDAAPI tcuMemHostGetDevicePointer(CUdeviceptr *pdptr, void *p, unsigned int Flags); typedef CUresult CUDAAPI tcuMemHostGetFlags(unsigned int *pFlags, void *p); typedef CUresult CUDAAPI tcuMemHostRegister(void *p, size_t bytesize, unsigned int Flags); typedef CUresult CUDAAPI tcuMemHostUnregister(void *p);; typedef CUresult CUDAAPI tcuMemcpy(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount); typedef CUresult CUDAAPI tcuMemcpyPeer(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount); /************************************ ** ** Synchronous Memcpy ** ** Intra-device memcpy's done with these functions may execute in parallel with the CPU, ** but if host memory is involved, they wait until the copy is done before returning. ** ***********************************/ // 1D functions #if __CUDA_API_VERSION >= 3020 // system <-> device memory typedef CUresult CUDAAPI tcuMemcpyHtoD(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount); typedef CUresult CUDAAPI tcuMemcpyDtoH(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount); // device <-> device memory typedef CUresult CUDAAPI tcuMemcpyDtoD(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount); // device <-> array memory typedef CUresult CUDAAPI tcuMemcpyDtoA(CUarray dstArray, size_t dstOffset, CUdeviceptr srcDevice, size_t ByteCount); typedef CUresult CUDAAPI tcuMemcpyAtoD(CUdeviceptr dstDevice, CUarray srcArray, size_t srcOffset, size_t ByteCount); // system <-> array memory typedef CUresult CUDAAPI tcuMemcpyHtoA(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount); typedef CUresult CUDAAPI tcuMemcpyAtoH(void *dstHost, CUarray srcArray, size_t srcOffset, size_t ByteCount); // array <-> array memory typedef CUresult CUDAAPI tcuMemcpyAtoA(CUarray dstArray, size_t dstOffset, CUarray srcArray, size_t srcOffset, size_t ByteCount); #else // system <-> device memory typedef CUresult CUDAAPI tcuMemcpyHtoD(CUdeviceptr dstDevice, const void *srcHost, unsigned int ByteCount); typedef CUresult CUDAAPI tcuMemcpyDtoH(void *dstHost, CUdeviceptr srcDevice, unsigned int ByteCount); // device <-> device memory typedef CUresult CUDAAPI tcuMemcpyDtoD(CUdeviceptr dstDevice, CUdeviceptr srcDevice, unsigned int ByteCount); // device <-> array memory typedef CUresult CUDAAPI tcuMemcpyDtoA(CUarray dstArray, unsigned int dstOffset, CUdeviceptr srcDevice, unsigned int ByteCount); typedef CUresult CUDAAPI tcuMemcpyAtoD(CUdeviceptr dstDevice, CUarray srcArray, unsigned int srcOffset, unsigned int ByteCount); // system <-> array memory typedef CUresult CUDAAPI tcuMemcpyHtoA(CUarray dstArray, unsigned int dstOffset, const void *srcHost, unsigned int ByteCount); typedef CUresult CUDAAPI tcuMemcpyAtoH(void *dstHost, CUarray srcArray, unsigned int srcOffset, unsigned int ByteCount); // array <-> array memory typedef CUresult CUDAAPI tcuMemcpyAtoA(CUarray dstArray, unsigned int dstOffset, CUarray srcArray, unsigned int srcOffset, unsigned int ByteCount); #endif // 2D memcpy typedef CUresult CUDAAPI tcuMemcpy2D(const CUDA_MEMCPY2D *pCopy); typedef CUresult CUDAAPI tcuMemcpy2DUnaligned(const CUDA_MEMCPY2D *pCopy); // 3D memcpy typedef CUresult CUDAAPI tcuMemcpy3D(const CUDA_MEMCPY3D *pCopy); /************************************ ** ** Asynchronous Memcpy ** ** Any host memory involved must be DMA'able (e.g., allocated with cuMemAllocHost). ** memcpy's done with these functions execute in parallel with the CPU and, if ** the hardware is available, may execute in parallel with the GPU. ** Asynchronous memcpy must be accompanied by appropriate stream synchronization. ** ***********************************/ // 1D functions #if __CUDA_API_VERSION >= 3020 // system <-> device memory typedef CUresult CUDAAPI tcuMemcpyHtoDAsync(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount, CUstream hStream); typedef CUresult CUDAAPI tcuMemcpyDtoHAsync(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream); // device <-> device memory typedef CUresult CUDAAPI tcuMemcpyDtoDAsync(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream); // system <-> array memory typedef CUresult CUDAAPI tcuMemcpyHtoAAsync(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount, CUstream hStream); typedef CUresult CUDAAPI tcuMemcpyAtoHAsync(void *dstHost, CUarray srcArray, size_t srcOffset, size_t ByteCount, CUstream hStream); #else // system <-> device memory typedef CUresult CUDAAPI tcuMemcpyHtoDAsync(CUdeviceptr dstDevice, const void *srcHost, unsigned int ByteCount, CUstream hStream); typedef CUresult CUDAAPI tcuMemcpyDtoHAsync(void *dstHost, CUdeviceptr srcDevice, unsigned int ByteCount, CUstream hStream); // device <-> device memory typedef CUresult CUDAAPI tcuMemcpyDtoDAsync(CUdeviceptr dstDevice, CUdeviceptr srcDevice, unsigned int ByteCount, CUstream hStream); // system <-> array memory typedef CUresult CUDAAPI tcuMemcpyHtoAAsync(CUarray dstArray, unsigned int dstOffset, const void *srcHost, unsigned int ByteCount, CUstream hStream); typedef CUresult CUDAAPI tcuMemcpyAtoHAsync(void *dstHost, CUarray srcArray, unsigned int srcOffset, unsigned int ByteCount, CUstream hStream); #endif // 2D memcpy typedef CUresult CUDAAPI tcuMemcpy2DAsync(const CUDA_MEMCPY2D *pCopy, CUstream hStream); // 3D memcpy typedef CUresult CUDAAPI tcuMemcpy3DAsync(const CUDA_MEMCPY3D *pCopy, CUstream hStream); /************************************ ** ** Memset ** ***********************************/ typedef CUresult CUDAAPI tcuMemsetD8(CUdeviceptr dstDevice, unsigned char uc, unsigned int N); typedef CUresult CUDAAPI tcuMemsetD16(CUdeviceptr dstDevice, unsigned short us, unsigned int N); typedef CUresult CUDAAPI tcuMemsetD32(CUdeviceptr dstDevice, unsigned int ui, unsigned int N); #if __CUDA_API_VERSION >= 3020 typedef CUresult CUDAAPI tcuMemsetD2D8(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned char uc, size_t Width, size_t Height); typedef CUresult CUDAAPI tcuMemsetD2D16(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned short us, size_t Width, size_t Height); typedef CUresult CUDAAPI tcuMemsetD2D32(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned int ui, size_t Width, size_t Height); #else typedef CUresult CUDAAPI tcuMemsetD2D8(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned char uc, unsigned int Width, unsigned int Height); typedef CUresult CUDAAPI tcuMemsetD2D16(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned short us, unsigned int Width, unsigned int Height); typedef CUresult CUDAAPI tcuMemsetD2D32(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned int ui, unsigned int Width, unsigned int Height); #endif /************************************ ** ** Function management ** ***********************************/ typedef CUresult CUDAAPI tcuFuncSetBlockShape(CUfunction hfunc, int x, int y, int z); typedef CUresult CUDAAPI tcuFuncSetSharedSize(CUfunction hfunc, unsigned int bytes); typedef CUresult CUDAAPI tcuFuncGetAttribute(int *pi, CUfunction_attribute attrib, CUfunction hfunc); typedef CUresult CUDAAPI tcuFuncSetCacheConfig(CUfunction hfunc, CUfunc_cache config); typedef CUresult CUDAAPI tcuLaunchKernel(CUfunction f, unsigned int gridDimX, unsigned int gridDimY, unsigned int gridDimZ, unsigned int blockDimX, unsigned int blockDimY, unsigned int blockDimZ, unsigned int sharedMemBytes, CUstream hStream, void **kernelParams, void **extra); /************************************ ** ** Array management ** ***********************************/ typedef CUresult CUDAAPI tcuArrayCreate(CUarray *pHandle, const CUDA_ARRAY_DESCRIPTOR *pAllocateArray); typedef CUresult CUDAAPI tcuArrayGetDescriptor(CUDA_ARRAY_DESCRIPTOR *pArrayDescriptor, CUarray hArray); typedef CUresult CUDAAPI tcuArrayDestroy(CUarray hArray); typedef CUresult CUDAAPI tcuArray3DCreate(CUarray *pHandle, const CUDA_ARRAY3D_DESCRIPTOR *pAllocateArray); typedef CUresult CUDAAPI tcuArray3DGetDescriptor(CUDA_ARRAY3D_DESCRIPTOR *pArrayDescriptor, CUarray hArray); /************************************ ** ** Texture reference management ** ***********************************/ typedef CUresult CUDAAPI tcuTexRefCreate(CUtexref *pTexRef); typedef CUresult CUDAAPI tcuTexRefDestroy(CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefSetArray(CUtexref hTexRef, CUarray hArray, unsigned int Flags); #if __CUDA_API_VERSION >= 3020 typedef CUresult CUDAAPI tcuTexRefSetAddress(size_t *ByteOffset, CUtexref hTexRef, CUdeviceptr dptr, size_t bytes); typedef CUresult CUDAAPI tcuTexRefSetAddress2D(CUtexref hTexRef, const CUDA_ARRAY_DESCRIPTOR *desc, CUdeviceptr dptr, size_t Pitch); #else typedef CUresult CUDAAPI tcuTexRefSetAddress(unsigned int *ByteOffset, CUtexref hTexRef, CUdeviceptr dptr, unsigned int bytes); typedef CUresult CUDAAPI tcuTexRefSetAddress2D(CUtexref hTexRef, const CUDA_ARRAY_DESCRIPTOR *desc, CUdeviceptr dptr, unsigned int Pitch); #endif typedef CUresult CUDAAPI tcuTexRefSetFormat(CUtexref hTexRef, CUarray_format fmt, int NumPackedComponents); typedef CUresult CUDAAPI tcuTexRefSetAddressMode(CUtexref hTexRef, int dim, CUaddress_mode am); typedef CUresult CUDAAPI tcuTexRefSetFilterMode(CUtexref hTexRef, CUfilter_mode fm); typedef CUresult CUDAAPI tcuTexRefSetFlags(CUtexref hTexRef, unsigned int Flags); typedef CUresult CUDAAPI tcuTexRefGetAddress(CUdeviceptr *pdptr, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefGetArray(CUarray *phArray, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefGetAddressMode(CUaddress_mode *pam, CUtexref hTexRef, int dim); typedef CUresult CUDAAPI tcuTexRefGetFilterMode(CUfilter_mode *pfm, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefGetFormat(CUarray_format *pFormat, int *pNumChannels, CUtexref hTexRef); typedef CUresult CUDAAPI tcuTexRefGetFlags(unsigned int *pFlags, CUtexref hTexRef); /************************************ ** ** Surface reference management ** ***********************************/ typedef CUresult CUDAAPI tcuSurfRefSetArray(CUsurfref hSurfRef, CUarray hArray, unsigned int Flags); typedef CUresult CUDAAPI tcuSurfRefGetArray(CUarray *phArray, CUsurfref hSurfRef); /************************************ ** ** Parameter management ** ***********************************/ typedef CUresult CUDAAPI tcuParamSetSize(CUfunction hfunc, unsigned int numbytes); typedef CUresult CUDAAPI tcuParamSeti(CUfunction hfunc, int offset, unsigned int value); typedef CUresult CUDAAPI tcuParamSetf(CUfunction hfunc, int offset, float value); typedef CUresult CUDAAPI tcuParamSetv(CUfunction hfunc, int offset, void *ptr, unsigned int numbytes); typedef CUresult CUDAAPI tcuParamSetTexRef(CUfunction hfunc, int texunit, CUtexref hTexRef); /************************************ ** ** Launch functions ** ***********************************/ typedef CUresult CUDAAPI tcuLaunch(CUfunction f); typedef CUresult CUDAAPI tcuLaunchGrid(CUfunction f, int grid_width, int grid_height); typedef CUresult CUDAAPI tcuLaunchGridAsync(CUfunction f, int grid_width, int grid_height, CUstream hStream); /************************************ ** ** Events ** ***********************************/ typedef CUresult CUDAAPI tcuEventCreate(CUevent *phEvent, unsigned int Flags); typedef CUresult CUDAAPI tcuEventRecord(CUevent hEvent, CUstream hStream); typedef CUresult CUDAAPI tcuEventQuery(CUevent hEvent); typedef CUresult CUDAAPI tcuEventSynchronize(CUevent hEvent); typedef CUresult CUDAAPI tcuEventDestroy(CUevent hEvent); typedef CUresult CUDAAPI tcuEventElapsedTime(float *pMilliseconds, CUevent hStart, CUevent hEnd); /************************************ ** ** Streams ** ***********************************/ typedef CUresult CUDAAPI tcuStreamCreate(CUstream *phStream, unsigned int Flags); typedef CUresult CUDAAPI tcuStreamQuery(CUstream hStream); typedef CUresult CUDAAPI tcuStreamSynchronize(CUstream hStream); typedef CUresult CUDAAPI tcuStreamDestroy(CUstream hStream); /************************************ ** ** Graphics interop ** ***********************************/ typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resource); typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray *pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel); #if __CUDA_API_VERSION >= 3020 typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer(CUdeviceptr *pDevPtr, size_t *pSize, CUgraphicsResource resource); #else typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer(CUdeviceptr *pDevPtr, unsigned int *pSize, CUgraphicsResource resource); #endif typedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags(CUgraphicsResource resource, unsigned int flags); typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned int count, CUgraphicsResource *resources, CUstream hStream); typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned int count, CUgraphicsResource *resources, CUstream hStream); /************************************ ** ** Export tables ** ***********************************/ typedef CUresult CUDAAPI tcuGetExportTable(const void **ppExportTable, const CUuuid *pExportTableId); /************************************ ** ** Limits ** ***********************************/ typedef CUresult CUDAAPI tcuCtxSetLimit(CUlimit limit, size_t value); typedef CUresult CUDAAPI tcuCtxGetLimit(size_t *pvalue, CUlimit limit); /************************************ ************************************/ extern CUresult CUDAAPI cuInit(unsigned int, int cudaVersion); extern tcuDriverGetVersion *cuDriverGetVersion; extern tcuDeviceGet *cuDeviceGet; extern tcuDeviceGetCount *cuDeviceGetCount; extern tcuDeviceGetName *cuDeviceGetName; extern tcuDeviceComputeCapability *cuDeviceComputeCapability; extern tcuDeviceGetProperties *cuDeviceGetProperties; extern tcuDeviceGetAttribute *cuDeviceGetAttribute; extern tcuCtxDestroy *cuCtxDestroy; extern tcuCtxAttach *cuCtxAttach; extern tcuCtxDetach *cuCtxDetach; extern tcuCtxPushCurrent *cuCtxPushCurrent; extern tcuCtxPopCurrent *cuCtxPopCurrent; extern tcuCtxSetCurrent *cuCtxSetCurrent; extern tcuCtxGetCurrent *cuCtxGetCurrent; extern tcuCtxGetDevice *cuCtxGetDevice; extern tcuCtxSynchronize *cuCtxSynchronize; extern tcuModuleLoad *cuModuleLoad; extern tcuModuleLoadData *cuModuleLoadData; extern tcuModuleLoadDataEx *cuModuleLoadDataEx; extern tcuModuleLoadFatBinary *cuModuleLoadFatBinary; extern tcuModuleUnload *cuModuleUnload; extern tcuModuleGetFunction *cuModuleGetFunction; extern tcuModuleGetTexRef *cuModuleGetTexRef; extern tcuModuleGetSurfRef *cuModuleGetSurfRef; extern tcuMemFreeHost *cuMemFreeHost; extern tcuMemHostAlloc *cuMemHostAlloc; extern tcuMemHostGetFlags *cuMemHostGetFlags; extern tcuMemHostRegister *cuMemHostRegister; extern tcuMemHostUnregister *cuMemHostUnregister; extern tcuMemcpy *cuMemcpy; extern tcuMemcpyPeer *cuMemcpyPeer; extern tcuDeviceTotalMem *cuDeviceTotalMem; extern tcuCtxCreate *cuCtxCreate; extern tcuModuleGetGlobal *cuModuleGetGlobal; extern tcuMemGetInfo *cuMemGetInfo; extern tcuMemAlloc *cuMemAlloc; extern tcuMemAllocPitch *cuMemAllocPitch; extern tcuMemFree *cuMemFree; extern tcuMemGetAddressRange *cuMemGetAddressRange; extern tcuMemAllocHost *cuMemAllocHost; extern tcuMemHostGetDevicePointer *cuMemHostGetDevicePointer; extern tcuFuncSetBlockShape *cuFuncSetBlockShape; extern tcuFuncSetSharedSize *cuFuncSetSharedSize; extern tcuFuncGetAttribute *cuFuncGetAttribute; extern tcuFuncSetCacheConfig *cuFuncSetCacheConfig; extern tcuLaunchKernel *cuLaunchKernel; extern tcuArrayDestroy *cuArrayDestroy; extern tcuTexRefCreate *cuTexRefCreate; extern tcuTexRefDestroy *cuTexRefDestroy; extern tcuTexRefSetArray *cuTexRefSetArray; extern tcuTexRefSetFormat *cuTexRefSetFormat; extern tcuTexRefSetAddressMode *cuTexRefSetAddressMode; extern tcuTexRefSetFilterMode *cuTexRefSetFilterMode; extern tcuTexRefSetFlags *cuTexRefSetFlags; extern tcuTexRefGetArray *cuTexRefGetArray; extern tcuTexRefGetAddressMode *cuTexRefGetAddressMode; extern tcuTexRefGetFilterMode *cuTexRefGetFilterMode; extern tcuTexRefGetFormat *cuTexRefGetFormat; extern tcuTexRefGetFlags *cuTexRefGetFlags; extern tcuSurfRefSetArray *cuSurfRefSetArray; extern tcuSurfRefGetArray *cuSurfRefGetArray; extern tcuParamSetSize *cuParamSetSize; extern tcuParamSeti *cuParamSeti; extern tcuParamSetf *cuParamSetf; extern tcuParamSetv *cuParamSetv; extern tcuParamSetTexRef *cuParamSetTexRef; extern tcuLaunch *cuLaunch; extern tcuLaunchGrid *cuLaunchGrid; extern tcuLaunchGridAsync *cuLaunchGridAsync; extern tcuEventCreate *cuEventCreate; extern tcuEventRecord *cuEventRecord; extern tcuEventQuery *cuEventQuery; extern tcuEventSynchronize *cuEventSynchronize; extern tcuEventDestroy *cuEventDestroy; extern tcuEventElapsedTime *cuEventElapsedTime; extern tcuStreamCreate *cuStreamCreate; extern tcuStreamQuery *cuStreamQuery; extern tcuStreamSynchronize *cuStreamSynchronize; extern tcuStreamDestroy *cuStreamDestroy; extern tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource; extern tcuGraphicsSubResourceGetMappedArray *cuGraphicsSubResourceGetMappedArray; extern tcuGraphicsResourceSetMapFlags *cuGraphicsResourceSetMapFlags; extern tcuGraphicsMapResources *cuGraphicsMapResources; extern tcuGraphicsUnmapResources *cuGraphicsUnmapResources; extern tcuGetExportTable *cuGetExportTable; extern tcuCtxSetLimit *cuCtxSetLimit; extern tcuCtxGetLimit *cuCtxGetLimit; // These functions could be using the CUDA 3.2 interface (_v2) extern tcuMemcpyHtoD *cuMemcpyHtoD; extern tcuMemcpyDtoH *cuMemcpyDtoH; extern tcuMemcpyDtoD *cuMemcpyDtoD; extern tcuMemcpyDtoA *cuMemcpyDtoA; extern tcuMemcpyAtoD *cuMemcpyAtoD; extern tcuMemcpyHtoA *cuMemcpyHtoA; extern tcuMemcpyAtoH *cuMemcpyAtoH; extern tcuMemcpyAtoA *cuMemcpyAtoA; extern tcuMemcpy2D *cuMemcpy2D; extern tcuMemcpy2DUnaligned *cuMemcpy2DUnaligned; extern tcuMemcpy3D *cuMemcpy3D; extern tcuMemcpyHtoDAsync *cuMemcpyHtoDAsync; extern tcuMemcpyDtoHAsync *cuMemcpyDtoHAsync; extern tcuMemcpyDtoDAsync *cuMemcpyDtoDAsync; extern tcuMemcpyHtoAAsync *cuMemcpyHtoAAsync; extern tcuMemcpyAtoHAsync *cuMemcpyAtoHAsync; extern tcuMemcpy2DAsync *cuMemcpy2DAsync; extern tcuMemcpy3DAsync *cuMemcpy3DAsync; extern tcuMemsetD8 *cuMemsetD8; extern tcuMemsetD16 *cuMemsetD16; extern tcuMemsetD32 *cuMemsetD32; extern tcuMemsetD2D8 *cuMemsetD2D8; extern tcuMemsetD2D16 *cuMemsetD2D16; extern tcuMemsetD2D32 *cuMemsetD2D32; extern tcuArrayCreate *cuArrayCreate; extern tcuArrayGetDescriptor *cuArrayGetDescriptor; extern tcuArray3DCreate *cuArray3DCreate; extern tcuArray3DGetDescriptor *cuArray3DGetDescriptor; extern tcuTexRefSetAddress *cuTexRefSetAddress; extern tcuTexRefSetAddress2D *cuTexRefSetAddress2D; extern tcuTexRefGetAddress *cuTexRefGetAddress; extern tcuGraphicsResourceGetMappedPointer *cuGraphicsResourceGetMappedPointer; #ifdef __cplusplus } #endif //#undef __CUDA_API_VERSION #endif //__cuda_drvapi_dynlink_cuda_h__ ================================================ FILE: tests/projects/cuda/console/inc/dynlink/cuda_drvapi_dynlink_d3d.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef __cuda_drvapi_dynlink_d3d_h__ #define __cuda_drvapi_dynlink_d3d_h__ #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #pragma warning(disable: 4312) #if defined (CUDA_INIT_D3D9) || defined(CUDA_INIT_D3D10) || defined(CUDA_INIT_D3D11) #include #include #endif #ifdef CUDA_INIT_D3D9 #include #pragma warning( disable : 4996 ) // disable deprecated warning #include #pragma warning( default : 4996 ) /** * CUDA 2.x compatibility - Flags to register a D3D9 graphics resource */ typedef enum CUd3d9register_flags_enum { CU_D3D9_REGISTER_FLAGS_NONE = 0x00, CU_D3D9_REGISTER_FLAGS_ARRAY = 0x01, } CUd3d9register_flags; /** * CUDA 2.x compatibility - Flags for D3D9 mapping and unmapping interop resources */ typedef enum CUd3d9map_flags_enum { CU_D3D9_MAPRESOURCE_FLAGS_NONE = 0x00, CU_D3D9_MAPRESOURCE_FLAGS_READONLY = 0x01, CU_D3D9_MAPRESOURCE_FLAGS_WRITEDISCARD = 0x02, } CUd3d9map_flags; // D3D9/CUDA interop (CUDA 1.x compatible API). These functions are deprecated, please use the ones below typedef CUresult CUDAAPI tcuD3D9Begin(IDirect3DDevice9 *pDevice); typedef CUresult CUDAAPI tcuD3D9End(void); typedef CUresult CUDAAPI tcuD3D9RegisterVertexBuffer(IDirect3DVertexBuffer9 *pVB); typedef CUresult CUDAAPI tcuD3D9MapVertexBuffer(CUdeviceptr *pDevPtr, unsigned int *pSize, IDirect3DVertexBuffer9 *pVB); typedef CUresult CUDAAPI tcuD3D9UnmapVertexBuffer(IDirect3DVertexBuffer9 *pVB); typedef CUresult CUDAAPI tcuD3D9UnregisterVertexBuffer(IDirect3DVertexBuffer9 *pVB); // D3D9/CUDA interop (CUDA 2.x compatible) typedef CUresult CUDAAPI tcuD3D9GetDirect3DDevice(IDirect3DDevice9 **ppD3DDevice); typedef CUresult CUDAAPI tcuD3D9RegisterResource(IDirect3DResource9 *pResource, unsigned int Flags); typedef CUresult CUDAAPI tcuD3D9UnregisterResource(IDirect3DResource9 *pResource); typedef CUresult CUDAAPI tcuD3D9MapResources(unsigned int count, IDirect3DResource9 **ppResource); typedef CUresult CUDAAPI tcuD3D9UnmapResources(unsigned int count, IDirect3DResource9 **ppResource); typedef CUresult CUDAAPI tcuD3D9ResourceSetMapFlags(IDirect3DResource9 *pResource, unsigned int Flags); typedef CUresult CUDAAPI tcuD3D9ResourceGetSurfaceDimensions(unsigned int *pWidth, unsigned int *pHeight, unsigned int *pDepth, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level); typedef CUresult CUDAAPI tcuD3D9ResourceGetMappedArray(CUarray *pArray, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level); typedef CUresult CUDAAPI tcuD3D9ResourceGetMappedPointer(CUdeviceptr *pDevPtr, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level); typedef CUresult CUDAAPI tcuD3D9ResourceGetMappedSize(unsigned int *pSize, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level); typedef CUresult CUDAAPI tcuD3D9ResourceGetMappedPitch(unsigned int *pPitch, unsigned int *pPitchSlice, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level); // D3D9/CUDA interop (CUDA 2.0+) typedef CUresult CUDAAPI tcuD3D9GetDevice(CUdevice *pCudaDevice, const char *pszAdapterName); typedef CUresult CUDAAPI tcuD3D9CtxCreate(CUcontext *pCtx, CUdevice *pCudaDevice, unsigned int Flags, IDirect3DDevice9 *pD3DDevice); typedef CUresult CUDAAPI tcuGraphicsD3D9RegisterResource(CUgraphicsResource *pCudaResource, IDirect3DResource9 *pD3DResource, unsigned int Flags); #endif #ifdef CUDA_INIT_D3D10 #include #include #include #include #pragma warning( disable : 4996 ) // disable deprecated warning #include #pragma warning( default : 4996 ) // D3D11/CUDA interop (CUDA 3.0) typedef CUresult CUDAAPI tcuD3D10GetDevice(CUdevice *pCudaDevice, IDXGIAdapter *pAdapter); typedef CUresult CUDAAPI tcuD3D10CtxCreate(CUcontext *pCtx, CUdevice *pCudaDevice, unsigned int Flags, ID3D10Device *pD3DDevice); typedef CUresult CUDAAPI tcuGraphicsD3D10RegisterResource(CUgraphicsResource *pCudaResource, ID3D10Resource *pD3DResource, unsigned int Flags); #endif // CUDA_INIT_D3D10 #ifdef CUDA_INIT_D3D11 #include #include #include #pragma warning( disable : 4996 ) // disable deprecated warning #include #pragma warning( default : 4996 ) // D3D11/CUDA interop (CUDA 3.0) typedef CUresult CUDAAPI tcuD3D11GetDevice(CUdevice *pCudaDevice, IDXGIAdapter *pAdapter); typedef CUresult CUDAAPI tcuD3D11CtxCreate(CUcontext *pCtx, CUdevice *pCudaDevice, unsigned int Flags, ID3D11Device *pD3DDevice); typedef CUresult CUDAAPI tcuGraphicsD3D11RegisterResource(CUgraphicsResource *pCudaResource, ID3D11Resource *pD3DResource, unsigned int Flags); #endif // CUDA_INIT_D3D11 #endif // WIN32 #endif // __cuda_drvapi_dynlink_cuda_d3d_h__ ================================================ FILE: tests/projects/cuda/console/inc/dynlink/cuda_drvapi_dynlink_gl.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef __cuda_drvapi_dynlink_cuda_gl_h__ #define __cuda_drvapi_dynlink_cuda_gl_h__ #ifdef CUDA_INIT_OPENGL #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) # define WINDOWS_LEAN_AND_MEAN # define NOMINMAX # include #endif // includes, system #include #include #include #include // includes, GL #include #if defined (__APPLE__) || defined(MACOSX) #include #else #include #endif /************************************ ** ** OpenGL Graphics/Interop ** ***********************************/ // OpenGL/CUDA interop (CUDA 2.0+) typedef CUresult CUDAAPI tcuGLCtxCreate(CUcontext *pCtx, unsigned int Flags, CUdevice device); typedef CUresult CUDAAPI tcuGraphicsGLRegisterBuffer(CUgraphicsResource *pCudaResource, GLuint buffer, unsigned int Flags); typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource *pCudaResource, GLuint image, GLenum target, unsigned int Flags); #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #include // WIN32 typedef CUresult CUDAAPI tcuWGLGetDevice(CUdevice *pDevice, HGPUNV hGpu); #endif #endif // CUDA_INIT_OPENGL #endif // __cuda_drvapi_dynlink_cuda_gl_h__ ================================================ FILE: tests/projects/cuda/console/inc/dynlink_d3d10.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ //-------------------------------------------------------------------------------------- // File: dynlink_d3d10.h // // Shortcut macros and functions for using DX objects // // Copyright (c) Microsoft Corporation. All rights reserved //-------------------------------------------------------------------------------------- #ifndef _DYNLINK_D3D10_H_ #define _DYNLINK_D3D10_H_ // Standard Windows includes #include #include #include #include #include #include // for InitCommonControls() #include // for ExtractIcon() #include // for placement new #include #include #include #include // CRT's memory leak detection #if defined(DEBUG) || defined(_DEBUG) #include #endif // Direct3D9 includes #include #include // Direct3D10 includes #include #include #include #include // XInput includes #include // HRESULT translation for Direct3D10 and other APIs #include // strsafe.h deprecates old unsecure string functions. If you // really do not want to it to (not recommended), then uncomment the next line //#define STRSAFE_NO_DEPRECATE #ifndef STRSAFE_NO_DEPRECATE #pragma deprecated("strncpy") #pragma deprecated("wcsncpy") #pragma deprecated("_tcsncpy") #pragma deprecated("wcsncat") #pragma deprecated("strncat") #pragma deprecated("_tcsncat") #endif #pragma warning( disable : 4996 ) // disable deprecated warning #include #pragma warning( default : 4996 ) //-------------------------------------------------------------------------------------- // Structs //-------------------------------------------------------------------------------------- struct DXUTD3D9DeviceSettings { UINT AdapterOrdinal; D3DDEVTYPE DeviceType; D3DFORMAT AdapterFormat; DWORD BehaviorFlags; D3DPRESENT_PARAMETERS pp; }; struct DXUTD3D10DeviceSettings { UINT AdapterOrdinal; D3D10_DRIVER_TYPE DriverType; UINT Output; DXGI_SWAP_CHAIN_DESC sd; UINT32 CreateFlags; UINT32 SyncInterval; DWORD PresentFlags; bool AutoCreateDepthStencil; // DXUT will create the a depth stencil resource and view if true DXGI_FORMAT AutoDepthStencilFormat; }; enum DXUTDeviceVersion { DXUT_D3D9_DEVICE, DXUT_D3D10_DEVICE }; struct DXUTDeviceSettings { DXUTDeviceVersion ver; union { DXUTD3D9DeviceSettings d3d9; // only valid if ver == DXUT_D3D9_DEVICE DXUTD3D10DeviceSettings d3d10; // only valid if ver == DXUT_D3D10_DEVICE }; }; //-------------------------------------------------------------------------------------- // Error codes //-------------------------------------------------------------------------------------- #define DXUTERR_NODIRECT3D MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0901) #define DXUTERR_NOCOMPATIBLEDEVICES MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0902) #define DXUTERR_MEDIANOTFOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0903) #define DXUTERR_NONZEROREFCOUNT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0904) #define DXUTERR_CREATINGDEVICE MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0905) #define DXUTERR_RESETTINGDEVICE MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0906) #define DXUTERR_CREATINGDEVICEOBJECTS MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0907) #define DXUTERR_RESETTINGDEVICEOBJECTS MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0908) #define DXUTERR_DEVICEREMOVED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x090A) typedef HRESULT(WINAPI *LPCREATEDXGIFACTORY)(REFIID, void **); typedef HRESULT(WINAPI *LPD3D10CREATEDEVICE)(IDXGIAdapter *, D3D10_DRIVER_TYPE, HMODULE, UINT, UINT32, ID3D10Device **); typedef HRESULT(WINAPI *LPD3D10CREATEDEVICE1)(IDXGIAdapter *, D3D10_DRIVER_TYPE, HMODULE, UINT, D3D10_FEATURE_LEVEL1, UINT, ID3D10Device1 **); typedef HRESULT(WINAPI *LPD3D10CREATESTATEBLOCK)(ID3D10Device *pDevice, D3D10_STATE_BLOCK_MASK *pStateBlockMask, ID3D10StateBlock **ppStateBlock); typedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKUNION)(D3D10_STATE_BLOCK_MASK *pA, D3D10_STATE_BLOCK_MASK *pB, D3D10_STATE_BLOCK_MASK *pResult); typedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKINTERSECT)(D3D10_STATE_BLOCK_MASK *pA, D3D10_STATE_BLOCK_MASK *pB, D3D10_STATE_BLOCK_MASK *pResult); typedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKDIFFERENCE)(D3D10_STATE_BLOCK_MASK *pA, D3D10_STATE_BLOCK_MASK *pB, D3D10_STATE_BLOCK_MASK *pResult); typedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKENABLECAPTURE)(D3D10_STATE_BLOCK_MASK *pMask, D3D10_DEVICE_STATE_TYPES StateType, UINT RangeStart, UINT RangeLength); typedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKDISABLECAPTURE)(D3D10_STATE_BLOCK_MASK *pMask, D3D10_DEVICE_STATE_TYPES StateType, UINT RangeStart, UINT RangeLength); typedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKENABLEALL)(D3D10_STATE_BLOCK_MASK *pMask); typedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKDISABLEALL)(D3D10_STATE_BLOCK_MASK *pMask); typedef BOOL (WINAPI *LPD3D10STATEBLOCKMASKGETSETTING)(D3D10_STATE_BLOCK_MASK *pMask, D3D10_DEVICE_STATE_TYPES StateType, UINT Entry); typedef HRESULT(WINAPI *LPD3D10COMPILEEFFECTFROMMEMORY)(void *pData, SIZE_T DataLength, LPCSTR pSrcFileName, CONST D3D10_SHADER_MACRO *pDefines, ID3D10Include *pInclude, UINT HLSLFlags, UINT FXFlags, ID3D10Blob **ppCompiledEffect, ID3D10Blob **ppErrors); typedef HRESULT(WINAPI *LPD3D10CREATEEFFECTFROMMEMORY)(void *pData, SIZE_T DataLength, UINT FXFlags, ID3D10Device *pDevice, ID3D10EffectPool *pEffectPool, ID3D10Effect **ppEffect); typedef HRESULT(WINAPI *LPD3D10CREATEEFFECTPOOLFROMMEMORY)(void *pData, SIZE_T DataLength, UINT FXFlags, ID3D10Device *pDevice, ID3D10EffectPool **ppEffectPool); typedef HRESULT(WINAPI *LPD3D10CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter *pAdapter, D3D10_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, UINT SDKVersion, DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain, ID3D10Device **ppDevice); typedef HRESULT(WINAPI *LPD3D10CREATEDEVICEANDSWAPCHAIN1)(IDXGIAdapter *pAdapter, D3D10_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, D3D10_FEATURE_LEVEL1 HardwareLevel, UINT SDKVersion, DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain, ID3D10Device1 **ppDevice); // Build a perspective projection matrix. (left-handed) typedef D3DXMATRIX *(WINAPI *LPD3DXMATRIXPERSPECTIVEFOVLH)(D3DXMATRIX *pOut, FLOAT fovy, FLOAT Aspect, FLOAT zn, FLOAT zf); // Build a lookat matrix. (left-handed) typedef D3DXMATRIX *(WINAPI *LPD3DXMATRIXLOOKATLH)(D3DXMATRIX *pOut, CONST D3DXVECTOR3 *pEye, CONST D3DXVECTOR3 *pAt, CONST D3DXVECTOR3 *pUp); // Module and function pointers static HMODULE g_hModDXGI = NULL; static HMODULE g_hModD3DX10 = NULL; static HMODULE g_hModD3D10 = NULL; static HMODULE g_hModD3D101 = NULL; static LPCREATEDXGIFACTORY sFnPtr_CreateDXGIFactory = NULL; static LPD3D10CREATESTATEBLOCK sFnPtr_D3D10CreateStateBlock = NULL; static LPD3D10CREATEDEVICE sFnPtr_D3D10CreateDevice = NULL; static LPD3D10CREATEDEVICE1 sFnPtr_D3D10CreateDevice1 = NULL; static LPD3D10STATEBLOCKMASKUNION sFnPtr_D3D10StateBlockMaskUnion = NULL; static LPD3D10STATEBLOCKMASKINTERSECT sFnPtr_D3D10StateBlockMaskIntersect = NULL; static LPD3D10STATEBLOCKMASKDIFFERENCE sFnPtr_D3D10StateBlockMaskDifference = NULL; static LPD3D10STATEBLOCKMASKENABLECAPTURE sFnPtr_D3D10StateBlockMaskEnableCapture = NULL; static LPD3D10STATEBLOCKMASKDISABLECAPTURE sFnPtr_D3D10StateBlockMaskDisableCapture = NULL; static LPD3D10STATEBLOCKMASKENABLEALL sFnPtr_D3D10StateBlockMaskEnableAll = NULL; static LPD3D10STATEBLOCKMASKDISABLEALL sFnPtr_D3D10StateBlockMaskDisableAll = NULL; static LPD3D10STATEBLOCKMASKGETSETTING sFnPtr_D3D10StateBlockMaskGetSetting = NULL; static LPD3D10COMPILEEFFECTFROMMEMORY sFnPtr_D3D10CompileEffectFromMemory = NULL; static LPD3D10CREATEEFFECTFROMMEMORY sFnPtr_D3D10CreateEffectFromMemory = NULL; static LPD3D10CREATEEFFECTPOOLFROMMEMORY sFnPtr_D3D10CreateEffectPoolFromMemory = NULL; static LPD3D10CREATEDEVICEANDSWAPCHAIN sFnPtr_D3D10CreateDeviceAndSwapChain = NULL; static LPD3D10CREATEDEVICEANDSWAPCHAIN1 sFnPtr_D3D10CreateDeviceAndSwapChain1 = NULL; static LPD3DXMATRIXPERSPECTIVEFOVLH sFnPtr_D3DXMatrixPerspectiveFovLH = NULL; static LPD3DXMATRIXLOOKATLH sFnPtr_D3DXMatrixLookAtLH = NULL; // unload the D3D10 DLLs static bool dynlinkUnloadD3D10API(void) { if (g_hModD3D10) { FreeLibrary(g_hModD3D10); g_hModD3D10 = NULL; } if (g_hModD3DX10) { FreeLibrary(g_hModD3DX10); g_hModD3DX10 = NULL; } if (g_hModDXGI) { FreeLibrary(g_hModDXGI); g_hModDXGI = NULL; } if (g_hModD3D101) { FreeLibrary(g_hModD3D101); g_hModD3D101 = NULL; } return true; } // Dynamically load the D3D10 DLLs loaded and map the function pointers static bool dynlinkLoadD3D10API(void) { // First check to see if the D3D10 Library is present. // if it succeeds, then we can call GetProcAddress to grab all of the DX10 functions g_hModD3D10 = LoadLibrary("d3d10.dll"); if (g_hModD3D10 != NULL) { sFnPtr_D3D10CreateStateBlock = (LPD3D10CREATESTATEBLOCK) GetProcAddress(g_hModD3D10, "D3D10CreateStateBlock"); sFnPtr_D3D10CreateDevice = (LPD3D10CREATEDEVICE) GetProcAddress(g_hModD3D10, "D3D10CreateDevice"); sFnPtr_D3D10StateBlockMaskUnion = (LPD3D10STATEBLOCKMASKUNION) GetProcAddress(g_hModD3D10, "D3D10StateBlockMaskUnion"); sFnPtr_D3D10StateBlockMaskIntersect = (LPD3D10STATEBLOCKMASKINTERSECT) GetProcAddress(g_hModD3D10, "D3D10StateBlockMaskIntersect"); sFnPtr_D3D10StateBlockMaskDifference = (LPD3D10STATEBLOCKMASKDIFFERENCE) GetProcAddress(g_hModD3D10, "D3D10StateBlockMaskDifference"); sFnPtr_D3D10StateBlockMaskEnableCapture = (LPD3D10STATEBLOCKMASKENABLECAPTURE) GetProcAddress(g_hModD3D10, "D3D10StateBlockMaskEnableCapture"); sFnPtr_D3D10StateBlockMaskDisableCapture = (LPD3D10STATEBLOCKMASKDISABLECAPTURE)GetProcAddress(g_hModD3D10, "D3D10StateBlockMaskDisableCapture"); sFnPtr_D3D10StateBlockMaskEnableAll = (LPD3D10STATEBLOCKMASKENABLEALL) GetProcAddress(g_hModD3D10, "D3D10StateBlockMaskEnableAll"); sFnPtr_D3D10StateBlockMaskDisableAll = (LPD3D10STATEBLOCKMASKDISABLEALL) GetProcAddress(g_hModD3D10, "D3D10StateBlockMaskDisableAll"); sFnPtr_D3D10StateBlockMaskGetSetting = (LPD3D10STATEBLOCKMASKGETSETTING) GetProcAddress(g_hModD3D10, "D3D10StateBlockMaskGetSetting"); sFnPtr_D3D10CompileEffectFromMemory = (LPD3D10COMPILEEFFECTFROMMEMORY) GetProcAddress(g_hModD3D10, "D3D10CompileEffectFromMemory"); sFnPtr_D3D10CreateEffectFromMemory = (LPD3D10CREATEEFFECTFROMMEMORY) GetProcAddress(g_hModD3D10, "D3D10CreateEffectFromMemory"); sFnPtr_D3D10CreateEffectPoolFromMemory = (LPD3D10CREATEEFFECTPOOLFROMMEMORY) GetProcAddress(g_hModD3D10, "D3D10CreateEffectPoolFromMemory"); sFnPtr_D3D10CreateDeviceAndSwapChain = (LPD3D10CREATEDEVICEANDSWAPCHAIN) GetProcAddress(g_hModD3D10, "D3D10CreateDeviceAndSwapChain"); } g_hModD3DX10 = LoadLibrary("d3dx10.dll"); if (g_hModD3DX10) { sFnPtr_D3DXMatrixPerspectiveFovLH = (LPD3DXMATRIXPERSPECTIVEFOVLH) GetProcAddress(g_hModD3DX10, "D3DXMatrixPerspectiveFovLH"); sFnPtr_D3DXMatrixLookAtLH = (LPD3DXMATRIXLOOKATLH) GetProcAddress(g_hModD3DX10, "D3DXMatrixLookAtLH"); } g_hModDXGI = LoadLibrary("dxgi.dll"); if (g_hModDXGI) { sFnPtr_CreateDXGIFactory = (LPCREATEDXGIFACTORY) GetProcAddress(g_hModDXGI , "CreateDXGIFactory"); } // This may fail if this machine isn't Windows Vista SP1 or later g_hModD3D101 = LoadLibrary("d3d10_1.dll"); if (g_hModD3D101 != NULL) { sFnPtr_D3D10CreateDevice1 = (LPD3D10CREATEDEVICE1) GetProcAddress(g_hModD3D101, "D3D10CreateDevice1"); sFnPtr_D3D10CreateDeviceAndSwapChain1 = (LPD3D10CREATEDEVICEANDSWAPCHAIN1) GetProcAddress(g_hModD3D101, "D3D10CreateDeviceAndSwapChain1"); } if (g_hModD3D10 == NULL || g_hModD3DX10 == NULL || g_hModDXGI == NULL || g_hModD3D101 == NULL) { dynlinkUnloadD3D10API(); return false; } return true; } #endif ================================================ FILE: tests/projects/cuda/console/inc/dynlink_d3d11.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ //-------------------------------------------------------------------------------------- // File: dynlink_d3d11.h // // Shortcut macros and functions for using DX objects // // Copyright (c) Microsoft Corporation. All rights reserved //-------------------------------------------------------------------------------------- #ifndef _DYNLINK_D3D11_H_ #define _DYNLINK_D3D11_H_ // Standard Windows includes #include #include #include #include #include #include // for InitCommonControls() #include // for ExtractIcon() #include // for placement new #include #include #include #include // CRT's memory leak detection #if defined(DEBUG) || defined(_DEBUG) #include #endif // Direct3D9 includes //#include //#include // Direct3D10 includes #include #include #include // #include <..\Samples\C++\Effects11\Inc\d3dx11effect.h> // XInput includes #include // HRESULT translation for Direct3D10 and other APIs #include // strsafe.h deprecates old unsecure string functions. If you // really do not want to it to (not recommended), then uncomment the next line //#define STRSAFE_NO_DEPRECATE #ifndef STRSAFE_NO_DEPRECATE #pragma deprecated("strncpy") #pragma deprecated("wcsncpy") #pragma deprecated("_tcsncpy") #pragma deprecated("wcsncat") #pragma deprecated("strncat") #pragma deprecated("_tcsncat") #endif #pragma warning( disable : 4996 ) // disable deprecated warning #include #pragma warning( default : 4996 ) typedef HRESULT(WINAPI *LPCREATEDXGIFACTORY)(REFIID, void **); typedef HRESULT(WINAPI *LPD3D11CREATEDEVICEANDSWAPCHAIN)(__in_opt IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, __in_ecount_opt(FeatureLevels) CONST D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, __in_opt CONST DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, __out_opt IDXGISwapChain **ppSwapChain, __out_opt ID3D11Device **ppDevice, __out_opt D3D_FEATURE_LEVEL *pFeatureLevel, __out_opt ID3D11DeviceContext **ppImmediateContext); typedef HRESULT(WINAPI *LPD3D11CREATEDEVICE)(IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT32, D3D_FEATURE_LEVEL *, UINT, UINT32, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **); typedef void (WINAPI *LPD3DX11COMPILEFROMMEMORY)(LPCSTR pSrcData, SIZE_T SrcDataLen, LPCSTR pFileName, CONST D3D10_SHADER_MACRO *pDefines, LPD3D10INCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, UINT Flags1, UINT Flags2, ID3DX11ThreadPump *pPump, ID3D10Blob **ppShader, ID3D10Blob **ppErrorMsgs, HRESULT *pHResult); static HMODULE s_hModDXGI = NULL; static LPCREATEDXGIFACTORY sFnPtr_CreateDXGIFactory = NULL; static HMODULE s_hModD3D11 = NULL; static HMODULE s_hModD3DX11 = NULL; static LPD3D11CREATEDEVICE sFnPtr_D3D11CreateDevice = NULL; static LPD3D11CREATEDEVICEANDSWAPCHAIN sFnPtr_D3D11CreateDeviceAndSwapChain = NULL; static LPD3DX11COMPILEFROMMEMORY sFnPtr_D3DX11CompileFromMemory = NULL; // unload the D3D10 DLLs static bool dynlinkUnloadD3D11API(void) { if (s_hModDXGI) { FreeLibrary(s_hModDXGI); s_hModDXGI = NULL; } if (s_hModD3D11) { FreeLibrary(s_hModD3D11); s_hModD3D11 = NULL; } if (s_hModD3DX11) { FreeLibrary(s_hModD3DX11); s_hModD3DX11 = NULL; } return true; } // Dynamically load the D3D11 DLLs loaded and map the function pointers static bool dynlinkLoadD3D11API(void) { // If both modules are non-NULL, this function has already been called. Note // that this doesn't guarantee that all ProcAddresses were found. if (s_hModD3D11 != NULL && s_hModD3DX11 != NULL && s_hModDXGI != NULL) { return true; } #if 1 // This may fail if Direct3D 11 isn't installed s_hModD3D11 = LoadLibrary("d3d11.dll"); if (s_hModD3D11 != NULL) { sFnPtr_D3D11CreateDevice = (LPD3D11CREATEDEVICE)GetProcAddress(s_hModD3D11, "D3D11CreateDevice"); sFnPtr_D3D11CreateDeviceAndSwapChain = (LPD3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(s_hModD3D11, "D3D11CreateDeviceAndSwapChain"); } // first try to load D3DX11CompileFromMemory from DirectX 2010 June s_hModD3DX11 = LoadLibrary("D3DX11d_43.dll"); if (s_hModD3DX11 != NULL) { sFnPtr_D3DX11CompileFromMemory = (LPD3DX11COMPILEFROMMEMORY) GetProcAddress(s_hModD3DX11, "D3DX11CompileFromMemory"); } else // if absent try to take it from DirectX 2010 Feb { s_hModD3DX11 = LoadLibrary("D3DX11d_42.dll"); if (s_hModD3DX11 != NULL) { sFnPtr_D3DX11CompileFromMemory = (LPD3DX11COMPILEFROMMEMORY) GetProcAddress(s_hModD3DX11, "D3DX11CompileFromMemory"); } } if (!sFnPtr_CreateDXGIFactory) { s_hModDXGI = LoadLibrary("dxgi.dll"); if (s_hModDXGI) { sFnPtr_CreateDXGIFactory = (LPCREATEDXGIFACTORY)GetProcAddress(s_hModDXGI, "CreateDXGIFactory1"); } return (s_hModDXGI != NULL) && (s_hModD3D11 != NULL); } return (s_hModD3D11 != NULL); #else sFnPtr_D3D11CreateDevice = (LPD3D11CREATEDEVICE)D3D11CreateDeviceAndSwapChain; sFnPtr_D3D11CreateDeviceAndSwapChain = (LPD3D11CREATEDEVICEANDSWAPCHAIN)D3D11CreateDeviceAndSwapChain; //sFnPtr_D3DX11CreateEffectFromMemory = ( LPD3DX11CREATEEFFECTFROMMEMORY )D3DX11CreateEffectFromMemory; sFnPtr_D3DX11CompileFromMemory = (LPD3DX11COMPILEFROMMEMORY)D3DX11CompileFromMemory; sFnPtr_CreateDXGIFactory = (LPCREATEDXGIFACTORY)CreateDXGIFactory; return true; #endif return true; } #endif ================================================ FILE: tests/projects/cuda/console/inc/exception.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ /* CUda UTility Library */ #ifndef _EXCEPTION_H_ #define _EXCEPTION_H_ // includes, system #include #include #include #include //! Exception wrapper. //! @param Std_Exception Exception out of namespace std for easy typing. template class Exception : public Std_Exception { public: //! @brief Static construction interface //! @return Alwayss throws ( Located_Exception) //! @param file file in which the Exception occurs //! @param line line in which the Exception occurs //! @param detailed details on the code fragment causing the Exception static void throw_it(const char *file, const int line, const char *detailed = "-"); //! Static construction interface //! @return Alwayss throws ( Located_Exception) //! @param file file in which the Exception occurs //! @param line line in which the Exception occurs //! @param detailed details on the code fragment causing the Exception static void throw_it(const char *file, const int line, const std::string &detailed); //! Destructor virtual ~Exception() throw(); private: //! Constructor, default (private) Exception(); //! Constructor, standard //! @param str string returned by what() Exception(const std::string &str); }; //////////////////////////////////////////////////////////////////////////////// //! Exception handler function for arbitrary exceptions //! @param ex exception to handle //////////////////////////////////////////////////////////////////////////////// template inline void handleException(const Exception_Typ &ex) { std::cerr << ex.what() << std::endl; exit(EXIT_FAILURE); } //! Convenience macros //! Exception caused by dynamic program behavior, e.g. file does not exist #define RUNTIME_EXCEPTION( msg) \ Exception::throw_it( __FILE__, __LINE__, msg) //! Logic exception in program, e.g. an assert failed #define LOGIC_EXCEPTION( msg) \ Exception::throw_it( __FILE__, __LINE__, msg) //! Out of range exception #define RANGE_EXCEPTION( msg) \ Exception::throw_it( __FILE__, __LINE__, msg) //////////////////////////////////////////////////////////////////////////////// //! Implementation // includes, system #include //////////////////////////////////////////////////////////////////////////////// //! Static construction interface. //! @param Exception causing code fragment (file and line) and detailed infos. //////////////////////////////////////////////////////////////////////////////// /*static*/ template void Exception:: throw_it(const char *file, const int line, const char *detailed) { std::stringstream s; // Quiet heavy-weight but exceptions are not for // performance / release versions s << "Exception in file '" << file << "' in line " << line << "\n" << "Detailed description: " << detailed << "\n"; throw Exception(s.str()); } //////////////////////////////////////////////////////////////////////////////// //! Static construction interface. //! @param Exception causing code fragment (file and line) and detailed infos. //////////////////////////////////////////////////////////////////////////////// /*static*/ template void Exception:: throw_it(const char *file, const int line, const std::string &msg) { throw_it(file, line, msg.c_str()); } //////////////////////////////////////////////////////////////////////////////// //! Constructor, default (private). //////////////////////////////////////////////////////////////////////////////// template Exception::Exception() : Std_Exception("Unknown Exception.\n") { } //////////////////////////////////////////////////////////////////////////////// //! Constructor, standard (private). //! String returned by what(). //////////////////////////////////////////////////////////////////////////////// template Exception::Exception(const std::string &s) : Std_Exception(s) { } //////////////////////////////////////////////////////////////////////////////// //! Destructor //////////////////////////////////////////////////////////////////////////////// template Exception::~Exception() throw() { } // functions, exported #endif // #ifndef _EXCEPTION_H_ ================================================ FILE: tests/projects/cuda/console/inc/helper_cuda.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ //////////////////////////////////////////////////////////////////////////////// // These are CUDA Helper functions for initialization and error checking #ifndef HELPER_CUDA_H #define HELPER_CUDA_H #pragma once #include #include #include #include #ifndef EXIT_WAIVED #define EXIT_WAIVED 2 #endif // Note, it is required that your SDK sample to include the proper header files, please // refer the CUDA examples for examples of the needed CUDA headers, which may change depending // on which CUDA functions are used. // CUDA Runtime error messages #ifdef __DRIVER_TYPES_H__ static const char *_cudaGetErrorEnum(cudaError_t error) { switch (error) { case cudaSuccess: return "cudaSuccess"; case cudaErrorMissingConfiguration: return "cudaErrorMissingConfiguration"; case cudaErrorMemoryAllocation: return "cudaErrorMemoryAllocation"; case cudaErrorInitializationError: return "cudaErrorInitializationError"; case cudaErrorLaunchFailure: return "cudaErrorLaunchFailure"; case cudaErrorPriorLaunchFailure: return "cudaErrorPriorLaunchFailure"; case cudaErrorLaunchTimeout: return "cudaErrorLaunchTimeout"; case cudaErrorLaunchOutOfResources: return "cudaErrorLaunchOutOfResources"; case cudaErrorInvalidDeviceFunction: return "cudaErrorInvalidDeviceFunction"; case cudaErrorInvalidConfiguration: return "cudaErrorInvalidConfiguration"; case cudaErrorInvalidDevice: return "cudaErrorInvalidDevice"; case cudaErrorInvalidValue: return "cudaErrorInvalidValue"; case cudaErrorInvalidPitchValue: return "cudaErrorInvalidPitchValue"; case cudaErrorInvalidSymbol: return "cudaErrorInvalidSymbol"; case cudaErrorMapBufferObjectFailed: return "cudaErrorMapBufferObjectFailed"; case cudaErrorUnmapBufferObjectFailed: return "cudaErrorUnmapBufferObjectFailed"; case cudaErrorInvalidHostPointer: return "cudaErrorInvalidHostPointer"; case cudaErrorInvalidDevicePointer: return "cudaErrorInvalidDevicePointer"; case cudaErrorInvalidTexture: return "cudaErrorInvalidTexture"; case cudaErrorInvalidTextureBinding: return "cudaErrorInvalidTextureBinding"; case cudaErrorInvalidChannelDescriptor: return "cudaErrorInvalidChannelDescriptor"; case cudaErrorInvalidMemcpyDirection: return "cudaErrorInvalidMemcpyDirection"; case cudaErrorAddressOfConstant: return "cudaErrorAddressOfConstant"; case cudaErrorTextureFetchFailed: return "cudaErrorTextureFetchFailed"; case cudaErrorTextureNotBound: return "cudaErrorTextureNotBound"; case cudaErrorSynchronizationError: return "cudaErrorSynchronizationError"; case cudaErrorInvalidFilterSetting: return "cudaErrorInvalidFilterSetting"; case cudaErrorInvalidNormSetting: return "cudaErrorInvalidNormSetting"; case cudaErrorMixedDeviceExecution: return "cudaErrorMixedDeviceExecution"; case cudaErrorCudartUnloading: return "cudaErrorCudartUnloading"; case cudaErrorUnknown: return "cudaErrorUnknown"; case cudaErrorNotYetImplemented: return "cudaErrorNotYetImplemented"; case cudaErrorMemoryValueTooLarge: return "cudaErrorMemoryValueTooLarge"; case cudaErrorInvalidResourceHandle: return "cudaErrorInvalidResourceHandle"; case cudaErrorNotReady: return "cudaErrorNotReady"; case cudaErrorInsufficientDriver: return "cudaErrorInsufficientDriver"; case cudaErrorSetOnActiveProcess: return "cudaErrorSetOnActiveProcess"; case cudaErrorInvalidSurface: return "cudaErrorInvalidSurface"; case cudaErrorNoDevice: return "cudaErrorNoDevice"; case cudaErrorECCUncorrectable: return "cudaErrorECCUncorrectable"; case cudaErrorSharedObjectSymbolNotFound: return "cudaErrorSharedObjectSymbolNotFound"; case cudaErrorSharedObjectInitFailed: return "cudaErrorSharedObjectInitFailed"; case cudaErrorUnsupportedLimit: return "cudaErrorUnsupportedLimit"; case cudaErrorDuplicateVariableName: return "cudaErrorDuplicateVariableName"; case cudaErrorDuplicateTextureName: return "cudaErrorDuplicateTextureName"; case cudaErrorDuplicateSurfaceName: return "cudaErrorDuplicateSurfaceName"; case cudaErrorDevicesUnavailable: return "cudaErrorDevicesUnavailable"; case cudaErrorInvalidKernelImage: return "cudaErrorInvalidKernelImage"; case cudaErrorNoKernelImageForDevice: return "cudaErrorNoKernelImageForDevice"; case cudaErrorIncompatibleDriverContext: return "cudaErrorIncompatibleDriverContext"; case cudaErrorPeerAccessAlreadyEnabled: return "cudaErrorPeerAccessAlreadyEnabled"; case cudaErrorPeerAccessNotEnabled: return "cudaErrorPeerAccessNotEnabled"; case cudaErrorDeviceAlreadyInUse: return "cudaErrorDeviceAlreadyInUse"; case cudaErrorProfilerDisabled: return "cudaErrorProfilerDisabled"; case cudaErrorProfilerNotInitialized: return "cudaErrorProfilerNotInitialized"; case cudaErrorProfilerAlreadyStarted: return "cudaErrorProfilerAlreadyStarted"; case cudaErrorProfilerAlreadyStopped: return "cudaErrorProfilerAlreadyStopped"; /* Since CUDA 4.0*/ case cudaErrorAssert: return "cudaErrorAssert"; case cudaErrorTooManyPeers: return "cudaErrorTooManyPeers"; case cudaErrorHostMemoryAlreadyRegistered: return "cudaErrorHostMemoryAlreadyRegistered"; case cudaErrorHostMemoryNotRegistered: return "cudaErrorHostMemoryNotRegistered"; /* Since CUDA 5.0 */ case cudaErrorOperatingSystem: return "cudaErrorOperatingSystem"; case cudaErrorPeerAccessUnsupported: return "cudaErrorPeerAccessUnsupported"; case cudaErrorLaunchMaxDepthExceeded: return "cudaErrorLaunchMaxDepthExceeded"; case cudaErrorLaunchFileScopedTex: return "cudaErrorLaunchFileScopedTex"; case cudaErrorLaunchFileScopedSurf: return "cudaErrorLaunchFileScopedSurf"; case cudaErrorSyncDepthExceeded: return "cudaErrorSyncDepthExceeded"; case cudaErrorLaunchPendingCountExceeded: return "cudaErrorLaunchPendingCountExceeded"; case cudaErrorNotPermitted: return "cudaErrorNotPermitted"; case cudaErrorNotSupported: return "cudaErrorNotSupported"; /* Since CUDA 6.0 */ case cudaErrorHardwareStackError: return "cudaErrorHardwareStackError"; case cudaErrorIllegalInstruction: return "cudaErrorIllegalInstruction"; case cudaErrorMisalignedAddress: return "cudaErrorMisalignedAddress"; case cudaErrorInvalidAddressSpace: return "cudaErrorInvalidAddressSpace"; case cudaErrorInvalidPc: return "cudaErrorInvalidPc"; case cudaErrorIllegalAddress: return "cudaErrorIllegalAddress"; /* Since CUDA 6.5*/ case cudaErrorInvalidPtx: return "cudaErrorInvalidPtx"; case cudaErrorInvalidGraphicsContext: return "cudaErrorInvalidGraphicsContext"; case cudaErrorStartupFailure: return "cudaErrorStartupFailure"; case cudaErrorApiFailureBase: return "cudaErrorApiFailureBase"; /* Since CUDA 8.0*/ case cudaErrorNvlinkUncorrectable : return "cudaErrorNvlinkUncorrectable"; /* Since CUDA 8.5*/ case cudaErrorJitCompilerNotFound : return "cudaErrorJitCompilerNotFound"; /* Since CUDA 9.0*/ case cudaErrorCooperativeLaunchTooLarge : return "cudaErrorCooperativeLaunchTooLarge"; } return ""; } #endif #ifdef __cuda_cuda_h__ // CUDA Driver API errors static const char *_cudaGetErrorEnum(CUresult error) { switch (error) { case CUDA_SUCCESS: return "CUDA_SUCCESS"; case CUDA_ERROR_INVALID_VALUE: return "CUDA_ERROR_INVALID_VALUE"; case CUDA_ERROR_OUT_OF_MEMORY: return "CUDA_ERROR_OUT_OF_MEMORY"; case CUDA_ERROR_NOT_INITIALIZED: return "CUDA_ERROR_NOT_INITIALIZED"; case CUDA_ERROR_DEINITIALIZED: return "CUDA_ERROR_DEINITIALIZED"; case CUDA_ERROR_PROFILER_DISABLED: return "CUDA_ERROR_PROFILER_DISABLED"; case CUDA_ERROR_PROFILER_NOT_INITIALIZED: return "CUDA_ERROR_PROFILER_NOT_INITIALIZED"; case CUDA_ERROR_PROFILER_ALREADY_STARTED: return "CUDA_ERROR_PROFILER_ALREADY_STARTED"; case CUDA_ERROR_PROFILER_ALREADY_STOPPED: return "CUDA_ERROR_PROFILER_ALREADY_STOPPED"; case CUDA_ERROR_NO_DEVICE: return "CUDA_ERROR_NO_DEVICE"; case CUDA_ERROR_INVALID_DEVICE: return "CUDA_ERROR_INVALID_DEVICE"; case CUDA_ERROR_INVALID_IMAGE: return "CUDA_ERROR_INVALID_IMAGE"; case CUDA_ERROR_INVALID_CONTEXT: return "CUDA_ERROR_INVALID_CONTEXT"; case CUDA_ERROR_CONTEXT_ALREADY_CURRENT: return "CUDA_ERROR_CONTEXT_ALREADY_CURRENT"; case CUDA_ERROR_MAP_FAILED: return "CUDA_ERROR_MAP_FAILED"; case CUDA_ERROR_UNMAP_FAILED: return "CUDA_ERROR_UNMAP_FAILED"; case CUDA_ERROR_ARRAY_IS_MAPPED: return "CUDA_ERROR_ARRAY_IS_MAPPED"; case CUDA_ERROR_ALREADY_MAPPED: return "CUDA_ERROR_ALREADY_MAPPED"; case CUDA_ERROR_NO_BINARY_FOR_GPU: return "CUDA_ERROR_NO_BINARY_FOR_GPU"; case CUDA_ERROR_ALREADY_ACQUIRED: return "CUDA_ERROR_ALREADY_ACQUIRED"; case CUDA_ERROR_NOT_MAPPED: return "CUDA_ERROR_NOT_MAPPED"; case CUDA_ERROR_NOT_MAPPED_AS_ARRAY: return "CUDA_ERROR_NOT_MAPPED_AS_ARRAY"; case CUDA_ERROR_NOT_MAPPED_AS_POINTER: return "CUDA_ERROR_NOT_MAPPED_AS_POINTER"; case CUDA_ERROR_ECC_UNCORRECTABLE: return "CUDA_ERROR_ECC_UNCORRECTABLE"; case CUDA_ERROR_UNSUPPORTED_LIMIT: return "CUDA_ERROR_UNSUPPORTED_LIMIT"; case CUDA_ERROR_CONTEXT_ALREADY_IN_USE: return "CUDA_ERROR_CONTEXT_ALREADY_IN_USE"; case CUDA_ERROR_PEER_ACCESS_UNSUPPORTED: return "CUDA_ERROR_PEER_ACCESS_UNSUPPORTED"; case CUDA_ERROR_INVALID_PTX: return "CUDA_ERROR_INVALID_PTX"; case CUDA_ERROR_INVALID_GRAPHICS_CONTEXT: return "CUDA_ERROR_INVALID_GRAPHICS_CONTEXT"; case CUDA_ERROR_NVLINK_UNCORRECTABLE: return "CUDA_ERROR_NVLINK_UNCORRECTABLE"; case CUDA_ERROR_JIT_COMPILER_NOT_FOUND: return "CUDA_ERROR_JIT_COMPILER_NOT_FOUND"; case CUDA_ERROR_INVALID_SOURCE: return "CUDA_ERROR_INVALID_SOURCE"; case CUDA_ERROR_FILE_NOT_FOUND: return "CUDA_ERROR_FILE_NOT_FOUND"; case CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND: return "CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND"; case CUDA_ERROR_SHARED_OBJECT_INIT_FAILED: return "CUDA_ERROR_SHARED_OBJECT_INIT_FAILED"; case CUDA_ERROR_OPERATING_SYSTEM: return "CUDA_ERROR_OPERATING_SYSTEM"; case CUDA_ERROR_INVALID_HANDLE: return "CUDA_ERROR_INVALID_HANDLE"; case CUDA_ERROR_NOT_FOUND: return "CUDA_ERROR_NOT_FOUND"; case CUDA_ERROR_NOT_READY: return "CUDA_ERROR_NOT_READY"; case CUDA_ERROR_ILLEGAL_ADDRESS: return "CUDA_ERROR_ILLEGAL_ADDRESS"; case CUDA_ERROR_LAUNCH_FAILED: return "CUDA_ERROR_LAUNCH_FAILED"; case CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES: return "CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES"; case CUDA_ERROR_LAUNCH_TIMEOUT: return "CUDA_ERROR_LAUNCH_TIMEOUT"; case CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING: return "CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING"; case CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED: return "CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED"; case CUDA_ERROR_PEER_ACCESS_NOT_ENABLED: return "CUDA_ERROR_PEER_ACCESS_NOT_ENABLED"; case CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE: return "CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE"; case CUDA_ERROR_CONTEXT_IS_DESTROYED: return "CUDA_ERROR_CONTEXT_IS_DESTROYED"; case CUDA_ERROR_ASSERT: return "CUDA_ERROR_ASSERT"; case CUDA_ERROR_TOO_MANY_PEERS: return "CUDA_ERROR_TOO_MANY_PEERS"; case CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED: return "CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED"; case CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED: return "CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED"; case CUDA_ERROR_HARDWARE_STACK_ERROR: return "CUDA_ERROR_HARDWARE_STACK_ERROR"; case CUDA_ERROR_ILLEGAL_INSTRUCTION: return "CUDA_ERROR_ILLEGAL_INSTRUCTION"; case CUDA_ERROR_MISALIGNED_ADDRESS: return "CUDA_ERROR_MISALIGNED_ADDRESS"; case CUDA_ERROR_INVALID_ADDRESS_SPACE: return "CUDA_ERROR_INVALID_ADDRESS_SPACE"; case CUDA_ERROR_INVALID_PC: return "CUDA_ERROR_INVALID_PC"; case CUDA_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE: return "CUDA_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE"; case CUDA_ERROR_NOT_PERMITTED: return "CUDA_ERROR_NOT_PERMITTED"; case CUDA_ERROR_NOT_SUPPORTED: return "CUDA_ERROR_NOT_SUPPORTED"; case CUDA_ERROR_UNKNOWN: return "CUDA_ERROR_UNKNOWN"; } return ""; } #endif #ifdef CUBLAS_API_H_ // cuBLAS API errors static const char *_cudaGetErrorEnum(cublasStatus_t error) { switch (error) { case CUBLAS_STATUS_SUCCESS: return "CUBLAS_STATUS_SUCCESS"; case CUBLAS_STATUS_NOT_INITIALIZED: return "CUBLAS_STATUS_NOT_INITIALIZED"; case CUBLAS_STATUS_ALLOC_FAILED: return "CUBLAS_STATUS_ALLOC_FAILED"; case CUBLAS_STATUS_INVALID_VALUE: return "CUBLAS_STATUS_INVALID_VALUE"; case CUBLAS_STATUS_ARCH_MISMATCH: return "CUBLAS_STATUS_ARCH_MISMATCH"; case CUBLAS_STATUS_MAPPING_ERROR: return "CUBLAS_STATUS_MAPPING_ERROR"; case CUBLAS_STATUS_EXECUTION_FAILED: return "CUBLAS_STATUS_EXECUTION_FAILED"; case CUBLAS_STATUS_INTERNAL_ERROR: return "CUBLAS_STATUS_INTERNAL_ERROR"; case CUBLAS_STATUS_NOT_SUPPORTED: return "CUBLAS_STATUS_NOT_SUPPORTED"; case CUBLAS_STATUS_LICENSE_ERROR: return "CUBLAS_STATUS_LICENSE_ERROR"; } return ""; } #endif #ifdef _CUFFT_H_ // cuFFT API errors static const char *_cudaGetErrorEnum(cufftResult error) { switch (error) { case CUFFT_SUCCESS: return "CUFFT_SUCCESS"; case CUFFT_INVALID_PLAN: return "CUFFT_INVALID_PLAN"; case CUFFT_ALLOC_FAILED: return "CUFFT_ALLOC_FAILED"; case CUFFT_INVALID_TYPE: return "CUFFT_INVALID_TYPE"; case CUFFT_INVALID_VALUE: return "CUFFT_INVALID_VALUE"; case CUFFT_INTERNAL_ERROR: return "CUFFT_INTERNAL_ERROR"; case CUFFT_EXEC_FAILED: return "CUFFT_EXEC_FAILED"; case CUFFT_SETUP_FAILED: return "CUFFT_SETUP_FAILED"; case CUFFT_INVALID_SIZE: return "CUFFT_INVALID_SIZE"; case CUFFT_UNALIGNED_DATA: return "CUFFT_UNALIGNED_DATA"; case CUFFT_INCOMPLETE_PARAMETER_LIST: return "CUFFT_INCOMPLETE_PARAMETER_LIST"; case CUFFT_INVALID_DEVICE: return "CUFFT_INVALID_DEVICE"; case CUFFT_PARSE_ERROR: return "CUFFT_PARSE_ERROR"; case CUFFT_NO_WORKSPACE: return "CUFFT_NO_WORKSPACE"; case CUFFT_NOT_IMPLEMENTED: return "CUFFT_NOT_IMPLEMENTED"; case CUFFT_LICENSE_ERROR: return "CUFFT_LICENSE_ERROR"; case CUFFT_NOT_SUPPORTED: return "CUFFT_NOT_SUPPORTED"; } return ""; } #endif #ifdef CUSPARSEAPI // cuSPARSE API errors static const char *_cudaGetErrorEnum(cusparseStatus_t error) { switch (error) { case CUSPARSE_STATUS_SUCCESS: return "CUSPARSE_STATUS_SUCCESS"; case CUSPARSE_STATUS_NOT_INITIALIZED: return "CUSPARSE_STATUS_NOT_INITIALIZED"; case CUSPARSE_STATUS_ALLOC_FAILED: return "CUSPARSE_STATUS_ALLOC_FAILED"; case CUSPARSE_STATUS_INVALID_VALUE: return "CUSPARSE_STATUS_INVALID_VALUE"; case CUSPARSE_STATUS_ARCH_MISMATCH: return "CUSPARSE_STATUS_ARCH_MISMATCH"; case CUSPARSE_STATUS_MAPPING_ERROR: return "CUSPARSE_STATUS_MAPPING_ERROR"; case CUSPARSE_STATUS_EXECUTION_FAILED: return "CUSPARSE_STATUS_EXECUTION_FAILED"; case CUSPARSE_STATUS_INTERNAL_ERROR: return "CUSPARSE_STATUS_INTERNAL_ERROR"; case CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED: return "CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED"; } return ""; } #endif #ifdef CUSOLVER_COMMON_H_ //cuSOLVER API errors static const char *_cudaGetErrorEnum(cusolverStatus_t error) { switch(error) { case CUSOLVER_STATUS_SUCCESS: return "CUSOLVER_STATUS_SUCCESS"; case CUSOLVER_STATUS_NOT_INITIALIZED: return "CUSOLVER_STATUS_NOT_INITIALIZED"; case CUSOLVER_STATUS_ALLOC_FAILED: return "CUSOLVER_STATUS_ALLOC_FAILED"; case CUSOLVER_STATUS_INVALID_VALUE: return "CUSOLVER_STATUS_INVALID_VALUE"; case CUSOLVER_STATUS_ARCH_MISMATCH: return "CUSOLVER_STATUS_ARCH_MISMATCH"; case CUSOLVER_STATUS_MAPPING_ERROR: return "CUSOLVER_STATUS_MAPPING_ERROR"; case CUSOLVER_STATUS_EXECUTION_FAILED: return "CUSOLVER_STATUS_EXECUTION_FAILED"; case CUSOLVER_STATUS_INTERNAL_ERROR: return "CUSOLVER_STATUS_INTERNAL_ERROR"; case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED: return "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED"; case CUSOLVER_STATUS_NOT_SUPPORTED : return "CUSOLVER_STATUS_NOT_SUPPORTED "; case CUSOLVER_STATUS_ZERO_PIVOT: return "CUSOLVER_STATUS_ZERO_PIVOT"; case CUSOLVER_STATUS_INVALID_LICENSE: return "CUSOLVER_STATUS_INVALID_LICENSE"; } return ""; } #endif #ifdef CURAND_H_ // cuRAND API errors static const char *_cudaGetErrorEnum(curandStatus_t error) { switch (error) { case CURAND_STATUS_SUCCESS: return "CURAND_STATUS_SUCCESS"; case CURAND_STATUS_VERSION_MISMATCH: return "CURAND_STATUS_VERSION_MISMATCH"; case CURAND_STATUS_NOT_INITIALIZED: return "CURAND_STATUS_NOT_INITIALIZED"; case CURAND_STATUS_ALLOCATION_FAILED: return "CURAND_STATUS_ALLOCATION_FAILED"; case CURAND_STATUS_TYPE_ERROR: return "CURAND_STATUS_TYPE_ERROR"; case CURAND_STATUS_OUT_OF_RANGE: return "CURAND_STATUS_OUT_OF_RANGE"; case CURAND_STATUS_LENGTH_NOT_MULTIPLE: return "CURAND_STATUS_LENGTH_NOT_MULTIPLE"; case CURAND_STATUS_DOUBLE_PRECISION_REQUIRED: return "CURAND_STATUS_DOUBLE_PRECISION_REQUIRED"; case CURAND_STATUS_LAUNCH_FAILURE: return "CURAND_STATUS_LAUNCH_FAILURE"; case CURAND_STATUS_PREEXISTING_FAILURE: return "CURAND_STATUS_PREEXISTING_FAILURE"; case CURAND_STATUS_INITIALIZATION_FAILED: return "CURAND_STATUS_INITIALIZATION_FAILED"; case CURAND_STATUS_ARCH_MISMATCH: return "CURAND_STATUS_ARCH_MISMATCH"; case CURAND_STATUS_INTERNAL_ERROR: return "CURAND_STATUS_INTERNAL_ERROR"; } return ""; } #endif #ifdef NV_NPPIDEFS_H // NPP API errors static const char *_cudaGetErrorEnum(NppStatus error) { switch (error) { case NPP_NOT_SUPPORTED_MODE_ERROR: return "NPP_NOT_SUPPORTED_MODE_ERROR"; case NPP_ROUND_MODE_NOT_SUPPORTED_ERROR: return "NPP_ROUND_MODE_NOT_SUPPORTED_ERROR"; case NPP_RESIZE_NO_OPERATION_ERROR: return "NPP_RESIZE_NO_OPERATION_ERROR"; case NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY: return "NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY"; #if ((NPP_VERSION_MAJOR << 12) + (NPP_VERSION_MINOR << 4)) <= 0x5000 case NPP_BAD_ARG_ERROR: return "NPP_BAD_ARGUMENT_ERROR"; case NPP_COEFF_ERROR: return "NPP_COEFFICIENT_ERROR"; case NPP_RECT_ERROR: return "NPP_RECTANGLE_ERROR"; case NPP_QUAD_ERROR: return "NPP_QUADRANGLE_ERROR"; case NPP_MEM_ALLOC_ERR: return "NPP_MEMORY_ALLOCATION_ERROR"; case NPP_HISTO_NUMBER_OF_LEVELS_ERROR: return "NPP_HISTOGRAM_NUMBER_OF_LEVELS_ERROR"; case NPP_INVALID_INPUT: return "NPP_INVALID_INPUT"; case NPP_POINTER_ERROR: return "NPP_POINTER_ERROR"; case NPP_WARNING: return "NPP_WARNING"; case NPP_ODD_ROI_WARNING: return "NPP_ODD_ROI_WARNING"; #else // These are for CUDA 5.5 or higher case NPP_BAD_ARGUMENT_ERROR: return "NPP_BAD_ARGUMENT_ERROR"; case NPP_COEFFICIENT_ERROR: return "NPP_COEFFICIENT_ERROR"; case NPP_RECTANGLE_ERROR: return "NPP_RECTANGLE_ERROR"; case NPP_QUADRANGLE_ERROR: return "NPP_QUADRANGLE_ERROR"; case NPP_MEMORY_ALLOCATION_ERR: return "NPP_MEMORY_ALLOCATION_ERROR"; case NPP_HISTOGRAM_NUMBER_OF_LEVELS_ERROR: return "NPP_HISTOGRAM_NUMBER_OF_LEVELS_ERROR"; case NPP_INVALID_HOST_POINTER_ERROR: return "NPP_INVALID_HOST_POINTER_ERROR"; case NPP_INVALID_DEVICE_POINTER_ERROR: return "NPP_INVALID_DEVICE_POINTER_ERROR"; #endif case NPP_LUT_NUMBER_OF_LEVELS_ERROR: return "NPP_LUT_NUMBER_OF_LEVELS_ERROR"; case NPP_TEXTURE_BIND_ERROR: return "NPP_TEXTURE_BIND_ERROR"; case NPP_WRONG_INTERSECTION_ROI_ERROR: return "NPP_WRONG_INTERSECTION_ROI_ERROR"; case NPP_NOT_EVEN_STEP_ERROR: return "NPP_NOT_EVEN_STEP_ERROR"; case NPP_INTERPOLATION_ERROR: return "NPP_INTERPOLATION_ERROR"; case NPP_RESIZE_FACTOR_ERROR: return "NPP_RESIZE_FACTOR_ERROR"; case NPP_HAAR_CLASSIFIER_PIXEL_MATCH_ERROR: return "NPP_HAAR_CLASSIFIER_PIXEL_MATCH_ERROR"; #if ((NPP_VERSION_MAJOR << 12) + (NPP_VERSION_MINOR << 4)) <= 0x5000 case NPP_MEMFREE_ERR: return "NPP_MEMFREE_ERR"; case NPP_MEMSET_ERR: return "NPP_MEMSET_ERR"; case NPP_MEMCPY_ERR: return "NPP_MEMCPY_ERROR"; case NPP_MIRROR_FLIP_ERR: return "NPP_MIRROR_FLIP_ERR"; #else case NPP_MEMFREE_ERROR: return "NPP_MEMFREE_ERROR"; case NPP_MEMSET_ERROR: return "NPP_MEMSET_ERROR"; case NPP_MEMCPY_ERROR: return "NPP_MEMCPY_ERROR"; case NPP_MIRROR_FLIP_ERROR: return "NPP_MIRROR_FLIP_ERROR"; #endif case NPP_ALIGNMENT_ERROR: return "NPP_ALIGNMENT_ERROR"; case NPP_STEP_ERROR: return "NPP_STEP_ERROR"; case NPP_SIZE_ERROR: return "NPP_SIZE_ERROR"; case NPP_NULL_POINTER_ERROR: return "NPP_NULL_POINTER_ERROR"; case NPP_CUDA_KERNEL_EXECUTION_ERROR: return "NPP_CUDA_KERNEL_EXECUTION_ERROR"; case NPP_NOT_IMPLEMENTED_ERROR: return "NPP_NOT_IMPLEMENTED_ERROR"; case NPP_ERROR: return "NPP_ERROR"; case NPP_SUCCESS: return "NPP_SUCCESS"; case NPP_WRONG_INTERSECTION_QUAD_WARNING: return "NPP_WRONG_INTERSECTION_QUAD_WARNING"; case NPP_MISALIGNED_DST_ROI_WARNING: return "NPP_MISALIGNED_DST_ROI_WARNING"; case NPP_AFFINE_QUAD_INCORRECT_WARNING: return "NPP_AFFINE_QUAD_INCORRECT_WARNING"; case NPP_DOUBLE_SIZE_WARNING: return "NPP_DOUBLE_SIZE_WARNING"; case NPP_WRONG_INTERSECTION_ROI_WARNING: return "NPP_WRONG_INTERSECTION_ROI_WARNING"; #if ((NPP_VERSION_MAJOR << 12) + (NPP_VERSION_MINOR << 4)) >= 0x6000 /* These are 6.0 or higher */ case NPP_LUT_PALETTE_BITSIZE_ERROR: return "NPP_LUT_PALETTE_BITSIZE_ERROR"; case NPP_ZC_MODE_NOT_SUPPORTED_ERROR: return "NPP_ZC_MODE_NOT_SUPPORTED_ERROR"; case NPP_QUALITY_INDEX_ERROR: return "NPP_QUALITY_INDEX_ERROR"; case NPP_CHANNEL_ORDER_ERROR: return "NPP_CHANNEL_ORDER_ERROR"; case NPP_ZERO_MASK_VALUE_ERROR: return "NPP_ZERO_MASK_VALUE_ERROR"; case NPP_NUMBER_OF_CHANNELS_ERROR: return "NPP_NUMBER_OF_CHANNELS_ERROR"; case NPP_COI_ERROR: return "NPP_COI_ERROR"; case NPP_DIVISOR_ERROR: return "NPP_DIVISOR_ERROR"; case NPP_CHANNEL_ERROR: return "NPP_CHANNEL_ERROR"; case NPP_STRIDE_ERROR: return "NPP_STRIDE_ERROR"; case NPP_ANCHOR_ERROR: return "NPP_ANCHOR_ERROR"; case NPP_MASK_SIZE_ERROR: return "NPP_MASK_SIZE_ERROR"; case NPP_MOMENT_00_ZERO_ERROR: return "NPP_MOMENT_00_ZERO_ERROR"; case NPP_THRESHOLD_NEGATIVE_LEVEL_ERROR: return "NPP_THRESHOLD_NEGATIVE_LEVEL_ERROR"; case NPP_THRESHOLD_ERROR: return "NPP_THRESHOLD_ERROR"; case NPP_CONTEXT_MATCH_ERROR: return "NPP_CONTEXT_MATCH_ERROR"; case NPP_FFT_FLAG_ERROR: return "NPP_FFT_FLAG_ERROR"; case NPP_FFT_ORDER_ERROR: return "NPP_FFT_ORDER_ERROR"; case NPP_SCALE_RANGE_ERROR: return "NPP_SCALE_RANGE_ERROR"; case NPP_DATA_TYPE_ERROR: return "NPP_DATA_TYPE_ERROR"; case NPP_OUT_OFF_RANGE_ERROR: return "NPP_OUT_OFF_RANGE_ERROR"; case NPP_DIVIDE_BY_ZERO_ERROR: return "NPP_DIVIDE_BY_ZERO_ERROR"; case NPP_RANGE_ERROR: return "NPP_RANGE_ERROR"; case NPP_NO_MEMORY_ERROR: return "NPP_NO_MEMORY_ERROR"; case NPP_ERROR_RESERVED: return "NPP_ERROR_RESERVED"; case NPP_NO_OPERATION_WARNING: return "NPP_NO_OPERATION_WARNING"; case NPP_DIVIDE_BY_ZERO_WARNING: return "NPP_DIVIDE_BY_ZERO_WARNING"; #endif #if ((NPP_VERSION_MAJOR << 12) + (NPP_VERSION_MINOR << 4)) >= 0x7000 /* These are 7.0 or higher */ case NPP_OVERFLOW_ERROR: return "NPP_OVERFLOW_ERROR"; case NPP_CORRUPTED_DATA_ERROR: return "NPP_CORRUPTED_DATA_ERROR"; #endif } return ""; } #endif #ifdef __DRIVER_TYPES_H__ #ifndef DEVICE_RESET #define DEVICE_RESET cudaDeviceReset(); #endif #else #ifndef DEVICE_RESET #define DEVICE_RESET #endif #endif template< typename T > void check(T result, char const *const func, const char *const file, int const line) { if (result) { fprintf(stderr, "CUDA error at %s:%d code=%d(%s) \"%s\" \n", file, line, static_cast(result), _cudaGetErrorEnum(result), func); DEVICE_RESET // Make sure we call CUDA Device Reset before exiting exit(EXIT_FAILURE); } } #ifdef __DRIVER_TYPES_H__ // This will output the proper CUDA error strings in the event that a CUDA host call returns an error #define checkCudaErrors(val) check ( (val), #val, __FILE__, __LINE__ ) // This will output the proper error string when calling cudaGetLastError #define getLastCudaError(msg) __getLastCudaError (msg, __FILE__, __LINE__) inline void __getLastCudaError(const char *errorMessage, const char *file, const int line) { cudaError_t err = cudaGetLastError(); if (cudaSuccess != err) { fprintf(stderr, "%s(%i) : getLastCudaError() CUDA error : %s : (%d) %s.\n", file, line, errorMessage, (int)err, cudaGetErrorString(err)); DEVICE_RESET exit(EXIT_FAILURE); } } // This will only print the proper error string when calling cudaGetLastError but not exit program incase error detected. #define printLastCudaError(msg) __printLastCudaError (msg, __FILE__, __LINE__) inline void __printLastCudaError(const char *errorMessage, const char *file, const int line) { cudaError_t err = cudaGetLastError(); if (cudaSuccess != err) { fprintf(stderr, "%s(%i) : getLastCudaError() CUDA error : %s : (%d) %s.\n", file, line, errorMessage, (int)err, cudaGetErrorString(err)); } } #endif #ifndef MAX #define MAX(a,b) (a > b ? a : b) #endif // Float To Int conversion inline int ftoi(float value) { return (value >= 0 ? (int)(value + 0.5) : (int)(value - 0.5)); } // Beginning of GPU Architecture definitions inline int _ConvertSMVer2Cores(int major, int minor) { // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM typedef struct { int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version int Cores; } sSMtoCores; sSMtoCores nGpuArchCoresPerSM[] = { { 0x30, 192}, // Kepler Generation (SM 3.0) GK10x class { 0x32, 192}, // Kepler Generation (SM 3.2) GK10x class { 0x35, 192}, // Kepler Generation (SM 3.5) GK11x class { 0x37, 192}, // Kepler Generation (SM 3.7) GK21x class { 0x50, 128}, // Maxwell Generation (SM 5.0) GM10x class { 0x52, 128}, // Maxwell Generation (SM 5.2) GM20x class { 0x53, 128}, // Maxwell Generation (SM 5.3) GM20x class { 0x60, 64 }, // Pascal Generation (SM 6.0) GP100 class { 0x61, 128}, // Pascal Generation (SM 6.1) GP10x class { 0x62, 128}, // Pascal Generation (SM 6.2) GP10x class { 0x70, 64 }, // Volta Generation (SM 7.0) GV100 class { 0x72, 64 }, // Volta Generation (SM 7.2) GV11b class { -1, -1 } }; int index = 0; while (nGpuArchCoresPerSM[index].SM != -1) { if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) { return nGpuArchCoresPerSM[index].Cores; } index++; } // If we don't find the values, we default use the previous one to run properly printf("MapSMtoCores for SM %d.%d is undefined. Default to use %d Cores/SM\n", major, minor, nGpuArchCoresPerSM[index-1].Cores); return nGpuArchCoresPerSM[index-1].Cores; } // end of GPU Architecture definitions #ifdef __CUDA_RUNTIME_H__ // General GPU Device CUDA Initialization inline int gpuDeviceInit(int devID) { int device_count; checkCudaErrors(cudaGetDeviceCount(&device_count)); if (device_count == 0) { fprintf(stderr, "gpuDeviceInit() CUDA error: no devices supporting CUDA.\n"); exit(EXIT_FAILURE); } if (devID < 0) { devID = 0; } if (devID > device_count-1) { fprintf(stderr, "\n"); fprintf(stderr, ">> %d CUDA capable GPU device(s) detected. <<\n", device_count); fprintf(stderr, ">> gpuDeviceInit (-device=%d) is not a valid GPU device. <<\n", devID); fprintf(stderr, "\n"); return -devID; } cudaDeviceProp deviceProp; checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID)); if (deviceProp.computeMode == cudaComputeModeProhibited) { fprintf(stderr, "Error: device is running in , no threads can use ::cudaSetDevice().\n"); return -1; } if (deviceProp.major < 1) { fprintf(stderr, "gpuDeviceInit(): GPU device does not support CUDA.\n"); exit(EXIT_FAILURE); } checkCudaErrors(cudaSetDevice(devID)); printf("gpuDeviceInit() CUDA Device [%d]: \"%s\n", devID, deviceProp.name); return devID; } // This function returns the best GPU (with maximum GFLOPS) inline int gpuGetMaxGflopsDeviceId() { int current_device = 0, sm_per_multiproc = 0; int max_perf_device = 0; int device_count = 0, best_SM_arch = 0; int devices_prohibited = 0; unsigned long long max_compute_perf = 0; cudaDeviceProp deviceProp; checkCudaErrors(cudaGetDeviceCount(&device_count)); if (device_count == 0) { fprintf(stderr, "gpuGetMaxGflopsDeviceId() CUDA error: no devices supporting CUDA.\n"); exit(EXIT_FAILURE); } // Find the best major SM Architecture GPU device while (current_device < device_count) { cudaGetDeviceProperties(&deviceProp, current_device); // If this GPU is not running on Compute Mode prohibited, then we can add it to the list if (deviceProp.computeMode != cudaComputeModeProhibited) { if (deviceProp.major > 0 && deviceProp.major < 9999) { best_SM_arch = MAX(best_SM_arch, deviceProp.major); } } else { devices_prohibited++; } current_device++; } if (devices_prohibited == device_count) { fprintf(stderr, "gpuGetMaxGflopsDeviceId() CUDA error: all devices have compute mode prohibited.\n"); exit(EXIT_FAILURE); } // Find the best CUDA capable GPU device current_device = 0; while (current_device < device_count) { cudaGetDeviceProperties(&deviceProp, current_device); // If this GPU is not running on Compute Mode prohibited, then we can add it to the list if (deviceProp.computeMode != cudaComputeModeProhibited) { if (deviceProp.major == 9999 && deviceProp.minor == 9999) { sm_per_multiproc = 1; } else { sm_per_multiproc = _ConvertSMVer2Cores(deviceProp.major, deviceProp.minor); } unsigned long long compute_perf = (unsigned long long) deviceProp.multiProcessorCount * sm_per_multiproc * deviceProp.clockRate; if (compute_perf > max_compute_perf) { // If we find GPU with SM major > 2, search only these if (best_SM_arch > 2) { // If our device==dest_SM_arch, choose this, or else pass if (deviceProp.major == best_SM_arch) { max_compute_perf = compute_perf; max_perf_device = current_device; } } else { max_compute_perf = compute_perf; max_perf_device = current_device; } } } ++current_device; } return max_perf_device; } // Initialization code to find the best CUDA Device inline int findCudaDevice(int argc, const char **argv) { cudaDeviceProp deviceProp; int devID = 0; // If the command-line has a device number specified, use it if (checkCmdLineFlag(argc, argv, "device")) { devID = getCmdLineArgumentInt(argc, argv, "device="); if (devID < 0) { printf("Invalid command line parameter\n "); exit(EXIT_FAILURE); } else { devID = gpuDeviceInit(devID); if (devID < 0) { printf("exiting...\n"); exit(EXIT_FAILURE); } } } else { // Otherwise pick the device with highest Gflops/s devID = gpuGetMaxGflopsDeviceId(); checkCudaErrors(cudaSetDevice(devID)); checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID)); printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n", devID, deviceProp.name, deviceProp.major, deviceProp.minor); } return devID; } inline int findIntegratedGPU() { int current_device = 0; int device_count = 0; int devices_prohibited = 0; cudaDeviceProp deviceProp; checkCudaErrors(cudaGetDeviceCount(&device_count)); if (device_count == 0) { fprintf(stderr, "CUDA error: no devices supporting CUDA.\n"); exit(EXIT_FAILURE); } // Find the integrated GPU which is compute capable while (current_device < device_count) { cudaGetDeviceProperties(&deviceProp, current_device); // If GPU is integrated and is not running on Compute Mode prohibited, then cuda can map to GLES resource if (deviceProp.integrated && (deviceProp.computeMode != cudaComputeModeProhibited)) { checkCudaErrors(cudaSetDevice(current_device)); checkCudaErrors(cudaGetDeviceProperties(&deviceProp, current_device)); printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n", current_device, deviceProp.name, deviceProp.major, deviceProp.minor); return current_device; } else { devices_prohibited++; } current_device++; } if (devices_prohibited == device_count) { fprintf(stderr, "CUDA error: No GLES-CUDA Interop capable GPU found.\n"); exit(EXIT_FAILURE); } return -1; } // General check for CUDA GPU SM Capabilities inline bool checkCudaCapabilities(int major_version, int minor_version) { cudaDeviceProp deviceProp; deviceProp.major = 0; deviceProp.minor = 0; int dev; checkCudaErrors(cudaGetDevice(&dev)); checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev)); if ((deviceProp.major > major_version) || (deviceProp.major == major_version && deviceProp.minor >= minor_version)) { printf(" Device %d: <%16s >, Compute SM %d.%d detected\n", dev, deviceProp.name, deviceProp.major, deviceProp.minor); return true; } else { printf(" No GPU device was found that can support CUDA compute capability %d.%d.\n", major_version, minor_version); return false; } } #endif // end of CUDA Helper Functions #endif ================================================ FILE: tests/projects/cuda/console/inc/helper_cuda_drvapi.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // Helper functions for CUDA Driver API error handling (make sure that CUDA_H is included in your projects) #ifndef HELPER_CUDA_DRVAPI_H #define HELPER_CUDA_DRVAPI_H #include #include #include #include #include #ifndef MAX #define MAX(a,b) (a > b ? a : b) #endif #ifndef HELPER_CUDA_H inline int ftoi(float value) { return (value >= 0 ? (int)(value + 0.5) : (int)(value - 0.5)); } #endif #ifndef EXIT_WAIVED #define EXIT_WAIVED 2 #endif //////////////////////////////////////////////////////////////////////////////// // These are CUDA Helper functions // add a level of protection to the CUDA SDK samples, let's force samples to explicitly include CUDA.H #ifdef __cuda_cuda_h__ // This will output the proper CUDA error strings in the event that a CUDA host call returns an error #ifndef checkCudaErrors #define checkCudaErrors(err) __checkCudaErrors (err, __FILE__, __LINE__) // These are the inline versions for all of the SDK helper functions inline void __checkCudaErrors(CUresult err, const char *file, const int line) { if (CUDA_SUCCESS != err) { fprintf(stderr, "checkCudaErrors() Driver API error = %04d \"%s\" from file <%s>, line %i.\n", err, getCudaDrvErrorString(err), file, line); exit(EXIT_FAILURE); } } #endif #ifdef getLastCudaDrvErrorMsg #undef getLastCudaDrvErrorMsg #endif #define getLastCudaDrvErrorMsg(msg) __getLastCudaDrvErrorMsg (msg, __FILE__, __LINE__) inline void __getLastCudaDrvErrorMsg(const char *msg, const char *file, const int line) { CUresult err = cuCtxSynchronize(); if (CUDA_SUCCESS != err) { fprintf(stderr, "getLastCudaDrvErrorMsg -> %s", msg); fprintf(stderr, "getLastCudaDrvErrorMsg -> cuCtxSynchronize API error = %04d \"%s\" in file <%s>, line %i.\n", err, getCudaDrvErrorString(err), file, line); exit(EXIT_FAILURE); } } // This function wraps the CUDA Driver API into a template function template inline void getCudaAttribute(T *attribute, CUdevice_attribute device_attribute, int device) { CUresult error_result = cuDeviceGetAttribute(attribute, device_attribute, device); if (error_result != CUDA_SUCCESS) { printf("cuDeviceGetAttribute returned %d\n-> %s\n", (int)error_result, getCudaDrvErrorString(error_result)); exit(EXIT_SUCCESS); } } #endif // Beginning of GPU Architecture definitions inline int _ConvertSMVer2CoresDRV(int major, int minor) { // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM typedef struct { int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version int Cores; } sSMtoCores; sSMtoCores nGpuArchCoresPerSM[] = { { 0x30, 192}, // Kepler Generation (SM 3.0) GK10x class { 0x32, 192}, // Kepler Generation (SM 3.2) GK10x class { 0x35, 192}, // Kepler Generation (SM 3.5) GK11x class { 0x37, 192}, // Kepler Generation (SM 3.7) GK21x class { 0x50, 128}, // Maxwell Generation (SM 5.0) GM10x class { 0x52, 128}, // Maxwell Generation (SM 5.2) GM20x class { 0x53, 128}, // Maxwell Generation (SM 5.3) GM20x class { 0x60, 64 }, // Pascal Generation (SM 6.0) GP100 class { 0x61, 128}, // Pascal Generation (SM 6.1) GP10x class { 0x62, 128}, // Pascal Generation (SM 6.2) GP10x class { 0x70, 64 }, // Volta Generation (SM 7.0) GV100 class { 0x72, 64 }, // Volta Generation (SM 7.2) GV11b class { -1, -1 } }; int index = 0; while (nGpuArchCoresPerSM[index].SM != -1) { if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) { return nGpuArchCoresPerSM[index].Cores; } index++; } // If we don't find the values, we default use the previous one to run properly printf("MapSMtoCores for SM %d.%d is undefined. Default to use %d Cores/SM\n", major, minor, nGpuArchCoresPerSM[index-1].Cores); return nGpuArchCoresPerSM[index-1].Cores; } // end of GPU Architecture definitions #ifdef __cuda_cuda_h__ // General GPU Device CUDA Initialization inline int gpuDeviceInitDRV(int ARGC, const char **ARGV) { int cuDevice = 0; int deviceCount = 0; CUresult err = cuInit(0); if (CUDA_SUCCESS == err) { checkCudaErrors(cuDeviceGetCount(&deviceCount)); } if (deviceCount == 0) { fprintf(stderr, "cudaDeviceInit error: no devices supporting CUDA\n"); exit(EXIT_FAILURE); } int dev = 0; dev = getCmdLineArgumentInt(ARGC, (const char **) ARGV, "device="); if (dev < 0) { dev = 0; } if (dev > deviceCount-1) { fprintf(stderr, "\n"); fprintf(stderr, ">> %d CUDA capable GPU device(s) detected. <<\n", deviceCount); fprintf(stderr, ">> cudaDeviceInit (-device=%d) is not a valid GPU device. <<\n", dev); fprintf(stderr, "\n"); return -dev; } checkCudaErrors(cuDeviceGet(&cuDevice, dev)); char name[100]; cuDeviceGetName(name, 100, cuDevice); int computeMode; getCudaAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, dev); if (computeMode == CU_COMPUTEMODE_PROHIBITED) { fprintf(stderr, "Error: device is running in , no threads can use this CUDA Device.\n"); return -1; } if (checkCmdLineFlag(ARGC, (const char **) ARGV, "quiet") == false) { printf("gpuDeviceInitDRV() Using CUDA Device [%d]: %s\n", dev, name); } return dev; } // This function returns the best GPU based on performance inline int gpuGetMaxGflopsDeviceIdDRV() { CUdevice current_device = 0; CUdevice max_perf_device = 0; int device_count = 0; int sm_per_multiproc = 0; unsigned long long max_compute_perf = 0; int best_SM_arch = 0; int major = 0; int minor = 0; int multiProcessorCount; int clockRate; int devices_prohibited = 0; cuInit(0); checkCudaErrors(cuDeviceGetCount(&device_count)); if (device_count == 0) { fprintf(stderr, "gpuGetMaxGflopsDeviceIdDRV error: no devices supporting CUDA\n"); exit(EXIT_FAILURE); } // Find the best major SM Architecture GPU device while (current_device < device_count) { checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); if (major > 0 && major < 9999) { best_SM_arch = MAX(best_SM_arch, major); } current_device++; } // Find the best CUDA capable GPU device current_device = 0; while (current_device < device_count) { checkCudaErrors(cuDeviceGetAttribute(&multiProcessorCount, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, current_device)); checkCudaErrors(cuDeviceGetAttribute(&clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, current_device)); checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); int computeMode; getCudaAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device); if (computeMode != CU_COMPUTEMODE_PROHIBITED) { if (major == 9999 && minor == 9999) { sm_per_multiproc = 1; } else { sm_per_multiproc = _ConvertSMVer2CoresDRV(major, minor); } unsigned long long compute_perf = (unsigned long long) (multiProcessorCount * sm_per_multiproc * clockRate); if (compute_perf > max_compute_perf) { // If we find GPU with SM major > 2, search only these if (best_SM_arch > 2) { // If our device==dest_SM_arch, choose this, or else pass if (major == best_SM_arch) { max_compute_perf = compute_perf; max_perf_device = current_device; } } else { max_compute_perf = compute_perf; max_perf_device = current_device; } } } else { devices_prohibited++; } ++current_device; } if (devices_prohibited == device_count) { fprintf(stderr, "gpuGetMaxGflopsDeviceIdDRV error: all devices have compute mode prohibited.\n"); exit(EXIT_FAILURE); } return max_perf_device; } // This function returns the best Graphics GPU based on performance inline int gpuGetMaxGflopsGLDeviceIdDRV() { CUdevice current_device = 0, max_perf_device = 0; int device_count = 0, sm_per_multiproc = 0; int max_compute_perf = 0, best_SM_arch = 0; int major = 0, minor = 0, multiProcessorCount, clockRate; int bTCC = 0; int devices_prohibited = 0; char deviceName[256]; cuInit(0); checkCudaErrors(cuDeviceGetCount(&device_count)); if (device_count == 0) { fprintf(stderr, "gpuGetMaxGflopsGLDeviceIdDRV error: no devices supporting CUDA\n"); exit(EXIT_FAILURE); } // Find the best major SM Architecture GPU device that are graphics devices while (current_device < device_count) { checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device)); checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); #if CUDA_VERSION >= 3020 checkCudaErrors(cuDeviceGetAttribute(&bTCC, CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device)); #else // Assume a Tesla GPU is running in TCC if we are running CUDA 3.1 if (deviceName[0] == 'T') { bTCC = 1; } #endif int computeMode; getCudaAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device); if (computeMode != CU_COMPUTEMODE_PROHIBITED) { if (!bTCC) { if (major > 0 && major < 9999) { best_SM_arch = MAX(best_SM_arch, major); } } } else { devices_prohibited++; } current_device++; } if (devices_prohibited == device_count) { fprintf(stderr, "gpuGetMaxGflopsGLDeviceIdDRV error: all devices have compute mode prohibited.\n"); exit(EXIT_FAILURE); } // Find the best CUDA capable GPU device current_device = 0; while (current_device < device_count) { checkCudaErrors(cuDeviceGetAttribute(&multiProcessorCount, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, current_device)); checkCudaErrors(cuDeviceGetAttribute(&clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, current_device)); checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); #if CUDA_VERSION >= 3020 checkCudaErrors(cuDeviceGetAttribute(&bTCC, CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device)); #else // Assume a Tesla GPU is running in TCC if we are running CUDA 3.1 if (deviceName[0] == 'T') { bTCC = 1; } #endif int computeMode; getCudaAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device); if (computeMode != CU_COMPUTEMODE_PROHIBITED) { if (major == 9999 && minor == 9999) { sm_per_multiproc = 1; } else { sm_per_multiproc = _ConvertSMVer2CoresDRV(major, minor); } // If this is a Tesla based GPU and SM 2.0, and TCC is disabled, this is a contendor if (!bTCC) // Is this GPU running the TCC driver? If so we pass on this { int compute_perf = multiProcessorCount * sm_per_multiproc * clockRate; if (compute_perf > max_compute_perf) { // If we find GPU with SM major > 2, search only these if (best_SM_arch > 2) { // If our device = dest_SM_arch, then we pick this one if (major == best_SM_arch) { max_compute_perf = compute_perf; max_perf_device = current_device; } } else { max_compute_perf = compute_perf; max_perf_device = current_device; } } } } ++current_device; } return max_perf_device; } // General initialization call to pick the best CUDA Device inline CUdevice findCudaDeviceDRV(int argc, const char **argv) { CUdevice cuDevice; int devID = 0; // If the command-line has a device number specified, use it if (checkCmdLineFlag(argc, (const char **)argv, "device")) { devID = gpuDeviceInitDRV(argc, argv); if (devID < 0) { printf("exiting...\n"); exit(EXIT_SUCCESS); } } else { // Otherwise pick the device with highest Gflops/s char name[100]; devID = gpuGetMaxGflopsDeviceIdDRV(); checkCudaErrors(cuDeviceGet(&cuDevice, devID)); cuDeviceGetName(name, 100, cuDevice); printf("> Using CUDA Device [%d]: %s\n", devID, name); } cuDeviceGet(&cuDevice, devID); return cuDevice; } inline CUdevice findIntegratedGPUDrv() { CUdevice current_device = 0; int device_count = 0; int devices_prohibited = 0; int isIntegrated; cuInit(0); checkCudaErrors(cuDeviceGetCount(&device_count)); if (device_count == 0) { fprintf(stderr, "CUDA error: no devices supporting CUDA.\n"); exit(EXIT_FAILURE); } // Find the integrated GPU which is compute capable while (current_device < device_count) { int computeMode = -1; checkCudaErrors(cuDeviceGetAttribute(&isIntegrated, CU_DEVICE_ATTRIBUTE_INTEGRATED, current_device)); checkCudaErrors(cuDeviceGetAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device)); // If GPU is integrated and is not running on Compute Mode prohibited use that if (isIntegrated && (computeMode != CU_COMPUTEMODE_PROHIBITED)) { int major = 0, minor = 0; char deviceName[256]; checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device)); printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n", current_device, deviceName, major, minor); return current_device; } else { devices_prohibited++; } current_device++; } if (devices_prohibited == device_count) { fprintf(stderr, "CUDA error: No Integrated CUDA capable GPU found.\n"); exit(EXIT_FAILURE); } return -1; } // This function will pick the best CUDA device available with OpenGL interop inline CUdevice findCudaGLDeviceDRV(int argc, const char **argv) { CUdevice cuDevice; int devID = 0; // If the command-line has a device number specified, use it if (checkCmdLineFlag(argc, (const char **)argv, "device")) { devID = gpuDeviceInitDRV(argc, (const char **)argv); if (devID < 0) { printf("no CUDA capable devices found, exiting...\n"); exit(EXIT_SUCCESS); } } else { char name[100]; // Otherwise pick the device with highest Gflops/s devID = gpuGetMaxGflopsGLDeviceIdDRV(); checkCudaErrors(cuDeviceGet(&cuDevice, devID)); cuDeviceGetName(name, 100, cuDevice); printf("> Using CUDA/GL Device [%d]: %s\n", devID, name); } return devID; } // General check for CUDA GPU SM Capabilities inline bool checkCudaCapabilitiesDRV(int major_version, int minor_version, int devID) { CUdevice cuDevice; char name[256]; int major = 0, minor = 0; checkCudaErrors(cuDeviceGet(&cuDevice, devID)); checkCudaErrors(cuDeviceGetName(name, 100, cuDevice)); checkCudaErrors(cuDeviceComputeCapability(&major, &minor, devID)); if ((major > major_version) || (major == major_version && minor >= minor_version)) { printf("> Device %d: <%16s >, Compute SM %d.%d detected\n", devID, name, major, minor); return true; } else { printf("No GPU device was found that can support CUDA compute capability %d.%d.\n", major_version, minor_version); return false; } } #endif // end of CUDA Helper Functions #endif ================================================ FILE: tests/projects/cuda/console/inc/helper_cuda_gl.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef HELPER_CUDA_GL_H #define HELPER_CUDA_GL_H #include #include #include // includes, graphics #if defined (__APPLE__) || defined(MACOSX) #include #else #include #endif #ifndef EXIT_WAIVED #define EXIT_WAIVED 2 #endif #ifdef __DRIVER_TYPES_H__ #ifndef DEVICE_RESET #define DEVICE_RESET cudaDeviceReset() #endif #else #ifndef DEVICE_RESET #define DEVICE_RESET #endif #endif #ifdef __CUDA_GL_INTEROP_H__ //////////////////////////////////////////////////////////////////////////////// // These are CUDA OpenGL Helper functions inline int gpuGLDeviceInit(int ARGC, const char **ARGV) { int deviceCount; checkCudaErrors(cudaGetDeviceCount(&deviceCount)); if (deviceCount == 0) { fprintf(stderr, "CUDA error: no devices supporting CUDA.\n"); exit(EXIT_FAILURE); } int dev = 0; dev = getCmdLineArgumentInt(ARGC, ARGV, "device="); if (dev < 0) { dev = 0; } if (dev > deviceCount-1) { fprintf(stderr, "\n"); fprintf(stderr, ">> %d CUDA capable GPU device(s) detected. <<\n", deviceCount); fprintf(stderr, ">> gpuGLDeviceInit (-device=%d) is not a valid GPU device. <<\n", dev); fprintf(stderr, "\n"); return -dev; } cudaDeviceProp deviceProp; checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev)); if (deviceProp.computeMode == cudaComputeModeProhibited) { fprintf(stderr, "Error: device is running in , no threads can use ::cudaSetDevice().\n"); return -1; } if (deviceProp.major < 1) { fprintf(stderr, "Error: device does not support CUDA.\n"); exit(EXIT_FAILURE); } if (checkCmdLineFlag(ARGC, ARGV, "quiet") == false) { fprintf(stderr, "Using device %d: %s\n", dev, deviceProp.name); } checkCudaErrors(cudaGLSetGLDevice(dev)); return dev; } // This function will pick the best CUDA device available with OpenGL interop inline int findCudaGLDevice(int argc, const char **argv) { int devID = 0; // If the command-line has a device number specified, use it if (checkCmdLineFlag(argc, (const char **)argv, "device")) { devID = gpuGLDeviceInit(argc, (const char **)argv); if (devID < 0) { printf("no CUDA capable devices found, exiting...\n"); DEVICE_RESET exit(EXIT_SUCCESS); } } else { // Otherwise pick the device with highest Gflops/s devID = gpuGetMaxGflopsDeviceId(); cudaGLSetGLDevice(devID); } return devID; } static inline const char* glErrorToString(GLenum err) { #define CASE_RETURN_MACRO(arg) case arg: return #arg switch(err) { CASE_RETURN_MACRO(GL_NO_ERROR); CASE_RETURN_MACRO(GL_INVALID_ENUM); CASE_RETURN_MACRO(GL_INVALID_VALUE); CASE_RETURN_MACRO(GL_INVALID_OPERATION); CASE_RETURN_MACRO(GL_OUT_OF_MEMORY); CASE_RETURN_MACRO(GL_STACK_UNDERFLOW); CASE_RETURN_MACRO(GL_STACK_OVERFLOW); #ifdef GL_INVALID_FRAMEBUFFER_OPERATION CASE_RETURN_MACRO(GL_INVALID_FRAMEBUFFER_OPERATION); #endif default: break; } #undef CASE_RETURN_MACRO return "*UNKNOWN*"; } //////////////////////////////////////////////////////////////////////////// //! Check for OpenGL error //! @return bool if no GL error has been encountered, otherwise 0 //! @param file __FILE__ macro //! @param line __LINE__ macro //! @note The GL error is listed on stderr //! @note This function should be used via the CHECK_ERROR_GL() macro //////////////////////////////////////////////////////////////////////////// inline bool sdkCheckErrorGL(const char *file, const int line) { bool ret_val = true; // check for error GLenum gl_error = glGetError(); if (gl_error != GL_NO_ERROR) { #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) char tmpStr[512]; // NOTE: "%s(%i) : " allows Visual Studio to directly jump to the file at the right line // when the user double clicks on the error line in the Output pane. Like any compile error. sprintf_s(tmpStr, 255, "\n%s(%i) : GL Error : %s\n\n", file, line, glErrorToString(gl_error)); fprintf(stderr, "%s", tmpStr); #endif fprintf(stderr, "GL Error in file '%s' in line %d :\n", file, line); fprintf(stderr, "%s\n", glErrorToString(gl_error)); ret_val = false; } return ret_val; } #define SDK_CHECK_ERROR_GL() \ if( false == sdkCheckErrorGL( __FILE__, __LINE__)) { \ DEVICE_RESET \ exit(EXIT_FAILURE); \ } #endif #endif ================================================ FILE: tests/projects/cuda/console/inc/helper_cusolver.h ================================================ /* * Copyright 2015 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef HELPER_CUSOLVER #define HELPER_CUSOLVER #include #include #include #include #include #include #include "cusparse.h" #define SWITCH_CHAR '-' struct testOpts { char *sparse_mat_filename; // by switch -F const char *testFunc; // by switch -R const char *reorder; // by switch -P int lda; // by switch -lda }; double vec_norminf(int n, const double *x) { double norminf = 0; for(int j = 0 ; j < n ; j++){ double x_abs = fabs(x[j]); norminf = (norminf > x_abs)? norminf : x_abs; } return norminf; } /* * |A| = max { |A|*ones(m,1) } */ double mat_norminf( int m, int n, const double *A, int lda) { double norminf = 0; for(int i = 0 ; i < m ; i++){ double sum = 0.0; for(int j = 0 ; j < n ; j++){ double A_abs = fabs(A[i + j*lda]); sum += A_abs; } norminf = (norminf > sum)? norminf : sum; } return norminf; } /* * |A| = max { |A|*ones(m,1) } */ double csr_mat_norminf( int m, int n, int nnzA, const cusparseMatDescr_t descrA, const double *csrValA, const int *csrRowPtrA, const int *csrColIndA) { const int baseA = (CUSPARSE_INDEX_BASE_ONE == cusparseGetMatIndexBase(descrA))? 1:0; double norminf = 0; for(int i = 0 ; i < m ; i++){ double sum = 0.0; const int start = csrRowPtrA[i ] - baseA; const int end = csrRowPtrA[i+1] - baseA; for(int colidx = start ; colidx < end ; colidx++){ // const int j = csrColIndA[colidx] - baseA; double A_abs = fabs( csrValA[colidx] ); sum += A_abs; } norminf = (norminf > sum)? norminf : sum; } return norminf; } void display_matrix( int m, int n, int nnzA, const cusparseMatDescr_t descrA, const double *csrValA, const int *csrRowPtrA, const int *csrColIndA) { const int baseA = (CUSPARSE_INDEX_BASE_ONE == cusparseGetMatIndexBase(descrA))? 1:0; printf("m = %d, n = %d, nnz = %d, matlab base-1\n", m, n, nnzA); for(int row = 0 ; row < m ; row++){ const int start = csrRowPtrA[row ] - baseA; const int end = csrRowPtrA[row+1] - baseA; for(int colidx = start ; colidx < end ; colidx++){ const int col = csrColIndA[colidx] - baseA; double Areg = csrValA[colidx]; printf("A(%d, %d) = %20.16E\n", row+1, col+1, Areg); } } } #if defined(_WIN32) #if !defined(WIN32_LEAN_AND_MEAN) #define WIN32_LEAN_AND_MEAN #endif #include double second (void) { LARGE_INTEGER t; static double oofreq; static int checkedForHighResTimer; static BOOL hasHighResTimer; if (!checkedForHighResTimer) { hasHighResTimer = QueryPerformanceFrequency (&t); oofreq = 1.0 / (double)t.QuadPart; checkedForHighResTimer = 1; } if (hasHighResTimer) { QueryPerformanceCounter (&t); return (double)t.QuadPart * oofreq; } else { return (double)GetTickCount() / 1000.0; } } #elif defined(__linux) || defined(__QNX__) #include #include #include double second (void) { struct timeval tv; gettimeofday(&tv, NULL); return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; } #elif defined(__APPLE__) #include #include #include #include #include double second (void) { struct timeval tv; gettimeofday(&tv, NULL); return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; } #else #error unsupported platform #endif #endif ================================================ FILE: tests/projects/cuda/console/inc/helper_functions.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // These are helper functions for the SDK samples (string parsing, timers, image helpers, etc) #ifndef HELPER_FUNCTIONS_H #define HELPER_FUNCTIONS_H #ifdef WIN32 #pragma warning(disable:4996) #endif // includes, project #include #include #include #include #include #include #include #include #include #include // includes, timer, string parsing, image helpers #include // helper functions for timers #include // helper functions for string parsing #include // helper functions for image compare, dump, data comparisons #ifndef EXIT_WAIVED #define EXIT_WAIVED 2 #endif #endif // HELPER_FUNCTIONS_H ================================================ FILE: tests/projects/cuda/console/inc/helper_gl.h ================================================ /** * Copyright 2014 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // These are helper functions for the SDK samples (OpenGL) #ifndef HELPER_GL_H #define HELPER_GL_H #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #include #endif #if defined(__APPLE__) || defined(MACOSX) #include #else #include #ifdef __linux__ #include #endif /* __linux__ */ #endif #include #include #include #include #include #include #include /* Prototypes */ namespace __HelperGL { static int isGLVersionSupported(unsigned reqMajor, unsigned reqMinor); static int areGLExtensionsSupported(const std::string &); #ifdef __linux__ #ifndef HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION #define USE_GL_FUNC(name, proto) proto name = (proto) glXGetProcAddress ((const GLubyte *)#name) #else #define USE_GL_FUNC(name, proto) extern proto name #endif USE_GL_FUNC(glBindBuffer, PFNGLBINDBUFFERPROC); USE_GL_FUNC(glDeleteBuffers, PFNGLDELETEBUFFERSPROC); USE_GL_FUNC(glBufferData, PFNGLBUFFERDATAPROC); USE_GL_FUNC(glBufferSubData, PFNGLBUFFERSUBDATAPROC); USE_GL_FUNC(glGenBuffers, PFNGLGENBUFFERSPROC); USE_GL_FUNC(glCreateProgram, PFNGLCREATEPROGRAMPROC); USE_GL_FUNC(glBindProgramARB, PFNGLBINDPROGRAMARBPROC); USE_GL_FUNC(glGenProgramsARB, PFNGLGENPROGRAMSARBPROC); USE_GL_FUNC(glDeleteProgramsARB, PFNGLDELETEPROGRAMSARBPROC); USE_GL_FUNC(glDeleteProgram, PFNGLDELETEPROGRAMPROC); USE_GL_FUNC(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC); USE_GL_FUNC(glGetProgramiv, PFNGLGETPROGRAMIVPROC); USE_GL_FUNC(glProgramParameteriEXT, PFNGLPROGRAMPARAMETERIEXTPROC); USE_GL_FUNC(glProgramStringARB, PFNGLPROGRAMSTRINGARBPROC); USE_GL_FUNC(glUnmapBuffer, PFNGLUNMAPBUFFERPROC); USE_GL_FUNC(glMapBuffer, PFNGLMAPBUFFERPROC); USE_GL_FUNC(glGetBufferParameteriv, PFNGLGETBUFFERPARAMETERIVPROC); USE_GL_FUNC(glLinkProgram, PFNGLLINKPROGRAMPROC); USE_GL_FUNC(glUseProgram, PFNGLUSEPROGRAMPROC); USE_GL_FUNC(glAttachShader, PFNGLATTACHSHADERPROC); USE_GL_FUNC(glCreateShader, PFNGLCREATESHADERPROC); USE_GL_FUNC(glShaderSource, PFNGLSHADERSOURCEPROC); USE_GL_FUNC(glCompileShader, PFNGLCOMPILESHADERPROC); USE_GL_FUNC(glDeleteShader, PFNGLDELETESHADERPROC); USE_GL_FUNC(glGetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC); USE_GL_FUNC(glGetShaderiv, PFNGLGETSHADERIVPROC); USE_GL_FUNC(glUniform1i, PFNGLUNIFORM1IPROC); USE_GL_FUNC(glUniform1f, PFNGLUNIFORM1FPROC); USE_GL_FUNC(glUniform2f, PFNGLUNIFORM2FPROC); USE_GL_FUNC(glUniform3f, PFNGLUNIFORM3FPROC); USE_GL_FUNC(glUniform4f, PFNGLUNIFORM4FPROC); USE_GL_FUNC(glUniform1fv, PFNGLUNIFORM1FVPROC); USE_GL_FUNC(glUniform2fv, PFNGLUNIFORM2FVPROC); USE_GL_FUNC(glUniform3fv, PFNGLUNIFORM3FVPROC); USE_GL_FUNC(glUniform4fv, PFNGLUNIFORM4FVPROC); USE_GL_FUNC(glUniformMatrix4fv, PFNGLUNIFORMMATRIX4FVPROC); USE_GL_FUNC(glSecondaryColor3fv, PFNGLSECONDARYCOLOR3FVPROC); USE_GL_FUNC(glGetUniformLocation, PFNGLGETUNIFORMLOCATIONPROC); USE_GL_FUNC(glGenFramebuffersEXT, PFNGLGENFRAMEBUFFERSEXTPROC); USE_GL_FUNC(glBindFramebufferEXT, PFNGLBINDFRAMEBUFFEREXTPROC); USE_GL_FUNC(glDeleteFramebuffersEXT, PFNGLDELETEFRAMEBUFFERSEXTPROC); USE_GL_FUNC(glCheckFramebufferStatusEXT, PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC); USE_GL_FUNC(glGetFramebufferAttachmentParameterivEXT, PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC); USE_GL_FUNC(glFramebufferTexture1DEXT, PFNGLFRAMEBUFFERTEXTURE1DEXTPROC); USE_GL_FUNC(glFramebufferTexture2DEXT, PFNGLFRAMEBUFFERTEXTURE2DEXTPROC); USE_GL_FUNC(glFramebufferTexture3DEXT, PFNGLFRAMEBUFFERTEXTURE3DEXTPROC); USE_GL_FUNC(glGenerateMipmapEXT, PFNGLGENERATEMIPMAPEXTPROC); USE_GL_FUNC(glGenRenderbuffersEXT, PFNGLGENRENDERBUFFERSEXTPROC); USE_GL_FUNC(glDeleteRenderbuffersEXT, PFNGLDELETERENDERBUFFERSEXTPROC); USE_GL_FUNC(glBindRenderbufferEXT, PFNGLBINDRENDERBUFFEREXTPROC); USE_GL_FUNC(glRenderbufferStorageEXT, PFNGLRENDERBUFFERSTORAGEEXTPROC); USE_GL_FUNC(glFramebufferRenderbufferEXT, PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC); USE_GL_FUNC(glClampColorARB, PFNGLCLAMPCOLORARBPROC); USE_GL_FUNC(glBindFragDataLocationEXT, PFNGLBINDFRAGDATALOCATIONEXTPROC); #if !defined(GLX_EXTENSION_NAME) || !defined(GL_VERSION_1_3) USE_GL_FUNC(glActiveTexture, PFNGLACTIVETEXTUREPROC); USE_GL_FUNC(glClientActiveTexture, PFNGLACTIVETEXTUREPROC); #endif #undef USE_GL_FUNC #endif /*__linux__ */ } namespace __HelperGL { namespace __Int { static std::vector split(const std::string &str) { std::istringstream ss(str); std::istream_iterator it(ss); return std::vector (it, std::istream_iterator()); } /* Sort the vector passed by reference */ template static inline void sort(std::vector &a) { std::sort(a.begin(), a.end()); } /* Compare two vectors */ template static int equals(std::vector a, std::vector b) { if (a.size() != b.size()) return 0; sort(a); sort(b); return std::equal(a.begin(), a.end(), b.begin()); } template static std::vector getIntersection(std::vector a, std::vector b) { sort(a); sort(b); std::vector rc; std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter >(rc)); return rc; } static std::vector getGLExtensions() { std::string extensionsStr( (const char *)glGetString(GL_EXTENSIONS)); return split (extensionsStr); } } static int areGLExtensionsSupported(const std::string &extensions) { std::vector all = __Int::getGLExtensions(); std::vector requested = __Int::split(extensions); std::vector matched = __Int::getIntersection(all, requested); return __Int::equals(matched, requested); } static int isGLVersionSupported(unsigned reqMajor, unsigned reqMinor) { #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) if (glewInit() != GLEW_OK) { std::cerr << "glewInit() failed!" << std::endl; return 0; } #endif std::string version ((const char *) glGetString (GL_VERSION)); std::stringstream stream (version); unsigned major, minor; char dot; stream >> major >> dot >> minor; assert (dot == '.'); return major > reqMajor || (major == reqMajor && minor >= reqMinor); } } /* of namespace __HelperGL*/ using namespace __HelperGL; #endif /*HELPER_GL_H*/ ================================================ FILE: tests/projects/cuda/console/inc/helper_image.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // These are helper functions for the SDK samples (image,bitmap) #ifndef HELPER_IMAGE_H #define HELPER_IMAGE_H #include #include #include #include #include #include #include #include #ifndef MIN #define MIN(a,b) ((a < b) ? a : b) #endif #ifndef MAX #define MAX(a,b) ((a > b) ? a : b) #endif #ifndef EXIT_WAIVED #define EXIT_WAIVED 2 #endif #include // namespace unnamed (internal) namespace { //! size of PGM file header const unsigned int PGMHeaderSize = 0x40; // types //! Data converter from unsigned char / unsigned byte to type T template struct ConverterFromUByte; //! Data converter from unsigned char / unsigned byte template<> struct ConverterFromUByte { //! Conversion operator //! @return converted value //! @param val value to convert float operator()(const unsigned char &val) { return static_cast(val); } }; //! Data converter from unsigned char / unsigned byte to float template<> struct ConverterFromUByte { //! Conversion operator //! @return converted value //! @param val value to convert float operator()(const unsigned char &val) { return static_cast(val) / 255.0f; } }; //! Data converter from unsigned char / unsigned byte to type T template struct ConverterToUByte; //! Data converter from unsigned char / unsigned byte to unsigned int template<> struct ConverterToUByte { //! Conversion operator (essentially a passthru //! @return converted value //! @param val value to convert unsigned char operator()(const unsigned char &val) { return val; } }; //! Data converter from unsigned char / unsigned byte to unsigned int template<> struct ConverterToUByte { //! Conversion operator //! @return converted value //! @param val value to convert unsigned char operator()(const float &val) { return static_cast(val * 255.0f); } }; } #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #ifndef FOPEN #define FOPEN(fHandle,filename,mode) fopen_s(&fHandle, filename, mode) #endif #ifndef FOPEN_FAIL #define FOPEN_FAIL(result) (result != 0) #endif #ifndef SSCANF #define SSCANF sscanf_s #endif #else #ifndef FOPEN #define FOPEN(fHandle,filename,mode) (fHandle = fopen(filename, mode)) #endif #ifndef FOPEN_FAIL #define FOPEN_FAIL(result) (result == NULL) #endif #ifndef SSCANF #define SSCANF sscanf #endif #endif inline bool __loadPPM(const char *file, unsigned char **data, unsigned int *w, unsigned int *h, unsigned int *channels) { FILE *fp = NULL; if (FOPEN_FAIL(FOPEN(fp, file, "rb"))) { std::cerr << "__LoadPPM() : Failed to open file: " << file << std::endl; return false; } // check header char header[PGMHeaderSize]; if (fgets(header, PGMHeaderSize, fp) == NULL) { std::cerr << "__LoadPPM() : reading PGM header returned NULL" << std::endl; return false; } if (strncmp(header, "P5", 2) == 0) { *channels = 1; } else if (strncmp(header, "P6", 2) == 0) { *channels = 3; } else { std::cerr << "__LoadPPM() : File is not a PPM or PGM image" << std::endl; *channels = 0; return false; } // parse header, read maxval, width and height unsigned int width = 0; unsigned int height = 0; unsigned int maxval = 0; unsigned int i = 0; while (i < 3) { if (fgets(header, PGMHeaderSize, fp) == NULL) { std::cerr << "__LoadPPM() : reading PGM header returned NULL" << std::endl; return false; } if (header[0] == '#') { continue; } if (i == 0) { i += SSCANF(header, "%u %u %u", &width, &height, &maxval); } else if (i == 1) { i += SSCANF(header, "%u %u", &height, &maxval); } else if (i == 2) { i += SSCANF(header, "%u", &maxval); } } // check if given handle for the data is initialized if (NULL != *data) { if (*w != width || *h != height) { std::cerr << "__LoadPPM() : Invalid image dimensions." << std::endl; } } else { *data = (unsigned char *) malloc(sizeof(unsigned char) * width * height **channels); *w = width; *h = height; } // read and close file if (fread(*data, sizeof(unsigned char), width * height **channels, fp) == 0) { std::cerr << "__LoadPPM() read data returned error." << std::endl; } fclose(fp); return true; } template inline bool sdkLoadPGM(const char *file, T **data, unsigned int *w, unsigned int *h) { unsigned char *idata = NULL; unsigned int channels; if (true != __loadPPM(file, &idata, w, h, &channels)) { return false; } unsigned int size = *w **h * channels; // initialize mem if necessary // the correct size is checked / set in loadPGMc() if (NULL == *data) { *data = (T *) malloc(sizeof(T) * size); } // copy and cast data std::transform(idata, idata + size, *data, ConverterFromUByte()); free(idata); return true; } template inline bool sdkLoadPPM4(const char *file, T **data, unsigned int *w,unsigned int *h) { unsigned char *idata = 0; unsigned int channels; if (__loadPPM(file, &idata, w, h, &channels)) { // pad 4th component int size = *w **h; // keep the original pointer unsigned char *idata_orig = idata; *data = (T *) malloc(sizeof(T) * size * 4); unsigned char *ptr = *data; for (int i=0; i 0); assert(h > 0); std::fstream fh(file, std::fstream::out | std::fstream::binary); if (fh.bad()) { std::cerr << "__savePPM() : Opening file failed." << std::endl; return false; } if (channels == 1) { fh << "P5\n"; } else if (channels == 3) { fh << "P6\n"; } else { std::cerr << "__savePPM() : Invalid number of channels." << std::endl; return false; } fh << w << "\n" << h << "\n" << 0xff << std::endl; for (unsigned int i = 0; (i < (w*h*channels)) && fh.good(); ++i) { fh << data[i]; } fh.flush(); if (fh.bad()) { std::cerr << "__savePPM() : Writing data failed." << std::endl; return false; } fh.close(); return true; } template inline bool sdkSavePGM(const char *file, T *data, unsigned int w, unsigned int h) { unsigned int size = w * h; unsigned char *idata = (unsigned char *) malloc(sizeof(unsigned char) * size); std::transform(data, data + size, idata, ConverterToUByte()); // write file bool result = __savePPM(file, idata, w, h, 1); // cleanup free(idata); return result; } inline bool sdkSavePPM4ub(const char *file, unsigned char *data, unsigned int w, unsigned int h) { // strip 4th component int size = w * h; unsigned char *ndata = (unsigned char *) malloc(sizeof(unsigned char) * size*3); unsigned char *ptr = ndata; for (int i=0; i inline bool sdkReadFile(const char *filename, T **data, unsigned int *len, bool verbose) { // check input arguments assert(NULL != filename); assert(NULL != len); // intermediate storage for the data read std::vector data_read; // open file for reading FILE *fh = NULL; // check if filestream is valid if (FOPEN_FAIL(FOPEN(fh, filename, "r"))) { printf("Unable to open input file: %s\n", filename); return false; } // read all data elements T token; while (!feof(fh)) { fscanf(fh, "%f", &token); data_read.push_back(token); } // the last element is read twice data_read.pop_back(); fclose(fh); // check if the given handle is already initialized if (NULL != *data) { if (*len != data_read.size()) { std::cerr << "sdkReadFile() : Initialized memory given but " << "size mismatch with signal read " << "(data read / data init = " << (unsigned int)data_read.size() << " / " << *len << ")" << std::endl; return false; } } else { // allocate storage for the data read *data = (T *) malloc(sizeof(T) * data_read.size()); // store signal size *len = static_cast(data_read.size()); } // copy data memcpy(*data, &data_read.front(), sizeof(T) * data_read.size()); return true; } ////////////////////////////////////////////////////////////////////////////// //! Read file \filename and return the data //! @return bool if reading the file succeeded, otherwise false //! @param filename name of the source file //! @param data uninitialized pointer, returned initialized and pointing to //! the data read //! @param len number of data elements in data, -1 on error ////////////////////////////////////////////////////////////////////////////// template inline bool sdkReadFileBlocks(const char *filename, T **data, unsigned int *len, unsigned int block_num, unsigned int block_size, bool verbose) { // check input arguments assert(NULL != filename); assert(NULL != len); // open file for reading FILE *fh = fopen(filename, "rb"); if (fh == NULL && verbose) { std::cerr << "sdkReadFile() : Opening file failed." << std::endl; return false; } // check if the given handle is already initialized // allocate storage for the data read data[block_num] = (T *) malloc(block_size); // read all data elements fseek(fh, block_num * block_size, SEEK_SET); *len = fread(data[block_num], sizeof(T), block_size/sizeof(T), fh); fclose(fh); return true; } ////////////////////////////////////////////////////////////////////////////// //! Write a data file \filename //! @return true if writing the file succeeded, otherwise false //! @param filename name of the source file //! @param data data to write //! @param len number of data elements in data, -1 on error //! @param epsilon epsilon for comparison ////////////////////////////////////////////////////////////////////////////// template inline bool sdkWriteFile(const char *filename, const T *data, unsigned int len, const S epsilon, bool verbose, bool append = false) { assert(NULL != filename); assert(NULL != data); // open file for writing // if (append) { std::fstream fh(filename, std::fstream::out | std::fstream::ate); if (verbose) { std::cerr << "sdkWriteFile() : Open file " << filename << " for write/append." << std::endl; } /* } else { std::fstream fh(filename, std::fstream::out); if (verbose) { std::cerr << "sdkWriteFile() : Open file " << filename << " for write." << std::endl; } } */ // check if filestream is valid if (! fh.good()) { if (verbose) { std::cerr << "sdkWriteFile() : Opening file failed." << std::endl; } return false; } // first write epsilon fh << "# " << epsilon << "\n"; // write data for (unsigned int i = 0; (i < len) && (fh.good()); ++i) { fh << data[i] << ' '; } // Check if writing succeeded if (! fh.good()) { if (verbose) { std::cerr << "sdkWriteFile() : Writing file failed." << std::endl; } return false; } // file ends with nl fh << std::endl; return true; } ////////////////////////////////////////////////////////////////////////////// //! Compare two arrays of arbitrary type //! @return true if \a reference and \a data are identical, otherwise false //! @param reference timer_interface to the reference data / gold image //! @param data handle to the computed data //! @param len number of elements in reference and data //! @param epsilon epsilon to use for the comparison ////////////////////////////////////////////////////////////////////////////// template inline bool compareData(const T *reference, const T *data, const unsigned int len, const S epsilon, const float threshold) { assert(epsilon >= 0); bool result = true; unsigned int error_count = 0; for (unsigned int i = 0; i < len; ++i) { float diff = (float)reference[i] - (float)data[i]; bool comp = (diff <= epsilon) && (diff >= -epsilon); result &= comp; error_count += !comp; #if 0 if (! comp) { std::cerr << "ERROR, i = " << i << ",\t " << reference[i] << " / " << data[i] << " (reference / data)\n"; } #endif } if (threshold == 0.0f) { return (result) ? true : false; } else { if (error_count) { printf("%4.2f(%%) of bytes mismatched (count=%d)\n", (float)error_count*100/(float)len, error_count); } return (len*threshold > error_count) ? true : false; } } #ifndef __MIN_EPSILON_ERROR #define __MIN_EPSILON_ERROR 1e-3f #endif ////////////////////////////////////////////////////////////////////////////// //! Compare two arrays of arbitrary type //! @return true if \a reference and \a data are identical, otherwise false //! @param reference handle to the reference data / gold image //! @param data handle to the computed data //! @param len number of elements in reference and data //! @param epsilon epsilon to use for the comparison //! @param epsilon threshold % of (# of bytes) for pass/fail ////////////////////////////////////////////////////////////////////////////// template inline bool compareDataAsFloatThreshold(const T *reference, const T *data, const unsigned int len, const S epsilon, const float threshold) { assert(epsilon >= 0); // If we set epsilon to be 0, let's set a minimum threshold float max_error = MAX((float)epsilon, __MIN_EPSILON_ERROR); int error_count = 0; bool result = true; for (unsigned int i = 0; i < len; ++i) { float diff = fabs((float)reference[i] - (float)data[i]); bool comp = (diff < max_error); result &= comp; if (! comp) { error_count++; #if 0 if (error_count < 50) { printf("\n ERROR(epsilon=%4.3f), i=%d, (ref)0x%02x / (data)0x%02x / (diff)%d\n", max_error, i, *(unsigned int *)&reference[i], *(unsigned int *)&data[i], (unsigned int)diff); } #endif } } if (threshold == 0.0f) { if (error_count) { printf("total # of errors = %d\n", error_count); } return (error_count == 0) ? true : false; } else { if (error_count) { printf("%4.2f(%%) of bytes mismatched (count=%d)\n", (float)error_count*100/(float)len, error_count); } return ((len*threshold > error_count) ? true : false); } } inline void sdkDumpBin(void *data, unsigned int bytes, const char *filename) { printf("sdkDumpBin: <%s>\n", filename); FILE *fp; FOPEN(fp, filename, "wb"); fwrite(data, bytes, 1, fp); fflush(fp); fclose(fp); } inline bool sdkCompareBin2BinUint(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold, char *exec_path) { unsigned int *src_buffer, *ref_buffer; FILE *src_fp = NULL, *ref_fp = NULL; unsigned long error_count = 0; size_t fsize = 0; if (FOPEN_FAIL(FOPEN(src_fp, src_file, "rb"))) { printf("compareBin2Bin unable to open src_file: %s\n", src_file); error_count++; } char *ref_file_path = sdkFindFilePath(ref_file, exec_path); if (ref_file_path == NULL) { printf("compareBin2Bin unable to find <%s> in <%s>\n", ref_file, exec_path); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } else { if (FOPEN_FAIL(FOPEN(ref_fp, ref_file_path, "rb"))) { printf("compareBin2Bin unable to open ref_file: %s\n", ref_file_path); error_count++; } if (src_fp && ref_fp) { src_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int)); ref_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int)); fsize = fread(src_buffer, nelements, sizeof(unsigned int), src_fp); fsize = fread(ref_buffer, nelements, sizeof(unsigned int), ref_fp); printf("> compareBin2Bin nelements=%d, epsilon=%4.2f, threshold=%4.2f\n", nelements, epsilon, threshold); printf(" src_file <%s>, size=%d bytes\n", src_file, (int)fsize); printf(" ref_file <%s>, size=%d bytes\n", ref_file_path, (int)fsize); if (!compareData(ref_buffer, src_buffer, nelements, epsilon, threshold)) { error_count++; } fclose(src_fp); fclose(ref_fp); free(src_buffer); free(ref_buffer); } else { if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } } if (error_count == 0) { printf(" OK\n"); } else { printf(" FAILURE: %d errors...\n", (unsigned int)error_count); } return (error_count == 0); // returns true if all pixels pass } inline bool sdkCompareBin2BinFloat(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold, char *exec_path) { float *src_buffer, *ref_buffer; FILE *src_fp = NULL, *ref_fp = NULL; size_t fsize = 0; unsigned long error_count = 0; if (FOPEN_FAIL(FOPEN(src_fp, src_file, "rb"))) { printf("compareBin2Bin unable to open src_file: %s\n", src_file); error_count = 1; } char *ref_file_path = sdkFindFilePath(ref_file, exec_path); if (ref_file_path == NULL) { printf("compareBin2Bin unable to find <%s> in <%s>\n", ref_file, exec_path); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", exec_path); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } else { if (FOPEN_FAIL(FOPEN(ref_fp, ref_file_path, "rb"))) { printf("compareBin2Bin unable to open ref_file: %s\n", ref_file_path); error_count = 1; } if (src_fp && ref_fp) { src_buffer = (float *)malloc(nelements*sizeof(float)); ref_buffer = (float *)malloc(nelements*sizeof(float)); fsize = fread(src_buffer, nelements, sizeof(float), src_fp); fsize = fread(ref_buffer, nelements, sizeof(float), ref_fp); printf("> compareBin2Bin nelements=%d, epsilon=%4.2f, threshold=%4.2f\n", nelements, epsilon, threshold); printf(" src_file <%s>, size=%d bytes\n", src_file, (int)fsize); printf(" ref_file <%s>, size=%d bytes\n", ref_file_path, (int)fsize); if (!compareDataAsFloatThreshold(ref_buffer, src_buffer, nelements, epsilon, threshold)) { error_count++; } fclose(src_fp); fclose(ref_fp); free(src_buffer); free(ref_buffer); } else { if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } } if (error_count == 0) { printf(" OK\n"); } else { printf(" FAILURE: %d errors...\n", (unsigned int)error_count); } return (error_count == 0); // returns true if all pixels pass } inline bool sdkCompareL2fe(const float *reference, const float *data, const unsigned int len, const float epsilon) { assert(epsilon >= 0); float error = 0; float ref = 0; for (unsigned int i = 0; i < len; ++i) { float diff = reference[i] - data[i]; error += diff * diff; ref += reference[i] * reference[i]; } float normRef = sqrtf(ref); if (fabs(ref) < 1e-7) { #ifdef _DEBUG std::cerr << "ERROR, reference l2-norm is 0\n"; #endif return false; } float normError = sqrtf(error); error = normError / normRef; bool result = error < epsilon; #ifdef _DEBUG if (! result) { std::cerr << "ERROR, l2-norm error " << error << " is greater than epsilon " << epsilon << "\n"; } #endif return result; } inline bool sdkLoadPPMub(const char *file, unsigned char **data, unsigned int *w,unsigned int *h) { unsigned int channels; return __loadPPM(file, data, w, h, &channels); } inline bool sdkLoadPPM4ub(const char *file, unsigned char **data, unsigned int *w, unsigned int *h) { unsigned char *idata = 0; unsigned int channels; if (__loadPPM(file, &idata, w, h, &channels)) { // pad 4th component int size = *w **h; // keep the original pointer unsigned char *idata_orig = idata; *data = (unsigned char *) malloc(sizeof(unsigned char) * size * 4); unsigned char *ptr = *data; for (int i=0; i Compare (a)rendered: <" << src_file << ">\n"; std::cerr << "> (b)reference: <" << ref_file << ">\n"; } if (sdkLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != true) { if (verboseErrors) { std::cerr << "PPMvsPPM: unable to load ref image file: "<< ref_file << "\n"; } return false; } if (sdkLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != true) { std::cerr << "PPMvsPPM: unable to load src image file: " << src_file << "\n"; return false; } if (src_height != ref_height || src_width != ref_width) { if (verboseErrors) std::cerr << "PPMvsPPM: source and ref size mismatch (" << src_width << "," << src_height << ")vs(" << ref_width << "," << ref_height << ")\n"; } if (verboseErrors) std::cerr << "PPMvsPPM: comparing images size (" << src_width << "," << src_height << ") epsilon(" << epsilon << "), threshold(" << threshold*100 << "%)\n"; if (compareData(ref_data, src_data, src_width*src_height*4, epsilon, threshold) == false) { error_count=1; } if (error_count == 0) { if (verboseErrors) { std::cerr << " OK\n\n"; } } else { if (verboseErrors) { std::cerr << " FAILURE! "< Compare (a)rendered: <" << src_file << ">\n"; std::cerr << "> (b)reference: <" << ref_file << ">\n"; } if (sdkLoadPPMub(ref_file, &ref_data, &ref_width, &ref_height) != true) { if (verboseErrors) { std::cerr << "PGMvsPGM: unable to load ref image file: "<< ref_file << "\n"; } return false; } if (sdkLoadPPMub(src_file, &src_data, &src_width, &src_height) != true) { std::cerr << "PGMvsPGM: unable to load src image file: " << src_file << "\n"; return false; } if (src_height != ref_height || src_width != ref_width) { if (verboseErrors) std::cerr << "PGMvsPGM: source and ref size mismatch (" << src_width << "," << src_height << ")vs(" << ref_width << "," << ref_height << ")\n"; } if (verboseErrors) std::cerr << "PGMvsPGM: comparing images size (" << src_width << "," << src_height << ") epsilon(" << epsilon << "), threshold(" << threshold*100 << "%)\n"; if (compareData(ref_data, src_data, src_width*src_height, epsilon, threshold) == false) { error_count=1; } if (error_count == 0) { if (verboseErrors) { std::cerr << " OK\n\n"; } } else { if (verboseErrors) { std::cerr << " FAILURE! "< //////////////////////////////////////////////////////////////////////////////// // host implementations of CUDA functions //////////////////////////////////////////////////////////////////////////////// inline float fminf(float a, float b) { return a < b ? a : b; } inline float fmaxf(float a, float b) { return a > b ? a : b; } inline int max(int a, int b) { return a > b ? a : b; } inline int min(int a, int b) { return a < b ? a : b; } inline float rsqrtf(float x) { return 1.0f / sqrtf(x); } #endif //////////////////////////////////////////////////////////////////////////////// // constructors //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 make_float2(float s) { return make_float2(s, s); } inline __host__ __device__ float2 make_float2(float3 a) { return make_float2(a.x, a.y); } inline __host__ __device__ float2 make_float2(int2 a) { return make_float2(float(a.x), float(a.y)); } inline __host__ __device__ float2 make_float2(uint2 a) { return make_float2(float(a.x), float(a.y)); } inline __host__ __device__ int2 make_int2(int s) { return make_int2(s, s); } inline __host__ __device__ int2 make_int2(int3 a) { return make_int2(a.x, a.y); } inline __host__ __device__ int2 make_int2(uint2 a) { return make_int2(int(a.x), int(a.y)); } inline __host__ __device__ int2 make_int2(float2 a) { return make_int2(int(a.x), int(a.y)); } inline __host__ __device__ uint2 make_uint2(uint s) { return make_uint2(s, s); } inline __host__ __device__ uint2 make_uint2(uint3 a) { return make_uint2(a.x, a.y); } inline __host__ __device__ uint2 make_uint2(int2 a) { return make_uint2(uint(a.x), uint(a.y)); } inline __host__ __device__ float3 make_float3(float s) { return make_float3(s, s, s); } inline __host__ __device__ float3 make_float3(float2 a) { return make_float3(a.x, a.y, 0.0f); } inline __host__ __device__ float3 make_float3(float2 a, float s) { return make_float3(a.x, a.y, s); } inline __host__ __device__ float3 make_float3(float4 a) { return make_float3(a.x, a.y, a.z); } inline __host__ __device__ float3 make_float3(int3 a) { return make_float3(float(a.x), float(a.y), float(a.z)); } inline __host__ __device__ float3 make_float3(uint3 a) { return make_float3(float(a.x), float(a.y), float(a.z)); } inline __host__ __device__ int3 make_int3(int s) { return make_int3(s, s, s); } inline __host__ __device__ int3 make_int3(int2 a) { return make_int3(a.x, a.y, 0); } inline __host__ __device__ int3 make_int3(int2 a, int s) { return make_int3(a.x, a.y, s); } inline __host__ __device__ int3 make_int3(uint3 a) { return make_int3(int(a.x), int(a.y), int(a.z)); } inline __host__ __device__ int3 make_int3(float3 a) { return make_int3(int(a.x), int(a.y), int(a.z)); } inline __host__ __device__ uint3 make_uint3(uint s) { return make_uint3(s, s, s); } inline __host__ __device__ uint3 make_uint3(uint2 a) { return make_uint3(a.x, a.y, 0); } inline __host__ __device__ uint3 make_uint3(uint2 a, uint s) { return make_uint3(a.x, a.y, s); } inline __host__ __device__ uint3 make_uint3(uint4 a) { return make_uint3(a.x, a.y, a.z); } inline __host__ __device__ uint3 make_uint3(int3 a) { return make_uint3(uint(a.x), uint(a.y), uint(a.z)); } inline __host__ __device__ float4 make_float4(float s) { return make_float4(s, s, s, s); } inline __host__ __device__ float4 make_float4(float3 a) { return make_float4(a.x, a.y, a.z, 0.0f); } inline __host__ __device__ float4 make_float4(float3 a, float w) { return make_float4(a.x, a.y, a.z, w); } inline __host__ __device__ float4 make_float4(int4 a) { return make_float4(float(a.x), float(a.y), float(a.z), float(a.w)); } inline __host__ __device__ float4 make_float4(uint4 a) { return make_float4(float(a.x), float(a.y), float(a.z), float(a.w)); } inline __host__ __device__ int4 make_int4(int s) { return make_int4(s, s, s, s); } inline __host__ __device__ int4 make_int4(int3 a) { return make_int4(a.x, a.y, a.z, 0); } inline __host__ __device__ int4 make_int4(int3 a, int w) { return make_int4(a.x, a.y, a.z, w); } inline __host__ __device__ int4 make_int4(uint4 a) { return make_int4(int(a.x), int(a.y), int(a.z), int(a.w)); } inline __host__ __device__ int4 make_int4(float4 a) { return make_int4(int(a.x), int(a.y), int(a.z), int(a.w)); } inline __host__ __device__ uint4 make_uint4(uint s) { return make_uint4(s, s, s, s); } inline __host__ __device__ uint4 make_uint4(uint3 a) { return make_uint4(a.x, a.y, a.z, 0); } inline __host__ __device__ uint4 make_uint4(uint3 a, uint w) { return make_uint4(a.x, a.y, a.z, w); } inline __host__ __device__ uint4 make_uint4(int4 a) { return make_uint4(uint(a.x), uint(a.y), uint(a.z), uint(a.w)); } //////////////////////////////////////////////////////////////////////////////// // negate //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 operator-(float2 &a) { return make_float2(-a.x, -a.y); } inline __host__ __device__ int2 operator-(int2 &a) { return make_int2(-a.x, -a.y); } inline __host__ __device__ float3 operator-(float3 &a) { return make_float3(-a.x, -a.y, -a.z); } inline __host__ __device__ int3 operator-(int3 &a) { return make_int3(-a.x, -a.y, -a.z); } inline __host__ __device__ float4 operator-(float4 &a) { return make_float4(-a.x, -a.y, -a.z, -a.w); } inline __host__ __device__ int4 operator-(int4 &a) { return make_int4(-a.x, -a.y, -a.z, -a.w); } //////////////////////////////////////////////////////////////////////////////// // addition //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 operator+(float2 a, float2 b) { return make_float2(a.x + b.x, a.y + b.y); } inline __host__ __device__ void operator+=(float2 &a, float2 b) { a.x += b.x; a.y += b.y; } inline __host__ __device__ float2 operator+(float2 a, float b) { return make_float2(a.x + b, a.y + b); } inline __host__ __device__ float2 operator+(float b, float2 a) { return make_float2(a.x + b, a.y + b); } inline __host__ __device__ void operator+=(float2 &a, float b) { a.x += b; a.y += b; } inline __host__ __device__ int2 operator+(int2 a, int2 b) { return make_int2(a.x + b.x, a.y + b.y); } inline __host__ __device__ void operator+=(int2 &a, int2 b) { a.x += b.x; a.y += b.y; } inline __host__ __device__ int2 operator+(int2 a, int b) { return make_int2(a.x + b, a.y + b); } inline __host__ __device__ int2 operator+(int b, int2 a) { return make_int2(a.x + b, a.y + b); } inline __host__ __device__ void operator+=(int2 &a, int b) { a.x += b; a.y += b; } inline __host__ __device__ uint2 operator+(uint2 a, uint2 b) { return make_uint2(a.x + b.x, a.y + b.y); } inline __host__ __device__ void operator+=(uint2 &a, uint2 b) { a.x += b.x; a.y += b.y; } inline __host__ __device__ uint2 operator+(uint2 a, uint b) { return make_uint2(a.x + b, a.y + b); } inline __host__ __device__ uint2 operator+(uint b, uint2 a) { return make_uint2(a.x + b, a.y + b); } inline __host__ __device__ void operator+=(uint2 &a, uint b) { a.x += b; a.y += b; } inline __host__ __device__ float3 operator+(float3 a, float3 b) { return make_float3(a.x + b.x, a.y + b.y, a.z + b.z); } inline __host__ __device__ void operator+=(float3 &a, float3 b) { a.x += b.x; a.y += b.y; a.z += b.z; } inline __host__ __device__ float3 operator+(float3 a, float b) { return make_float3(a.x + b, a.y + b, a.z + b); } inline __host__ __device__ void operator+=(float3 &a, float b) { a.x += b; a.y += b; a.z += b; } inline __host__ __device__ int3 operator+(int3 a, int3 b) { return make_int3(a.x + b.x, a.y + b.y, a.z + b.z); } inline __host__ __device__ void operator+=(int3 &a, int3 b) { a.x += b.x; a.y += b.y; a.z += b.z; } inline __host__ __device__ int3 operator+(int3 a, int b) { return make_int3(a.x + b, a.y + b, a.z + b); } inline __host__ __device__ void operator+=(int3 &a, int b) { a.x += b; a.y += b; a.z += b; } inline __host__ __device__ uint3 operator+(uint3 a, uint3 b) { return make_uint3(a.x + b.x, a.y + b.y, a.z + b.z); } inline __host__ __device__ void operator+=(uint3 &a, uint3 b) { a.x += b.x; a.y += b.y; a.z += b.z; } inline __host__ __device__ uint3 operator+(uint3 a, uint b) { return make_uint3(a.x + b, a.y + b, a.z + b); } inline __host__ __device__ void operator+=(uint3 &a, uint b) { a.x += b; a.y += b; a.z += b; } inline __host__ __device__ int3 operator+(int b, int3 a) { return make_int3(a.x + b, a.y + b, a.z + b); } inline __host__ __device__ uint3 operator+(uint b, uint3 a) { return make_uint3(a.x + b, a.y + b, a.z + b); } inline __host__ __device__ float3 operator+(float b, float3 a) { return make_float3(a.x + b, a.y + b, a.z + b); } inline __host__ __device__ float4 operator+(float4 a, float4 b) { return make_float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } inline __host__ __device__ void operator+=(float4 &a, float4 b) { a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; } inline __host__ __device__ float4 operator+(float4 a, float b) { return make_float4(a.x + b, a.y + b, a.z + b, a.w + b); } inline __host__ __device__ float4 operator+(float b, float4 a) { return make_float4(a.x + b, a.y + b, a.z + b, a.w + b); } inline __host__ __device__ void operator+=(float4 &a, float b) { a.x += b; a.y += b; a.z += b; a.w += b; } inline __host__ __device__ int4 operator+(int4 a, int4 b) { return make_int4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } inline __host__ __device__ void operator+=(int4 &a, int4 b) { a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; } inline __host__ __device__ int4 operator+(int4 a, int b) { return make_int4(a.x + b, a.y + b, a.z + b, a.w + b); } inline __host__ __device__ int4 operator+(int b, int4 a) { return make_int4(a.x + b, a.y + b, a.z + b, a.w + b); } inline __host__ __device__ void operator+=(int4 &a, int b) { a.x += b; a.y += b; a.z += b; a.w += b; } inline __host__ __device__ uint4 operator+(uint4 a, uint4 b) { return make_uint4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } inline __host__ __device__ void operator+=(uint4 &a, uint4 b) { a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; } inline __host__ __device__ uint4 operator+(uint4 a, uint b) { return make_uint4(a.x + b, a.y + b, a.z + b, a.w + b); } inline __host__ __device__ uint4 operator+(uint b, uint4 a) { return make_uint4(a.x + b, a.y + b, a.z + b, a.w + b); } inline __host__ __device__ void operator+=(uint4 &a, uint b) { a.x += b; a.y += b; a.z += b; a.w += b; } //////////////////////////////////////////////////////////////////////////////// // subtract //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 operator-(float2 a, float2 b) { return make_float2(a.x - b.x, a.y - b.y); } inline __host__ __device__ void operator-=(float2 &a, float2 b) { a.x -= b.x; a.y -= b.y; } inline __host__ __device__ float2 operator-(float2 a, float b) { return make_float2(a.x - b, a.y - b); } inline __host__ __device__ float2 operator-(float b, float2 a) { return make_float2(b - a.x, b - a.y); } inline __host__ __device__ void operator-=(float2 &a, float b) { a.x -= b; a.y -= b; } inline __host__ __device__ int2 operator-(int2 a, int2 b) { return make_int2(a.x - b.x, a.y - b.y); } inline __host__ __device__ void operator-=(int2 &a, int2 b) { a.x -= b.x; a.y -= b.y; } inline __host__ __device__ int2 operator-(int2 a, int b) { return make_int2(a.x - b, a.y - b); } inline __host__ __device__ int2 operator-(int b, int2 a) { return make_int2(b - a.x, b - a.y); } inline __host__ __device__ void operator-=(int2 &a, int b) { a.x -= b; a.y -= b; } inline __host__ __device__ uint2 operator-(uint2 a, uint2 b) { return make_uint2(a.x - b.x, a.y - b.y); } inline __host__ __device__ void operator-=(uint2 &a, uint2 b) { a.x -= b.x; a.y -= b.y; } inline __host__ __device__ uint2 operator-(uint2 a, uint b) { return make_uint2(a.x - b, a.y - b); } inline __host__ __device__ uint2 operator-(uint b, uint2 a) { return make_uint2(b - a.x, b - a.y); } inline __host__ __device__ void operator-=(uint2 &a, uint b) { a.x -= b; a.y -= b; } inline __host__ __device__ float3 operator-(float3 a, float3 b) { return make_float3(a.x - b.x, a.y - b.y, a.z - b.z); } inline __host__ __device__ void operator-=(float3 &a, float3 b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; } inline __host__ __device__ float3 operator-(float3 a, float b) { return make_float3(a.x - b, a.y - b, a.z - b); } inline __host__ __device__ float3 operator-(float b, float3 a) { return make_float3(b - a.x, b - a.y, b - a.z); } inline __host__ __device__ void operator-=(float3 &a, float b) { a.x -= b; a.y -= b; a.z -= b; } inline __host__ __device__ int3 operator-(int3 a, int3 b) { return make_int3(a.x - b.x, a.y - b.y, a.z - b.z); } inline __host__ __device__ void operator-=(int3 &a, int3 b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; } inline __host__ __device__ int3 operator-(int3 a, int b) { return make_int3(a.x - b, a.y - b, a.z - b); } inline __host__ __device__ int3 operator-(int b, int3 a) { return make_int3(b - a.x, b - a.y, b - a.z); } inline __host__ __device__ void operator-=(int3 &a, int b) { a.x -= b; a.y -= b; a.z -= b; } inline __host__ __device__ uint3 operator-(uint3 a, uint3 b) { return make_uint3(a.x - b.x, a.y - b.y, a.z - b.z); } inline __host__ __device__ void operator-=(uint3 &a, uint3 b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; } inline __host__ __device__ uint3 operator-(uint3 a, uint b) { return make_uint3(a.x - b, a.y - b, a.z - b); } inline __host__ __device__ uint3 operator-(uint b, uint3 a) { return make_uint3(b - a.x, b - a.y, b - a.z); } inline __host__ __device__ void operator-=(uint3 &a, uint b) { a.x -= b; a.y -= b; a.z -= b; } inline __host__ __device__ float4 operator-(float4 a, float4 b) { return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } inline __host__ __device__ void operator-=(float4 &a, float4 b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; } inline __host__ __device__ float4 operator-(float4 a, float b) { return make_float4(a.x - b, a.y - b, a.z - b, a.w - b); } inline __host__ __device__ void operator-=(float4 &a, float b) { a.x -= b; a.y -= b; a.z -= b; a.w -= b; } inline __host__ __device__ int4 operator-(int4 a, int4 b) { return make_int4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } inline __host__ __device__ void operator-=(int4 &a, int4 b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; } inline __host__ __device__ int4 operator-(int4 a, int b) { return make_int4(a.x - b, a.y - b, a.z - b, a.w - b); } inline __host__ __device__ int4 operator-(int b, int4 a) { return make_int4(b - a.x, b - a.y, b - a.z, b - a.w); } inline __host__ __device__ void operator-=(int4 &a, int b) { a.x -= b; a.y -= b; a.z -= b; a.w -= b; } inline __host__ __device__ uint4 operator-(uint4 a, uint4 b) { return make_uint4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } inline __host__ __device__ void operator-=(uint4 &a, uint4 b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; } inline __host__ __device__ uint4 operator-(uint4 a, uint b) { return make_uint4(a.x - b, a.y - b, a.z - b, a.w - b); } inline __host__ __device__ uint4 operator-(uint b, uint4 a) { return make_uint4(b - a.x, b - a.y, b - a.z, b - a.w); } inline __host__ __device__ void operator-=(uint4 &a, uint b) { a.x -= b; a.y -= b; a.z -= b; a.w -= b; } //////////////////////////////////////////////////////////////////////////////// // multiply //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 operator*(float2 a, float2 b) { return make_float2(a.x * b.x, a.y * b.y); } inline __host__ __device__ void operator*=(float2 &a, float2 b) { a.x *= b.x; a.y *= b.y; } inline __host__ __device__ float2 operator*(float2 a, float b) { return make_float2(a.x * b, a.y * b); } inline __host__ __device__ float2 operator*(float b, float2 a) { return make_float2(b * a.x, b * a.y); } inline __host__ __device__ void operator*=(float2 &a, float b) { a.x *= b; a.y *= b; } inline __host__ __device__ int2 operator*(int2 a, int2 b) { return make_int2(a.x * b.x, a.y * b.y); } inline __host__ __device__ void operator*=(int2 &a, int2 b) { a.x *= b.x; a.y *= b.y; } inline __host__ __device__ int2 operator*(int2 a, int b) { return make_int2(a.x * b, a.y * b); } inline __host__ __device__ int2 operator*(int b, int2 a) { return make_int2(b * a.x, b * a.y); } inline __host__ __device__ void operator*=(int2 &a, int b) { a.x *= b; a.y *= b; } inline __host__ __device__ uint2 operator*(uint2 a, uint2 b) { return make_uint2(a.x * b.x, a.y * b.y); } inline __host__ __device__ void operator*=(uint2 &a, uint2 b) { a.x *= b.x; a.y *= b.y; } inline __host__ __device__ uint2 operator*(uint2 a, uint b) { return make_uint2(a.x * b, a.y * b); } inline __host__ __device__ uint2 operator*(uint b, uint2 a) { return make_uint2(b * a.x, b * a.y); } inline __host__ __device__ void operator*=(uint2 &a, uint b) { a.x *= b; a.y *= b; } inline __host__ __device__ float3 operator*(float3 a, float3 b) { return make_float3(a.x * b.x, a.y * b.y, a.z * b.z); } inline __host__ __device__ void operator*=(float3 &a, float3 b) { a.x *= b.x; a.y *= b.y; a.z *= b.z; } inline __host__ __device__ float3 operator*(float3 a, float b) { return make_float3(a.x * b, a.y * b, a.z * b); } inline __host__ __device__ float3 operator*(float b, float3 a) { return make_float3(b * a.x, b * a.y, b * a.z); } inline __host__ __device__ void operator*=(float3 &a, float b) { a.x *= b; a.y *= b; a.z *= b; } inline __host__ __device__ int3 operator*(int3 a, int3 b) { return make_int3(a.x * b.x, a.y * b.y, a.z * b.z); } inline __host__ __device__ void operator*=(int3 &a, int3 b) { a.x *= b.x; a.y *= b.y; a.z *= b.z; } inline __host__ __device__ int3 operator*(int3 a, int b) { return make_int3(a.x * b, a.y * b, a.z * b); } inline __host__ __device__ int3 operator*(int b, int3 a) { return make_int3(b * a.x, b * a.y, b * a.z); } inline __host__ __device__ void operator*=(int3 &a, int b) { a.x *= b; a.y *= b; a.z *= b; } inline __host__ __device__ uint3 operator*(uint3 a, uint3 b) { return make_uint3(a.x * b.x, a.y * b.y, a.z * b.z); } inline __host__ __device__ void operator*=(uint3 &a, uint3 b) { a.x *= b.x; a.y *= b.y; a.z *= b.z; } inline __host__ __device__ uint3 operator*(uint3 a, uint b) { return make_uint3(a.x * b, a.y * b, a.z * b); } inline __host__ __device__ uint3 operator*(uint b, uint3 a) { return make_uint3(b * a.x, b * a.y, b * a.z); } inline __host__ __device__ void operator*=(uint3 &a, uint b) { a.x *= b; a.y *= b; a.z *= b; } inline __host__ __device__ float4 operator*(float4 a, float4 b) { return make_float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); } inline __host__ __device__ void operator*=(float4 &a, float4 b) { a.x *= b.x; a.y *= b.y; a.z *= b.z; a.w *= b.w; } inline __host__ __device__ float4 operator*(float4 a, float b) { return make_float4(a.x * b, a.y * b, a.z * b, a.w * b); } inline __host__ __device__ float4 operator*(float b, float4 a) { return make_float4(b * a.x, b * a.y, b * a.z, b * a.w); } inline __host__ __device__ void operator*=(float4 &a, float b) { a.x *= b; a.y *= b; a.z *= b; a.w *= b; } inline __host__ __device__ int4 operator*(int4 a, int4 b) { return make_int4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); } inline __host__ __device__ void operator*=(int4 &a, int4 b) { a.x *= b.x; a.y *= b.y; a.z *= b.z; a.w *= b.w; } inline __host__ __device__ int4 operator*(int4 a, int b) { return make_int4(a.x * b, a.y * b, a.z * b, a.w * b); } inline __host__ __device__ int4 operator*(int b, int4 a) { return make_int4(b * a.x, b * a.y, b * a.z, b * a.w); } inline __host__ __device__ void operator*=(int4 &a, int b) { a.x *= b; a.y *= b; a.z *= b; a.w *= b; } inline __host__ __device__ uint4 operator*(uint4 a, uint4 b) { return make_uint4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); } inline __host__ __device__ void operator*=(uint4 &a, uint4 b) { a.x *= b.x; a.y *= b.y; a.z *= b.z; a.w *= b.w; } inline __host__ __device__ uint4 operator*(uint4 a, uint b) { return make_uint4(a.x * b, a.y * b, a.z * b, a.w * b); } inline __host__ __device__ uint4 operator*(uint b, uint4 a) { return make_uint4(b * a.x, b * a.y, b * a.z, b * a.w); } inline __host__ __device__ void operator*=(uint4 &a, uint b) { a.x *= b; a.y *= b; a.z *= b; a.w *= b; } //////////////////////////////////////////////////////////////////////////////// // divide //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 operator/(float2 a, float2 b) { return make_float2(a.x / b.x, a.y / b.y); } inline __host__ __device__ void operator/=(float2 &a, float2 b) { a.x /= b.x; a.y /= b.y; } inline __host__ __device__ float2 operator/(float2 a, float b) { return make_float2(a.x / b, a.y / b); } inline __host__ __device__ void operator/=(float2 &a, float b) { a.x /= b; a.y /= b; } inline __host__ __device__ float2 operator/(float b, float2 a) { return make_float2(b / a.x, b / a.y); } inline __host__ __device__ float3 operator/(float3 a, float3 b) { return make_float3(a.x / b.x, a.y / b.y, a.z / b.z); } inline __host__ __device__ void operator/=(float3 &a, float3 b) { a.x /= b.x; a.y /= b.y; a.z /= b.z; } inline __host__ __device__ float3 operator/(float3 a, float b) { return make_float3(a.x / b, a.y / b, a.z / b); } inline __host__ __device__ void operator/=(float3 &a, float b) { a.x /= b; a.y /= b; a.z /= b; } inline __host__ __device__ float3 operator/(float b, float3 a) { return make_float3(b / a.x, b / a.y, b / a.z); } inline __host__ __device__ float4 operator/(float4 a, float4 b) { return make_float4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); } inline __host__ __device__ void operator/=(float4 &a, float4 b) { a.x /= b.x; a.y /= b.y; a.z /= b.z; a.w /= b.w; } inline __host__ __device__ float4 operator/(float4 a, float b) { return make_float4(a.x / b, a.y / b, a.z / b, a.w / b); } inline __host__ __device__ void operator/=(float4 &a, float b) { a.x /= b; a.y /= b; a.z /= b; a.w /= b; } inline __host__ __device__ float4 operator/(float b, float4 a) { return make_float4(b / a.x, b / a.y, b / a.z, b / a.w); } //////////////////////////////////////////////////////////////////////////////// // min //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 fminf(float2 a, float2 b) { return make_float2(fminf(a.x,b.x), fminf(a.y,b.y)); } inline __host__ __device__ float3 fminf(float3 a, float3 b) { return make_float3(fminf(a.x,b.x), fminf(a.y,b.y), fminf(a.z,b.z)); } inline __host__ __device__ float4 fminf(float4 a, float4 b) { return make_float4(fminf(a.x,b.x), fminf(a.y,b.y), fminf(a.z,b.z), fminf(a.w,b.w)); } inline __host__ __device__ int2 min(int2 a, int2 b) { return make_int2(min(a.x,b.x), min(a.y,b.y)); } inline __host__ __device__ int3 min(int3 a, int3 b) { return make_int3(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z)); } inline __host__ __device__ int4 min(int4 a, int4 b) { return make_int4(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z), min(a.w,b.w)); } inline __host__ __device__ uint2 min(uint2 a, uint2 b) { return make_uint2(min(a.x,b.x), min(a.y,b.y)); } inline __host__ __device__ uint3 min(uint3 a, uint3 b) { return make_uint3(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z)); } inline __host__ __device__ uint4 min(uint4 a, uint4 b) { return make_uint4(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z), min(a.w,b.w)); } //////////////////////////////////////////////////////////////////////////////// // max //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 fmaxf(float2 a, float2 b) { return make_float2(fmaxf(a.x,b.x), fmaxf(a.y,b.y)); } inline __host__ __device__ float3 fmaxf(float3 a, float3 b) { return make_float3(fmaxf(a.x,b.x), fmaxf(a.y,b.y), fmaxf(a.z,b.z)); } inline __host__ __device__ float4 fmaxf(float4 a, float4 b) { return make_float4(fmaxf(a.x,b.x), fmaxf(a.y,b.y), fmaxf(a.z,b.z), fmaxf(a.w,b.w)); } inline __host__ __device__ int2 max(int2 a, int2 b) { return make_int2(max(a.x,b.x), max(a.y,b.y)); } inline __host__ __device__ int3 max(int3 a, int3 b) { return make_int3(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z)); } inline __host__ __device__ int4 max(int4 a, int4 b) { return make_int4(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z), max(a.w,b.w)); } inline __host__ __device__ uint2 max(uint2 a, uint2 b) { return make_uint2(max(a.x,b.x), max(a.y,b.y)); } inline __host__ __device__ uint3 max(uint3 a, uint3 b) { return make_uint3(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z)); } inline __host__ __device__ uint4 max(uint4 a, uint4 b) { return make_uint4(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z), max(a.w,b.w)); } //////////////////////////////////////////////////////////////////////////////// // lerp // - linear interpolation between a and b, based on value t in [0, 1] range //////////////////////////////////////////////////////////////////////////////// inline __device__ __host__ float lerp(float a, float b, float t) { return a + t*(b-a); } inline __device__ __host__ float2 lerp(float2 a, float2 b, float t) { return a + t*(b-a); } inline __device__ __host__ float3 lerp(float3 a, float3 b, float t) { return a + t*(b-a); } inline __device__ __host__ float4 lerp(float4 a, float4 b, float t) { return a + t*(b-a); } //////////////////////////////////////////////////////////////////////////////// // clamp // - clamp the value v to be in the range [a, b] //////////////////////////////////////////////////////////////////////////////// inline __device__ __host__ float clamp(float f, float a, float b) { return fmaxf(a, fminf(f, b)); } inline __device__ __host__ int clamp(int f, int a, int b) { return max(a, min(f, b)); } inline __device__ __host__ uint clamp(uint f, uint a, uint b) { return max(a, min(f, b)); } inline __device__ __host__ float2 clamp(float2 v, float a, float b) { return make_float2(clamp(v.x, a, b), clamp(v.y, a, b)); } inline __device__ __host__ float2 clamp(float2 v, float2 a, float2 b) { return make_float2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); } inline __device__ __host__ float3 clamp(float3 v, float a, float b) { return make_float3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); } inline __device__ __host__ float3 clamp(float3 v, float3 a, float3 b) { return make_float3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); } inline __device__ __host__ float4 clamp(float4 v, float a, float b) { return make_float4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); } inline __device__ __host__ float4 clamp(float4 v, float4 a, float4 b) { return make_float4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); } inline __device__ __host__ int2 clamp(int2 v, int a, int b) { return make_int2(clamp(v.x, a, b), clamp(v.y, a, b)); } inline __device__ __host__ int2 clamp(int2 v, int2 a, int2 b) { return make_int2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); } inline __device__ __host__ int3 clamp(int3 v, int a, int b) { return make_int3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); } inline __device__ __host__ int3 clamp(int3 v, int3 a, int3 b) { return make_int3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); } inline __device__ __host__ int4 clamp(int4 v, int a, int b) { return make_int4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); } inline __device__ __host__ int4 clamp(int4 v, int4 a, int4 b) { return make_int4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); } inline __device__ __host__ uint2 clamp(uint2 v, uint a, uint b) { return make_uint2(clamp(v.x, a, b), clamp(v.y, a, b)); } inline __device__ __host__ uint2 clamp(uint2 v, uint2 a, uint2 b) { return make_uint2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); } inline __device__ __host__ uint3 clamp(uint3 v, uint a, uint b) { return make_uint3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); } inline __device__ __host__ uint3 clamp(uint3 v, uint3 a, uint3 b) { return make_uint3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); } inline __device__ __host__ uint4 clamp(uint4 v, uint a, uint b) { return make_uint4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); } inline __device__ __host__ uint4 clamp(uint4 v, uint4 a, uint4 b) { return make_uint4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); } //////////////////////////////////////////////////////////////////////////////// // dot product //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float dot(float2 a, float2 b) { return a.x * b.x + a.y * b.y; } inline __host__ __device__ float dot(float3 a, float3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } inline __host__ __device__ float dot(float4 a, float4 b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } inline __host__ __device__ int dot(int2 a, int2 b) { return a.x * b.x + a.y * b.y; } inline __host__ __device__ int dot(int3 a, int3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } inline __host__ __device__ int dot(int4 a, int4 b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } inline __host__ __device__ uint dot(uint2 a, uint2 b) { return a.x * b.x + a.y * b.y; } inline __host__ __device__ uint dot(uint3 a, uint3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } inline __host__ __device__ uint dot(uint4 a, uint4 b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } //////////////////////////////////////////////////////////////////////////////// // length //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float length(float2 v) { return sqrtf(dot(v, v)); } inline __host__ __device__ float length(float3 v) { return sqrtf(dot(v, v)); } inline __host__ __device__ float length(float4 v) { return sqrtf(dot(v, v)); } //////////////////////////////////////////////////////////////////////////////// // normalize //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 normalize(float2 v) { float invLen = rsqrtf(dot(v, v)); return v * invLen; } inline __host__ __device__ float3 normalize(float3 v) { float invLen = rsqrtf(dot(v, v)); return v * invLen; } inline __host__ __device__ float4 normalize(float4 v) { float invLen = rsqrtf(dot(v, v)); return v * invLen; } //////////////////////////////////////////////////////////////////////////////// // floor //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 floorf(float2 v) { return make_float2(floorf(v.x), floorf(v.y)); } inline __host__ __device__ float3 floorf(float3 v) { return make_float3(floorf(v.x), floorf(v.y), floorf(v.z)); } inline __host__ __device__ float4 floorf(float4 v) { return make_float4(floorf(v.x), floorf(v.y), floorf(v.z), floorf(v.w)); } //////////////////////////////////////////////////////////////////////////////// // frac - returns the fractional portion of a scalar or each vector component //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float fracf(float v) { return v - floorf(v); } inline __host__ __device__ float2 fracf(float2 v) { return make_float2(fracf(v.x), fracf(v.y)); } inline __host__ __device__ float3 fracf(float3 v) { return make_float3(fracf(v.x), fracf(v.y), fracf(v.z)); } inline __host__ __device__ float4 fracf(float4 v) { return make_float4(fracf(v.x), fracf(v.y), fracf(v.z), fracf(v.w)); } //////////////////////////////////////////////////////////////////////////////// // fmod //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 fmodf(float2 a, float2 b) { return make_float2(fmodf(a.x, b.x), fmodf(a.y, b.y)); } inline __host__ __device__ float3 fmodf(float3 a, float3 b) { return make_float3(fmodf(a.x, b.x), fmodf(a.y, b.y), fmodf(a.z, b.z)); } inline __host__ __device__ float4 fmodf(float4 a, float4 b) { return make_float4(fmodf(a.x, b.x), fmodf(a.y, b.y), fmodf(a.z, b.z), fmodf(a.w, b.w)); } //////////////////////////////////////////////////////////////////////////////// // absolute value //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float2 fabs(float2 v) { return make_float2(fabs(v.x), fabs(v.y)); } inline __host__ __device__ float3 fabs(float3 v) { return make_float3(fabs(v.x), fabs(v.y), fabs(v.z)); } inline __host__ __device__ float4 fabs(float4 v) { return make_float4(fabs(v.x), fabs(v.y), fabs(v.z), fabs(v.w)); } inline __host__ __device__ int2 abs(int2 v) { return make_int2(abs(v.x), abs(v.y)); } inline __host__ __device__ int3 abs(int3 v) { return make_int3(abs(v.x), abs(v.y), abs(v.z)); } inline __host__ __device__ int4 abs(int4 v) { return make_int4(abs(v.x), abs(v.y), abs(v.z), abs(v.w)); } //////////////////////////////////////////////////////////////////////////////// // reflect // - returns reflection of incident ray I around surface normal N // - N should be normalized, reflected vector's length is equal to length of I //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float3 reflect(float3 i, float3 n) { return i - 2.0f * n * dot(n,i); } //////////////////////////////////////////////////////////////////////////////// // cross product //////////////////////////////////////////////////////////////////////////////// inline __host__ __device__ float3 cross(float3 a, float3 b) { return make_float3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); } //////////////////////////////////////////////////////////////////////////////// // smoothstep // - returns 0 if x < a // - returns 1 if x > b // - otherwise returns smooth interpolation between 0 and 1 based on x //////////////////////////////////////////////////////////////////////////////// inline __device__ __host__ float smoothstep(float a, float b, float x) { float y = clamp((x - a) / (b - a), 0.0f, 1.0f); return (y*y*(3.0f - (2.0f*y))); } inline __device__ __host__ float2 smoothstep(float2 a, float2 b, float2 x) { float2 y = clamp((x - a) / (b - a), 0.0f, 1.0f); return (y*y*(make_float2(3.0f) - (make_float2(2.0f)*y))); } inline __device__ __host__ float3 smoothstep(float3 a, float3 b, float3 x) { float3 y = clamp((x - a) / (b - a), 0.0f, 1.0f); return (y*y*(make_float3(3.0f) - (make_float3(2.0f)*y))); } inline __device__ __host__ float4 smoothstep(float4 a, float4 b, float4 x) { float4 y = clamp((x - a) / (b - a), 0.0f, 1.0f); return (y*y*(make_float4(3.0f) - (make_float4(2.0f)*y))); } #endif ================================================ FILE: tests/projects/cuda/console/inc/helper_string.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // These are helper functions for the SDK samples (string parsing, timers, etc) #ifndef STRING_HELPER_H #define STRING_HELPER_H #include #include #include #include #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE #endif #ifndef STRCASECMP #define STRCASECMP _stricmp #endif #ifndef STRNCASECMP #define STRNCASECMP _strnicmp #endif #ifndef STRCPY #define STRCPY(sFilePath, nLength, sPath) strcpy_s(sFilePath, nLength, sPath) #endif #ifndef FOPEN #define FOPEN(fHandle,filename,mode) fopen_s(&fHandle, filename, mode) #endif #ifndef FOPEN_FAIL #define FOPEN_FAIL(result) (result != 0) #endif #ifndef SSCANF #define SSCANF sscanf_s #endif #ifndef SPRINTF #define SPRINTF sprintf_s #endif #else // Linux Includes #include #include #ifndef STRCASECMP #define STRCASECMP strcasecmp #endif #ifndef STRNCASECMP #define STRNCASECMP strncasecmp #endif #ifndef STRCPY #define STRCPY(sFilePath, nLength, sPath) strcpy(sFilePath, sPath) #endif #ifndef FOPEN #define FOPEN(fHandle,filename,mode) (fHandle = fopen(filename, mode)) #endif #ifndef FOPEN_FAIL #define FOPEN_FAIL(result) (result == NULL) #endif #ifndef SSCANF #define SSCANF sscanf #endif #ifndef SPRINTF #define SPRINTF sprintf #endif #endif #ifndef EXIT_WAIVED #define EXIT_WAIVED 2 #endif // CUDA Utility Helper Functions inline int stringRemoveDelimiter(char delimiter, const char *string) { int string_start = 0; while (string[string_start] == delimiter) { string_start++; } if (string_start >= (int)strlen(string)-1) { return 0; } return string_start; } inline int getFileExtension(char *filename, char **extension) { int string_length = (int)strlen(filename); while (filename[string_length--] != '.') { if (string_length == 0) break; } if (string_length > 0) string_length += 2; if (string_length == 0) *extension = NULL; else *extension = &filename[string_length]; return string_length; } inline bool checkCmdLineFlag(const int argc, const char **argv, const char *string_ref) { bool bFound = false; if (argc >= 1) { for (int i=1; i < argc; i++) { int string_start = stringRemoveDelimiter('-', argv[i]); const char *string_argv = &argv[i][string_start]; const char *equal_pos = strchr(string_argv, '='); int argv_length = (int)(equal_pos == 0 ? strlen(string_argv) : equal_pos - string_argv); int length = (int)strlen(string_ref); if (length == argv_length && !STRNCASECMP(string_argv, string_ref, length)) { bFound = true; continue; } } } return bFound; } // This function wraps the CUDA Driver API into a template function template inline bool getCmdLineArgumentValue(const int argc, const char **argv, const char *string_ref, T *value) { bool bFound = false; if (argc >= 1) { for (int i=1; i < argc; i++) { int string_start = stringRemoveDelimiter('-', argv[i]); const char *string_argv = &argv[i][string_start]; int length = (int)strlen(string_ref); if (!STRNCASECMP(string_argv, string_ref, length)) { if (length+1 <= (int)strlen(string_argv)) { int auto_inc = (string_argv[length] == '=') ? 1 : 0; *value = (T)atoi(&string_argv[length + auto_inc]); } bFound = true; i=argc; } } } return bFound; } inline int getCmdLineArgumentInt(const int argc, const char **argv, const char *string_ref) { bool bFound = false; int value = -1; if (argc >= 1) { for (int i=1; i < argc; i++) { int string_start = stringRemoveDelimiter('-', argv[i]); const char *string_argv = &argv[i][string_start]; int length = (int)strlen(string_ref); if (!STRNCASECMP(string_argv, string_ref, length)) { if (length+1 <= (int)strlen(string_argv)) { int auto_inc = (string_argv[length] == '=') ? 1 : 0; value = atoi(&string_argv[length + auto_inc]); } else { value = 0; } bFound = true; continue; } } } if (bFound) { return value; } else { return 0; } } inline float getCmdLineArgumentFloat(const int argc, const char **argv, const char *string_ref) { bool bFound = false; float value = -1; if (argc >= 1) { for (int i=1; i < argc; i++) { int string_start = stringRemoveDelimiter('-', argv[i]); const char *string_argv = &argv[i][string_start]; int length = (int)strlen(string_ref); if (!STRNCASECMP(string_argv, string_ref, length)) { if (length+1 <= (int)strlen(string_argv)) { int auto_inc = (string_argv[length] == '=') ? 1 : 0; value = (float)atof(&string_argv[length + auto_inc]); } else { value = 0.f; } bFound = true; continue; } } } if (bFound) { return value; } else { return 0; } } inline bool getCmdLineArgumentString(const int argc, const char **argv, const char *string_ref, char **string_retval) { bool bFound = false; if (argc >= 1) { for (int i=1; i < argc; i++) { int string_start = stringRemoveDelimiter('-', argv[i]); char *string_argv = (char *)&argv[i][string_start]; int length = (int)strlen(string_ref); if (!STRNCASECMP(string_argv, string_ref, length)) { *string_retval = &string_argv[length+1]; bFound = true; continue; } } } if (!bFound) { *string_retval = NULL; } return bFound; } ////////////////////////////////////////////////////////////////////////////// //! Find the path for a file assuming that //! files are found in the searchPath. //! //! @return the path if succeeded, otherwise 0 //! @param filename name of the file //! @param executable_path optional absolute path of the executable ////////////////////////////////////////////////////////////////////////////// inline char *sdkFindFilePath(const char *filename, const char *executable_path) { // defines a variable that is replaced with the name of the executable // Typical relative search paths to locate needed companion files (e.g. sample input data, or JIT source files) // The origin for the relative search may be the .exe file, a .bat file launching an .exe, a browser .exe launching the .exe or .bat, etc const char *searchPath[] = { "./", // same dir "./_data_files/", "./common/", // "/common/" subdir "./common/data/", // "/common/data/" subdir "./data/", // "/data/" subdir "./src/", // "/src/" subdir "./src//data/", // "/src//data/" subdir "./inc/", // "/inc/" subdir "./0_Simple/", // "/0_Simple/" subdir "./1_Utilities/", // "/1_Utilities/" subdir "./2_Graphics/", // "/2_Graphics/" subdir "./3_Imaging/", // "/3_Imaging/" subdir "./4_Finance/", // "/4_Finance/" subdir "./5_Simulations/", // "/5_Simulations/" subdir "./6_Advanced/", // "/6_Advanced/" subdir "./7_CUDALibraries/", // "/7_CUDALibraries/" subdir "./8_Android/", // "/8_Android/" subdir "./samples/", // "/samples/" subdir "./0_Simple//data/", // "/0_Simple//data/" subdir "./1_Utilities//data/", // "/1_Utilities//data/" subdir "./2_Graphics//data/", // "/2_Graphics//data/" subdir "./3_Imaging//data/", // "/3_Imaging//data/" subdir "./4_Finance//data/", // "/4_Finance//data/" subdir "./5_Simulations//data/", // "/5_Simulations//data/" subdir "./6_Advanced//data/", // "/6_Advanced//data/" subdir "./7_CUDALibraries//", // "/7_CUDALibraries//" subdir "./7_CUDALibraries//data/", // "/7_CUDALibraries//data/" subdir "../", // up 1 in tree "../common/", // up 1 in tree, "/common/" subdir "../common/data/", // up 1 in tree, "/common/data/" subdir "../data/", // up 1 in tree, "/data/" subdir "../src/", // up 1 in tree, "/src/" subdir "../inc/", // up 1 in tree, "/inc/" subdir "../0_Simple//data/", // up 1 in tree, "/0_Simple//" subdir "../1_Utilities//data/", // up 1 in tree, "/1_Utilities//" subdir "../2_Graphics//data/", // up 1 in tree, "/2_Graphics//" subdir "../3_Imaging//data/", // up 1 in tree, "/3_Imaging//" subdir "../4_Finance//data/", // up 1 in tree, "/4_Finance//" subdir "../5_Simulations//data/", // up 1 in tree, "/5_Simulations//" subdir "../6_Advanced//data/", // up 1 in tree, "/6_Advanced//" subdir "../7_CUDALibraries//data/",// up 1 in tree, "/7_CUDALibraries//" subdir "../8_Android//data/", // up 1 in tree, "/8_Android//" subdir "../samples//data/", // up 1 in tree, "/samples//" subdir "../../", // up 2 in tree "../../common/", // up 2 in tree, "/common/" subdir "../../common/data/", // up 2 in tree, "/common/data/" subdir "../../data/", // up 2 in tree, "/data/" subdir "../../src/", // up 2 in tree, "/src/" subdir "../../inc/", // up 2 in tree, "/inc/" subdir "../../sandbox//data/", // up 2 in tree, "/sandbox//" subdir "../../0_Simple//data/", // up 2 in tree, "/0_Simple//" subdir "../../1_Utilities//data/", // up 2 in tree, "/1_Utilities//" subdir "../../2_Graphics//data/", // up 2 in tree, "/2_Graphics//" subdir "../../3_Imaging//data/", // up 2 in tree, "/3_Imaging//" subdir "../../4_Finance//data/", // up 2 in tree, "/4_Finance//" subdir "../../5_Simulations//data/", // up 2 in tree, "/5_Simulations//" subdir "../../6_Advanced//data/", // up 2 in tree, "/6_Advanced//" subdir "../../7_CUDALibraries//data/", // up 2 in tree, "/7_CUDALibraries//" subdir "../../8_Android//data/", // up 2 in tree, "/8_Android//" subdir "../../samples//data/", // up 2 in tree, "/samples//" subdir "../../../", // up 3 in tree "../../../src//", // up 3 in tree, "/src//" subdir "../../../src//data/", // up 3 in tree, "/src//data/" subdir "../../../src//src/", // up 3 in tree, "/src//src/" subdir "../../../src//inc/", // up 3 in tree, "/src//inc/" subdir "../../../sandbox//", // up 3 in tree, "/sandbox//" subdir "../../../sandbox//data/", // up 3 in tree, "/sandbox//data/" subdir "../../../sandbox//src/", // up 3 in tree, "/sandbox//src/" subdir "../../../sandbox//inc/", // up 3 in tree, "/sandbox//inc/" subdir "../../../0_Simple//data/", // up 3 in tree, "/0_Simple//" subdir "../../../1_Utilities//data/", // up 3 in tree, "/1_Utilities//" subdir "../../../2_Graphics//data/", // up 3 in tree, "/2_Graphics//" subdir "../../../3_Imaging//data/", // up 3 in tree, "/3_Imaging//" subdir "../../../4_Finance//data/", // up 3 in tree, "/4_Finance//" subdir "../../../5_Simulations//data/", // up 3 in tree, "/5_Simulations//" subdir "../../../6_Advanced//data/", // up 3 in tree, "/6_Advanced//" subdir "../../../7_CUDALibraries//data/", // up 3 in tree, "/7_CUDALibraries//" subdir "../../../8_Android//data/", // up 3 in tree, "/8_Android//" subdir "../../../0_Simple//", // up 3 in tree, "/0_Simple//" subdir "../../../1_Utilities//", // up 3 in tree, "/1_Utilities//" subdir "../../../2_Graphics//", // up 3 in tree, "/2_Graphics//" subdir "../../../3_Imaging//", // up 3 in tree, "/3_Imaging//" subdir "../../../4_Finance//", // up 3 in tree, "/4_Finance//" subdir "../../../5_Simulations//", // up 3 in tree, "/5_Simulations//" subdir "../../../6_Advanced//", // up 3 in tree, "/6_Advanced//" subdir "../../../7_CUDALibraries//", // up 3 in tree, "/7_CUDALibraries//" subdir "../../../8_Android//", // up 3 in tree, "/8_Android//" subdir "../../../samples//data/", // up 3 in tree, "/samples//" subdir "../../../common/", // up 3 in tree, "../../../common/" subdir "../../../common/data/", // up 3 in tree, "../../../common/data/" subdir "../../../data/", // up 3 in tree, "../../../data/" subdir "../../../../", // up 4 in tree "../../../../src//", // up 4 in tree, "/src//" subdir "../../../../src//data/", // up 4 in tree, "/src//data/" subdir "../../../../src//src/", // up 4 in tree, "/src//src/" subdir "../../../../src//inc/", // up 4 in tree, "/src//inc/" subdir "../../../../sandbox//", // up 4 in tree, "/sandbox//" subdir "../../../../sandbox//data/", // up 4 in tree, "/sandbox//data/" subdir "../../../../sandbox//src/", // up 4 in tree, "/sandbox//src/" subdir "../../../../sandbox//inc/", // up 4 in tree, "/sandbox//inc/" subdir "../../../../0_Simple//data/", // up 4 in tree, "/0_Simple//" subdir "../../../../1_Utilities//data/", // up 4 in tree, "/1_Utilities//" subdir "../../../../2_Graphics//data/", // up 4 in tree, "/2_Graphics//" subdir "../../../../3_Imaging//data/", // up 4 in tree, "/3_Imaging//" subdir "../../../../4_Finance//data/", // up 4 in tree, "/4_Finance//" subdir "../../../../5_Simulations//data/",// up 4 in tree, "/5_Simulations//" subdir "../../../../6_Advanced//data/", // up 4 in tree, "/6_Advanced//" subdir "../../../../7_CUDALibraries//data/", // up 4 in tree, "/7_CUDALibraries//" subdir "../../../../8_Android//data/", // up 4 in tree, "/8_Android//" subdir "../../../../0_Simple//", // up 4 in tree, "/0_Simple//" subdir "../../../../1_Utilities//", // up 4 in tree, "/1_Utilities//" subdir "../../../../2_Graphics//", // up 4 in tree, "/2_Graphics//" subdir "../../../../3_Imaging//", // up 4 in tree, "/3_Imaging//" subdir "../../../../4_Finance//", // up 4 in tree, "/4_Finance//" subdir "../../../../5_Simulations//",// up 4 in tree, "/5_Simulations//" subdir "../../../../6_Advanced//", // up 4 in tree, "/6_Advanced//" subdir "../../../../7_CUDALibraries//", // up 4 in tree, "/7_CUDALibraries//" subdir "../../../../8_Android//", // up 4 in tree, "/8_Android//" subdir "../../../../samples//data/", // up 4 in tree, "/samples//" subdir "../../../../common/", // up 4 in tree, "../../../common/" subdir "../../../../common/data/", // up 4 in tree, "../../../common/data/" subdir "../../../../data/", // up 4 in tree, "../../../data/" subdir "../../../../../", // up 5 in tree "../../../../../src//", // up 5 in tree, "/src//" subdir "../../../../../src//data/", // up 5 in tree, "/src//data/" subdir "../../../../../src//src/", // up 5 in tree, "/src//src/" subdir "../../../../../src//inc/", // up 5 in tree, "/src//inc/" subdir "../../../../../sandbox//", // up 5 in tree, "/sandbox//" subdir "../../../../../sandbox//data/", // up 5 in tree, "/sandbox//data/" subdir "../../../../../sandbox//src/", // up 5 in tree, "/sandbox//src/" subdir "../../../../../sandbox//inc/", // up 5 in tree, "/sandbox//inc/" subdir "../../../../../0_Simple//data/", // up 5 in tree, "/0_Simple//" subdir "../../../../../1_Utilities//data/", // up 5 in tree, "/1_Utilities//" subdir "../../../../../2_Graphics//data/", // up 5 in tree, "/2_Graphics//" subdir "../../../../../3_Imaging//data/", // up 5 in tree, "/3_Imaging//" subdir "../../../../../4_Finance//data/", // up 5 in tree, "/4_Finance//" subdir "../../../../../5_Simulations//data/",// up 5 in tree, "/5_Simulations//" subdir "../../../../../6_Advanced//data/", // up 5 in tree, "/6_Advanced//" subdir "../../../../../7_CUDALibraries//data/", // up 5 in tree, "/7_CUDALibraries//" subdir "../../../../../8_Android//data/", // up 5 in tree, "/8_Android//" subdir "../../../../../samples//data/", // up 5 in tree, "/samples//" subdir "../../../../../common/", // up 5 in tree, "../../../common/" subdir "../../../../../common/data/", // up 5 in tree, "../../../common/data/" subdir }; // Extract the executable name std::string executable_name; if (executable_path != 0) { executable_name = std::string(executable_path); #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) // Windows path delimiter size_t delimiter_pos = executable_name.find_last_of('\\'); executable_name.erase(0, delimiter_pos + 1); if (executable_name.rfind(".exe") != std::string::npos) { // we strip .exe, only if the .exe is found executable_name.resize(executable_name.size() - 4); } #else // Linux & OSX path delimiter size_t delimiter_pos = executable_name.find_last_of('/'); executable_name.erase(0,delimiter_pos+1); #endif } // Loop over all search paths and return the first hit for (unsigned int i = 0; i < sizeof(searchPath)/sizeof(char *); ++i) { std::string path(searchPath[i]); size_t executable_name_pos = path.find(""); // If there is executable_name variable in the searchPath // replace it with the value if (executable_name_pos != std::string::npos) { if (executable_path != 0) { path.replace(executable_name_pos, strlen(""), executable_name); } else { // Skip this path entry if no executable argument is given continue; } } #ifdef _DEBUG printf("sdkFindFilePath <%s> in %s\n", filename, path.c_str()); #endif // Test if the file exists path.append(filename); FILE *fp; FOPEN(fp, path.c_str(), "rb"); if (fp != NULL) { fclose(fp); // File found // returning an allocated array here for backwards compatibility reasons char *file_path = (char *) malloc(path.length() + 1); STRCPY(file_path, path.length() + 1, path.c_str()); return file_path; } if (fp) { fclose(fp); } } // File not found return 0; } #endif ================================================ FILE: tests/projects/cuda/console/inc/helper_timer.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // Helper Timing Functions #ifndef HELPER_TIMER_H #define HELPER_TIMER_H #ifndef EXIT_WAIVED #define EXIT_WAIVED 2 #endif // includes, system #include // includes, project #include // Definition of the StopWatch Interface, this is used if we don't want to use the CUT functions // But rather in a self contained class interface class StopWatchInterface { public: StopWatchInterface() {}; virtual ~StopWatchInterface() {}; public: //! Start time measurement virtual void start() = 0; //! Stop time measurement virtual void stop() = 0; //! Reset time counters to zero virtual void reset() = 0; //! Time in msec. after start. If the stop watch is still running (i.e. there //! was no call to stop()) then the elapsed time is returned, otherwise the //! time between the last start() and stop call is returned virtual float getTime() = 0; //! Mean time to date based on the number of times the stopwatch has been //! _stopped_ (ie finished sessions) and the current total time virtual float getAverageTime() = 0; }; ////////////////////////////////////////////////////////////////// // Begin Stopwatch timer class definitions for all OS platforms // ////////////////////////////////////////////////////////////////// #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) // includes, system #define WINDOWS_LEAN_AND_MEAN #include #undef min #undef max //! Windows specific implementation of StopWatch class StopWatchWin : public StopWatchInterface { public: //! Constructor, default StopWatchWin() : start_time(), end_time(), diff_time(0.0f), total_time(0.0f), running(false), clock_sessions(0), freq(0), freq_set(false) { if (! freq_set) { // helper variable LARGE_INTEGER temp; // get the tick frequency from the OS QueryPerformanceFrequency((LARGE_INTEGER *) &temp); // convert to type in which it is needed freq = ((double) temp.QuadPart) / 1000.0; // rememeber query freq_set = true; } }; // Destructor ~StopWatchWin() { }; public: //! Start time measurement inline void start(); //! Stop time measurement inline void stop(); //! Reset time counters to zero inline void reset(); //! Time in msec. after start. If the stop watch is still running (i.e. there //! was no call to stop()) then the elapsed time is returned, otherwise the //! time between the last start() and stop call is returned inline float getTime(); //! Mean time to date based on the number of times the stopwatch has been //! _stopped_ (ie finished sessions) and the current total time inline float getAverageTime(); private: // member variables //! Start of measurement LARGE_INTEGER start_time; //! End of measurement LARGE_INTEGER end_time; //! Time difference between the last start and stop float diff_time; //! TOTAL time difference between starts and stops float total_time; //! flag if the stop watch is running bool running; //! Number of times clock has been started //! and stopped to allow averaging int clock_sessions; //! tick frequency double freq; //! flag if the frequency has been set bool freq_set; }; // functions, inlined //////////////////////////////////////////////////////////////////////////////// //! Start time measurement //////////////////////////////////////////////////////////////////////////////// inline void StopWatchWin::start() { QueryPerformanceCounter((LARGE_INTEGER *) &start_time); running = true; } //////////////////////////////////////////////////////////////////////////////// //! Stop time measurement and increment add to the current diff_time summation //! variable. Also increment the number of times this clock has been run. //////////////////////////////////////////////////////////////////////////////// inline void StopWatchWin::stop() { QueryPerformanceCounter((LARGE_INTEGER *) &end_time); diff_time = (float) (((double) end_time.QuadPart - (double) start_time.QuadPart) / freq); total_time += diff_time; clock_sessions++; running = false; } //////////////////////////////////////////////////////////////////////////////// //! Reset the timer to 0. Does not change the timer running state but does //! recapture this point in time as the current start time if it is running. //////////////////////////////////////////////////////////////////////////////// inline void StopWatchWin::reset() { diff_time = 0; total_time = 0; clock_sessions = 0; if (running) { QueryPerformanceCounter((LARGE_INTEGER *) &start_time); } } //////////////////////////////////////////////////////////////////////////////// //! Time in msec. after start. If the stop watch is still running (i.e. there //! was no call to stop()) then the elapsed time is returned added to the //! current diff_time sum, otherwise the current summed time difference alone //! is returned. //////////////////////////////////////////////////////////////////////////////// inline float StopWatchWin::getTime() { // Return the TOTAL time to date float retval = total_time; if (running) { LARGE_INTEGER temp; QueryPerformanceCounter((LARGE_INTEGER *) &temp); retval += (float) (((double)(temp.QuadPart - start_time.QuadPart)) / freq); } return retval; } //////////////////////////////////////////////////////////////////////////////// //! Time in msec. for a single run based on the total number of COMPLETED runs //! and the total time. //////////////////////////////////////////////////////////////////////////////// inline float StopWatchWin::getAverageTime() { return (clock_sessions > 0) ? (total_time/clock_sessions) : 0.0f; } #else // Declarations for Stopwatch on Linux and Mac OSX // includes, system #include #include //! Windows specific implementation of StopWatch class StopWatchLinux : public StopWatchInterface { public: //! Constructor, default StopWatchLinux() : start_time(), diff_time(0.0), total_time(0.0), running(false), clock_sessions(0) { }; // Destructor virtual ~StopWatchLinux() { }; public: //! Start time measurement inline void start(); //! Stop time measurement inline void stop(); //! Reset time counters to zero inline void reset(); //! Time in msec. after start. If the stop watch is still running (i.e. there //! was no call to stop()) then the elapsed time is returned, otherwise the //! time between the last start() and stop call is returned inline float getTime(); //! Mean time to date based on the number of times the stopwatch has been //! _stopped_ (ie finished sessions) and the current total time inline float getAverageTime(); private: // helper functions //! Get difference between start time and current time inline float getDiffTime(); private: // member variables //! Start of measurement struct timeval start_time; //! Time difference between the last start and stop float diff_time; //! TOTAL time difference between starts and stops float total_time; //! flag if the stop watch is running bool running; //! Number of times clock has been started //! and stopped to allow averaging int clock_sessions; }; // functions, inlined //////////////////////////////////////////////////////////////////////////////// //! Start time measurement //////////////////////////////////////////////////////////////////////////////// inline void StopWatchLinux::start() { gettimeofday(&start_time, 0); running = true; } //////////////////////////////////////////////////////////////////////////////// //! Stop time measurement and increment add to the current diff_time summation //! variable. Also increment the number of times this clock has been run. //////////////////////////////////////////////////////////////////////////////// inline void StopWatchLinux::stop() { diff_time = getDiffTime(); total_time += diff_time; running = false; clock_sessions++; } //////////////////////////////////////////////////////////////////////////////// //! Reset the timer to 0. Does not change the timer running state but does //! recapture this point in time as the current start time if it is running. //////////////////////////////////////////////////////////////////////////////// inline void StopWatchLinux::reset() { diff_time = 0; total_time = 0; clock_sessions = 0; if (running) { gettimeofday(&start_time, 0); } } //////////////////////////////////////////////////////////////////////////////// //! Time in msec. after start. If the stop watch is still running (i.e. there //! was no call to stop()) then the elapsed time is returned added to the //! current diff_time sum, otherwise the current summed time difference alone //! is returned. //////////////////////////////////////////////////////////////////////////////// inline float StopWatchLinux::getTime() { // Return the TOTAL time to date float retval = total_time; if (running) { retval += getDiffTime(); } return retval; } //////////////////////////////////////////////////////////////////////////////// //! Time in msec. for a single run based on the total number of COMPLETED runs //! and the total time. //////////////////////////////////////////////////////////////////////////////// inline float StopWatchLinux::getAverageTime() { return (clock_sessions > 0) ? (total_time/clock_sessions) : 0.0f; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// inline float StopWatchLinux::getDiffTime() { struct timeval t_time; gettimeofday(&t_time, 0); // time difference in milli-seconds return (float)(1000.0 * (t_time.tv_sec - start_time.tv_sec) + (0.001 * (t_time.tv_usec - start_time.tv_usec))); } #endif // WIN32 //////////////////////////////////////////////////////////////////////////////// //! Timer functionality exported //////////////////////////////////////////////////////////////////////////////// //! Create a new timer //! @return true if a time has been created, otherwise false //! @param name of the new timer, 0 if the creation failed //////////////////////////////////////////////////////////////////////////////// inline bool sdkCreateTimer(StopWatchInterface **timer_interface) { //printf("sdkCreateTimer called object %08x\n", (void *)*timer_interface); #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) *timer_interface = (StopWatchInterface *)new StopWatchWin(); #else *timer_interface = (StopWatchInterface *)new StopWatchLinux(); #endif return (*timer_interface != NULL) ? true : false; } //////////////////////////////////////////////////////////////////////////////// //! Delete a timer //! @return true if a time has been deleted, otherwise false //! @param name of the timer to delete //////////////////////////////////////////////////////////////////////////////// inline bool sdkDeleteTimer(StopWatchInterface **timer_interface) { //printf("sdkDeleteTimer called object %08x\n", (void *)*timer_interface); if (*timer_interface) { delete *timer_interface; *timer_interface = NULL; } return true; } //////////////////////////////////////////////////////////////////////////////// //! Start the time with name \a name //! @param name name of the timer to start //////////////////////////////////////////////////////////////////////////////// inline bool sdkStartTimer(StopWatchInterface **timer_interface) { //printf("sdkStartTimer called object %08x\n", (void *)*timer_interface); if (*timer_interface) { (*timer_interface)->start(); } return true; } //////////////////////////////////////////////////////////////////////////////// //! Stop the time with name \a name. Does not reset. //! @param name name of the timer to stop //////////////////////////////////////////////////////////////////////////////// inline bool sdkStopTimer(StopWatchInterface **timer_interface) { // printf("sdkStopTimer called object %08x\n", (void *)*timer_interface); if (*timer_interface) { (*timer_interface)->stop(); } return true; } //////////////////////////////////////////////////////////////////////////////// //! Resets the timer's counter. //! @param name name of the timer to reset. //////////////////////////////////////////////////////////////////////////////// inline bool sdkResetTimer(StopWatchInterface **timer_interface) { // printf("sdkResetTimer called object %08x\n", (void *)*timer_interface); if (*timer_interface) { (*timer_interface)->reset(); } return true; } //////////////////////////////////////////////////////////////////////////////// //! Return the average time for timer execution as the total time //! for the timer dividied by the number of completed (stopped) runs the timer //! has made. //! Excludes the current running time if the timer is currently running. //! @param name name of the timer to return the time of //////////////////////////////////////////////////////////////////////////////// inline float sdkGetAverageTimerValue(StopWatchInterface **timer_interface) { // printf("sdkGetAverageTimerValue called object %08x\n", (void *)*timer_interface); if (*timer_interface) { return (*timer_interface)->getAverageTime(); } else { return 0.0f; } } //////////////////////////////////////////////////////////////////////////////// //! Total execution time for the timer over all runs since the last reset //! or timer creation. //! @param name name of the timer to obtain the value of. //////////////////////////////////////////////////////////////////////////////// inline float sdkGetTimerValue(StopWatchInterface **timer_interface) { // printf("sdkGetTimerValue called object %08x\n", (void *)*timer_interface); if (*timer_interface) { return (*timer_interface)->getTime(); } else { return 0.0f; } } #endif // HELPER_TIMER_H ================================================ FILE: tests/projects/cuda/console/inc/multithreading.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef MULTITHREADING_H #define MULTITHREADING_H //Simple portable thread library. //Windows threads. #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #include typedef HANDLE CUTThread; typedef unsigned(WINAPI *CUT_THREADROUTINE)(void *); #define CUT_THREADPROC unsigned WINAPI #define CUT_THREADEND return 0 #else //POSIX threads. #include typedef pthread_t CUTThread; typedef void *(*CUT_THREADROUTINE)(void *); #define CUT_THREADPROC void #define CUT_THREADEND #endif #ifdef __cplusplus extern "C" { #endif //Create thread. CUTThread cutStartThread(CUT_THREADROUTINE, void *data); //Wait for thread to finish. void cutEndThread(CUTThread thread); //Destroy thread. void cutDestroyThread(CUTThread thread); //Wait for multiple threads. void cutWaitForThreads(const CUTThread *threads, int num); #ifdef __cplusplus } //extern "C" #endif #endif //MULTITHREADING_H ================================================ FILE: tests/projects/cuda/console/inc/nvMath.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // // Template math library for common 3D functionality // // This code is in part deriver from glh, a cross platform glut helper library. // The copyright for glh follows this notice. // // Copyright (c) NVIDIA Corporation. All rights reserved. //////////////////////////////////////////////////////////////////////////////// /* Copyright (c) 2000 Cass Everitt Copyright (c) 2000 NVIDIA Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of contributors to this software may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Cass Everitt - cass@r3.nu */ #ifndef NV_MATH_H #define NV_MATH_H #include #include #include #include #define NV_PI float(3.1415926535897932384626433832795) namespace nv { typedef vec2 vec2f; typedef vec3 vec3f; typedef vec3 vec3i; typedef vec3 vec3ui; typedef vec4 vec4f; typedef matrix4 matrix4f; typedef quaternion quaternionf; inline void applyRotation(const quaternionf &r) { float angle; vec3f axis; r.get_value(axis, angle); glRotatef(angle/3.1415926f * 180.0f, axis[0], axis[1], axis[2]); } }; #endif ================================================ FILE: tests/projects/cuda/console/inc/nvMatrix.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // // Template math library for common 3D functionality // // nvMatrix.h - template matrix code // // This code is in part deriver from glh, a cross platform glut helper library. // The copyright for glh follows this notice. // // Copyright (c) NVIDIA Corporation. All rights reserved. //////////////////////////////////////////////////////////////////////////////// /* Copyright (c) 2000 Cass Everitt Copyright (c) 2000 NVIDIA Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of contributors to this software may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Cass Everitt - cass@r3.nu */ #ifndef NV_MATRIX_H #define NV_MATRIX_H namespace nv { template class vec2; template class vec3; template class vec4; //////////////////////////////////////////////////////////////////////////////// // // Matrix // //////////////////////////////////////////////////////////////////////////////// template class matrix4 { public: matrix4() { make_identity(); } matrix4(T t) { set_value(t); } matrix4(const T *m) { set_value(m); } matrix4(T a00, T a01, T a02, T a03, T a10, T a11, T a12, T a13, T a20, T a21, T a22, T a23, T a30, T a31, T a32, T a33) : _11(a00), _12(a01), _13(a02), _14(a03), _21(a10), _22(a11), _23(a12), _24(a13), _31(a20), _32(a21), _33(a22), _34(a23), _41(a30), _42(a31), _43(a32), _44(a33) {} void get_value(T *mp) const { int c = 0; for (int j=0; j < 4; j++) for (int i=0; i < 4; i++) { mp[c++] = element(i,j); } } const T *get_value() const { return _array; } void set_value(T *mp) { int c = 0; for (int j=0; j < 4; j++) for (int i=0; i < 4; i++) { element(i,j) = mp[c++]; } } void set_value(T r) { for (int i=0; i < 4; i++) for (int j=0; j < 4; j++) { element(i,j) = r; } } void make_identity() { element(0,0) = 1.0; element(0,1) = 0.0; element(0,2) = 0.0; element(0,3) = 0.0; element(1,0) = 0.0; element(1,1) = 1.0; element(1,2) = 0.0; element(1,3) = 0.0; element(2,0) = 0.0; element(2,1) = 0.0; element(2,2) = 1.0; element(2,3) = 0.0; element(3,0) = 0.0; element(3,1) = 0.0; element(3,2) = 0.0; element(3,3) = 1.0; } // set a uniform scale void set_scale(T s) { element(0,0) = s; element(1,1) = s; element(2,2) = s; } void set_scale(const vec3 &s) { for (int i = 0; i < 3; i++) { element(i,i) = s[i]; } } void set_translate(const vec3 &t) { for (int i = 0; i < 3; i++) { element(i,3) = t[i]; } } void set_row(int r, const vec4 &t) { for (int i = 0; i < 4; i++) { element(r,i) = t[i]; } } void set_column(int c, const vec4 &t) { for (int i = 0; i < 4; i++) { element(i,c) = t[i]; } } vec4 get_row(int r) const { vec4 v; for (int i = 0; i < 4; i++) { v[i] = element(r,i); } return v; } vec4 get_column(int c) const { vec4 v; for (int i = 0; i < 4; i++) { v[i] = element(i,c); } return v; } friend matrix4 inverse(const matrix4 &m) { matrix4 minv; T r1[8], r2[8], r3[8], r4[8]; T *s[4], *tmprow; s[0] = &r1[0]; s[1] = &r2[0]; s[2] = &r3[0]; s[3] = &r4[0]; register int i,j,p,jj; for (i=0; i<4; i++) { for (j=0; j<4; j++) { s[i][j] = m.element(i,j); if (i==j) { s[i][j+4] = 1.0; } else { s[i][j+4] = 0.0; } } } T scp[4]; for (i=0; i<4; i++) { scp[i] = T(fabs(s[i][0])); for (j=1; j<4; j++) if (T(fabs(s[i][j])) > scp[i]) { scp[i] = T(fabs(s[i][j])); } if (scp[i] == 0.0) { return minv; // singular matrix! } } int pivot_to; T scp_max; for (i=0; i<4; i++) { // select pivot row pivot_to = i; scp_max = T(fabs(s[i][i]/scp[i])); // find out which row should be on top for (p=i+1; p<4; p++) if (T(fabs(s[p][i]/scp[p])) > scp_max) { scp_max = T(fabs(s[p][i]/scp[p])); pivot_to = p; } // Pivot if necessary if (pivot_to != i) { tmprow = s[i]; s[i] = s[pivot_to]; s[pivot_to] = tmprow; T tmpscp; tmpscp = scp[i]; scp[i] = scp[pivot_to]; scp[pivot_to] = tmpscp; } T mji; // perform gaussian elimination for (j=i+1; j<4; j++) { mji = s[j][i]/s[i][i]; s[j][i] = 0.0; for (jj=i+1; jj<8; jj++) { s[j][jj] -= mji*s[i][jj]; } } } if (s[3][3] == 0.0) { return minv; // singular matrix! } // // Now we have an upper triangular matrix. // // x x x x | y y y y // 0 x x x | y y y y // 0 0 x x | y y y y // 0 0 0 x | y y y y // // we'll back substitute to get the inverse // // 1 0 0 0 | z z z z // 0 1 0 0 | z z z z // 0 0 1 0 | z z z z // 0 0 0 1 | z z z z // T mij; for (i=3; i>0; i--) { for (j=i-1; j > -1; j--) { mij = s[j][i]/s[i][i]; for (jj=j+1; jj<8; jj++) { s[j][jj] -= mij*s[i][jj]; } } } for (i=0; i<4; i++) for (j=0; j<4; j++) { minv(i,j) = s[i][j+4] / s[i][i]; } return minv; } friend matrix4 transpose(const matrix4 &m) { matrix4 mtrans; for (int i=0; i<4; i++) for (int j=0; j<4; j++) { mtrans(i,j) = m.element(j,i); } return mtrans; } matrix4 &operator *= (const matrix4 &rhs) { matrix4 mt(*this); set_value(T(0)); for (int i=0; i < 4; i++) for (int j=0; j < 4; j++) for (int c=0; c < 4; c++) { element(i,j) += mt(i,c) * rhs(c,j); } return *this; } friend matrix4 operator * (const matrix4 &lhs, const matrix4 &rhs) { matrix4 r(T(0)); for (int i=0; i < 4; i++) for (int j=0; j < 4; j++) for (int c=0; c < 4; c++) { r.element(i,j) += lhs(i,c) * rhs(c,j); } return r; } // dst = M * src vec4 operator *(const vec4 &src) const { vec4 r; for (int i = 0; i < 4; i++) r[i] = (src[0] * element(i,0) + src[1] * element(i,1) + src[2] * element(i,2) + src[3] * element(i,3)); return r; } // dst = src * M friend vec4 operator *(const vec4 &lhs, const matrix4 &rhs) { vec4 r; for (int i = 0; i < 4; i++) r[i] = (lhs[0] * rhs.element(0,i) + lhs[1] * rhs.element(1,i) + lhs[2] * rhs.element(2,i) + lhs[3] * rhs.element(3,i)); return r; } T &operator()(int row, int col) { return element(row,col); } const T &operator()(int row, int col) const { return element(row,col); } T &element(int row, int col) { return _array[row | (col<<2)]; } const T &element(int row, int col) const { return _array[row | (col<<2)]; } matrix4 &operator *= (const T &r) { for (int i = 0; i < 4; ++i) { element(0,i) *= r; element(1,i) *= r; element(2,i) *= r; element(3,i) *= r; } return *this; } matrix4 &operator += (const matrix4 &mat) { for (int i = 0; i < 4; ++i) { element(0,i) += mat.element(0,i); element(1,i) += mat.element(1,i); element(2,i) += mat.element(2,i); element(3,i) += mat.element(3,i); } return *this; } friend bool operator == (const matrix4 &lhs, const matrix4 &rhs) { bool r = true; for (int i = 0; i < 16; i++) { r &= lhs._array[i] == rhs._array[i]; } return r; } friend bool operator != (const matrix4 &lhs, const matrix4 &rhs) { bool r = true; for (int i = 0; i < 16; i++) { r &= lhs._array[i] != rhs._array[i]; } return r; } union { struct { T _11, _12, _13, _14; // standard names for components T _21, _22, _23, _24; // standard names for components T _31, _32, _33, _34; // standard names for components T _41, _42, _43, _44; // standard names for components }; T _array[16]; // array access }; }; }; #endif ================================================ FILE: tests/projects/cuda/console/inc/nvQuaternion.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // // Template math library for common 3D functionality // // nvQuaterion.h - quaternion template and utility functions // // This code is in part deriver from glh, a cross platform glut helper library. // The copyright for glh follows this notice. // // Copyright (c) NVIDIA Corporation. All rights reserved. //////////////////////////////////////////////////////////////////////////////// /* Copyright (c) 2000 Cass Everitt Copyright (c) 2000 NVIDIA Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of contributors to this software may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Cass Everitt - cass@r3.nu */ #ifndef NV_QUATERNION_H #define NV_QUATERNION_H namespace nv { template class vec2; template class vec3; template class vec4; //////////////////////////////////////////////////////////////////////////////// // // Quaternion // //////////////////////////////////////////////////////////////////////////////// template< class T> class quaternion { public: quaternion() : x(0.0), y(0.0), z(0.0), w(0.0) { } quaternion(const T v[4]) { set_value(v); } quaternion(T q0, T q1, T q2, T q3) { set_value(q0, q1, q2, q3); } quaternion(const matrix4 &m) { set_value(m); } quaternion(const vec3 &axis, T radians) { set_value(axis, radians); } quaternion(const vec3 &rotateFrom, const vec3 &rotateTo) { set_value(rotateFrom, rotateTo); } quaternion(const vec3 &from_look, const vec3 &from_up, const vec3 &to_look, const vec3 &to_up) { set_value(from_look, from_up, to_look, to_up); } const T *get_value() const { return &_array[0]; } void get_value(T &q0, T &q1, T &q2, T &q3) const { q0 = _array[0]; q1 = _array[1]; q2 = _array[2]; q3 = _array[3]; } quaternion &set_value(T q0, T q1, T q2, T q3) { _array[0] = q0; _array[1] = q1; _array[2] = q2; _array[3] = q3; return *this; } void get_value(vec3 &axis, T &radians) const { radians = T(acos(_array[3]) * T(2.0)); if (radians == T(0.0)) { axis = vec3(0.0, 0.0, 1.0); } else { axis[0] = _array[0]; axis[1] = _array[1]; axis[2] = _array[2]; axis = normalize(axis); } } void get_value(matrix4 &m) const { T s, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz; T norm = _array[0] * _array[0] + _array[1] * _array[1] + _array[2] * _array[2] + _array[3] * _array[3]; s = (norm == T(0.0)) ? T(0.0) : (T(2.0) / norm); xs = _array[0] * s; ys = _array[1] * s; zs = _array[2] * s; wx = _array[3] * xs; wy = _array[3] * ys; wz = _array[3] * zs; xx = _array[0] * xs; xy = _array[0] * ys; xz = _array[0] * zs; yy = _array[1] * ys; yz = _array[1] * zs; zz = _array[2] * zs; m(0,0) = T(T(1.0) - (yy + zz)); m(1,0) = T(xy + wz); m(2,0) = T(xz - wy); m(0,1) = T(xy - wz); m(1,1) = T(T(1.0) - (xx + zz)); m(2,1) = T(yz + wx); m(0,2) = T(xz + wy); m(1,2) = T(yz - wx); m(2,2) = T(T(1.0) - (xx + yy)); m(3,0) = m(3,1) = m(3,2) = m(0,3) = m(1,3) = m(2,3) = T(0.0); m(3,3) = T(1.0); } quaternion &set_value(const T *qp) { for (int i = 0; i < 4; i++) { _array[i] = qp[i]; } return *this; } quaternion &set_value(const matrix4 &m) { T tr, s; int i, j, k; const int nxt[3] = { 1, 2, 0 }; tr = m(0,0) + m(1,1) + m(2,2); if (tr > T(0)) { s = T(sqrt(tr + m(3,3))); _array[3] = T(s * 0.5); s = T(0.5) / s; _array[0] = T((m(1,2) - m(2,1)) * s); _array[1] = T((m(2,0) - m(0,2)) * s); _array[2] = T((m(0,1) - m(1,0)) * s); } else { i = 0; if (m(1,1) > m(0,0)) { i = 1; } if (m(2,2) > m(i,i)) { i = 2; } j = nxt[i]; k = nxt[j]; s = T(sqrt((m(i,j) - (m(j,j) + m(k,k))) + T(1.0))); _array[i] = T(s * 0.5); s = T(0.5 / s); _array[3] = T((m(j,k) - m(k,j)) * s); _array[j] = T((m(i,j) + m(j,i)) * s); _array[k] = T((m(i,k) + m(k,i)) * s); } return *this; } quaternion &set_value(const vec3 &axis, T theta) { T sqnorm = square_norm(axis); if (sqnorm == T(0.0)) { // axis too small. x = y = z = T(0.0); w = T(1.0); } else { theta *= T(0.5); T sin_theta = T(sin(theta)); if (sqnorm != T(1)) { sin_theta /= T(sqrt(sqnorm)); } x = sin_theta * axis[0]; y = sin_theta * axis[1]; z = sin_theta * axis[2]; w = T(cos(theta)); } return *this; } quaternion &set_value(const vec3 &rotateFrom, const vec3 &rotateTo) { vec3 p1, p2; T alpha; p1 = normalize(rotateFrom); p2 = normalize(rotateTo); alpha = dot(p1, p2); if (alpha == T(1.0)) { *this = quaternion(); return *this; } // ensures that the anti-parallel case leads to a positive dot if (alpha == T(-1.0)) { vec3 v; if (p1[0] != p1[1] || p1[0] != p1[2]) { v = vec3(p1[1], p1[2], p1[0]); } else { v = vec3(-p1[0], p1[1], p1[2]); } v -= p1 * dot(p1, v); v = normalize(v); set_value(v, T(3.1415926)); return *this; } p1 = normalize(cross(p1, p2)); set_value(p1,T(acos(alpha))); return *this; } quaternion &set_value(const vec3 &from_look, const vec3 &from_up, const vec3 &to_look, const vec3 &to_up) { quaternion r_look = quaternion(from_look, to_look); vec3 rotated_from_up(from_up); r_look.mult_vec(rotated_from_up); quaternion r_twist = quaternion(rotated_from_up, to_up); *this = r_twist; *this *= r_look; return *this; } quaternion &operator *= (const quaternion &qr) { quaternion ql(*this); w = ql.w * qr.w - ql.x * qr.x - ql.y * qr.y - ql.z * qr.z; x = ql.w * qr.x + ql.x * qr.w + ql.y * qr.z - ql.z * qr.y; y = ql.w * qr.y + ql.y * qr.w + ql.z * qr.x - ql.x * qr.z; z = ql.w * qr.z + ql.z * qr.w + ql.x * qr.y - ql.y * qr.x; return *this; } friend quaternion normalize(const quaternion &q) { quaternion r(q); T rnorm = T(1.0) / T(sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z)); r.x *= rnorm; r.y *= rnorm; r.z *= rnorm; r.w *= rnorm; } friend quaternion conjugate(const quaternion &q) { quaternion r(q); r._array[0] *= T(-1.0); r._array[1] *= T(-1.0); r._array[2] *= T(-1.0); return r; } friend quaternion inverse(const quaternion &q) { return conjugate(q); } // // Quaternion multiplication with cartesian vector // v' = q*v*q(star) // void mult_vec(const vec3 &src, vec3 &dst) const { T v_coef = w * w - x * x - y * y - z * z; T u_coef = T(2.0) * (src[0] * x + src[1] * y + src[2] * z); T c_coef = T(2.0) * w; dst.v[0] = v_coef * src.v[0] + u_coef * x + c_coef * (y * src.v[2] - z * src.v[1]); dst.v[1] = v_coef * src.v[1] + u_coef * y + c_coef * (z * src.v[0] - x * src.v[2]); dst.v[2] = v_coef * src.v[2] + u_coef * z + c_coef * (x * src.v[1] - y * src.v[0]); } void mult_vec(vec3 &src_and_dst) const { mult_vec(vec3(src_and_dst), src_and_dst); } void scale_angle(T scaleFactor) { vec3 axis; T radians; get_value(axis, radians); radians *= scaleFactor; set_value(axis, radians); } friend quaternion slerp(const quaternion &p, const quaternion &q, T alpha) { quaternion r; T cos_omega = p.x * q.x + p.y * q.y + p.z * q.z + p.w * q.w; // if B is on opposite hemisphere from A, use -B instead int bflip; if ((bflip = (cos_omega < T(0)))) { cos_omega = -cos_omega; } // complementary interpolation parameter T beta = T(1) - alpha; if (cos_omega >= T(1)) { return p; } T omega = T(acos(cos_omega)); T one_over_sin_omega = T(1.0) / T(sin(omega)); beta = T(sin(omega*beta) * one_over_sin_omega); alpha = T(sin(omega*alpha) * one_over_sin_omega); if (bflip) { alpha = -alpha; } r.x = beta * p._array[0]+ alpha * q._array[0]; r.y = beta * p._array[1]+ alpha * q._array[1]; r.z = beta * p._array[2]+ alpha * q._array[2]; r.w = beta * p._array[3]+ alpha * q._array[3]; return r; } T &operator [](int i) { return _array[i]; } const T &operator [](int i) const { return _array[i]; } friend bool operator == (const quaternion &lhs, const quaternion &rhs) { bool r = true; for (int i = 0; i < 4; i++) { r &= lhs._array[i] == rhs._array[i]; } return r; } friend bool operator != (const quaternion &lhs, const quaternion &rhs) { bool r = true; for (int i = 0; i < 4; i++) { r &= lhs._array[i] == rhs._array[i]; } return r; } friend quaternion operator * (const quaternion &lhs, const quaternion &rhs) { quaternion r(lhs); r *= rhs; return r; } union { struct { T x; T y; T z; T w; }; T _array[4]; }; }; }; #endif ================================================ FILE: tests/projects/cuda/console/inc/nvShaderUtils.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ /* * * Utility functions for compiling shaders and programs * * Author: Evan Hart * Copyright (c) NVIDIA Corporation. All rights reserved. * */ #ifndef NV_SHADER_UTILS_H #define NV_SHADER_UTILS_H #include #include namespace nv { // // //////////////////////////////////////////////////////////// inline GLuint CompileGLSLShader(GLenum target, const char *shader) { GLuint object; object = glCreateShader(target); if (!object) { return object; } glShaderSource(object, 1, &shader, NULL); glCompileShader(object); // check if shader compiled GLint compiled = 0; glGetShaderiv(object, GL_COMPILE_STATUS, &compiled); if (!compiled) { #ifdef NV_REPORT_COMPILE_ERRORS char temp[256] = ""; glGetShaderInfoLog(object, 256, NULL, temp); fprintf(stderr, "Compile failed:\n%s\n", temp); #endif glDeleteShader(object); return 0; } return object; } // // //////////////////////////////////////////////////////////// inline GLuint CompileGLSLShaderFromFile(GLenum target, const char *filename) { FILE *shaderFile; char *text; long size; size_t fsize = 0; // read files as binary to prevent problems from newline translation #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) if (fopen_s(&shaderFile, filename, "rb") != 0) #else if ((shaderFile = fopen(filename, "rb")) == 0) #endif { return 0; } // Get the length of the file fseek(shaderFile, 0, SEEK_END); size = ftell(shaderFile); // Read the file contents from the start, then close file and add a null terminator fseek(shaderFile, 0, SEEK_SET); text = new char[size+1]; fsize = fread(text, size, 1, shaderFile); fclose(shaderFile); if (fsize == 0) { printf("CompileGLSLShaderFromFile(), error... fsize = 0\n"); } text[size] = '\0'; GLuint object = CompileGLSLShader(target, text); delete []text; return object; } // Create a program composed of vertex and fragment shaders. inline GLuint LinkGLSLProgram(GLuint vertexShader, GLuint fragmentShader) { GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); glLinkProgram(program); #ifdef NV_REPORT_COMPILE_ERRORS // Get error log. GLint charsWritten, infoLogLength; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); char *infoLog = new char[infoLogLength]; glGetProgramInfoLog(program, infoLogLength, &charsWritten, infoLog); printf(infoLog); delete [] infoLog; #endif // Test linker result. GLint linkSucceed = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkSucceed); if (linkSucceed == GL_FALSE) { glDeleteProgram(program); return 0; } return program; } // Create a program composed of vertex, geometry and fragment shaders. inline GLuint LinkGLSLProgram(GLuint vertexShader, GLuint geometryShader, GLint inputType, GLint vertexOut, GLint outputType, GLuint fragmentShader) { GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, geometryShader); glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, inputType); glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, vertexOut); glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, outputType); glAttachShader(program, fragmentShader); glLinkProgram(program); #ifdef NV_REPORT_COMPILE_ERRORS // Get error log. GLint charsWritten, infoLogLength; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); char *infoLog = new char[infoLogLength]; glGetProgramInfoLog(program, infoLogLength, &charsWritten, infoLog); printf(infoLog); delete [] infoLog; #endif // Test linker result. GLint linkSucceed = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkSucceed); if (linkSucceed == GL_FALSE) { glDeleteProgram(program); return 0; } return program; } // // //////////////////////////////////////////////////////////// inline GLuint CompileASMShader(GLenum program_type, const char *code) { GLuint program_id; glGenProgramsARB(1, &program_id); glBindProgramARB(program_type, program_id); glProgramStringARB(program_type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei) strlen(code), (GLubyte *) code); GLint error_pos; glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); if (error_pos != -1) { #ifdef NV_REPORT_COMPILE_ERRORS const GLubyte *error_string; error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB); fprintf(stderr, "Program error at position: %d\n%s\n", (int)error_pos, error_string); #endif return 0; } return program_id; } // // //////////////////////////////////////////////////////////// inline GLuint CompileASMShaderFromFile(GLenum target, const char *filename) { FILE *shaderFile; char *text; long size; size_t fsize = 0; // read files as binary to prevent problems from newline translation #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) if (fopen_s(&shaderFile, filename, "rb") != 0) #else if ((shaderFile = fopen(filename, "rb")) == 0) #endif { return 0; } // Get the length of the file fseek(shaderFile, 0, SEEK_END); size = ftell(shaderFile); // Read the file contents from the start, then close file and add a null terminator fseek(shaderFile, 0, SEEK_SET); text = new char[size+1]; fsize = fread(text, size, 1, shaderFile); fclose(shaderFile); if (fsize == 0) { printf("CompileGLSLShaderFromFile(), error... fsize = 0\n"); } text[size] = '\0'; GLuint program_id = CompileASMShader(target, text); delete []text; return program_id; } } // nv namespace #endif ================================================ FILE: tests/projects/cuda/console/inc/nvVector.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // // Template math library for common 3D functionality // // nvVector.h - 2-vector, 3-vector, and 4-vector templates and utilities // // This code is in part deriver from glh, a cross platform glut helper library. // The copyright for glh follows this notice. // // Copyright (c) NVIDIA Corporation. All rights reserved. //////////////////////////////////////////////////////////////////////////////// /* Copyright (c) 2000 Cass Everitt Copyright (c) 2000 NVIDIA Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of contributors to this software may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Cass Everitt - cass@r3.nu */ #ifndef NV_VECTOR_H #define NV_VECTOR_H namespace nv { template class vec2; template class vec3; template class vec4; ////////////////////////////////////////////////////////////////////// // // vec2 - template class for 2-tuple vector // ////////////////////////////////////////////////////////////////////// template class vec2 { public: typedef T value_type; int size() const { return 2; } //////////////////////////////////////////////////////// // // Constructors // //////////////////////////////////////////////////////// // Default/scalar constructor vec2(const T &t = T()) { for (int i = 0; i < size(); i++) { _array[i] = t; } } // Construct from array vec2(const T *tp) { for (int i = 0; i < size(); i++) { _array[i] = tp[i]; } } // Construct from explicit values vec2(const T v0, const T v1) { x = v0; y = v1; } explicit vec2(const vec3 &u) { for (int i = 0; i < size(); i++) { _array[i] = u._array[i]; } } explicit vec2(const vec4 &u) { for (int i = 0; i < size(); i++) { _array[i] = u._array[i]; } } const T *get_value() const { return _array; } vec2 &set_value(const T *rhs) { for (int i = 0; i < size(); i++) { _array[i] = rhs[i]; } return *this; } // indexing operators T &operator [](int i) { return _array[i]; } const T &operator [](int i) const { return _array[i]; } // type-cast operators operator T *() { return _array; } operator const T *() const { return _array; } //////////////////////////////////////////////////////// // // Math operators // //////////////////////////////////////////////////////// // scalar multiply assign friend vec2 &operator *= (vec2 &lhs, T d) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] *= d; } return lhs; } // component-wise vector multiply assign friend vec2 &operator *= (vec2 &lhs, const vec2 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] *= rhs[i]; } return lhs; } // scalar divide assign friend vec2 &operator /= (vec2 &lhs, T d) { if (d == 0) { return lhs; } for (int i = 0; i < lhs.size(); i++) { lhs._array[i] /= d; } return lhs; } // component-wise vector divide assign friend vec2 &operator /= (vec2 &lhs, const vec2 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] /= rhs._array[i]; } return lhs; } // component-wise vector add assign friend vec2 &operator += (vec2 &lhs, const vec2 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] += rhs._array[i]; } return lhs; } // component-wise vector subtract assign friend vec2 &operator -= (vec2 &lhs, const vec2 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] -= rhs._array[i]; } return lhs; } // unary negate friend vec2 operator - (const vec2 &rhs) { vec2 rv; for (int i = 0; i < rhs.size(); i++) { rv._array[i] = -rhs._array[i]; } return rv; } // vector add friend vec2 operator + (const vec2 &lhs, const vec2 &rhs) { vec2 rt(lhs); return rt += rhs; } // vector subtract friend vec2 operator - (const vec2 &lhs, const vec2 &rhs) { vec2 rt(lhs); return rt -= rhs; } // scalar multiply friend vec2 operator * (const vec2 &lhs, T rhs) { vec2 rt(lhs); return rt *= rhs; } // scalar multiply friend vec2 operator * (T lhs, const vec2 &rhs) { vec2 rt(lhs); return rt *= rhs; } // vector component-wise multiply friend vec2 operator * (const vec2 &lhs, const vec2 &rhs) { vec2 rt(lhs); return rt *= rhs; } // scalar multiply friend vec2 operator / (const vec2 &lhs, T rhs) { vec2 rt(lhs); return rt /= rhs; } // vector component-wise multiply friend vec2 operator / (const vec2 &lhs, const vec2 &rhs) { vec2 rt(lhs); return rt /= rhs; } //////////////////////////////////////////////////////// // // Comparison operators // //////////////////////////////////////////////////////// // equality friend bool operator == (const vec2 &lhs, const vec2 &rhs) { bool r = true; for (int i = 0; i < lhs.size(); i++) { r &= lhs._array[i] == rhs._array[i]; } return r; } // inequality friend bool operator != (const vec2 &lhs, const vec2 &rhs) { bool r = true; for (int i = 0; i < lhs.size(); i++) { r &= lhs._array[i] != rhs._array[i]; } return r; } //data intentionally left public to allow vec2.x union { struct { T x,y; // standard names for components }; struct { T s,t; // standard names for components }; T _array[2]; // array access }; }; ////////////////////////////////////////////////////////////////////// // // vec3 - template class for 3-tuple vector // ////////////////////////////////////////////////////////////////////// template class vec3 { public: typedef T value_type; int size() const { return 3; } //////////////////////////////////////////////////////// // // Constructors // //////////////////////////////////////////////////////// // Default/scalar constructor vec3(const T &t = T()) { for (int i = 0; i < size(); i++) { _array[i] = t; } } // Construct from array vec3(const T *tp) { for (int i = 0; i < size(); i++) { _array[i] = tp[i]; } } // Construct from explicit values vec3(const T v0, const T v1, const T v2) { x = v0; y = v1; z = v2; } explicit vec3(const vec4 &u) { for (int i = 0; i < size(); i++) { _array[i] = u._array[i]; } } explicit vec3(const vec2 &u, T v0) { x = u.x; y = u.y; z = v0; } const T *get_value() const { return _array; } vec3 &set_value(const T *rhs) { for (int i = 0; i < size(); i++) { _array[i] = rhs[i]; } return *this; } // indexing operators T &operator [](int i) { return _array[i]; } const T &operator [](int i) const { return _array[i]; } // type-cast operators operator T *() { return _array; } operator const T *() const { return _array; } //////////////////////////////////////////////////////// // // Math operators // //////////////////////////////////////////////////////// // scalar multiply assign friend vec3 &operator *= (vec3 &lhs, T d) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] *= d; } return lhs; } // component-wise vector multiply assign friend vec3 &operator *= (vec3 &lhs, const vec3 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] *= rhs[i]; } return lhs; } // scalar divide assign friend vec3 &operator /= (vec3 &lhs, T d) { if (d == 0) { return lhs; } for (int i = 0; i < lhs.size(); i++) { lhs._array[i] /= d; } return lhs; } // component-wise vector divide assign friend vec3 &operator /= (vec3 &lhs, const vec3 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] /= rhs._array[i]; } return lhs; } // component-wise vector add assign friend vec3 &operator += (vec3 &lhs, const vec3 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] += rhs._array[i]; } return lhs; } // component-wise vector subtract assign friend vec3 &operator -= (vec3 &lhs, const vec3 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] -= rhs._array[i]; } return lhs; } // unary negate friend vec3 operator - (const vec3 &rhs) { vec3 rv; for (int i = 0; i < rhs.size(); i++) { rv._array[i] = -rhs._array[i]; } return rv; } // vector add friend vec3 operator + (const vec3 &lhs, const vec3 &rhs) { vec3 rt(lhs); return rt += rhs; } // vector subtract friend vec3 operator - (const vec3 &lhs, const vec3 &rhs) { vec3 rt(lhs); return rt -= rhs; } // scalar multiply friend vec3 operator * (const vec3 &lhs, T rhs) { vec3 rt(lhs); return rt *= rhs; } // scalar multiply friend vec3 operator * (T lhs, const vec3 &rhs) { vec3 rt(lhs); return rt *= rhs; } // vector component-wise multiply friend vec3 operator * (const vec3 &lhs, const vec3 &rhs) { vec3 rt(lhs); return rt *= rhs; } // scalar multiply friend vec3 operator / (const vec3 &lhs, T rhs) { vec3 rt(lhs); return rt /= rhs; } // vector component-wise multiply friend vec3 operator / (const vec3 &lhs, const vec3 &rhs) { vec3 rt(lhs); return rt /= rhs; } //////////////////////////////////////////////////////// // // Comparison operators // //////////////////////////////////////////////////////// // equality friend bool operator == (const vec3 &lhs, const vec3 &rhs) { bool r = true; for (int i = 0; i < lhs.size(); i++) { r &= lhs._array[i] == rhs._array[i]; } return r; } // inequality friend bool operator != (const vec3 &lhs, const vec3 &rhs) { bool r = true; for (int i = 0; i < lhs.size(); i++) { r &= lhs._array[i] != rhs._array[i]; } return r; } //////////////////////////////////////////////////////////////////////////////// // // dimension specific operations // //////////////////////////////////////////////////////////////////////////////// // cross product friend vec3 cross(const vec3 &lhs, const vec3 &rhs) { vec3 r; r.x = lhs.y * rhs.z - lhs.z * rhs.y; r.y = lhs.z * rhs.x - lhs.x * rhs.z; r.z = lhs.x * rhs.y - lhs.y * rhs.x; return r; } //data intentionally left public to allow vec2.x union { struct { T x, y, z; // standard names for components }; struct { T s, t, r; // standard names for components }; T _array[3]; // array access }; }; ////////////////////////////////////////////////////////////////////// // // vec4 - template class for 4-tuple vector // ////////////////////////////////////////////////////////////////////// template class vec4 { public: typedef T value_type; int size() const { return 4; } //////////////////////////////////////////////////////// // // Constructors // //////////////////////////////////////////////////////// // Default/scalar constructor vec4(const T &t = T()) { for (int i = 0; i < size(); i++) { _array[i] = t; } } // Construct from array vec4(const T *tp) { for (int i = 0; i < size(); i++) { _array[i] = tp[i]; } } // Construct from explicit values vec4(const T v0, const T v1, const T v2, const T v3) { x = v0; y = v1; z = v2; w = v3; } explicit vec4(const vec3 &u, T v0) { x = u.x; y = u.y; z = u.z; w = v0; } explicit vec4(const vec2 &u, T v0, T v1) { x = u.x; y = u.y; z = v0; w = v1; } const T *get_value() const { return _array; } vec4 &set_value(const T *rhs) { for (int i = 0; i < size(); i++) { _array[i] = rhs[i]; } return *this; } // indexing operators T &operator [](int i) { return _array[i]; } const T &operator [](int i) const { return _array[i]; } // type-cast operators operator T *() { return _array; } operator const T *() const { return _array; } //////////////////////////////////////////////////////// // // Math operators // //////////////////////////////////////////////////////// // scalar multiply assign friend vec4 &operator *= (vec4 &lhs, T d) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] *= d; } return lhs; } // component-wise vector multiply assign friend vec4 &operator *= (vec4 &lhs, const vec4 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] *= rhs[i]; } return lhs; } // scalar divide assign friend vec4 &operator /= (vec4 &lhs, T d) { if (d == 0) { return lhs; } for (int i = 0; i < lhs.size(); i++) { lhs._array[i] /= d; } return lhs; } // component-wise vector divide assign friend vec4 &operator /= (vec4 &lhs, const vec4 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] /= rhs._array[i]; } return lhs; } // component-wise vector add assign friend vec4 &operator += (vec4 &lhs, const vec4 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] += rhs._array[i]; } return lhs; } // component-wise vector subtract assign friend vec4 &operator -= (vec4 &lhs, const vec4 &rhs) { for (int i = 0; i < lhs.size(); i++) { lhs._array[i] -= rhs._array[i]; } return lhs; } // unary negate friend vec4 operator - (const vec4 &rhs) { vec4 rv; for (int i = 0; i < rhs.size(); i++) { rv._array[i] = -rhs._array[i]; } return rv; } // vector add friend vec4 operator + (const vec4 &lhs, const vec4 &rhs) { vec4 rt(lhs); return rt += rhs; } // vector subtract friend vec4 operator - (const vec4 &lhs, const vec4 &rhs) { vec4 rt(lhs); return rt -= rhs; } // scalar multiply friend vec4 operator * (const vec4 &lhs, T rhs) { vec4 rt(lhs); return rt *= rhs; } // scalar multiply friend vec4 operator * (T lhs, const vec4 &rhs) { vec4 rt(lhs); return rt *= rhs; } // vector component-wise multiply friend vec4 operator * (const vec4 &lhs, const vec4 &rhs) { vec4 rt(lhs); return rt *= rhs; } // scalar multiply friend vec4 operator / (const vec4 &lhs, T rhs) { vec4 rt(lhs); return rt /= rhs; } // vector component-wise multiply friend vec4 operator / (const vec4 &lhs, const vec4 &rhs) { vec4 rt(lhs); return rt /= rhs; } //////////////////////////////////////////////////////// // // Comparison operators // //////////////////////////////////////////////////////// // equality friend bool operator == (const vec4 &lhs, const vec4 &rhs) { bool r = true; for (int i = 0; i < lhs.size(); i++) { r &= lhs._array[i] == rhs._array[i]; } return r; } // inequality friend bool operator != (const vec4 &lhs, const vec4 &rhs) { bool r = true; for (int i = 0; i < lhs.size(); i++) { r &= lhs._array[i] != rhs._array[i]; } return r; } //data intentionally left public to allow vec2.x union { struct { T x, y, z, w; // standard names for components }; struct { T s, t, r, q; // standard names for components }; T _array[4]; // array access }; }; //////////////////////////////////////////////////////////////////////////////// // // Generic vector operations // //////////////////////////////////////////////////////////////////////////////// // compute the dot product of two vectors template inline typename T::value_type dot(const T &lhs, const T &rhs) { typename T::value_type r = 0; for (int i = 0; i < lhs.size(); i++) { r += lhs._array[i] * rhs._array[i]; } return r; } // return the length of the provided vector template< class T> inline typename T::value_type length(const T &vec) { typename T::value_type r = 0; for (int i = 0; i < vec.size(); i++) { r += vec._array[i]*vec._array[i]; } return typename T::value_type(sqrt(r)); } // return the squared norm template< class T> inline typename T::value_type square_norm(const T &vec) { typename T::value_type r = 0; for (int i = 0; i < vec.size(); i++) { r += vec._array[i]*vec._array[i]; } return r; } // return the normalized version of the vector template< class T> inline T normalize(const T &vec) { typename T::value_type sum(0); T r; for (int i = 0; i < vec.size(); i++) { sum += vec._array[i] * vec._array[i]; } sum = typename T::value_type(sqrt(sum)); if (sum > 0) for (int i = 0; i < vec.size(); i++) { r._array[i] = vec._array[i] / sum; } return r; } // In VC8 : min and max are already defined by a #define... #ifdef min #undef min #endif #ifdef max #undef max #endif //componentwise min template< class T> inline T min(const T &lhs, const T &rhs) { T rt; for (int i = 0; i < lhs.size(); i++) { rt._array[i] = std::min(lhs._array[i], rhs._array[i]); } return rt; } // componentwise max template< class T> inline T max(const T &lhs, const T &rhs) { T rt; for (int i = 0; i < lhs.size(); i++) { rt._array[i] = std::max(lhs._array[i], rhs._array[i]); } return rt; } }; #endif ================================================ FILE: tests/projects/cuda/console/inc/nvrtc_helper.h ================================================ #if !defined(__NVRTC_HELPER__) #define __NVRTC_HELPER__ 1 #include #include #include #include #include #include #define NVRTC_SAFE_CALL(Name, x) \ do { \ nvrtcResult result = x; \ if (result != NVRTC_SUCCESS) { \ std::cerr << "\nerror: " << Name << " failed with error " << \ nvrtcGetErrorString(result); \ exit(1); \ } \ } while(0) void compileFileToPTX(char *filename, int argc, char **argv, char **ptxResult, size_t *ptxResultSize, int requiresCGheaders) { std::ifstream inputFile(filename, std::ios::in | std::ios::binary | std::ios::ate); if (!inputFile.is_open()) { std::cerr << "\nerror: unable to open " << filename << " for reading!\n"; exit(1); } std::streampos pos = inputFile.tellg(); size_t inputSize = (size_t)pos; char * memBlock = new char [inputSize + 1]; inputFile.seekg (0, std::ios::beg); inputFile.read (memBlock, inputSize); inputFile.close(); memBlock[inputSize] = '\x0'; int numCompileOptions = 0; char *compileParams[1]; if (requiresCGheaders) { std::string compileOptions; char *HeaderNames = "cooperative_groups.h"; compileOptions = "--include-path="; std::string path = sdkFindFilePath(HeaderNames, argv[0]); if (!path.empty()) { std::size_t found = path.find(HeaderNames); path.erase(found); } else { printf("\nCooperativeGroups headers not found, please install it in %s sample directory..\n Exiting..\n", argv[0]); } compileOptions += path.c_str(); compileParams[0] = (char *) malloc(sizeof(char)* (compileOptions.length() + 1)); strcpy(compileParams[0], compileOptions.c_str()); numCompileOptions++; } // compile nvrtcProgram prog; NVRTC_SAFE_CALL("nvrtcCreateProgram", nvrtcCreateProgram(&prog, memBlock, filename, 0, NULL, NULL)); nvrtcResult res = nvrtcCompileProgram(prog, numCompileOptions, compileParams); // dump log size_t logSize; NVRTC_SAFE_CALL("nvrtcGetProgramLogSize", nvrtcGetProgramLogSize(prog, &logSize)); char *log = (char *) malloc(sizeof(char) * logSize + 1); NVRTC_SAFE_CALL("nvrtcGetProgramLog", nvrtcGetProgramLog(prog, log)); log[logSize] = '\x0'; if (strlen(log) >= 2) { std::cerr << "\n compilation log ---\n"; std::cerr << log; std::cerr << "\n end log ---\n"; } free(log); NVRTC_SAFE_CALL("nvrtcCompileProgram", res); // fetch PTX size_t ptxSize; NVRTC_SAFE_CALL("nvrtcGetPTXSize", nvrtcGetPTXSize(prog, &ptxSize)); char *ptx = (char *) malloc(sizeof(char) * ptxSize); NVRTC_SAFE_CALL("nvrtcGetPTX", nvrtcGetPTX(prog, ptx)); NVRTC_SAFE_CALL("nvrtcDestroyProgram", nvrtcDestroyProgram(&prog)); *ptxResult = ptx; *ptxResultSize = ptxSize; if (requiresCGheaders) free(compileParams[0]); } CUmodule loadPTX(char *ptx, int argc, char **argv) { CUmodule module; CUcontext context; int major = 0, minor = 0; char deviceName[256]; // Picks the best CUDA device available CUdevice cuDevice = findCudaDeviceDRV(argc, (const char **)argv); // get compute capabilities and the devicename checkCudaErrors(cuDeviceComputeCapability(&major, &minor, cuDevice)); checkCudaErrors(cuDeviceGetName(deviceName, 256, cuDevice)); printf("> GPU Device has SM %d.%d compute capability\n", major, minor); checkCudaErrors(cuInit(0)); checkCudaErrors(cuDeviceGet(&cuDevice, 0)); checkCudaErrors(cuCtxCreate(&context, 0, cuDevice)); checkCudaErrors(cuModuleLoadDataEx(&module, ptx, 0, 0, 0)); free(ptx); return module; } #endif ================================================ FILE: tests/projects/cuda/console/inc/param.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ /* Simple parameter system sgreen@nvidia.com 4/2001 */ #ifndef PARAM_H #define PARAM_H #include #include #include #include #include #include // base class for named parameter class ParamBase { public: ParamBase(const char *name) : m_name(name) { } virtual ~ParamBase() { } std::string &GetName() { return m_name; } virtual float GetFloatValue() = 0; virtual int GetIntValue() = 0; virtual std::string GetValueString() = 0; virtual void Reset() = 0; virtual void Increment() = 0; virtual void Decrement() = 0; virtual float GetPercentage() = 0; virtual void SetPercentage(float p) = 0; virtual void Write(std::ostream &stream) = 0; virtual void Read(std::istream &stream) = 0; virtual bool IsList() = 0; protected: std::string m_name; }; // derived class for single-valued parameter template class Param : public ParamBase { public: Param(const char *name, T value = 0, T min = 0, T max = 10000, T step = 1, T *ptr = 0) : ParamBase(name), m_default(value), m_min(min), m_max(max), m_step(step), m_precision(3) { if (ptr) { m_ptr = ptr; } else { m_ptr = &m_value; } *m_ptr = value; } ~Param() { } T GetValue() const { return *m_ptr; } T SetValue(const T value) { *m_ptr = value; } float GetFloatValue() { return (float) *m_ptr; } int GetIntValue() { return (int) *m_ptr; } std::string GetValueString() { std::ostringstream ost; ost< m_max) { *m_ptr = m_max; } } void Decrement() { *m_ptr -= m_step; if (*m_ptr < m_min) { *m_ptr = m_min; } } void Write(std::ostream &stream) { stream << m_name << " " << *m_ptr << '\n'; } void Read(std::istream &stream) { stream >> m_name >> *m_ptr; } bool IsList() { return false; } private: T m_value; T *m_ptr; // pointer to value declared elsewhere T m_default, m_min, m_max, m_step; int m_precision; // number of digits after decimal point in string output }; const Param dummy("error"); // list of parameters class ParamList : public ParamBase { public: ParamList(const char *name = "") : ParamBase(name) { active = true; } ~ParamList() { } float GetFloatValue() { return 0.0f; } int GetIntValue() { return 0; } void AddParam(ParamBase *param) { m_params.push_back(param); m_map[param->GetName()] = param; m_current = m_params.begin(); } // look-up parameter based on name ParamBase *GetParam(char *name) { ParamBase *p = m_map[name]; if (p) { return p; } else { return (ParamBase *) &dummy; } } ParamBase *GetParam(int i) { return m_params[i]; } ParamBase *GetCurrent() { return *m_current; } int GetSize() { return (int)m_params.size(); } std::string GetValueString() { return m_name; } // functions to traverse list void Reset() { m_current = m_params.begin(); } void Increment() { m_current++; if (m_current == m_params.end()) { m_current = m_params.begin(); } } void Decrement() { if (m_current == m_params.begin()) { m_current = m_params.end()-1; } else { m_current--; } } float GetPercentage() { return 0.0f; } void SetPercentage(float /*p*/) {} void Write(std::ostream &stream) { stream << m_name << '\n'; for (std::vector::const_iterator p = m_params.begin(); p != m_params.end(); ++p) { (*p)->Write(stream); } } void Read(std::istream &stream) { stream >> m_name; for (std::vector::const_iterator p = m_params.begin(); p != m_params.end(); ++p) { (*p)->Read(stream); } } bool IsList() { return true; } void ResetAll() { for (std::vector::const_iterator p = m_params.begin(); p != m_params.end(); ++p) { (*p)->Reset(); } } protected: bool active; std::vector m_params; std::map m_map; std::vector::const_iterator m_current; }; #endif ================================================ FILE: tests/projects/cuda/console/inc/paramgl.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ /* ParamListGL - class derived from ParamList to do simple OpenGL rendering of a parameter list sgg 8/2001 */ #ifndef PARAMGL_H #define PARAMGL_H #if defined(__APPLE__) || defined(MACOSX) #include #else #include #endif #include #include inline void beginWinCoords(void) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glTranslatef(0.0, (GLfloat)(glutGet(GLUT_WINDOW_HEIGHT) - 1.0), 0.0); glScalef(1.0, -1.0, 1.0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT), -1, 1); glMatrixMode(GL_MODELVIEW); } inline void endWinCoords(void) { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } inline void glPrint(int x, int y, const char *s, void *font) { glRasterPos2f((GLfloat)x, (GLfloat)y); int len = (int) strlen(s); for (int i = 0; i < len; i++) { glutBitmapCharacter(font, s[i]); } } inline void glPrintShadowed(int x, int y, const char *s, void *font, float *color) { glColor3f(0.0, 0.0, 0.0); glPrint(x-1, y-1, s, font); glColor3fv((GLfloat *) color); glPrint(x, y, s, font); } class ParamListGL : public ParamList { public: ParamListGL(const char *name = "") : ParamList(name), m_active(true), m_text_color_selected(1.0, 1.0, 1.0), m_text_color_unselected(0.75, 0.75, 0.75), m_text_color_shadow(0.0, 0.0, 0.0), m_bar_color_outer(0.25, 0.25, 0.25), m_bar_color_inner(1.0, 1.0, 1.0) { m_font = (void *) GLUT_BITMAP_9_BY_15; // GLUT_BITMAP_8_BY_13; m_font_h = 15; m_bar_x = 260; m_bar_w = 250; m_bar_h = 10; m_bar_offset = 5; m_text_x = 5; m_separation = 15; m_value_x = 200; m_start_x = 0; m_start_y = 0; } void Render(int x, int y, bool shadow = false) { beginWinCoords(); m_start_x = x; m_start_y = y; for (std::vector::const_iterator p = m_params.begin(); p != m_params.end(); ++p) { if ((*p)->IsList()) { ParamListGL *list = (ParamListGL *)(*p); list->Render(x+10, y); y += m_separation*list->GetSize(); } else { if (p == m_current) { glColor3fv(&m_text_color_selected.r); } else { glColor3fv(&m_text_color_unselected.r); } if (shadow) { glPrintShadowed(x + m_text_x, y + m_font_h, (*p)->GetName().c_str(), m_font, (p == m_current) ? &m_text_color_selected.r : &m_text_color_unselected.r); glPrintShadowed(x + m_value_x, y + m_font_h, (*p)->GetValueString().c_str(), m_font, (p == m_current) ? &m_text_color_selected.r : &m_text_color_unselected.r); } else { glPrint(x + m_text_x, y + m_font_h, (*p)->GetName().c_str(), m_font); glPrint(x + m_value_x, y + m_font_h, (*p)->GetValueString().c_str(), m_font); } glColor3fv((GLfloat *) &m_bar_color_outer.r); glBegin(GL_LINE_LOOP); glVertex2f((GLfloat)(x + m_bar_x) , (GLfloat)(y + m_bar_offset)); glVertex2f((GLfloat)(x + m_bar_x + m_bar_w), (GLfloat)(y + m_bar_offset)); glVertex2f((GLfloat)(x + m_bar_x + m_bar_w), (GLfloat)(y + m_bar_offset + m_bar_h)); glVertex2f((GLfloat)(x + m_bar_x) , (GLfloat)(y + m_bar_offset + m_bar_h)); glEnd(); glColor3fv((GLfloat *) &m_bar_color_inner.r); glRectf((GLfloat)(x + m_bar_x), (GLfloat)(y + m_bar_offset + m_bar_h), (GLfloat)(x + m_bar_x + ((m_bar_w-1)*(*p)->GetPercentage())), (GLfloat)(y + m_bar_offset + 1)); y += m_separation; } } endWinCoords(); } bool Mouse(int x, int y, int button=GLUT_LEFT_BUTTON, int state=GLUT_DOWN) { if ((y < m_start_y) || (y > (int)(m_start_y + (m_separation * m_params.size()) - 1))) { m_active = false; return false; } m_active = true; int i = (y - m_start_y) / m_separation; if ((button==GLUT_LEFT_BUTTON) && (state==GLUT_DOWN)) { #if defined(__GNUC__) && (__GNUC__ < 3) m_current = &m_params[i]; #else // MJH: workaround since the version of vector::at used here is non-standard for (m_current = m_params.begin(); m_current != m_params.end() && i > 0; m_current++, i--) ; //m_current = (std::vector::const_iterator)&m_params.at(i); #endif if ((x > m_bar_x) && (x < m_bar_x + m_bar_w)) { Motion(x, y); } } return true; } bool Motion(int x, int y) { if ((y < m_start_y) || (y > m_start_y + (m_separation * (int)m_params.size()) - 1)) { return false; } if (x < m_bar_x) { (*m_current)->SetPercentage(0.0); return true; } if (x > m_bar_x + m_bar_w) { (*m_current)->SetPercentage(1.0); return true; } (*m_current)->SetPercentage((x-m_bar_x) / (float) m_bar_w); return true; } void Special(int key, int x, int y) { if (!m_active) return; switch (key) { case GLUT_KEY_DOWN: Increment(); break; case GLUT_KEY_UP: Decrement(); break; case GLUT_KEY_RIGHT: GetCurrent()->Increment(); break; case GLUT_KEY_LEFT: GetCurrent()->Decrement(); break; case GLUT_KEY_HOME: GetCurrent()->Reset(); break; case GLUT_KEY_END: GetCurrent()->SetPercentage(1.0); break; } glutPostRedisplay(); } void SetFont(void *font, int height) { m_font = font; m_font_h = height; } void SetSelectedColor(float r, float g, float b) { m_text_color_selected = Color(r, g, b); } void SetUnSelectedColor(float r, float g, float b) { m_text_color_unselected = Color(r, g, b); } void SetBarColorInner(float r, float g, float b) { m_bar_color_inner = Color(r, g, b); } void SetBarColorOuter(float r, float g, float b) { m_bar_color_outer = Color(r, g, b); } void SetActive(bool b) { m_active = b; } private: void *m_font; int m_font_h; // font height int m_bar_x; // bar start x position int m_bar_w; // bar width int m_bar_h; // bar height int m_text_x; // text start x position int m_separation; // bar separation in y int m_value_x; // value text x position int m_bar_offset; // bar offset in y int m_start_x, m_start_y; bool m_active; struct Color { Color(float _r, float _g, float _b) { r = _r; g = _g; b = _b; } float r, g, b; }; Color m_text_color_selected; Color m_text_color_unselected; Color m_text_color_shadow; Color m_bar_color_outer; Color m_bar_color_inner; }; #endif ================================================ FILE: tests/projects/cuda/console/inc/rendercheck_d3d10.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #pragma once #ifndef _RENDERCHECK_D3D10_H_ #define _RENDERCHECK_D3D10_H_ #include #include #include #include #include #include class CheckRenderD3D10 { public: CheckRenderD3D10() {} static HRESULT ActiveRenderTargetToPPM(ID3D10Device *pDevice, const char *zFileName); static HRESULT ResourceToPPM(ID3D10Device *pDevice, ID3D10Resource *pResource, const char *zFileName); static bool PPMvsPPM(const char *src_file, const char *ref_file, const char *exec_path, const float epsilon, const float threshold = 0.0f); }; #endif ================================================ FILE: tests/projects/cuda/console/inc/rendercheck_d3d11.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #pragma once #ifndef _RENDERCHECK_D3D11_H_ #define _RENDERCHECK_D3D11_H_ #include #include #include #include #include #include class CheckRenderD3D11 { public: CheckRenderD3D11() {} static HRESULT ActiveRenderTargetToPPM(ID3D11Device *pDevice, const char *zFileName); static HRESULT ResourceToPPM(ID3D11Device *pDevice, ID3D11Resource *pResource, const char *zFileName); static bool PPMvsPPM(const char *src_file, const char *ref_file, const char *exec_path, const float epsilon, const float threshold = 0.0f); }; #endif ================================================ FILE: tests/projects/cuda/console/inc/rendercheck_d3d9.h ================================================ /* * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #pragma once #ifndef _RENDERCHECK_D3D9_H_ #define _RENDERCHECK_D3D9_H_ #include #include #include #include #include class CheckRenderD3D9 { public: CheckRenderD3D9() {} static HRESULT BackbufferToPPM(IDirect3DDevice9 *pDevice, const char *zFileName); static HRESULT SurfaceToPPM(IDirect3DDevice9 *pDevice, IDirect3DSurface9 *pSurface, const char *zFileName); static bool PPMvsPPM(const char *src_file, const char *ref_file, const char *exec_path, const float epsilon, const float threshold = 0.0f); }; #endif ================================================ FILE: tests/projects/cuda/console/inc/rendercheck_gl.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef _RENDERCHECK_GL_H_ #define _RENDERCHECK_GL_H_ #include #include #include #include #include #include #include #if defined(__APPLE__) || defined(MACOSX) #include #else #include #endif #include #include using std::vector; using std::map; using std::string; #define BUFFER_OFFSET(i) ((char *)NULL + (i)) #if _DEBUG #define CHECK_FBO checkStatus(__FILE__, __LINE__, true) #else #define CHECK_FBO true #endif class CheckRender { public: CheckRender(unsigned int width, unsigned int height, unsigned int Bpp, bool bQAReadback, bool bUseFBO, bool bUsePBO) : m_Width(width), m_Height(height), m_Bpp(Bpp), m_bQAReadback(bQAReadback), m_bUseFBO(bUseFBO), m_bUsePBO(bUsePBO), m_PixelFormat(GL_BGRA), m_fThresholdCompare(0.0f) { allocateMemory(width, height, Bpp, bUseFBO, bUsePBO); } virtual ~CheckRender() { // Release PBO resources if (m_bUsePBO) { glDeleteBuffers(1, &m_pboReadback); m_pboReadback = 0; } free(m_pImageData); } virtual void allocateMemory(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseFBO, bool bUsePBO) { // Create the PBO for readbacks if (bUsePBO) { glGenBuffers(1, &m_pboReadback); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, m_pboReadback); glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width*height*Bpp, NULL, GL_STREAM_READ); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); } m_pImageData = (unsigned char *)malloc(width*height*Bpp); // This is the image data stored in system memory } virtual void setExecPath(char *path) { m_ExecPath = path; } virtual void EnableQAReadback(bool bStatus) { m_bQAReadback = bStatus; } virtual bool IsQAReadback() { return m_bQAReadback; } virtual bool IsFBO() { return m_bUseFBO; } virtual bool IsPBO() { return m_bUsePBO; } virtual void *imageData() { return m_pImageData; } // Interface to this class functions virtual void setPixelFormat(GLenum format) { m_PixelFormat = format; } virtual int getPixelFormat() { return m_PixelFormat; } virtual bool checkStatus(const char *zfile, int line, bool silent) = 0; virtual bool readback(GLuint width, GLuint height) = 0; virtual bool readback(GLuint width, GLuint height, GLuint bufObject) = 0; virtual bool readback(GLuint width, GLuint height, unsigned char *membuf) = 0; virtual void bindReadback() { if (!m_bQAReadback) { printf("CheckRender::bindReadback() uninitialized!\n"); return; } if (m_bUsePBO) { glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, m_pboReadback); // Bind the PBO } } virtual void unbindReadback() { if (!m_bQAReadback) { printf("CheckRender::unbindReadback() uninitialized!\n"); return; } if (m_bUsePBO) { glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); // Release the bind on the PBO } } virtual void savePGM(const char *zfilename, bool bInvert, void **ppReadBuf) { if (zfilename != NULL) { if (bInvert) { unsigned char *readBuf; unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height); for (unsigned int y=0; y < m_Height; y++) { if (ppReadBuf) { readBuf = *(unsigned char **)ppReadBuf; } else { readBuf = (unsigned char *)m_pImageData; } memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*(m_Height-1-y)), m_Width); } // we copy the results back to original system buffer if (ppReadBuf) { memcpy(*ppReadBuf, writeBuf, m_Width*m_Height); } else { memcpy(m_pImageData, writeBuf, m_Width*m_Height); } free(writeBuf); } printf("> Saving PGM: <%s>\n", zfilename); if (ppReadBuf) { sdkSavePGM(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height); } else { sdkSavePGM(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height); } } } virtual void savePPM(const char *zfilename, bool bInvert, void **ppReadBuf) { if (zfilename != NULL) { if (bInvert) { unsigned char *readBuf; unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height * m_Bpp); for (unsigned int y=0; y < m_Height; y++) { if (ppReadBuf) { readBuf = *(unsigned char **)ppReadBuf; } else { readBuf = (unsigned char *)m_pImageData; } memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*m_Bpp*(m_Height-1-y)), m_Width*m_Bpp); } // we copy the results back to original system buffer if (ppReadBuf) { memcpy(*ppReadBuf, writeBuf, m_Width*m_Height*m_Bpp); } else { memcpy(m_pImageData, writeBuf, m_Width*m_Height*m_Bpp); } free(writeBuf); } printf("> Saving PPM: <%s>\n", zfilename); if (ppReadBuf) { sdkSavePPM4ub(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height); } else { sdkSavePPM4ub(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height); } } } virtual bool PGMvsPGM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f) { unsigned char *src_data = NULL, *ref_data = NULL; unsigned long error_count = 0; unsigned int width, height; char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); if (ref_file_path == NULL) { printf("CheckRender::PGMvsPGM unable to find <%s> in <%s> Aborting comparison!\n", ref_file, m_ExecPath.c_str()); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; } else { if (src_file == NULL || ref_file_path == NULL) { printf("PGMvsPGM: Aborting comparison\n"); return false; } printf(" src_file <%s>\n", src_file); printf(" ref_file <%s>\n", ref_file_path); if (sdkLoadPPMub(ref_file_path, &ref_data, &width, &height) != true) { printf("PGMvsPGM: unable to load ref image file: %s\n", ref_file_path); return false; } if (sdkLoadPPMub(src_file, &src_data, &width, &height) != true) { printf("PGMvsPGM: unable to load src image file: %s\n", src_file); return false; } printf("PGMvsPGM: comparing images size (%d,%d) epsilon(%2.4f), threshold(%4.2f%%)\n", m_Height, m_Width, epsilon, threshold*100); if (compareDataAsFloatThreshold(ref_data, src_data, m_Height*m_Width, epsilon, threshold) == false) { error_count = 1; } } if (error_count == 0) { printf(" OK\n"); } else { printf(" FAILURE: %d errors...\n", (unsigned int)error_count); } return (error_count == 0); // returns true if all pixels pass } virtual bool PPMvsPPM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f) { unsigned long error_count = 0; char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); if (ref_file_path == NULL) { printf("CheckRender::PPMvsPPM unable to find <%s> in <%s> Aborting comparison!\n", ref_file, m_ExecPath.c_str()); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; } if (src_file == NULL || ref_file_path == NULL) { printf("PPMvsPPM: Aborting comparison\n"); return false; } printf(" src_file <%s>\n", src_file); printf(" ref_file <%s>\n", ref_file_path); return (sdkComparePPM(src_file, ref_file_path, epsilon, threshold, true) == true ? true : false); } void setThresholdCompare(float value) { m_fThresholdCompare = value; } virtual void dumpBin(void *data, unsigned int bytes, const char *filename) { FILE *fp; printf("CheckRender::dumpBin: <%s>\n", filename); FOPEN(fp, filename, "wb"); fwrite(data, bytes, 1, fp); fflush(fp); fclose(fp); } virtual bool compareBin2BinUint(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold) { unsigned int *src_buffer, *ref_buffer; FILE *src_fp = NULL, *ref_fp = NULL; unsigned long error_count = 0; size_t fsize = 0; FOPEN(src_fp, src_file, "rb"); if (src_fp == NULL) { printf("compareBin2Bin unable to open src_file: %s\n", src_file); error_count++; } char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); if (ref_file_path == NULL) { printf("compareBin2Bin unable to find <%s> in <%s>\n", ref_file, m_ExecPath.c_str()); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } else { FOPEN(ref_fp, ref_file_path, "rb"); if (ref_fp == NULL) { printf("compareBin2Bin unable to open ref_file: %s\n", ref_file_path); error_count++; } if (src_fp && ref_fp) { src_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int)); ref_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int)); fsize = fread(src_buffer, sizeof(unsigned int), nelements, src_fp); if (fsize != nelements) { printf("compareBin2Bin failed to read %u elements from %s\n", nelements, src_file); error_count++; } fsize = fread(ref_buffer, sizeof(unsigned int), nelements, ref_fp); if (fsize == 0) { printf("compareBin2Bin failed to read %u elements from %s\n", nelements, ref_file_path); error_count++; } printf("> compareBin2Bin nelements=%d, epsilon=%4.2f, threshold=%4.2f\n", nelements, epsilon, threshold); printf(" src_file <%s>\n", src_file); printf(" ref_file <%s>\n", ref_file_path); if (!compareData(ref_buffer, src_buffer, nelements, epsilon, threshold)) { error_count++; } fclose(src_fp); fclose(ref_fp); free(src_buffer); free(ref_buffer); } else { if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } } if (error_count == 0) { printf(" OK\n"); } else { printf(" FAILURE: %d errors...\n", (unsigned int)error_count); } return (error_count == 0); // returns true if all pixels pass } virtual bool compareBin2BinFloat(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold) { float *src_buffer, *ref_buffer; FILE *src_fp = NULL, *ref_fp = NULL; size_t fsize = 0; unsigned long error_count = 0; FOPEN(src_fp, src_file, "rb"); if (src_fp == NULL) { printf("compareBin2Bin unable to open src_file: %s\n", src_file); error_count = 1; } char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); if (ref_file_path == NULL) { printf("compareBin2Bin unable to find <%s> in <%s>\n", ref_file, m_ExecPath.c_str()); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", m_ExecPath.c_str()); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } else { FOPEN(ref_fp, ref_file_path, "rb"); if (ref_fp == NULL) { printf("compareBin2Bin unable to open ref_file: %s\n", ref_file_path); error_count = 1; } if (src_fp && ref_fp) { src_buffer = (float *)malloc(nelements*sizeof(float)); ref_buffer = (float *)malloc(nelements*sizeof(float)); fsize = fread(src_buffer, sizeof(float), nelements, src_fp); if (fsize != nelements) { printf("compareBin2Bin failed to read %u elements from %s\n", nelements, src_file); error_count++; } fsize = fread(ref_buffer, sizeof(float), nelements, ref_fp); if (fsize == 0) { printf("compareBin2Bin failed to read %u elements from %s\n", nelements, ref_file_path); error_count++; } printf("> compareBin2Bin nelements=%d, epsilon=%4.2f, threshold=%4.2f\n", nelements, epsilon, threshold); printf(" src_file <%s>\n", src_file); printf(" ref_file <%s>\n", ref_file_path); if (!compareDataAsFloatThreshold(ref_buffer, src_buffer, nelements, epsilon, threshold)) { error_count++; } fclose(src_fp); fclose(ref_fp); free(src_buffer); free(ref_buffer); } else { if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } } if (error_count == 0) { printf(" OK\n"); } else { printf(" FAILURE: %d errors...\n", (unsigned int)error_count); } return (error_count == 0); // returns true if all pixels pass } protected: unsigned int m_Width, m_Height, m_Bpp; unsigned char *m_pImageData; // This is the image data stored in system memory bool m_bQAReadback, m_bUseFBO, m_bUsePBO; GLuint m_pboReadback; GLenum m_PixelFormat; float m_fThresholdCompare; string m_ExecPath; }; class CheckBackBuffer : public CheckRender { public: CheckBackBuffer(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseOpenGL = true) : CheckRender(width, height, Bpp, false, false, bUseOpenGL) { } virtual ~CheckBackBuffer() { } virtual bool checkStatus(const char *zfile, int line, bool silent) { GLenum nErrorCode = glGetError(); if (nErrorCode != GL_NO_ERROR) { if (!silent) { printf("Assertion failed(%s,%d): %s\n", zfile, line, gluErrorString(nErrorCode)); } } return true; } virtual bool readback(GLuint width, GLuint height) { bool ret = false; if (m_bUsePBO) { // binds the PBO for readback bindReadback(); // Initiate the readback BLT from BackBuffer->PBO->membuf glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckBackBuffer::glReadPixels() checkStatus = %d\n", ret); } // map - unmap simulates readback without the copy void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); // release the PBO unbindReadback(); } else { // reading direct from the backbuffer glReadBuffer(GL_FRONT); glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); } return ret; } virtual bool readback(GLuint width, GLuint height, GLuint bufObject) { bool ret = false; if (m_bUseFBO) { if (m_bUsePBO) { printf("CheckBackBuffer::readback() FBO->PBO->m_pImageData\n"); // binds the PBO for readback bindReadback(); // bind FBO buffer (we want to transfer FBO -> PBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject); // Now initiate the readback to PBO glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckBackBuffer::readback() FBO->PBO checkStatus = %d\n", ret); } // map - unmap simulates readback without the copy void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); // release the FBO glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // release the PBO unbindReadback(); } else { printf("CheckBackBuffer::readback() FBO->m_pImageData\n"); // Reading direct to FBO using glReadPixels glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckBackBuffer::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\n", bufObject, ret); } glReadBuffer(static_cast(GL_COLOR_ATTACHMENT0_EXT)); ret &= checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckBackBuffer::readback::glReadBuffer() fbo=%d checkStatus = %d\n", bufObject, ret); } glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } } else { printf("CheckBackBuffer::readback() PBO->m_pImageData\n"); // read from bufObject (PBO) to system memorys image glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, bufObject); // Bind the PBO // map - unmap simulates readback without the copy void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); // allocate a buffer so we can flip the image unsigned char *temp_buf = (unsigned char *)malloc(width*height*m_Bpp); memcpy(temp_buf, ioMem, width*height*m_Bpp); // let's flip the image as we copy for (unsigned int y = 0; y < height; y++) { memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(temp_buf[y*width*m_Bpp]), width*m_Bpp); } free(temp_buf); glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); // read from bufObject (PBO) to system memory image glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); // unBind the PBO } return CHECK_FBO; } virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf) { // let's flip the image as we copy for (unsigned int y = 0; y < height; y++) { memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp); } return true; } private: virtual void bindFragmentProgram() {}; virtual void bindRenderPath() {}; virtual void unbindRenderPath() {}; // bind to the BackBuffer to Texture virtual void bindTexture() {}; // release this bind virtual void unbindTexture() {}; }; // structure defining the properties of a single buffer struct bufferConfig { string name; GLenum format; int bits; }; // structures defining properties of an FBO struct fboConfig { string name; GLenum colorFormat; GLenum depthFormat; int redbits; int depthBits; int depthSamples; int coverageSamples; }; struct fboData { GLuint colorTex; //color texture GLuint depthTex; //depth texture GLuint fb; // render framebuffer GLuint resolveFB; //multisample resolve target GLuint colorRB; //color render buffer GLuint depthRB; // depth render buffer }; class CFrameBufferObject { public: CFrameBufferObject(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseFloat, GLenum eTarget) : m_Width(width), m_Height(height), m_bUseFloat(bUseFloat), m_eGLTarget(eTarget) { glGenFramebuffersEXT(1, &m_fboData.fb); m_fboData.colorTex = createTexture(m_eGLTarget, width, height, (bUseFloat ? GL_RGBA32F_ARB : GL_RGBA8), GL_RGBA); m_fboData.depthTex = createTexture(m_eGLTarget, width, height, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT); attachTexture(m_eGLTarget, m_fboData.colorTex, GL_COLOR_ATTACHMENT0_EXT); attachTexture(m_eGLTarget, m_fboData.depthTex, GL_DEPTH_ATTACHMENT_EXT); // bool ret = checkStatus(__FILE__, __LINE__, true); } virtual ~CFrameBufferObject() { // freeResources(); } GLuint createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format) { GLuint texid; glGenTextures(1, &texid); glBindTexture(target, texid); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_FLOAT, 0); return texid; } void attachTexture(GLenum texTarget, GLuint texId, GLenum attachment = GL_COLOR_ATTACHMENT0_EXT, int mipLevel = 0, int zSlice = 0) { bindRenderPath(); switch (texTarget) { case GL_TEXTURE_1D: glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_1D, texId, mipLevel); break; case GL_TEXTURE_3D: glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_3D, texId, mipLevel, zSlice); break; default: // Default is GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB, or cube faces glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, texTarget, texId, mipLevel); break; } unbindRenderPath(); } bool initialize(unsigned width, unsigned height, fboConfig &rConfigFBO, fboData &rActiveFBO) { //Framebuffer config options vector colorConfigs; vector depthConfigs; bufferConfig temp; //add default color configs temp.name = (m_bUseFloat ? "RGBA32F" : "RGBA8"); temp.bits = (m_bUseFloat ? 32 : 8); temp.format = (m_bUseFloat ? GL_RGBA32F_ARB : GL_RGBA8); colorConfigs.push_back(temp); //add default depth configs temp.name = "D24"; temp.bits = 24; temp.format = GL_DEPTH_COMPONENT24; depthConfigs.push_back(temp); // If the FBO can be created, add it to the list of available configs, and make a menu entry string root = colorConfigs[0].name + " " + depthConfigs[0].name; rConfigFBO.colorFormat = colorConfigs[0].format; rConfigFBO.depthFormat = depthConfigs[0].format; rConfigFBO.redbits = colorConfigs[0].bits; rConfigFBO.depthBits = depthConfigs[0].bits; //single sample rConfigFBO.name = root; rConfigFBO.coverageSamples = 0; rConfigFBO.depthSamples = 0; create(width, height, rConfigFBO, rActiveFBO); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); if (m_bUseFloat) { // load fragment programs const char *strTextureProgram2D = "!!ARBfp1.0\n" "TEX result.color, fragment.texcoord[0], texture[0], 2D;\n" "END\n"; m_textureProgram = nv::CompileASMShader(GL_FRAGMENT_PROGRAM_ARB, strTextureProgram2D); const char *strOverlayProgram = "!!ARBfp1.0\n" "TEMP t;\n" "TEX t, fragment.texcoord[0], texture[0], 2D;\n" "MOV result.color, t;\n" "END\n"; m_overlayProgram = nv::CompileASMShader(GL_FRAGMENT_PROGRAM_ARB, strOverlayProgram); } return CHECK_FBO; } bool create(GLuint width, GLuint height, fboConfig &config, fboData &data) { bool multisample = config.depthSamples > 0; bool ret = true; GLint query; printf("\nCreating FBO <%s> (%dx%d) Float:%s\n", config.name.c_str(), (int)width, (int)height, (m_bUseFloat ? "Y":"N")); glGenFramebuffersEXT(1, &data.fb); glGenTextures(1, &data.colorTex); // init texture glBindTexture(m_eGLTarget, data.colorTex); glTexImage2D(m_eGLTarget, 0, config.colorFormat, width, height, 0, GL_RGBA, (m_bUseFloat ? GL_FLOAT : GL_UNSIGNED_BYTE), NULL); glGenerateMipmapEXT(m_eGLTarget); glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR); { glGenTextures(1, &data.depthTex); data.depthRB = 0; data.colorRB = 0; data.resolveFB = 0; //non-multisample, so bind things directly to the FBO glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.fb); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_eGLTarget, data.colorTex, 0); glBindTexture(m_eGLTarget, data.depthTex); glTexImage2D(m_eGLTarget, 0, config.depthFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR); glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR); glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(m_eGLTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_eGLTarget, data.depthTex, 0); ret &= checkStatus(__FILE__, __LINE__, true); } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.fb); glGetIntegerv(GL_RED_BITS, &query); if (query != config.redbits) { ret = false; } glGetIntegerv(GL_DEPTH_BITS, &query); if (query != config.depthBits) { ret = false; } if (multisample) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.resolveFB); glGetIntegerv(GL_RED_BITS, &query); if (query != config.redbits) { ret = false; } } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); ret &= checkStatus(__FILE__, __LINE__, true); return ret; } virtual void freeResources() { if (m_fboData.fb) { glDeleteFramebuffersEXT(1, &m_fboData.fb); } if (m_fboData.resolveFB) { glDeleteFramebuffersEXT(1, &m_fboData.resolveFB); } if (m_fboData.colorRB) { glDeleteRenderbuffersEXT(1, &m_fboData.colorRB); } if (m_fboData.depthRB) { glDeleteRenderbuffersEXT(1, &m_fboData.depthRB); } if (m_fboData.colorTex) { glDeleteTextures(1, &m_fboData.colorTex); } if (m_fboData.depthTex) { glDeleteTextures(1, &m_fboData.depthTex); } glDeleteProgramsARB(1, &m_textureProgram); glDeleteProgramsARB(1, &m_overlayProgram); } virtual bool checkStatus(const char *zfile, int line, bool silent) { GLenum status; status = (GLenum) glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { printf("<%s : %d> - ", zfile, line); } switch (status) { case GL_FRAMEBUFFER_COMPLETE_EXT: break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: if (!silent) { printf("Unsupported framebuffer format\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: if (!silent) { printf("Framebuffer incomplete, missing attachment\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: if (!silent) { printf("Framebuffer incomplete, duplicate attachment\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: if (!silent) { printf("Framebuffer incomplete, attached images must have same dimensions\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: if (!silent) { printf("Framebuffer incomplete, attached images must have same format\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: if (!silent) { printf("Framebuffer incomplete, missing draw buffer\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: if (!silent) { printf("Framebuffer incomplete, missing read buffer\n"); } return false; default: assert(0); return false; } return true; } virtual void renderQuad(int width, int height, GLenum eTarget) { float width_norm = (float)width/(float)m_Width, height_norm = (float)height/(float)m_Height; // Bind the FBO texture for the display path glBindTexture(eTarget, m_fboData.colorTex); glGenerateMipmapEXT(GL_TEXTURE_2D); glBindTexture(eTarget, 0); // now render to the full screen using this texture glClearColor(0.2f, 0.2f, 0.2f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_textureProgram); glEnable(GL_FRAGMENT_PROGRAM_ARB); glDisable(GL_DEPTH_TEST); glBegin(GL_QUADS); { glVertex2f(0.0f , 0.0f); glTexCoord2f(0.0f , 0.0f); glVertex2f(0.0f , height_norm); glTexCoord2f(width_norm, 0.0f); glVertex2f(width_norm, height_norm); glTexCoord2f(width_norm, height_norm); glVertex2f(width_norm, 0.0f); glTexCoord2f(0.0f , height_norm); } glEnd(); // Release the FBO texture (finished rendering) glBindTexture(eTarget, 0); } // bind to the Fragment Program void bindFragmentProgram() { glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_textureProgram); glEnable(GL_FRAGMENT_PROGRAM_ARB); } // bind to the FrameBuffer Object void bindRenderPath() { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboData.fb); } // release current FrameBuffer Object void unbindRenderPath() { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } // bind to the FBO to Texture void bindTexture() { glBindTexture(m_eGLTarget, m_fboData.colorTex); } // release this bind void unbindTexture() { glBindTexture(m_eGLTarget, 0); } GLuint getFbo() { return m_fboData.fb; } GLuint getTex() { return m_fboData.colorTex; } GLuint getDepthTex() { return m_fboData.depthTex; } private: GLuint m_Width, m_Height; fboData m_fboData; fboConfig m_fboConfig; GLuint m_textureProgram; GLuint m_overlayProgram; bool m_bUseFloat; GLenum m_eGLTarget; }; // CheckFBO - render and verify contents of the FBO class CheckFBO: public CheckRender { public: CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp) : CheckRender(width, height, Bpp, false, false, true), m_pFrameBufferObject(NULL) { } CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp, CFrameBufferObject *pFrameBufferObject) : CheckRender(width, height, Bpp, false, true, true), m_pFrameBufferObject(pFrameBufferObject) { } virtual ~CheckFBO() { } virtual bool checkStatus(const char *zfile, int line, bool silent) { GLenum status; status = (GLenum) glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { printf("<%s : %d> - ", zfile, line); } switch (status) { case GL_FRAMEBUFFER_COMPLETE_EXT: break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: if (!silent) { printf("Unsupported framebuffer format\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: if (!silent) { printf("Framebuffer incomplete, missing attachment\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: if (!silent) { printf("Framebuffer incomplete, duplicate attachment\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: if (!silent) { printf("Framebuffer incomplete, attached images must have same dimensions\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: if (!silent) { printf("Framebuffer incomplete, attached images must have same format\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: if (!silent) { printf("Framebuffer incomplete, missing draw buffer\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: if (!silent) { printf("Framebuffer incomplete, missing read buffer\n"); } return false; default: assert(0); return false; } return true; } virtual bool readback(GLuint width, GLuint height) { bool ret = false; if (m_bUsePBO) { // binds the PBO for readback bindReadback(); // bind FBO buffer (we want to transfer FBO -> PBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_pFrameBufferObject->getFbo()); // Now initiate the readback to PBO glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback() FBO->PBO checkStatus = %d\n", ret); } // map - unmap simulates readback without the copy void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); // release the FBO glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // release the PBO unbindReadback(); } else { // Reading back from FBO using glReadPixels glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_pFrameBufferObject->getFbo()); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback::glBindFramebufferEXT() checkStatus = %d\n", ret); } glReadBuffer(static_cast(GL_COLOR_ATTACHMENT0_EXT)); ret &= checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback::glReadBuffer() checkStatus = %d\n", ret); } glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } return CHECK_FBO; } virtual bool readback(GLuint width, GLuint height, GLuint bufObject) { bool ret = false; if (m_bUseFBO) { if (m_bUsePBO) { printf("CheckFBO::readback() FBO->PBO->m_pImageData\n"); // binds the PBO for readback bindReadback(); // bind FBO buffer (we want to transfer FBO -> PBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject); // Now initiate the readback to PBO glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback() FBO->PBO checkStatus = %d\n", ret); } // map - unmap simulates readback without the copy void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); // release the FBO glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // release the PBO unbindReadback(); } else { printf("CheckFBO::readback() FBO->m_pImageData\n"); // Reading direct to FBO using glReadPixels glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\n", (int)bufObject, (int)ret); } glReadBuffer(static_cast(GL_COLOR_ATTACHMENT0_EXT)); ret &= checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback::glReadBuffer() fbo=%d checkStatus = %d\n", (int)bufObject, (int)ret); } glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } } else { printf("CheckFBO::readback() PBO->m_pImageData\n"); // read from bufObject (PBO) to system memorys image glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, bufObject); // Bind the PBO // map - unmap simulates readback without the copy void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); // read from bufObject (PBO) to system memory image glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); // unBind the PBO } return CHECK_FBO; } virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf) { // let's flip the image as we copy for (unsigned int y = 0; y < height; y++) { memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp); } return true; } private: CFrameBufferObject *m_pFrameBufferObject; }; #endif // _RENDERCHECK_GL_H_ ================================================ FILE: tests/projects/cuda/console/inc/rendercheck_gles.h ================================================ /** * Copyright 1993-2015 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef _RENDERCHECK_GLES_H_ #define _RENDERCHECK_GLES_H_ #include #include #include #include #include #include #include #include #include using std::vector; using std::map; using std::string; #define BUFFER_OFFSET(i) ((char *)NULL + (i)) #if _DEBUG #define CHECK_FBO checkStatus(__FILE__, __LINE__, true) #else #define CHECK_FBO true #endif class CheckRender { public: CheckRender(unsigned int width, unsigned int height, unsigned int Bpp, bool bQAReadback, bool bUseFBO, bool bUsePBO) : m_Width(width), m_Height(height), m_Bpp(Bpp), m_bQAReadback(bQAReadback), m_bUseFBO(bUseFBO), m_bUsePBO(bUsePBO), m_PixelFormat(GL_RGBA), m_fThresholdCompare(0.0f) { allocateMemory(width, height, Bpp, bUseFBO, bUsePBO); } virtual ~CheckRender() { // Release PBO resources if (m_bUsePBO) { glDeleteBuffers(1, &m_pboReadback); m_pboReadback = 0; } free(m_pImageData); } virtual void allocateMemory(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseFBO, bool bUsePBO) { // Create the PBO for readbacks if (bUsePBO) { glGenBuffers(1, &m_pboReadback); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pboReadback); glBufferData(GL_PIXEL_UNPACK_BUFFER, width*height*Bpp, NULL, GL_STREAM_READ); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } m_pImageData = (unsigned char *)malloc(width*height*Bpp); // This is the image data stored in system memory } virtual void setExecPath(char *path) { m_ExecPath = path; } virtual void EnableQAReadback(bool bStatus) { m_bQAReadback = bStatus; } virtual bool IsQAReadback() { return m_bQAReadback; } virtual bool IsFBO() { return m_bUseFBO; } virtual bool IsPBO() { return m_bUsePBO; } virtual void *imageData() { return m_pImageData; } // Interface to this class functions virtual void setPixelFormat(GLenum format) { m_PixelFormat = format; } virtual int getPixelFormat() { return m_PixelFormat; } virtual bool checkStatus(const char *zfile, int line, bool silent) = 0; virtual bool readback(GLuint width, GLuint height) = 0; virtual bool readback(GLuint width, GLuint height, GLuint bufObject) = 0; virtual bool readback(GLuint width, GLuint height, unsigned char *membuf) = 0; virtual void bindReadback() { if (!m_bQAReadback) { printf("CheckRender::bindReadback() uninitialized!\n"); return; } if (m_bUsePBO) { glBindBuffer(GL_PIXEL_PACK_BUFFER, m_pboReadback); // Bind the PBO } } virtual void unbindReadback() { if (!m_bQAReadback) { printf("CheckRender::unbindReadback() uninitialized!\n"); return; } if (m_bUsePBO) { glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); // Release the bind on the PBO } } virtual void savePGM(const char *zfilename, bool bInvert, void **ppReadBuf) { if (zfilename != NULL) { if (bInvert) { unsigned char *readBuf; unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height); for (unsigned int y=0; y < m_Height; y++) { if (ppReadBuf) { readBuf = *(unsigned char **)ppReadBuf; } else { readBuf = (unsigned char *)m_pImageData; } memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*(m_Height-1-y)), m_Width); } // we copy the results back to original system buffer if (ppReadBuf) { memcpy(*ppReadBuf, writeBuf, m_Width*m_Height); } else { memcpy(m_pImageData, writeBuf, m_Width*m_Height); } free(writeBuf); } printf("> Saving PGM: <%s>\n", zfilename); if (ppReadBuf) { sdkSavePGM(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height); } else { sdkSavePGM(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height); } } } virtual void savePPM(const char *zfilename, bool bInvert, void **ppReadBuf) { if (zfilename != NULL) { if (bInvert) { unsigned char *readBuf; unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height * m_Bpp); for (unsigned int y=0; y < m_Height; y++) { if (ppReadBuf) { readBuf = *(unsigned char **)ppReadBuf; } else { readBuf = (unsigned char *)m_pImageData; } memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*m_Bpp*(m_Height-1-y)), m_Width*m_Bpp); } // we copy the results back to original system buffer if (ppReadBuf) { memcpy(*ppReadBuf, writeBuf, m_Width*m_Height*m_Bpp); } else { memcpy(m_pImageData, writeBuf, m_Width*m_Height*m_Bpp); } free(writeBuf); } printf("> Saving PPM: <%s>\n", zfilename); if (ppReadBuf) { sdkSavePPM4ub(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height); } else { sdkSavePPM4ub(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height); } } } virtual bool PGMvsPGM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f) { unsigned char *src_data = NULL, *ref_data = NULL; unsigned long error_count = 0; unsigned int width, height; char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); if (ref_file_path == NULL) { printf("CheckRender::PGMvsPGM unable to find <%s> in <%s> Aborting comparison!\n", ref_file, m_ExecPath.c_str()); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; } else { if (src_file == NULL || ref_file_path == NULL) { printf("PGMvsPGM: Aborting comparison\n"); return false; } printf(" src_file <%s>\n", src_file); printf(" ref_file <%s>\n", ref_file_path); if (sdkLoadPPMub(ref_file_path, &ref_data, &width, &height) != true) { printf("PGMvsPGM: unable to load ref image file: %s\n", ref_file_path); return false; } if (sdkLoadPPMub(src_file, &src_data, &width, &height) != true) { printf("PGMvsPGM: unable to load src image file: %s\n", src_file); return false; } printf("PGMvsPGM: comparing images size (%d,%d) epsilon(%2.4f), threshold(%4.2f%%)\n", m_Height, m_Width, epsilon, threshold*100); if (compareDataAsFloatThreshold(ref_data, src_data, m_Height*m_Width, epsilon, threshold) == false) { error_count = 1; } } if (error_count == 0) { printf(" OK\n"); } else { printf(" FAILURE: %d errors...\n", (unsigned int)error_count); } return (error_count == 0); // returns true if all pixels pass } virtual bool PPMvsPPM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f) { unsigned long error_count = 0; char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); if (ref_file_path == NULL) { printf("CheckRender::PPMvsPPM unable to find <%s> in <%s> Aborting comparison!\n", ref_file, m_ExecPath.c_str()); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; } if (src_file == NULL || ref_file_path == NULL) { printf("PPMvsPPM: Aborting comparison\n"); return false; } printf(" src_file <%s>\n", src_file); printf(" ref_file <%s>\n", ref_file_path); return (sdkComparePPM(src_file, ref_file_path, epsilon, threshold, true) == true ? true : false); } void setThresholdCompare(float value) { m_fThresholdCompare = value; } virtual void dumpBin(void *data, unsigned int bytes, const char *filename) { FILE *fp; printf("CheckRender::dumpBin: <%s>\n", filename); FOPEN(fp, filename, "wb"); fwrite(data, bytes, 1, fp); fflush(fp); fclose(fp); } virtual bool compareBin2BinUint(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold) { unsigned int *src_buffer, *ref_buffer; FILE *src_fp = NULL, *ref_fp = NULL; unsigned long error_count = 0; size_t fsize = 0; FOPEN(src_fp, src_file, "rb"); if (src_fp == NULL) { printf("compareBin2Bin unable to open src_file: %s\n", src_file); error_count++; } char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); if (ref_file_path == NULL) { printf("compareBin2Bin unable to find <%s> in <%s>\n", ref_file, m_ExecPath.c_str()); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } else { FOPEN(ref_fp, ref_file_path, "rb"); if (ref_fp == NULL) { printf("compareBin2Bin unable to open ref_file: %s\n", ref_file_path); error_count++; } if (src_fp && ref_fp) { src_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int)); ref_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int)); fsize = fread(src_buffer, sizeof(unsigned int), nelements, src_fp); if (fsize != nelements) { printf("compareBin2Bin failed to read %u elements from %s\n", nelements, src_file); error_count++; } fsize = fread(ref_buffer, sizeof(unsigned int), nelements, ref_fp); if (fsize == 0) { printf("compareBin2Bin failed to read %u elements from %s\n", nelements, ref_file_path); error_count++; } printf("> compareBin2Bin nelements=%d, epsilon=%4.2f, threshold=%4.2f\n", nelements, epsilon, threshold); printf(" src_file <%s>\n", src_file); printf(" ref_file <%s>\n", ref_file_path); if (!compareData(ref_buffer, src_buffer, nelements, epsilon, threshold)) { error_count++; } fclose(src_fp); fclose(ref_fp); free(src_buffer); free(ref_buffer); } else { if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } } if (error_count == 0) { printf(" OK\n"); } else { printf(" FAILURE: %d errors...\n", (unsigned int)error_count); } return (error_count == 0); // returns true if all pixels pass } virtual bool compareBin2BinFloat(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold) { float *src_buffer, *ref_buffer; FILE *src_fp = NULL, *ref_fp = NULL; size_t fsize = 0; unsigned long error_count = 0; FOPEN(src_fp, src_file, "rb"); if (src_fp == NULL) { printf("compareBin2Bin unable to open src_file: %s\n", src_file); error_count = 1; } char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); if (ref_file_path == NULL) { printf("compareBin2Bin unable to find <%s> in <%s>\n", ref_file, m_ExecPath.c_str()); printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", m_ExecPath.c_str()); printf("Aborting comparison!\n"); printf(" FAILED\n"); error_count++; if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } else { FOPEN(ref_fp, ref_file_path, "rb"); if (ref_fp == NULL) { printf("compareBin2Bin unable to open ref_file: %s\n", ref_file_path); error_count = 1; } if (src_fp && ref_fp) { src_buffer = (float *)malloc(nelements*sizeof(float)); ref_buffer = (float *)malloc(nelements*sizeof(float)); fsize = fread(src_buffer, sizeof(float), nelements, src_fp); if (fsize != nelements) { printf("compareBin2Bin failed to read %u elements from %s\n", nelements, src_file); error_count++; } fsize = fread(ref_buffer, sizeof(float), nelements, ref_fp); if (fsize == 0) { printf("compareBin2Bin failed to read %u elements from %s\n", nelements, ref_file_path); error_count++; } printf("> compareBin2Bin nelements=%d, epsilon=%4.2f, threshold=%4.2f\n", nelements, epsilon, threshold); printf(" src_file <%s>\n", src_file); printf(" ref_file <%s>\n", ref_file_path); if (!compareDataAsFloatThreshold(ref_buffer, src_buffer, nelements, epsilon, threshold)) { error_count++; } fclose(src_fp); fclose(ref_fp); free(src_buffer); free(ref_buffer); } else { if (src_fp) { fclose(src_fp); } if (ref_fp) { fclose(ref_fp); } } } if (error_count == 0) { printf(" OK\n"); } else { printf(" FAILURE: %d errors...\n", (unsigned int)error_count); } return (error_count == 0); // returns true if all pixels pass } protected: unsigned int m_Width, m_Height, m_Bpp; unsigned char *m_pImageData; // This is the image data stored in system memory bool m_bQAReadback, m_bUseFBO, m_bUsePBO; GLuint m_pboReadback; GLenum m_PixelFormat; float m_fThresholdCompare; string m_ExecPath; }; class CheckBackBuffer : public CheckRender { public: CheckBackBuffer(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseOpenGL = true) : CheckRender(width, height, Bpp, false, false, bUseOpenGL) { } virtual ~CheckBackBuffer() { } virtual bool checkStatus(const char *zfile, int line, bool silent) { GLenum nErrorCode = glGetError(); if (nErrorCode != GL_NO_ERROR) { if (!silent) { //printf("Assertion failed(%s,%d): %s\n", zfile, line, gluErrorString(nErrorCode)); } } return true; } virtual bool readback(GLuint width, GLuint height) { bool ret = false; if (m_bUsePBO) { // binds the PBO for readback bindReadback(); // Initiate the readback BLT from BackBuffer->PBO->membuf glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckBackBuffer::glReadPixels() checkStatus = %d\n", ret); } // map - unmap simulates readback without the copy void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_READ_ONLY); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); // release the PBO unbindReadback(); } else { // reading direct from the backbuffer glReadBuffer(GL_FRONT); glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); } return ret; } virtual bool readback(GLuint width, GLuint height, GLuint bufObject) { bool ret = false; if (m_bUseFBO) { if (m_bUsePBO) { printf("CheckBackBuffer::readback() FBO->PBO->m_pImageData\n"); // binds the PBO for readback bindReadback(); // bind FBO buffer (we want to transfer FBO -> PBO) glBindFramebuffer(GL_FRAMEBUFFER, bufObject); // Now initiate the readback to PBO glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckBackBuffer::readback() FBO->PBO checkStatus = %d\n", ret); } // map - unmap simulates readback without the copy void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); // release the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); // release the PBO unbindReadback(); } else { printf("CheckBackBuffer::readback() FBO->m_pImageData\n"); // Reading direct to FBO using glReadPixels glBindFramebuffer(GL_FRAMEBUFFER, bufObject); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckBackBuffer::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\n", bufObject, ret); } glReadBuffer(static_cast(GL_COLOR_ATTACHMENT0)); ret &= checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckBackBuffer::readback::glReadBuffer() fbo=%d checkStatus = %d\n", bufObject, ret); } glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); glBindFramebuffer(GL_FRAMEBUFFER, 0); } } else { printf("CheckBackBuffer::readback() PBO->m_pImageData\n"); // read from bufObject (PBO) to system memorys image glBindBuffer(GL_PIXEL_PACK_BUFFER, bufObject); // Bind the PBO // map - unmap simulates readback without the copy void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); // allocate a buffer so we can flip the image unsigned char *temp_buf = (unsigned char *)malloc(width*height*m_Bpp); memcpy(temp_buf, ioMem, width*height*m_Bpp); // let's flip the image as we copy for (unsigned int y = 0; y < height; y++) { memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(temp_buf[y*width*m_Bpp]), width*m_Bpp); } free(temp_buf); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); // read from bufObject (PBO) to system memory image glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); // unBind the PBO } return CHECK_FBO; } virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf) { // let's flip the image as we copy for (unsigned int y = 0; y < height; y++) { memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp); } return true; } private: virtual void bindFragmentProgram() {}; virtual void bindRenderPath() {}; virtual void unbindRenderPath() {}; // bind to the BackBuffer to Texture virtual void bindTexture() {}; // release this bind virtual void unbindTexture() {}; }; // structure defining the properties of a single buffer struct bufferConfig { string name; GLenum format; int bits; }; // structures defining properties of an FBO struct fboConfig { string name; GLenum colorFormat; GLenum depthFormat; int redbits; int depthBits; int depthSamples; int coverageSamples; }; struct fboData { GLuint colorTex; //color texture GLuint depthTex; //depth texture GLuint fb; // render framebuffer GLuint resolveFB; //multisample resolve target GLuint colorRB; //color render buffer GLuint depthRB; // depth render buffer }; class CFrameBufferObject { public: CFrameBufferObject(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseFloat, GLenum eTarget) : m_Width(width), m_Height(height), m_bUseFloat(bUseFloat), m_eGLTarget(eTarget) { glGenFramebuffers(1, &m_fboData.fb); m_fboData.colorTex = createTexture(m_eGLTarget, width, height, GL_RGBA, GL_RGBA); m_fboData.depthTex = createTexture(m_eGLTarget, width, height, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT); attachTexture(m_eGLTarget, m_fboData.depthTex, GL_DEPTH_ATTACHMENT); attachTexture(m_eGLTarget, m_fboData.colorTex, GL_COLOR_ATTACHMENT0); bool ret = checkStatus(__FILE__, __LINE__, false); } void check_gl_error(const char *file, int line) { GLenum err (glGetError()); while(err!=GL_NO_ERROR) { char error[64]; switch(err) { case GL_INVALID_OPERATION: strcpy(error, "INVALID_OPERATION"); break; case GL_INVALID_ENUM: strcpy(error, "INVALID_ENUM"); break; case GL_INVALID_VALUE: strcpy(error, "INVALID_VALUE"); break; case GL_OUT_OF_MEMORY: strcpy(error, "OUT_OF_MEMORY"); break; case GL_INVALID_FRAMEBUFFER_OPERATION: strcpy(error, "INVALID_FRAMEBUFFER_OPERATION"); break; } printf ( "GL_%s - %s : %d\n", error, file, line); err=glGetError(); } } virtual ~CFrameBufferObject() { freeResources(); } GLuint createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format) { GLuint texid; glGenTextures(1, &texid); glBindTexture(target, texid); if (format != GL_DEPTH_COMPONENT) { glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } else { glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (internalformat == GL_DEPTH_COMPONENT24) { glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_UNSIGNED_INT, 0); } else { glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_UNSIGNED_BYTE, 0); } check_gl_error(__FILE__, __LINE__); glBindTexture(target, 0); return texid; } void attachTexture(GLenum texTarget, GLuint texId, GLenum attachment = GL_COLOR_ATTACHMENT0, int mipLevel = 0, int zSlice = 0) { bindRenderPath(); check_gl_error(__FILE__, __LINE__); glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, texTarget, texId, mipLevel); checkStatus(__FILE__, __LINE__, false); unbindRenderPath(); } bool initialize(unsigned width, unsigned height, fboConfig &rConfigFBO, fboData &rActiveFBO) { //Framebuffer config options vector colorConfigs; vector depthConfigs; bufferConfig temp; //add default color configs temp.name = (m_bUseFloat ? "RGBA32F" : "RGBA8"); temp.bits = (m_bUseFloat ? 32 : 8); temp.format = (m_bUseFloat ? GL_RGBA32F : GL_RGBA8); colorConfigs.push_back(temp); //add default depth configs temp.name = "D24"; temp.bits = 24; temp.format = GL_DEPTH_COMPONENT24; depthConfigs.push_back(temp); // If the FBO can be created, add it to the list of available configs, and make a menu entry string root = colorConfigs[0].name + " " + depthConfigs[0].name; rConfigFBO.colorFormat = colorConfigs[0].format; rConfigFBO.depthFormat = depthConfigs[0].format; rConfigFBO.redbits = colorConfigs[0].bits; rConfigFBO.depthBits = depthConfigs[0].bits; //single sample rConfigFBO.name = root; rConfigFBO.coverageSamples = 0; rConfigFBO.depthSamples = 0; create(width, height, rConfigFBO, rActiveFBO); glBindFramebuffer(GL_FRAMEBUFFER, 0); return CHECK_FBO; } bool create(GLuint width, GLuint height, fboConfig &config, fboData &data) { bool multisample = config.depthSamples > 0; bool ret = true; GLint query; printf("\nCreating FBO <%s> (%dx%d) Float:%s\n", config.name.c_str(), (int)width, (int)height, (m_bUseFloat ? "Y":"N")); glGenFramebuffers(1, &data.fb); glGenTextures(1, &data.colorTex); // init texture glBindTexture(m_eGLTarget, data.colorTex); glTexImage2D(m_eGLTarget, 0, config.colorFormat, width, height, 0, GL_RGBA, (m_bUseFloat ? GL_FLOAT : GL_UNSIGNED_BYTE), NULL); glGenerateMipmap(m_eGLTarget); glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR); { glGenTextures(1, &data.depthTex); data.depthRB = 0; data.colorRB = 0; data.resolveFB = 0; //non-multisample, so bind things directly to the FBO glBindFramebuffer(GL_FRAMEBUFFER, data.fb); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_eGLTarget, data.colorTex, 0); glBindTexture(m_eGLTarget, data.depthTex); glTexImage2D(m_eGLTarget, 0, config.depthFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR); glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR); glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // glTexParameterf(m_eGLTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_eGLTarget, data.depthTex, 0); ret &= checkStatus(__FILE__, __LINE__, false); } glBindFramebuffer(GL_FRAMEBUFFER, data.fb); glGetIntegerv(GL_RED_BITS, &query); if (query != config.redbits) { ret = false; } glGetIntegerv(GL_DEPTH_BITS, &query); if (query != config.depthBits) { ret = false; } if (multisample) { glBindFramebuffer(GL_FRAMEBUFFER, data.resolveFB); glGetIntegerv(GL_RED_BITS, &query); if (query != config.redbits) { ret = false; } } glBindFramebuffer(GL_FRAMEBUFFER, 0); ret &= checkStatus(__FILE__, __LINE__, true); return ret; } virtual void freeResources() { if (m_fboData.fb) { glDeleteFramebuffers(1, &m_fboData.fb); } if (m_fboData.resolveFB) { glDeleteFramebuffers(1, &m_fboData.resolveFB); } if (m_fboData.colorRB) { glDeleteRenderbuffers(1, &m_fboData.colorRB); } if (m_fboData.depthRB) { glDeleteRenderbuffers(1, &m_fboData.depthRB); } if (m_fboData.colorTex) { glDeleteTextures(1, &m_fboData.colorTex); } if (m_fboData.depthTex) { glDeleteTextures(1, &m_fboData.depthTex); } glDeleteProgram(m_textureProgram); glDeleteProgram(m_overlayProgram); } virtual bool checkStatus(const char *zfile, int line, bool silent) { GLenum status; status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { printf("<%s : %d> - this one ", zfile, line); } switch (status) { case GL_FRAMEBUFFER_COMPLETE: break; case GL_FRAMEBUFFER_UNSUPPORTED: if (!silent) { printf("Unsupported framebuffer format\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: if (!silent) { printf("Framebuffer incomplete, missing attachment\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: if (!silent) { printf("Framebuffer incomplete, duplicate attachment\n"); } return false; default: assert(0); return false; } return true; } // bind to the FrameBuffer Object void bindRenderPath() { glBindFramebuffer(GL_FRAMEBUFFER, m_fboData.fb); } // release current FrameBuffer Object void unbindRenderPath() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } // bind to the FBO to Texture void bindTexture() { glBindTexture(m_eGLTarget, m_fboData.colorTex); } // release this bind void unbindTexture() { glBindTexture(m_eGLTarget, 0); } GLuint getFbo() { return m_fboData.fb; } GLuint getTex() { return m_fboData.colorTex; } GLuint getDepthTex() { return m_fboData.depthTex; } private: GLuint m_Width, m_Height; fboData m_fboData; fboConfig m_fboConfig; GLuint m_textureProgram; GLuint m_overlayProgram; bool m_bUseFloat; GLenum m_eGLTarget; }; // CheckFBO - render and verify contents of the FBO class CheckFBO: public CheckRender { public: CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp) : CheckRender(width, height, Bpp, false, false, true), m_pFrameBufferObject(NULL) { } CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp, CFrameBufferObject *pFrameBufferObject) : CheckRender(width, height, Bpp, false, true, true), m_pFrameBufferObject(pFrameBufferObject) { } void check_gl_error(const char *file, int line) { GLenum err (glGetError()); while(err!=GL_NO_ERROR) { char error[64]; switch(err) { case GL_INVALID_OPERATION: strcpy(error, "INVALID_OPERATION"); break; case GL_INVALID_ENUM: strcpy(error, "INVALID_ENUM"); break; case GL_INVALID_VALUE: strcpy(error, "INVALID_VALUE"); break; case GL_OUT_OF_MEMORY: strcpy(error, "OUT_OF_MEMORY"); break; case GL_INVALID_FRAMEBUFFER_OPERATION: strcpy(error, "INVALID_FRAMEBUFFER_OPERATION"); break; } printf ( "GL_%s - %s : %d\n", error, file, line); err=glGetError(); } } virtual ~CheckFBO() { } virtual bool checkStatus(const char *zfile, int line, bool silent) { GLenum status; status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { printf("<%s : %d> - here ", zfile, line); } switch (status) { case GL_FRAMEBUFFER_COMPLETE: break; case GL_FRAMEBUFFER_UNSUPPORTED: if (!silent) { printf("Unsupported framebuffer format\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: if (!silent) { printf("Framebuffer incomplete, missing attachment\n"); } return false; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: if (!silent) { printf("Framebuffer incomplete, duplicate attachment\n"); } return false; case GL_FRAMEBUFFER_UNDEFINED: if (!silent) { printf("Framebuffer undefined\n"); } return false; default: if (!silent) { printf("Framebuffer incomplete, default state\n"); } assert(0); return false; } return true; } virtual bool readback(GLuint width, GLuint height) { bool ret = false; if (m_bUsePBO) { // binds the PBO for readback bindReadback(); // bind FBO buffer (we want to transfer FBO -> PBO) glBindFramebuffer(GL_FRAMEBUFFER, m_pFrameBufferObject->getFbo()); ret = checkStatus(__FILE__, __LINE__, false); if (!ret) { printf("CheckFBO::readback() glBindFramebuffer checkStatus = %d\n", ret); } // Now initiate the readback to PBO glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); ret = checkStatus(__FILE__, __LINE__, false); check_gl_error(__FILE__, __LINE__); if (!ret) { printf("CheckFBO::readback() FBO->PBO checkStatus = %d\n", ret); } int nBufferSize = 0; glGetBufferParameteriv(GL_PIXEL_PACK_BUFFER, GL_BUFFER_SIZE, &nBufferSize); if (nBufferSize != width*height*m_Bpp) { printf("Buffer size incorrect, exiting..\n"); exit(EXIT_FAILURE); } // map - unmap simulates readback without the copy void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); check_gl_error(__FILE__, __LINE__); if (ioMem != NULL) { memcpy(m_pImageData, ioMem, width*height*m_Bpp); } else { printf("\nError: Unable to map the PBO\n"); exit(EXIT_FAILURE); } glUnmapBuffer(GL_PIXEL_PACK_BUFFER); // release the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); // release the PBO unbindReadback(); } else { // Reading back from FBO using glReadPixels glBindFramebuffer(GL_FRAMEBUFFER, m_pFrameBufferObject->getFbo()); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback::glBindFramebufferEXT() checkStatus = %d\n", ret); } glReadBuffer(static_cast(GL_COLOR_ATTACHMENT0)); ret &= checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback::glReadBuffer() checkStatus = %d\n", ret); } glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); glBindFramebuffer(GL_FRAMEBUFFER, 0); } return CHECK_FBO; } virtual bool readback(GLuint width, GLuint height, GLuint bufObject) { bool ret = false; if (m_bUseFBO) { if (m_bUsePBO) { printf("CheckFBO::readback() FBO->PBO->m_pImageData\n"); // binds the PBO for readback bindReadback(); // bind FBO buffer (we want to transfer FBO -> PBO) glBindFramebuffer(GL_FRAMEBUFFER, bufObject); // Now initiate the readback to PBO glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback() FBO->PBO checkStatus = %d\n", ret); } // map - unmap simulates readback without the copy void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); // release the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); // release the PBO unbindReadback(); } else { printf("CheckFBO::readback() FBO->m_pImageData\n"); // Reading direct to FBO using glReadPixels glBindFramebuffer(GL_FRAMEBUFFER, bufObject); ret = checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\n", (int)bufObject, (int)ret); } glReadBuffer(static_cast(GL_COLOR_ATTACHMENT0)); ret &= checkStatus(__FILE__, __LINE__, true); if (!ret) { printf("CheckFBO::readback::glReadBuffer() fbo=%d checkStatus = %d\n", (int)bufObject, (int)ret); } glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); glBindFramebuffer(GL_FRAMEBUFFER, 0); } } else { printf("CheckFBO::readback() PBO->m_pImageData\n"); // read from bufObject (PBO) to system memorys image glBindBuffer(GL_PIXEL_PACK_BUFFER, bufObject); // Bind the PBO // map - unmap simulates readback without the copy void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); memcpy(m_pImageData, ioMem, width*height*m_Bpp); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); // read from bufObject (PBO) to system memory image glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); // unBind the PBO } return CHECK_FBO; } virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf) { // let's flip the image as we copy for (unsigned int y = 0; y < height; y++) { memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp); } return true; } private: CFrameBufferObject *m_pFrameBufferObject; }; #endif // _RENDERCHECK_GLES_H_ ================================================ FILE: tests/projects/cuda/console/inc/timer.h ================================================ /** * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #ifndef TIMER_H #define TIMER_H #include #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #define WIN32_LEAN_AND_MEAN #include #else #include #endif #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) double PCFreq = 0.0; __int64 timerStart = 0; #else struct timeval timerStart; #endif void StartTimer() { #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) LARGE_INTEGER li; if (!QueryPerformanceFrequency(&li)) { printf("QueryPerformanceFrequency failed!\n"); } PCFreq = (double)li.QuadPart/1000.0; QueryPerformanceCounter(&li); timerStart = li.QuadPart; #else gettimeofday(&timerStart, NULL); #endif } // time elapsed in ms double GetTimer() { #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) LARGE_INTEGER li; QueryPerformanceCounter(&li); return (double)(li.QuadPart-timerStart)/PCFreq; #else struct timeval timerStop, timerElapsed; gettimeofday(&timerStop, NULL); timersub(&timerStop, &timerStart, &timerElapsed); return timerElapsed.tv_sec*1000.0+timerElapsed.tv_usec/1000.0; #endif } #endif // TIMER_H ================================================ FILE: tests/projects/cuda/console/src/main.cu ================================================ /* * Copyright 1993-2015 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ // System includes #include #include // CUDA runtime #include // helper functions and utilities to work with CUDA #include #include #ifndef MAX #define MAX(a,b) (a > b ? a : b) #endif __global__ void testKernel(int val) { printf("[%d, %d]:\t\tValue is:%d\n",\ blockIdx.y*gridDim.x+blockIdx.x,\ threadIdx.z*blockDim.x*blockDim.y+threadIdx.y*blockDim.x+threadIdx.x,\ val); } int main(int argc, char **argv) { int devID; cudaDeviceProp props; // This will pick the best possible CUDA capable device devID = findCudaDevice(argc, (const char **)argv); //Get GPU information checkCudaErrors(cudaGetDevice(&devID)); checkCudaErrors(cudaGetDeviceProperties(&props, devID)); printf("Device %d: \"%s\" with Compute %d.%d capability\n", devID, props.name, props.major, props.minor); printf("printf() is called. Output:\n\n"); //Kernel configuration, where a two-dimensional grid and //three-dimensional blocks are configured. dim3 dimGrid(2, 2); dim3 dimBlock(2, 2, 2); testKernel<<>>(10); cudaDeviceSynchronize(); return EXIT_SUCCESS; } ================================================ FILE: tests/projects/cuda/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("cuda_console") set_kind("binary") add_includedirs("inc") add_files("src/*.cu") -- generate SASS code for each SM architecture add_cugencodes("sm_75", "sm_80", "sm_89", "sm_90", "sm_100") -- generate PTX code from the highest SM architecture to guarantee forward-compatibility add_cugencodes("compute_100") ================================================ FILE: tests/projects/cuda/console_2/inc/lib.cuh ================================================ #pragma once __global__ void addKernel(int *c, const int *a, const int *b); ================================================ FILE: tests/projects/cuda/console_2/src/lib.cu ================================================ #include __global__ void addKernel(int *c, const int *a, const int *b) { int i = threadIdx.x; c[i] = a[i] + b[i]; } ================================================ FILE: tests/projects/cuda/console_2/src/main.cu ================================================ #include "cuda_runtime.h" #include "device_launch_parameters.h" #include #include cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size); int main() { const int arraySize = 5; const int a[arraySize] = {1, 2, 3, 4, 5}; const int b[arraySize] = {10, 20, 30, 40, 50}; int c[arraySize] = {0}; // Add vectors in parallel. cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addWithCuda failed!"); return 1; } printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n", c[0], c[1], c[2], c[3], c[4]); // cudaDeviceReset must be called before exiting in order for profiling and // tracing tools such as Nsight and Visual Profiler to show complete traces. cudaStatus = cudaDeviceReset(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaDeviceReset failed!"); return 1; } return 0; } // Helper function for using CUDA to add vectors in parallel. cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size) { int *dev_a = 0; int *dev_b = 0; int *dev_c = 0; cudaError_t cudaStatus; // Choose which GPU to run on, change this on a multi-GPU system. cudaStatus = cudaSetDevice(0); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?"); goto Error; } // Allocate GPU buffers for three vectors (two input, one output) . cudaStatus = cudaMalloc((void **)&dev_c, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void **)&dev_b, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } // Copy input vectors from host memory to GPU buffers. cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } // Launch a kernel on the GPU with one thread for each element. addKernel<<<1, size>>>(dev_c, dev_a, dev_b); // Check for any errors launching the kernel cudaStatus = cudaGetLastError(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus)); goto Error; } // cudaDeviceSynchronize waits for the kernel to finish, and returns // any errors encountered during the launch. cudaStatus = cudaDeviceSynchronize(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus); goto Error; } // Copy output vector from GPU buffer to host memory. cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } Error: cudaFree(dev_c); cudaFree(dev_a); cudaFree(dev_b); return cudaStatus; } ================================================ FILE: tests/projects/cuda/console_2/xmake.lua ================================================ add_rules("mode.debug", "mode.release") -- generate PTX code for the virtual architecture to guarantee compatibility add_cugencodes("compute_75") target("bin") set_kind("binary") add_includedirs("inc") add_files("src/*.cu") ================================================ FILE: tests/projects/cuda/shared/inc/lib.cuh ================================================ #pragma once #include "cuda_runtime.h" #include "device_launch_parameters.h" #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) #define __export __declspec(dllexport) #elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) #define __export __attribute__((visibility("default"))) #else #define __export #endif __export cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/cuda/shared/src/lib.cu ================================================ #include #include __global__ void addKernel(int *c, const int *a, const int *b) { int i = threadIdx.x; c[i] = a[i] + b[i]; } // Helper function for using CUDA to add vectors in parallel. cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size) { int *dev_a = 0; int *dev_b = 0; int *dev_c = 0; cudaError_t cudaStatus; // Choose which GPU to run on, change this on a multi-GPU system. cudaStatus = cudaSetDevice(0); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?"); goto Error; } // Allocate GPU buffers for three vectors (two input, one output) . cudaStatus = cudaMalloc((void **)&dev_c, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void **)&dev_b, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } // Copy input vectors from host memory to GPU buffers. cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } // Launch a kernel on the GPU with one thread for each element. addKernel<<<1, size>>>(dev_c, dev_a, dev_b); // Check for any errors launching the kernel cudaStatus = cudaGetLastError(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus)); goto Error; } // cudaDeviceSynchronize waits for the kernel to finish, and returns // any errors encountered during the launch. cudaStatus = cudaDeviceSynchronize(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus); goto Error; } // Copy output vector from GPU buffer to host memory. cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } Error: cudaFree(dev_c); cudaFree(dev_a); cudaFree(dev_b); return cudaStatus; } ================================================ FILE: tests/projects/cuda/shared/src/main.cu ================================================ #include "cuda_runtime.h" #include #include int main() { const int arraySize = 5; const int a[arraySize] = {1, 2, 3, 4, 5}; const int b[arraySize] = {10, 20, 30, 40, 50}; int c[arraySize] = {0}; // Add vectors in parallel. cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addWithCuda failed!"); return 1; } printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n", c[0], c[1], c[2], c[3], c[4]); // cudaDeviceReset must be called before exiting in order for profiling and // tracing tools such as Nsight and Visual Profiler to show complete traces. cudaStatus = cudaDeviceReset(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaDeviceReset failed!"); return 1; } return 0; } ================================================ FILE: tests/projects/cuda/shared/xmake.lua ================================================ add_rules("mode.debug", "mode.release") -- generate PTX code for the virtual architecture to guarantee compatibility add_cugencodes("compute_75") target("lib") set_kind("shared") add_files("src/lib.cu") add_includedirs("inc", {public = true}) target("bin") add_deps("lib") set_kind("binary") add_files("src/main.cu") ================================================ FILE: tests/projects/cuda/static/inc/lib.cuh ================================================ #pragma once __global__ void addKernel(int *c, const int *a, const int *b); ================================================ FILE: tests/projects/cuda/static/src/lib.cu ================================================ #include __global__ void addKernel(int *c, const int *a, const int *b) { int i = threadIdx.x; c[i] = a[i] + b[i]; } ================================================ FILE: tests/projects/cuda/static/src/main.cu ================================================ #include "cuda_runtime.h" #include "device_launch_parameters.h" #include #include cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size); int main() { const int arraySize = 5; const int a[arraySize] = {1, 2, 3, 4, 5}; const int b[arraySize] = {10, 20, 30, 40, 50}; int c[arraySize] = {0}; // Add vectors in parallel. cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addWithCuda failed!"); return 1; } printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n", c[0], c[1], c[2], c[3], c[4]); // cudaDeviceReset must be called before exiting in order for profiling and // tracing tools such as Nsight and Visual Profiler to show complete traces. cudaStatus = cudaDeviceReset(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaDeviceReset failed!"); return 1; } return 0; } // Helper function for using CUDA to add vectors in parallel. cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size) { int *dev_a = 0; int *dev_b = 0; int *dev_c = 0; cudaError_t cudaStatus; // Choose which GPU to run on, change this on a multi-GPU system. cudaStatus = cudaSetDevice(0); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?"); goto Error; } // Allocate GPU buffers for three vectors (two input, one output) . cudaStatus = cudaMalloc((void **)&dev_c, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void **)&dev_b, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } // Copy input vectors from host memory to GPU buffers. cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } // Launch a kernel on the GPU with one thread for each element. addKernel<<<1, size>>>(dev_c, dev_a, dev_b); // Check for any errors launching the kernel cudaStatus = cudaGetLastError(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus)); goto Error; } // cudaDeviceSynchronize waits for the kernel to finish, and returns // any errors encountered during the launch. cudaStatus = cudaDeviceSynchronize(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus); goto Error; } // Copy output vector from GPU buffer to host memory. cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } Error: cudaFree(dev_c); cudaFree(dev_a); cudaFree(dev_b); return cudaStatus; } ================================================ FILE: tests/projects/cuda/static/xmake.lua ================================================ add_rules("mode.debug", "mode.release") -- generate PTX code for the virtual architecture to guarantee compatibility add_cugencodes("compute_75") target("lib") set_kind("static") add_includedirs("inc", {public = true}) add_files("src/lib.cu") target("bin") add_deps("lib") set_kind("binary") add_files("src/main.cu") ================================================ FILE: tests/projects/dlang/console/src/main.d ================================================ import std.stdio; void main() { writeln("hello world!"); } ================================================ FILE: tests/projects/dlang/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.d") ================================================ FILE: tests/projects/dlang/console_with_pkgs/src/main.d ================================================ import std.stdio; import std.datetime; import util.log; import dateparser; void main() { log = Log(stderrLogger, stdoutLogger(LogLevel.info), fileLogger("log")); log.info("hello xmake"); assert(parse("2003-09-25") == SysTime(DateTime(2003, 9, 25))); assert(parse("09/25/2003") == SysTime(DateTime(2003, 9, 25))); assert(parse("Sep 2003") == SysTime(DateTime(2003, 9, 1))); } ================================================ FILE: tests/projects/dlang/console_with_pkgs/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("dub::log 0.4.3", {alias = "log"}) add_requires("dub::dateparser", {alias = "dateparser"}) add_requires("dub::emsi_containers", {alias = "emsi_containers"}) add_requires("dub::stdx-allocator", {alias = "stdx-allocator"}) add_requires("dub::mir-core", {alias = "mir-core"}) target("test") set_kind("binary") add_files("src/*.d") add_packages("log", "dateparser", "emsi_containers", "stdx-allocator", "mir-core") ================================================ FILE: tests/projects/dlang/dub_package/src/main.d ================================================ import util.log; void main() { log = Log(stderrLogger, stdoutLogger(LogLevel.info), fileLogger("log")); log.warn("test"); } ================================================ FILE: tests/projects/dlang/dub_package/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("dub::log 0.4.3") target("test") set_kind("binary") add_files("src/main.d") add_packages("dub::log") ================================================ FILE: tests/projects/dlang/shared_library/src/interfaces.d ================================================ version(Windows) { import core.sys.windows.windows; import core.sys.windows.dll; mixin SimpleDllMain; } extern(C) int add(int a, int b) { return a + b; } extern(C) int sub(int a, int b) { return a - b; } ================================================ FILE: tests/projects/dlang/shared_library/src/main.d ================================================ import std.stdio; import interfaces; void main() { printf("add: %d\n", interfaces.add(1, 1)); printf("sub: %d\n", interfaces.sub(2, 1)); } ================================================ FILE: tests/projects/dlang/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("interfaces") set_kind("shared") add_files("src/interfaces.d") add_includedirs("src", {public = true}) add_rules("utils.symbols.export_list", {symbols = { "add", "sub"}}) target("test") set_kind("binary") add_deps("interfaces") add_files("src/main.d") ================================================ FILE: tests/projects/dlang/static_library/src/interfaces.d ================================================ extern(C) int add(int a, int b) { return a + b; } extern(C) int sub(int a, int b) { return a - b; } ================================================ FILE: tests/projects/dlang/static_library/src/main.d ================================================ import std.stdio; import interfaces; void main() { printf("add: %d\n", interfaces.add(1, 1)); printf("sub: %d\n", interfaces.sub(2, 1)); } ================================================ FILE: tests/projects/dlang/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("interfaces") set_kind("static") add_files("src/interfaces.d") add_includedirs("src", {public = true}) target("test") set_kind("binary") add_deps("interfaces") add_files("src/main.d") ================================================ FILE: tests/projects/embed/c51/hello/src/main.c ================================================ #include #define REP(i, j) for(i = 0; i < j; ++i) sbit control = P3 ^ 2; void delay_ms(unsigned int n) { unsigned int i, j; for (j = n; j > 0; j--) for (i = 112; i > 0; i--); } int i; void set(unsigned int x) { P1 = x; delay_ms(100); } void left_fill() { REP(i, 8) set(0xFF >> i); } void right_fill() { REP(i, 8) set((0xFF >> (7 - i)) ^ 0xFF); } void left_erase() { REP(i, 8) set((0xFF >> (7 - i))); } void right_erase() { REP(i, 8) set((0xFF >> i) ^ 0xFF); } int main() { P1 = 0xFF; P3 = 0xFF; while (1) { if (control == 0) { left_fill(); left_erase(); right_fill(); right_erase(); } else { set(0x55); set(0xAA); } } } ================================================ FILE: tests/projects/embed/c51/hello/xmake.lua ================================================ target("hello") add_rules("c51.binary") set_toolchains("c51") add_files("src/main.c") ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/foo/foo.c ================================================ int foo(int x) { return x; } ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/gcc_arm.ld ================================================ /****************************************************************************** * @file gcc_arm.ld * @brief GNU Linker Script for Cortex-M based device * @version V2.1.0 * @date 04. August 2020 ******************************************************************************/ /* * Copyright (c) 2009-2020 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* *-------- <<< Use Configuration Wizard in Context Menu >>> ------------------- */ /*---------------------- Flash Configuration ---------------------------------- Flash Configuration Flash Base Address <0x0-0xFFFFFFFF:8> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8> -----------------------------------------------------------------------------*/ __ROM_BASE = 0x00000000; __ROM_SIZE = 0x00040000; /*--------------------- Embedded RAM Configuration ---------------------------- RAM Configuration RAM Base Address <0x0-0xFFFFFFFF:8> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8> -----------------------------------------------------------------------------*/ __RAM_BASE = 0x20000000; __RAM_SIZE = 0x00020000; /*--------------------- Stack / Heap Configuration ---------------------------- Stack / Heap Configuration Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> -----------------------------------------------------------------------------*/ __STACK_SIZE = 0x00000400; __HEAP_SIZE = 0x00000C00; /* *-------------------- <<< end of configuration section >>> ------------------- */ MEMORY { FLASH (rx) : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE RAM (rwx) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE } /* Linker script to place sections and symbol values. Should be used together * with other linker script that defines memory regions FLASH and RAM. * It references following symbols, which must be defined in code: * Reset_Handler : Entry of reset handler * * It defines following symbols, which code can use without definition: * __exidx_start * __exidx_end * __copy_table_start__ * __copy_table_end__ * __zero_table_start__ * __zero_table_end__ * __etext * __data_start__ * __preinit_array_start * __preinit_array_end * __init_array_start * __init_array_end * __fini_array_start * __fini_array_end * __data_end__ * __bss_start__ * __bss_end__ * __end__ * end * __HeapLimit * __StackLimit * __StackTop * __stack */ ENTRY(Reset_Handler) SECTIONS { .text : { KEEP(*(.vectors)) *(.text*) KEEP(*(.init)) KEEP(*(.fini)) /* .ctors */ *crtbegin.o(.ctors) *crtbegin?.o(.ctors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) *(SORT(.ctors.*)) *(.ctors) /* .dtors */ *crtbegin.o(.dtors) *crtbegin?.o(.dtors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) *(SORT(.dtors.*)) *(.dtors) *(.rodata*) KEEP(*(.eh_frame*)) } > FLASH /* * SG veneers: * All SG veneers are placed in the special output section .gnu.sgstubs. Its start address * must be set, either with the command line option --section-start or in a linker script, * to indicate where to place these veneers in memory. */ /* .gnu.sgstubs : { . = ALIGN(32); } > FLASH */ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > FLASH __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > FLASH __exidx_end = .; .copy.table : { . = ALIGN(4); __copy_table_start__ = .; LONG (__etext) LONG (__data_start__) LONG ((__data_end__ - __data_start__) / 4) /* Add each additional data section here */ /* LONG (__etext2) LONG (__data2_start__) LONG ((__data2_end__ - __data2_start__) / 4) */ __copy_table_end__ = .; } > FLASH .zero.table : { . = ALIGN(4); __zero_table_start__ = .; /* Add each additional bss section here */ /* LONG (__bss2_start__) LONG ((__bss2_end__ - __bss2_start__) / 4) */ __zero_table_end__ = .; } > FLASH /** * Location counter can end up 2byte aligned with narrow Thumb code but * __etext is assumed by startup code to be the LMA of a section in RAM * which must be 4byte aligned */ __etext = ALIGN (4); .data : AT (__etext) { __data_start__ = .; *(vtable) *(.data) *(.data.*) . = ALIGN(4); /* preinit data */ PROVIDE_HIDDEN (__preinit_array_start = .); KEEP(*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); . = ALIGN(4); /* init data */ PROVIDE_HIDDEN (__init_array_start = .); KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); . = ALIGN(4); /* finit data */ PROVIDE_HIDDEN (__fini_array_start = .); KEEP(*(SORT(.fini_array.*))) KEEP(*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .); KEEP(*(.jcr*)) . = ALIGN(4); /* All data end */ __data_end__ = .; } > RAM /* * Secondary data section, optional * * Remember to add each additional data section * to the .copy.table above to asure proper * initialization during startup. */ /* __etext2 = ALIGN (4); .data2 : AT (__etext2) { . = ALIGN(4); __data2_start__ = .; *(.data2) *(.data2.*) . = ALIGN(4); __data2_end__ = .; } > RAM2 */ .bss : { . = ALIGN(4); __bss_start__ = .; *(.bss) *(.bss.*) *(COMMON) . = ALIGN(4); __bss_end__ = .; } > RAM AT > RAM /* * Secondary bss section, optional * * Remember to add each additional bss section * to the .zero.table above to asure proper * initialization during startup. */ /* .bss2 : { . = ALIGN(4); __bss2_start__ = .; *(.bss2) *(.bss2.*) . = ALIGN(4); __bss2_end__ = .; } > RAM2 AT > RAM2 */ .heap (COPY) : { . = ALIGN(8); __end__ = .; PROVIDE(end = .); . = . + __HEAP_SIZE; . = ALIGN(8); __HeapLimit = .; } > RAM .stack (ORIGIN(RAM) + LENGTH(RAM) - __STACK_SIZE) (COPY) : { . = ALIGN(8); __StackLimit = .; . = . + __STACK_SIZE; . = ALIGN(8); __StackTop = .; } > RAM PROVIDE(__stack = __StackTop); /* Check if data + heap + stack exceeds RAM limit */ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") } ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/lib/cmsis/ARMCM3.h ================================================ /**************************************************************************//** * @file ARMCM3.h * @brief CMSIS Core Peripheral Access Layer Header File for * ARMCM3 Device * @version V5.3.1 * @date 09. July 2018 ******************************************************************************/ /* * Copyright (c) 2009-2018 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ARMCM3_H #define ARMCM3_H #ifdef __cplusplus extern "C" { #endif /* ------------------------- Interrupt Number Definition ------------------------ */ typedef enum IRQn { /* ------------------- Processor Exceptions Numbers ----------------------------- */ NonMaskableInt_IRQn = -14, /* 2 Non Maskable Interrupt */ HardFault_IRQn = -13, /* 3 HardFault Interrupt */ MemoryManagement_IRQn = -12, /* 4 Memory Management Interrupt */ BusFault_IRQn = -11, /* 5 Bus Fault Interrupt */ UsageFault_IRQn = -10, /* 6 Usage Fault Interrupt */ SVCall_IRQn = -5, /* 11 SV Call Interrupt */ DebugMonitor_IRQn = -4, /* 12 Debug Monitor Interrupt */ PendSV_IRQn = -2, /* 14 Pend SV Interrupt */ SysTick_IRQn = -1, /* 15 System Tick Interrupt */ /* ------------------- Processor Interrupt Numbers ------------------------------ */ Interrupt0_IRQn = 0, Interrupt1_IRQn = 1, Interrupt2_IRQn = 2, Interrupt3_IRQn = 3, Interrupt4_IRQn = 4, Interrupt5_IRQn = 5, Interrupt6_IRQn = 6, Interrupt7_IRQn = 7, Interrupt8_IRQn = 8, Interrupt9_IRQn = 9 /* Interrupts 10 .. 224 are left out */ } IRQn_Type; /* ================================================================================ */ /* ================ Processor and Core Peripheral Section ================ */ /* ================================================================================ */ /* ------- Start of section using anonymous unions and disabling warnings ------- */ #if defined (__CC_ARM) #pragma push #pragma anon_unions #elif defined (__ICCARM__) #pragma language=extended #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc11-extensions" #pragma clang diagnostic ignored "-Wreserved-id-macro" #elif defined (__GNUC__) /* anonymous unions are enabled by default */ #elif defined (__TMS470__) /* anonymous unions are enabled by default */ #elif defined (__TASKING__) #pragma warning 586 #elif defined (__CSMC__) /* anonymous unions are enabled by default */ #else #warning Not supported compiler type #endif /* -------- Configuration of Core Peripherals ----------------------------------- */ #define __CM3_REV 0x0201U /* Core revision r2p1 */ #define __MPU_PRESENT 1U /* MPU present */ #define __VTOR_PRESENT 1U /* VTOR present */ #define __NVIC_PRIO_BITS 3U /* Number of Bits used for Priority Levels */ #define __Vendor_SysTickConfig 0U /* Set to 1 if different SysTick Config is used */ #include "core_cm3.h" /* Processor and core peripherals */ #include "system_ARMCM3.h" /* System Header */ /* -------- End of section using anonymous unions and disabling warnings -------- */ #if defined (__CC_ARM) #pragma pop #elif defined (__ICCARM__) /* leave anonymous unions enabled */ #elif (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) #pragma clang diagnostic pop #elif defined (__GNUC__) /* anonymous unions are enabled by default */ #elif defined (__TMS470__) /* anonymous unions are enabled by default */ #elif defined (__TASKING__) #pragma warning restore #elif defined (__CSMC__) /* anonymous unions are enabled by default */ #else #warning Not supported compiler type #endif #ifdef __cplusplus } #endif #endif /* ARMCM3_H */ ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/lib/cmsis/cmsis_compiler.h ================================================ /**************************************************************************//** * @file cmsis_compiler.h * @brief CMSIS compiler generic header file * @version V5.1.0 * @date 09. October 2018 ******************************************************************************/ /* * Copyright (c) 2009-2018 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __CMSIS_COMPILER_H #define __CMSIS_COMPILER_H #include /* * Arm Compiler 4/5 */ #if defined ( __CC_ARM ) #include "cmsis_armcc.h" /* * Arm Compiler 6.6 LTM (armclang) */ #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100) #include "cmsis_armclang_ltm.h" /* * Arm Compiler above 6.10.1 (armclang) */ #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100) #include "cmsis_armclang.h" /* * GNU Compiler */ #elif defined ( __GNUC__ ) #include "cmsis_gcc.h" /* * IAR Compiler */ #elif defined ( __ICCARM__ ) #include /* * TI Arm Compiler */ #elif defined ( __TI_ARM__ ) #include #ifndef __ASM #define __ASM __asm #endif #ifndef __INLINE #define __INLINE inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE __STATIC_INLINE #endif #ifndef __NO_RETURN #define __NO_RETURN __attribute__((noreturn)) #endif #ifndef __USED #define __USED __attribute__((used)) #endif #ifndef __WEAK #define __WEAK __attribute__((weak)) #endif #ifndef __PACKED #define __PACKED __attribute__((packed)) #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT struct __attribute__((packed)) #endif #ifndef __PACKED_UNION #define __PACKED_UNION union __attribute__((packed)) #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ struct __attribute__((packed)) T_UINT32 { uint32_t v; }; #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) #endif #ifndef __UNALIGNED_UINT16_WRITE __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) #endif #ifndef __UNALIGNED_UINT32_WRITE __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) #endif #ifndef __ALIGNED #define __ALIGNED(x) __attribute__((aligned(x))) #endif #ifndef __RESTRICT #define __RESTRICT __restrict #endif #ifndef __COMPILER_BARRIER #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. #define __COMPILER_BARRIER() (void)0 #endif /* * TASKING Compiler */ #elif defined ( __TASKING__ ) /* * The CMSIS functions have been implemented as intrinsics in the compiler. * Please use "carm -?i" to get an up to date list of all intrinsics, * Including the CMSIS ones. */ #ifndef __ASM #define __ASM __asm #endif #ifndef __INLINE #define __INLINE inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE __STATIC_INLINE #endif #ifndef __NO_RETURN #define __NO_RETURN __attribute__((noreturn)) #endif #ifndef __USED #define __USED __attribute__((used)) #endif #ifndef __WEAK #define __WEAK __attribute__((weak)) #endif #ifndef __PACKED #define __PACKED __packed__ #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT struct __packed__ #endif #ifndef __PACKED_UNION #define __PACKED_UNION union __packed__ #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ struct __packed__ T_UINT32 { uint32_t v; }; #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) #endif #ifndef __UNALIGNED_UINT16_WRITE __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) #endif #ifndef __UNALIGNED_UINT32_WRITE __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) #endif #ifndef __ALIGNED #define __ALIGNED(x) __align(x) #endif #ifndef __RESTRICT #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. #define __RESTRICT #endif #ifndef __COMPILER_BARRIER #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. #define __COMPILER_BARRIER() (void)0 #endif /* * COSMIC Compiler */ #elif defined ( __CSMC__ ) #include #ifndef __ASM #define __ASM _asm #endif #ifndef __INLINE #define __INLINE inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE __STATIC_INLINE #endif #ifndef __NO_RETURN // NO RETURN is automatically detected hence no warning here #define __NO_RETURN #endif #ifndef __USED #warning No compiler specific solution for __USED. __USED is ignored. #define __USED #endif #ifndef __WEAK #define __WEAK __weak #endif #ifndef __PACKED #define __PACKED @packed #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT @packed struct #endif #ifndef __PACKED_UNION #define __PACKED_UNION @packed union #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ @packed struct T_UINT32 { uint32_t v; }; #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) #endif #ifndef __UNALIGNED_UINT16_WRITE __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) #endif #ifndef __UNALIGNED_UINT32_WRITE __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) #endif #ifndef __ALIGNED #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored. #define __ALIGNED(x) #endif #ifndef __RESTRICT #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. #define __RESTRICT #endif #ifndef __COMPILER_BARRIER #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. #define __COMPILER_BARRIER() (void)0 #endif #else #error Unknown compiler. #endif #endif /* __CMSIS_COMPILER_H */ ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/lib/cmsis/cmsis_gcc.h ================================================ /**************************************************************************//** * @file cmsis_gcc.h * @brief CMSIS compiler GCC header file * @version V5.4.1 * @date 27. May 2021 ******************************************************************************/ /* * Copyright (c) 2009-2021 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __CMSIS_GCC_H #define __CMSIS_GCC_H /* ignore some GCC warnings */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wunused-parameter" /* Fallback for __has_builtin */ #ifndef __has_builtin #define __has_builtin(x) (0) #endif /* CMSIS compiler specific defines */ #ifndef __ASM #define __ASM __asm #endif #ifndef __INLINE #define __INLINE inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline #endif #ifndef __NO_RETURN #define __NO_RETURN __attribute__((__noreturn__)) #endif #ifndef __USED #define __USED __attribute__((used)) #endif #ifndef __WEAK #define __WEAK __attribute__((weak)) #endif #ifndef __PACKED #define __PACKED __attribute__((packed, aligned(1))) #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) #endif #ifndef __PACKED_UNION #define __PACKED_UNION union __attribute__((packed, aligned(1))) #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpacked" #pragma GCC diagnostic ignored "-Wattributes" struct __attribute__((packed)) T_UINT32 { uint32_t v; }; #pragma GCC diagnostic pop #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) #endif #ifndef __UNALIGNED_UINT16_WRITE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpacked" #pragma GCC diagnostic ignored "-Wattributes" __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; #pragma GCC diagnostic pop #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpacked" #pragma GCC diagnostic ignored "-Wattributes" __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; #pragma GCC diagnostic pop #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) #endif #ifndef __UNALIGNED_UINT32_WRITE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpacked" #pragma GCC diagnostic ignored "-Wattributes" __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; #pragma GCC diagnostic pop #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpacked" #pragma GCC diagnostic ignored "-Wattributes" __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; #pragma GCC diagnostic pop #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) #endif #ifndef __ALIGNED #define __ALIGNED(x) __attribute__((aligned(x))) #endif #ifndef __RESTRICT #define __RESTRICT __restrict #endif #ifndef __COMPILER_BARRIER #define __COMPILER_BARRIER() __ASM volatile("":::"memory") #endif /* ######################### Startup and Lowlevel Init ######################## */ #ifndef __PROGRAM_START /** \brief Initializes data and bss sections \details This default implementations initialized all data and additional bss sections relying on .copy.table and .zero.table specified properly in the used linker script. */ __STATIC_FORCEINLINE __NO_RETURN void __cmsis_start(void) { extern void _start(void) __NO_RETURN; typedef struct { uint32_t const* src; uint32_t* dest; uint32_t wlen; } __copy_table_t; typedef struct { uint32_t* dest; uint32_t wlen; } __zero_table_t; extern const __copy_table_t __copy_table_start__; extern const __copy_table_t __copy_table_end__; extern const __zero_table_t __zero_table_start__; extern const __zero_table_t __zero_table_end__; for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) { for(uint32_t i=0u; iwlen; ++i) { pTable->dest[i] = pTable->src[i]; } } for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) { for(uint32_t i=0u; iwlen; ++i) { pTable->dest[i] = 0u; } } _start(); } #define __PROGRAM_START __cmsis_start #endif #ifndef __INITIAL_SP #define __INITIAL_SP __StackTop #endif #ifndef __STACK_LIMIT #define __STACK_LIMIT __StackLimit #endif #ifndef __VECTOR_TABLE #define __VECTOR_TABLE __Vectors #endif #ifndef __VECTOR_TABLE_ATTRIBUTE #define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section(".vectors"))) #endif #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) #ifndef __STACK_SEAL #define __STACK_SEAL __StackSeal #endif #ifndef __TZ_STACK_SEAL_SIZE #define __TZ_STACK_SEAL_SIZE 8U #endif #ifndef __TZ_STACK_SEAL_VALUE #define __TZ_STACK_SEAL_VALUE 0xFEF5EDA5FEF5EDA5ULL #endif __STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) { *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE; } #endif /* ########################## Core Instruction Access ######################### */ /** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface Access to dedicated instructions @{ */ /* Define macros for porting to both thumb1 and thumb2. * For thumb1, use low register (r0-r7), specified by constraint "l" * Otherwise, use general registers, specified by constraint "r" */ #if defined (__thumb__) && !defined (__thumb2__) #define __CMSIS_GCC_OUT_REG(r) "=l" (r) #define __CMSIS_GCC_RW_REG(r) "+l" (r) #define __CMSIS_GCC_USE_REG(r) "l" (r) #else #define __CMSIS_GCC_OUT_REG(r) "=r" (r) #define __CMSIS_GCC_RW_REG(r) "+r" (r) #define __CMSIS_GCC_USE_REG(r) "r" (r) #endif /** \brief No Operation \details No Operation does nothing. This instruction can be used for code alignment purposes. */ #define __NOP() __ASM volatile ("nop") /** \brief Wait For Interrupt \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. */ #define __WFI() __ASM volatile ("wfi":::"memory") /** \brief Wait For Event \details Wait For Event is a hint instruction that permits the processor to enter a low-power state until one of a number of events occurs. */ #define __WFE() __ASM volatile ("wfe":::"memory") /** \brief Send Event \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. */ #define __SEV() __ASM volatile ("sev") /** \brief Instruction Synchronization Barrier \details Instruction Synchronization Barrier flushes the pipeline in the processor, so that all instructions following the ISB are fetched from cache or memory, after the instruction has been completed. */ __STATIC_FORCEINLINE void __ISB(void) { __ASM volatile ("isb 0xF":::"memory"); } /** \brief Data Synchronization Barrier \details Acts as a special kind of Data Memory Barrier. It completes when all explicit memory accesses before this instruction complete. */ __STATIC_FORCEINLINE void __DSB(void) { __ASM volatile ("dsb 0xF":::"memory"); } /** \brief Data Memory Barrier \details Ensures the apparent order of the explicit memory operations before and after the instruction, without ensuring their completion. */ __STATIC_FORCEINLINE void __DMB(void) { __ASM volatile ("dmb 0xF":::"memory"); } /** \brief Reverse byte order (32 bit) \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. \param [in] value Value to reverse \return Reversed value */ __STATIC_FORCEINLINE uint32_t __REV(uint32_t value) { #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) return __builtin_bswap32(value); #else uint32_t result; __ASM ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); return result; #endif } /** \brief Reverse byte order (16 bit) \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. \param [in] value Value to reverse \return Reversed value */ __STATIC_FORCEINLINE uint32_t __REV16(uint32_t value) { uint32_t result; __ASM ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); return result; } /** \brief Reverse byte order (16 bit) \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. \param [in] value Value to reverse \return Reversed value */ __STATIC_FORCEINLINE int16_t __REVSH(int16_t value) { #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) return (int16_t)__builtin_bswap16(value); #else int16_t result; __ASM ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); return result; #endif } /** \brief Rotate Right in unsigned value (32 bit) \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. \param [in] op1 Value to rotate \param [in] op2 Number of Bits to rotate \return Rotated value */ __STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) { op2 %= 32U; if (op2 == 0U) { return op1; } return (op1 >> op2) | (op1 << (32U - op2)); } /** \brief Breakpoint \details Causes the processor to enter Debug state. Debug tools can use this to investigate system state when the instruction at a particular address is reached. \param [in] value is ignored by the processor. If required, a debugger can use it to store additional information about the breakpoint. */ #define __BKPT(value) __ASM volatile ("bkpt "#value) /** \brief Reverse bit order of value \details Reverses the bit order of the given value. \param [in] value Value to reverse \return Reversed value */ __STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value) { uint32_t result; #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) __ASM ("rbit %0, %1" : "=r" (result) : "r" (value) ); #else uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */ result = value; /* r will be reversed bits of v; first get LSB of v */ for (value >>= 1U; value != 0U; value >>= 1U) { result <<= 1U; result |= value & 1U; s--; } result <<= s; /* shift when v's highest bits are zero */ #endif return result; } /** \brief Count leading zeros \details Counts the number of leading zeros of a data value. \param [in] value Value to count the leading zeros \return number of leading zeros in value */ __STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) { /* Even though __builtin_clz produces a CLZ instruction on ARM, formally __builtin_clz(0) is undefined behaviour, so handle this case specially. This guarantees ARM-compatible results if happening to compile on a non-ARM target, and ensures the compiler doesn't decide to activate any optimisations using the logic "value was passed to __builtin_clz, so it is non-zero". ARM GCC 7.3 and possibly earlier will optimise this test away, leaving a single CLZ instruction. */ if (value == 0U) { return 32U; } return __builtin_clz(value); } #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) /** \brief LDR Exclusive (8 bit) \details Executes a exclusive LDR instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ __STATIC_FORCEINLINE uint8_t __LDREXB(volatile uint8_t *addr) { uint32_t result; #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) __ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) ); #else /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not accepted by assembler. So has to use following less efficient pattern. */ __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); #endif return ((uint8_t) result); /* Add explicit type cast here */ } /** \brief LDR Exclusive (16 bit) \details Executes a exclusive LDR instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ __STATIC_FORCEINLINE uint16_t __LDREXH(volatile uint16_t *addr) { uint32_t result; #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) __ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) ); #else /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not accepted by assembler. So has to use following less efficient pattern. */ __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); #endif return ((uint16_t) result); /* Add explicit type cast here */ } /** \brief LDR Exclusive (32 bit) \details Executes a exclusive LDR instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ __STATIC_FORCEINLINE uint32_t __LDREXW(volatile uint32_t *addr) { uint32_t result; __ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) ); return(result); } /** \brief STR Exclusive (8 bit) \details Executes a exclusive STR instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ __STATIC_FORCEINLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr) { uint32_t result; __ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); return(result); } /** \brief STR Exclusive (16 bit) \details Executes a exclusive STR instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ __STATIC_FORCEINLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr) { uint32_t result; __ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); return(result); } /** \brief STR Exclusive (32 bit) \details Executes a exclusive STR instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ __STATIC_FORCEINLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr) { uint32_t result; __ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); return(result); } /** \brief Remove the exclusive lock \details Removes the exclusive lock which is created by LDREX. */ __STATIC_FORCEINLINE void __CLREX(void) { __ASM volatile ("clrex" ::: "memory"); } #endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) /** \brief Signed Saturate \details Saturates a signed value. \param [in] ARG1 Value to be saturated \param [in] ARG2 Bit position to saturate to (1..32) \return Saturated value */ #define __SSAT(ARG1, ARG2) \ __extension__ \ ({ \ int32_t __RES, __ARG1 = (ARG1); \ __ASM volatile ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) : "cc" ); \ __RES; \ }) /** \brief Unsigned Saturate \details Saturates an unsigned value. \param [in] ARG1 Value to be saturated \param [in] ARG2 Bit position to saturate to (0..31) \return Saturated value */ #define __USAT(ARG1, ARG2) \ __extension__ \ ({ \ uint32_t __RES, __ARG1 = (ARG1); \ __ASM volatile ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) : "cc" ); \ __RES; \ }) /** \brief Rotate Right with Extend (32 bit) \details Moves each bit of a bitstring right by one bit. The carry input is shifted in at the left end of the bitstring. \param [in] value Value to rotate \return Rotated value */ __STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) { uint32_t result; __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); return(result); } /** \brief LDRT Unprivileged (8 bit) \details Executes a Unprivileged LDRT instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ __STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) { uint32_t result; #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); #else /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not accepted by assembler. So has to use following less efficient pattern. */ __ASM volatile ("ldrbt %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); #endif return ((uint8_t) result); /* Add explicit type cast here */ } /** \brief LDRT Unprivileged (16 bit) \details Executes a Unprivileged LDRT instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ __STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) { uint32_t result; #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); #else /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not accepted by assembler. So has to use following less efficient pattern. */ __ASM volatile ("ldrht %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); #endif return ((uint16_t) result); /* Add explicit type cast here */ } /** \brief LDRT Unprivileged (32 bit) \details Executes a Unprivileged LDRT instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ __STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) { uint32_t result; __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); return(result); } /** \brief STRT Unprivileged (8 bit) \details Executes a Unprivileged STRT instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) { __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } /** \brief STRT Unprivileged (16 bit) \details Executes a Unprivileged STRT instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) { __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } /** \brief STRT Unprivileged (32 bit) \details Executes a Unprivileged STRT instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) { __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); } #else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ /** \brief Signed Saturate \details Saturates a signed value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (1..32) \return Saturated value */ __STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) { if ((sat >= 1U) && (sat <= 32U)) { const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); const int32_t min = -1 - max ; if (val > max) { return max; } else if (val < min) { return min; } } return val; } /** \brief Unsigned Saturate \details Saturates an unsigned value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (0..31) \return Saturated value */ __STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) { if (sat <= 31U) { const uint32_t max = ((1U << sat) - 1U); if (val > (int32_t)max) { return max; } else if (val < 0) { return 0U; } } return (uint32_t)val; } #endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ #if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) /** \brief Load-Acquire (8 bit) \details Executes a LDAB instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ __STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) { uint32_t result; __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return ((uint8_t) result); } /** \brief Load-Acquire (16 bit) \details Executes a LDAH instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ __STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) { uint32_t result; __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return ((uint16_t) result); } /** \brief Load-Acquire (32 bit) \details Executes a LDA instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ __STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) { uint32_t result; __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return(result); } /** \brief Store-Release (8 bit) \details Executes a STLB instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) { __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); } /** \brief Store-Release (16 bit) \details Executes a STLH instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) { __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); } /** \brief Store-Release (32 bit) \details Executes a STL instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) { __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); } /** \brief Load-Acquire Exclusive (8 bit) \details Executes a LDAB exclusive instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ __STATIC_FORCEINLINE uint8_t __LDAEXB(volatile uint8_t *ptr) { uint32_t result; __ASM volatile ("ldaexb %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return ((uint8_t) result); } /** \brief Load-Acquire Exclusive (16 bit) \details Executes a LDAH exclusive instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ __STATIC_FORCEINLINE uint16_t __LDAEXH(volatile uint16_t *ptr) { uint32_t result; __ASM volatile ("ldaexh %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return ((uint16_t) result); } /** \brief Load-Acquire Exclusive (32 bit) \details Executes a LDA exclusive instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ __STATIC_FORCEINLINE uint32_t __LDAEX(volatile uint32_t *ptr) { uint32_t result; __ASM volatile ("ldaex %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return(result); } /** \brief Store-Release Exclusive (8 bit) \details Executes a STLB exclusive instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ __STATIC_FORCEINLINE uint32_t __STLEXB(uint8_t value, volatile uint8_t *ptr) { uint32_t result; __ASM volatile ("stlexb %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); return(result); } /** \brief Store-Release Exclusive (16 bit) \details Executes a STLH exclusive instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ __STATIC_FORCEINLINE uint32_t __STLEXH(uint16_t value, volatile uint16_t *ptr) { uint32_t result; __ASM volatile ("stlexh %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); return(result); } /** \brief Store-Release Exclusive (32 bit) \details Executes a STL exclusive instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ __STATIC_FORCEINLINE uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr) { uint32_t result; __ASM volatile ("stlex %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); return(result); } #endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ /*@}*/ /* end of group CMSIS_Core_InstructionInterface */ /* ########################### Core Function Access ########################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions @{ */ /** \brief Enable IRQ Interrupts \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __enable_irq(void) { __ASM volatile ("cpsie i" : : : "memory"); } /** \brief Disable IRQ Interrupts \details Disables IRQ interrupts by setting special-purpose register PRIMASK. Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __disable_irq(void) { __ASM volatile ("cpsid i" : : : "memory"); } /** \brief Get Control Register \details Returns the content of the Control Register. \return Control Register value */ __STATIC_FORCEINLINE uint32_t __get_CONTROL(void) { uint32_t result; __ASM volatile ("MRS %0, control" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Control Register (non-secure) \details Returns the content of the non-secure Control Register when in secure mode. \return non-secure Control Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) { uint32_t result; __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Control Register \details Writes the given value to the Control Register. \param [in] control Control Register value to set */ __STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) { __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); __ISB(); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Control Register (non-secure) \details Writes the given value to the non-secure Control Register when in secure state. \param [in] control Control Register value to set */ __STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) { __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); __ISB(); } #endif /** \brief Get IPSR Register \details Returns the content of the IPSR Register. \return IPSR Register value */ __STATIC_FORCEINLINE uint32_t __get_IPSR(void) { uint32_t result; __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); return(result); } /** \brief Get APSR Register \details Returns the content of the APSR Register. \return APSR Register value */ __STATIC_FORCEINLINE uint32_t __get_APSR(void) { uint32_t result; __ASM volatile ("MRS %0, apsr" : "=r" (result) ); return(result); } /** \brief Get xPSR Register \details Returns the content of the xPSR Register. \return xPSR Register value */ __STATIC_FORCEINLINE uint32_t __get_xPSR(void) { uint32_t result; __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); return(result); } /** \brief Get Process Stack Pointer \details Returns the current value of the Process Stack Pointer (PSP). \return PSP Register value */ __STATIC_FORCEINLINE uint32_t __get_PSP(void) { uint32_t result; __ASM volatile ("MRS %0, psp" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Process Stack Pointer (non-secure) \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. \return PSP Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) { uint32_t result; __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Process Stack Pointer \details Assigns the given value to the Process Stack Pointer (PSP). \param [in] topOfProcStack Process Stack Pointer value to set */ __STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) { __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Process Stack Pointer (non-secure) \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. \param [in] topOfProcStack Process Stack Pointer value to set */ __STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) { __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); } #endif /** \brief Get Main Stack Pointer \details Returns the current value of the Main Stack Pointer (MSP). \return MSP Register value */ __STATIC_FORCEINLINE uint32_t __get_MSP(void) { uint32_t result; __ASM volatile ("MRS %0, msp" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Main Stack Pointer (non-secure) \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. \return MSP Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) { uint32_t result; __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Main Stack Pointer \details Assigns the given value to the Main Stack Pointer (MSP). \param [in] topOfMainStack Main Stack Pointer value to set */ __STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) { __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Main Stack Pointer (non-secure) \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. \param [in] topOfMainStack Main Stack Pointer value to set */ __STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) { __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); } #endif #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Stack Pointer (non-secure) \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. \return SP Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) { uint32_t result; __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); return(result); } /** \brief Set Stack Pointer (non-secure) \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. \param [in] topOfStack Stack Pointer value to set */ __STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) { __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); } #endif /** \brief Get Priority Mask \details Returns the current state of the priority mask bit from the Priority Mask Register. \return Priority Mask value */ __STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) { uint32_t result; __ASM volatile ("MRS %0, primask" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Priority Mask (non-secure) \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. \return Priority Mask value */ __STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) { uint32_t result; __ASM volatile ("MRS %0, primask_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Priority Mask \details Assigns the given value to the Priority Mask Register. \param [in] priMask Priority Mask */ __STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) { __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Priority Mask (non-secure) \details Assigns the given value to the non-secure Priority Mask Register when in secure state. \param [in] priMask Priority Mask */ __STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) { __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); } #endif #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) /** \brief Enable FIQ \details Enables FIQ interrupts by clearing special-purpose register FAULTMASK. Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __enable_fault_irq(void) { __ASM volatile ("cpsie f" : : : "memory"); } /** \brief Disable FIQ \details Disables FIQ interrupts by setting special-purpose register FAULTMASK. Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __disable_fault_irq(void) { __ASM volatile ("cpsid f" : : : "memory"); } /** \brief Get Base Priority \details Returns the current value of the Base Priority register. \return Base Priority register value */ __STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) { uint32_t result; __ASM volatile ("MRS %0, basepri" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Base Priority (non-secure) \details Returns the current value of the non-secure Base Priority register when in secure state. \return Base Priority register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) { uint32_t result; __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Base Priority \details Assigns the given value to the Base Priority register. \param [in] basePri Base Priority value to set */ __STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) { __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Base Priority (non-secure) \details Assigns the given value to the non-secure Base Priority register when in secure state. \param [in] basePri Base Priority value to set */ __STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) { __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); } #endif /** \brief Set Base Priority with condition \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, or the new value increases the BASEPRI priority level. \param [in] basePri Base Priority value to set */ __STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) { __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); } /** \brief Get Fault Mask \details Returns the current value of the Fault Mask register. \return Fault Mask register value */ __STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) { uint32_t result; __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Fault Mask (non-secure) \details Returns the current value of the non-secure Fault Mask register when in secure state. \return Fault Mask register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) { uint32_t result; __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Fault Mask \details Assigns the given value to the Fault Mask register. \param [in] faultMask Fault Mask value to set */ __STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) { __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Fault Mask (non-secure) \details Assigns the given value to the non-secure Fault Mask register when in secure state. \param [in] faultMask Fault Mask value to set */ __STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) { __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); } #endif #endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ #if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) /** \brief Get Process Stack Pointer Limit Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence zero is returned always in non-secure mode. \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). \return PSPLIM Register value */ __STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) { #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) // without main extensions, the non-secure PSPLIM is RAZ/WI return 0U; #else uint32_t result; __ASM volatile ("MRS %0, psplim" : "=r" (result) ); return result; #endif } #if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Process Stack Pointer Limit (non-secure) Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence zero is returned always. \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. \return PSPLIM Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) { #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) // without main extensions, the non-secure PSPLIM is RAZ/WI return 0U; #else uint32_t result; __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); return result; #endif } #endif /** \brief Set Process Stack Pointer Limit Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence the write is silently ignored in non-secure mode. \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set */ __STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) { #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) // without main extensions, the non-secure PSPLIM is RAZ/WI (void)ProcStackPtrLimit; #else __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); #endif } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Process Stack Pointer (non-secure) Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence the write is silently ignored. \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set */ __STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) { #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) // without main extensions, the non-secure PSPLIM is RAZ/WI (void)ProcStackPtrLimit; #else __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); #endif } #endif /** \brief Get Main Stack Pointer Limit Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence zero is returned always in non-secure mode. \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). \return MSPLIM Register value */ __STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) { #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) // without main extensions, the non-secure MSPLIM is RAZ/WI return 0U; #else uint32_t result; __ASM volatile ("MRS %0, msplim" : "=r" (result) ); return result; #endif } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Main Stack Pointer Limit (non-secure) Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence zero is returned always. \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. \return MSPLIM Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) { #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) // without main extensions, the non-secure MSPLIM is RAZ/WI return 0U; #else uint32_t result; __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); return result; #endif } #endif /** \brief Set Main Stack Pointer Limit Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence the write is silently ignored in non-secure mode. \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set */ __STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) { #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) // without main extensions, the non-secure MSPLIM is RAZ/WI (void)MainStackPtrLimit; #else __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); #endif } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Main Stack Pointer Limit (non-secure) Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence the write is silently ignored. \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. \param [in] MainStackPtrLimit Main Stack Pointer value to set */ __STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) { #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) // without main extensions, the non-secure MSPLIM is RAZ/WI (void)MainStackPtrLimit; #else __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); #endif } #endif #endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ /** \brief Get FPSCR \details Returns the current value of the Floating Point Status/Control register. \return Floating Point Status/Control register value */ __STATIC_FORCEINLINE uint32_t __get_FPSCR(void) { #if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) #if __has_builtin(__builtin_arm_get_fpscr) // Re-enable using built-in when GCC has been fixed // || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ return __builtin_arm_get_fpscr(); #else uint32_t result; __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); return(result); #endif #else return(0U); #endif } /** \brief Set FPSCR \details Assigns the given value to the Floating Point Status/Control register. \param [in] fpscr Floating Point Status/Control value to set */ __STATIC_FORCEINLINE void __set_FPSCR(uint32_t fpscr) { #if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) #if __has_builtin(__builtin_arm_set_fpscr) // Re-enable using built-in when GCC has been fixed // || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ __builtin_arm_set_fpscr(fpscr); #else __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc", "memory"); #endif #else (void)fpscr; #endif } /*@} end of CMSIS_Core_RegAccFunctions */ /* ################### Compiler specific Intrinsics ########################### */ /** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics Access to dedicated SIMD instructions @{ */ #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) __STATIC_FORCEINLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("sadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("qadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("shadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("uadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uqadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uhadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("ssub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("qsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("shsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("usub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uqsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uhsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("sadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("qadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("shadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("uadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uqadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uhadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("ssub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("qsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("shsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("usub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uqsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uhsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SASX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("sasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __QASX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("qasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("shasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UASX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("uasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uqasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uhasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("ssax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("qsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("shsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __USAX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("usax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uqsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uhsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("usad8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; __ASM ("usada8 %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); return(result); } #define __SSAT16(ARG1, ARG2) \ __extension__ \ ({ \ int32_t __RES, __ARG1 = (ARG1); \ __ASM volatile ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) : "cc" ); \ __RES; \ }) #define __USAT16(ARG1, ARG2) \ __extension__ \ ({ \ uint32_t __RES, __ARG1 = (ARG1); \ __ASM volatile ("usat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) : "cc" ); \ __RES; \ }) __STATIC_FORCEINLINE uint32_t __UXTB16(uint32_t op1) { uint32_t result; __ASM ("uxtb16 %0, %1" : "=r" (result) : "r" (op1)); return(result); } __STATIC_FORCEINLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("uxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SXTB16(uint32_t op1) { uint32_t result; __ASM ("sxtb16 %0, %1" : "=r" (result) : "r" (op1)); return(result); } __STATIC_FORCEINLINE uint32_t __SXTB16_RORn(uint32_t op1, uint32_t rotate) { uint32_t result; if (__builtin_constant_p(rotate) && ((rotate == 8U) || (rotate == 16U) || (rotate == 24U))) { __ASM volatile ("sxtb16 %0, %1, ROR %2" : "=r" (result) : "r" (op1), "i" (rotate) ); } else { result = __SXTB16(__ROR(op1, rotate)) ; } return result; } __STATIC_FORCEINLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) { uint32_t result; __ASM ("sxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SXTAB16_RORn(uint32_t op1, uint32_t op2, uint32_t rotate) { uint32_t result; if (__builtin_constant_p(rotate) && ((rotate == 8U) || (rotate == 16U) || (rotate == 24U))) { __ASM volatile ("sxtab16 %0, %1, %2, ROR %3" : "=r" (result) : "r" (op1) , "r" (op2) , "i" (rotate)); } else { result = __SXTAB16(op1, __ROR(op2, rotate)); } return result; } __STATIC_FORCEINLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("smuad %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("smuadx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; __ASM volatile ("smlad %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); return(result); } __STATIC_FORCEINLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; __ASM volatile ("smladx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); return(result); } __STATIC_FORCEINLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; uint64_t w64; } llr; llr.w64 = acc; #ifndef __ARMEB__ /* Little endian */ __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); #else /* Big endian */ __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); #endif return(llr.w64); } __STATIC_FORCEINLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; uint64_t w64; } llr; llr.w64 = acc; #ifndef __ARMEB__ /* Little endian */ __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); #else /* Big endian */ __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); #endif return(llr.w64); } __STATIC_FORCEINLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("smusd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("smusdx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; __ASM volatile ("smlsd %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); return(result); } __STATIC_FORCEINLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) { uint32_t result; __ASM volatile ("smlsdx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); return(result); } __STATIC_FORCEINLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; uint64_t w64; } llr; llr.w64 = acc; #ifndef __ARMEB__ /* Little endian */ __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); #else /* Big endian */ __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); #endif return(llr.w64); } __STATIC_FORCEINLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) { union llreg_u{ uint32_t w32[2]; uint64_t w64; } llr; llr.w64 = acc; #ifndef __ARMEB__ /* Little endian */ __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); #else /* Big endian */ __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); #endif return(llr.w64); } __STATIC_FORCEINLINE uint32_t __SEL (uint32_t op1, uint32_t op2) { uint32_t result; __ASM volatile ("sel %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE int32_t __QADD( int32_t op1, int32_t op2) { int32_t result; __ASM volatile ("qadd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } __STATIC_FORCEINLINE int32_t __QSUB( int32_t op1, int32_t op2) { int32_t result; __ASM volatile ("qsub %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); return(result); } #define __PKHBT(ARG1,ARG2,ARG3) \ __extension__ \ ({ \ uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ __ASM ("pkhbt %0, %1, %2, lsl %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ __RES; \ }) #define __PKHTB(ARG1,ARG2,ARG3) \ __extension__ \ ({ \ uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ if (ARG3 == 0) \ __ASM ("pkhtb %0, %1, %2" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2) ); \ else \ __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ __RES; \ }) __STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) { int32_t result; __ASM ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); return(result); } #endif /* (__ARM_FEATURE_DSP == 1) */ /*@} end of group CMSIS_SIMD_intrinsics */ #pragma GCC diagnostic pop #endif /* __CMSIS_GCC_H */ ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/lib/cmsis/cmsis_version.h ================================================ /**************************************************************************//** * @file cmsis_version.h * @brief CMSIS Core(M) Version definitions * @version V5.0.4 * @date 23. July 2019 ******************************************************************************/ /* * Copyright (c) 2009-2019 ARM Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif #ifndef __CMSIS_VERSION_H #define __CMSIS_VERSION_H /* CMSIS Version definitions */ #define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ #define __CM_CMSIS_VERSION_SUB ( 4U) /*!< [15:0] CMSIS Core(M) sub version */ #define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ #endif ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/lib/cmsis/core_cm3.h ================================================ /**************************************************************************//** * @file core_cm3.h * @brief CMSIS Cortex-M3 Core Peripheral Access Layer Header File * @version V5.1.2 * @date 04. June 2021 ******************************************************************************/ /* * Copyright (c) 2009-2021 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif #ifndef __CORE_CM3_H_GENERIC #define __CORE_CM3_H_GENERIC #include #ifdef __cplusplus extern "C" { #endif /** \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions CMSIS violates the following MISRA-C:2004 rules: \li Required Rule 8.5, object/function definition in header file.
Function definitions in header files are used to allow 'inlining'. \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
Unions are used for effective representation of core registers. \li Advisory Rule 19.7, Function-like macro defined.
Function-like macros are used to allow more efficient code. */ /******************************************************************************* * CMSIS definitions ******************************************************************************/ /** \ingroup Cortex_M3 @{ */ #include "cmsis_version.h" /* CMSIS CM3 definitions */ #define __CM3_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ #define __CM3_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __CM3_CMSIS_VERSION ((__CM3_CMSIS_VERSION_MAIN << 16U) | \ __CM3_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ #define __CORTEX_M (3U) /*!< Cortex-M Core */ /** __FPU_USED indicates whether an FPU is used or not. This core does not support an FPU at all */ #define __FPU_USED 0U #if defined ( __CC_ARM ) #if defined __TARGET_FPU_VFP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) #if defined __ARM_FP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __GNUC__ ) #if defined (__VFP_FP__) && !defined(__SOFTFP__) #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __ICCARM__ ) #if defined __ARMVFP__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __TASKING__ ) #if defined __FPU_VFP__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __CSMC__ ) #if ( __CSMC__ & 0x400U) #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #endif #include "cmsis_compiler.h" /* CMSIS compiler specific defines */ #ifdef __cplusplus } #endif #endif /* __CORE_CM3_H_GENERIC */ #ifndef __CMSIS_GENERIC #ifndef __CORE_CM3_H_DEPENDANT #define __CORE_CM3_H_DEPENDANT #ifdef __cplusplus extern "C" { #endif /* check device defines and use defaults */ #if defined __CHECK_DEVICE_DEFINES #ifndef __CM3_REV #define __CM3_REV 0x0200U #warning "__CM3_REV not defined in device header file; using default!" #endif #ifndef __MPU_PRESENT #define __MPU_PRESENT 0U #warning "__MPU_PRESENT not defined in device header file; using default!" #endif #ifndef __VTOR_PRESENT #define __VTOR_PRESENT 1U #warning "__VTOR_PRESENT not defined in device header file; using default!" #endif #ifndef __NVIC_PRIO_BITS #define __NVIC_PRIO_BITS 3U #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" #endif #ifndef __Vendor_SysTickConfig #define __Vendor_SysTickConfig 0U #warning "__Vendor_SysTickConfig not defined in device header file; using default!" #endif #endif /* IO definitions (access restrictions to peripheral registers) */ /** \defgroup CMSIS_glob_defs CMSIS Global Defines IO Type Qualifiers are used \li to specify the access to peripheral variables. \li for automatic generation of peripheral register debug information. */ #ifdef __cplusplus #define __I volatile /*!< Defines 'read only' permissions */ #else #define __I volatile const /*!< Defines 'read only' permissions */ #endif #define __O volatile /*!< Defines 'write only' permissions */ #define __IO volatile /*!< Defines 'read / write' permissions */ /* following defines should be used for structure members */ #define __IM volatile const /*! Defines 'read only' structure member permissions */ #define __OM volatile /*! Defines 'write only' structure member permissions */ #define __IOM volatile /*! Defines 'read / write' structure member permissions */ /*@} end of group Cortex_M3 */ /******************************************************************************* * Register Abstraction Core Register contain: - Core Register - Core NVIC Register - Core SCB Register - Core SysTick Register - Core Debug Register - Core MPU Register ******************************************************************************/ /** \defgroup CMSIS_core_register Defines and Type Definitions \brief Type definitions and defines for Cortex-M processor based devices. */ /** \ingroup CMSIS_core_register \defgroup CMSIS_CORE Status and Control Registers \brief Core Register type definitions. @{ */ /** \brief Union type to access the Application Program Status Register (APSR). */ typedef union { struct { uint32_t _reserved0:27; /*!< bit: 0..26 Reserved */ uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ uint32_t C:1; /*!< bit: 29 Carry condition code flag */ uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ uint32_t N:1; /*!< bit: 31 Negative condition code flag */ } b; /*!< Structure used for bit access */ uint32_t w; /*!< Type used for word access */ } APSR_Type; /* APSR Register Definitions */ #define APSR_N_Pos 31U /*!< APSR: N Position */ #define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ #define APSR_Z_Pos 30U /*!< APSR: Z Position */ #define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ #define APSR_C_Pos 29U /*!< APSR: C Position */ #define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ #define APSR_V_Pos 28U /*!< APSR: V Position */ #define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ #define APSR_Q_Pos 27U /*!< APSR: Q Position */ #define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ /** \brief Union type to access the Interrupt Program Status Register (IPSR). */ typedef union { struct { uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ } b; /*!< Structure used for bit access */ uint32_t w; /*!< Type used for word access */ } IPSR_Type; /* IPSR Register Definitions */ #define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ #define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ /** \brief Union type to access the Special-Purpose Program Status Registers (xPSR). */ typedef union { struct { uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ uint32_t _reserved0:1; /*!< bit: 9 Reserved */ uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ uint32_t _reserved1:8; /*!< bit: 16..23 Reserved */ uint32_t T:1; /*!< bit: 24 Thumb bit */ uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ uint32_t C:1; /*!< bit: 29 Carry condition code flag */ uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ uint32_t N:1; /*!< bit: 31 Negative condition code flag */ } b; /*!< Structure used for bit access */ uint32_t w; /*!< Type used for word access */ } xPSR_Type; /* xPSR Register Definitions */ #define xPSR_N_Pos 31U /*!< xPSR: N Position */ #define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ #define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ #define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ #define xPSR_C_Pos 29U /*!< xPSR: C Position */ #define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ #define xPSR_V_Pos 28U /*!< xPSR: V Position */ #define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ #define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ #define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ #define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ #define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ #define xPSR_T_Pos 24U /*!< xPSR: T Position */ #define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ #define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ #define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ #define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ #define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ /** \brief Union type to access the Control Registers (CONTROL). */ typedef union { struct { uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ } b; /*!< Structure used for bit access */ uint32_t w; /*!< Type used for word access */ } CONTROL_Type; /* CONTROL Register Definitions */ #define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ #define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ #define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ #define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ /*@} end of group CMSIS_CORE */ /** \ingroup CMSIS_core_register \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) \brief Type definitions for the NVIC Registers @{ */ /** \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). */ typedef struct { __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[24U]; __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ uint32_t RESERVED1[24U]; __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[24U]; __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ uint32_t RESERVED3[24U]; __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ uint32_t RESERVED4[56U]; __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ uint32_t RESERVED5[644U]; __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ } NVIC_Type; /* Software Triggered Interrupt Register Definitions */ #define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ #define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ /*@} end of group CMSIS_NVIC */ /** \ingroup CMSIS_core_register \defgroup CMSIS_SCB System Control Block (SCB) \brief Type definitions for the System Control Block Registers @{ */ /** \brief Structure type to access the System Control Block (SCB). */ typedef struct { __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ uint32_t RESERVED0[5U]; __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ } SCB_Type; /* SCB CPUID Register Definitions */ #define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ #define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ #define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ #define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ #define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ #define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ #define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ #define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ #define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ #define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ /* SCB Interrupt Control State Register Definitions */ #define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ #define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ #define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ #define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ #define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ #define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ #define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ #define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ #define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ #define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ #define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ #define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ #define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ #define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ #define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ #define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ #define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ #define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ #define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ #define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ /* SCB Vector Table Offset Register Definitions */ #if defined (__CM3_REV) && (__CM3_REV < 0x0201U) /* core r2p1 */ #define SCB_VTOR_TBLBASE_Pos 29U /*!< SCB VTOR: TBLBASE Position */ #define SCB_VTOR_TBLBASE_Msk (1UL << SCB_VTOR_TBLBASE_Pos) /*!< SCB VTOR: TBLBASE Mask */ #define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ #define SCB_VTOR_TBLOFF_Msk (0x3FFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ #else #define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ #define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ #endif /* SCB Application Interrupt and Reset Control Register Definitions */ #define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ #define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ #define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ #define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ #define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ #define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ #define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ #define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ #define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ #define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ #define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ #define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ #define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ #define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ /* SCB System Control Register Definitions */ #define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ #define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ #define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ #define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ #define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ #define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ /* SCB Configuration Control Register Definitions */ #define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ #define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ #define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ #define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ #define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ #define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ #define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ #define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ #define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ #define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ #define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ #define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ /* SCB System Handler Control and State Register Definitions */ #define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ #define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ #define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ #define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ #define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ #define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ #define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ #define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ #define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ #define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ #define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ #define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ #define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ #define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ #define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ #define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ #define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ #define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ #define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ #define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ #define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ #define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ #define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ #define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ #define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ #define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ #define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ #define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ /* SCB Configurable Fault Status Register Definitions */ #define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ #define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ #define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ #define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ #define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ #define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ /* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ #define SCB_CFSR_MMARVALID_Pos (SCB_CFSR_MEMFAULTSR_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ #define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ #define SCB_CFSR_MSTKERR_Pos (SCB_CFSR_MEMFAULTSR_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ #define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ #define SCB_CFSR_MUNSTKERR_Pos (SCB_CFSR_MEMFAULTSR_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ #define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ #define SCB_CFSR_DACCVIOL_Pos (SCB_CFSR_MEMFAULTSR_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ #define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ #define SCB_CFSR_IACCVIOL_Pos (SCB_CFSR_MEMFAULTSR_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ #define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ /* BusFault Status Register (part of SCB Configurable Fault Status Register) */ #define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ #define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ #define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ #define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ #define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ #define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ #define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ #define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ #define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ #define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ #define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ #define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ /* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ #define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ #define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ #define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ #define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ #define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ #define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ #define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ #define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ #define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ #define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ #define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ #define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ /* SCB Hard Fault Status Register Definitions */ #define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ #define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ #define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ #define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ #define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ #define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ /* SCB Debug Fault Status Register Definitions */ #define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ #define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ #define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ #define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ #define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ #define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ #define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ #define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ #define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ #define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ /*@} end of group CMSIS_SCB */ /** \ingroup CMSIS_core_register \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) \brief Type definitions for the System Control and ID Register not in the SCB @{ */ /** \brief Structure type to access the System Control and ID Register not in the SCB. */ typedef struct { uint32_t RESERVED0[1U]; __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ #if defined (__CM3_REV) && (__CM3_REV >= 0x200U) __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ #else uint32_t RESERVED1[1U]; #endif } SCnSCB_Type; /* Interrupt Controller Type Register Definitions */ #define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ #define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ /* Auxiliary Control Register Definitions */ #if defined (__CM3_REV) && (__CM3_REV >= 0x200U) #define SCnSCB_ACTLR_DISOOFP_Pos 9U /*!< ACTLR: DISOOFP Position */ #define SCnSCB_ACTLR_DISOOFP_Msk (1UL << SCnSCB_ACTLR_DISOOFP_Pos) /*!< ACTLR: DISOOFP Mask */ #define SCnSCB_ACTLR_DISFPCA_Pos 8U /*!< ACTLR: DISFPCA Position */ #define SCnSCB_ACTLR_DISFPCA_Msk (1UL << SCnSCB_ACTLR_DISFPCA_Pos) /*!< ACTLR: DISFPCA Mask */ #define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ #define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ #define SCnSCB_ACTLR_DISDEFWBUF_Pos 1U /*!< ACTLR: DISDEFWBUF Position */ #define SCnSCB_ACTLR_DISDEFWBUF_Msk (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos) /*!< ACTLR: DISDEFWBUF Mask */ #define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ #define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ #endif /*@} end of group CMSIS_SCnotSCB */ /** \ingroup CMSIS_core_register \defgroup CMSIS_SysTick System Tick Timer (SysTick) \brief Type definitions for the System Timer Registers. @{ */ /** \brief Structure type to access the System Timer (SysTick). */ typedef struct { __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ } SysTick_Type; /* SysTick Control / Status Register Definitions */ #define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ #define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ #define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ #define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ #define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ #define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ #define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ #define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ /* SysTick Reload Register Definitions */ #define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ #define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ /* SysTick Current Register Definitions */ #define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ #define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ /* SysTick Calibration Register Definitions */ #define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ #define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ #define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ #define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ #define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ #define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ /*@} end of group CMSIS_SysTick */ /** \ingroup CMSIS_core_register \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) \brief Type definitions for the Instrumentation Trace Macrocell (ITM) @{ */ /** \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). */ typedef struct { __OM union { __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ uint32_t RESERVED0[864U]; __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ uint32_t RESERVED1[15U]; __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ uint32_t RESERVED2[15U]; __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ uint32_t RESERVED3[32U]; uint32_t RESERVED4[43U]; __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ uint32_t RESERVED5[6U]; __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ } ITM_Type; /* ITM Trace Privilege Register Definitions */ #define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ #define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ /* ITM Trace Control Register Definitions */ #define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ #define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ #define ITM_TCR_TraceBusID_Pos 16U /*!< ITM TCR: ATBID Position */ #define ITM_TCR_TraceBusID_Msk (0x7FUL << ITM_TCR_TraceBusID_Pos) /*!< ITM TCR: ATBID Mask */ #define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ #define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ #define ITM_TCR_TSPrescale_Pos 8U /*!< ITM TCR: TSPrescale Position */ #define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ #define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ #define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ #define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ #define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ #define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ #define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ #define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ #define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ #define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ #define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ /* ITM Lock Status Register Definitions */ #define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ #define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ #define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ #define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ #define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ #define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ /*@}*/ /* end of group CMSIS_ITM */ /** \ingroup CMSIS_core_register \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) \brief Type definitions for the Data Watchpoint and Trace (DWT) @{ */ /** \brief Structure type to access the Data Watchpoint and Trace Register (DWT). */ typedef struct { __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ uint32_t RESERVED0[1U]; __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ uint32_t RESERVED1[1U]; __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ uint32_t RESERVED2[1U]; __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ } DWT_Type; /* DWT Control Register Definitions */ #define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ #define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ #define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ #define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ #define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ #define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ #define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ #define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ #define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ #define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ #define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ #define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ #define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ #define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ #define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ #define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ #define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ #define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ #define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ #define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ #define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ #define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ #define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ #define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ #define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ #define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ #define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ #define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ #define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ #define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ #define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ #define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ #define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ #define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ #define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ #define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ /* DWT CPI Count Register Definitions */ #define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ #define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ /* DWT Exception Overhead Count Register Definitions */ #define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ #define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ /* DWT Sleep Count Register Definitions */ #define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ #define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ /* DWT LSU Count Register Definitions */ #define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ #define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ /* DWT Folded-instruction Count Register Definitions */ #define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ #define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ /* DWT Comparator Mask Register Definitions */ #define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ #define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ /* DWT Comparator Function Register Definitions */ #define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ #define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ #define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ #define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ #define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ #define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ #define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ #define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ #define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ #define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ #define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ #define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ #define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ #define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ #define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ #define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ #define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ #define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ /*@}*/ /* end of group CMSIS_DWT */ /** \ingroup CMSIS_core_register \defgroup CMSIS_TPI Trace Port Interface (TPI) \brief Type definitions for the Trace Port Interface (TPI) @{ */ /** \brief Structure type to access the Trace Port Interface Register (TPI). */ typedef struct { __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ uint32_t RESERVED0[2U]; __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ uint32_t RESERVED1[55U]; __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ uint32_t RESERVED2[131U]; __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ uint32_t RESERVED3[759U]; __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ uint32_t RESERVED4[1U]; __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ uint32_t RESERVED5[39U]; __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ uint32_t RESERVED7[8U]; __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ } TPI_Type; /* TPI Asynchronous Clock Prescaler Register Definitions */ #define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ #define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ /* TPI Selected Pin Protocol Register Definitions */ #define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ #define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ /* TPI Formatter and Flush Status Register Definitions */ #define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ #define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ #define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ #define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ #define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ #define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ #define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ #define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ /* TPI Formatter and Flush Control Register Definitions */ #define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ #define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ #define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ #define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ /* TPI TRIGGER Register Definitions */ #define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ #define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ /* TPI Integration ETM Data Register Definitions (FIFO0) */ #define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ #define TPI_FIFO0_ITM_ATVALID_Msk (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ #define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ #define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ #define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ #define TPI_FIFO0_ETM_ATVALID_Msk (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ #define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ #define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ #define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ #define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ #define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ #define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ #define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ #define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ /* TPI ITATBCTR2 Register Definitions */ #define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ #define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ #define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ #define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ /* TPI Integration ITM Data Register Definitions (FIFO1) */ #define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ #define TPI_FIFO1_ITM_ATVALID_Msk (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ #define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ #define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ #define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ #define TPI_FIFO1_ETM_ATVALID_Msk (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ #define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ #define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ #define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ #define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ #define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ #define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ #define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ #define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ /* TPI ITATBCTR0 Register Definitions */ #define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ #define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ #define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ #define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ /* TPI Integration Mode Control Register Definitions */ #define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ #define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ /* TPI DEVID Register Definitions */ #define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ #define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ #define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ #define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ #define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ #define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ #define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ #define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ #define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ #define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ #define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ #define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ /* TPI DEVTYPE Register Definitions */ #define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ #define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ #define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ #define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ /*@}*/ /* end of group CMSIS_TPI */ #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_MPU Memory Protection Unit (MPU) \brief Type definitions for the Memory Protection Unit (MPU) @{ */ /** \brief Structure type to access the Memory Protection Unit (MPU). */ typedef struct { __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ } MPU_Type; #define MPU_TYPE_RALIASES 4U /* MPU Type Register Definitions */ #define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ #define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ #define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ #define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ #define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ #define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ /* MPU Control Register Definitions */ #define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ #define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ #define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ #define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ #define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ #define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ /* MPU Region Number Register Definitions */ #define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ #define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ /* MPU Region Base Address Register Definitions */ #define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ #define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ #define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ #define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ #define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ #define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ /* MPU Region Attribute and Size Register Definitions */ #define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ #define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ #define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ #define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ #define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ #define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ #define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ #define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ #define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ #define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ #define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ #define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ #define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ #define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ #define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ #define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ #define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ #define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ #define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ #define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ /*@} end of group CMSIS_MPU */ #endif /** \ingroup CMSIS_core_register \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) \brief Type definitions for the Core Debug Registers @{ */ /** \brief Structure type to access the Core Debug Register (CoreDebug). */ typedef struct { __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ } CoreDebug_Type; /* Debug Halting Control and Status Register Definitions */ #define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ #define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ #define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ #define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ #define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ #define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ #define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ #define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ #define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ #define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ #define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ #define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ #define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ #define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ #define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ #define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ #define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ #define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ #define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ #define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ #define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ #define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ #define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ #define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ /* Debug Core Register Selector Register Definitions */ #define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ #define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ #define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ #define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ /* Debug Exception and Monitor Control Register Definitions */ #define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ #define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ #define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ #define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ #define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ #define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ #define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ #define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ #define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ #define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ #define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ #define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ #define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ #define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ #define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ #define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ #define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ #define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ #define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ #define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ #define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ #define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ #define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ #define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ #define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ #define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ /*@} end of group CMSIS_CoreDebug */ /** \ingroup CMSIS_core_register \defgroup CMSIS_core_bitfield Core register bit field macros \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). @{ */ /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ #define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ #define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ /** \ingroup CMSIS_core_register \defgroup CMSIS_core_base Core Definitions \brief Definitions for base addresses, unions, and structures. @{ */ /* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ #define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ #define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ #define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ #define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ #define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ #endif /*@} */ /******************************************************************************* * Hardware Abstraction Layer Core Function Interface contains: - Core NVIC Functions - Core SysTick Functions - Core Debug Functions - Core Register Access Functions ******************************************************************************/ /** \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference */ /* ########################## NVIC functions #################################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_NVICFunctions NVIC Functions \brief Functions that manage interrupts and exceptions via the NVIC. @{ */ #ifdef CMSIS_NVIC_VIRTUAL #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" #endif #include CMSIS_NVIC_VIRTUAL_HEADER_FILE #else #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping #define NVIC_EnableIRQ __NVIC_EnableIRQ #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ #define NVIC_DisableIRQ __NVIC_DisableIRQ #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ #define NVIC_GetActive __NVIC_GetActive #define NVIC_SetPriority __NVIC_SetPriority #define NVIC_GetPriority __NVIC_GetPriority #define NVIC_SystemReset __NVIC_SystemReset #endif /* CMSIS_NVIC_VIRTUAL */ #ifdef CMSIS_VECTAB_VIRTUAL #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" #endif #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE #else #define NVIC_SetVector __NVIC_SetVector #define NVIC_GetVector __NVIC_GetVector #endif /* (CMSIS_VECTAB_VIRTUAL) */ #define NVIC_USER_IRQ_OFFSET 16 /* The following EXC_RETURN values are saved the LR on exception entry */ #define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ #define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ #define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ /** \brief Set Priority Grouping \details Sets the priority grouping field using the required unlock sequence. The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. Only values from 0..7 are used. In case of a conflict between priority grouping and available priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. \param [in] PriorityGroup Priority grouping field. */ __STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ reg_value = SCB->AIRCR; /* read old register configuration */ reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ reg_value = (reg_value | ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ SCB->AIRCR = reg_value; } /** \brief Get Priority Grouping \details Reads the priority grouping field from the NVIC Interrupt Controller. \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). */ __STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) { return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); } /** \brief Enable Interrupt \details Enables a device specific interrupt in the NVIC interrupt controller. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { __COMPILER_BARRIER(); NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); __COMPILER_BARRIER(); } } /** \brief Get Interrupt Enable status \details Returns a device specific interrupt enable status from the NVIC interrupt controller. \param [in] IRQn Device specific interrupt number. \return 0 Interrupt is not enabled. \return 1 Interrupt is enabled. \note IRQn must not be negative. */ __STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); } else { return(0U); } } /** \brief Disable Interrupt \details Disables a device specific interrupt in the NVIC interrupt controller. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); __DSB(); __ISB(); } } /** \brief Get Pending Interrupt \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. \note IRQn must not be negative. */ __STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); } else { return(0U); } } /** \brief Set Pending Interrupt \details Sets the pending bit of a device specific interrupt in the NVIC pending register. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); } } /** \brief Clear Pending Interrupt \details Clears the pending bit of a device specific interrupt in the NVIC pending register. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); } } /** \brief Get Active Interrupt \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not active. \return 1 Interrupt status is active. \note IRQn must not be negative. */ __STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); } else { return(0U); } } /** \brief Set Interrupt Priority \details Sets the priority of a device specific interrupt or a processor exception. The interrupt number can be positive to specify a device specific interrupt, or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. \note The priority cannot be set for every processor exception. */ __STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { if ((int32_t)(IRQn) >= 0) { NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } else { SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } } /** \brief Get Interrupt Priority \details Reads the priority of a device specific interrupt or a processor exception. The interrupt number can be positive to specify a device specific interrupt, or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ __STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); } else { return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); } } /** \brief Encode Priority \details Encodes the priority for an interrupt with the given priority group, preemptive priority value, and subpriority value. In case of a conflict between priority grouping and available priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. \param [in] PriorityGroup Used priority group. \param [in] PreemptPriority Preemptive priority value (starting from 0). \param [in] SubPriority Subpriority value (starting from 0). \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). */ __STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) { uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ uint32_t PreemptPriorityBits; uint32_t SubPriorityBits; PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); return ( ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) ); } /** \brief Decode Priority \details Decodes an interrupt priority value with a given priority group to preemptive priority value and subpriority value. In case of a conflict between priority grouping and available priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). \param [in] PriorityGroup Used priority group. \param [out] pPreemptPriority Preemptive priority value (starting from 0). \param [out] pSubPriority Subpriority value (starting from 0). */ __STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) { uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ uint32_t PreemptPriorityBits; uint32_t SubPriorityBits; PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); } /** \brief Set Interrupt Vector \details Sets an interrupt vector in SRAM based interrupt vector table. The interrupt number can be positive to specify a device specific interrupt, or negative to specify a processor exception. VTOR must been relocated to SRAM before. \param [in] IRQn Interrupt number \param [in] vector Address of interrupt handler function */ __STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) { uint32_t *vectors = (uint32_t *)SCB->VTOR; vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; /* ARM Application Note 321 states that the M3 does not require the architectural barrier */ } /** \brief Get Interrupt Vector \details Reads an interrupt vector from interrupt vector table. The interrupt number can be positive to specify a device specific interrupt, or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Address of interrupt handler function */ __STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) { uint32_t *vectors = (uint32_t *)SCB->VTOR; return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; } /** \brief System Reset \details Initiates a system reset request to reset the MCU. */ __NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ __DSB(); /* Ensure completion of memory access */ for(;;) /* wait until reset */ { __NOP(); } } /*@} end of CMSIS_Core_NVICFunctions */ /* ########################## MPU functions #################################### */ #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #include "mpu_armv7.h" #endif /* ########################## FPU functions #################################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_FpuFunctions FPU Functions \brief Function that provides FPU type. @{ */ /** \brief get FPU type \details returns the FPU type \returns - \b 0: No FPU - \b 1: Single precision FPU - \b 2: Double + Single precision FPU */ __STATIC_INLINE uint32_t SCB_GetFPUType(void) { return 0U; /* No FPU */ } /*@} end of CMSIS_Core_FpuFunctions */ /* ################################## SysTick function ############################################ */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_SysTickFunctions SysTick Functions \brief Functions that configure the System. @{ */ #if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. Counter is in free running mode to generate periodic interrupts. \param [in] ticks Number of ticks between two interrupts. \return 0 Function succeeded. \return 1 Function failed. \note When the variable __Vendor_SysTickConfig is set to 1, then the function SysTick_Config is not included. In this case, the file device.h must contain a vendor-specific implementation of this function. */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); /* Reload value impossible */ } SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ return (0UL); /* Function successful */ } #endif /*@} end of CMSIS_Core_SysTickFunctions */ /* ##################################### Debug In/Output function ########################################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_core_DebugFunctions ITM Functions \brief Functions that access the ITM debug interface. @{ */ extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ #define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ /** \brief ITM Send Character \details Transmits a character via the ITM channel 0, and \li Just returns when no debugger is connected that has booked the output. \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. \param [in] ch Character to transmit. \returns Character to transmit. */ __STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) { if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ { while (ITM->PORT[0U].u32 == 0UL) { __NOP(); } ITM->PORT[0U].u8 = (uint8_t)ch; } return (ch); } /** \brief ITM Receive Character \details Inputs a character via the external variable \ref ITM_RxBuffer. \return Received character. \return -1 No character pending. */ __STATIC_INLINE int32_t ITM_ReceiveChar (void) { int32_t ch = -1; /* no character available */ if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) { ch = ITM_RxBuffer; ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ } return (ch); } /** \brief ITM Check Character \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. \return 0 No character available. \return 1 Character available. */ __STATIC_INLINE int32_t ITM_CheckChar (void) { if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) { return (0); /* no character available */ } else { return (1); /* character available */ } } /*@} end of CMSIS_core_DebugFunctions */ #ifdef __cplusplus } #endif #endif /* __CORE_CM3_H_DEPENDANT */ #endif /* __CMSIS_GENERIC */ ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/lib/cmsis/mpu_armv7.h ================================================ /****************************************************************************** * @file mpu_armv7.h * @brief CMSIS MPU API for Armv7-M MPU * @version V5.1.2 * @date 25. May 2020 ******************************************************************************/ /* * Copyright (c) 2017-2020 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif #ifndef ARM_MPU_ARMV7_H #define ARM_MPU_ARMV7_H #define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes #define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes #define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes #define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes #define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes #define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte #define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes #define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes #define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes #define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes #define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes #define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes #define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes #define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes #define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes #define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte #define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes #define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes #define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes #define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes #define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes #define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes #define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes #define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes #define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes #define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte #define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes #define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes #define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access #define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only #define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only #define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access #define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only #define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access /** MPU Region Base Address Register Value * * \param Region The region to be configured, number 0 to 15. * \param BaseAddress The base address for the region. */ #define ARM_MPU_RBAR(Region, BaseAddress) \ (((BaseAddress) & MPU_RBAR_ADDR_Msk) | \ ((Region) & MPU_RBAR_REGION_Msk) | \ (MPU_RBAR_VALID_Msk)) /** * MPU Memory Access Attributes * * \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. * \param IsShareable Region is shareable between multiple bus masters. * \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. * \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. */ #define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \ ((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \ (((IsShareable) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \ (((IsCacheable) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \ (((IsBufferable) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk)) /** * MPU Region Attribute and Size Register Value * * \param DisableExec Instruction access disable bit, 1= disable instruction fetches. * \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. * \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_. * \param SubRegionDisable Sub-region disable field. * \param Size Region size of the region to be configured, for example 4K, 8K. */ #define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \ ((((DisableExec) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \ (((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \ (((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \ (((SubRegionDisable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) | \ (((Size) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) | \ (((MPU_RASR_ENABLE_Msk)))) /** * MPU Region Attribute and Size Register Value * * \param DisableExec Instruction access disable bit, 1= disable instruction fetches. * \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. * \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. * \param IsShareable Region is shareable between multiple bus masters. * \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. * \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. * \param SubRegionDisable Sub-region disable field. * \param Size Region size of the region to be configured, for example 4K, 8K. */ #define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \ ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size) /** * MPU Memory Access Attribute for strongly ordered memory. * - TEX: 000b * - Shareable * - Non-cacheable * - Non-bufferable */ #define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U) /** * MPU Memory Access Attribute for device memory. * - TEX: 000b (if shareable) or 010b (if non-shareable) * - Shareable or non-shareable * - Non-cacheable * - Bufferable (if shareable) or non-bufferable (if non-shareable) * * \param IsShareable Configures the device memory as shareable or non-shareable. */ #define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U)) /** * MPU Memory Access Attribute for normal memory. * - TEX: 1BBb (reflecting outer cacheability rules) * - Shareable or non-shareable * - Cacheable or non-cacheable (reflecting inner cacheability rules) * - Bufferable or non-bufferable (reflecting inner cacheability rules) * * \param OuterCp Configures the outer cache policy. * \param InnerCp Configures the inner cache policy. * \param IsShareable Configures the memory as shareable or non-shareable. */ #define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) >> 1U), ((InnerCp) & 1U)) /** * MPU Memory Access Attribute non-cacheable policy. */ #define ARM_MPU_CACHEP_NOCACHE 0U /** * MPU Memory Access Attribute write-back, write and read allocate policy. */ #define ARM_MPU_CACHEP_WB_WRA 1U /** * MPU Memory Access Attribute write-through, no write allocate policy. */ #define ARM_MPU_CACHEP_WT_NWA 2U /** * MPU Memory Access Attribute write-back, no write allocate policy. */ #define ARM_MPU_CACHEP_WB_NWA 3U /** * Struct for a single MPU Region */ typedef struct { uint32_t RBAR; //!< The region base address register value (RBAR) uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR } ARM_MPU_Region_t; /** Enable the MPU. * \param MPU_Control Default access permissions for unconfigured regions. */ __STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control) { __DMB(); MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk; #ifdef SCB_SHCSR_MEMFAULTENA_Msk SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; #endif __DSB(); __ISB(); } /** Disable the MPU. */ __STATIC_INLINE void ARM_MPU_Disable(void) { __DMB(); #ifdef SCB_SHCSR_MEMFAULTENA_Msk SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; #endif MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk; __DSB(); __ISB(); } /** Clear and disable the given MPU region. * \param rnr Region number to be cleared. */ __STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr) { MPU->RNR = rnr; MPU->RASR = 0U; } /** Configure an MPU region. * \param rbar Value for RBAR register. * \param rasr Value for RASR register. */ __STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr) { MPU->RBAR = rbar; MPU->RASR = rasr; } /** Configure the given MPU region. * \param rnr Region number to be configured. * \param rbar Value for RBAR register. * \param rasr Value for RASR register. */ __STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr) { MPU->RNR = rnr; MPU->RBAR = rbar; MPU->RASR = rasr; } /** Memcpy with strictly ordered memory access, e.g. used by code in ARM_MPU_Load(). * \param dst Destination data is copied to. * \param src Source data is copied from. * \param len Amount of data words to be copied. */ __STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len) { uint32_t i; for (i = 0U; i < len; ++i) { dst[i] = src[i]; } } /** Load the given number of MPU regions from a table. * \param table Pointer to the MPU configuration table. * \param cnt Amount of regions to be configured. */ __STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt) { const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U; while (cnt > MPU_TYPE_RALIASES) { ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize); table += MPU_TYPE_RALIASES; cnt -= MPU_TYPE_RALIASES; } ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize); } #endif ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/lib/cmsis/system_ARMCM3.h ================================================ /**************************************************************************//** * @file system_ARMCM3.h * @brief CMSIS Device System Header File for * ARMCM3 Device * @version V5.3.2 * @date 15. November 2019 ******************************************************************************/ /* * Copyright (c) 2009-2019 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SYSTEM_ARMCM3_H #define SYSTEM_ARMCM3_H #ifdef __cplusplus extern "C" { #endif /** \brief Exception / Interrupt Handler Function Prototype */ typedef void(*VECTOR_TABLE_Type)(void); /** \brief System Clock Frequency (Core Clock) */ extern uint32_t SystemCoreClock; /** \brief Setup the microcontroller system. Initialize the System and update the SystemCoreClock variable. */ extern void SystemInit (void); /** \brief Update SystemCoreClock variable. Updates the SystemCoreClock with current core Clock retrieved from cpu registers. */ extern void SystemCoreClockUpdate (void); #ifdef __cplusplus } #endif #endif /* SYSTEM_ARMCM3_H */ ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/main.c ================================================ int foo(int x); int main() { return foo(1); } ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/startup_ARMCM3.S ================================================ /**************************************************************************//** * @file startup_ARMCM3.S * @brief CMSIS-Core(M) Device Startup File for Cortex-M3 Device * @version V2.2.0 * @date 26. May 2021 ******************************************************************************/ /* * Copyright (c) 2009-2021 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ .syntax unified .arch armv7-m .section .vectors .align 2 .globl __Vectors .globl __Vectors_End .globl __Vectors_Size __Vectors: .long __StackTop /* Top of Stack */ .long Reset_Handler /* Reset Handler */ .long NMI_Handler /* -14 NMI Handler */ .long HardFault_Handler /* -13 Hard Fault Handler */ .long MemManage_Handler /* -12 MPU Fault Handler */ .long BusFault_Handler /* -11 Bus Fault Handler */ .long UsageFault_Handler /* -10 Usage Fault Handler */ .long 0 /* Reserved */ .long 0 /* Reserved */ .long 0 /* Reserved */ .long 0 /* Reserved */ .long SVC_Handler /* -5 SVC Handler */ .long DebugMon_Handler /* -4 Debug Monitor Handler */ .long 0 /* Reserved */ .long PendSV_Handler /* -2 PendSV Handler */ .long SysTick_Handler /* -1 SysTick Handler */ /* Interrupts */ .long Interrupt0_Handler /* 0 Interrupt 0 */ .long Interrupt1_Handler /* 1 Interrupt 1 */ .long Interrupt2_Handler /* 2 Interrupt 2 */ .long Interrupt3_Handler /* 3 Interrupt 3 */ .long Interrupt4_Handler /* 4 Interrupt 4 */ .long Interrupt5_Handler /* 5 Interrupt 5 */ .long Interrupt6_Handler /* 6 Interrupt 6 */ .long Interrupt7_Handler /* 7 Interrupt 7 */ .long Interrupt8_Handler /* 8 Interrupt 8 */ .long Interrupt9_Handler /* 9 Interrupt 9 */ .space (214 * 4) /* Interrupts 10 .. 224 are left out */ __Vectors_End: .equ __Vectors_Size, __Vectors_End - __Vectors .size __Vectors, . - __Vectors .thumb .section .text .align 2 .thumb_func .type Reset_Handler, %function .globl Reset_Handler .fnstart Reset_Handler: bl SystemInit ldr r4, =__copy_table_start__ ldr r5, =__copy_table_end__ .L_loop0: cmp r4, r5 bge .L_loop0_done ldr r1, [r4] /* source address */ ldr r2, [r4, #4] /* destination address */ ldr r3, [r4, #8] /* word count */ lsls r3, r3, #2 /* byte count */ .L_loop0_0: subs r3, #4 /* decrement byte count */ ittt ge ldrge r0, [r1, r3] strge r0, [r2, r3] bge .L_loop0_0 adds r4, #12 b .L_loop0 .L_loop0_done: ldr r3, =__zero_table_start__ ldr r4, =__zero_table_end__ .L_loop2: cmp r3, r4 bge .L_loop2_done ldr r1, [r3] /* destination address */ ldr r2, [r3, #4] /* word count */ lsls r2, r2, #2 /* byte count */ movs r0, 0 .L_loop2_0: subs r2, #4 /* decrement byte count */ itt ge strge r0, [r1, r2] bge .L_loop2_0 adds r3, #8 b .L_loop2 .L_loop2_done: bl _start .fnend .size Reset_Handler, . - Reset_Handler /* The default macro is not used for HardFault_Handler * because this results in a poor debug illusion. */ .thumb_func .type HardFault_Handler, %function .weak HardFault_Handler .fnstart HardFault_Handler: b . .fnend .size HardFault_Handler, . - HardFault_Handler .thumb_func .type Default_Handler, %function .weak Default_Handler .fnstart Default_Handler: b . .fnend .size Default_Handler, . - Default_Handler /* Macro to define default exception/interrupt handlers. * Default handler are weak symbols with an endless loop. * They can be overwritten by real handlers. */ .macro Set_Default_Handler Handler_Name .weak \Handler_Name .set \Handler_Name, Default_Handler .endm /* Default exception/interrupt handler */ Set_Default_Handler NMI_Handler Set_Default_Handler MemManage_Handler Set_Default_Handler BusFault_Handler Set_Default_Handler UsageFault_Handler Set_Default_Handler SVC_Handler Set_Default_Handler DebugMon_Handler Set_Default_Handler PendSV_Handler Set_Default_Handler SysTick_Handler Set_Default_Handler Interrupt0_Handler Set_Default_Handler Interrupt1_Handler Set_Default_Handler Interrupt2_Handler Set_Default_Handler Interrupt3_Handler Set_Default_Handler Interrupt4_Handler Set_Default_Handler Interrupt5_Handler Set_Default_Handler Interrupt6_Handler Set_Default_Handler Interrupt7_Handler Set_Default_Handler Interrupt8_Handler Set_Default_Handler Interrupt9_Handler .end ================================================ FILE: tests/projects/embed/gnu-rm/hello/src/system_ARMCM3.c ================================================ /**************************************************************************//** * @file system_ARMCM3.c * @brief CMSIS Device System Source File for * ARMCM3 Device * @version V1.0.1 * @date 15. November 2019 ******************************************************************************/ /* * Copyright (c) 2009-2019 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ARMCM3.h" /*---------------------------------------------------------------------------- Define clocks *----------------------------------------------------------------------------*/ #define XTAL (50000000UL) /* Oscillator frequency */ #define SYSTEM_CLOCK (XTAL / 2U) /*---------------------------------------------------------------------------- Exception / Interrupt Vector table *----------------------------------------------------------------------------*/ extern const VECTOR_TABLE_Type __VECTOR_TABLE[240]; /*---------------------------------------------------------------------------- System Core Clock Variable *----------------------------------------------------------------------------*/ uint32_t SystemCoreClock = SYSTEM_CLOCK; /* System Core Clock Frequency */ /*---------------------------------------------------------------------------- System Core Clock update function *----------------------------------------------------------------------------*/ void SystemCoreClockUpdate (void) { SystemCoreClock = SYSTEM_CLOCK; } /*---------------------------------------------------------------------------- System initialization function *----------------------------------------------------------------------------*/ void SystemInit (void) { #if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) SCB->VTOR = (uint32_t) &(__VECTOR_TABLE[0]); #endif SystemCoreClock = SYSTEM_CLOCK; } ================================================ FILE: tests/projects/embed/gnu-rm/hello/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("gnu-rm") set_toolchains("@gnu-rm") set_plat("cross") set_arch("armv7") target("foo") add_rules("gnu-rm.static") add_files("src/foo/*.c") target("hello") add_deps("foo") add_rules("gnu-rm.binary") add_files("src/*.c", "src/*.S") add_files("src/*.ld") add_includedirs("src/lib/cmsis") ================================================ FILE: tests/projects/embed/iverilog/hello/src/main.v ================================================ module hello; initial begin $display("hello world!"); $finish ; end endmodule ================================================ FILE: tests/projects/embed/iverilog/hello/xmake.lua ================================================ add_requires("iverilog") target("hello") add_rules("iverilog.binary") set_toolchains("@iverilog") add_files("src/*.v") ================================================ FILE: tests/projects/embed/iverilog/hello_vcd/src/main.v ================================================ module hello; initial begin $display("hello world!"); $dumpfile("hello.vcd"); $dumpvars(0, hello); $finish ; end endmodule ================================================ FILE: tests/projects/embed/iverilog/hello_vcd/xmake.lua ================================================ add_requires("iverilog") target("hello") add_rules("iverilog.binary") set_toolchains("@iverilog") add_files("src/*.v") ================================================ FILE: tests/projects/embed/mdk/hello/src/foo/foo.c ================================================ int foo(int x) { return x; } ================================================ FILE: tests/projects/embed/mdk/hello/src/lib/cmsis/ARMCM3.h ================================================ /**************************************************************************//** * @file ARMCM3.h * @brief CMSIS Core Peripheral Access Layer Header File for * ARMCM3 Device * @version V5.3.1 * @date 09. July 2018 ******************************************************************************/ /* * Copyright (c) 2009-2018 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ARMCM3_H #define ARMCM3_H #ifdef __cplusplus extern "C" { #endif /* ------------------------- Interrupt Number Definition ------------------------ */ typedef enum IRQn { /* ------------------- Processor Exceptions Numbers ----------------------------- */ NonMaskableInt_IRQn = -14, /* 2 Non Maskable Interrupt */ HardFault_IRQn = -13, /* 3 HardFault Interrupt */ MemoryManagement_IRQn = -12, /* 4 Memory Management Interrupt */ BusFault_IRQn = -11, /* 5 Bus Fault Interrupt */ UsageFault_IRQn = -10, /* 6 Usage Fault Interrupt */ SVCall_IRQn = -5, /* 11 SV Call Interrupt */ DebugMonitor_IRQn = -4, /* 12 Debug Monitor Interrupt */ PendSV_IRQn = -2, /* 14 Pend SV Interrupt */ SysTick_IRQn = -1, /* 15 System Tick Interrupt */ /* ------------------- Processor Interrupt Numbers ------------------------------ */ Interrupt0_IRQn = 0, Interrupt1_IRQn = 1, Interrupt2_IRQn = 2, Interrupt3_IRQn = 3, Interrupt4_IRQn = 4, Interrupt5_IRQn = 5, Interrupt6_IRQn = 6, Interrupt7_IRQn = 7, Interrupt8_IRQn = 8, Interrupt9_IRQn = 9 /* Interrupts 10 .. 224 are left out */ } IRQn_Type; /* ================================================================================ */ /* ================ Processor and Core Peripheral Section ================ */ /* ================================================================================ */ /* ------- Start of section using anonymous unions and disabling warnings ------- */ #if defined (__CC_ARM) #pragma push #pragma anon_unions #elif defined (__ICCARM__) #pragma language=extended #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc11-extensions" #pragma clang diagnostic ignored "-Wreserved-id-macro" #elif defined (__GNUC__) /* anonymous unions are enabled by default */ #elif defined (__TMS470__) /* anonymous unions are enabled by default */ #elif defined (__TASKING__) #pragma warning 586 #elif defined (__CSMC__) /* anonymous unions are enabled by default */ #else #warning Not supported compiler type #endif /* -------- Configuration of Core Peripherals ----------------------------------- */ #define __CM3_REV 0x0201U /* Core revision r2p1 */ #define __MPU_PRESENT 1U /* MPU present */ #define __VTOR_PRESENT 1U /* VTOR present */ #define __NVIC_PRIO_BITS 3U /* Number of Bits used for Priority Levels */ #define __Vendor_SysTickConfig 0U /* Set to 1 if different SysTick Config is used */ #include "core_cm3.h" /* Processor and core peripherals */ #include "system_ARMCM3.h" /* System Header */ /* -------- End of section using anonymous unions and disabling warnings -------- */ #if defined (__CC_ARM) #pragma pop #elif defined (__ICCARM__) /* leave anonymous unions enabled */ #elif (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) #pragma clang diagnostic pop #elif defined (__GNUC__) /* anonymous unions are enabled by default */ #elif defined (__TMS470__) /* anonymous unions are enabled by default */ #elif defined (__TASKING__) #pragma warning restore #elif defined (__CSMC__) /* anonymous unions are enabled by default */ #else #warning Not supported compiler type #endif #ifdef __cplusplus } #endif #endif /* ARMCM3_H */ ================================================ FILE: tests/projects/embed/mdk/hello/src/lib/cmsis/cmsis_armcc.h ================================================ /**************************************************************************//** * @file cmsis_armcc.h * @brief CMSIS compiler ARMCC (Arm Compiler 5) header file * @version V5.3.2 * @date 27. May 2021 ******************************************************************************/ /* * Copyright (c) 2009-2021 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __CMSIS_ARMCC_H #define __CMSIS_ARMCC_H #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 400677) #error "Please use Arm Compiler Toolchain V4.0.677 or later!" #endif /* CMSIS compiler control architecture macros */ #if ((defined (__TARGET_ARCH_6_M ) && (__TARGET_ARCH_6_M == 1)) || \ (defined (__TARGET_ARCH_6S_M ) && (__TARGET_ARCH_6S_M == 1)) ) #define __ARM_ARCH_6M__ 1 #endif #if (defined (__TARGET_ARCH_7_M ) && (__TARGET_ARCH_7_M == 1)) #define __ARM_ARCH_7M__ 1 #endif #if (defined (__TARGET_ARCH_7E_M) && (__TARGET_ARCH_7E_M == 1)) #define __ARM_ARCH_7EM__ 1 #endif /* __ARM_ARCH_8M_BASE__ not applicable */ /* __ARM_ARCH_8M_MAIN__ not applicable */ /* __ARM_ARCH_8_1M_MAIN__ not applicable */ /* CMSIS compiler control DSP macros */ #if ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) #define __ARM_FEATURE_DSP 1 #endif /* CMSIS compiler specific defines */ #ifndef __ASM #define __ASM __asm #endif #ifndef __INLINE #define __INLINE __inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static __inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE static __forceinline #endif #ifndef __NO_RETURN #define __NO_RETURN __declspec(noreturn) #endif #ifndef __USED #define __USED __attribute__((used)) #endif #ifndef __WEAK #define __WEAK __attribute__((weak)) #endif #ifndef __PACKED #define __PACKED __attribute__((packed)) #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT __packed struct #endif #ifndef __PACKED_UNION #define __PACKED_UNION __packed union #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ #define __UNALIGNED_UINT32(x) (*((__packed uint32_t *)(x))) #endif #ifndef __UNALIGNED_UINT16_WRITE #define __UNALIGNED_UINT16_WRITE(addr, val) ((*((__packed uint16_t *)(addr))) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ #define __UNALIGNED_UINT16_READ(addr) (*((const __packed uint16_t *)(addr))) #endif #ifndef __UNALIGNED_UINT32_WRITE #define __UNALIGNED_UINT32_WRITE(addr, val) ((*((__packed uint32_t *)(addr))) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ #define __UNALIGNED_UINT32_READ(addr) (*((const __packed uint32_t *)(addr))) #endif #ifndef __ALIGNED #define __ALIGNED(x) __attribute__((aligned(x))) #endif #ifndef __RESTRICT #define __RESTRICT __restrict #endif #ifndef __COMPILER_BARRIER #define __COMPILER_BARRIER() __memory_changed() #endif /* ######################### Startup and Lowlevel Init ######################## */ #ifndef __PROGRAM_START #define __PROGRAM_START __main #endif #ifndef __INITIAL_SP #define __INITIAL_SP Image$$ARM_LIB_STACK$$ZI$$Limit #endif #ifndef __STACK_LIMIT #define __STACK_LIMIT Image$$ARM_LIB_STACK$$ZI$$Base #endif #ifndef __VECTOR_TABLE #define __VECTOR_TABLE __Vectors #endif #ifndef __VECTOR_TABLE_ATTRIBUTE #define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section("RESET"))) #endif /* ########################## Core Instruction Access ######################### */ /** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface Access to dedicated instructions @{ */ /** \brief No Operation \details No Operation does nothing. This instruction can be used for code alignment purposes. */ #define __NOP __nop /** \brief Wait For Interrupt \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. */ #define __WFI __wfi /** \brief Wait For Event \details Wait For Event is a hint instruction that permits the processor to enter a low-power state until one of a number of events occurs. */ #define __WFE __wfe /** \brief Send Event \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. */ #define __SEV __sev /** \brief Instruction Synchronization Barrier \details Instruction Synchronization Barrier flushes the pipeline in the processor, so that all instructions following the ISB are fetched from cache or memory, after the instruction has been completed. */ #define __ISB() __isb(0xF) /** \brief Data Synchronization Barrier \details Acts as a special kind of Data Memory Barrier. It completes when all explicit memory accesses before this instruction complete. */ #define __DSB() __dsb(0xF) /** \brief Data Memory Barrier \details Ensures the apparent order of the explicit memory operations before and after the instruction, without ensuring their completion. */ #define __DMB() __dmb(0xF) /** \brief Reverse byte order (32 bit) \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. \param [in] value Value to reverse \return Reversed value */ #define __REV __rev /** \brief Reverse byte order (16 bit) \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. \param [in] value Value to reverse \return Reversed value */ #ifndef __NO_EMBEDDED_ASM __attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(uint32_t value) { rev16 r0, r0 bx lr } #endif /** \brief Reverse byte order (16 bit) \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. \param [in] value Value to reverse \return Reversed value */ #ifndef __NO_EMBEDDED_ASM __attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int16_t __REVSH(int16_t value) { revsh r0, r0 bx lr } #endif /** \brief Rotate Right in unsigned value (32 bit) \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. \param [in] op1 Value to rotate \param [in] op2 Number of Bits to rotate \return Rotated value */ #define __ROR __ror /** \brief Breakpoint \details Causes the processor to enter Debug state. Debug tools can use this to investigate system state when the instruction at a particular address is reached. \param [in] value is ignored by the processor. If required, a debugger can use it to store additional information about the breakpoint. */ #define __BKPT(value) __breakpoint(value) /** \brief Reverse bit order of value \details Reverses the bit order of the given value. \param [in] value Value to reverse \return Reversed value */ #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) #define __RBIT __rbit #else __attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) { uint32_t result; uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */ result = value; /* r will be reversed bits of v; first get LSB of v */ for (value >>= 1U; value != 0U; value >>= 1U) { result <<= 1U; result |= value & 1U; s--; } result <<= s; /* shift when v's highest bits are zero */ return result; } #endif /** \brief Count leading zeros \details Counts the number of leading zeros of a data value. \param [in] value Value to count the leading zeros \return number of leading zeros in value */ #define __CLZ __clz #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) /** \brief LDR Exclusive (8 bit) \details Executes a exclusive LDR instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) #define __LDREXB(ptr) ((uint8_t ) __ldrex(ptr)) #else #define __LDREXB(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint8_t ) __ldrex(ptr)) _Pragma("pop") #endif /** \brief LDR Exclusive (16 bit) \details Executes a exclusive LDR instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) #define __LDREXH(ptr) ((uint16_t) __ldrex(ptr)) #else #define __LDREXH(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint16_t) __ldrex(ptr)) _Pragma("pop") #endif /** \brief LDR Exclusive (32 bit) \details Executes a exclusive LDR instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) #define __LDREXW(ptr) ((uint32_t ) __ldrex(ptr)) #else #define __LDREXW(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint32_t ) __ldrex(ptr)) _Pragma("pop") #endif /** \brief STR Exclusive (8 bit) \details Executes a exclusive STR instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) #define __STREXB(value, ptr) __strex(value, ptr) #else #define __STREXB(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") #endif /** \brief STR Exclusive (16 bit) \details Executes a exclusive STR instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) #define __STREXH(value, ptr) __strex(value, ptr) #else #define __STREXH(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") #endif /** \brief STR Exclusive (32 bit) \details Executes a exclusive STR instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) #define __STREXW(value, ptr) __strex(value, ptr) #else #define __STREXW(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") #endif /** \brief Remove the exclusive lock \details Removes the exclusive lock which is created by LDREX. */ #define __CLREX __clrex /** \brief Signed Saturate \details Saturates a signed value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (1..32) \return Saturated value */ #define __SSAT __ssat /** \brief Unsigned Saturate \details Saturates an unsigned value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (0..31) \return Saturated value */ #define __USAT __usat /** \brief Rotate Right with Extend (32 bit) \details Moves each bit of a bitstring right by one bit. The carry input is shifted in at the left end of the bitstring. \param [in] value Value to rotate \return Rotated value */ #ifndef __NO_EMBEDDED_ASM __attribute__((section(".rrx_text"))) __STATIC_INLINE __ASM uint32_t __RRX(uint32_t value) { rrx r0, r0 bx lr } #endif /** \brief LDRT Unprivileged (8 bit) \details Executes a Unprivileged LDRT instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ #define __LDRBT(ptr) ((uint8_t ) __ldrt(ptr)) /** \brief LDRT Unprivileged (16 bit) \details Executes a Unprivileged LDRT instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ #define __LDRHT(ptr) ((uint16_t) __ldrt(ptr)) /** \brief LDRT Unprivileged (32 bit) \details Executes a Unprivileged LDRT instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ #define __LDRT(ptr) ((uint32_t ) __ldrt(ptr)) /** \brief STRT Unprivileged (8 bit) \details Executes a Unprivileged STRT instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ #define __STRBT(value, ptr) __strt(value, ptr) /** \brief STRT Unprivileged (16 bit) \details Executes a Unprivileged STRT instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ #define __STRHT(value, ptr) __strt(value, ptr) /** \brief STRT Unprivileged (32 bit) \details Executes a Unprivileged STRT instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ #define __STRT(value, ptr) __strt(value, ptr) #else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ /** \brief Signed Saturate \details Saturates a signed value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (1..32) \return Saturated value */ __attribute__((always_inline)) __STATIC_INLINE int32_t __SSAT(int32_t val, uint32_t sat) { if ((sat >= 1U) && (sat <= 32U)) { const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); const int32_t min = -1 - max ; if (val > max) { return max; } else if (val < min) { return min; } } return val; } /** \brief Unsigned Saturate \details Saturates an unsigned value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (0..31) \return Saturated value */ __attribute__((always_inline)) __STATIC_INLINE uint32_t __USAT(int32_t val, uint32_t sat) { if (sat <= 31U) { const uint32_t max = ((1U << sat) - 1U); if (val > (int32_t)max) { return max; } else if (val < 0) { return 0U; } } return (uint32_t)val; } #endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ /*@}*/ /* end of group CMSIS_Core_InstructionInterface */ /* ########################### Core Function Access ########################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions @{ */ /** \brief Enable IRQ Interrupts \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. Can only be executed in Privileged modes. */ /* intrinsic void __enable_irq(); */ /** \brief Disable IRQ Interrupts \details Disables IRQ interrupts by setting special-purpose register PRIMASK. Can only be executed in Privileged modes. */ /* intrinsic void __disable_irq(); */ /** \brief Get Control Register \details Returns the content of the Control Register. \return Control Register value */ __STATIC_INLINE uint32_t __get_CONTROL(void) { register uint32_t __regControl __ASM("control"); return(__regControl); } /** \brief Set Control Register \details Writes the given value to the Control Register. \param [in] control Control Register value to set */ __STATIC_INLINE void __set_CONTROL(uint32_t control) { register uint32_t __regControl __ASM("control"); __regControl = control; __ISB(); } /** \brief Get IPSR Register \details Returns the content of the IPSR Register. \return IPSR Register value */ __STATIC_INLINE uint32_t __get_IPSR(void) { register uint32_t __regIPSR __ASM("ipsr"); return(__regIPSR); } /** \brief Get APSR Register \details Returns the content of the APSR Register. \return APSR Register value */ __STATIC_INLINE uint32_t __get_APSR(void) { register uint32_t __regAPSR __ASM("apsr"); return(__regAPSR); } /** \brief Get xPSR Register \details Returns the content of the xPSR Register. \return xPSR Register value */ __STATIC_INLINE uint32_t __get_xPSR(void) { register uint32_t __regXPSR __ASM("xpsr"); return(__regXPSR); } /** \brief Get Process Stack Pointer \details Returns the current value of the Process Stack Pointer (PSP). \return PSP Register value */ __STATIC_INLINE uint32_t __get_PSP(void) { register uint32_t __regProcessStackPointer __ASM("psp"); return(__regProcessStackPointer); } /** \brief Set Process Stack Pointer \details Assigns the given value to the Process Stack Pointer (PSP). \param [in] topOfProcStack Process Stack Pointer value to set */ __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) { register uint32_t __regProcessStackPointer __ASM("psp"); __regProcessStackPointer = topOfProcStack; } /** \brief Get Main Stack Pointer \details Returns the current value of the Main Stack Pointer (MSP). \return MSP Register value */ __STATIC_INLINE uint32_t __get_MSP(void) { register uint32_t __regMainStackPointer __ASM("msp"); return(__regMainStackPointer); } /** \brief Set Main Stack Pointer \details Assigns the given value to the Main Stack Pointer (MSP). \param [in] topOfMainStack Main Stack Pointer value to set */ __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) { register uint32_t __regMainStackPointer __ASM("msp"); __regMainStackPointer = topOfMainStack; } /** \brief Get Priority Mask \details Returns the current state of the priority mask bit from the Priority Mask Register. \return Priority Mask value */ __STATIC_INLINE uint32_t __get_PRIMASK(void) { register uint32_t __regPriMask __ASM("primask"); return(__regPriMask); } /** \brief Set Priority Mask \details Assigns the given value to the Priority Mask Register. \param [in] priMask Priority Mask */ __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) { register uint32_t __regPriMask __ASM("primask"); __regPriMask = (priMask); } #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) /** \brief Enable FIQ \details Enables FIQ interrupts by clearing special-purpose register FAULTMASK. Can only be executed in Privileged modes. */ #define __enable_fault_irq __enable_fiq /** \brief Disable FIQ \details Disables FIQ interrupts by setting special-purpose register FAULTMASK. Can only be executed in Privileged modes. */ #define __disable_fault_irq __disable_fiq /** \brief Get Base Priority \details Returns the current value of the Base Priority register. \return Base Priority register value */ __STATIC_INLINE uint32_t __get_BASEPRI(void) { register uint32_t __regBasePri __ASM("basepri"); return(__regBasePri); } /** \brief Set Base Priority \details Assigns the given value to the Base Priority register. \param [in] basePri Base Priority value to set */ __STATIC_INLINE void __set_BASEPRI(uint32_t basePri) { register uint32_t __regBasePri __ASM("basepri"); __regBasePri = (basePri & 0xFFU); } /** \brief Set Base Priority with condition \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, or the new value increases the BASEPRI priority level. \param [in] basePri Base Priority value to set */ __STATIC_INLINE void __set_BASEPRI_MAX(uint32_t basePri) { register uint32_t __regBasePriMax __ASM("basepri_max"); __regBasePriMax = (basePri & 0xFFU); } /** \brief Get Fault Mask \details Returns the current value of the Fault Mask register. \return Fault Mask register value */ __STATIC_INLINE uint32_t __get_FAULTMASK(void) { register uint32_t __regFaultMask __ASM("faultmask"); return(__regFaultMask); } /** \brief Set Fault Mask \details Assigns the given value to the Fault Mask register. \param [in] faultMask Fault Mask value to set */ __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) { register uint32_t __regFaultMask __ASM("faultmask"); __regFaultMask = (faultMask & (uint32_t)1U); } #endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ /** \brief Get FPSCR \details Returns the current value of the Floating Point Status/Control register. \return Floating Point Status/Control register value */ __STATIC_INLINE uint32_t __get_FPSCR(void) { #if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) register uint32_t __regfpscr __ASM("fpscr"); return(__regfpscr); #else return(0U); #endif } /** \brief Set FPSCR \details Assigns the given value to the Floating Point Status/Control register. \param [in] fpscr Floating Point Status/Control value to set */ __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) { #if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) register uint32_t __regfpscr __ASM("fpscr"); __regfpscr = (fpscr); #else (void)fpscr; #endif } /*@} end of CMSIS_Core_RegAccFunctions */ /* ################### Compiler specific Intrinsics ########################### */ /** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics Access to dedicated SIMD instructions @{ */ #if ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) #define __SADD8 __sadd8 #define __QADD8 __qadd8 #define __SHADD8 __shadd8 #define __UADD8 __uadd8 #define __UQADD8 __uqadd8 #define __UHADD8 __uhadd8 #define __SSUB8 __ssub8 #define __QSUB8 __qsub8 #define __SHSUB8 __shsub8 #define __USUB8 __usub8 #define __UQSUB8 __uqsub8 #define __UHSUB8 __uhsub8 #define __SADD16 __sadd16 #define __QADD16 __qadd16 #define __SHADD16 __shadd16 #define __UADD16 __uadd16 #define __UQADD16 __uqadd16 #define __UHADD16 __uhadd16 #define __SSUB16 __ssub16 #define __QSUB16 __qsub16 #define __SHSUB16 __shsub16 #define __USUB16 __usub16 #define __UQSUB16 __uqsub16 #define __UHSUB16 __uhsub16 #define __SASX __sasx #define __QASX __qasx #define __SHASX __shasx #define __UASX __uasx #define __UQASX __uqasx #define __UHASX __uhasx #define __SSAX __ssax #define __QSAX __qsax #define __SHSAX __shsax #define __USAX __usax #define __UQSAX __uqsax #define __UHSAX __uhsax #define __USAD8 __usad8 #define __USADA8 __usada8 #define __SSAT16 __ssat16 #define __USAT16 __usat16 #define __UXTB16 __uxtb16 #define __UXTAB16 __uxtab16 #define __SXTB16 __sxtb16 #define __SXTAB16 __sxtab16 #define __SMUAD __smuad #define __SMUADX __smuadx #define __SMLAD __smlad #define __SMLADX __smladx #define __SMLALD __smlald #define __SMLALDX __smlaldx #define __SMUSD __smusd #define __SMUSDX __smusdx #define __SMLSD __smlsd #define __SMLSDX __smlsdx #define __SMLSLD __smlsld #define __SMLSLDX __smlsldx #define __SEL __sel #define __QADD __qadd #define __QSUB __qsub #define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) #define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) #define __SMMLA(ARG1,ARG2,ARG3) ( (int32_t)((((int64_t)(ARG1) * (ARG2)) + \ ((int64_t)(ARG3) << 32U) ) >> 32U)) #define __SXTB16_RORn(ARG1, ARG2) __SXTB16(__ROR(ARG1, ARG2)) #define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3)) #endif /* ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ /*@} end of group CMSIS_SIMD_intrinsics */ #endif /* __CMSIS_ARMCC_H */ ================================================ FILE: tests/projects/embed/mdk/hello/src/lib/cmsis/cmsis_armclang.h ================================================ /**************************************************************************//** * @file cmsis_armclang.h * @brief CMSIS compiler armclang (Arm Compiler 6) header file * @version V5.4.3 * @date 27. May 2021 ******************************************************************************/ /* * Copyright (c) 2009-2021 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*lint -esym(9058, IRQn)*/ /* disable MISRA 2012 Rule 2.4 for IRQn */ #ifndef __CMSIS_ARMCLANG_H #define __CMSIS_ARMCLANG_H #pragma clang system_header /* treat file as system include file */ /* CMSIS compiler specific defines */ #ifndef __ASM #define __ASM __asm #endif #ifndef __INLINE #define __INLINE __inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static __inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline #endif #ifndef __NO_RETURN #define __NO_RETURN __attribute__((__noreturn__)) #endif #ifndef __USED #define __USED __attribute__((used)) #endif #ifndef __WEAK #define __WEAK __attribute__((weak)) #endif #ifndef __PACKED #define __PACKED __attribute__((packed, aligned(1))) #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) #endif #ifndef __PACKED_UNION #define __PACKED_UNION union __attribute__((packed, aligned(1))) #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpacked" /*lint -esym(9058, T_UINT32)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32 */ struct __attribute__((packed)) T_UINT32 { uint32_t v; }; #pragma clang diagnostic pop #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) #endif #ifndef __UNALIGNED_UINT16_WRITE #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpacked" /*lint -esym(9058, T_UINT16_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_WRITE */ __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; #pragma clang diagnostic pop #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpacked" /*lint -esym(9058, T_UINT16_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_READ */ __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; #pragma clang diagnostic pop #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) #endif #ifndef __UNALIGNED_UINT32_WRITE #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpacked" /*lint -esym(9058, T_UINT32_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_WRITE */ __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; #pragma clang diagnostic pop #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpacked" /*lint -esym(9058, T_UINT32_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_READ */ __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; #pragma clang diagnostic pop #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) #endif #ifndef __ALIGNED #define __ALIGNED(x) __attribute__((aligned(x))) #endif #ifndef __RESTRICT #define __RESTRICT __restrict #endif #ifndef __COMPILER_BARRIER #define __COMPILER_BARRIER() __ASM volatile("":::"memory") #endif /* ######################### Startup and Lowlevel Init ######################## */ #ifndef __PROGRAM_START #define __PROGRAM_START __main #endif #ifndef __INITIAL_SP #define __INITIAL_SP Image$$ARM_LIB_STACK$$ZI$$Limit #endif #ifndef __STACK_LIMIT #define __STACK_LIMIT Image$$ARM_LIB_STACK$$ZI$$Base #endif #ifndef __VECTOR_TABLE #define __VECTOR_TABLE __Vectors #endif #ifndef __VECTOR_TABLE_ATTRIBUTE #define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section("RESET"))) #endif #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) #ifndef __STACK_SEAL #define __STACK_SEAL Image$$STACKSEAL$$ZI$$Base #endif #ifndef __TZ_STACK_SEAL_SIZE #define __TZ_STACK_SEAL_SIZE 8U #endif #ifndef __TZ_STACK_SEAL_VALUE #define __TZ_STACK_SEAL_VALUE 0xFEF5EDA5FEF5EDA5ULL #endif __STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) { *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE; } #endif /* ########################## Core Instruction Access ######################### */ /** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface Access to dedicated instructions @{ */ /* Define macros for porting to both thumb1 and thumb2. * For thumb1, use low register (r0-r7), specified by constraint "l" * Otherwise, use general registers, specified by constraint "r" */ #if defined (__thumb__) && !defined (__thumb2__) #define __CMSIS_GCC_OUT_REG(r) "=l" (r) #define __CMSIS_GCC_RW_REG(r) "+l" (r) #define __CMSIS_GCC_USE_REG(r) "l" (r) #else #define __CMSIS_GCC_OUT_REG(r) "=r" (r) #define __CMSIS_GCC_RW_REG(r) "+r" (r) #define __CMSIS_GCC_USE_REG(r) "r" (r) #endif /** \brief No Operation \details No Operation does nothing. This instruction can be used for code alignment purposes. */ #define __NOP __builtin_arm_nop /** \brief Wait For Interrupt \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. */ #define __WFI __builtin_arm_wfi /** \brief Wait For Event \details Wait For Event is a hint instruction that permits the processor to enter a low-power state until one of a number of events occurs. */ #define __WFE __builtin_arm_wfe /** \brief Send Event \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. */ #define __SEV __builtin_arm_sev /** \brief Instruction Synchronization Barrier \details Instruction Synchronization Barrier flushes the pipeline in the processor, so that all instructions following the ISB are fetched from cache or memory, after the instruction has been completed. */ #define __ISB() __builtin_arm_isb(0xF) /** \brief Data Synchronization Barrier \details Acts as a special kind of Data Memory Barrier. It completes when all explicit memory accesses before this instruction complete. */ #define __DSB() __builtin_arm_dsb(0xF) /** \brief Data Memory Barrier \details Ensures the apparent order of the explicit memory operations before and after the instruction, without ensuring their completion. */ #define __DMB() __builtin_arm_dmb(0xF) /** \brief Reverse byte order (32 bit) \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. \param [in] value Value to reverse \return Reversed value */ #define __REV(value) __builtin_bswap32(value) /** \brief Reverse byte order (16 bit) \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. \param [in] value Value to reverse \return Reversed value */ #define __REV16(value) __ROR(__REV(value), 16) /** \brief Reverse byte order (16 bit) \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. \param [in] value Value to reverse \return Reversed value */ #define __REVSH(value) (int16_t)__builtin_bswap16(value) /** \brief Rotate Right in unsigned value (32 bit) \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. \param [in] op1 Value to rotate \param [in] op2 Number of Bits to rotate \return Rotated value */ __STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) { op2 %= 32U; if (op2 == 0U) { return op1; } return (op1 >> op2) | (op1 << (32U - op2)); } /** \brief Breakpoint \details Causes the processor to enter Debug state. Debug tools can use this to investigate system state when the instruction at a particular address is reached. \param [in] value is ignored by the processor. If required, a debugger can use it to store additional information about the breakpoint. */ #define __BKPT(value) __ASM volatile ("bkpt "#value) /** \brief Reverse bit order of value \details Reverses the bit order of the given value. \param [in] value Value to reverse \return Reversed value */ #define __RBIT __builtin_arm_rbit /** \brief Count leading zeros \details Counts the number of leading zeros of a data value. \param [in] value Value to count the leading zeros \return number of leading zeros in value */ __STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) { /* Even though __builtin_clz produces a CLZ instruction on ARM, formally __builtin_clz(0) is undefined behaviour, so handle this case specially. This guarantees ARM-compatible results if happening to compile on a non-ARM target, and ensures the compiler doesn't decide to activate any optimisations using the logic "value was passed to __builtin_clz, so it is non-zero". ARM Compiler 6.10 and possibly earlier will optimise this test away, leaving a single CLZ instruction. */ if (value == 0U) { return 32U; } return __builtin_clz(value); } #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) /** \brief LDR Exclusive (8 bit) \details Executes a exclusive LDR instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ #define __LDREXB (uint8_t)__builtin_arm_ldrex /** \brief LDR Exclusive (16 bit) \details Executes a exclusive LDR instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ #define __LDREXH (uint16_t)__builtin_arm_ldrex /** \brief LDR Exclusive (32 bit) \details Executes a exclusive LDR instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ #define __LDREXW (uint32_t)__builtin_arm_ldrex /** \brief STR Exclusive (8 bit) \details Executes a exclusive STR instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #define __STREXB (uint32_t)__builtin_arm_strex /** \brief STR Exclusive (16 bit) \details Executes a exclusive STR instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #define __STREXH (uint32_t)__builtin_arm_strex /** \brief STR Exclusive (32 bit) \details Executes a exclusive STR instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #define __STREXW (uint32_t)__builtin_arm_strex /** \brief Remove the exclusive lock \details Removes the exclusive lock which is created by LDREX. */ #define __CLREX __builtin_arm_clrex #endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) /** \brief Signed Saturate \details Saturates a signed value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (1..32) \return Saturated value */ #define __SSAT __builtin_arm_ssat /** \brief Unsigned Saturate \details Saturates an unsigned value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (0..31) \return Saturated value */ #define __USAT __builtin_arm_usat /** \brief Rotate Right with Extend (32 bit) \details Moves each bit of a bitstring right by one bit. The carry input is shifted in at the left end of the bitstring. \param [in] value Value to rotate \return Rotated value */ __STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) { uint32_t result; __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); return(result); } /** \brief LDRT Unprivileged (8 bit) \details Executes a Unprivileged LDRT instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ __STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) { uint32_t result; __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); return ((uint8_t) result); /* Add explicit type cast here */ } /** \brief LDRT Unprivileged (16 bit) \details Executes a Unprivileged LDRT instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ __STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) { uint32_t result; __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); return ((uint16_t) result); /* Add explicit type cast here */ } /** \brief LDRT Unprivileged (32 bit) \details Executes a Unprivileged LDRT instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ __STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) { uint32_t result; __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); return(result); } /** \brief STRT Unprivileged (8 bit) \details Executes a Unprivileged STRT instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) { __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } /** \brief STRT Unprivileged (16 bit) \details Executes a Unprivileged STRT instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) { __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); } /** \brief STRT Unprivileged (32 bit) \details Executes a Unprivileged STRT instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) { __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); } #else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ /** \brief Signed Saturate \details Saturates a signed value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (1..32) \return Saturated value */ __STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) { if ((sat >= 1U) && (sat <= 32U)) { const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); const int32_t min = -1 - max ; if (val > max) { return max; } else if (val < min) { return min; } } return val; } /** \brief Unsigned Saturate \details Saturates an unsigned value. \param [in] value Value to be saturated \param [in] sat Bit position to saturate to (0..31) \return Saturated value */ __STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) { if (sat <= 31U) { const uint32_t max = ((1U << sat) - 1U); if (val > (int32_t)max) { return max; } else if (val < 0) { return 0U; } } return (uint32_t)val; } #endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ #if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) /** \brief Load-Acquire (8 bit) \details Executes a LDAB instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ __STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) { uint32_t result; __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return ((uint8_t) result); } /** \brief Load-Acquire (16 bit) \details Executes a LDAH instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ __STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) { uint32_t result; __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return ((uint16_t) result); } /** \brief Load-Acquire (32 bit) \details Executes a LDA instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ __STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) { uint32_t result; __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); return(result); } /** \brief Store-Release (8 bit) \details Executes a STLB instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) { __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); } /** \brief Store-Release (16 bit) \details Executes a STLH instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) { __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); } /** \brief Store-Release (32 bit) \details Executes a STL instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location */ __STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) { __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); } /** \brief Load-Acquire Exclusive (8 bit) \details Executes a LDAB exclusive instruction for 8 bit value. \param [in] ptr Pointer to data \return value of type uint8_t at (*ptr) */ #define __LDAEXB (uint8_t)__builtin_arm_ldaex /** \brief Load-Acquire Exclusive (16 bit) \details Executes a LDAH exclusive instruction for 16 bit values. \param [in] ptr Pointer to data \return value of type uint16_t at (*ptr) */ #define __LDAEXH (uint16_t)__builtin_arm_ldaex /** \brief Load-Acquire Exclusive (32 bit) \details Executes a LDA exclusive instruction for 32 bit values. \param [in] ptr Pointer to data \return value of type uint32_t at (*ptr) */ #define __LDAEX (uint32_t)__builtin_arm_ldaex /** \brief Store-Release Exclusive (8 bit) \details Executes a STLB exclusive instruction for 8 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #define __STLEXB (uint32_t)__builtin_arm_stlex /** \brief Store-Release Exclusive (16 bit) \details Executes a STLH exclusive instruction for 16 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #define __STLEXH (uint32_t)__builtin_arm_stlex /** \brief Store-Release Exclusive (32 bit) \details Executes a STL exclusive instruction for 32 bit values. \param [in] value Value to store \param [in] ptr Pointer to location \return 0 Function succeeded \return 1 Function failed */ #define __STLEX (uint32_t)__builtin_arm_stlex #endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ /*@}*/ /* end of group CMSIS_Core_InstructionInterface */ /* ########################### Core Function Access ########################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions @{ */ /** \brief Enable IRQ Interrupts \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. Can only be executed in Privileged modes. */ #ifndef __ARM_COMPAT_H __STATIC_FORCEINLINE void __enable_irq(void) { __ASM volatile ("cpsie i" : : : "memory"); } #endif /** \brief Disable IRQ Interrupts \details Disables IRQ interrupts by setting special-purpose register PRIMASK. Can only be executed in Privileged modes. */ #ifndef __ARM_COMPAT_H __STATIC_FORCEINLINE void __disable_irq(void) { __ASM volatile ("cpsid i" : : : "memory"); } #endif /** \brief Get Control Register \details Returns the content of the Control Register. \return Control Register value */ __STATIC_FORCEINLINE uint32_t __get_CONTROL(void) { uint32_t result; __ASM volatile ("MRS %0, control" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Control Register (non-secure) \details Returns the content of the non-secure Control Register when in secure mode. \return non-secure Control Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) { uint32_t result; __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Control Register \details Writes the given value to the Control Register. \param [in] control Control Register value to set */ __STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) { __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); __ISB(); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Control Register (non-secure) \details Writes the given value to the non-secure Control Register when in secure state. \param [in] control Control Register value to set */ __STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) { __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); __ISB(); } #endif /** \brief Get IPSR Register \details Returns the content of the IPSR Register. \return IPSR Register value */ __STATIC_FORCEINLINE uint32_t __get_IPSR(void) { uint32_t result; __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); return(result); } /** \brief Get APSR Register \details Returns the content of the APSR Register. \return APSR Register value */ __STATIC_FORCEINLINE uint32_t __get_APSR(void) { uint32_t result; __ASM volatile ("MRS %0, apsr" : "=r" (result) ); return(result); } /** \brief Get xPSR Register \details Returns the content of the xPSR Register. \return xPSR Register value */ __STATIC_FORCEINLINE uint32_t __get_xPSR(void) { uint32_t result; __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); return(result); } /** \brief Get Process Stack Pointer \details Returns the current value of the Process Stack Pointer (PSP). \return PSP Register value */ __STATIC_FORCEINLINE uint32_t __get_PSP(void) { uint32_t result; __ASM volatile ("MRS %0, psp" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Process Stack Pointer (non-secure) \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. \return PSP Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) { uint32_t result; __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Process Stack Pointer \details Assigns the given value to the Process Stack Pointer (PSP). \param [in] topOfProcStack Process Stack Pointer value to set */ __STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) { __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Process Stack Pointer (non-secure) \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. \param [in] topOfProcStack Process Stack Pointer value to set */ __STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) { __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); } #endif /** \brief Get Main Stack Pointer \details Returns the current value of the Main Stack Pointer (MSP). \return MSP Register value */ __STATIC_FORCEINLINE uint32_t __get_MSP(void) { uint32_t result; __ASM volatile ("MRS %0, msp" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Main Stack Pointer (non-secure) \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. \return MSP Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) { uint32_t result; __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Main Stack Pointer \details Assigns the given value to the Main Stack Pointer (MSP). \param [in] topOfMainStack Main Stack Pointer value to set */ __STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) { __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Main Stack Pointer (non-secure) \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. \param [in] topOfMainStack Main Stack Pointer value to set */ __STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) { __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); } #endif #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Stack Pointer (non-secure) \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. \return SP Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) { uint32_t result; __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); return(result); } /** \brief Set Stack Pointer (non-secure) \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. \param [in] topOfStack Stack Pointer value to set */ __STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) { __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); } #endif /** \brief Get Priority Mask \details Returns the current state of the priority mask bit from the Priority Mask Register. \return Priority Mask value */ __STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) { uint32_t result; __ASM volatile ("MRS %0, primask" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Priority Mask (non-secure) \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. \return Priority Mask value */ __STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) { uint32_t result; __ASM volatile ("MRS %0, primask_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Priority Mask \details Assigns the given value to the Priority Mask Register. \param [in] priMask Priority Mask */ __STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) { __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Priority Mask (non-secure) \details Assigns the given value to the non-secure Priority Mask Register when in secure state. \param [in] priMask Priority Mask */ __STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) { __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); } #endif #if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) /** \brief Enable FIQ \details Enables FIQ interrupts by clearing special-purpose register FAULTMASK. Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __enable_fault_irq(void) { __ASM volatile ("cpsie f" : : : "memory"); } /** \brief Disable FIQ \details Disables FIQ interrupts by setting special-purpose register FAULTMASK. Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __disable_fault_irq(void) { __ASM volatile ("cpsid f" : : : "memory"); } /** \brief Get Base Priority \details Returns the current value of the Base Priority register. \return Base Priority register value */ __STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) { uint32_t result; __ASM volatile ("MRS %0, basepri" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Base Priority (non-secure) \details Returns the current value of the non-secure Base Priority register when in secure state. \return Base Priority register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) { uint32_t result; __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Base Priority \details Assigns the given value to the Base Priority register. \param [in] basePri Base Priority value to set */ __STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) { __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Base Priority (non-secure) \details Assigns the given value to the non-secure Base Priority register when in secure state. \param [in] basePri Base Priority value to set */ __STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) { __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); } #endif /** \brief Set Base Priority with condition \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, or the new value increases the BASEPRI priority level. \param [in] basePri Base Priority value to set */ __STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) { __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); } /** \brief Get Fault Mask \details Returns the current value of the Fault Mask register. \return Fault Mask register value */ __STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) { uint32_t result; __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); return(result); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Fault Mask (non-secure) \details Returns the current value of the non-secure Fault Mask register when in secure state. \return Fault Mask register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) { uint32_t result; __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); return(result); } #endif /** \brief Set Fault Mask \details Assigns the given value to the Fault Mask register. \param [in] faultMask Fault Mask value to set */ __STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) { __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Fault Mask (non-secure) \details Assigns the given value to the non-secure Fault Mask register when in secure state. \param [in] faultMask Fault Mask value to set */ __STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) { __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); } #endif #endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ #if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) /** \brief Get Process Stack Pointer Limit Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence zero is returned always in non-secure mode. \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). \return PSPLIM Register value */ __STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) { #if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) // without main extensions, the non-secure PSPLIM is RAZ/WI return 0U; #else uint32_t result; __ASM volatile ("MRS %0, psplim" : "=r" (result) ); return result; #endif } #if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Process Stack Pointer Limit (non-secure) Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence zero is returned always in non-secure mode. \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. \return PSPLIM Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) { #if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) // without main extensions, the non-secure PSPLIM is RAZ/WI return 0U; #else uint32_t result; __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); return result; #endif } #endif /** \brief Set Process Stack Pointer Limit Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence the write is silently ignored in non-secure mode. \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set */ __STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) { #if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) // without main extensions, the non-secure PSPLIM is RAZ/WI (void)ProcStackPtrLimit; #else __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); #endif } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Process Stack Pointer (non-secure) Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence the write is silently ignored in non-secure mode. \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set */ __STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) { #if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) // without main extensions, the non-secure PSPLIM is RAZ/WI (void)ProcStackPtrLimit; #else __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); #endif } #endif /** \brief Get Main Stack Pointer Limit Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence zero is returned always. \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). \return MSPLIM Register value */ __STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) { #if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) // without main extensions, the non-secure MSPLIM is RAZ/WI return 0U; #else uint32_t result; __ASM volatile ("MRS %0, msplim" : "=r" (result) ); return result; #endif } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Get Main Stack Pointer Limit (non-secure) Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence zero is returned always. \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. \return MSPLIM Register value */ __STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) { #if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) // without main extensions, the non-secure MSPLIM is RAZ/WI return 0U; #else uint32_t result; __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); return result; #endif } #endif /** \brief Set Main Stack Pointer Limit Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence the write is silently ignored. \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set */ __STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) { #if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) // without main extensions, the non-secure MSPLIM is RAZ/WI (void)MainStackPtrLimit; #else __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); #endif } #if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) /** \brief Set Main Stack Pointer Limit (non-secure) Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure Stack Pointer Limit register hence the write is silently ignored. \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. \param [in] MainStackPtrLimit Main Stack Pointer value to set */ __STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) { #if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) // without main extensions, the non-secure MSPLIM is RAZ/WI (void)MainStackPtrLimit; #else __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); #endif } #endif #endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ /** \brief Get FPSCR \details Returns the current value of the Floating Point Status/Control register. \return Floating Point Status/Control register value */ #if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) #define __get_FPSCR (uint32_t)__builtin_arm_get_fpscr #else #define __get_FPSCR() ((uint32_t)0U) #endif /** \brief Set FPSCR \details Assigns the given value to the Floating Point Status/Control register. \param [in] fpscr Floating Point Status/Control value to set */ #if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) #define __set_FPSCR __builtin_arm_set_fpscr #else #define __set_FPSCR(x) ((void)(x)) #endif /*@} end of CMSIS_Core_RegAccFunctions */ /* ################### Compiler specific Intrinsics ########################### */ /** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics Access to dedicated SIMD instructions @{ */ #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) #define __SADD8 __builtin_arm_sadd8 #define __QADD8 __builtin_arm_qadd8 #define __SHADD8 __builtin_arm_shadd8 #define __UADD8 __builtin_arm_uadd8 #define __UQADD8 __builtin_arm_uqadd8 #define __UHADD8 __builtin_arm_uhadd8 #define __SSUB8 __builtin_arm_ssub8 #define __QSUB8 __builtin_arm_qsub8 #define __SHSUB8 __builtin_arm_shsub8 #define __USUB8 __builtin_arm_usub8 #define __UQSUB8 __builtin_arm_uqsub8 #define __UHSUB8 __builtin_arm_uhsub8 #define __SADD16 __builtin_arm_sadd16 #define __QADD16 __builtin_arm_qadd16 #define __SHADD16 __builtin_arm_shadd16 #define __UADD16 __builtin_arm_uadd16 #define __UQADD16 __builtin_arm_uqadd16 #define __UHADD16 __builtin_arm_uhadd16 #define __SSUB16 __builtin_arm_ssub16 #define __QSUB16 __builtin_arm_qsub16 #define __SHSUB16 __builtin_arm_shsub16 #define __USUB16 __builtin_arm_usub16 #define __UQSUB16 __builtin_arm_uqsub16 #define __UHSUB16 __builtin_arm_uhsub16 #define __SASX __builtin_arm_sasx #define __QASX __builtin_arm_qasx #define __SHASX __builtin_arm_shasx #define __UASX __builtin_arm_uasx #define __UQASX __builtin_arm_uqasx #define __UHASX __builtin_arm_uhasx #define __SSAX __builtin_arm_ssax #define __QSAX __builtin_arm_qsax #define __SHSAX __builtin_arm_shsax #define __USAX __builtin_arm_usax #define __UQSAX __builtin_arm_uqsax #define __UHSAX __builtin_arm_uhsax #define __USAD8 __builtin_arm_usad8 #define __USADA8 __builtin_arm_usada8 #define __SSAT16 __builtin_arm_ssat16 #define __USAT16 __builtin_arm_usat16 #define __UXTB16 __builtin_arm_uxtb16 #define __UXTAB16 __builtin_arm_uxtab16 #define __SXTB16 __builtin_arm_sxtb16 #define __SXTAB16 __builtin_arm_sxtab16 #define __SMUAD __builtin_arm_smuad #define __SMUADX __builtin_arm_smuadx #define __SMLAD __builtin_arm_smlad #define __SMLADX __builtin_arm_smladx #define __SMLALD __builtin_arm_smlald #define __SMLALDX __builtin_arm_smlaldx #define __SMUSD __builtin_arm_smusd #define __SMUSDX __builtin_arm_smusdx #define __SMLSD __builtin_arm_smlsd #define __SMLSDX __builtin_arm_smlsdx #define __SMLSLD __builtin_arm_smlsld #define __SMLSLDX __builtin_arm_smlsldx #define __SEL __builtin_arm_sel #define __QADD __builtin_arm_qadd #define __QSUB __builtin_arm_qsub #define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) #define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) #define __SXTB16_RORn(ARG1, ARG2) __SXTB16(__ROR(ARG1, ARG2)) #define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3)) __STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) { int32_t result; __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); return(result); } #endif /* (__ARM_FEATURE_DSP == 1) */ /*@} end of group CMSIS_SIMD_intrinsics */ #endif /* __CMSIS_ARMCLANG_H */ ================================================ FILE: tests/projects/embed/mdk/hello/src/lib/cmsis/cmsis_compiler.h ================================================ /**************************************************************************//** * @file cmsis_compiler.h * @brief CMSIS compiler generic header file * @version V5.1.0 * @date 09. October 2018 ******************************************************************************/ /* * Copyright (c) 2009-2018 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __CMSIS_COMPILER_H #define __CMSIS_COMPILER_H #include /* * Arm Compiler 4/5 */ #if defined ( __CC_ARM ) #include "cmsis_armcc.h" /* * Arm Compiler 6.6 LTM (armclang) */ #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100) #include "cmsis_armclang_ltm.h" /* * Arm Compiler above 6.10.1 (armclang) */ #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100) #include "cmsis_armclang.h" /* * GNU Compiler */ #elif defined ( __GNUC__ ) #include "cmsis_gcc.h" /* * IAR Compiler */ #elif defined ( __ICCARM__ ) #include /* * TI Arm Compiler */ #elif defined ( __TI_ARM__ ) #include #ifndef __ASM #define __ASM __asm #endif #ifndef __INLINE #define __INLINE inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE __STATIC_INLINE #endif #ifndef __NO_RETURN #define __NO_RETURN __attribute__((noreturn)) #endif #ifndef __USED #define __USED __attribute__((used)) #endif #ifndef __WEAK #define __WEAK __attribute__((weak)) #endif #ifndef __PACKED #define __PACKED __attribute__((packed)) #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT struct __attribute__((packed)) #endif #ifndef __PACKED_UNION #define __PACKED_UNION union __attribute__((packed)) #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ struct __attribute__((packed)) T_UINT32 { uint32_t v; }; #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) #endif #ifndef __UNALIGNED_UINT16_WRITE __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) #endif #ifndef __UNALIGNED_UINT32_WRITE __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) #endif #ifndef __ALIGNED #define __ALIGNED(x) __attribute__((aligned(x))) #endif #ifndef __RESTRICT #define __RESTRICT __restrict #endif #ifndef __COMPILER_BARRIER #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. #define __COMPILER_BARRIER() (void)0 #endif /* * TASKING Compiler */ #elif defined ( __TASKING__ ) /* * The CMSIS functions have been implemented as intrinsics in the compiler. * Please use "carm -?i" to get an up to date list of all intrinsics, * Including the CMSIS ones. */ #ifndef __ASM #define __ASM __asm #endif #ifndef __INLINE #define __INLINE inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE __STATIC_INLINE #endif #ifndef __NO_RETURN #define __NO_RETURN __attribute__((noreturn)) #endif #ifndef __USED #define __USED __attribute__((used)) #endif #ifndef __WEAK #define __WEAK __attribute__((weak)) #endif #ifndef __PACKED #define __PACKED __packed__ #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT struct __packed__ #endif #ifndef __PACKED_UNION #define __PACKED_UNION union __packed__ #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ struct __packed__ T_UINT32 { uint32_t v; }; #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) #endif #ifndef __UNALIGNED_UINT16_WRITE __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) #endif #ifndef __UNALIGNED_UINT32_WRITE __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) #endif #ifndef __ALIGNED #define __ALIGNED(x) __align(x) #endif #ifndef __RESTRICT #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. #define __RESTRICT #endif #ifndef __COMPILER_BARRIER #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. #define __COMPILER_BARRIER() (void)0 #endif /* * COSMIC Compiler */ #elif defined ( __CSMC__ ) #include #ifndef __ASM #define __ASM _asm #endif #ifndef __INLINE #define __INLINE inline #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static inline #endif #ifndef __STATIC_FORCEINLINE #define __STATIC_FORCEINLINE __STATIC_INLINE #endif #ifndef __NO_RETURN // NO RETURN is automatically detected hence no warning here #define __NO_RETURN #endif #ifndef __USED #warning No compiler specific solution for __USED. __USED is ignored. #define __USED #endif #ifndef __WEAK #define __WEAK __weak #endif #ifndef __PACKED #define __PACKED @packed #endif #ifndef __PACKED_STRUCT #define __PACKED_STRUCT @packed struct #endif #ifndef __PACKED_UNION #define __PACKED_UNION @packed union #endif #ifndef __UNALIGNED_UINT32 /* deprecated */ @packed struct T_UINT32 { uint32_t v; }; #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) #endif #ifndef __UNALIGNED_UINT16_WRITE __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT16_READ __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) #endif #ifndef __UNALIGNED_UINT32_WRITE __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) #endif #ifndef __UNALIGNED_UINT32_READ __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) #endif #ifndef __ALIGNED #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored. #define __ALIGNED(x) #endif #ifndef __RESTRICT #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. #define __RESTRICT #endif #ifndef __COMPILER_BARRIER #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. #define __COMPILER_BARRIER() (void)0 #endif #else #error Unknown compiler. #endif #endif /* __CMSIS_COMPILER_H */ ================================================ FILE: tests/projects/embed/mdk/hello/src/lib/cmsis/cmsis_version.h ================================================ /**************************************************************************//** * @file cmsis_version.h * @brief CMSIS Core(M) Version definitions * @version V5.0.4 * @date 23. July 2019 ******************************************************************************/ /* * Copyright (c) 2009-2019 ARM Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif #ifndef __CMSIS_VERSION_H #define __CMSIS_VERSION_H /* CMSIS Version definitions */ #define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ #define __CM_CMSIS_VERSION_SUB ( 4U) /*!< [15:0] CMSIS Core(M) sub version */ #define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ #endif ================================================ FILE: tests/projects/embed/mdk/hello/src/lib/cmsis/core_cm3.h ================================================ /**************************************************************************//** * @file core_cm3.h * @brief CMSIS Cortex-M3 Core Peripheral Access Layer Header File * @version V5.1.2 * @date 04. June 2021 ******************************************************************************/ /* * Copyright (c) 2009-2021 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif #ifndef __CORE_CM3_H_GENERIC #define __CORE_CM3_H_GENERIC #include #ifdef __cplusplus extern "C" { #endif /** \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions CMSIS violates the following MISRA-C:2004 rules: \li Required Rule 8.5, object/function definition in header file.
Function definitions in header files are used to allow 'inlining'. \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
Unions are used for effective representation of core registers. \li Advisory Rule 19.7, Function-like macro defined.
Function-like macros are used to allow more efficient code. */ /******************************************************************************* * CMSIS definitions ******************************************************************************/ /** \ingroup Cortex_M3 @{ */ #include "cmsis_version.h" /* CMSIS CM3 definitions */ #define __CM3_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ #define __CM3_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ #define __CM3_CMSIS_VERSION ((__CM3_CMSIS_VERSION_MAIN << 16U) | \ __CM3_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ #define __CORTEX_M (3U) /*!< Cortex-M Core */ /** __FPU_USED indicates whether an FPU is used or not. This core does not support an FPU at all */ #define __FPU_USED 0U #if defined ( __CC_ARM ) #if defined __TARGET_FPU_VFP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) #if defined __ARM_FP #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __GNUC__ ) #if defined (__VFP_FP__) && !defined(__SOFTFP__) #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __ICCARM__ ) #if defined __ARMVFP__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __TI_ARM__ ) #if defined __TI_VFP_SUPPORT__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __TASKING__ ) #if defined __FPU_VFP__ #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #elif defined ( __CSMC__ ) #if ( __CSMC__ & 0x400U) #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #endif #endif #include "cmsis_compiler.h" /* CMSIS compiler specific defines */ #ifdef __cplusplus } #endif #endif /* __CORE_CM3_H_GENERIC */ #ifndef __CMSIS_GENERIC #ifndef __CORE_CM3_H_DEPENDANT #define __CORE_CM3_H_DEPENDANT #ifdef __cplusplus extern "C" { #endif /* check device defines and use defaults */ #if defined __CHECK_DEVICE_DEFINES #ifndef __CM3_REV #define __CM3_REV 0x0200U #warning "__CM3_REV not defined in device header file; using default!" #endif #ifndef __MPU_PRESENT #define __MPU_PRESENT 0U #warning "__MPU_PRESENT not defined in device header file; using default!" #endif #ifndef __VTOR_PRESENT #define __VTOR_PRESENT 1U #warning "__VTOR_PRESENT not defined in device header file; using default!" #endif #ifndef __NVIC_PRIO_BITS #define __NVIC_PRIO_BITS 3U #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" #endif #ifndef __Vendor_SysTickConfig #define __Vendor_SysTickConfig 0U #warning "__Vendor_SysTickConfig not defined in device header file; using default!" #endif #endif /* IO definitions (access restrictions to peripheral registers) */ /** \defgroup CMSIS_glob_defs CMSIS Global Defines IO Type Qualifiers are used \li to specify the access to peripheral variables. \li for automatic generation of peripheral register debug information. */ #ifdef __cplusplus #define __I volatile /*!< Defines 'read only' permissions */ #else #define __I volatile const /*!< Defines 'read only' permissions */ #endif #define __O volatile /*!< Defines 'write only' permissions */ #define __IO volatile /*!< Defines 'read / write' permissions */ /* following defines should be used for structure members */ #define __IM volatile const /*! Defines 'read only' structure member permissions */ #define __OM volatile /*! Defines 'write only' structure member permissions */ #define __IOM volatile /*! Defines 'read / write' structure member permissions */ /*@} end of group Cortex_M3 */ /******************************************************************************* * Register Abstraction Core Register contain: - Core Register - Core NVIC Register - Core SCB Register - Core SysTick Register - Core Debug Register - Core MPU Register ******************************************************************************/ /** \defgroup CMSIS_core_register Defines and Type Definitions \brief Type definitions and defines for Cortex-M processor based devices. */ /** \ingroup CMSIS_core_register \defgroup CMSIS_CORE Status and Control Registers \brief Core Register type definitions. @{ */ /** \brief Union type to access the Application Program Status Register (APSR). */ typedef union { struct { uint32_t _reserved0:27; /*!< bit: 0..26 Reserved */ uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ uint32_t C:1; /*!< bit: 29 Carry condition code flag */ uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ uint32_t N:1; /*!< bit: 31 Negative condition code flag */ } b; /*!< Structure used for bit access */ uint32_t w; /*!< Type used for word access */ } APSR_Type; /* APSR Register Definitions */ #define APSR_N_Pos 31U /*!< APSR: N Position */ #define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ #define APSR_Z_Pos 30U /*!< APSR: Z Position */ #define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ #define APSR_C_Pos 29U /*!< APSR: C Position */ #define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ #define APSR_V_Pos 28U /*!< APSR: V Position */ #define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ #define APSR_Q_Pos 27U /*!< APSR: Q Position */ #define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ /** \brief Union type to access the Interrupt Program Status Register (IPSR). */ typedef union { struct { uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ } b; /*!< Structure used for bit access */ uint32_t w; /*!< Type used for word access */ } IPSR_Type; /* IPSR Register Definitions */ #define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ #define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ /** \brief Union type to access the Special-Purpose Program Status Registers (xPSR). */ typedef union { struct { uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ uint32_t _reserved0:1; /*!< bit: 9 Reserved */ uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ uint32_t _reserved1:8; /*!< bit: 16..23 Reserved */ uint32_t T:1; /*!< bit: 24 Thumb bit */ uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ uint32_t C:1; /*!< bit: 29 Carry condition code flag */ uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ uint32_t N:1; /*!< bit: 31 Negative condition code flag */ } b; /*!< Structure used for bit access */ uint32_t w; /*!< Type used for word access */ } xPSR_Type; /* xPSR Register Definitions */ #define xPSR_N_Pos 31U /*!< xPSR: N Position */ #define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ #define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ #define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ #define xPSR_C_Pos 29U /*!< xPSR: C Position */ #define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ #define xPSR_V_Pos 28U /*!< xPSR: V Position */ #define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ #define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ #define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ #define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ #define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ #define xPSR_T_Pos 24U /*!< xPSR: T Position */ #define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ #define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ #define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ #define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ #define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ /** \brief Union type to access the Control Registers (CONTROL). */ typedef union { struct { uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ } b; /*!< Structure used for bit access */ uint32_t w; /*!< Type used for word access */ } CONTROL_Type; /* CONTROL Register Definitions */ #define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ #define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ #define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ #define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ /*@} end of group CMSIS_CORE */ /** \ingroup CMSIS_core_register \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) \brief Type definitions for the NVIC Registers @{ */ /** \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). */ typedef struct { __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[24U]; __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ uint32_t RESERVED1[24U]; __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[24U]; __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ uint32_t RESERVED3[24U]; __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ uint32_t RESERVED4[56U]; __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ uint32_t RESERVED5[644U]; __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ } NVIC_Type; /* Software Triggered Interrupt Register Definitions */ #define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ #define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ /*@} end of group CMSIS_NVIC */ /** \ingroup CMSIS_core_register \defgroup CMSIS_SCB System Control Block (SCB) \brief Type definitions for the System Control Block Registers @{ */ /** \brief Structure type to access the System Control Block (SCB). */ typedef struct { __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ uint32_t RESERVED0[5U]; __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ } SCB_Type; /* SCB CPUID Register Definitions */ #define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ #define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ #define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ #define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ #define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ #define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ #define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ #define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ #define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ #define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ /* SCB Interrupt Control State Register Definitions */ #define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ #define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ #define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ #define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ #define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ #define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ #define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ #define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ #define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ #define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ #define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ #define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ #define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ #define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ #define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ #define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ #define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ #define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ #define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ #define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ /* SCB Vector Table Offset Register Definitions */ #if defined (__CM3_REV) && (__CM3_REV < 0x0201U) /* core r2p1 */ #define SCB_VTOR_TBLBASE_Pos 29U /*!< SCB VTOR: TBLBASE Position */ #define SCB_VTOR_TBLBASE_Msk (1UL << SCB_VTOR_TBLBASE_Pos) /*!< SCB VTOR: TBLBASE Mask */ #define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ #define SCB_VTOR_TBLOFF_Msk (0x3FFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ #else #define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ #define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ #endif /* SCB Application Interrupt and Reset Control Register Definitions */ #define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ #define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ #define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ #define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ #define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ #define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ #define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ #define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ #define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ #define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ #define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ #define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ #define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ #define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ /* SCB System Control Register Definitions */ #define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ #define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ #define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ #define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ #define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ #define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ /* SCB Configuration Control Register Definitions */ #define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ #define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ #define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ #define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ #define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ #define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ #define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ #define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ #define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ #define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ #define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ #define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ /* SCB System Handler Control and State Register Definitions */ #define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ #define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ #define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ #define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ #define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ #define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ #define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ #define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ #define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ #define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ #define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ #define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ #define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ #define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ #define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ #define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ #define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ #define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ #define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ #define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ #define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ #define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ #define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ #define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ #define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ #define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ #define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ #define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ /* SCB Configurable Fault Status Register Definitions */ #define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ #define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ #define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ #define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ #define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ #define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ /* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ #define SCB_CFSR_MMARVALID_Pos (SCB_CFSR_MEMFAULTSR_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ #define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ #define SCB_CFSR_MSTKERR_Pos (SCB_CFSR_MEMFAULTSR_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ #define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ #define SCB_CFSR_MUNSTKERR_Pos (SCB_CFSR_MEMFAULTSR_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ #define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ #define SCB_CFSR_DACCVIOL_Pos (SCB_CFSR_MEMFAULTSR_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ #define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ #define SCB_CFSR_IACCVIOL_Pos (SCB_CFSR_MEMFAULTSR_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ #define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ /* BusFault Status Register (part of SCB Configurable Fault Status Register) */ #define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ #define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ #define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ #define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ #define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ #define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ #define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ #define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ #define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ #define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ #define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ #define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ /* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ #define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ #define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ #define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ #define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ #define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ #define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ #define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ #define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ #define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ #define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ #define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ #define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ /* SCB Hard Fault Status Register Definitions */ #define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ #define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ #define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ #define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ #define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ #define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ /* SCB Debug Fault Status Register Definitions */ #define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ #define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ #define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ #define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ #define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ #define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ #define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ #define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ #define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ #define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ /*@} end of group CMSIS_SCB */ /** \ingroup CMSIS_core_register \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) \brief Type definitions for the System Control and ID Register not in the SCB @{ */ /** \brief Structure type to access the System Control and ID Register not in the SCB. */ typedef struct { uint32_t RESERVED0[1U]; __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ #if defined (__CM3_REV) && (__CM3_REV >= 0x200U) __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ #else uint32_t RESERVED1[1U]; #endif } SCnSCB_Type; /* Interrupt Controller Type Register Definitions */ #define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ #define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ /* Auxiliary Control Register Definitions */ #if defined (__CM3_REV) && (__CM3_REV >= 0x200U) #define SCnSCB_ACTLR_DISOOFP_Pos 9U /*!< ACTLR: DISOOFP Position */ #define SCnSCB_ACTLR_DISOOFP_Msk (1UL << SCnSCB_ACTLR_DISOOFP_Pos) /*!< ACTLR: DISOOFP Mask */ #define SCnSCB_ACTLR_DISFPCA_Pos 8U /*!< ACTLR: DISFPCA Position */ #define SCnSCB_ACTLR_DISFPCA_Msk (1UL << SCnSCB_ACTLR_DISFPCA_Pos) /*!< ACTLR: DISFPCA Mask */ #define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ #define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ #define SCnSCB_ACTLR_DISDEFWBUF_Pos 1U /*!< ACTLR: DISDEFWBUF Position */ #define SCnSCB_ACTLR_DISDEFWBUF_Msk (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos) /*!< ACTLR: DISDEFWBUF Mask */ #define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ #define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ #endif /*@} end of group CMSIS_SCnotSCB */ /** \ingroup CMSIS_core_register \defgroup CMSIS_SysTick System Tick Timer (SysTick) \brief Type definitions for the System Timer Registers. @{ */ /** \brief Structure type to access the System Timer (SysTick). */ typedef struct { __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ } SysTick_Type; /* SysTick Control / Status Register Definitions */ #define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ #define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ #define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ #define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ #define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ #define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ #define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ #define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ /* SysTick Reload Register Definitions */ #define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ #define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ /* SysTick Current Register Definitions */ #define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ #define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ /* SysTick Calibration Register Definitions */ #define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ #define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ #define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ #define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ #define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ #define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ /*@} end of group CMSIS_SysTick */ /** \ingroup CMSIS_core_register \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) \brief Type definitions for the Instrumentation Trace Macrocell (ITM) @{ */ /** \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). */ typedef struct { __OM union { __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ uint32_t RESERVED0[864U]; __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ uint32_t RESERVED1[15U]; __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ uint32_t RESERVED2[15U]; __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ uint32_t RESERVED3[32U]; uint32_t RESERVED4[43U]; __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ uint32_t RESERVED5[6U]; __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ } ITM_Type; /* ITM Trace Privilege Register Definitions */ #define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ #define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ /* ITM Trace Control Register Definitions */ #define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ #define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ #define ITM_TCR_TraceBusID_Pos 16U /*!< ITM TCR: ATBID Position */ #define ITM_TCR_TraceBusID_Msk (0x7FUL << ITM_TCR_TraceBusID_Pos) /*!< ITM TCR: ATBID Mask */ #define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ #define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ #define ITM_TCR_TSPrescale_Pos 8U /*!< ITM TCR: TSPrescale Position */ #define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ #define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ #define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ #define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ #define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ #define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ #define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ #define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ #define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ #define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ #define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ /* ITM Lock Status Register Definitions */ #define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ #define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ #define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ #define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ #define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ #define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ /*@}*/ /* end of group CMSIS_ITM */ /** \ingroup CMSIS_core_register \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) \brief Type definitions for the Data Watchpoint and Trace (DWT) @{ */ /** \brief Structure type to access the Data Watchpoint and Trace Register (DWT). */ typedef struct { __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ uint32_t RESERVED0[1U]; __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ uint32_t RESERVED1[1U]; __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ uint32_t RESERVED2[1U]; __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ } DWT_Type; /* DWT Control Register Definitions */ #define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ #define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ #define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ #define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ #define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ #define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ #define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ #define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ #define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ #define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ #define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ #define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ #define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ #define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ #define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ #define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ #define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ #define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ #define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ #define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ #define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ #define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ #define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ #define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ #define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ #define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ #define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ #define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ #define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ #define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ #define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ #define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ #define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ #define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ #define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ #define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ /* DWT CPI Count Register Definitions */ #define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ #define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ /* DWT Exception Overhead Count Register Definitions */ #define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ #define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ /* DWT Sleep Count Register Definitions */ #define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ #define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ /* DWT LSU Count Register Definitions */ #define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ #define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ /* DWT Folded-instruction Count Register Definitions */ #define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ #define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ /* DWT Comparator Mask Register Definitions */ #define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ #define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ /* DWT Comparator Function Register Definitions */ #define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ #define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ #define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ #define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ #define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ #define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ #define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ #define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ #define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ #define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ #define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ #define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ #define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ #define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ #define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ #define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ #define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ #define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ /*@}*/ /* end of group CMSIS_DWT */ /** \ingroup CMSIS_core_register \defgroup CMSIS_TPI Trace Port Interface (TPI) \brief Type definitions for the Trace Port Interface (TPI) @{ */ /** \brief Structure type to access the Trace Port Interface Register (TPI). */ typedef struct { __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ uint32_t RESERVED0[2U]; __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ uint32_t RESERVED1[55U]; __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ uint32_t RESERVED2[131U]; __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ uint32_t RESERVED3[759U]; __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ uint32_t RESERVED4[1U]; __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ uint32_t RESERVED5[39U]; __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ uint32_t RESERVED7[8U]; __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ } TPI_Type; /* TPI Asynchronous Clock Prescaler Register Definitions */ #define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ #define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ /* TPI Selected Pin Protocol Register Definitions */ #define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ #define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ /* TPI Formatter and Flush Status Register Definitions */ #define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ #define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ #define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ #define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ #define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ #define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ #define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ #define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ /* TPI Formatter and Flush Control Register Definitions */ #define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ #define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ #define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ #define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ /* TPI TRIGGER Register Definitions */ #define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ #define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ /* TPI Integration ETM Data Register Definitions (FIFO0) */ #define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ #define TPI_FIFO0_ITM_ATVALID_Msk (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ #define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ #define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ #define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ #define TPI_FIFO0_ETM_ATVALID_Msk (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ #define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ #define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ #define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ #define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ #define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ #define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ #define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ #define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ /* TPI ITATBCTR2 Register Definitions */ #define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ #define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ #define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ #define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ /* TPI Integration ITM Data Register Definitions (FIFO1) */ #define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ #define TPI_FIFO1_ITM_ATVALID_Msk (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ #define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ #define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ #define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ #define TPI_FIFO1_ETM_ATVALID_Msk (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ #define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ #define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ #define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ #define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ #define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ #define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ #define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ #define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ /* TPI ITATBCTR0 Register Definitions */ #define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ #define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ #define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ #define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ /* TPI Integration Mode Control Register Definitions */ #define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ #define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ /* TPI DEVID Register Definitions */ #define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ #define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ #define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ #define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ #define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ #define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ #define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ #define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ #define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ #define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ #define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ #define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ /* TPI DEVTYPE Register Definitions */ #define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ #define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ #define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ #define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ /*@}*/ /* end of group CMSIS_TPI */ #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /** \ingroup CMSIS_core_register \defgroup CMSIS_MPU Memory Protection Unit (MPU) \brief Type definitions for the Memory Protection Unit (MPU) @{ */ /** \brief Structure type to access the Memory Protection Unit (MPU). */ typedef struct { __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ } MPU_Type; #define MPU_TYPE_RALIASES 4U /* MPU Type Register Definitions */ #define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ #define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ #define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ #define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ #define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ #define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ /* MPU Control Register Definitions */ #define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ #define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ #define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ #define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ #define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ #define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ /* MPU Region Number Register Definitions */ #define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ #define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ /* MPU Region Base Address Register Definitions */ #define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ #define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ #define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ #define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ #define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ #define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ /* MPU Region Attribute and Size Register Definitions */ #define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ #define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ #define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ #define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ #define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ #define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ #define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ #define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ #define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ #define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ #define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ #define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ #define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ #define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ #define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ #define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ #define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ #define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ #define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ #define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ /*@} end of group CMSIS_MPU */ #endif /** \ingroup CMSIS_core_register \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) \brief Type definitions for the Core Debug Registers @{ */ /** \brief Structure type to access the Core Debug Register (CoreDebug). */ typedef struct { __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ } CoreDebug_Type; /* Debug Halting Control and Status Register Definitions */ #define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ #define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ #define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ #define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ #define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ #define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ #define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ #define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ #define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ #define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ #define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ #define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ #define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ #define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ #define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ #define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ #define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ #define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ #define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ #define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ #define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ #define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ #define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ #define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ /* Debug Core Register Selector Register Definitions */ #define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ #define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ #define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ #define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ /* Debug Exception and Monitor Control Register Definitions */ #define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ #define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ #define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ #define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ #define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ #define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ #define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ #define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ #define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ #define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ #define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ #define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ #define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ #define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ #define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ #define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ #define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ #define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ #define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ #define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ #define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ #define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ #define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ #define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ #define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ #define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ /*@} end of group CMSIS_CoreDebug */ /** \ingroup CMSIS_core_register \defgroup CMSIS_core_bitfield Core register bit field macros \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). @{ */ /** \brief Mask and shift a bit field value for use in a register bit range. \param[in] field Name of the register bit field. \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. \return Masked and shifted value. */ #define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) /** \brief Mask and shift a register value to extract a bit filed value. \param[in] field Name of the register bit field. \param[in] value Value of register. This parameter is interpreted as an uint32_t type. \return Masked and shifted bit field value. */ #define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) /*@} end of group CMSIS_core_bitfield */ /** \ingroup CMSIS_core_register \defgroup CMSIS_core_base Core Definitions \brief Definitions for base addresses, unions, and structures. @{ */ /* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ #define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ #define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ #define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ #define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ #define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ #define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ #define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ #define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ #define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ #endif /*@} */ /******************************************************************************* * Hardware Abstraction Layer Core Function Interface contains: - Core NVIC Functions - Core SysTick Functions - Core Debug Functions - Core Register Access Functions ******************************************************************************/ /** \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference */ /* ########################## NVIC functions #################################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_NVICFunctions NVIC Functions \brief Functions that manage interrupts and exceptions via the NVIC. @{ */ #ifdef CMSIS_NVIC_VIRTUAL #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" #endif #include CMSIS_NVIC_VIRTUAL_HEADER_FILE #else #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping #define NVIC_EnableIRQ __NVIC_EnableIRQ #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ #define NVIC_DisableIRQ __NVIC_DisableIRQ #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ #define NVIC_GetActive __NVIC_GetActive #define NVIC_SetPriority __NVIC_SetPriority #define NVIC_GetPriority __NVIC_GetPriority #define NVIC_SystemReset __NVIC_SystemReset #endif /* CMSIS_NVIC_VIRTUAL */ #ifdef CMSIS_VECTAB_VIRTUAL #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" #endif #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE #else #define NVIC_SetVector __NVIC_SetVector #define NVIC_GetVector __NVIC_GetVector #endif /* (CMSIS_VECTAB_VIRTUAL) */ #define NVIC_USER_IRQ_OFFSET 16 /* The following EXC_RETURN values are saved the LR on exception entry */ #define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ #define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ #define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ /** \brief Set Priority Grouping \details Sets the priority grouping field using the required unlock sequence. The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. Only values from 0..7 are used. In case of a conflict between priority grouping and available priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. \param [in] PriorityGroup Priority grouping field. */ __STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ reg_value = SCB->AIRCR; /* read old register configuration */ reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ reg_value = (reg_value | ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ SCB->AIRCR = reg_value; } /** \brief Get Priority Grouping \details Reads the priority grouping field from the NVIC Interrupt Controller. \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). */ __STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) { return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); } /** \brief Enable Interrupt \details Enables a device specific interrupt in the NVIC interrupt controller. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { __COMPILER_BARRIER(); NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); __COMPILER_BARRIER(); } } /** \brief Get Interrupt Enable status \details Returns a device specific interrupt enable status from the NVIC interrupt controller. \param [in] IRQn Device specific interrupt number. \return 0 Interrupt is not enabled. \return 1 Interrupt is enabled. \note IRQn must not be negative. */ __STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); } else { return(0U); } } /** \brief Disable Interrupt \details Disables a device specific interrupt in the NVIC interrupt controller. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); __DSB(); __ISB(); } } /** \brief Get Pending Interrupt \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not pending. \return 1 Interrupt status is pending. \note IRQn must not be negative. */ __STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); } else { return(0U); } } /** \brief Set Pending Interrupt \details Sets the pending bit of a device specific interrupt in the NVIC pending register. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); } } /** \brief Clear Pending Interrupt \details Clears the pending bit of a device specific interrupt in the NVIC pending register. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); } } /** \brief Get Active Interrupt \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. \param [in] IRQn Device specific interrupt number. \return 0 Interrupt status is not active. \return 1 Interrupt status is active. \note IRQn must not be negative. */ __STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); } else { return(0U); } } /** \brief Set Interrupt Priority \details Sets the priority of a device specific interrupt or a processor exception. The interrupt number can be positive to specify a device specific interrupt, or negative to specify a processor exception. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. \note The priority cannot be set for every processor exception. */ __STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { if ((int32_t)(IRQn) >= 0) { NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } else { SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } } /** \brief Get Interrupt Priority \details Reads the priority of a device specific interrupt or a processor exception. The interrupt number can be positive to specify a device specific interrupt, or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Interrupt Priority. Value is aligned automatically to the implemented priority bits of the microcontroller. */ __STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); } else { return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); } } /** \brief Encode Priority \details Encodes the priority for an interrupt with the given priority group, preemptive priority value, and subpriority value. In case of a conflict between priority grouping and available priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. \param [in] PriorityGroup Used priority group. \param [in] PreemptPriority Preemptive priority value (starting from 0). \param [in] SubPriority Subpriority value (starting from 0). \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). */ __STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) { uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ uint32_t PreemptPriorityBits; uint32_t SubPriorityBits; PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); return ( ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) ); } /** \brief Decode Priority \details Decodes an interrupt priority value with a given priority group to preemptive priority value and subpriority value. In case of a conflict between priority grouping and available priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). \param [in] PriorityGroup Used priority group. \param [out] pPreemptPriority Preemptive priority value (starting from 0). \param [out] pSubPriority Subpriority value (starting from 0). */ __STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) { uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ uint32_t PreemptPriorityBits; uint32_t SubPriorityBits; PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); } /** \brief Set Interrupt Vector \details Sets an interrupt vector in SRAM based interrupt vector table. The interrupt number can be positive to specify a device specific interrupt, or negative to specify a processor exception. VTOR must been relocated to SRAM before. \param [in] IRQn Interrupt number \param [in] vector Address of interrupt handler function */ __STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) { uint32_t *vectors = (uint32_t *)SCB->VTOR; vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; /* ARM Application Note 321 states that the M3 does not require the architectural barrier */ } /** \brief Get Interrupt Vector \details Reads an interrupt vector from interrupt vector table. The interrupt number can be positive to specify a device specific interrupt, or negative to specify a processor exception. \param [in] IRQn Interrupt number. \return Address of interrupt handler function */ __STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) { uint32_t *vectors = (uint32_t *)SCB->VTOR; return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; } /** \brief System Reset \details Initiates a system reset request to reset the MCU. */ __NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) { __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ __DSB(); /* Ensure completion of memory access */ for(;;) /* wait until reset */ { __NOP(); } } /*@} end of CMSIS_Core_NVICFunctions */ /* ########################## MPU functions #################################### */ #if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) #include "mpu_armv7.h" #endif /* ########################## FPU functions #################################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_FpuFunctions FPU Functions \brief Function that provides FPU type. @{ */ /** \brief get FPU type \details returns the FPU type \returns - \b 0: No FPU - \b 1: Single precision FPU - \b 2: Double + Single precision FPU */ __STATIC_INLINE uint32_t SCB_GetFPUType(void) { return 0U; /* No FPU */ } /*@} end of CMSIS_Core_FpuFunctions */ /* ################################## SysTick function ############################################ */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_Core_SysTickFunctions SysTick Functions \brief Functions that configure the System. @{ */ #if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) /** \brief System Tick Configuration \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. Counter is in free running mode to generate periodic interrupts. \param [in] ticks Number of ticks between two interrupts. \return 0 Function succeeded. \return 1 Function failed. \note When the variable __Vendor_SysTickConfig is set to 1, then the function SysTick_Config is not included. In this case, the file device.h must contain a vendor-specific implementation of this function. */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); /* Reload value impossible */ } SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ return (0UL); /* Function successful */ } #endif /*@} end of CMSIS_Core_SysTickFunctions */ /* ##################################### Debug In/Output function ########################################### */ /** \ingroup CMSIS_Core_FunctionInterface \defgroup CMSIS_core_DebugFunctions ITM Functions \brief Functions that access the ITM debug interface. @{ */ extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ #define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ /** \brief ITM Send Character \details Transmits a character via the ITM channel 0, and \li Just returns when no debugger is connected that has booked the output. \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. \param [in] ch Character to transmit. \returns Character to transmit. */ __STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) { if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ { while (ITM->PORT[0U].u32 == 0UL) { __NOP(); } ITM->PORT[0U].u8 = (uint8_t)ch; } return (ch); } /** \brief ITM Receive Character \details Inputs a character via the external variable \ref ITM_RxBuffer. \return Received character. \return -1 No character pending. */ __STATIC_INLINE int32_t ITM_ReceiveChar (void) { int32_t ch = -1; /* no character available */ if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) { ch = ITM_RxBuffer; ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ } return (ch); } /** \brief ITM Check Character \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. \return 0 No character available. \return 1 Character available. */ __STATIC_INLINE int32_t ITM_CheckChar (void) { if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) { return (0); /* no character available */ } else { return (1); /* character available */ } } /*@} end of CMSIS_core_DebugFunctions */ #ifdef __cplusplus } #endif #endif /* __CORE_CM3_H_DEPENDANT */ #endif /* __CMSIS_GENERIC */ ================================================ FILE: tests/projects/embed/mdk/hello/src/lib/cmsis/mpu_armv7.h ================================================ /****************************************************************************** * @file mpu_armv7.h * @brief CMSIS MPU API for Armv7-M MPU * @version V5.1.2 * @date 25. May 2020 ******************************************************************************/ /* * Copyright (c) 2017-2020 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #elif defined (__clang__) #pragma clang system_header /* treat file as system include file */ #endif #ifndef ARM_MPU_ARMV7_H #define ARM_MPU_ARMV7_H #define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes #define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes #define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes #define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes #define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes #define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte #define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes #define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes #define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes #define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes #define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes #define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes #define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes #define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes #define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes #define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte #define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes #define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes #define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes #define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes #define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes #define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes #define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes #define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes #define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes #define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte #define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes #define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes #define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access #define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only #define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only #define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access #define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only #define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access /** MPU Region Base Address Register Value * * \param Region The region to be configured, number 0 to 15. * \param BaseAddress The base address for the region. */ #define ARM_MPU_RBAR(Region, BaseAddress) \ (((BaseAddress) & MPU_RBAR_ADDR_Msk) | \ ((Region) & MPU_RBAR_REGION_Msk) | \ (MPU_RBAR_VALID_Msk)) /** * MPU Memory Access Attributes * * \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. * \param IsShareable Region is shareable between multiple bus masters. * \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. * \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. */ #define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \ ((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \ (((IsShareable) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \ (((IsCacheable) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \ (((IsBufferable) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk)) /** * MPU Region Attribute and Size Register Value * * \param DisableExec Instruction access disable bit, 1= disable instruction fetches. * \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. * \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_. * \param SubRegionDisable Sub-region disable field. * \param Size Region size of the region to be configured, for example 4K, 8K. */ #define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \ ((((DisableExec) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \ (((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \ (((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \ (((SubRegionDisable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) | \ (((Size) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) | \ (((MPU_RASR_ENABLE_Msk)))) /** * MPU Region Attribute and Size Register Value * * \param DisableExec Instruction access disable bit, 1= disable instruction fetches. * \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. * \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. * \param IsShareable Region is shareable between multiple bus masters. * \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. * \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. * \param SubRegionDisable Sub-region disable field. * \param Size Region size of the region to be configured, for example 4K, 8K. */ #define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \ ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size) /** * MPU Memory Access Attribute for strongly ordered memory. * - TEX: 000b * - Shareable * - Non-cacheable * - Non-bufferable */ #define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U) /** * MPU Memory Access Attribute for device memory. * - TEX: 000b (if shareable) or 010b (if non-shareable) * - Shareable or non-shareable * - Non-cacheable * - Bufferable (if shareable) or non-bufferable (if non-shareable) * * \param IsShareable Configures the device memory as shareable or non-shareable. */ #define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U)) /** * MPU Memory Access Attribute for normal memory. * - TEX: 1BBb (reflecting outer cacheability rules) * - Shareable or non-shareable * - Cacheable or non-cacheable (reflecting inner cacheability rules) * - Bufferable or non-bufferable (reflecting inner cacheability rules) * * \param OuterCp Configures the outer cache policy. * \param InnerCp Configures the inner cache policy. * \param IsShareable Configures the memory as shareable or non-shareable. */ #define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) >> 1U), ((InnerCp) & 1U)) /** * MPU Memory Access Attribute non-cacheable policy. */ #define ARM_MPU_CACHEP_NOCACHE 0U /** * MPU Memory Access Attribute write-back, write and read allocate policy. */ #define ARM_MPU_CACHEP_WB_WRA 1U /** * MPU Memory Access Attribute write-through, no write allocate policy. */ #define ARM_MPU_CACHEP_WT_NWA 2U /** * MPU Memory Access Attribute write-back, no write allocate policy. */ #define ARM_MPU_CACHEP_WB_NWA 3U /** * Struct for a single MPU Region */ typedef struct { uint32_t RBAR; //!< The region base address register value (RBAR) uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR } ARM_MPU_Region_t; /** Enable the MPU. * \param MPU_Control Default access permissions for unconfigured regions. */ __STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control) { __DMB(); MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk; #ifdef SCB_SHCSR_MEMFAULTENA_Msk SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; #endif __DSB(); __ISB(); } /** Disable the MPU. */ __STATIC_INLINE void ARM_MPU_Disable(void) { __DMB(); #ifdef SCB_SHCSR_MEMFAULTENA_Msk SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; #endif MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk; __DSB(); __ISB(); } /** Clear and disable the given MPU region. * \param rnr Region number to be cleared. */ __STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr) { MPU->RNR = rnr; MPU->RASR = 0U; } /** Configure an MPU region. * \param rbar Value for RBAR register. * \param rasr Value for RASR register. */ __STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr) { MPU->RBAR = rbar; MPU->RASR = rasr; } /** Configure the given MPU region. * \param rnr Region number to be configured. * \param rbar Value for RBAR register. * \param rasr Value for RASR register. */ __STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr) { MPU->RNR = rnr; MPU->RBAR = rbar; MPU->RASR = rasr; } /** Memcpy with strictly ordered memory access, e.g. used by code in ARM_MPU_Load(). * \param dst Destination data is copied to. * \param src Source data is copied from. * \param len Amount of data words to be copied. */ __STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len) { uint32_t i; for (i = 0U; i < len; ++i) { dst[i] = src[i]; } } /** Load the given number of MPU regions from a table. * \param table Pointer to the MPU configuration table. * \param cnt Amount of regions to be configured. */ __STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt) { const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U; while (cnt > MPU_TYPE_RALIASES) { ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize); table += MPU_TYPE_RALIASES; cnt -= MPU_TYPE_RALIASES; } ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize); } #endif ================================================ FILE: tests/projects/embed/mdk/hello/src/lib/cmsis/system_ARMCM3.h ================================================ /**************************************************************************//** * @file system_ARMCM3.h * @brief CMSIS Device System Header File for * ARMCM3 Device * @version V5.3.2 * @date 15. November 2019 ******************************************************************************/ /* * Copyright (c) 2009-2019 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SYSTEM_ARMCM3_H #define SYSTEM_ARMCM3_H #ifdef __cplusplus extern "C" { #endif /** \brief Exception / Interrupt Handler Function Prototype */ typedef void(*VECTOR_TABLE_Type)(void); /** \brief System Clock Frequency (Core Clock) */ extern uint32_t SystemCoreClock; /** \brief Setup the microcontroller system. Initialize the System and update the SystemCoreClock variable. */ extern void SystemInit (void); /** \brief Update SystemCoreClock variable. Updates the SystemCoreClock with current core Clock retrieved from cpu registers. */ extern void SystemCoreClockUpdate (void); #ifdef __cplusplus } #endif #endif /* SYSTEM_ARMCM3_H */ ================================================ FILE: tests/projects/embed/mdk/hello/src/main.c ================================================ int foo(int x); int main() { return foo(1); } ================================================ FILE: tests/projects/embed/mdk/hello/src/startup_ARMCM3.s ================================================ ;/**************************************************************************//** ; * @file startup_ARMCM3.s ; * @brief CMSIS Core Device Startup File for ; * ARMCM3 Device ; * @version V1.0.1 ; * @date 23. July 2019 ; ******************************************************************************/ ;/* ; * Copyright (c) 2009-2019 Arm Limited. All rights reserved. ; * ; * SPDX-License-Identifier: Apache-2.0 ; * ; * Licensed under the Apache License, Version 2.0 (the License); you may ; * not use this file except in compliance with the License. ; * You may obtain a copy of the License at ; * ; * www.apache.org/licenses/LICENSE-2.0 ; * ; * Unless required by applicable law or agreed to in writing, software ; * distributed under the License is distributed on an AS IS BASIS, WITHOUT ; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; * See the License for the specific language governing permissions and ; * limitations under the License. ; */ ;//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------ ; Stack Configuration ; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> ; Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 __stack_limit Stack_Mem SPACE Stack_Size __initial_sp ; Heap Configuration ; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; Heap_Size EQU 0x00000C00 IF Heap_Size != 0 ; Heap is provided AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit ENDIF PRESERVE8 THUMB ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size __Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; -14 NMI Handler DCD HardFault_Handler ; -13 Hard Fault Handler DCD MemManage_Handler ; -12 MPU Fault Handler DCD BusFault_Handler ; -11 Bus Fault Handler DCD UsageFault_Handler ; -10 Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; -5 SVCall Handler DCD DebugMon_Handler ; -4 Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; -2 PendSV Handler DCD SysTick_Handler ; -1 SysTick Handler ; Interrupts DCD Interrupt0_Handler ; 0 Interrupt 0 DCD Interrupt1_Handler ; 1 Interrupt 1 DCD Interrupt2_Handler ; 2 Interrupt 2 DCD Interrupt3_Handler ; 3 Interrupt 3 DCD Interrupt4_Handler ; 4 Interrupt 4 DCD Interrupt5_Handler ; 5 Interrupt 5 DCD Interrupt6_Handler ; 6 Interrupt 6 DCD Interrupt7_Handler ; 7 Interrupt 7 DCD Interrupt8_Handler ; 8 Interrupt 8 DCD Interrupt9_Handler ; 9 Interrupt 9 SPACE (214 * 4) ; Interrupts 10 .. 224 are left out __Vectors_End __Vectors_Size EQU __Vectors_End - __Vectors AREA |.text|, CODE, READONLY ; Reset Handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP ; The default macro is not used for HardFault_Handler ; because this results in a poor debug illusion. HardFault_Handler PROC EXPORT HardFault_Handler [WEAK] B . ENDP ; Macro to define default exception/interrupt handlers. ; Default handler are weak symbols with an endless loop. ; They can be overwritten by real handlers. MACRO Set_Default_Handler $Handler_Name $Handler_Name PROC EXPORT $Handler_Name [WEAK] B . ENDP MEND ; Default exception/interrupt handler Set_Default_Handler NMI_Handler Set_Default_Handler MemManage_Handler Set_Default_Handler BusFault_Handler Set_Default_Handler UsageFault_Handler Set_Default_Handler SVC_Handler Set_Default_Handler DebugMon_Handler Set_Default_Handler PendSV_Handler Set_Default_Handler SysTick_Handler Set_Default_Handler Interrupt0_Handler Set_Default_Handler Interrupt1_Handler Set_Default_Handler Interrupt2_Handler Set_Default_Handler Interrupt3_Handler Set_Default_Handler Interrupt4_Handler Set_Default_Handler Interrupt5_Handler Set_Default_Handler Interrupt6_Handler Set_Default_Handler Interrupt7_Handler Set_Default_Handler Interrupt8_Handler Set_Default_Handler Interrupt9_Handler ALIGN ; User setup Stack & Heap IF :LNOT::DEF:__MICROLIB IMPORT __use_two_region_memory ENDIF EXPORT __stack_limit EXPORT __initial_sp IF Heap_Size != 0 ; Heap is provided EXPORT __heap_base EXPORT __heap_limit ENDIF END ================================================ FILE: tests/projects/embed/mdk/hello/src/system_ARMCM3.c ================================================ /**************************************************************************//** * @file system_ARMCM3.c * @brief CMSIS Device System Source File for * ARMCM3 Device * @version V1.0.1 * @date 15. November 2019 ******************************************************************************/ /* * Copyright (c) 2009-2019 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ARMCM3.h" /*---------------------------------------------------------------------------- Define clocks *----------------------------------------------------------------------------*/ #define XTAL (50000000UL) /* Oscillator frequency */ #define SYSTEM_CLOCK (XTAL / 2U) /*---------------------------------------------------------------------------- Exception / Interrupt Vector table *----------------------------------------------------------------------------*/ extern const VECTOR_TABLE_Type __VECTOR_TABLE[240]; /*---------------------------------------------------------------------------- System Core Clock Variable *----------------------------------------------------------------------------*/ uint32_t SystemCoreClock = SYSTEM_CLOCK; /* System Core Clock Frequency */ /*---------------------------------------------------------------------------- System Core Clock update function *----------------------------------------------------------------------------*/ void SystemCoreClockUpdate (void) { SystemCoreClock = SYSTEM_CLOCK; } /*---------------------------------------------------------------------------- System initialization function *----------------------------------------------------------------------------*/ void SystemInit (void) { #if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) SCB->VTOR = (uint32_t) &(__VECTOR_TABLE[0]); #endif SystemCoreClock = SYSTEM_CLOCK; } ================================================ FILE: tests/projects/embed/mdk/hello/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_runtimes("microlib") target("foo") add_rules("mdk.static") add_files("src/foo/*.c") target("hello") add_deps("foo") add_rules("mdk.binary") add_files("src/*.c", "src/*.s") add_includedirs("src/lib/cmsis") ================================================ FILE: tests/projects/embed/verilator/hello/src/main.v ================================================ module hello; initial begin $display("hello world!"); $finish ; end endmodule ================================================ FILE: tests/projects/embed/verilator/hello/src/sim_main.cpp ================================================ #include "hello.h" #include "verilated.h" double sc_time_stamp() { return 0; } int main(int argc, char** argv) { VerilatedContext* contextp = new VerilatedContext; contextp->commandArgs(argc, argv); hello* top = new hello{contextp}; while (!contextp->gotFinish()) { top->eval(); } delete top; delete contextp; return 0; } ================================================ FILE: tests/projects/embed/verilator/hello/xmake.lua ================================================ add_requires("verilator") target("hello") add_rules("verilator.binary") set_toolchains("@verilator") add_files("src/*.v") add_files("src/*.cpp") ================================================ FILE: tests/projects/embed/verilator/hello_vcd/src/main.v ================================================ module hello; initial begin $display("hello world!"); $dumpvars(0, hello); $finish ; end endmodule ================================================ FILE: tests/projects/embed/verilator/hello_vcd/src/sim_main.cpp ================================================ #include "hello.h" #include "verilated.h" #include "verilated_vcd_c.h" double sc_time_stamp() { return 0; } int main(int argc, char** argv) { char const* vcdfile = NULL; if (argc == 2) { vcdfile = argv[1]; } if (!vcdfile) { vcdfile = "hello.vcd"; } VerilatedContext* contextp = new VerilatedContext; contextp->commandArgs(argc, argv); hello* top = new hello{contextp}; VerilatedVcdC* tfp = new VerilatedVcdC; top->trace(tfp, 99); Verilated::traceEverOn(true); tfp->open(vcdfile); while (!contextp->gotFinish()) { top->eval(); } tfp->close(); delete top; delete contextp; return 0; } ================================================ FILE: tests/projects/embed/verilator/hello_vcd/xmake.lua ================================================ add_requires("verilator") target("hello") add_rules("verilator.binary") set_toolchains("@verilator") add_files("src/*.v") add_files("src/*.cpp") add_values("verilator.flags", "--trace", "--timing") ================================================ FILE: tests/projects/embed/verilator/shared/src/main.v ================================================ module hello; initial begin $display("hello world!"); $finish ; end endmodule ================================================ FILE: tests/projects/embed/verilator/shared/src/sim_main.cpp ================================================ #include "hello.h" #include "verilated.h" double sc_time_stamp() { return 0; } int main(int argc, char** argv) { VerilatedContext* contextp = new VerilatedContext; contextp->commandArgs(argc, argv); hello* top = new hello{contextp}; while (!contextp->gotFinish()) { top->eval(); } delete top; delete contextp; return 0; } ================================================ FILE: tests/projects/embed/verilator/shared/xmake.lua ================================================ add_requires("verilator") target("hello") add_rules("verilator.shared") set_toolchains("@verilator") add_files("src/*.v") target("test") add_deps("hello") add_files("src/*.cpp") ================================================ FILE: tests/projects/embed/verilator/static/src/main.v ================================================ module hello; initial begin $display("hello world!"); $finish ; end endmodule ================================================ FILE: tests/projects/embed/verilator/static/src/sim_main.cpp ================================================ #include "hello.h" #include "verilated.h" double sc_time_stamp() { return 0; } int main(int argc, char** argv) { VerilatedContext* contextp = new VerilatedContext; contextp->commandArgs(argc, argv); hello* top = new hello{contextp}; while (!contextp->gotFinish()) { top->eval(); } delete top; delete contextp; return 0; } ================================================ FILE: tests/projects/embed/verilator/static/xmake.lua ================================================ add_requires("verilator") target("hello") add_rules("verilator.static") set_toolchains("@verilator") add_files("src/*.v") target("test") add_deps("hello") add_files("src/*.cpp") ================================================ FILE: tests/projects/fortran/console/src/main.f90 ================================================ program hello print *, "Hello World!" end program hello ================================================ FILE: tests/projects/fortran/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.f90") ================================================ FILE: tests/projects/fortran/shared_library/src/main.f90 ================================================ program hello use test, only: print_hello implicit none (type, external) call print_hello() end program hello ================================================ FILE: tests/projects/fortran/shared_library/src/test.f90 ================================================ module test implicit none (type, external) contains subroutine print_hello() print *, "Hello World!" end subroutine print_hello end module test ================================================ FILE: tests/projects/fortran/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("testlib") set_kind("shared") add_files("src/test.f90") target("test") set_kind("binary") add_deps("testlib") add_files("src/main.f90") ================================================ FILE: tests/projects/fortran/static_library/src/main.f90 ================================================ program hello use test, only: print_hello implicit none (type, external) call print_hello() end program hello ================================================ FILE: tests/projects/fortran/static_library/src/test.f90 ================================================ module test implicit none (type, external) contains subroutine print_hello() print *, "Hello World!" end subroutine print_hello end module test ================================================ FILE: tests/projects/fortran/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("testlib") set_kind("static") add_files("src/test.f90") target("test") set_kind("binary") add_deps("testlib") add_files("src/main.f90") ================================================ FILE: tests/projects/go/console/src/main.go ================================================ package main import "fmt" func main() { fmt.Println("hello xmake!") } ================================================ FILE: tests/projects/go/console/test.lua ================================================ function main(t) if is_host("macosx") and os.arch() ~= "arm64" then -- t:build() else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/go/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.go") ================================================ FILE: tests/projects/go/static_library/src/main.go ================================================ package main func main() { Run() } ================================================ FILE: tests/projects/go/static_library/src/module/add.go ================================================ package module func Add(a int, b int) int { return a + b; } ================================================ FILE: tests/projects/go/static_library/src/module/sub.go ================================================ package module func Sub(a int, b int) int { return a - b; } ================================================ FILE: tests/projects/go/static_library/src/test.go ================================================ package main import ( "fmt" "module" ) func Run() { fmt.Printf("add: %d\n", module.Add(1, 2)); fmt.Printf("sub: %d\n", module.Sub(1, 2)); } ================================================ FILE: tests/projects/go/static_library/test.lua ================================================ function main(t) if is_host("macosx") and os.arch() ~= "arm64" then -- t:build() else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/go/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("module") set_kind("static") add_files("src/module/*.go") target("test") set_kind("binary") add_deps("module") add_files("src/*.go") ================================================ FILE: tests/projects/hybrid/static_library/src/main.cpp ================================================ #include "test.h" int main(int argc, char** argv) { test1(); #ifdef MACOSX test2(); test3(); #endif test4(); return 0; } ================================================ FILE: tests/projects/hybrid/static_library/src/main2.cpp ================================================ #include "test.h" int main(int argc, char** argv) { test5(); return 0; } ================================================ FILE: tests/projects/hybrid/static_library/src/test.h ================================================ #ifdef __cplusplus extern "C" { #endif void test1(void); void test2(void); void test3(void); void test4(void); int test5(void); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/hybrid/static_library/src/test1.c ================================================ #include "test.h" void test1() { } ================================================ FILE: tests/projects/hybrid/static_library/src/test2.m ================================================ #include "test.h" void test2() { } ================================================ FILE: tests/projects/hybrid/static_library/src/test3.mm ================================================ #include "test.h" void test3() { } ================================================ FILE: tests/projects/hybrid/static_library/src/test4.cpp ================================================ #include "test.h" void test4() { } ================================================ FILE: tests/projects/hybrid/static_library/src/test5.d ================================================ extern(C) int test5() { return 5; } ================================================ FILE: tests/projects/hybrid/static_library/test.lua ================================================ function main(t) if is_host("macosx") and os.arch() == "arm64" then return end t:build() end ================================================ FILE: tests/projects/hybrid/static_library/xmake.lua ================================================ add_rules("mode.release", "mode.debug") target("test") set_kind("static") add_files("src/*.c", "src/*.cpp") if is_plat("macosx") then add_files("src/*.m", "src/*.mm") end target("demo") set_kind("binary") add_deps("test") add_files("src/main.cpp") if is_plat("macosx") then add_defines("MACOSX") end --[[ target("demo2") set_kind("binary") add_files("src/main2.cpp", "src/*.d") if not is_plat("macosx") then set_enabled(false) end ]] ================================================ FILE: tests/projects/kotlin-native/console/src/main.kt ================================================ fun main() { println("hello xmake!") } ================================================ FILE: tests/projects/kotlin-native/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("kotlin-native") target("test") set_kind("binary") add_files("src/*.kt") set_toolchains("@kotlin-native") ================================================ FILE: tests/projects/kotlin-native/package/cli-parser/src/main.kt ================================================ import kotlinx.cli.ArgParser import kotlinx.cli.ArgType import kotlinx.cli.default fun main(args: Array) { val parser = ArgParser("example") val name by parser.option(ArgType.String, shortName = "n", description = "Your name").default("World") parser.parse(args) println("Hello, $name!") } ================================================ FILE: tests/projects/kotlin-native/package/cli-parser/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("kotlin-native") add_requires("kotlin-native::org.jetbrains.kotlinx:kotlinx-cli 0.3.6", {alias = "kotlinx-cli"}) target("test") set_kind("binary") add_files("src/*.kt") add_packages("kotlinx-cli") set_toolchains("@kotlin-native") ================================================ FILE: tests/projects/kotlin-native/package/json/src/main.kt ================================================ import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @Serializable private data class Message( val topic: String, val content: String, ) private val PrettyPrintJson = Json { prettyPrint = true } fun main() { val message = Message( topic = "Kotlin/Native", content = "Hello!" ) println(PrettyPrintJson.encodeToString(message)) } ================================================ FILE: tests/projects/kotlin-native/package/json/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("kotlin-native") add_requires("kotlin-native::org.jetbrains.kotlinx:kotlinx-serialization-json 1.8.0", {alias = "json"}) add_requires("kotlin-native::org.jetbrains.kotlinx:kotlinx-serialization-core 1.8.0", {alias = "core"}) target("test") set_kind("binary") add_files("src/*.kt") add_packages("json", "core") set_toolchains("@kotlin-native") ================================================ FILE: tests/projects/kotlin-native/shared_library/src/foo.kt ================================================ @CName("kotlin_add") fun add(a: Int, b: Int): Int = a + b ================================================ FILE: tests/projects/kotlin-native/shared_library/src/main.c ================================================ #include "libfoo_api.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", kotlin_add(1, 2)); return 0; } ================================================ FILE: tests/projects/kotlin-native/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("kotlin-native") target("foo") set_kind("shared") add_files("src/foo.kt") set_toolchains("@kotlin-native") target("test") set_kind("binary") add_files("src/main.c") add_deps("foo") ================================================ FILE: tests/projects/kotlin-native/static_library/src/foo.kt ================================================ @CName("kotlin_add") fun add(a: Int, b: Int): Int = a + b ================================================ FILE: tests/projects/kotlin-native/static_library/src/main.c ================================================ #include "libfoo_api.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", kotlin_add(1, 2)); return 0; } ================================================ FILE: tests/projects/kotlin-native/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("kotlin-native") target("foo") set_kind("static") add_files("src/foo.kt") set_toolchains("@kotlin-native") target("test") set_kind("binary") add_files("src/main.c") add_deps("foo") ================================================ FILE: tests/projects/lex_yacc/src/calc.l ================================================ %option noyywrap %{ #include #define YY_DECL int yylex() #include "calc.tab.h" %} %% [ \t] ; // ignore all whitespace [0-9]+\.[0-9]+ {yylval.fval = atof(yytext); return T_FLOAT;} [0-9]+ {yylval.ival = atoi(yytext); return T_INT;} \n {return T_NEWLINE;} "+" {return T_PLUS;} "-" {return T_MINUS;} "*" {return T_MULTIPLY;} "/" {return T_DIVIDE;} "(" {return T_LEFT;} ")" {return T_RIGHT;} "exit" {return T_QUIT;} "quit" {return T_QUIT;} %% ================================================ FILE: tests/projects/lex_yacc/src/calc.y ================================================ %{ #include #include extern int yylex(); extern int yyparse(); extern FILE* yyin; void yyerror(const char* s); %} %union { int ival; float fval; } %token T_INT %token T_FLOAT %token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT %token T_NEWLINE T_QUIT %left T_PLUS T_MINUS %left T_MULTIPLY T_DIVIDE %type expression %type mixed_expression %start calculation %% calculation: | calculation line ; line: T_NEWLINE | mixed_expression T_NEWLINE { printf("\tResult: %f\n", $1);} | expression T_NEWLINE { printf("\tResult: %i\n", $1); } | T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); } ; mixed_expression: T_FLOAT { $$ = $1; } | mixed_expression T_PLUS mixed_expression { $$ = $1 + $3; } | mixed_expression T_MINUS mixed_expression { $$ = $1 - $3; } | mixed_expression T_MULTIPLY mixed_expression { $$ = $1 * $3; } | mixed_expression T_DIVIDE mixed_expression { $$ = $1 / $3; } | T_LEFT mixed_expression T_RIGHT { $$ = $2; } | expression T_PLUS mixed_expression { $$ = $1 + $3; } | expression T_MINUS mixed_expression { $$ = $1 - $3; } | expression T_MULTIPLY mixed_expression { $$ = $1 * $3; } | expression T_DIVIDE mixed_expression { $$ = $1 / $3; } | mixed_expression T_PLUS expression { $$ = $1 + $3; } | mixed_expression T_MINUS expression { $$ = $1 - $3; } | mixed_expression T_MULTIPLY expression { $$ = $1 * $3; } | mixed_expression T_DIVIDE expression { $$ = $1 / $3; } | expression T_DIVIDE expression { $$ = $1 / (float)$3; } ; expression: T_INT { $$ = $1; } | expression T_PLUS expression { $$ = $1 + $3; } | expression T_MINUS expression { $$ = $1 - $3; } | expression T_MULTIPLY expression { $$ = $1 * $3; } | T_LEFT expression T_RIGHT { $$ = $2; } ; %% int main() { yyin = stdin; do { yyparse(); } while(!feof(yyin)); return 0; } void yyerror(const char* s) { fprintf(stderr, "Parse error: %s\n", s); exit(1); } ================================================ FILE: tests/projects/lex_yacc/src/test.c ================================================ #include "calc.tab.h" void test() { } ================================================ FILE: tests/projects/lex_yacc/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("calc") set_kind("binary") add_rules("lex", "yacc") add_files("src/*.c", "src/*.l", "src/*.y") ================================================ FILE: tests/projects/linux/bpf/minimal/src/minimal.bpf.c ================================================ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Copyright (c) 2020 Facebook */ #include #include char LICENSE[] SEC("license") = "Dual BSD/GPL"; int my_pid = 0; SEC("tp/syscalls/sys_enter_write") int handle_tp(void *ctx) { int pid = bpf_get_current_pid_tgid() >> 32; if (pid != my_pid) return 0; bpf_printk("BPF triggered from PID %d.\n", pid); return 0; } ================================================ FILE: tests/projects/linux/bpf/minimal/src/minimal.c ================================================ // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* Copyright (c) 2020 Facebook */ #include #include #include #include #include "minimal.skel.h" static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) { return vfprintf(stderr, format, args); } static void bump_memlock_rlimit(void) { struct rlimit rlim_new = { .rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY, }; if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n"); exit(1); } } int main(int argc, char **argv) { struct minimal_bpf *skel; int err; /* Set up libbpf errors and debug info callback */ libbpf_set_print(libbpf_print_fn); /* Bump RLIMIT_MEMLOCK to allow BPF sub-system to do anything */ bump_memlock_rlimit(); /* Open BPF application */ skel = minimal_bpf__open(); if (!skel) { fprintf(stderr, "Failed to open BPF skeleton\n"); return 1; } /* ensure BPF program only handles write() syscalls from our process */ skel->bss->my_pid = getpid(); /* Load & verify BPF programs */ err = minimal_bpf__load(skel); if (err) { fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto cleanup; } /* Attach tracepoint handler */ err = minimal_bpf__attach(skel); if (err) { fprintf(stderr, "Failed to attach BPF skeleton\n"); goto cleanup; } printf("Successfully started!\n"); for (;;) { /* trigger our BPF program */ fprintf(stderr, "."); sleep(1); } cleanup: minimal_bpf__destroy(skel); return -err; } ================================================ FILE: tests/projects/linux/bpf/minimal/test.lua ================================================ function main(t) if is_host("linux") and os.arch() == "x86_64" and linuxos.name() ~= "alpine" then os.vrun("xmake f -y -p android -vD") os.vrun("xmake -y -vD") end end ================================================ FILE: tests/projects/linux/bpf/minimal/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_rules("platform.linux.bpf") add_requires("linux-tools", {configs = {bpftool = true}}) add_requires("libbpf") if is_plat("android") then add_requires("ndk >=22.0 <26.0") set_toolchains("@ndk", {sdkver = "23"}) else add_requires("llvm >=10.x") set_toolchains("@llvm") add_requires("linux-headers") end -- fix error: libbpf: map 'my_pid_map': unsupported map linkage static. for bpftool >= 7.2.0 -- we cannot add `"-fvisibility=hidden"` when compiling *.bpf.c -- @see https://github.com/libbpf/bpftool/issues/120 set_symbols("none") target("minimal") set_kind("binary") add_files("src/*.c") add_packages("linux-tools", "linux-headers", "libbpf") set_license("GPL-2.0") ================================================ FILE: tests/projects/linux/driver/hello/src/add.c ================================================ #include "add.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/linux/driver/hello/src/add.h ================================================ #pragma once int add(int a, int b); ================================================ FILE: tests/projects/linux/driver/hello/src/hello.c ================================================ #include #include #include "add.h" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Ruki"); MODULE_DESCRIPTION("A simple Hello World Module"); MODULE_ALIAS("a simplest module"); static int hello_init(void) { printk(KERN_INFO "Hello World: %d\n", add(1, 2)); return 0; } static void hello_exit(void) { printk(KERN_INFO "Goodbye World\n"); } module_init(hello_init); module_exit(hello_exit); ================================================ FILE: tests/projects/linux/driver/hello/xmake.lua ================================================ add_requires("linux-headers", {configs = {driver_modules = true}}) target("hello") add_rules("platform.linux.module") add_files("src/*.c") add_packages("linux-headers") set_license("GPL-2.0") ================================================ FILE: tests/projects/linux/driver/hello_custom/src/add.c ================================================ #include "add.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/linux/driver/hello_custom/src/add.h ================================================ #pragma once int add(int a, int b); ================================================ FILE: tests/projects/linux/driver/hello_custom/src/hello.c ================================================ #include #include #include "add.h" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Ruki"); MODULE_DESCRIPTION("A simple Hello World Module"); MODULE_ALIAS("a simplest module"); static int hello_init(void) { printk(KERN_INFO "Hello World: %d\n", add(1, 2)); return 0; } static void hello_exit(void) { printk(KERN_INFO "Goodbye World\n"); } module_init(hello_init); module_exit(hello_exit); ================================================ FILE: tests/projects/linux/driver/hello_custom/xmake.lua ================================================ option("linux-headers", {showmenu = true, description = "Set linux-headers path."}) target("hello") add_rules("platform.linux.module") add_files("src/*.c") set_values("linux.driver.linux-headers", "$(linux-headers)") ================================================ FILE: tests/projects/linux/driver/hello_makefile/src/add.c ================================================ #include "add.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/linux/driver/hello_makefile/src/add.h ================================================ #pragma once int add(int a, int b); ================================================ FILE: tests/projects/linux/driver/hello_makefile/src/hello.c ================================================ #include #include #include "add.h" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Ruki"); MODULE_DESCRIPTION("A simple Hello World Module"); MODULE_ALIAS("a simplest module"); static int hello_init(void) { printk(KERN_INFO "Hello World: %d\n", add(1, 2)); return 0; } static void hello_exit(void) { printk(KERN_INFO "Goodbye World\n"); } module_init(hello_init); module_exit(hello_exit); ================================================ FILE: tests/projects/nim/console/src/main.nim ================================================ echo "hello xmake!" ================================================ FILE: tests/projects/nim/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/main.nim") ================================================ FILE: tests/projects/nim/console_with_c/src/foo.c ================================================ int foo(int n) { return n; } ================================================ FILE: tests/projects/nim/console_with_c/src/main.nim ================================================ proc foo(n: int): int {.cdecl, importc} echo foo(2) ================================================ FILE: tests/projects/nim/console_with_c/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("static") add_files("src/*.c") target("test") set_kind("binary") add_deps("foo") add_files("src/main.nim") ================================================ FILE: tests/projects/nim/link_library/headers/test_header.h ================================================ #ifndef TEST_HEADER_H #define TEST_HEADER_H #define TEST_HEADER_VAL 123 static int test_add_five(int x) { return x + 5; } #endif ================================================ FILE: tests/projects/nim/link_library/inc/test.h ================================================ #ifndef TEST_H #define TEST_H #ifdef TEST_STATIC #define TEST_MSG "Hello from Static Lib!" #else #define TEST_MSG "Hello from Shared Lib!" #endif #endif ================================================ FILE: tests/projects/nim/link_library/maindll.nim ================================================ import shared echo "Calling shared lib mulTwo(10): ", mulTwo(10) echo "Calling shared lib countWords('hello, world, hello'): ", countWords("hello, world, hello") echo "Calling shared lib getMsg('test'): ", getMsg() {.emit: """ #include """.} var testHeaderVal {.importc: "TEST_HEADER_VAL", nodecl.}: cint echo "TEST_HEADER_VAL: ", testHeaderVal proc test_add_five(x: cint): cint {.importc: "test_add_five", nodecl.} echo "test_add_five(80): ", test_add_five(80) ================================================ FILE: tests/projects/nim/link_library/mainlib.nim ================================================ import static {.emit: """ #include #define STB_IMAGE_IMPLEMENTATION #include """.} proc zlibVersion(): cstring {.importc: "zlibVersion", nodecl.} proc stbi_set_flip_vertically_on_load(flag_true_if_should_flip: cint) {.importc: "stbi_set_flip_vertically_on_load", nodecl.} echo "Zlib Version: ", zlibVersion() stbi_set_flip_vertically_on_load(1) echo "STB Image: Flip vertically on load set to 1" echo "Calling static lib addTwo(10): ", addTwo(10) echo "Calling static lib getAlphabet(): ", getAlphabet() echo "Calling static lib getMsg('test'): ", getMsg() {.emit: """ #include """.} var testHeaderVal {.importc: "TEST_HEADER_VAL", nodecl.}: cint echo "TEST_HEADER_VAL: ", testHeaderVal proc test_add_five(x: cint): cint {.importc: "test_add_five", nodecl.} echo "test_add_five(55): ", test_add_five(55) ================================================ FILE: tests/projects/nim/link_library/shared.nim ================================================ proc mulTwo*(x: int): int = return x * 2 import tables, strutils proc countWords*(input: string): string = var wordFrequencies = initCountTable[string]() for word in input.split(", "): wordFrequencies.inc(word) return "The most frequent word is '" & $wordFrequencies.largest & "'" {.emit: """ #include "test.h" """.} proc getMsg*(): cstring {.exportc, dynlib.} = var msg: cstring {.emit: "`msg` = TEST_MSG;".} return msg {.emit: """ #include """.} var testHeaderVal {.importc: "TEST_HEADER_VAL", nodecl.}: cint echo "TEST_HEADER_VAL: ", testHeaderVal proc test_add_five(x: cint): cint {.importc: "test_add_five", nodecl.} echo "test_add_five(10): ", test_add_five(10) ================================================ FILE: tests/projects/nim/link_library/static.nim ================================================ proc addTwo*(x: int): int = return x + 2 proc getAlphabet*(): string = for letter in 'a'..'z': result.add(letter) {.emit: """ #define TEST_STATIC #include "test.h" """.} proc getMsg*(): cstring {.exportc, dynlib.} = var msg: cstring {.emit: "`msg` = TEST_MSG;".} return msg {.emit: """ #include """.} var testHeaderVal {.importc: "TEST_HEADER_VAL", nodecl.}: cint echo "TEST_HEADER_VAL: ", testHeaderVal proc test_add_five(x: cint): cint {.importc: "test_add_five", nodecl.} echo "test_add_five(60): ", test_add_five(60) ================================================ FILE: tests/projects/nim/link_library/xmake.lua ================================================ set_project("link_libs") add_rules("mode.debug", "mode.release") add_requires("zlib", {system = false, configs = {shared = true}}) add_requires("stb", {system = false}) target("headers") set_kind("headeronly") add_headerfiles("headers/*.h") add_includedirs("headers", {public = true}) target("executablestatic") set_kind("binary") add_files("mainlib.nim") add_deps("staticlib") add_packages("zlib", "stb", {public = true}) if is_plat("linux") then add_syslinks("pthread", "m") end target("executableshared") set_kind("binary") add_files("maindll.nim") add_deps("sharedlib") if is_plat("linux") then add_syslinks("pthread", "m") end target("staticlib") set_kind("static") add_files("static.nim") add_includedirs("inc", {public = true}) add_headerfiles("inc/*.h") if is_plat("linux") then add_syslinks("pthread", "m") end add_deps("headers") target("sharedlib") set_kind("shared") add_files("shared.nim") add_includedirs("inc", {public = true}) add_headerfiles("inc/*.h") if is_plat("linux") then add_syslinks("pthread", "m") end add_deps("headers") ================================================ FILE: tests/projects/nim/native_package/src/main.nim ================================================ proc zlibVersion(): cstring {.cdecl, importc} echo zlibVersion() ================================================ FILE: tests/projects/nim/native_package/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("zlib") target("test") set_kind("binary") add_files("src/main.nim") add_packages("zlib") ================================================ FILE: tests/projects/nim/nimble_package/src/main.nim ================================================ import zip/zlib echo zlibVersion() ================================================ FILE: tests/projects/nim/nimble_package/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("nimble::zip >0.3") target("test") set_kind("binary") add_files("src/main.nim") add_packages("nimble::zip") ================================================ FILE: tests/projects/nim/shared_library/src/foo.nim ================================================ proc foo(n: int): int {.cdecl, exportc, dynlib.} = if n < 2: result = n else: result = foo(n - 1) + (n - 2).foo ================================================ FILE: tests/projects/nim/shared_library/src/main.nim ================================================ proc foo(n: int): int {.cdecl, importc} echo foo(2) ================================================ FILE: tests/projects/nim/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("shared") add_files("src/foo.nim") target("test") set_kind("binary") add_deps("foo") add_files("src/main.nim") ================================================ FILE: tests/projects/nim/static_library/src/foo.nim ================================================ proc foo(n: int): int {.cdecl, exportc} = if n < 2: result = n else: result = foo(n - 1) + (n - 2).foo ================================================ FILE: tests/projects/nim/static_library/src/main.nim ================================================ proc foo(n: int): int {.cdecl, importc} echo foo(2) ================================================ FILE: tests/projects/nim/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("static") add_files("src/foo.nim") target("test") set_kind("binary") add_deps("foo") add_files("src/main.nim") ================================================ FILE: tests/projects/objc/bundle/src/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. ================================================ FILE: tests/projects/objc/bundle/src/test.h ================================================ #import FOUNDATION_EXPORT int add(int a, int b); ================================================ FILE: tests/projects/objc/bundle/src/test.m ================================================ #include "test.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/objc/bundle/test.lua ================================================ function main(t) if is_host("macosx") then t:build({iphoneos = true}) else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/objc/bundle/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") add_rules("xcode.bundle") add_files("src/test.m") add_files("src/Info.plist") ================================================ FILE: tests/projects/objc/console/src/main.m ================================================ #import int main(int argc, char** argv) { @autoreleasepool { NSLog(@"hello world!"); } return 0; } ================================================ FILE: tests/projects/objc/console/test.lua ================================================ function main(t) if os.host() == "macosx" then t:build({iphoneos = true}) else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/objc/console/xmake.lua ================================================ -- add rules add_rules("mode.debug", "mode.release") -- add target target("console_objc") -- set kind set_kind("binary") -- add files add_files("src/*.m") ================================================ FILE: tests/projects/objc/framework/src/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. ================================================ FILE: tests/projects/objc/framework/src/main.m ================================================ #import #import int main(int argc, char** argv) { @autoreleasepool { NSLog(@"add(1, 2): %d", add(1, 2)); Test* t = [[Test alloc] init]; [t hello]; } return 0; } ================================================ FILE: tests/projects/objc/framework/src/test.h ================================================ #import FOUNDATION_EXPORT int add(int a, int b); @interface Test : NSObject - (void)hello; @end ================================================ FILE: tests/projects/objc/framework/src/test.m ================================================ #include "test.h" int add(int a, int b) { return a + b; } @implementation Test - (void)hello { NSLog(@"hello xmake!"); } @end ================================================ FILE: tests/projects/objc/framework/test.lua ================================================ function main(t) if is_host("macosx") then t:build({iphoneos = true}) else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/objc/framework/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") add_rules("xcode.framework") add_files("src/test.m") add_files("src/Info.plist") add_headerfiles("src/*.h") target("demo") set_kind("binary") add_deps("test") add_files("src/main.m") ================================================ FILE: tests/projects/objc/iosapp/src/AppDelegate.h ================================================ // // AppDelegate.h // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import @interface AppDelegate : UIResponder @end ================================================ FILE: tests/projects/objc/iosapp/src/AppDelegate.m ================================================ // // AppDelegate.m // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } #pragma mark - UISceneSession lifecycle - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; } - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } @end ================================================ FILE: tests/projects/objc/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/iosapp/src/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/iosapp/src/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: tests/projects/objc/iosapp/src/Base.lproj/Main.storyboard ================================================ ================================================ FILE: tests/projects/objc/iosapp/src/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundleDisplayName $(PRODUCT_DISPLAY_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneConfigurationName Default Configuration UISceneDelegateClassName SceneDelegate UISceneStoryboardFile Main UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: tests/projects/objc/iosapp/src/SceneDelegate.h ================================================ // // SceneDelegate.h // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import @interface SceneDelegate : UIResponder @property (strong, nonatomic) UIWindow * window; @end ================================================ FILE: tests/projects/objc/iosapp/src/SceneDelegate.m ================================================ #import "SceneDelegate.h" @interface SceneDelegate () @end @implementation SceneDelegate - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). } - (void)sceneDidDisconnect:(UIScene *)scene { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). } - (void)sceneDidBecomeActive:(UIScene *)scene { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } - (void)sceneWillResignActive:(UIScene *)scene { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } - (void)sceneWillEnterForeground:(UIScene *)scene { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } - (void)sceneDidEnterBackground:(UIScene *)scene { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } @end ================================================ FILE: tests/projects/objc/iosapp/src/ViewController.h ================================================ // // ViewController.h // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import @interface ViewController : UIViewController @end ================================================ FILE: tests/projects/objc/iosapp/src/ViewController.m ================================================ // // ViewController.m // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } @end ================================================ FILE: tests/projects/objc/iosapp/src/main.m ================================================ // // main.m // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { NSString * appDelegateClassName; @autoreleasepool { // Setup code that might create autoreleased objects goes here. appDelegateClassName = NSStringFromClass([AppDelegate class]); } return UIApplicationMain(argc, argv, nil, appDelegateClassName); } ================================================ FILE: tests/projects/objc/iosapp/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") add_rules("xcode.application") add_files("src/*.m", "src/**.storyboard", "src/*.xcassets") add_files("src/Info.plist") set_plat("iphoneos") ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/AppDelegate.h ================================================ // // AppDelegate.h // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import @interface AppDelegate : UIResponder @end ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/AppDelegate.m ================================================ // // AppDelegate.m // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import "AppDelegate.h" #import @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. NSLog(@"add(1, 2): %d", add(1, 2)); Test* t = [[Test alloc] init]; [t hello]; return YES; } #pragma mark - UISceneSession lifecycle - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; } - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } @end ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/Base.lproj/Main.storyboard ================================================ ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundleDisplayName $(PRODUCT_DISPLAY_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneConfigurationName Default Configuration UISceneDelegateClassName SceneDelegate UISceneStoryboardFile Main UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/SceneDelegate.h ================================================ // // SceneDelegate.h // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import @interface SceneDelegate : UIResponder @property (strong, nonatomic) UIWindow * window; @end ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/SceneDelegate.m ================================================ #import "SceneDelegate.h" @interface SceneDelegate () @end @implementation SceneDelegate - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). } - (void)sceneDidDisconnect:(UIScene *)scene { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). } - (void)sceneDidBecomeActive:(UIScene *)scene { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } - (void)sceneWillResignActive:(UIScene *)scene { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } - (void)sceneWillEnterForeground:(UIScene *)scene { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } - (void)sceneDidEnterBackground:(UIScene *)scene { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } @end ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/ViewController.h ================================================ // // ViewController.h // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import @interface ViewController : UIViewController @end ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/ViewController.m ================================================ // // ViewController.m // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } @end ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/app/main.m ================================================ // // main.m // test // // Created by ruki on 2020/4/8. // Copyright © 2020 tboox. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { NSString * appDelegateClassName; @autoreleasepool { // Setup code that might create autoreleased objects goes here. appDelegateClassName = NSStringFromClass([AppDelegate class]); } return UIApplicationMain(argc, argv, nil, appDelegateClassName); } ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/framework/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2020 xmake.io. All rights reserved. ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/framework/test.h ================================================ #import FOUNDATION_EXPORT int add(int a, int b); @interface Test : NSObject - (void)hello; @end ================================================ FILE: tests/projects/objc/iosapp_with_framework/src/framework/test.m ================================================ #include "test.h" int add(int a, int b) { return a + b; } @implementation Test - (void)hello { NSLog(@"hello xmake!"); } @end ================================================ FILE: tests/projects/objc/iosapp_with_framework/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") add_rules("xcode.framework") add_files("src/framework/test.m") add_files("src/framework/Info.plist") add_headerfiles("src/framework/test.h") target("demo") add_rules("xcode.application") add_deps("test") add_files("src/app/*.m", "src/app/**.storyboard", "src/app/*.xcassets") add_files("src/app/Info.plist") ================================================ FILE: tests/projects/objc/macapp/src/AppDelegate.h ================================================ // // AppDelegate.h // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import @interface AppDelegate : NSObject @end ================================================ FILE: tests/projects/objc/macapp/src/AppDelegate.m ================================================ // // AppDelegate.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application } - (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application } @end ================================================ FILE: tests/projects/objc/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "mac", "size" : "16x16", "scale" : "1x" }, { "idiom" : "mac", "size" : "16x16", "scale" : "2x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "1x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "2x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "1x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "2x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "1x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "2x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "1x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/macapp/src/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/macapp/src/Base.lproj/Main.storyboard ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: tests/projects/objc/macapp/src/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundleDisplayName $(PRODUCT_DISPLAY_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass NSApplication NSSupportsAutomaticTermination NSSupportsSuddenTermination ================================================ FILE: tests/projects/objc/macapp/src/ViewController.h ================================================ // // ViewController.h // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import @interface ViewController : NSViewController @end ================================================ FILE: tests/projects/objc/macapp/src/ViewController.m ================================================ // // ViewController.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import "ViewController.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)setRepresentedObject:(id)representedObject { [super setRepresentedObject:representedObject]; // Update the view, if already loaded. } @end ================================================ FILE: tests/projects/objc/macapp/src/main.m ================================================ // // main.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import int main(int argc, const char * argv[]) { @autoreleasepool { // Setup code that might create autoreleased objects goes here. } return NSApplicationMain(argc, argv); } ================================================ FILE: tests/projects/objc/macapp/src/test.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only ================================================ FILE: tests/projects/objc/macapp/xmake.lua ================================================ add_rules("mode.debug", "mode.release") rule("test") add_deps("xcode.application") target("test") add_rules("xcode.application") add_files("src/*.m", "src/**.storyboard", "src/*.xcassets") add_files("src/Info.plist") add_rules("test") ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/AppDelegate.h ================================================ // // AppDelegate.h // test // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import @interface AppDelegate : NSObject @end ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/AppDelegate.m ================================================ // // AppDelegate.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import "AppDelegate.h" #import @interface AppDelegate () @end @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application add(1, 2); } - (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application } @end ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "mac", "size" : "16x16", "scale" : "1x" }, { "idiom" : "mac", "size" : "16x16", "scale" : "2x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "1x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "2x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "1x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "2x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "1x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "2x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "1x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/Base.lproj/Main.storyboard ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundleDisplayName $(PRODUCT_DISPLAY_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass NSApplication NSSupportsAutomaticTermination NSSupportsSuddenTermination ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/ViewController.h ================================================ // // ViewController.h // test // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import @interface ViewController : NSViewController @end ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/ViewController.m ================================================ // // ViewController.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import "ViewController.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)setRepresentedObject:(id)representedObject { [super setRepresentedObject:representedObject]; // Update the view, if already loaded. } @end ================================================ FILE: tests/projects/objc/macapp_with_framework/src/app/main.m ================================================ // // main.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import int main(int argc, const char * argv[]) { @autoreleasepool { // Setup code that might create autoreleased objects goes here. } return NSApplicationMain(argc, argv); } ================================================ FILE: tests/projects/objc/macapp_with_framework/src/framework/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. ================================================ FILE: tests/projects/objc/macapp_with_framework/src/framework/test.h ================================================ #import FOUNDATION_EXPORT int add(int a, int b); ================================================ FILE: tests/projects/objc/macapp_with_framework/src/framework/test.m ================================================ #include "test.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/objc/macapp_with_framework/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") add_rules("xcode.framework") add_files("src/framework/test.m") add_files("src/framework/Info.plist") add_headerfiles("src/framework/test.h") target("demo") add_rules("xcode.application") add_deps("test") add_files("src/app/*.m", "src/app/**.storyboard", "src/app/*.xcassets") add_files("src/app/Info.plist") ================================================ FILE: tests/projects/objc/macapp_with_shared/src/AppDelegate.h ================================================ // // AppDelegate.h // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import @interface AppDelegate : NSObject @end ================================================ FILE: tests/projects/objc/macapp_with_shared/src/AppDelegate.m ================================================ // // AppDelegate.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import "AppDelegate.h" #include "test.h" @interface AppDelegate () @end @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application add(1, 2); } - (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application } @end ================================================ FILE: tests/projects/objc/macapp_with_shared/src/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "mac", "size" : "16x16", "scale" : "1x" }, { "idiom" : "mac", "size" : "16x16", "scale" : "2x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "1x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "2x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "1x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "2x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "1x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "2x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "1x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/macapp_with_shared/src/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/objc/macapp_with_shared/src/Base.lproj/Main.storyboard ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: tests/projects/objc/macapp_with_shared/src/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundleDisplayName $(PRODUCT_DISPLAY_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass NSApplication NSSupportsAutomaticTermination NSSupportsSuddenTermination ================================================ FILE: tests/projects/objc/macapp_with_shared/src/ViewController.h ================================================ // // ViewController.h // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import @interface ViewController : NSViewController @end ================================================ FILE: tests/projects/objc/macapp_with_shared/src/ViewController.m ================================================ // // ViewController.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import "ViewController.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)setRepresentedObject:(id)representedObject { [super setRepresentedObject:representedObject]; // Update the view, if already loaded. } @end ================================================ FILE: tests/projects/objc/macapp_with_shared/src/main.m ================================================ // // main.m // test3 // // Created by ruki on 2020/4/4. // Copyright © 2020 tboox. All rights reserved. // #import int main(int argc, const char * argv[]) { @autoreleasepool { // Setup code that might create autoreleased objects goes here. } return NSApplicationMain(argc, argv); } ================================================ FILE: tests/projects/objc/macapp_with_shared/src/test.c ================================================ #include "test.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/objc/macapp_with_shared/src/test.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only ================================================ FILE: tests/projects/objc/macapp_with_shared/src/test.h ================================================ #ifdef __cplusplus extern "C" { #endif /*! calculate add(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ __attribute__((visibility("default"))) int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/objc/macapp_with_shared/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("shared") add_files("src/test.c") target("demo") add_rules("xcode.application") add_deps("test") add_files("src/*.m", "src/**.storyboard", "src/*.xcassets") add_files("src/Info.plist") ================================================ FILE: tests/projects/objc/metal_app/.gitignore ================================================ # See LICENSE folder for this sample’s licensing information. # # Apple sample code gitignore configuration. # Finder .DS_Store # Xcode - User files xcuserdata/ **/*.xcodeproj/project.xcworkspace/* !**/*.xcodeproj/project.xcworkspace/xcshareddata **/*.xcodeproj/project.xcworkspace/xcshareddata/* !**/*.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings **/*.playground/playground.xcworkspace/* !**/*.playground/playground.xcworkspace/xcshareddata **/*.playground/playground.xcworkspace/xcshareddata/* !**/*.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ FILE: tests/projects/objc/metal_app/Application/AAPLAppDelegate.h ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Header for our iOS & tvOS application delegate */ #import @interface AAPLAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: tests/projects/objc/metal_app/Application/AAPLAppDelegate.m ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Implementation of our iOS & tvOS application delegate */ #import "AAPLAppDelegate.h" @implementation AAPLAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { return YES; } @end ================================================ FILE: tests/projects/objc/metal_app/Application/AAPLViewController.h ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Header for our our cross-platform view controller */ #if defined(TARGET_IOS) || defined(TARGET_TVOS) @import UIKit; #define PlatformViewController UIViewController #else @import AppKit; #define PlatformViewController NSViewController #endif @import MetalKit; #import "AAPLRenderer.h" // Our view controller @interface AAPLViewController : PlatformViewController @end ================================================ FILE: tests/projects/objc/metal_app/Application/AAPLViewController.m ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Implementation of our cross-platform view controller */ #import "AAPLViewController.h" #import "AAPLRenderer.h" @implementation AAPLViewController { MTKView *_view; AAPLRenderer *_renderer; } - (void)viewDidLoad { [super viewDidLoad]; // Set the view to use the default device _view = (MTKView *)self.view; _view.device = MTLCreateSystemDefaultDevice(); NSAssert(_view.device, @"Metal is not supported on this device"); _renderer = [[AAPLRenderer alloc] initWithMetalKitView:_view]; NSAssert(_renderer, @"Renderer failed initialization"); // Initialize our renderer with the view size [_renderer mtkView:_view drawableSizeWillChange:_view.drawableSize]; _view.delegate = _renderer; } @end ================================================ FILE: tests/projects/objc/metal_app/Application/iOS/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: tests/projects/objc/metal_app/Application/iOS/Base.lproj/Main.storyboard ================================================ ================================================ FILE: tests/projects/objc/metal_app/Application/iOS/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UIStatusBarHidden UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: tests/projects/objc/metal_app/Application/macOS/Base.lproj/Main.storyboard ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: tests/projects/objc/metal_app/Application/macOS/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSMainStoryboardFile Main NSPrincipalClass NSApplication ================================================ FILE: tests/projects/objc/metal_app/Application/main.m ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Application entry point for all platforms */ #if defined(TARGET_IOS) || defined(TARGET_TVOS) #import #import #import #import "AAPLAppDelegate.h" #else #import #endif #if defined(TARGET_IOS) || defined(TARGET_TVOS) int main(int argc, char * argv[]) { #if TARGET_OS_SIMULATOR && (!defined(__IPHONE_13_0) || !defined(__TVOS_13_0)) #error No simulator support for Metal API for this SDK version. Must build for a device #endif @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AAPLAppDelegate class])); } } #elif defined(TARGET_MACOS) int main(int argc, const char * argv[]) { return NSApplicationMain(argc, argv); } #endif ================================================ FILE: tests/projects/objc/metal_app/Application/tvOS/Base.lproj/Main.storyboard ================================================ ================================================ FILE: tests/projects/objc/metal_app/Application/tvOS/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIMainStoryboardFile Main UIRequiredDeviceCapabilities arm64 UIUserInterfaceStyle Automatic ================================================ FILE: tests/projects/objc/metal_app/Configuration/SampleCode.xcconfig ================================================ // // See LICENSE folder for this sample’s licensing information. // // SampleCode.xcconfig // // The `SAMPLE_CODE_DISAMBIGUATOR` configuration is to make it easier to build // and run a sample code project. Once you set your project's development team, // you'll have a unique bundle identifier. This is because the bundle identifier // is derived based on the 'SAMPLE_CODE_DISAMBIGUATOR' value. Do not use this // approach in your own projects—it's only useful for sample code projects because // they are frequently downloaded and don't have a development team set. SAMPLE_CODE_DISAMBIGUATOR=${DEVELOPMENT_TEAM} ================================================ FILE: tests/projects/objc/metal_app/HelloTriangle.xcodeproj/.xcodesamplecode.plist ================================================ ================================================ FILE: tests/projects/objc/metal_app/HelloTriangle.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 3A05CBE01F731ABB00CA21B1 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A1F1B411F0338CF001622B3 /* MetalKit.framework */; }; 3A05CBE11F731AC000CA21B1 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A05CBDE1F731AB800CA21B1 /* MetalKit.framework */; }; 3A1F1B391F033765001622B3 /* AAPLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A35329C1E99974500C194AD /* AAPLViewController.m */; }; 3A1F1B3D1F033827001622B3 /* AAPLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A35329C1E99974500C194AD /* AAPLViewController.m */; }; 3A1F1B3E1F033846001622B3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532931E99974500C194AD /* main.m */; }; 3A1F1B3F1F033846001622B3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532931E99974500C194AD /* main.m */; }; 3A1F1B441F033EF3001622B3 /* AAPLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACD21341EAE60D2000D1DED /* AAPLAppDelegate.m */; }; 3A3532941E99974500C194AD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532931E99974500C194AD /* main.m */; }; 3A35329D1E99974500C194AD /* AAPLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A35329C1E99974500C194AD /* AAPLViewController.m */; }; 3A3532A01E99974500C194AD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A35329E1E99974500C194AD /* Main.storyboard */; }; 3A3532A31E99974500C194AD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A3532A11E99974500C194AD /* LaunchScreen.storyboard */; }; 3A3532B91E99974500C194AD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A3532B71E99974500C194AD /* Main.storyboard */; }; 3A3532CC1E99974500C194AD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A3532CA1E99974500C194AD /* Main.storyboard */; }; 3A3532CE1E99974500C194AD /* AAPLRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532851E99974500C194AD /* AAPLRenderer.m */; }; 3A3532CF1E99974500C194AD /* AAPLRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532851E99974500C194AD /* AAPLRenderer.m */; }; 3A3532D01E99974500C194AD /* AAPLRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532851E99974500C194AD /* AAPLRenderer.m */; }; 3ACD21351EAE60D2000D1DED /* AAPLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACD21341EAE60D2000D1DED /* AAPLAppDelegate.m */; }; 63E77A181ED2059A00E1E542 /* AAPLShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532871E99974500C194AD /* AAPLShaders.metal */; }; 63E77A191ED2059E00E1E542 /* AAPLShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532871E99974500C194AD /* AAPLShaders.metal */; }; 63E77A1A1ED205A200E1E542 /* AAPLShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532871E99974500C194AD /* AAPLShaders.metal */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 328A8E964EC41C65EC8AF01A /* LICENSE.txt */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 3A05CBDE1F731AB800CA21B1 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = ../../../../iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.sdk/System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; 3A1F1B411F0338CF001622B3 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = ../../../../AppleTVOS.platform/Developer/SDKs/AppleTVOS11.0.sdk/System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; 3A3532841E99974500C194AD /* AAPLRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AAPLRenderer.h; sourceTree = ""; }; 3A3532851E99974500C194AD /* AAPLRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AAPLRenderer.m; sourceTree = ""; }; 3A3532861E99974500C194AD /* AAPLShaderTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AAPLShaderTypes.h; sourceTree = ""; }; 3A3532871E99974500C194AD /* AAPLShaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = AAPLShaders.metal; sourceTree = ""; }; 3A35328F1E99974500C194AD /* HelloTriangle.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloTriangle.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3A3532931E99974500C194AD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 3A35329B1E99974500C194AD /* AAPLViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AAPLViewController.h; sourceTree = ""; }; 3A35329C1E99974500C194AD /* AAPLViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AAPLViewController.m; sourceTree = ""; }; 3A35329F1E99974500C194AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 3A3532A21E99974500C194AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 3A3532A41E99974500C194AD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 3A3532A91E99974500C194AD /* HelloTriangle.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloTriangle.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3A3532B81E99974500C194AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 3A3532BA1E99974500C194AD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 3A3532BF1E99974500C194AD /* HelloTriangle.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloTriangle.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3A3532CB1E99974500C194AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 3A3532CD1E99974500C194AD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 3ACD21331EAE60D2000D1DED /* AAPLAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AAPLAppDelegate.h; sourceTree = ""; }; 3ACD21341EAE60D2000D1DED /* AAPLAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AAPLAppDelegate.m; sourceTree = ""; }; 3ED283CC1EC2C6D200A23F58 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = SampleCode.xcconfig; path = Configuration/SampleCode.xcconfig; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 3A35328C1E99974500C194AD /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 3A05CBE11F731AC000CA21B1 /* MetalKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A3532A61E99974500C194AD /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 3A05CBE01F731ABB00CA21B1 /* MetalKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A3532BC1E99974500C194AD /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 3A1F1B351F0336A8001622B3 /* iOS */ = { isa = PBXGroup; children = ( 3A35329E1E99974500C194AD /* Main.storyboard */, 3A3532A11E99974500C194AD /* LaunchScreen.storyboard */, 3A3532A41E99974500C194AD /* Info.plist */, ); path = iOS; sourceTree = ""; }; 3A1F1B361F0336DB001622B3 /* macOS */ = { isa = PBXGroup; children = ( 3A3532CA1E99974500C194AD /* Main.storyboard */, 3A3532CD1E99974500C194AD /* Info.plist */, ); path = macOS; sourceTree = ""; }; 3A1F1B371F0336F4001622B3 /* tvOS */ = { isa = PBXGroup; children = ( 3A3532B71E99974500C194AD /* Main.storyboard */, 3A3532BA1E99974500C194AD /* Info.plist */, ); path = tvOS; sourceTree = ""; }; 3A35327E1E99974500C194AD = { isa = PBXGroup; children = ( 3ED283CC1EC2C6D200A23F58 /* README.md */, 3A3532831E99974500C194AD /* Renderer */, 3A3532911E99974500C194AD /* Application */, 3AE289861EEA0A9100DF4C9A /* Frameworks */, 3A3532901E99974500C194AD /* Products */, F4F7FAFBBA6575359FC81F34 /* Configuration */, 9772A968083C4C14D4BE84E1 /* LICENSE */, ); sourceTree = ""; }; 3A3532831E99974500C194AD /* Renderer */ = { isa = PBXGroup; children = ( 3A3532841E99974500C194AD /* AAPLRenderer.h */, 3A3532851E99974500C194AD /* AAPLRenderer.m */, 3A3532861E99974500C194AD /* AAPLShaderTypes.h */, 3A3532871E99974500C194AD /* AAPLShaders.metal */, ); path = Renderer; sourceTree = ""; }; 3A3532901E99974500C194AD /* Products */ = { isa = PBXGroup; children = ( 3A35328F1E99974500C194AD /* HelloTriangle.app */, 3A3532A91E99974500C194AD /* HelloTriangle.app */, 3A3532BF1E99974500C194AD /* HelloTriangle.app */, ); name = Products; sourceTree = ""; }; 3A3532911E99974500C194AD /* Application */ = { isa = PBXGroup; children = ( 3ACD21331EAE60D2000D1DED /* AAPLAppDelegate.h */, 3ACD21341EAE60D2000D1DED /* AAPLAppDelegate.m */, 3A35329B1E99974500C194AD /* AAPLViewController.h */, 3A35329C1E99974500C194AD /* AAPLViewController.m */, 3A3532931E99974500C194AD /* main.m */, 3A1F1B361F0336DB001622B3 /* macOS */, 3A1F1B371F0336F4001622B3 /* tvOS */, 3A1F1B351F0336A8001622B3 /* iOS */, ); path = Application; sourceTree = ""; }; 3AE289861EEA0A9100DF4C9A /* Frameworks */ = { isa = PBXGroup; children = ( 3A05CBDE1F731AB800CA21B1 /* MetalKit.framework */, 3A1F1B411F0338CF001622B3 /* MetalKit.framework */, ); name = Frameworks; sourceTree = ""; }; 9772A968083C4C14D4BE84E1 /* LICENSE */ = { isa = PBXGroup; children = ( 328A8E964EC41C65EC8AF01A /* LICENSE.txt */, ); path = LICENSE; sourceTree = ""; }; F4F7FAFBBA6575359FC81F34 /* Configuration */ = { isa = PBXGroup; children = ( 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */, ); name = Configuration; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 3A35328E1E99974500C194AD /* HelloTriangle-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 3A3532E21E99974500C194AD /* Build configuration list for PBXNativeTarget "HelloTriangle-iOS" */; buildPhases = ( 3A35328B1E99974500C194AD /* Sources */, 3A35328C1E99974500C194AD /* Frameworks */, 3A35328D1E99974500C194AD /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "HelloTriangle-iOS"; productName = iOS; productReference = 3A35328F1E99974500C194AD /* HelloTriangle.app */; productType = "com.apple.product-type.application"; }; 3A3532A81E99974500C194AD /* HelloTriangle-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 3A3532E51E99974500C194AD /* Build configuration list for PBXNativeTarget "HelloTriangle-tvOS" */; buildPhases = ( 3A3532A51E99974500C194AD /* Sources */, 3A3532A61E99974500C194AD /* Frameworks */, 3A3532A71E99974500C194AD /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "HelloTriangle-tvOS"; productName = tvOS; productReference = 3A3532A91E99974500C194AD /* HelloTriangle.app */; productType = "com.apple.product-type.application"; }; 3A3532BE1E99974500C194AD /* HelloTriangle-macOS */ = { isa = PBXNativeTarget; buildConfigurationList = 3A3532E81E99974500C194AD /* Build configuration list for PBXNativeTarget "HelloTriangle-macOS" */; buildPhases = ( 3A3532BB1E99974500C194AD /* Sources */, 3A3532BC1E99974500C194AD /* Frameworks */, 3A3532BD1E99974500C194AD /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "HelloTriangle-macOS"; productName = macOS; productReference = 3A3532BF1E99974500C194AD /* HelloTriangle.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 3A35327F1E99974500C194AD /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1200; ORGANIZATIONNAME = Apple; TargetAttributes = { 3A35328E1E99974500C194AD = { CreatedOnToolsVersion = 8.3; ProvisioningStyle = Automatic; }; 3A3532A81E99974500C194AD = { CreatedOnToolsVersion = 8.3; ProvisioningStyle = Automatic; }; 3A3532BE1E99974500C194AD = { CreatedOnToolsVersion = 8.3; DevelopmentTeam = 43AAQM58X3; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 3A3532821E99974500C194AD /* Build configuration list for PBXProject "HelloTriangle" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 3A35327E1E99974500C194AD; productRefGroup = 3A3532901E99974500C194AD /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 3A3532BE1E99974500C194AD /* HelloTriangle-macOS */, 3A35328E1E99974500C194AD /* HelloTriangle-iOS */, 3A3532A81E99974500C194AD /* HelloTriangle-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 3A35328D1E99974500C194AD /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 3A3532A01E99974500C194AD /* Main.storyboard in Resources */, 3A3532A31E99974500C194AD /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A3532A71E99974500C194AD /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 3A3532B91E99974500C194AD /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A3532BD1E99974500C194AD /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 3A3532CC1E99974500C194AD /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 3A35328B1E99974500C194AD /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 63E77A181ED2059A00E1E542 /* AAPLShaders.metal in Sources */, 3A35329D1E99974500C194AD /* AAPLViewController.m in Sources */, 3A3532941E99974500C194AD /* main.m in Sources */, 3A3532CE1E99974500C194AD /* AAPLRenderer.m in Sources */, 3ACD21351EAE60D2000D1DED /* AAPLAppDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A3532A51E99974500C194AD /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 63E77A191ED2059E00E1E542 /* AAPLShaders.metal in Sources */, 3A3532CF1E99974500C194AD /* AAPLRenderer.m in Sources */, 3A1F1B391F033765001622B3 /* AAPLViewController.m in Sources */, 3A1F1B3F1F033846001622B3 /* main.m in Sources */, 3A1F1B441F033EF3001622B3 /* AAPLAppDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A3532BB1E99974500C194AD /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3A1F1B3D1F033827001622B3 /* AAPLViewController.m in Sources */, 63E77A1A1ED205A200E1E542 /* AAPLShaders.metal in Sources */, 3A1F1B3E1F033846001622B3 /* main.m in Sources */, 3A3532D01E99974500C194AD /* AAPLRenderer.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 3A35329E1E99974500C194AD /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 3A35329F1E99974500C194AD /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 3A3532A11E99974500C194AD /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 3A3532A21E99974500C194AD /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; 3A3532B71E99974500C194AD /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 3A3532B81E99974500C194AD /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 3A3532CA1E99974500C194AD /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 3A3532CB1E99974500C194AD /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 3A3532E01E99974500C194AD /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MTL_ENABLE_DEBUG_INFO = YES; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = HelloTriangle; }; name = Debug; }; 3A3532E11E99974500C194AD /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = HelloTriangle; }; name = Release; }; 3A3532E31E99974500C194AD /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)/System/Library/Frameworks", ); GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", TARGET_IOS, ); INFOPLIST_FILE = Application/iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.HelloTriangle${SAMPLE_CODE_DISAMBIGUATOR}"; PRODUCT_NAME = HelloTriangle; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 3A3532E41E99974500C194AD /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)/System/Library/Frameworks", ); GCC_PREPROCESSOR_DEFINITIONS = TARGET_IOS; INFOPLIST_FILE = Application/iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.HelloTriangle${SAMPLE_CODE_DISAMBIGUATOR}"; PRODUCT_NAME = HelloTriangle; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 3A3532E61E99974500C194AD /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)/System/Library/Frameworks", ); GCC_PREPROCESSOR_DEFINITIONS = ( TARGET_TVOS, "$(inherited)", ); INFOPLIST_FILE = Application/tvOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.HelloTriangle${SAMPLE_CODE_DISAMBIGUATOR}"; PRODUCT_NAME = HelloTriangle; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = appletvos; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; }; 3A3532E71E99974500C194AD /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)/System/Library/Frameworks", ); GCC_PREPROCESSOR_DEFINITIONS = TARGET_TVOS; INFOPLIST_FILE = Application/tvOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.HelloTriangle${SAMPLE_CODE_DISAMBIGUATOR}"; PRODUCT_NAME = HelloTriangle; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = appletvos; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 12.0; VALIDATE_PRODUCT = YES; }; name = Release; }; 3A3532E91E99974500C194AD /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "Mac Developer"; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 43AAQM58X3; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", TARGET_MACOS, ); INFOPLIST_FILE = Application/macOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.$(PRODUCT_NAME)${SAMPLE_CODE_DISAMBIGUATOR}"; PRODUCT_NAME = HelloTriangle; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; }; name = Debug; }; 3A3532EA1E99974500C194AD /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "Mac Developer"; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 43AAQM58X3; GCC_PREPROCESSOR_DEFINITIONS = TARGET_MACOS; INFOPLIST_FILE = Application/macOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.$(PRODUCT_NAME)${SAMPLE_CODE_DISAMBIGUATOR}"; PRODUCT_NAME = HelloTriangle; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 3A3532821E99974500C194AD /* Build configuration list for PBXProject "HelloTriangle" */ = { isa = XCConfigurationList; buildConfigurations = ( 3A3532E01E99974500C194AD /* Debug */, 3A3532E11E99974500C194AD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3A3532E21E99974500C194AD /* Build configuration list for PBXNativeTarget "HelloTriangle-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 3A3532E31E99974500C194AD /* Debug */, 3A3532E41E99974500C194AD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3A3532E51E99974500C194AD /* Build configuration list for PBXNativeTarget "HelloTriangle-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 3A3532E61E99974500C194AD /* Debug */, 3A3532E71E99974500C194AD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3A3532E81E99974500C194AD /* Build configuration list for PBXNativeTarget "HelloTriangle-macOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 3A3532E91E99974500C194AD /* Debug */, 3A3532EA1E99974500C194AD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 3A35327F1E99974500C194AD /* Project object */; } ================================================ FILE: tests/projects/objc/metal_app/HelloTriangle.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ BuildSystemType Latest ================================================ FILE: tests/projects/objc/metal_app/LICENSE/LICENSE.txt ================================================ Copyright © 2020 Apple Inc. 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 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. ================================================ FILE: tests/projects/objc/metal_app/README.md ================================================ # Using a Render Pipeline to Render Primitives Render a simple 2D triangle. ## Overview In [Using Metal to Draw a View’s Contents](https://developer.apple.com/documentation/metal/basic_tasks_and_concepts/using_metal_to_draw_a_view_s_contents), you learned how to set up an `MTKView` object and to change the view's contents using a render pass. That sample simply erased the view's contents to a background color. This sample shows you how to configure a render pipeline and use it as part of the render pass to draw a simple 2D colored triangle into the view. The sample supplies a position and color for each vertex, and the render pipeline uses that data to render the triangle, interpolating color values between the colors specified for the triangle's vertices. ![Simple 2D Triangle Vertices](Documentation/2DTriangleVertices.png) The Xcode project contains schemes for running the sample on macOS, iOS, and tvOS. ## Understand the Metal Render Pipeline A *render pipeline* processes drawing commands and writes data into a render pass’s targets. A render pipeline has many stages, some programmed using shaders and others with fixed or configurable behavior. This sample focuses on the three main stages of the pipeline: the vertex stage, the rasterization stage, and the fragment stage. The vertex stage and fragment stage are programmable, so you write functions for them in Metal Shading Language (MSL). The rasterization stage has fixed behavior. **Figure 1** Main stages of the Metal graphics render pipeline ![Main Stages of the Metal Graphics Render Pipeline](Documentation/SimplePipeline.png) Rendering starts with a drawing command, which includes a vertex count and what kind of primitive to render. For example, here's the drawing command from this sample: ``` objective-c // Draw the triangle. [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3]; ``` The vertex stage provides data for each vertex. When enough vertices have been processed, the render pipeline rasterizes the primitive, determining which pixels in the render targets lie within the boundaries of the primitive. The fragment stage determines the values to write into the render targets for those pixels. In the rest of this sample, you will see how to write the vertex and fragment functions, how to create the render pipeline state object, and finally, how to encode a draw command that uses this pipeline. ## Decide How Data is Processed by Your Custom Render Pipeline A vertex function generates data for a single vertex and a fragment function generates data for a single fragment, but you decide how they work. You configure the stages of the pipeline with a goal in mind, meaning that you know what you want the pipeline to generate and how it generates those results. Decide what data to pass into your render pipeline and what data is passed to later stages of the pipeline. There are typically three places where you do this: - The inputs to the pipeline, which are provided by your app and passed to the vertex stage. - The outputs of the vertex stage, which is passed to the rasterization stage. - The inputs to the fragment stage, which are provided by your app or generated by the rasterization stage. In this sample, the input data for the pipeline is the position of a vertex and its color. To demonstrate the kind of transformation you typically perform in a vertex function, input coordinates are defined in a custom coordinate space, measured in pixels from the center of the view. These coordinates need to be translated into Metal's coordinate system. Declare an `AAPLVertex` structure, using SIMD vector types to hold the position and color data. To share a single definition for how the structure is laid out in memory, declare the structure in a common header and import it in both the Metal shader and the app. ``` objective-c typedef struct { vector_float2 position; vector_float4 color; } AAPLVertex; ``` SIMD types are commonplace in Metal Shading Language, and you should also use them in your app using the simd library. SIMD types contain multiple channels of a particular data type, so declaring the position as a `vector_float2` means it contains two 32-bit float values (which will hold the x and y coordinates.) Colors are stored using a `vector_float4`, so they have four channels – red, green, blue, and alpha. In the app, the input data is specified using a constant array: ``` objective-c static const AAPLVertex triangleVertices[] = { // 2D positions, RGBA colors { { 250, -250 }, { 1, 0, 0, 1 } }, { { -250, -250 }, { 0, 1, 0, 1 } }, { { 0, 250 }, { 0, 0, 1, 1 } }, }; ``` The vertex stage generates data for a vertex, so it needs to provide a color and a transformed position. Declare a `RasterizerData` structure containing a position and a color value, again using SIMD types. ``` metal struct RasterizerData { // The [[position]] attribute of this member indicates that this value // is the clip space position of the vertex when this structure is // returned from the vertex function. float4 position [[position]]; // Since this member does not have a special attribute, the rasterizer // interpolates its value with the values of the other triangle vertices // and then passes the interpolated value to the fragment shader for each // fragment in the triangle. float4 color; }; ``` The output position (described in detail below) must be defined as a `vector_float4`. The color is declared as it was in the input data structure. You need to tell Metal which field in the rasterization data provides position data, because Metal doesn't enforce any particular naming convention for fields in your struct. Annotate the `position` field with the `[[position]]` attribute qualifier to declare that this field holds the output position. The fragment function simply passes the rasterization stage's data to later stages so it doesn't need any additional arguments. ## Declare the Vertex Function Declare the vertex function, including its input arguments and the data it outputs. Much like compute functions were declared using the `kernel` keyword, you declare a vertex function using the `vertex` keyword. ``` metal vertex RasterizerData vertexShader(uint vertexID [[vertex_id]], constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]], constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]]) ``` The first argument, `vertexID`, uses the `[[vertex_id]]` attribute qualifier, which is another Metal keyword. When you execute a render command, the GPU calls your vertex function multiple times, generating a unique value for each vertex. The second argument, `vertices`, is an array that contains the vertex data, using the `AAPLVertex` struct previously defined. To transform the position into Metal's coordinates, the function needs the size of the viewport (in pixels) that the triangle is being drawn into, so this is stored in the `viewportSizePointer` argument. The second and third arguments have the `[[buffer(n)]]` attribute qualifier. By default, Metal assigns slots in the argument table for each parameter automatically. When you add the `[[buffer(n)]]` qualifier to a buffer argument, you tell Metal explicitly which slot to use. Declaring slots explicitly can make it easier to revise your shaders without also needing to change your app code. Declare the constants for the two indicies in the shared header file. The function's output is a `RasterizerData` struct. ## Write the Vertex Function Your vertex function must generate both fields of the output struct. Use the `vertexID` argument to index into the `vertices` array and read the input data for the vertex. Also, retrieve the viewport dimensions. ``` metal float2 pixelSpacePosition = vertices[vertexID].position.xy; // Get the viewport size and cast to float. vector_float2 viewportSize = vector_float2(*viewportSizePointer); ``` Vertex functions must provide position data in *clip-space coordinates*, which are 3D points specified using a four-dimensional homogenous vector (`x,y,z,w`). The rasterization stage takes the output position and divides the `x`,`y`, and `z` coordinates by `w` to generate a 3D point in *normalized device coordinates*. Normalized device coordinates are independent of viewport size. **Figure 2** Normalized device coordinate system ![Normalized device coordinate system](Documentation/normalizeddevicecoords.png) Normalized device coordinates use a *left-handed coordinate system* and map to positions in the viewport. Primitives are clipped to a box in this coordinate system and then rasterized. The lower-left corner of the clipping box is at an `(x,y)` coordinate of `(-1.0,-1.0)` and the upper-right corner is at `(1.0,1.0)`. Positive-z values point away from the camera (into the screen.) The visible portion of the `z` coordinate is between `0.0` (the near clipping plane) and `1.0` (the far clipping plane). Transform the input coordinate system to the normalized device coordinate system. ![Vertex function coordinate transformation](Documentation/metal-coordinate-transformation.png) Because this is a 2D application and does not need homogenous coordinates, first write a default value to the output coordinate, with the the `w` value is set to `1.0` and the other coordinates set to `0.0`. This means that the coordinates are already in the normalized device coordinate space and the vertex function should generate (x,y) coordinates in that coordinate space. Divide the input position by half the viewport size to generate normalized device coordinates. Since this calculation is performed using SIMD types, both channels can be divided at the same time using a single line of code. Perform the divide and put the results in the x and y channels of the output position. ``` metal out.position = vector_float4(0.0, 0.0, 0.0, 1.0); out.position.xy = pixelSpacePosition / (viewportSize / 2.0); ``` Finally, copy the color value into the `out.color` return value. ``` metal out.color = vertices[vertexID].color; ``` ## Write a Fragment Function A *fragment* is a possible change to the render targets. The rasterizer determines which pixels of the render target are covered by the primitive. Only fragments whose pixel centers are inside the triangle are rendered. **Figure 3** Fragments generated by the rasterization stage ![Fragments generated by the rasterization stage](Documentation/Rasterization.png) A fragment function processes incoming information from the rasterizer for a single position and calculates output values for each of the render targets. These fragment values are processed by later stages in the pipeline, eventually being written to the render targets. - Note: The reason a fragment is called a possible change is because the pipeline stages after the fragment stage can be configured to reject some fragments or change what gets written to the render targets. In this sample, all values calculated by the fragment stage are written as-is to the render target. The fragment shader in this sample receives the same parameters that were declared in the vertex shader's output. Declare the fragment function using the `fragment` keyword. It takes a single argument, the same `RasterizerData` structure that was provided by the vertex stage. Add the `[[stage_in]]` attribute qualifier to indicate that this argument is generated by the rasterizer. ``` metal fragment float4 fragmentShader(RasterizerData in [[stage_in]]) ``` If your fragment function writes to multiple render targets, it must declare a struct with fields for each render target. Because this sample only has a single render target, you specify a floating-point vector directly as the function's output. This output is the color to be written to the render target. The rasterization stage calculates values for each fragment's arguments and calls the fragment function with them. The rasterization stage calculates its color argument as a blend of the colors at the triangle's vertices. The closer a fragment is to a vertex, the more that vertex contributes to the final color. **Figure 4** Interpolated fragment colors ![Interpolated Fragment Colors](Documentation/Interpolation.png) Return the interpolated color as the function's output. ``` metal return in.color; ``` ## Create a Render Pipeline State Object Now that the functions are complete, you can create a render pipeline that uses them. First, get the default library and obtain a [`MTLFunction`][MTLFunction] object for each function. ``` objective-c id defaultLibrary = [_device newDefaultLibrary]; id vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"]; id fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"]; ``` Next, create a [`MTLRenderPipelineState`][MTLRenderPipelineState] object. Render pipelines have more stages to configure, so you use a [`MTLRenderPipelineDescriptor`][MTLRenderPipelineDescriptor] to configure the pipeline. ``` objective-c MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; pipelineStateDescriptor.label = @"Simple Pipeline"; pipelineStateDescriptor.vertexFunction = vertexFunction; pipelineStateDescriptor.fragmentFunction = fragmentFunction; pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat; _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; ``` In addition to specifying the vertex and fragment functions, you also declare the *pixel format* of all render targets that the pipeline will draw into. A pixel format ([`MTLPixelFormat`][MTLPixelFormat]) defines the memory layout of pixel data. For simple formats, this definition includes the number of bytes per pixel, the number of channels of data stored in a pixel, and the bit layout of those channels. Since this sample only has one render target and it is provided by the view, copy the view's pixel format into the render pipeline descriptor. Your render pipeline state must use a pixel format that is compatible with the one specified by the render pass. In this sample, the render pass and the pipeline state object both use the view's pixel format, so they are always the same. When Metal creates the render pipeline state object, the pipeline is configured to convert the fragment function's output into the render target's pixel format. If you want to target a different pixel format, you need to create a different pipeline state object. You can reuse the same shaders in multiple pipelines targeting different pixel formats. ## Set a Viewport Now that you have the render pipeline state object for the pipeline, you'll render the triangle. You do this using a render command encoder. First, set the viewport, so that Metal knows which part of the render target you want to draw into. ``` objective-c // Set the region of the drawable to draw into. [renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, 0.0, 1.0 }]; ``` ## Set the Render Pipeline State Set the render pipeline state for the pipeline you want to use. ``` objective-c [renderEncoder setRenderPipelineState:_pipelineState]; ``` ## Send Argument Data to the Vertex Function Often, you use buffers ([`MTLBuffer`][MTLBuffer]) to pass data to shaders. However, when you need to pass only a small amount of data to the vertex function, as is the case here, copy the data directly into the command buffer. The sample copies data for both parameters into the command buffer. The vertex data is copied from an array defined in the sample. The viewport data is copied from the same variable that you used to set the viewport. In this sample, the fragment function uses only the data it receives from the rasterizer, so there are no arguments to set. ``` objective-c [renderEncoder setVertexBytes:triangleVertices length:sizeof(triangleVertices) atIndex:AAPLVertexInputIndexVertices]; [renderEncoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:AAPLVertexInputIndexViewportSize]; ``` ## Encode the Drawing Command Specify the kind of primitive, the starting index, and the number of vertices. When the triangle is rendered, the vertex function is called with values of 0, 1, and 2 for the `vertexID` argument. ``` objective-c // Draw the triangle. [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3]; ``` As with Drawing to the Screen Using Metal, you end the encoding process and commit the command buffer. However, you could encode more render commands using the same set of steps. The final image is rendered as if the commands were processed in the order they were specified. (For performance, the GPU is allowed to process commands or even parts of commands in parallel, so long as the final result appears to have been rendered in order. ) ## Experiment with the Color Interpolation In this sample, color values were interpolated across the triangle. That's often what you want, but sometimes you want a value to be generated by one vertex and remain constant across the whole primitive. Specify the `flat` attribute qualifier on an output of the vertex function to do this. Try this now. Find the definition of `RasterizerData` in the sample project and add the `[[flat]]` qualifier to its `color` field. `float4 color [[flat]];` Run the sample again. The render pipeline uses the color value from the first vertex (called the *provoking vertex*) uniformly across the triangle, and it ignores the colors from the other two vertices. You can use a mix of flat shaded and interpolated values, simply by adding or omitting the `flat` qualifier on your vertex function's outputs. The [Metal Shading Language specification][ShadingLanguageSpec] defines other attribute qualifiers you can also use to modify the rasterization behavior. [ScreenDrawing]: https://developer.apple.com/documentation/metal [MTLDevice]: https://developer.apple.com/documentation/metal/mtldevice [MTLResource]: https://developer.apple.com/documentation/metal/mtlresource [MTLBuffer]: https://developer.apple.com/documentation/metal/mtlbuffer [MTLRenderPipelineState]: https://developer.apple.com/documentation/metal/mtlrenderpipelinestate [MTLRenderPipelineDescriptor]: https://developer.apple.com/documentation/metal/mtlrenderpipelinedescriptor [MTLRenderCommandEncoder]: https://developer.apple.com/documentation/metal/mtlrendercommandencoder [MTLPixelFormat]: https://developer.apple.com/documentation/metal/mtlpixelformat [MTKView]: https://developer.apple.com/documentation/metalkit/mtkview [ShadingLanguageSpec]: https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf [MTLFunction]: https://developer.apple.com/documentation/metal/mtlfunction ================================================ FILE: tests/projects/objc/metal_app/Renderer/AAPLRenderer.h ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Header for a platform independent renderer class, which performs Metal setup and per frame rendering. */ @import MetalKit; @interface AAPLRenderer : NSObject - (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView; @end ================================================ FILE: tests/projects/objc/metal_app/Renderer/AAPLRenderer.m ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Implementation of a platform independent renderer class, which performs Metal setup and per frame rendering */ @import simd; @import MetalKit; #import "AAPLRenderer.h" // Header shared between C code here, which executes Metal API commands, and .metal files, which // uses these types as inputs to the shaders. #import "AAPLShaderTypes.h" // Main class performing the rendering @implementation AAPLRenderer { id _device; // The render pipeline generated from the vertex and fragment shaders in the .metal shader file. id _pipelineState; // The command queue used to pass commands to the device. id _commandQueue; // The current size of the view, used as an input to the vertex shader. vector_uint2 _viewportSize; } - (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView { self = [super init]; if(self) { NSError *error; _device = mtkView.device; // Load all the shader files with a .metal file extension in the project. id defaultLibrary = [_device newDefaultLibrary]; id vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"]; id fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"]; // Configure a pipeline descriptor that is used to create a pipeline state. MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; pipelineStateDescriptor.label = @"Simple Pipeline"; pipelineStateDescriptor.vertexFunction = vertexFunction; pipelineStateDescriptor.fragmentFunction = fragmentFunction; pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat; _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; // Pipeline State creation could fail if the pipeline descriptor isn't set up properly. // If the Metal API validation is enabled, you can find out more information about what // went wrong. (Metal API validation is enabled by default when a debug build is run // from Xcode.) NSAssert(_pipelineState, @"Failed to create pipeline state: %@", error); // Create the command queue _commandQueue = [_device newCommandQueue]; } return self; } /// Called whenever view changes orientation or is resized - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size { // Save the size of the drawable to pass to the vertex shader. _viewportSize.x = size.width; _viewportSize.y = size.height; } /// Called whenever the view needs to render a frame. - (void)drawInMTKView:(nonnull MTKView *)view { static const AAPLVertex triangleVertices[] = { // 2D positions, RGBA colors { { 250, -250 }, { 1, 0, 0, 1 } }, { { -250, -250 }, { 0, 1, 0, 1 } }, { { 0, 250 }, { 0, 0, 1, 1 } }, }; // Create a new command buffer for each render pass to the current drawable. id commandBuffer = [_commandQueue commandBuffer]; commandBuffer.label = @"MyCommand"; // Obtain a renderPassDescriptor generated from the view's drawable textures. MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor; if(renderPassDescriptor != nil) { // Create a render command encoder. id renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; renderEncoder.label = @"MyRenderEncoder"; // Set the region of the drawable to draw into. [renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, 0.0, 1.0 }]; [renderEncoder setRenderPipelineState:_pipelineState]; // Pass in the parameter data. [renderEncoder setVertexBytes:triangleVertices length:sizeof(triangleVertices) atIndex:AAPLVertexInputIndexVertices]; [renderEncoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:AAPLVertexInputIndexViewportSize]; // Draw the triangle. [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3]; [renderEncoder endEncoding]; // Schedule a present once the framebuffer is complete using the current drawable. [commandBuffer presentDrawable:view.currentDrawable]; } // Finalize rendering here & push the command buffer to the GPU. [commandBuffer commit]; } @end ================================================ FILE: tests/projects/objc/metal_app/Renderer/AAPLShaderTypes.h ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Header containing types and enum constants shared between Metal shaders and C/ObjC source */ #ifndef AAPLShaderTypes_h #define AAPLShaderTypes_h #include // Buffer index values shared between shader and C code to ensure Metal shader buffer inputs // match Metal API buffer set calls. typedef enum AAPLVertexInputIndex { AAPLVertexInputIndexVertices = 0, AAPLVertexInputIndexViewportSize = 1, } AAPLVertexInputIndex; // This structure defines the layout of vertices sent to the vertex // shader. This header is shared between the .metal shader and C code, to guarantee that // the layout of the vertex array in the C code matches the layout that the .metal // vertex shader expects. typedef struct { vector_float2 position; vector_float4 color; } AAPLVertex; #endif /* AAPLShaderTypes_h */ ================================================ FILE: tests/projects/objc/metal_app/Renderer/AAPLShaders.metal ================================================ /* See LICENSE folder for this sample’s licensing information. Abstract: Metal shaders used for this sample */ #include using namespace metal; // Include header shared between this Metal shader code and C code executing Metal API commands. #include "AAPLShaderTypes.h" // Vertex shader outputs and fragment shader inputs struct RasterizerData { // The [[position]] attribute of this member indicates that this value // is the clip space position of the vertex when this structure is // returned from the vertex function. float4 position [[position]]; // Since this member does not have a special attribute, the rasterizer // interpolates its value with the values of the other triangle vertices // and then passes the interpolated value to the fragment shader for each // fragment in the triangle. float4 color; }; vertex RasterizerData vertexShader(uint vertexID [[vertex_id]], constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]], constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]]) { RasterizerData out; // Index into the array of positions to get the current vertex. // The positions are specified in pixel dimensions (i.e. a value of 100 // is 100 pixels from the origin). float2 pixelSpacePosition = vertices[vertexID].position.xy; // Get the viewport size and cast to float. vector_float2 viewportSize = vector_float2(*viewportSizePointer); // To convert from positions in pixel space to positions in clip-space, // divide the pixel coordinates by half the size of the viewport. out.position = vector_float4(0.0, 0.0, 0.0, 1.0); out.position.xy = pixelSpacePosition / (viewportSize / 2.0); // Pass the input color directly to the rasterizer. out.color = vertices[vertexID].color; return out; } fragment float4 fragmentShader(RasterizerData in [[stage_in]]) { // Return the interpolated color. return in.color; } ================================================ FILE: tests/projects/objc/metal_app/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("HelloTriangle") add_rules("xcode.application") add_includedirs("Renderer") add_frameworks("MetalKit") add_mflags("-fmodules") add_files("Renderer/*.m", "Renderer/*.metal") if is_plat("macosx") then add_files("Application/main.m") add_files("Application/AAPLViewController.m") add_files("Application/macOS/Info.plist") add_files("Application/macOS/Base.lproj/*.storyboard") add_defines("TARGET_MACOS") add_frameworks("AppKit") elseif is_plat("iphoneos") then add_files("Application/*.m") add_files("Application/iOS/Info.plist") add_files("Application/iOS/Base.lproj/*.storyboard") add_frameworks("UIKit") add_defines("TARGET_IOS") end ================================================ FILE: tests/projects/objc/modulemap/src/hello.h ================================================ #import @interface Hello : NSObject + (void)say:(NSString*)s; @end ================================================ FILE: tests/projects/objc/modulemap/src/hello.m ================================================ #import "hello.h" @implementation Hello + (void)say:(NSString*)s { NSLog(@"%@\n", s); } @end ================================================ FILE: tests/projects/objc/modulemap/src/main.m ================================================ #import @import Hello; int main(int argc, char** argv) { [Hello say:@"hello"]; return 0; } ================================================ FILE: tests/projects/objc/modulemap/src/module.modulemap ================================================ module Hello { header "hello.h" export * } ================================================ FILE: tests/projects/objc/modulemap/xmake.lua ================================================ target("modulemap") set_kind("binary") add_files("src/*.m") add_mflags("-fmodules", "-fmodule-map-file=src/module.modulemap") ================================================ FILE: tests/projects/objc++/console/src/main.mm ================================================ #import int main(int argc, char** argv) { @autoreleasepool { NSLog(@"hello world!"); } return 0; } ================================================ FILE: tests/projects/objc++/console/test.lua ================================================ function main(t) if os.host() == "macosx" then t:build({iphoneos = true}) else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/objc++/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("console_objc++") set_kind("binary") add_files("src/*.mm") ================================================ FILE: tests/projects/objc++/modulemap/src/hello.h ================================================ #import @interface Hello : NSObject + (void)say:(NSString*)s; @end ================================================ FILE: tests/projects/objc++/modulemap/src/hello.m ================================================ #import "hello.h" @implementation Hello + (void)say:(NSString*)s { NSLog(@"%@\n", s); } @end ================================================ FILE: tests/projects/objc++/modulemap/src/main.mm ================================================ #import @import Hello; int main(int argc, char** argv) { [Hello say:@"hello"]; return 0; } ================================================ FILE: tests/projects/objc++/modulemap/src/module.modulemap ================================================ module Hello { header "hello.h" export * } ================================================ FILE: tests/projects/objc++/modulemap/xmake.lua ================================================ target("modulemap") set_kind("binary") add_files("src/*.mm", "src/*.m") add_mxxflags("-fmodules", "-fcxx-modules", "-fmodule-map-file=src/module.modulemap") ================================================ FILE: tests/projects/objc++/precompiled_header/src/header.h ================================================ // header.h #ifndef HEADER_H #define HEADER_H #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif ================================================ FILE: tests/projects/objc++/precompiled_header/src/header2.h ================================================ ================================================ FILE: tests/projects/objc++/precompiled_header/src/main.mm ================================================ #include "header.h" int main(int argc, char** argv) { std::string s("xmake"); printf("hello %s!\n", s.c_str()); return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/src/test.c ================================================ void test_c(void) { } ================================================ FILE: tests/projects/objc++/precompiled_header/src/test.mm ================================================ // main.cpp #include "header.h" int test() { return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/src/test2.mm ================================================ // main.cpp #include "header.h" int test2() { return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/src/test4.mm ================================================ // main.cpp #include "header.h" int test4() { return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/src/test5.mm ================================================ // main.cpp #include "header.h" int test5() { return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/src/test6.mm ================================================ // main.cpp #include "header.h" int test6() { return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/src/test7.mm ================================================ // main.cpp #include "header.h" int test7() { return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/src/test8.mm ================================================ // main.cpp #include "header.h" int test8() { return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/test.lua ================================================ function main(t) if is_host("macosx") then t:build() end end ================================================ FILE: tests/projects/objc++/precompiled_header/test3.mm ================================================ #include "src/header.h" #include "src/header2.h" int test3() { return 0; } ================================================ FILE: tests/projects/objc++/precompiled_header/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("main") set_kind("binary") set_languages("cxx11") set_pmxxheader("src/header.h") add_files("src/*.mm", "src/*.c", "*.mm") ================================================ FILE: tests/projects/openmp/hello/src/main.c ================================================ #include #include int main(int argc, char** argv) { #pragma omp parallel { printf("hello %d\n", omp_get_thread_num()); } return 0; } ================================================ FILE: tests/projects/openmp/hello/xmake.lua ================================================ add_requires("openmp") target("hello") set_kind("binary") add_files("src/*.c") add_packages("openmp") ================================================ FILE: tests/projects/openmp/loop/src/main.cpp ================================================ #include #include int main(int argc, char** argv) { #pragma omp parallel for for (int i = 0; i < 10; ++i) { printf("hello(%d): i = %d\n", omp_get_thread_num(), i); } return 0; } ================================================ FILE: tests/projects/openmp/loop/xmake.lua ================================================ add_requires("openmp") target("loop") set_kind("binary") add_files("src/*.cpp") add_packages("openmp") ================================================ FILE: tests/projects/other/autogen/autogen_binary_module/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/autogen/autogen_binary_module/modules/autogen/foo/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/autogen/autogen_binary_module/modules/autogen/foo/src/main.cpp ================================================ #include #include #include using namespace std; int main(int argc, char** argv) { ifstream src_file(argv[1], ios::in | ios::binary); if (!src_file) { return 1; } vector buffer(istreambuf_iterator(src_file), {}); src_file.close(); ofstream dst_file(argv[2], ios::out); if (!dst_file) { return 1; } dst_file << "unsigned char g_codegen_data[] = {"; for (auto byte : buffer) { dst_file << "0x" << hex << (int)(unsigned char)byte << ","; } dst_file << "0};" << endl; dst_file.close(); return 0; } ================================================ FILE: tests/projects/other/autogen/autogen_binary_module/modules/autogen/foo/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("generate") add_rules("module.binary") add_files("src/*.cpp") set_languages("c++11") ================================================ FILE: tests/projects/other/autogen/autogen_binary_module/src/data.in ================================================ hello world! ================================================ FILE: tests/projects/other/autogen/autogen_binary_module/src/main.cpp ================================================ #include using namespace std; extern unsigned char g_codegen_data[]; int main(int argc, char** argv) { cout << (const char*)g_codegen_data << endl; return 0; } ================================================ FILE: tests/projects/other/autogen/autogen_binary_module/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/autogen/autogen_binary_module/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_moduledirs("modules") rule("autogen") set_extensions(".in") before_build_file(function (target, sourcefile, opt) import("utils.progress") import("core.project.depend") import("core.tool.compiler") import("autogen.foo", {always_build = true}) local sourcefile_cx = path.join(target:autogendir(), "rules", "autogen", path.basename(sourcefile) .. ".cpp") local objectfile = target:objectfile(sourcefile_cx) table.insert(target:objectfiles(), objectfile) depend.on_changed(function () progress.show(opt.progress, "${color.build.object}compiling.autogen %s", sourcefile) os.mkdir(path.directory(sourcefile_cx)) foo.generate(sourcefile, sourcefile_cx) compiler.compile(sourcefile_cx, objectfile, {target = target}) end, {dependfile = target:dependfile(objectfile), files = sourcefile, changed = target:is_rebuilt()}) end) target("test") set_kind("binary") add_rules("autogen") add_files("src/main.cpp") add_files("src/*.in") ================================================ FILE: tests/projects/other/autogen/autogen_code/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/autogen/autogen_code/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/autogen/autogen_code/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("$(builddir)/autogen.cpp", {always_added = true}) before_build(function (target) io.writefile("$(builddir)/autogen.cpp", [[ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ]]) end) ================================================ FILE: tests/projects/other/autogen/autogen_codedep/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/autogen/autogen_codedep/src/autogen.cpp ================================================ #include #include #include using namespace std; int main(int argc, char** argv) { ifstream src_file(argv[1], ios::in | ios::binary); if (!src_file) { return 1; } vector buffer(istreambuf_iterator(src_file), {}); src_file.close(); ofstream dst_file(argv[2], ios::out); if (!dst_file) { return 1; } dst_file << "unsigned char g_codegen_data[] = {"; for (auto byte : buffer) { dst_file << "0x" << hex << (int)(unsigned char)byte << ","; } dst_file << "0};" << endl; dst_file.close(); return 0; } ================================================ FILE: tests/projects/other/autogen/autogen_codedep/src/data.in ================================================ hello world! ================================================ FILE: tests/projects/other/autogen/autogen_codedep/src/main.cpp ================================================ #include using namespace std; extern unsigned char g_codegen_data[]; int main(int argc, char** argv) { cout << (const char*)g_codegen_data << endl; return 0; } ================================================ FILE: tests/projects/other/autogen/autogen_codedep/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/autogen/autogen_codedep/xmake.lua ================================================ add_rules("mode.debug", "mode.release") rule("autogen") set_extensions(".in") before_buildcmd_file(function (target, batchcmds, sourcefile, opt) local sourcefile_cx = path.join(target:autogendir(), "rules", "autogen", path.basename(sourcefile) .. ".cpp") local objectfile = target:objectfile(sourcefile_cx) table.insert(target:objectfiles(), objectfile) batchcmds:show_progress(opt.progress, "${color.build.object}compiling.autogen %s", sourcefile) batchcmds:mkdir(path.directory(sourcefile_cx)) batchcmds:vrunv(target:dep("autogen"):targetfile(), {sourcefile, sourcefile_cx}) batchcmds:compile(sourcefile_cx, objectfile) batchcmds:add_depfiles(sourcefile, target:dep("autogen"):targetfile()) batchcmds:set_depmtime(os.mtime(objectfile)) batchcmds:set_depcache(target:dependfile(objectfile)) end) target("autogen") set_default(false) set_kind("binary") set_plat(os.host()) set_arch(os.arch()) add_files("src/autogen.cpp") set_languages("c++11") set_policy("build.fence", true) target("test") set_kind("binary") add_deps("autogen") add_rules("autogen") add_files("src/main.cpp") add_files("src/*.in") ================================================ FILE: tests/projects/other/autogen/autogen_shared_module/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/autogen/autogen_shared_module/modules/autogen/foo/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/autogen/autogen_shared_module/modules/autogen/foo/src/main.cpp ================================================ #include #include #include #include using namespace std; static int generate(lua_State* lua) { const char* inputfile = lua_tostring(lua, 1); const char* outputfile = lua_tostring(lua, 2); ifstream src_file(inputfile, ios::in | ios::binary); if (!src_file) { return 1; } vector buffer(istreambuf_iterator(src_file), {}); src_file.close(); ofstream dst_file(outputfile, ios::out); if (!dst_file) { return 1; } dst_file << "unsigned char g_codegen_data[] = {"; for (auto byte : buffer) { dst_file << "0x" << hex << (int)(unsigned char)byte << ","; } dst_file << "0};" << endl; dst_file.close(); return 0; } int luaopen(foo, lua_State* lua) { static const luaL_Reg funcs[] = { {"generate", generate}, {NULL, NULL} }; lua_newtable(lua); luaL_setfuncs(lua, funcs, 0); return 1; } ================================================ FILE: tests/projects/other/autogen/autogen_shared_module/modules/autogen/foo/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") add_rules("module.shared") add_files("src/*.cpp") set_languages("c++11") ================================================ FILE: tests/projects/other/autogen/autogen_shared_module/src/data.in ================================================ hello world! ================================================ FILE: tests/projects/other/autogen/autogen_shared_module/src/main.cpp ================================================ #include using namespace std; extern unsigned char g_codegen_data[]; int main(int argc, char** argv) { cout << (const char*)g_codegen_data << endl; return 0; } ================================================ FILE: tests/projects/other/autogen/autogen_shared_module/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/autogen/autogen_shared_module/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_moduledirs("modules") rule("autogen") set_extensions(".in") before_build_file(function (target, sourcefile, opt) import("utils.progress") import("core.project.depend") import("core.tool.compiler") import("autogen.foo", {always_build = true}) local sourcefile_cx = path.join(target:autogendir(), "rules", "autogen", path.basename(sourcefile) .. ".cpp") local objectfile = target:objectfile(sourcefile_cx) table.insert(target:objectfiles(), objectfile) depend.on_changed(function () progress.show(opt.progress, "${color.build.object}compiling.autogen %s", sourcefile) os.mkdir(path.directory(sourcefile_cx)) foo.generate(sourcefile, sourcefile_cx) compiler.compile(sourcefile_cx, objectfile, {target = target}) end, {dependfile = target:dependfile(objectfile), files = sourcefile, changed = target:is_rebuilt()}) end) target("test") set_kind("binary") add_rules("autogen") add_files("src/main.cpp") add_files("src/*.in") ================================================ FILE: tests/projects/other/bin2c/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/bin2c/src/main.c ================================================ #include #include #include static unsigned char g_bin_data[] = { #include "data.bin.h" }; static unsigned char g_ico_data[] = { #include "xmake.ico.h" }; static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf("%s: size: %u bytes\n", name, (unsigned int)size); if (size == 0) { return; } // if file is larger than 128 bytes, only dump first 64 and last 64 bytes uint32_t dump_size = size; uint32_t start_offset = 0; uint32_t end_offset = 0; uint32_t skip_size = 0; if (size > 128) { dump_size = 64; start_offset = 0; end_offset = size - 64; skip_size = end_offset - start_offset - dump_size; } // dump start for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } // print skip indicator if needed if (skip_size > 0) { printf(" ... (skipped %u bytes) ...\n", (unsigned int)skip_size); } // dump end if needed if (size > 128) { for (uint32_t offset = end_offset; offset < size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } } } int main(int argc, char** argv) { hexdump("data.bin", g_bin_data, (uint32_t)sizeof(g_bin_data)); printf("\n"); hexdump("xmake.ico", g_ico_data, (uint32_t)sizeof(g_ico_data)); return 0; } ================================================ FILE: tests/projects/other/bin2c/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/bin2c/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_rules("utils.bin2c", {linewidth = 16, extensions = {".bin", ".ico"}}) add_files("src/*.c") add_files("src/*.bin") add_files("src/xmake.ico", {nozeroend = true}) ================================================ FILE: tests/projects/other/bin2obj/src/main.c ================================================ #include #include #include extern const uint8_t _binary_data_bin_start[]; extern const uint8_t _binary_data_bin_end[]; extern const uint8_t _binary_xmake_ico_start[]; extern const uint8_t _binary_xmake_ico_end[]; static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf("%s: size: %u bytes\n", name, (unsigned int)size); if (size == 0) { return; } // if file is larger than 128 bytes, only dump first 64 and last 64 bytes uint32_t dump_size = size; uint32_t start_offset = 0; uint32_t end_offset = 0; uint32_t skip_size = 0; if (size > 128) { dump_size = 64; start_offset = 0; end_offset = size - 64; skip_size = end_offset - start_offset - dump_size; } // dump start for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } // print skip indicator if needed if (skip_size > 0) { printf(" ... (skipped %u bytes) ...\n", (unsigned int)skip_size); } // dump end if needed if (size > 128) { for (uint32_t offset = end_offset; offset < size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } } } int main(int argc, char** argv) { const uint32_t _binary_data_bin_size = (uint32_t)(_binary_data_bin_end - _binary_data_bin_start); const uint32_t _binary_xmake_ico_size = (uint32_t)(_binary_xmake_ico_end - _binary_xmake_ico_start); hexdump("data.bin", _binary_data_bin_start, _binary_data_bin_size); printf("\n"); hexdump("xmake.ico", _binary_xmake_ico_start, _binary_xmake_ico_size); return 0; } ================================================ FILE: tests/projects/other/bin2obj/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/bin2obj/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_rules("utils.bin2obj", {extensions = {".bin", ".ico"}}) add_files("src/*.c") add_files("src/data.bin", {zeroend = true}) add_files("src/xmake.ico", {zeroend = false}) ================================================ FILE: tests/projects/other/build_deps/src/dep1.c ================================================ #include "interface.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/build_deps/src/dep2.c ================================================ #include "interface.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/build_deps/src/dep3.c ================================================ #include "interface.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/build_deps/src/dep4.c ================================================ #include "interface.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/build_deps/src/dep5.c ================================================ #include "interface.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/build_deps/src/interface.h ================================================ /*! calculate add(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ int add(int a, int b); ================================================ FILE: tests/projects/other/build_deps/src/test1.c ================================================ #include "interface.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/other/build_deps/src/test2.c ================================================ #include "interface.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/other/build_deps/src/test3.c ================================================ #include "interface.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/other/build_deps/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/build_deps/xmake.lua ================================================ add_rules("mode.release", "mode.debug") target("dep1") set_kind("static") add_deps("dep3") add_files("src/dep1.c") set_policy("build.fence", true) after_load(function (target) os.rm(target:targetfile()) os.rm(target:dep("dep3"):targetfile()) end) before_link(function (target) assert(os.isfile(target:dep("dep3"):targetfile()), "dep1: before_link failed!") end) after_link(function (target) assert(os.isfile(target:targetfile()), "dep1: after_link failed!") end) on_install(function (target) end) target("dep2") set_kind("static") add_deps("dep3") add_files("src/dep2.c") set_policy("build.fence", true) after_load(function (target) os.rm(target:targetfile()) os.rm(target:dep("dep3"):targetfile()) end) before_link(function (target) assert(os.isfile(target:dep("dep3"):targetfile()), "dep2: before_link failed!") end) after_link(function (target) assert(os.isfile(target:targetfile()), "dep2: after_link failed!") end) on_install(function (target) end) target("dep3") set_kind("static") add_files("src/dep3.c") add_deps("dep4", "dep5") set_policy("build.fence", true) after_load(function (target) os.rm(target:targetfile()) os.rm(target:dep("dep4"):targetfile()) os.rm(target:dep("dep5"):targetfile()) end) after_link(function (target) assert(os.isfile(target:targetfile()), "dep3: after_link failed!") assert(os.isfile(target:dep("dep4"):targetfile()), "dep3: after_link failed!") assert(os.isfile(target:dep("dep5"):targetfile()), "dep3: after_link failed!") end) on_install(function (target) end) target("dep4") set_kind("static") add_files("src/dep4.c") after_load(function (target) os.rm(target:targetfile()) end) after_link(function (target) assert(os.isfile(target:targetfile()), "dep4: after_link failed!") end) on_install(function (target) end) target("dep5") set_kind("static") add_files("src/dep5.c") after_load(function (target) os.rm(target:targetfile()) end) after_link(function (target) assert(os.isfile(target:targetfile()), "dep5: after_link failed!") end) on_install(function (target) end) target("test1") set_kind("binary") add_deps("dep1", "dep2") add_files("src/test1.c") after_load(function (target) os.rm(target:targetfile()) os.rm(target:dep("dep1"):targetfile()) os.rm(target:dep("dep2"):targetfile()) os.rm(target:dep("dep3"):targetfile()) end) before_link(function (target) assert(os.isfile(target:dep("dep1"):targetfile()), "test1: before_link failed!") assert(os.isfile(target:dep("dep2"):targetfile()), "test1: before_link failed!") assert(os.isfile(target:dep("dep3"):targetfile()), "test1: before_link failed!") end) after_link(function (target) assert(os.isfile(target:targetfile()), "test1: after_link failed!") end) on_install(function (target) end) target("test2") set_kind("binary") add_deps("dep1") add_files("src/test2.c") after_load(function (target) os.rm(target:targetfile()) os.rm(target:dep("dep1"):targetfile()) os.rm(target:dep("dep3"):targetfile()) end) before_link(function (target) assert(os.isfile(target:dep("dep1"):targetfile()), "test2: before_link failed!") assert(os.isfile(target:dep("dep3"):targetfile()), "test2: before_link failed!") end) after_link(function (target) assert(os.isfile(target:targetfile()), "test2: after_link failed!") end) on_install(function (target) end) rule("test3") before_build(function (target) assert(os.isfile(target:dep("dep1"):targetfile()), "test2: before_build/rule failed!") assert(os.isfile(target:dep("dep3"):targetfile()), "test2: before_build/rule failed!") end) target("test3") set_kind("binary") add_deps("dep1") add_rules("test3") add_files("src/test3.c") after_load(function (target) os.rm(target:targetfile()) os.rm(target:dep("dep1"):targetfile()) os.rm(target:dep("dep3"):targetfile()) end) before_build(function (target) assert(os.isfile(target:dep("dep1"):targetfile()), "test2: before_build failed!") assert(os.isfile(target:dep("dep3"):targetfile()), "test2: before_build failed!") end) after_link(function (target) assert(os.isfile(target:targetfile()), "test2: after_link failed!") end) on_install(function (target) end) ================================================ FILE: tests/projects/other/glsl2spv_bin2c/src/main.c ================================================ #include #include #include static unsigned char g_test_vert_spv_data[] = { #include "test.vert.spv.h" }; static unsigned char g_test_frag_spv_data[] = { #include "test.frag.spv.h" }; static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf("%s: size: %u bytes\n", name, (unsigned int)size); if (size == 0) { return; } // if file is larger than 128 bytes, only dump first 64 and last 64 bytes uint32_t dump_size = size; uint32_t start_offset = 0; uint32_t end_offset = 0; uint32_t skip_size = 0; if (size > 128) { dump_size = 64; start_offset = 0; end_offset = size - 64; skip_size = end_offset - start_offset - dump_size; } // dump start for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } // print skip indicator if needed if (skip_size > 0) { printf(" ... (skipped %u bytes) ...\n", (unsigned int)skip_size); } // dump end if needed if (size > 128) { for (uint32_t offset = end_offset; offset < size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } } } int main(int argc, char** argv) { hexdump("test.vert.spv", g_test_vert_spv_data, (uint32_t)sizeof(g_test_vert_spv_data)); printf("\n"); hexdump("test.frag.spv", g_test_frag_spv_data, (uint32_t)sizeof(g_test_frag_spv_data)); return 0; } ================================================ FILE: tests/projects/other/glsl2spv_bin2c/src/test.frag ================================================ #version 330 precision mediump float; void main() { } ================================================ FILE: tests/projects/other/glsl2spv_bin2c/src/test.vert ================================================ #version 330 precision mediump float; void main() { } ================================================ FILE: tests/projects/other/glsl2spv_bin2c/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("glslang", {configs = {binaryonly = true}}) target("test") set_kind("binary") add_rules("utils.glsl2spv", {bin2c = true}) add_files("src/*.c") add_files("src/*.vert", "src/*.frag") add_packages("glslang") ================================================ FILE: tests/projects/other/glsl2spv_bin2obj/src/main.c ================================================ #include #include #include extern const uint8_t _binary_test_vert_spv_start[]; extern const uint8_t _binary_test_vert_spv_end[]; extern const uint8_t _binary_test_frag_spv_start[]; extern const uint8_t _binary_test_frag_spv_end[]; static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf("%s: size: %u bytes\n", name, (unsigned int)size); if (size == 0) { return; } // if file is larger than 128 bytes, only dump first 64 and last 64 bytes uint32_t dump_size = size; uint32_t start_offset = 0; uint32_t end_offset = 0; uint32_t skip_size = 0; if (size > 128) { dump_size = 64; start_offset = 0; end_offset = size - 64; skip_size = end_offset - start_offset - dump_size; } // dump start for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } // print skip indicator if needed if (skip_size > 0) { printf(" ... (skipped %u bytes) ...\n", (unsigned int)skip_size); } // dump end if needed if (size > 128) { for (uint32_t offset = end_offset; offset < size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } } } int main(int argc, char** argv) { const uint32_t vert_size = (uint32_t)(_binary_test_vert_spv_end - _binary_test_vert_spv_start); const uint32_t frag_size = (uint32_t)(_binary_test_frag_spv_end - _binary_test_frag_spv_start); hexdump("test.vert.spv", _binary_test_vert_spv_start, vert_size); printf("\n"); hexdump("test.frag.spv", _binary_test_frag_spv_start, frag_size); return 0; } ================================================ FILE: tests/projects/other/glsl2spv_bin2obj/src/test.frag ================================================ #version 330 precision mediump float; void main() { } ================================================ FILE: tests/projects/other/glsl2spv_bin2obj/src/test.vert ================================================ #version 330 precision mediump float; void main() { } ================================================ FILE: tests/projects/other/glsl2spv_bin2obj/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("glslang", {configs = {binaryonly = true}}) target("test") set_kind("binary") add_rules("utils.glsl2spv", {bin2obj = true}) add_files("src/*.c") add_files("src/*.vert", "src/*.frag") add_packages("glslang") ================================================ FILE: tests/projects/other/group/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/group/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/other/group/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test1") set_kind("binary") add_files("src/*.cpp") set_group("group1") target("test2") set_kind("binary") add_files("src/*.cpp") set_group("group1") target("test3") set_kind("binary") add_files("src/*.cpp") set_group("group1/group2") target("test4") set_kind("binary") add_files("src/*.cpp") set_group("group3/group4") target("test5") set_kind("binary") add_files("src/*.cpp") target("test6") set_kind("binary") add_files("src/*.cpp") ================================================ FILE: tests/projects/other/hlsl2spv_bin2c/src/main.c ================================================ #include #include #include static unsigned char g_test_vs_spv_data[] = { #include "test.vs.spv.h" }; static unsigned char g_test_ps_spv_data[] = { #include "test.ps.spv.h" }; static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf("%s: size: %u bytes\n", name, (unsigned int)size); if (size == 0) { return; } // if file is larger than 128 bytes, only dump first 64 and last 64 bytes uint32_t dump_size = size; uint32_t start_offset = 0; uint32_t end_offset = 0; uint32_t skip_size = 0; if (size > 128) { dump_size = 64; start_offset = 0; end_offset = size - 64; skip_size = end_offset - start_offset - dump_size; } // dump start for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } // print skip indicator if needed if (skip_size > 0) { printf(" ... (skipped %u bytes) ...\n", (unsigned int)skip_size); } // dump end if needed if (size > 128) { for (uint32_t offset = end_offset; offset < size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } } } int main(int argc, char** argv) { hexdump("test.vs.spv", g_test_vs_spv_data, (uint32_t)sizeof(g_test_vs_spv_data)); printf("\n"); hexdump("test.ps.spv", g_test_ps_spv_data, (uint32_t)sizeof(g_test_ps_spv_data)); return 0; } ================================================ FILE: tests/projects/other/hlsl2spv_bin2c/src/test.ps.hlsl ================================================ struct PSInput { float4 position : SV_POSITION; float2 texcoord : TEXCOORD0; }; float4 main(PSInput input) : SV_TARGET { return float4(input.texcoord, 0.0, 1.0); } ================================================ FILE: tests/projects/other/hlsl2spv_bin2c/src/test.vs.hlsl ================================================ struct VSInput { float3 position : POSITION; float2 texcoord : TEXCOORD0; }; struct VSOutput { float4 position : SV_POSITION; float2 texcoord : TEXCOORD0; }; VSOutput main(VSInput input) { VSOutput output; output.position = float4(input.position, 1.0); output.texcoord = input.texcoord; return output; } ================================================ FILE: tests/projects/other/hlsl2spv_bin2c/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("directxshadercompiler", {configs = {binaryonly = true}}) target("test") set_kind("binary") add_rules("utils.hlsl2spv", {bin2c = true}) add_files("src/*.c") add_files("src/*.vs.hlsl", "src/*.ps.hlsl") add_packages("directxshadercompiler") ================================================ FILE: tests/projects/other/hlsl2spv_bin2obj/src/main.c ================================================ #include #include #include extern const uint8_t _binary_test_vs_spv_start[]; extern const uint8_t _binary_test_vs_spv_end[]; extern const uint8_t _binary_test_ps_spv_start[]; extern const uint8_t _binary_test_ps_spv_end[]; static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf("%s: size: %u bytes\n", name, (unsigned int)size); if (size == 0) { return; } // if file is larger than 128 bytes, only dump first 64 and last 64 bytes uint32_t dump_size = size; uint32_t start_offset = 0; uint32_t end_offset = 0; uint32_t skip_size = 0; if (size > 128) { dump_size = 64; start_offset = 0; end_offset = size - 64; skip_size = end_offset - start_offset - dump_size; } // dump start for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } // print skip indicator if needed if (skip_size > 0) { printf(" ... (skipped %u bytes) ...\n", (unsigned int)skip_size); } // dump end if needed if (size > 128) { for (uint32_t offset = end_offset; offset < size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { printf("%02x ", data[offset + i]); } else { printf(" "); } if (i == 7) { printf(" "); } } // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { uint8_t c = data[offset + i]; printf("%c", isprint(c) ? c : '.'); } printf("|\n"); } } } int main(int argc, char** argv) { const uint32_t vs_size = (uint32_t)(_binary_test_vs_spv_end - _binary_test_vs_spv_start); const uint32_t ps_size = (uint32_t)(_binary_test_ps_spv_end - _binary_test_ps_spv_start); hexdump("test.vs.spv", _binary_test_vs_spv_start, vs_size); printf("\n"); hexdump("test.ps.spv", _binary_test_ps_spv_start, ps_size); return 0; } ================================================ FILE: tests/projects/other/hlsl2spv_bin2obj/src/test.ps.hlsl ================================================ struct PSInput { float4 position : SV_POSITION; float2 texcoord : TEXCOORD0; }; float4 main(PSInput input) : SV_TARGET { return float4(input.texcoord, 0.0, 1.0); } ================================================ FILE: tests/projects/other/hlsl2spv_bin2obj/src/test.vs.hlsl ================================================ struct VSInput { float3 position : POSITION; float2 texcoord : TEXCOORD0; }; struct VSOutput { float4 position : SV_POSITION; float2 texcoord : TEXCOORD0; }; VSOutput main(VSInput input) { VSOutput output; output.position = float4(input.position, 1.0); output.texcoord = input.texcoord; return output; } ================================================ FILE: tests/projects/other/hlsl2spv_bin2obj/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("glslang", {configs = {binaryonly = true}}) target("test") set_kind("binary") add_rules("utils.hlsl2spv", {bin2obj = true}) add_files("src/*.c") add_files("src/*.hlsl") add_packages("directxshadercompiler") ================================================ FILE: tests/projects/other/ispc/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/ispc/src/main.cpp ================================================ #include "test_ispc.h" using namespace ispc; int main(int argc, char *argv[]) { test_ispc(); } ================================================ FILE: tests/projects/other/ispc/src/test.ispc ================================================ export void test_ispc() {} ================================================ FILE: tests/projects/other/ispc/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_rules("utils.ispc", {header_extension = "_ispc.h"}) set_values("ispc.flags", "--target=host") add_files("src/*.ispc") add_files("src/*.cpp") ================================================ FILE: tests/projects/other/merge_archive/src/add.c ================================================ int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/merge_archive/src/mul.c ================================================ int mul(int a, int b) { return a * b; } ================================================ FILE: tests/projects/other/merge_archive/src/sub.c ================================================ int sub(int a, int b) { return a - b; } ================================================ FILE: tests/projects/other/merge_archive/test.lua ================================================ function main(t) -- Solaris ar does not support merging archives with duplicate object file names if is_host("solaris") then return end t:build() end ================================================ FILE: tests/projects/other/merge_archive/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("add") set_kind("static") add_files("src/add.c") set_policy("build.fence", true) set_targetdir("$(builddir)/merge_archive") target("sub") set_kind("static") add_files("src/sub.c") set_policy("build.fence", true) set_targetdir("$(builddir)/merge_archive") target("mul") set_kind("static") add_deps("add", "sub") add_files("src/mul.c") if is_plat("windows") then add_files("$(builddir)/merge_archive/*.lib") else add_files("$(builddir)/merge_archive/*.a") end ================================================ FILE: tests/projects/other/merge_archive2/src/add.c ================================================ int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/merge_archive2/src/main.c ================================================ #include int add(int a, int b); int sub(int a, int b); int mul(int a, int b); int subdir_add(int a, int b); int subdir_sub(int a, int b); int main(int argc, char** argv) { printf("%d\n", add(1, 1)); printf("%d\n", sub(1, 1)); printf("%d\n", mul(1, 1)); printf("%d\n", subdir_add(1, 1)); printf("%d\n", subdir_sub(1, 1)); return 0; } ================================================ FILE: tests/projects/other/merge_archive2/src/mul.c ================================================ int mul(int a, int b) { return a * b; } ================================================ FILE: tests/projects/other/merge_archive2/src/sub.c ================================================ int sub(int a, int b) { return a - b; } ================================================ FILE: tests/projects/other/merge_archive2/src/subdir/add.c ================================================ int subdir_add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/merge_archive2/src/subdir/sub.c ================================================ int subdir_sub(int a, int b) { return a - b; } ================================================ FILE: tests/projects/other/merge_archive2/test.lua ================================================ function main(t) -- Solaris ar does not support merging archives with duplicate object file names if is_host("solaris") then return end t:build() end ================================================ FILE: tests/projects/other/merge_archive2/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("add") set_kind("static") add_files("src/add.c") add_files("src/subdir/add.c") target("sub") set_kind("static") add_files("src/sub.c") add_files("src/subdir/sub.c") target("mul") set_kind("static") add_deps("add", "sub") add_files("src/mul.c") set_policy("build.merge_archive", true) target("test") add_deps("mul") add_files("src/main.c") ================================================ FILE: tests/projects/other/merge_object/src/interface.c ================================================ #include "interface.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/merge_object/src/interface.h ================================================ /*! calculate add(a, b) * * @param a the first argument * @param b the second argument * * @return the result */ int add(int a, int b); ================================================ FILE: tests/projects/other/merge_object/src/test.c ================================================ #include "interface.h" #include int main(int argc, char** argv) { printf("add(1, 2) = %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/other/merge_object/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/merge_object/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("merge_object") set_kind("static") add_files("src/interface.c") set_policy("build.fence", true) after_build_file(function (target, sourcefile) os.cp(target:objectfile(sourcefile), "$(builddir)/merge_object/") end) target("test") set_kind("binary") add_deps("merge_object") add_files("src/test.c") if is_plat("windows") then add_files("$(builddir)/merge_object/interface.c.obj") else add_files("$(builddir)/merge_object/interface.c.o") end ================================================ FILE: tests/projects/other/multiplats_vs/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/multiplats_vs/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/other/multiplats_vs/src/test.asm ================================================ ================================================ FILE: tests/projects/other/multiplats_vs/src/test.rc ================================================ ================================================ FILE: tests/projects/other/multiplats_vs/test.lua ================================================ function test_multivs(t) if is_subhost("windows") then t:build() else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/other/multiplats_vs/xmake.lua ================================================ add_rules("mode.debug", "mode.release") rule("vs2015_x86") on_load(function (target) target:set("arch", "x86") target:set("toolchains", "msvc", {vs = "2015"}) end) target("testvs_vs2015_x86") set_kind("binary") add_files("src/*.cpp", "src/*.rc") add_rules("vs2015_x86") target("testvs") set_kind("binary") add_files("src/*.cpp", "src/*.rc") ================================================ FILE: tests/projects/other/multiplats_xcode/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/other/multiplats_xcode/test.lua ================================================ function main(t) if is_host("macosx") then os.exec("xmake f -c -vD") os.exec("xmake -rvD") end end ================================================ FILE: tests/projects/other/multiplats_xcode/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test_host") set_kind("binary") add_files("src/*.c") target("test_iphoneos") set_kind("binary") add_files("src/*.c") set_plat("iphoneos") ================================================ FILE: tests/projects/other/native_module/cjson/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/native_module/cjson/modules/lua/cjson/src/cjson.c ================================================ #include int luaopen_cjson(lua_State* lua); int luaopen(cjson, lua_State* lua) { return luaopen_cjson(lua); } ================================================ FILE: tests/projects/other/native_module/cjson/modules/lua/cjson/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("cjson") add_rules("module.shared") set_warnings("all") if is_plat("windows") then set_languages("c89") end add_files("src/*.c") add_files("../../../../../../../../core/src/lua-cjson/lua-cjson/*.c|fpconv.c") -- Use internal strtod() / g_fmt() code for performance and disable multi-thread add_defines("NDEBUG", "USE_INTERNAL_FPCONV") add_defines("XM_CONFIG_API_HAVE_LUA_CJSON") if is_plat("windows") then -- Windows sprintf()/strtod() handle NaN/inf differently. Not supported. add_defines("DISABLE_INVALID_NUMBERS") add_defines("inline=__inline") end ================================================ FILE: tests/projects/other/native_module/cjson/src/main.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/projects/other/native_module/cjson/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/native_module/cjson/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_moduledirs("modules") target("test") set_kind("binary") add_files("src/*.cpp") on_config(function (target) import("lua.cjson", {always_build = true}) print(cjson.decode('{"foo": 1, "bar": [1, 2, 3]}')) end) ================================================ FILE: tests/projects/other/native_module/hello/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/native_module/hello/modules/binary/bar/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/native_module/hello/modules/binary/bar/src/add.cpp ================================================ #include #include int main(int argc, char** argv) { int a = atoi(argv[1]); int b = atoi(argv[2]); printf("%d", a + b); return 0; } ================================================ FILE: tests/projects/other/native_module/hello/modules/binary/bar/src/sub.cpp ================================================ #include #include int main(int argc, char** argv) { int a = atoi(argv[1]); int b = atoi(argv[2]); printf("%d", a - b); return 0; } ================================================ FILE: tests/projects/other/native_module/hello/modules/binary/bar/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("add") add_rules("module.binary") add_files("src/add.cpp") target("sub") add_rules("module.binary") add_files("src/sub.cpp") ================================================ FILE: tests/projects/other/native_module/hello/modules/shared/foo/src/foo.c ================================================ #include static int add(lua_State* lua) { int a = lua_tointeger(lua, 1); int b = lua_tointeger(lua, 2); lua_pushinteger(lua, a + b); return 1; } static int sub(lua_State* lua) { int a = lua_tointeger(lua, 1); int b = lua_tointeger(lua, 2); lua_pushinteger(lua, a - b); return 1; } int luaopen(foo, lua_State* lua) { static const luaL_Reg funcs[] = { {"add", add}, {"sub", sub}, {NULL, NULL} }; lua_newtable(lua); luaL_setfuncs(lua, funcs, 0); return 1; } ================================================ FILE: tests/projects/other/native_module/hello/modules/shared/foo/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") add_rules("module.shared") add_files("src/foo.c") ================================================ FILE: tests/projects/other/native_module/hello/src/main.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "hello world!" << std::endl; return 0; } ================================================ FILE: tests/projects/other/native_module/hello/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/native_module/hello/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_moduledirs("modules") target("test") set_kind("binary") add_files("src/*.cpp") on_config(function (target) import("shared.foo", {always_build = true}) import("binary.bar") print("foo: 1 + 1 = %d", foo.add(1, 1)) print("foo: 1 - 1 = %d", foo.sub(1, 1)) print("bar: 1 + 1 = %s", bar.add(1, 1)) print("bar: 1 - 1 = %s", bar.sub(1, 1)) end) ================================================ FILE: tests/projects/other/object_only/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/object_only/src/foo.cpp ================================================ #include "foo.h" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/other/object_only/src/foo.h ================================================ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif ================================================ FILE: tests/projects/other/object_only/src/main.cpp ================================================ #include "foo.h" #include int main(int argc, char** argv) { std::cout << "add(1, 2) = " << add(1, 2) << std::endl; return 0; } ================================================ FILE: tests/projects/other/object_only/test.lua ================================================ function main(t) t:build() end ================================================ FILE: tests/projects/other/object_only/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("bar") set_kind("object") add_files("src/foo.cpp") target("foo") set_kind("static") add_deps("bar") add_rules("c++") target("test") set_kind("binary") add_deps("foo") add_files("src/main.cpp") ================================================ FILE: tests/projects/other/parallel_build/1.cpp ================================================ int main(int argv, char** argv) { return 0; } ================================================ FILE: tests/projects/other/parallel_build/2.cpp ================================================ // Make this object complex and cost longer compile time... #include #include #include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char** argv) { using Type = std::variant; Type a, b, c; a = 5; b = 3.0; c = 4.0f; double r; std::visit([&](auto a, auto b, auto c) { r = a + b + c; }, a, b, c); std::visit([&](auto a, auto b, auto c) { r = a + b - c; }, a, b, c); std::visit([&](auto a, auto b, auto c) { r = a - b - c; }, a, b, c); std::visit([&](auto a, auto b, auto c) { r = (a + b + c) * 2; }, a, b, c); std::visit([&](auto a, auto b, auto c) { r = (a + b - c) * 3; }, a, b, c); return 0; } ================================================ FILE: tests/projects/other/parallel_build/xmake.lua ================================================ -- These targets should compiled and linked concurrently. add_rules("mode.release", "mode.debug", "mode.releasedbg") set_policy("build.ccache", false) target("first") set_kind("binary") add_files("1.cpp") set_languages("clatest", "cxx20") target("second") set_kind("binary") add_files("2.cpp") set_languages("clatest", "cxx20") ================================================ FILE: tests/projects/other/parse_headerdeps/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/other/parse_headerdeps/common/test1.hpp ================================================ // ../common/test1.hpp #include void f() { std::cout << "f()" << std::endl; } ================================================ FILE: tests/projects/other/parse_headerdeps/src/test1.cpp ================================================ // test1.cpp #include "common/test1.hpp" int main(int argc, char** argv) { f(); return 0; } ================================================ FILE: tests/projects/other/parse_headerdeps/src/xmake.lua ================================================ -- xmake.lua -- global add_rules('mode.debug', 'mode.release') set_version('0.1.0') set_kind('binary') add_includedirs('..') set_warnings('all') --set_languages('cxx20') target('test1') add_files('test1.cpp') ================================================ FILE: tests/projects/package/basic/src/main.c ================================================ #include #include int test(); int main(int argc, char** argv) { printf("hello world!\n"); pcre2_compile(0, 0, 0, 0, 0, 0); test(); return 0; } ================================================ FILE: tests/projects/package/basic/src/test.c ================================================ #include #include int test() { printf("hello world!\n"); pcre2_compile(0, 0, 0, 0, 0, 0); return 0; } ================================================ FILE: tests/projects/package/basic/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/basic/xmake.lua ================================================ add_requires("tbox master", {debug = true}) add_requires("zlib >=1.2.11") add_requires("pcre2", {system = false, optional = true}) add_rules("mode.debug", "mode.release") target("test") set_kind("static") add_files("src/test.c") add_packages("pcre2", {public = true}) target("console") set_kind("binary") add_deps("test") add_files("src/main.c") add_packages("tbox", "zlib") ================================================ FILE: tests/projects/package/brew/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/brew/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/package/brew/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("brew::pcre2/libpcre2-8", {alias = "pcre2"}) target("brew") set_kind("binary") add_files("src/*.cpp") add_packages("pcre2") ================================================ FILE: tests/projects/package/cmake/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/cmake/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/package/cmake/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("cmake::ZLIB", {system = true}) add_requires("cmake::LibXml2", {system = true}) add_requires("cmake::Boost", {system = true, configs = {components = {"regex", "system"}, presets = {Boost_USE_STATIC_LIB = true}}}) target("test") set_kind("binary") add_files("src/*.cpp") add_packages("cmake::ZLIB", "cmake::Boost", "cmake::LibXml2") ================================================ FILE: tests/projects/package/compatibility/deps_with_version/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/compatibility/deps_with_version/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/compatibility/deps_with_version/xmake.lua ================================================ package("foo") add_deps("zlib >=1.2.13") set_policy("package.install_locally", true) on_install(function () end) package_end() package("bar") add_deps("zlib 1.2.x") -- add_deps("libpng dev") -- add_deps("boost", {system = false, configs = {zlib = false}}) set_policy("package.install_locally", true) on_install(function () end) package_end() package("zoo") -- add_deps("libpng master") -- add_deps("boost", {system = false, configs = {zlib = true}}) set_policy("package.install_locally", true) on_install(function () end) package_end() package("test") add_deps("foo", "bar", "zoo") set_policy("package.install_locally", true) on_install(function () end) package_end() add_requires("test") --add_requireconfs("**.boost", {override = true, configs = {zlib = false}}) target("test") set_kind("binary") add_files("src/*.c") add_packages("test") ================================================ FILE: tests/projects/package/compatibility/sync_requires_to_deps/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/compatibility/sync_requires_to_deps/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/compatibility/sync_requires_to_deps/xmake.lua ================================================ package("foo") add_deps("zlib >=1.2.13") set_policy("package.install_locally", true) on_install(function () end) package_end() package("bar") add_deps("zlib 1.2.x") set_policy("package.install_locally", true) on_install(function () end) package_end() package("zoo") set_policy("package.install_locally", true) on_install(function () end) package_end() package("test") add_deps("foo", "bar", "zoo") set_policy("package.install_locally", true) on_install(function () end) package_end() set_policy("package.sync_requires_to_deps", true) add_requires("test") add_requires("zlib >=1.2.13", {system = false, configs = {shared = true}}) target("test") set_kind("binary") add_files("src/*.c") add_packages("test") ================================================ FILE: tests/projects/package/components/src/graphics.cpp ================================================ #include extern "C" { void graphics() { sf::Text text; text.setString("Hello world"); } } ================================================ FILE: tests/projects/package/components/src/main.cpp ================================================ #include #include extern "C" { void network(); void graphics(); } int main(int argc, char** argv) { network(); graphics(); return 0; } ================================================ FILE: tests/projects/package/components/src/network.cpp ================================================ #include extern "C" { void network() { sf::UdpSocket socket; socket.bind(54000); char data[100]; std::size_t received; sf::IpAddress sender; unsigned short port; socket.receive(data, 100, received, sender, port); } } ================================================ FILE: tests/projects/package/components/test.lua ================================================ function main(t) if is_host("bsd", "solaris", "haiku") or is_subhost("msys") then return end if is_host("linux") and linuxos.name() == "alpine" then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/components/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("sfml") target("graphics") set_kind("static") add_files("src/graphics.cpp") add_packages("sfml", {components = "graphics", public = true}) target("network") set_kind("static") add_files("src/network.cpp") add_packages("sfml", {components = "network", public = true}) target("test") set_kind("binary") add_files("src/main.cpp") add_deps("graphics", "network") package("sfml") set_homepage("https://www.sfml-dev.org") set_description("Simple and Fast Multimedia Library") if is_plat("windows", "linux") then set_urls("https://www.sfml-dev.org/files/SFML-$(version)-sources.zip") add_urls("https://github.com/SFML/SFML/releases/download/$(version)/SFML-$(version)-sources.zip") add_versions("2.5.1", "bf1e0643acb92369b24572b703473af60bac82caf5af61e77c063b779471bb7f") elseif is_plat("macosx") then if is_arch("x64", "x86_64") then set_urls("https://www.sfml-dev.org/files/SFML-$(version)-macOS-clang.tar.gz") add_versions("2.5.1", "6af0f14fbd41dc038a00d7709f26fb66bb7ccdfe6187657ef0ef8cba578dcf14") add_configs("debug", {builtin = true, description = "Enable debug symbols.", default = false, type = "boolean", readonly = true}) add_configs("shared", {description = "Build shared library.", default = true, type = "boolean", readonly = true}) end end if is_plat("linux") then add_syslinks("pthread") end add_configs("graphics", {description = "Use the graphics module", default = true, type = "boolean"}) add_configs("window", {description = "Use the window module", default = true, type = "boolean"}) add_configs("audio", {description = "Use the audio module", default = true, type = "boolean"}) add_configs("network", {description = "Use the network module", default = true, type = "boolean"}) if is_plat("windows") then add_configs("main", {description = "Link to the sfml-main library", default = true, type = "boolean"}) end if is_plat("macosx") then add_extsources("brew::sfml/sfml-all") end on_component("graphics", function (package, component) local e = package:config("shared") and "" or "-s" if package:debug() then e = e .. "-d" end component:add("links", "sfml-graphics" .. e) if package:is_plat("windows") and not package:config("shared") then component:add("links", "freetype") component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32") end component:add("deps", "window", "system") component:add("extsources", "brew::sfml/sfml-graphics") end) on_component("window", function (package, component) local e = package:config("shared") and "" or "-s" if package:debug() then e = e .. "-d" end component:add("links", "sfml-window" .. e) if package:is_plat("windows") and not package:config("shared") then component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32") end component:add("deps", "system") component:add("extsources", "brew::sfml/sfml-window") end) on_component("audio", function (package, component) local e = package:config("shared") and "" or "-s" if package:debug() then e = e .. "-d" end component:add("links", "sfml-audio" .. e) if package:is_plat("windows") and not package:config("shared") then component:add("links", "openal32", "flac", "vorbisenc", "vorbisfile", "vorbis", "ogg") end component:add("deps", "system") component:add("extsources", "brew::sfml/sfml-audio") end) on_component("network", function (package, component) local e = package:config("shared") and "" or "-s" if package:debug() then e = e .. "-d" end component:add("links", "sfml-network" .. e) if package:is_plat("windows") and not package:config("shared") then component:add("syslinks", "ws2_32") end component:add("deps", "system") component:add("extsources", "brew::sfml/sfml-network") component:add("extsources", "apt::sfml-network") end) on_component("system", function (package, component) local e = package:config("shared") and "" or "-s" if package:debug() then e = e .. "-d" end component:add("links", "sfml-system" .. e) if package:is_plat("windows") then component:add("syslinks", "winmm") end if package:is_plat("windows") and package:config("main") then component:add("deps", "main") end component:add("extsources", "brew::sfml/sfml-system") end) on_component("main", function (package, component) if package:is_plat("windows") then local main_module = "sfml-main" if package:debug() then main_module = main_module .. "-d" end component:add("links", main_module) end end) on_load("windows", "linux", "macosx", function (package) if package:is_plat("windows", "linux") then package:add("deps", "cmake") end if not package:config("shared") then package:add("defines", "SFML_STATIC") end if package:is_plat("linux") then if package:config("window") or package:config("graphics") then package:add("deps", "libx11", "libxext", "libxrandr", "libxrender", "freetype", "eudev") package:add("deps", "opengl", "glx", {optional = true}) end if package:config("audio") then package:add("deps", "libogg", "libflac", "libvorbis", "openal-soft") end end package:add("components", "system") for _, component in ipairs({"graphics", "window", "audio", "network"}) do if package:config(component) then package:add("components", component) end end if package:is_plat("windows") and package:config("main") then package:add("components", "main") end end) on_install("windows", "linux", function (package) local configs = {"-DSFML_BUILD_DOC=OFF", "-DSFML_BUILD_EXAMPLES=OFF"} table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release")) if package:config("shared") then table.insert(configs, "-DBUILD_SHARED_LIBS=ON") else table.insert(configs, "-DBUILD_SHARED_LIBS=OFF") if package:is_plat("windows") and package:runtimes():startswith("MT") then table.insert(configs, "-DSFML_USE_STATIC_STD_LIBS=ON") end end local packagedeps if package:is_plat("linux") and package:config("shared") then io.replace("src/SFML/Graphics/CMakeLists.txt", "target_link_libraries(sfml-graphics PRIVATE X11)", "target_link_libraries(sfml-graphics PRIVATE X11 Xext Xrender)", {plain = true}) packagedeps = {"libxext", "libxrender"} end table.insert(configs, "-DSFML_BUILD_AUDIO=" .. (package:config("audio") and "ON" or "OFF")) table.insert(configs, "-DSFML_BUILD_GRAPHICS=" .. (package:config("graphics") and "ON" or "OFF")) table.insert(configs, "-DSFML_BUILD_WINDOW=" .. (package:config("window") and "ON" or "OFF")) table.insert(configs, "-DSFML_BUILD_NETWORK=" .. (package:config("network") and "ON" or "OFF")) import("package.tools.cmake").install(package, configs, {packagedeps = packagedeps}) end) on_install("macosx", function (package) os.cp("lib", package:installdir()) os.cp("include", package:installdir()) end) on_test(function (package) assert(package:check_cxxsnippets({test = [[ void test(int args, char** argv) { sf::Clock c; c.restart(); } ]]}, {includes = "SFML/System.hpp"})) if package:config("graphics") then assert(package:check_cxxsnippets({test = [[ void test(int args, char** argv) { sf::Text text; text.setString("Hello world"); } ]]}, {includes = "SFML/Graphics.hpp"})) end if package:config("window") or package:config("graphics") then assert(package:check_cxxsnippets({test = [[ void test(int args, char** argv) { sf::Window window(sf::VideoMode(1280, 720), "Title"); sf::Event event; window.pollEvent(event); } ]]}, {includes = "SFML/Window.hpp"})) end if package:config("audio") then assert(package:check_cxxsnippets({test = [[ void test(int args, char** argv) { sf::Music music; music.openFromFile("music.ogg"); music.play(); } ]]}, {includes = "SFML/Audio.hpp"})) end if package:config("network") then assert(package:check_cxxsnippets({test = [[ void test(int args, char** argv) { sf::UdpSocket socket; socket.bind(54000); char data[100]; std::size_t received; sf::IpAddress sender; unsigned short port; socket.receive(data, 100, received, sender, port); } ]]}, {includes = "SFML/Network.hpp"})) end end) package_end() ================================================ FILE: tests/projects/package/conan/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/conan/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/package/conan/xmake.lua ================================================ add_requires("conan::zlib 1.2.11", {alias = "zlib", debug = true, configs = {settings = "compiler.cppstd=14"}}) add_requires("conan::openssl 1.1.1t", {alias = "openssl", configs = {options = "shared=True"}}) target("test") set_kind("binary") add_files("src/*.cpp") add_packages("openssl", "zlib") ================================================ FILE: tests/projects/package/depconfigs/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/depconfigs/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/depconfigs/xmake.lua ================================================ add_requires("libpng", {system = false, configs = {runtimes = "MD"}}) add_requires("libtiff", {system = false, configs = {runtimes = "MD", zlib = true}}) add_requireconfs("libpng.zlib", {system = false, override = true, configs = {cxflags = "-DTEST1"}, version = "1.2.10"}) add_requireconfs("libtiff.*|cmake", {system = false, configs = {cxflags = "-DTEST2"}}) target("test") set_kind("binary") add_files("src/*.c") add_packages("libpng") before_build(function (target) if target:pkg("libpng") then local found for _, linkdir in ipairs(target:pkg("libpng"):get("linkdirs")) do if linkdir:find("zlib[/\\]v1%.2%.10") then found = true end end assert(found, "package(zlib 1.2.10) not found!") end end) target("test2") set_kind("binary") add_files("src/*.c") add_packages("libtiff") before_build(function (target) if target:pkg("libtiff") then local found for _, linkdir in ipairs(target:pkg("libtiff"):get("linkdirs")) do if linkdir:find("zlib", 1, true) then found = true end end assert(found, "package(zlib) not found!") end end) ================================================ FILE: tests/projects/package/inherit_base/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/inherit_base/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/inherit_base/xmake.lua ================================================ package("myzlib") set_base("zlib") set_urls("https://github.com/madler/zlib.git") package_end() add_requires("myzlib", {system = false, alias = "zlib"}) target("test") set_kind("binary") add_files("src/*.c") add_packages("zlib") ================================================ FILE: tests/projects/package/llvm_dev/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/llvm_dev/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/package/llvm_dev/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("llvm", {kind = "library", configs = {mlir = true}}) target("testllvm") set_kind("binary") add_files("src/*.cpp") add_packages("llvm", {components = "mlir"}) ================================================ FILE: tests/projects/package/multiconfig/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/multiconfig/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/multiconfig/xmake.lua ================================================ add_requires("zlib", {system = false}) add_requires("zlib", {system = false}) -- test repeat requires add_requires("zlib~debug", {system = false, debug = true}) add_requires("zlib~shared", {system = false, configs = {shared = true}, alias = "zlib_shared"}) set_policy("package.requires_lock", true) target("test1") set_kind("binary") add_files("src/*.c") add_packages("zlib") target("test2") set_kind("binary") add_files("src/*.c") add_packages("zlib~debug") target("test3") set_kind("binary") add_files("src/*.c") add_packages("zlib_shared") ================================================ FILE: tests/projects/package/multiplat/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/multiplat/src/main.cpp ================================================ /******************************************************************************************* * * raylib [core] example - Basic window * * Welcome to raylib! * * To test examples, just press F6 and execute raylib_compile_execute script * Note that compiled executable is placed in the same folder as .c file * * You can find all basic examples on C:\raylib\raylib\examples folder or * raylib official webpage: www.raylib.com * * Enjoy using raylib. :) * * This example has been created using raylib 1.0 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * * Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" int main(void) { // Initialization //-------------------------------------------------------------------------------------- const int screenWidth = 800; const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- // TODO: Update your variables here //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); ClearBackground(RAYWHITE); DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; } ================================================ FILE: tests/projects/package/multiplat/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("raylib") add_requires("raylib~mingw", {plat = "mingw", arch = "x86_64"}) target("hello") add_packages("raylib") set_kind("binary") add_files("src/*.cpp") set_languages("c++11") target("hello_mingw") set_plat("mingw") set_arch("x86_64") add_packages("raylib~mingw") set_kind("binary") add_files("src/*.cpp") ================================================ FILE: tests/projects/package/nuget/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/nuget/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/package/nuget/xmake.lua ================================================ add_requires("nuget::zlib_static", {alias = "zlib"}) target("test") set_kind("binary") add_files("src/*.cpp") add_packages("zlib") ================================================ FILE: tests/projects/package/package_rule/repo/packages/f/foo/rules/markdown.lua ================================================ rule("markdown") set_extensions(".md") on_config(function (target) print("test: config %s", target:name()) end) on_build_file(function(target, sourcefile) print("test: build %s", sourcefile) end) after_clean(function (target) print("test: clean") end) ================================================ FILE: tests/projects/package/package_rule/repo/packages/f/foo/xmake.lua ================================================ package("foo") on_install(function() end) ================================================ FILE: tests/projects/package/package_rule/src/main.cpp ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/package_rule/src/test.md ================================================ ================================================ FILE: tests/projects/package/package_rule/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/package_rule/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("foo") add_repositories("myrepo ./repo") target("console") set_kind("binary") add_files("src/main.cpp", "src/*.md") add_packages("foo") add_rules("@foo/markdown") ================================================ FILE: tests/projects/package/requires_lock/src/main.c ================================================ #include #include #include #include int main(int argc, char** argv) { printf("zlib version: %s\n", zlibVersion()); // simple compression test const char* source = "Hello, zlib requires lock test!"; uLong sourceLen = strlen(source) + 1; uLong destLen = compressBound(sourceLen); Bytef* dest = (Bytef*)malloc(destLen); if (compress(dest, &destLen, (const Bytef*)source, sourceLen) == Z_OK) { printf("Compression successful, compressed size: %lu\n", destLen); // decompression test uLong decompLen = sourceLen; Bytef* decomp = (Bytef*)malloc(decompLen); if (uncompress(decomp, &decompLen, dest, destLen) == Z_OK) { printf("Decompression successful: %s\n", (char*)decomp); } free(decomp); } free(dest); return 0; } ================================================ FILE: tests/projects/package/requires_lock/test.lua ================================================ import("core.project.config") -- helper function to count table entries function count_table(t) local count = 0 for _ in pairs(t) do count = count + 1 end return count end -- helper function to get all package keys from lock data function get_package_keys(lockdata) local keys = {} for key, _ in pairs(lockdata) do if key ~= "__meta__" then table.insert(keys, key) end end return keys end -- helper function to verify lock file basic structure function verify_lock_file_structure(lockdata) assert(lockdata, "lock file should be loadable") assert(lockdata.__meta__, "lock file should have metadata") assert(lockdata.__meta__.version == "1.0", "lock file version should be 1.0") -- find any platform entry local found_platform = nil for key, value in pairs(lockdata) do if key ~= "__meta__" then found_platform = key break end end assert(found_platform, "no platform entries found in lock file") return lockdata[found_platform] end -- helper function to count zlib entries function count_zlib_entries(plat_entries) local zlib_count = 0 for key, _ in pairs(plat_entries) do if key:find("zlib") then zlib_count = zlib_count + 1 end end return zlib_count end -- helper function to remove installed packages to trigger reinstallation function remove_zlib_packages() os.execv("xmake", {"lua", "private.xrepo", "remove", "--all", "-y", "zlib"}) end -- helper function to remove existing lock file function remove_lock_file(scriptdir) local lockfile = path.join(scriptdir, "xmake-requires.lock") os.tryrm(lockfile) end -- test lock file generation and basic content validation function test_lock_file_generation(scriptdir) local lockfile = path.join(scriptdir, "xmake-requires.lock") assert(os.isfile(lockfile), "xmake-requires.lock should be generated") -- load and verify lock file content local lockdata = io.load(lockfile) local plat_entries = verify_lock_file_structure(lockdata) -- check zlib entries and repo info local found_zlib = false for key, package_data in pairs(plat_entries) do if key:find("zlib#") then found_zlib = true assert(package_data.version, "zlib should have version") assert(package_data.repo, "zlib should have repo info") assert(package_data.repo.url, "zlib repo should have url") assert(package_data.repo.commit, "zlib repo should have commit") end end -- we should have three zlib entries (version constraint, specific version, shared config) local zlib_count = count_zlib_entries(plat_entries) assert(zlib_count == 3, "should find 3 zlib entries in lock file, found: " .. zlib_count) assert(found_zlib, "should find zlib entry in lock file") -- verify specific versions are locked correctly local found_old_version = false for key, package_data in pairs(plat_entries) do if key:find("zlib 1.2.13#") then found_old_version = true assert(package_data.version == "v1.2.13", "zlib 1.2.13 should be locked to v1.2.13") end end assert(found_old_version, "should find zlib 1.2.13 entry with v1.2.13") print("✓ lock file generation test passed") end -- test lock file stability across rebuilds function test_lock_file_stability(scriptdir, t) local lockfile = path.join(scriptdir, "xmake-requires.lock") -- get the lock file content and mtime after first build local lockdata_after_first = io.load(lockfile) local mtime_after_first = os.mtime(lockfile) local keys_after_first = get_package_keys(lockdata_after_first) -- remove installed packages using xmake lua private.xrepo to trigger reinstallation remove_zlib_packages() -- rebuild and verify lock file content doesn't change t:build() local lockdata_after_second = io.load(lockfile) local mtime_after_second = os.mtime(lockfile) local keys_after_second = get_package_keys(lockdata_after_second) -- compare lock file content assert(lockdata_after_first.__meta__.version == lockdata_after_second.__meta__.version, "lock metadata version should not change") assert(count_table(lockdata_after_first) == count_table(lockdata_after_second), "lock file structure should not change") -- compare platform-specific entries using the same platform for consistency local plat_entries_after_first = verify_lock_file_structure(lockdata_after_first) local plat_entries_after_second = verify_lock_file_structure(lockdata_after_second) -- ensure we're comparing the same platform entries by finding the common platform local first_platform_key = nil for key, value in pairs(lockdata_after_first) do if key ~= "__meta__" then first_platform_key = key break end end assert(first_platform_key, "no platform found in first lock file") assert(lockdata_after_second[first_platform_key], "platform " .. first_platform_key .. " not found in second lock file") plat_entries_after_first = lockdata_after_first[first_platform_key] plat_entries_after_second = lockdata_after_second[first_platform_key] assert(count_table(plat_entries_after_first) == count_table(plat_entries_after_second), "platform entries count should not change") -- verify package key order stability (keys should be in same order) assert(#keys_after_first == #keys_after_second, "package keys count should be the same") for i, key in ipairs(keys_after_first) do assert(keys_after_second[i] == key, "package key order should be stable at index " .. i .. ": " .. key) end -- verify each package entry is identical for key, first_data in pairs(plat_entries_after_first) do local second_data = plat_entries_after_second[key] assert(second_data, "package entry should exist: " .. key) assert(first_data.version == second_data.version, "version should not change for: " .. key .. ", first: " .. (first_data.version or "nil") .. ", second: " .. (second_data.version or "nil")) assert(first_data.repo.url == second_data.repo.url, "repo url should not change for: " .. key .. ", first: " .. (first_data.repo.url or "nil") .. ", second: " .. (second_data.repo.url or "nil")) assert(first_data.repo.commit == second_data.repo.commit, "repo commit should not change for: " .. key .. ", first: " .. (first_data.repo.commit or "nil") .. ", second: " .. (second_data.repo.commit or "nil")) assert(first_data.repo.branch == second_data.repo.branch, "repo branch should not change for: " .. key .. ", first: " .. (first_data.repo.branch or "nil") .. ", second: " .. (second_data.repo.branch or "nil")) end -- verify mtime doesn't change (lock file should only be written when content actually changes) -- With copy_if_different, the file should not be rewritten if content is identical local time_diff = math.abs(mtime_after_second - mtime_after_first) print("lock file mtime difference: " .. time_diff .. "s") -- mtime should be exactly the same when content is identical assert(time_diff == 0, "lock file mtime should not change when content is identical, diff: " .. time_diff .. "s") print("✓ lock file stability test passed") end function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then -- get script directory from context filename local scriptdir = path.directory(t.filename) -- remove existing lock file before test remove_lock_file(scriptdir) -- remove installed packages using xmake lua private.xrepo to trigger reinstallation remove_zlib_packages() -- build project and generate requires lock t:build() -- test requires lock file generation and content test_lock_file_generation(scriptdir) -- test building with existing lock file t:build() -- test lock file stability across rebuilds test_lock_file_stability(scriptdir, t) print("requires lock test passed!") end end ================================================ FILE: tests/projects/package/requires_lock/xmake.lua ================================================ -- test requires lock functionality with zlib package set_policy("package.requires_lock", true) add_requires("zlib >=1.2.11", {system = false}) add_requires("zlib 1.2.13", {system = false, alias = "zlib_old"}) -- test lower version add_requires("zlib", {system = false, configs = {shared = true}, alias = "zlib_shared"}) target("test_static") set_kind("binary") add_files("src/*.c") add_packages("zlib") target("test_shared") set_kind("binary") add_files("src/*.c") add_packages("zlib_shared") target("test_old") set_kind("binary") add_files("src/*.c") add_packages("zlib_old") ================================================ FILE: tests/projects/package/rootconfigs/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/rootconfigs/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end -- test packagekey os.execv("xmake", {"lua", "-vD", "utils.ci.packageskey"}) end ================================================ FILE: tests/projects/package/rootconfigs/xmake.lua ================================================ add_requireconfs("*", {system = false, configs = {debug = false}}) add_requires("zlib", {system = false, debug = true}) target("test") set_kind("binary") add_files("src/*.c") add_packages("zlib") ================================================ FILE: tests/projects/package/schemes/port/xmake.lua ================================================ includes("@builtin/check") add_rules("mode.release", "mode.debug") option("version", {description = "The ninja version."}) set_version("$(version)") set_languages("c++14") check_cfuncs("USE_PPOLL=1", "ppoll", {includes = "poll.h"}) target("libninja") set_kind("$(kind)") set_basename("ninja") add_files("src/build_log.cc") add_files("src/build.cc") add_files("src/clean.cc") add_files("src/clparser.cc") add_files("src/debug_flags.cc") add_files("src/deps_log.cc") add_files("src/disk_interface.cc") add_files("src/edit_distance.cc") add_files("src/eval_env.cc") add_files("src/graph.cc") add_files("src/graphviz.cc") add_files("src/line_printer.cc") add_files("src/manifest_parser.cc") add_files("src/metrics.cc") add_files("src/state.cc") add_files("src/string_piece_util.cc") add_files("src/util.cc") add_files("src/version.cc") add_files("src/depfile_parser.cc", "src/lexer.cc") if is_plat("windows", "mingw", "msys") then add_files("src/subprocess-win32.cc") add_files("src/includes_normalize-win32.cc") add_files("src/msvc_helper-win32.cc") add_files("src/msvc_helper_main-win32.cc") add_files("src/getopt.c", {sourcekind = "cxx"}) add_files("src/minidump-win32.cc") add_defines("NOMINMAX") else add_files("src/subprocess-posix.cc") end if is_plat("mingw") then add_defines("_WIN32_WINNT=0x0601", "__USE_MINGW_ANSI_STDIO=1") end on_load(function (target) import("core.base.semver") local version = semver.new(target:version()) if version:ge("1.13.1") then target:add("files", "src/elide_middle.cc") target:add("files", "src/jobserver.cc") target:add("files", "src/real_command_runner.cc") target:add("files", "src/status_printer.cc") if target:is_plat("windows", "mingw", "msys") then target:add("files", "src/jobserver-win32.cc") else target:add("files", "src/jobserver-posix.cc") end end if version:ge("1.11.0") then if version:lt("1.13.1") then target:add("files", "src/status.cc") end target:add("files", "src/json.cc") target:add("files", "src/missing_deps.cc") end if version:ge("1.10.0") then target:add("files", "src/dyndep.cc") target:add("files", "src/dyndep_parser.cc") target:add("files", "src/parser.cc") end end) target("ninja") set_kind("binary") add_deps("libninja") add_files("src/ninja.cc") if is_plat("windows") then add_files("windows/ninja.manifest") end ================================================ FILE: tests/projects/package/schemes/src/main.cpp ================================================ #include int main(int argc, char** argv) { std::cout << "Hello, schemes test!" << std::endl; return 0; } ================================================ FILE: tests/projects/package/schemes/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/schemes/xmake.lua ================================================ add_rules("mode.debug", "mode.release") package("ninja") set_kind("binary") set_homepage("https://ninja-build.org/") set_description("Small build system for use with gyp or CMake.") local function add_binary_urls(package, scheme_name) local scheme = package if scheme_name then scheme = package:scheme(scheme_name) end if is_host("macosx") then scheme:add("urls", "https://github.com/ninja-build/ninja/releases/download/v$(version)/ninja-mac.zip") scheme:add("versions", "1.13.1", "da7797794153629aca5570ef7c813342d0be214ba84632af886856e8f0063dd9") return true elseif is_host("linux") then scheme:add("urls", "https://github.com/ninja-build/ninja/releases/download/v$(version)/ninja-linux.zip") scheme:add("versions", "1.13.1", "0830252db77884957a1a4b87b05a1e2d9b5f658b8367f82999a941884cbe0238") return true elseif is_host("windows") then scheme:add("urls", "https://github.com/ninja-build/ninja/releases/download/v$(version)/ninja-win.zip") scheme:add("versions", "1.13.1", "26a40fa8595694dec2fad4911e62d29e10525d2133c9a4230b66397774ae25bf") return true end end local function add_source_urls(package, scheme_name) local scheme = package if scheme_name then scheme = package:scheme(scheme_name) end scheme:add("urls", "https://github.com/ninja-build/ninja/archive/refs/tags/v$(version).tar.gz") scheme:add("versions", "1.13.1", "f0055ad0369bf2e372955ba55128d000cfcc21777057806015b45e4accbebf23") end if add_schemes then add_schemes("binary", "source") on_source(function (package) add_binary_urls(package, "binary") add_source_urls(package, "source") end) else -- for compatibility with older xmake versions on_source(function (package) if add_binary_urls(package) then package:data_set("scheme", "binary") else add_source_urls(package) package:data_set("scheme", "source") end end) end on_install("@linux", "@windows", "@msys", "@cygwin", "@macosx", function (package) local scheme_name = package.current_scheme and package:current_scheme():name() or package:data("scheme") if scheme_name and scheme_name == "binary" then raise("trigger failure when installing binaries, then we will fallback to install it from source tarball.") else local configs = {} configs.version = package:version_str() os.cp(path.join(package:scriptdir(), "port", "xmake.lua"), "xmake.lua") import("package.tools.xmake").install(package, configs) end end) on_test(function (package) os.vrun("ninja --version") end) package_end() add_requires("ninja", {system = false}) target("test") set_kind("binary") add_files("src/*.cpp") add_packages("ninja") ================================================ FILE: tests/projects/package/toolchain_gnu_rm/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/toolchain_gnu_rm/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("gnu-rm") target("test") set_kind("binary") add_files("src/*.c") set_toolchains("@gnu-rm") ================================================ FILE: tests/projects/package/toolchain_llvm/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/toolchain_llvm/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("llvm 14.0.0", {alias = "llvm-14"}) target("test") set_kind("binary") add_files("src/*.c") set_toolchains("llvm@llvm-14") ================================================ FILE: tests/projects/package/toolchain_llvm_mingw/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/toolchain_llvm_mingw/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("llvm-mingw") target("test") set_kind("binary") add_files("src/*.c") set_toolchains("mingw[clang]@llvm-mingw") ================================================ FILE: tests/projects/package/toolchain_msvc/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/toolchain_msvc/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("msvc") target("test") set_kind("binary") add_files("src/*.c") set_toolchains("@msvc") --set_toolchains("clang-cl@msvc") ================================================ FILE: tests/projects/package/toolchain_muslcc/src/main.c ================================================ #include #include #include #include #ifdef HAVE_LIBPLIST # include #endif int main(int argc, char** argv) { printf("hello world!\n"); inflate(0, 0); ogg_sync_init(0); #ifdef HAVE_LIBPLIST plist_new_dict(); #endif return 0; } ================================================ FILE: tests/projects/package/toolchain_muslcc/test.lua ================================================ function main(t) -- freebsd ci is slower if is_host("bsd", "solaris", "haiku") then return end -- only for x86/x64, because it will take too long time on ci with arm/mips if os.subarch():startswith("x") or os.subarch() == "i386" then t:build() end end ================================================ FILE: tests/projects/package/toolchain_muslcc/xmake.lua ================================================ add_rules("mode.debug", "mode.release") -- set cross-compliation platform set_plat("cross") set_arch("arm") -- lock requires set_policy("package.requires_lock", true) -- custom toolchain toolchain("my_muslcc") set_homepage("https://musl.cc/") set_description("The musl-based cross-compilation toolchains") set_kind("cross") on_load(function (toolchain) toolchain:load_cross_toolchain() if toolchain:is_arch("arm") then toolchain:add("cxflags", "-march=armv7-a", "-msoft-float", {force = true}) toolchain:add("ldflags", "-march=armv7-a", "-msoft-float", {force = true}) end toolchain:add("syslinks", "gcc", "c") end) toolchain_end() -- add library packages -- for testing zlib/xmake, libplist/autoconf, libogg/cmake add_requires("zlib", "libogg", {system = false}) if is_host("macosx", "linux", "bsd", "solaris", "haiku") then add_requires("libplist", {system = false}) end -- add toolchains package add_requires("muslcc") -- set global toolchains for target and packages set_toolchains("my_muslcc@muslcc") -- use the builltin toolchain("muslcc") instead of "my_muslcc" --set_toolchains("@muslcc") target("test") set_kind("binary") add_files("src/*.c") add_packages("zlib", "libplist", "libogg") if has_package("libplist") then add_defines("HAVE_LIBPLIST") end ================================================ FILE: tests/projects/package/toolchain_tinycc/src/main.c ================================================ #include int main(int argc, char** argv) { printf("hello world!\n"); return 0; } ================================================ FILE: tests/projects/package/toolchain_tinycc/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("tinycc") target("test") set_kind("binary") add_files("src/*.c") set_toolchains("@tinycc") ================================================ FILE: tests/projects/package/toolchain_zig/src/main.zig ================================================ const std = @import("std"); pub fn main() !void { std.debug.print("Hello, {s}!\n", .{"world"}); } ================================================ FILE: tests/projects/package/toolchain_zig/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("zig") target("test") set_kind("binary") add_files("src/*.zig") set_toolchains("@zig") ================================================ FILE: tests/projects/package/vcpkg/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/vcpkg/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/package/vcpkg/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("vcpkg::zlib", "vcpkg::pcre2") add_requires("vcpkg::boost[core]", {alias = "boost"}) target("test") set_kind("binary") add_files("src/*.cpp") add_packages("vcpkg::zlib", "vcpkg::pcre2", "boost") ================================================ FILE: tests/projects/package/vcpkg_dependency/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/vcpkg_dependency/src/main.cpp ================================================ #include #include #include #include int main(int argc, char **argv) { // test for opencolorio, opencolorio is one of the dependencies of openimageio. auto transform = OCIO_NAMESPACE::ColorSpaceTransform::Create(); // test for openimageio. auto write_image = OIIO::ImageInput::open("test.png"); // test for boost-system, boost-system is one of the dependencies of boost-filesystem. boost::system::error_code ec; // test for boost-filesystem. boost::filesystem::exists("test.png", ec); return 0; } ================================================ FILE: tests/projects/package/vcpkg_dependency/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("vcpkg::openimageio[jpegxl,libraw,webp]", { configs = { shared = true } }) add_requires("vcpkg::boost-filesystem", { alias = "filesystem" }) target("test") set_kind("binary") add_files("src/*.cpp") set_languages("c++17") set_encodings("utf-8") add_packages("vcpkg::openimageio[jpegxl,libraw,webp]", "filesystem") ================================================ FILE: tests/projects/package/vcpkg_manifest/.gitignore ================================================ # Xmake cache .xmake/ build/ # MacOS Cache .DS_Store ================================================ FILE: tests/projects/package/vcpkg_manifest/src/main.cpp ================================================ #include using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ================================================ FILE: tests/projects/package/vcpkg_manifest/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("vcpkg::zlib 1.2.11+10") add_requires("vcpkg::fmt >=8.0.1", {configs = {baseline = "50fd3d9957195575849a49fa591e645f1d8e7156"}}) add_requires("vcpkg::libpng", {configs = {features = {"apng"}}}) target("test") set_kind("binary") add_files("src/*.cpp") add_packages("vcpkg::zlib", "vcpkg::fmt", "vcpkg::libpng") ================================================ FILE: tests/projects/pascal/console/src/main.pas ================================================ program Hello; begin writeln ('Hello, world.'); end. ================================================ FILE: tests/projects/pascal/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.pas") ================================================ FILE: tests/projects/pascal/console_with_c/src/foo.c ================================================ #include extern int64_t fib(int64_t n) { return n > 1 ? fib(n - 1) + fib(n - 2) : 1; } ================================================ FILE: tests/projects/pascal/console_with_c/src/main.pas ================================================ program hello; function fib(n: Int64): Int64; cdecl; external 'foo'; var Value: Integer; begin Value := 5; WriteLn(fib(Value)); end. ================================================ FILE: tests/projects/pascal/console_with_c/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("static") add_files("src/foo.c") target("test") set_kind("binary") add_deps("foo") add_files("src/main.pas") ================================================ FILE: tests/projects/pascal/shared/src/foo.pas ================================================ library foo; {$mode objfpc}{$H+} function fib(n : Int64) : Int64; cdecl; begin if n > 1 then begin Result := fib(n - 1) + fib(n - 2); end else Result := 1; end; exports fib; end. ================================================ FILE: tests/projects/pascal/shared/src/main.pas ================================================ program hello; function fib(n: Int64): Int64; cdecl; external 'foo'; var Value: Integer; begin Value := 5; WriteLn(fib(Value)); end. ================================================ FILE: tests/projects/pascal/shared/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("shared") add_files("src/foo.pas") target("test") set_kind("binary") add_deps("foo") add_files("src/main.pas") ================================================ FILE: tests/projects/policy/compile_commands/src/main.c ================================================ int main(int argc, char** argv) { return 0; } ================================================ FILE: tests/projects/policy/compile_commands/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("enabled") set_kind("binary") add_files("src/main.c") target("disabled") set_kind("binary") add_files("src/main.c") set_policy("generator.compile_commands", false) ================================================ FILE: tests/projects/python/cython/example/src/example.py ================================================ print("Hello, world!") ================================================ FILE: tests/projects/python/cython/example/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("python 3.x") target("example") add_rules("python.cython") add_files("src/*.py") add_packages("python") ================================================ FILE: tests/projects/python/pybind/example/src/example.cpp ================================================ #include #define STRINGIFY(x) #x #define MACRO_STRINGIFY(x) STRINGIFY(x) int add(int i, int j) { return i + j; } namespace py = pybind11; PYBIND11_MODULE(example, m) { m.doc() = R"pbdoc( Pybind11 example plugin ----------------------- .. currentmodule:: example .. autosummary:: :toctree: _generate add subtract )pbdoc"; m.def("add", &add, R"pbdoc( Add two numbers Some other explanation about the add function. )pbdoc"); m.def("subtract", [](int i, int j) { return i - j; }, R"pbdoc( Subtract two numbers Some other explanation about the subtract function. )pbdoc"); #ifdef VERSION_INFO m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO); #else m.attr("__version__") = "dev"; #endif } ================================================ FILE: tests/projects/python/pybind/example/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("pybind11") target("example") add_rules("python.module", {soabi = false}) add_files("src/*.cpp") add_packages("pybind11") set_languages("c++11") ================================================ FILE: tests/projects/python/pybind/example_with_soabi/src/example.cpp ================================================ #include #define STRINGIFY(x) #x #define MACRO_STRINGIFY(x) STRINGIFY(x) int add(int i, int j) { return i + j; } namespace py = pybind11; PYBIND11_MODULE(example, m) { m.doc() = R"pbdoc( Pybind11 example plugin ----------------------- .. currentmodule:: example .. autosummary:: :toctree: _generate add subtract )pbdoc"; m.def("add", &add, R"pbdoc( Add two numbers Some other explanation about the add function. )pbdoc"); m.def("subtract", [](int i, int j) { return i - j; }, R"pbdoc( Subtract two numbers Some other explanation about the subtract function. )pbdoc"); #ifdef VERSION_INFO m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO); #else m.attr("__version__") = "dev"; #endif } ================================================ FILE: tests/projects/python/pybind/example_with_soabi/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("pybind11") target("example") add_rules("python.module") add_files("src/*.cpp") add_packages("pybind11") set_languages("c++11") ================================================ FILE: tests/projects/qt/console/src/main.cpp ================================================ #include int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); printf("hello xmake\n"); return a.exec(); } ================================================ FILE: tests/projects/qt/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") add_rules("qt.console") add_files("src/*.cpp") ================================================ FILE: tests/projects/qt/console_static/src/main.cpp ================================================ #include int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); printf("hello xmake\n"); return a.exec(); } ================================================ FILE: tests/projects/qt/console_static/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") add_rules("qt.console") add_files("src/*.cpp") ================================================ FILE: tests/projects/qt/quickapp/src/main.cpp ================================================ #include #include int main(int argc, char *argv[]) { #if QT_VERSION >= 0x50601 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); } ================================================ FILE: tests/projects/qt/quickapp/src/main.qml ================================================ import QtQuick 2.6 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 Window { id: root visible: true width: 640 height: 480 title: qsTr("Hello World") Button { text: "Ok" onClicked: { root.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } } ================================================ FILE: tests/projects/qt/quickapp/src/qml.qrc ================================================ main.qml ================================================ FILE: tests/projects/qt/quickapp/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") add_rules("qt.quickapp") add_headerfiles("src/*.h") add_files("src/*.cpp") add_files("src/qml.qrc") ================================================ FILE: tests/projects/qt/quickapp_static/src/main.cpp ================================================ #include #include int main(int argc, char *argv[]) { #if QT_VERSION >= 0x50601 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); } ================================================ FILE: tests/projects/qt/quickapp_static/src/main.qml ================================================ import QtQuick 2.6 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 Window { id: root visible: true width: 640 height: 480 title: qsTr("Hello World") Button { text: "Ok" onClicked: { root.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } } ================================================ FILE: tests/projects/qt/quickapp_static/src/qml.qrc ================================================ main.qml ================================================ FILE: tests/projects/qt/quickapp_static/xmake.lua ================================================ add_rules("mode.debug", "mode.release") includes("@builtin/qt") target("demo") add_rules("qt.quickapp_static") add_headerfiles("src/*.h") add_files("src/*.cpp") add_files("src/qml.qrc") add_frameworks("QtQuickControls2", "QtQuickTemplates2") qt_add_static_plugins("QtQuick2Plugin", {linkdirs = "qml/QtQuick.2", links = "qtquick2plugin"}) qt_add_static_plugins("QtQuick2WindowPlugin", {linkdirs = "qml/QtQuick/Window.2", links = "windowplugin"}) qt_add_static_plugins("QtQuickControls2Plugin", {linkdirs = "qml/QtQuick/Controls.2", links = "qtquickcontrols2plugin"}) qt_add_static_plugins("QtQuickTemplates2Plugin", {linkdirs = "qml/QtQuick/Templates.2", links = "qtquicktemplates2plugin"}) ================================================ FILE: tests/projects/qt/quickplugin/src/Foo.cpp ================================================ #include "Foo.h" Foo::Foo(QObject *parent) : QObject { parent }, m_bar{ 0 } { } int Foo::bar() const noexcept { return m_bar; } void Foo::setBar(int bar) noexcept { if (bar == m_bar) return; m_bar = bar; Q_EMIT barChanged(m_bar); } ================================================ FILE: tests/projects/qt/quickplugin/src/Foo.h ================================================ #include #include class Foo: public QObject { Q_OBJECT Q_PROPERTY(int bar READ bar WRITE setBar NOTIFY barChanged) QML_NAMED_ELEMENT(Foo) public: explicit Foo(QObject *parent = nullptr); int bar() const noexcept; void setBar(int bar) noexcept; Q_SIGNALS: void barChanged(int bar); private: int m_bar; }; QML_DECLARE_TYPE(Foo) ================================================ FILE: tests/projects/qt/quickplugin/src/Plugin.cpp ================================================ #include "Plugin.h" void qml_register_types_My_Plugin(); ///////////////////////////////////// ///////////////////////////////////// Plugin::Plugin(QObject *parent) : QQmlEngineExtensionPlugin { parent } { volatile auto registration = &qml_register_types_My_Plugin; Q_UNUSED(registration); } ================================================ FILE: tests/projects/qt/quickplugin/src/Plugin.h ================================================ #include #include class Plugin: public QQmlEngineExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: explicit Plugin(QObject *parent = nullptr); }; ================================================ FILE: tests/projects/qt/quickplugin/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") add_rules("qt.qmlplugin") add_headerfiles("src/*.h") add_files("src/*.cpp") -- add files with Q_OBJECT meta (only for qt.moc) add_files("src/*.h") set_values("qt.qmlplugin.import_name", "My.Plugin") ================================================ FILE: tests/projects/qt/shared_library/src/demo.cpp ================================================ #include "demo.h" QtDemo::QtDemo() { } ================================================ FILE: tests/projects/qt/shared_library/src/demo.h ================================================ #ifndef QT_DEMO_H #define QT_DEMO_H #include "demo_global.h" class QT_DEMOSHARED_EXPORT QtDemo { public: QtDemo(); }; #endif // QT_TEST5_H ================================================ FILE: tests/projects/qt/shared_library/src/demo_global.h ================================================ #ifndef QT_DEMO_GLOBAL_H #define QT_DEMO_GLOBAL_H #include #if defined(QT_DEMO_LIBRARY) # define QT_DEMOSHARED_EXPORT Q_DECL_EXPORT #else # define QT_DEMOSHARED_EXPORT Q_DECL_IMPORT #endif #endif // QT_TEST5_GLOBAL_H ================================================ FILE: tests/projects/qt/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") add_rules("qt.shared") add_headerfiles("src/*.h") add_files("src/*.cpp") add_defines("QT_DEMO_LIBRARY") add_frameworks("QtGui") ================================================ FILE: tests/projects/qt/static_library/src/demo.cpp ================================================ #include "demo.h" QtDemo::QtDemo() { } ================================================ FILE: tests/projects/qt/static_library/src/demo.h ================================================ #ifndef QT_DEMO_H #define QT_DEMO_H class QtDemo { public: QtDemo(); }; #endif // QT_DEMO_H ================================================ FILE: tests/projects/qt/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("qt_demo") add_rules("qt.static") add_headerfiles("src/*.h") add_files("src/*.cpp") add_frameworks("QtGui") ================================================ FILE: tests/projects/qt/widgetapp/src/main.cpp ================================================ #include "mainwindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } ================================================ FILE: tests/projects/qt/widgetapp/src/mainwindow.cpp ================================================ #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } ================================================ FILE: tests/projects/qt/widgetapp/src/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H ================================================ FILE: tests/projects/qt/widgetapp/src/mainwindow.ui ================================================ MainWindow 0 0 400 300 MainWindow ================================================ FILE: tests/projects/qt/widgetapp/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") add_rules("qt.widgetapp") add_headerfiles("src/*.h") add_files("src/*.cpp") add_files("src/mainwindow.ui") add_files("src/mainwindow.h") ================================================ FILE: tests/projects/qt/widgetapp_private_slot/main.cpp ================================================ #include "mainwindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } ================================================ FILE: tests/projects/qt/widgetapp_private_slot/mainwindow.cpp ================================================ #include "mainwindow.h" #include class MainWindowPrivate { MainWindow *q_ptr; Q_DECLARE_PUBLIC(MainWindow) public: MainWindowPrivate(){} void mainWindow_slot(){qDebug()<<"mainWindow_slot";} }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { d_ptr = new MainWindowPrivate; d_ptr->q_ptr = this; } MainWindow::~MainWindow() { } #include "moc_mainwindow.cpp" ================================================ FILE: tests/projects/qt/widgetapp_private_slot/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class MainWindowPrivate; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: MainWindowPrivate *d_ptr; Q_DECLARE_PRIVATE(MainWindow) Q_DISABLE_COPY(MainWindow) Q_PRIVATE_SLOT(d_func(), void mainWindow_slot()) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif // MAINWINDOW_H ================================================ FILE: tests/projects/qt/widgetapp_private_slot/mainwindow.ui ================================================ MainWindow 0 0 400 300 MainWindow ================================================ FILE: tests/projects/qt/widgetapp_private_slot/xmake.lua ================================================ target("test") add_rules("qt.widgetapp") add_files("mainwindow.h") add_files("*.cpp") add_frameworks("QtCore", "QtGui") ================================================ FILE: tests/projects/qt/widgetapp_private_slot2/main.cpp ================================================ #include "mainwindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } ================================================ FILE: tests/projects/qt/widgetapp_private_slot2/mainwindow.cpp ================================================ #include "mainwindow.h" #include class MainWindowPrivate:public QObject { Q_OBJECT public: MainWindow *q_ptr; Q_DECLARE_PUBLIC(MainWindow) public: MainWindowPrivate(){} void mainWindow_slot(){qDebug()<<"mainWindow_slot";} private: Q_PRIVATE_SLOT(q_ptr, void test()) }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { d_ptr = new MainWindowPrivate; d_ptr->q_ptr = this; } MainWindow::~MainWindow() { } void MainWindow::test() { } #include "moc_mainwindow.cpp" #include "mainwindow.moc" ================================================ FILE: tests/projects/qt/widgetapp_private_slot2/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class MainWindowPrivate; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); public Q_SLOTS: void test(); private: MainWindowPrivate *d_ptr; Q_DECLARE_PRIVATE(MainWindow) Q_DISABLE_COPY(MainWindow) Q_PRIVATE_SLOT(d_func(), void mainWindow_slot()) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif // MAINWINDOW_H ================================================ FILE: tests/projects/qt/widgetapp_private_slot2/mainwindow.ui ================================================ MainWindow 0 0 400 300 MainWindow ================================================ FILE: tests/projects/qt/widgetapp_private_slot2/xmake.lua ================================================ target("test") add_rules("qt.widgetapp") add_files("main.cpp") add_files("mainwindow.cpp", {rules = "qt.moc"}) add_files("*.h") add_files("*.ui") ================================================ FILE: tests/projects/qt/widgetapp_static/src/main.cpp ================================================ #include "mainwindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } ================================================ FILE: tests/projects/qt/widgetapp_static/src/mainwindow.cpp ================================================ #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } ================================================ FILE: tests/projects/qt/widgetapp_static/src/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H ================================================ FILE: tests/projects/qt/widgetapp_static/src/mainwindow.ui ================================================ MainWindow 0 0 400 300 MainWindow ================================================ FILE: tests/projects/qt/widgetapp_static/xmake.lua ================================================ add_rules("mode.debug", "mode.release") includes("@builtin/qt") target("demo") add_rules("qt.widgetapp_static") add_headerfiles("src/*.h") add_files("src/*.cpp") add_files("src/mainwindow.ui") add_files("src/mainwindow.h") add_frameworks("QtSvg") qt_add_static_plugins("QSvgPlugin", {linkdirs = "plugins/imageformats", links = {"qsvg"}}) ================================================ FILE: tests/projects/qt/with_private/src/main.cpp ================================================ #include "mainwindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } ================================================ FILE: tests/projects/qt/with_private/src/mainwindow.cpp ================================================ #include "mainwindow.h" #include "ui_mainwindow.h" #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QQuickText *text = new QQuickText(); delete text; } MainWindow::~MainWindow() { delete ui; } ================================================ FILE: tests/projects/qt/with_private/src/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H ================================================ FILE: tests/projects/qt/with_private/src/mainwindow.ui ================================================ MainWindow 0 0 400 300 MainWindow ================================================ FILE: tests/projects/qt/with_private/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") add_rules("qt.widgetapp") add_frameworks("QtCore", "QtGui", "QtWidgets", "QtQuick", "QtQuickPrivate", "QtQml", "QtQmlPrivate", "QtCorePrivate", "QtGuiPrivate") add_headerfiles("src/*.h") add_files("src/*.cpp") add_files("src/mainwindow.ui") add_files("src/mainwindow.h") ================================================ FILE: tests/projects/qt/with_ts/src/demo_zh_CN.ts ================================================ MainWindow MainWindow 主窗口 PushButton 按钮 ================================================ FILE: tests/projects/qt/with_ts/src/demo_zh_TW.ts ================================================ MainWindow MainWindow 主視窗 PushButton 按鈕 ================================================ FILE: tests/projects/qt/with_ts/src/main.cpp ================================================ #include "mainwindow.h" #include #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QTranslator translator; const QStringList uiLanguages = QLocale::system().uiLanguages(); for (const QString& locale : uiLanguages) { const QString baseName = "demo_" + QLocale(locale).name(); if (translator.load(baseName + ".qm")) { a.installTranslator(&translator); break; } } MainWindow w; w.show(); return a.exec(); } ================================================ FILE: tests/projects/qt/with_ts/src/mainwindow.cpp ================================================ #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } ================================================ FILE: tests/projects/qt/with_ts/src/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H ================================================ FILE: tests/projects/qt/with_ts/src/mainwindow.ui ================================================ MainWindow 0 0 400 300 MainWindow 110 90 75 23 PushButton ================================================ FILE: tests/projects/qt/with_ts/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("demo") add_rules("qt.widgetapp") add_headerfiles("src/*.h") add_files("src/*.cpp") add_files("src/mainwindow.ui") add_files("src/mainwindow.h") add_files("src/demo_zh_CN.ts") add_files("src/demo_zh_TW.ts", { prefixdir = "translations" }) ================================================ FILE: tests/projects/rust/cargo_deps/src/main.rs ================================================ extern crate base64; use base64::{encode, decode}; fn main() { let a = b"hello world"; let b = "aGVsbG8gd29ybGQ="; assert_eq!(encode(a), b); assert_eq!(a, &decode(b).unwrap()[..]); println!("{}", encode(a)); } ================================================ FILE: tests/projects/rust/cargo_deps/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("cargo::base64 0.13.0") add_requires("cargo::flate2 1.0.17", {configs = {features = "zlib"}}) target("test") set_kind("binary") add_files("src/main.rs") add_packages("cargo::base64", "cargo::flate2") ================================================ FILE: tests/projects/rust/cargo_deps_cross_build/Cargo.toml ================================================ [package] name = "demo" version = "0.1.0" edition = "2021" [dependencies] spin = "^0.9" [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = "^9.3" ================================================ FILE: tests/projects/rust/cargo_deps_cross_build/src/main.rs ================================================ // src/main.rs #![no_main] #![no_std] use core::panic::PanicInfo; #[panic_handler] fn panic(_panic: &PanicInfo<'_>) -> ! { loop {} } ================================================ FILE: tests/projects/rust/cargo_deps_cross_build/xmake.lua ================================================ -- rustup target add aarch64-unknown-none -- xmake f -a aarch64-unknown-none set_arch("aarch64-unknown-none") add_rules("mode.release", "mode.debug") add_requires("cargo::test", {configs = { std = false, main = false, cargo_toml = path.join(os.projectdir(), "Cargo.toml")}}) target("test") set_kind("binary") add_files("src/main.rs") add_packages("cargo::test") ================================================ FILE: tests/projects/rust/cargo_deps_with_toml/Cargo.toml ================================================ [package] name = "test" version = "0.1.0" edition = "2021" [dependencies] base64 = "0.13.0" flate2 = {version = "1.0.17", features = ["zlib"]} ================================================ FILE: tests/projects/rust/cargo_deps_with_toml/src/main.rs ================================================ extern crate base64; use base64::{encode, decode}; fn main() { let a = b"hello world"; let b = "aGVsbG8gd29ybGQ="; assert_eq!(encode(a), b); assert_eq!(a, &decode(b).unwrap()[..]); println!("{}", encode(a)); } ================================================ FILE: tests/projects/rust/cargo_deps_with_toml/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("cargo::test", {configs = {cargo_toml = path.join(os.projectdir(), "Cargo.toml")}}) target("test") set_kind("binary") add_files("src/main.rs") add_packages("cargo::test") ================================================ FILE: tests/projects/rust/console/src/main.rs ================================================ fn main() { println!("hello xmake!"); } ================================================ FILE: tests/projects/rust/console/test.lua ================================================ function main(t) if is_host("macosx") and os.arch() ~= "arm64" then t:build() else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/rust/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/main.rs") ================================================ FILE: tests/projects/rust/cxx_call_rust_library/src/bridge.rsx ================================================ #[cxx::bridge] mod foo { extern "Rust" { fn add(a: i32, b: i32) -> i32; } } ================================================ FILE: tests/projects/rust/cxx_call_rust_library/src/foo.rs ================================================ #[cxx::bridge] mod foo { extern "Rust" { fn add(a: i32, b: i32) -> i32; } } pub fn add(a: i32, b: i32) -> i32 { return a + b; } ================================================ FILE: tests/projects/rust/cxx_call_rust_library/src/main.cc ================================================ #include #include "bridge.rs.h" int main(int argc, char** argv) { printf("add(1, 2) == %d\n", add(1, 2)); return 0; } ================================================ FILE: tests/projects/rust/cxx_call_rust_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("cargo::cxx 1.0") target("foo") set_kind("static") add_files("src/foo.rs") set_values("rust.cratetype", "staticlib") add_packages("cargo::cxx") target("test") set_kind("binary") add_rules("rust.cxxbridge") add_deps("foo") add_files("src/main.cc") add_files("src/bridge.rsx") ================================================ FILE: tests/projects/rust/rust_call_cxx_library/src/foo.cc ================================================ extern "C" int add(int a, int b) { return a + b; } ================================================ FILE: tests/projects/rust/rust_call_cxx_library/src/main.rs ================================================ extern "C" { fn add(a: i32, b: i32) -> i32; } fn main() { unsafe { println!("add(1, 2) = {}", add(1, 2)); } } ================================================ FILE: tests/projects/rust/rust_call_cxx_library/test.lua ================================================ function main(t) if is_host("macosx") and os.arch() ~= "arm64" then t:build() else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/rust/rust_call_cxx_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("static") add_files("src/foo.cc") target("test") set_kind("binary") add_deps("foo") add_files("src/main.rs") ================================================ FILE: tests/projects/rust/shared_library/src/foo.rs ================================================ pub fn add(a: i32, b: i32) -> i32 { return a + b; } ================================================ FILE: tests/projects/rust/shared_library/src/main.rs ================================================ extern crate foo; fn main() { println!("hello xmake!"); println!("add: {}", foo::add(1, 1)); } ================================================ FILE: tests/projects/rust/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("shared") add_files("src/foo.rs") target("test") set_kind("binary") add_deps("foo") add_files("src/main.rs") ================================================ FILE: tests/projects/rust/static_library/src/foo.rs ================================================ pub fn add(a: i32, b: i32) -> i32 { return a + b; } ================================================ FILE: tests/projects/rust/static_library/src/main.rs ================================================ extern crate foo; fn main() { println!("hello xmake!"); println!("add: {}", foo::add(1, 1)); } ================================================ FILE: tests/projects/rust/static_library/test.lua ================================================ function main(t) if is_host("macosx") and os.arch() ~= "arm64" then t:build() else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/rust/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("foo") set_kind("static") add_files("src/foo.rs") target("test") set_kind("binary") add_deps("foo") add_files("src/main.rs") ================================================ FILE: tests/projects/swift/bidirectional_cxx_interop_lib/include/fibonacci/fibonacci.h ================================================ #ifndef FIBONACCI_FIBONACCI_H #define FIBONACCI_FIBONACCI_H extern "C" int fibonacci_cpp(int x); #endif // FIBONACCI_FIBONACCI_H ================================================ FILE: tests/projects/swift/bidirectional_cxx_interop_lib/include/fibonacci/module.modulemap ================================================ module Fibonacci { header "fibonacci.h" } ================================================ FILE: tests/projects/swift/bidirectional_cxx_interop_lib/lib/fibonacci.cpp ================================================ #include #include #include extern "C" int fibonacci_cpp(int x) { std::cout << "x [cpp]: " << x << std::endl; if (x <= 1) return 1; return SwiftFibonacci::fibonacciSwift(x - 1) + SwiftFibonacci::fibonacciSwift(x - 2); } ================================================ FILE: tests/projects/swift/bidirectional_cxx_interop_lib/lib/fibonacci.swift ================================================ public func fibonacciSwift(_ x: CInt) -> CInt { print("x [swift]: \(x)") if x <= 1 { return 1 } return fibonacciSwift(x - 1) + fibonacciSwift(x - 2) } ================================================ FILE: tests/projects/swift/bidirectional_cxx_interop_lib/src/fibonacci.cpp ================================================ #include #include int main(int argc, char ** argv) { std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl; return 0; } ================================================ FILE: tests/projects/swift/bidirectional_cxx_interop_lib/src/fibonacci.swift ================================================ import Fibonacci print(fibonacci_cpp(5)) ================================================ FILE: tests/projects/swift/bidirectional_cxx_interop_lib/test.lua ================================================ function main(t) if os.host() == "macosx" then t:build({iphoneos = true}) else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/swift/bidirectional_cxx_interop_lib/xmake.lua ================================================ target("fibonacci") set_kind("$(kind)") set_languages("cxx20") add_files("lib/**.swift", {public = true}) add_files("lib/**.cpp") set_values("swift.modulename", "SwiftFibonacci") set_values("swift.interop", "cxx") -- for automatic clang modulemap add_includedirs("include/fibonacci", {public = true}) add_includedirs("include") add_headerfiles("include/**.h") target("cxx_interop_lib") set_kind("binary") set_languages("cxx20") add_files("src/**.cpp") add_deps("fibonacci") target("swift_interop_lib") set_kind("binary") add_files("src/**.swift") add_deps("fibonacci") set_values("swift.interop", "cxx") ================================================ FILE: tests/projects/swift/console/src/main.swift ================================================ import Foundation print("hello world!") ================================================ FILE: tests/projects/swift/console/test.lua ================================================ function main(t) if os.host() == "macosx" then t:build({iphoneos = true}) else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/swift/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.swift") ================================================ FILE: tests/projects/swift/cross_modules/src/A.swift ================================================ func test() { print("xxxxx") } ================================================ FILE: tests/projects/swift/cross_modules/src/main.swift ================================================ test() ================================================ FILE: tests/projects/swift/cross_modules/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.swift") ================================================ FILE: tests/projects/swift/cxx_interop/lib/fibonacci/fibonacci.swift ================================================ public func fibonacciSwift(_ x: CInt) -> CInt { print("x [swift]: \(x)") if x <= 1 { return 1 } return fibonacciSwift(x - 1) + fibonacciSwift(x - 2) } ================================================ FILE: tests/projects/swift/cxx_interop/src/fibonacci.cpp ================================================ #include #include int main(int argc, char ** argv) { std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl; return 0; } ================================================ FILE: tests/projects/swift/cxx_interop/test.lua ================================================ function main(t) if os.host() == "macosx" then t:build({iphoneos = true}) else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/swift/cxx_interop/xmake.lua ================================================ target("cxx_interop") set_kind("binary") set_languages("cxx20") add_files("lib/**.swift", {public = true}) add_files("src/**.cpp") set_values("swift.modulename", "SwiftFibonacci") set_values("swift.interop", "cxx") set_values("swift.interop.headername", "fibonacci-Swift.h") set_values("swift.interop.cxxmain", true) ================================================ FILE: tests/projects/swift/cxx_interop_lib/lib/fibonacci/fibonacci.swift ================================================ public func fibonacciSwift(_ x: CInt) -> CInt { print("x [swift]: \(x)") if x <= 1 { return 1 } return fibonacciSwift(x - 1) + fibonacciSwift(x - 2) } ================================================ FILE: tests/projects/swift/cxx_interop_lib/src/fibonacci.cpp ================================================ #include #include int main(int argc, char ** argv) { std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl; return 0; } ================================================ FILE: tests/projects/swift/cxx_interop_lib/test.lua ================================================ function main(t) if os.host() == "macosx" then t:build({iphoneos = true}) else return t:skip("wrong host platform") end end ================================================ FILE: tests/projects/swift/cxx_interop_lib/xmake.lua ================================================ target("fibonacci") set_kind("$(kind)") set_languages("cxx20") add_files("lib/**.swift", {public = true}) set_values("swift.modulename", "SwiftFibonacci") set_values("swift.interop", "cxx") target("cxx_interop_lib") set_kind("binary") set_languages("cxx20") add_files("src/**.cpp") add_deps("fibonacci") ================================================ FILE: tests/projects/swift/iosapp/src/AppDelegate.swift ================================================ // // AppDelegate.swift // test8 // // Created by ruki on 2020/4/10. // Copyright © 2020 tboox. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } } ================================================ FILE: tests/projects/swift/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/swift/iosapp/src/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/swift/iosapp/src/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: tests/projects/swift/iosapp/src/Base.lproj/Main.storyboard ================================================ ================================================ FILE: tests/projects/swift/iosapp/src/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundleDisplayName $(PRODUCT_DISPLAY_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneConfigurationName Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate UISceneStoryboardFile Main UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: tests/projects/swift/iosapp/src/SceneDelegate.swift ================================================ // // SceneDelegate.swift // test8 // // Created by ruki on 2020/4/10. // Copyright © 2020 tboox. All rights reserved. // import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). } func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } } ================================================ FILE: tests/projects/swift/iosapp/src/ViewController.swift ================================================ // // ViewController.swift // test8 // // Created by ruki on 2020/4/10. // Copyright © 2020 tboox. All rights reserved. // import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } } ================================================ FILE: tests/projects/swift/iosapp/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_plat("iphoneos") set_arch("arm64") target("test") add_rules("xcode.application") add_files("src/*.swift", "src/**.storyboard", "src/*.xcassets") add_files("src/Info.plist") ================================================ FILE: tests/projects/swift/macapp/src/AppDelegate.swift ================================================ // // AppDelegate.swift // test9 // // Created by ruki on 2020/4/10. // Copyright © 2020 tboox. All rights reserved. // import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application } } ================================================ FILE: tests/projects/swift/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "mac", "size" : "16x16", "scale" : "1x" }, { "idiom" : "mac", "size" : "16x16", "scale" : "2x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "1x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "2x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "1x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "2x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "1x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "2x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "1x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/swift/macapp/src/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: tests/projects/swift/macapp/src/Base.lproj/Main.storyboard ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: tests/projects/swift/macapp/src/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2020 tboox. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass NSApplication NSSupportsAutomaticTermination NSSupportsSuddenTermination ================================================ FILE: tests/projects/swift/macapp/src/ViewController.swift ================================================ // // ViewController.swift // test9 // // Created by ruki on 2020/4/10. // Copyright © 2020 tboox. All rights reserved. // import Cocoa class ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override var representedObject: Any? { didSet { // Update the view, if already loaded. } } } ================================================ FILE: tests/projects/swift/macapp/src/test.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only ================================================ FILE: tests/projects/swift/macapp/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") add_rules("xcode.application") add_files("src/*.swift", "src/**.storyboard", "src/*.xcassets") add_files("src/Info.plist") ================================================ FILE: tests/projects/swift/modulemap/src/hello.cpp ================================================ #include #include "hello.h" void say1(char const* s) { printf("%s\n", s); } ================================================ FILE: tests/projects/swift/modulemap/src/hello.h ================================================ #include #ifdef __cplusplus extern "C" { #endif void say1(char const* s); #ifdef __cplusplus } #endif static inline void say2(char const* s) { printf("%s\n", s); } ================================================ FILE: tests/projects/swift/modulemap/src/main.swift ================================================ import Foundation import hello hello.say1("hello1") hello.say2("hello2") ================================================ FILE: tests/projects/swift/modulemap/src/module.modulemap ================================================ module hello { header "hello.h" export * } ================================================ FILE: tests/projects/swift/modulemap/xmake.lua ================================================ target("modulemap") set_kind("binary") add_files("src/*.swift", "src/*.cpp") add_scflags("-Xcc -fmodules", "-Xcc -fmodule-map-file=src/module.modulemap", {force = true}) ================================================ FILE: tests/projects/swig/auto_include/src/example.cpp ================================================ double My_variable = 3.0; /* Compute factorial of n */ int fact(int n) { if (n <= 1) return 1; else return n*fact(n-1); } /* Compute n mod m */ int my_mod(int n, int m) { return(n % m); } ================================================ FILE: tests/projects/swig/auto_include/src/example.i ================================================ %module example %{ /* Put headers and other declarations here */ #include "nlohmann/json.hpp" extern double My_variable; extern int fact(int); extern int my_mod(int n, int m); %} extern double My_variable; extern int fact(int); extern int my_mod(int n, int m); ================================================ FILE: tests/projects/swig/auto_include/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("python 3.x") add_requires("nlohmann_json") target("example") add_rules("swig.cpp", {moduletype = "python"}) add_files("src/example.i", {scriptdir = "share"}) add_files("src/example.cpp") add_packages("python") add_packages("nlohmann_json") ================================================ FILE: tests/projects/swig/java_c/src/example.c ================================================ int fact(int n) { return n; } int fact2(int n) { return n; } ================================================ FILE: tests/projects/swig/java_c/src/example.i ================================================ %module example %{ extern int fact(int n); %} extern int fact(int n); %include "example2.i" ================================================ FILE: tests/projects/swig/java_c/src/example2.i ================================================ %inline %{ #include "test.h" %} %include "test.h" ================================================ FILE: tests/projects/swig/java_c/src/test.h ================================================ #pragma once int fact2(int n); ================================================ FILE: tests/projects/swig/java_c/xmake.lua ================================================ add_rules("mode.release", "mode.debug") -- make sure you config to an enviroment with jni.h -- for example: xmake f -c -p android target("example") set_kind('shared') -- set moduletype to java add_rules("swig.c", {moduletype = "java"}) -- test jar build -- add_rules("swig.c", {moduletype = "java" , buildjar = true}) -- use swigflags to provider package name and output path of java files add_files("src/example.i", {swigflags = { "-package", "com.example", "-outdir", "build/java/com/example/" }}) add_files("src/example.c") add_includedirs("src") before_build(function() -- ensure output path exists before running swig os.mkdir("build/java/com/example/") end) ================================================ FILE: tests/projects/swig/lua_c/src/example.c ================================================ int fact(int n) { return n; } ================================================ FILE: tests/projects/swig/lua_c/src/example.i ================================================ %module example %{ extern int fact(int n); %} extern int fact(int n); ================================================ FILE: tests/projects/swig/lua_c/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("lua") target("example") add_rules("swig.c", {moduletype = "lua"}) add_files("src/example.i", {swigflags = "-no-old-metatable-bindings"}) add_files("src/example.c") add_packages("lua") ================================================ FILE: tests/projects/swig/python_c/src/example.c ================================================ double My_variable = 3.0; /* Compute factorial of n */ int fact(int n) { if (n <= 1) return 1; else return n*fact(n-1); } /* Compute n mod m */ int my_mod(int n, int m) { return(n % m); } ================================================ FILE: tests/projects/swig/python_c/src/example.i ================================================ %module example %{ /* Put headers and other declarations here */ extern double My_variable; extern int fact(int); extern int my_mod(int n, int m); %} extern double My_variable; extern int fact(int); extern int my_mod(int n, int m); ================================================ FILE: tests/projects/swig/python_c/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("python 3.x") target("example") add_rules("swig.c", {moduletype = "python"}) add_files("src/example.i", {scriptdir = "share"}) add_files("src/example.c") add_packages("python") ================================================ FILE: tests/projects/swig/python_c_with_soabi/src/example.c ================================================ double My_variable = 3.0; /* Compute factorial of n */ int fact(int n) { if (n <= 1) return 1; else return n*fact(n-1); } /* Compute n mod m */ int my_mod(int n, int m) { return(n % m); } ================================================ FILE: tests/projects/swig/python_c_with_soabi/src/example.i ================================================ %module example %{ /* Put headers and other declarations here */ extern double My_variable; extern int fact(int); extern int my_mod(int n, int m); %} extern double My_variable; extern int fact(int); extern int my_mod(int n, int m); ================================================ FILE: tests/projects/swig/python_c_with_soabi/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("python 3.x") target("example") add_rules("swig.c", {moduletype = "python", soabi = true}) add_files("src/example.i", {scriptdir = "share"}) add_files("src/example.c") add_packages("python") ================================================ FILE: tests/projects/swig/python_cpp/src/example.cpp ================================================ double My_variable = 3.0; /* Compute factorial of n */ int fact(int n) { if (n <= 1) return 1; else return n*fact(n-1); } /* Compute n mod m */ int my_mod(int n, int m) { return(n % m); } ================================================ FILE: tests/projects/swig/python_cpp/src/example.i ================================================ %module example %{ /* Put headers and other declarations here */ extern double My_variable; extern int fact(int); extern int my_mod(int n, int m); %} extern double My_variable; extern int fact(int); extern int my_mod(int n, int m); ================================================ FILE: tests/projects/swig/python_cpp/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("python 3.x") target("example") add_rules("swig.cpp", {moduletype = "python"}) add_files("src/example.i", {scriptdir = "share"}) add_files("src/example.cpp") add_packages("python") ================================================ FILE: tests/projects/vala/gtk+3/src/main.vala ================================================ using Gtk; int main (string[] args) { Gtk.init (ref args); var window = new Window (); window.title = "First GTK+ Program"; window.border_width = 10; window.window_position = WindowPosition.CENTER; window.set_default_size (350, 70); window.destroy.connect (Gtk.main_quit); var button = new Button.with_label ("Click me!"); button.clicked.connect (() => { button.label = "Thank you"; }); window.add (button); window.show_all (); Gtk.main (); return 0; } ================================================ FILE: tests/projects/vala/gtk+3/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("gtk+3", "glib") target("test") set_kind("binary") add_rules("vala") add_files("src/*.vala") add_packages("gtk+3", "glib") add_values("vala.packages", "gtk+-3.0") ================================================ FILE: tests/projects/vala/includec/src/main.vala ================================================ extern void printer_from_c(); int main (string[] args) { printer_from_c(); printer_from_other_file(); return 0; } ================================================ FILE: tests/projects/vala/includec/src/printer.c ================================================ #include void printer_from_c() { printf("Calling from C"); } ================================================ FILE: tests/projects/vala/includec/src/printer.vala ================================================ void printer_from_other_file() { stdout.printf("Calling from other file"); } ================================================ FILE: tests/projects/vala/includec/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("glib") target("test") set_kind("binary") add_rules("vala") add_files("src/*.vala") add_files("src/*.c") add_packages("glib") ================================================ FILE: tests/projects/vala/lua/src/main.vala ================================================ using Lua; static int my_func (LuaVM vm) { stdout.printf ("Vala Code From Lua Code! (%f)\n", vm.to_number (1)); return 1; } static int main (string[] args) { string code = """ print "Lua Code From Vala Code!" my_func(33) """; var vm = new LuaVM (); vm.open_libs (); vm.register ("my_func", my_func); vm.do_string (code); return 0; } ================================================ FILE: tests/projects/vala/lua/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("lua", "glib") target("test") set_kind("binary") add_rules("vala") add_files("src/*.vala") add_packages("lua", "glib") add_values("vala.packages", "lua") ================================================ FILE: tests/projects/vala/sharedlib/src/main.vala ================================================ using MyMath; public void main() { stdout.printf("\n\t2 + 3 is %d", sum(2, 3)); stdout.printf("\n\t8 squared is %d\n", square(8)); } ================================================ FILE: tests/projects/vala/sharedlib/src/mymath.vala ================================================ namespace MyMath { public int sum(int a, int b) { return(a + b); } public int square(int a) { return(a * a); } } ================================================ FILE: tests/projects/vala/sharedlib/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("glib") target("mymath") set_kind("shared") add_rules("vala") add_files("src/mymath.vala") add_values("vala.header", "mymath.h") add_values("vala.vapi", "mymath-1.0.vapi") add_packages("glib") target("test") set_kind("binary") add_deps("mymath") add_rules("vala") add_files("src/main.vala") add_packages("glib") ================================================ FILE: tests/projects/vala/sqlite3/src/main.vala ================================================ /** * Using SQLite in Vala Sample Code * Port of an example found on the SQLite site. * http://www.sqlite.org/quickstart.html */ using GLib; using Sqlite; public class SqliteSample : GLib.Object { public static int callback (int n_columns, string[] values, string[] column_names) { for (int i = 0; i < n_columns; i++) { stdout.printf ("%s = %s\n", column_names[i], values[i]); } stdout.printf ("\n"); return 0; } public static int main (string[] args) { Database db; int rc; if (args.length != 3) { stderr.printf ("Usage: %s DATABASE SQL-STATEMENT\n", args[0]); return 1; } if (!FileUtils.test (args[1], FileTest.IS_REGULAR)) { stderr.printf ("Database %s does not exist or is directory\n", args[1]); return 1; } rc = Database.open (args[1], out db); if (rc != Sqlite.OK) { stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ()); return 1; } rc = db.exec (args[2], callback, null); /* maybe it is better to use closures, so you can access local variables, eg: */ /*rc = db.exec(args[2], (n_columns, values, column_names) => { for (int i = 0; i < n_columns; i++) { stdout.printf ("%s = %s\n", column_names[i], values[i]); } stdout.printf ("\n"); return 0; }, null); */ if (rc != Sqlite.OK) { stderr.printf ("SQL error: %d, %s\n", rc, db.errmsg ()); return 1; } return 0; } } ================================================ FILE: tests/projects/vala/sqlite3/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("sqlite3", "glib") target("test") set_kind("binary") add_rules("vala") add_files("src/*.vala") add_packages("sqlite3", "glib") add_values("vala.packages", "sqlite3") ================================================ FILE: tests/projects/vala/staticlib/src/main.vala ================================================ using MyMath; public void main() { stdout.printf("\n\t2 + 3 is %d", sum(2, 3)); stdout.printf("\n\t8 squared is %d\n", square(8)); } ================================================ FILE: tests/projects/vala/staticlib/src/mymath.vala ================================================ namespace MyMath { public int sum(int a, int b) { return(a + b); } public int square(int a) { return(a * a); } } ================================================ FILE: tests/projects/vala/staticlib/xmake.lua ================================================ add_rules("mode.release", "mode.debug") add_requires("glib") target("mymath") set_kind("static") add_rules("vala") add_files("src/mymath.vala") add_values("vala.header", "mymath.h") add_values("vala.vapi", "mymath-1.0.vapi") add_packages("glib") target("test") set_kind("binary") add_deps("mymath") add_rules("vala") add_files("src/main.vala") add_packages("glib") ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/driver/nonpnp.c ================================================ /*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: nonpnp.c Abstract: Purpose of this driver is to demonstrate how to write a legacy (NON WDM) driver using framework, show how to handle 4 different ioctls - METHOD_NEITHER - in particular and also show how to read & write to file from KernelMode using Zw functions. For a non-framework version of sample on how to handle IOCTLs in driver, study src\general\IOCTL in the DDK. Environment: Kernel mode only. --*/ #include "nonpnp.h" // // The trace message header file must be included in a source file // before any WPP macro calls and after defining a WPP_CONTROL_GUIDS // macro. During the compilation, WPP scans the source files for // TraceEvents() calls and builds a .tmh file which stores a unique // data GUID for each message, the text resource string for each message, // and the data types of the variables passed in for each message. // This file is automatically generated and used during post-processing. // #include "nonpnp.tmh" #ifdef ALLOC_PRAGMA #pragma alloc_text( INIT, DriverEntry ) #pragma alloc_text( PAGE, NonPnpDeviceAdd) #pragma alloc_text( PAGE, NonPnpEvtDriverContextCleanup) #pragma alloc_text( PAGE, NonPnpEvtDriverUnload) #pragma alloc_text( PAGE, NonPnpEvtDeviceIoInCallerContext) #pragma alloc_text( PAGE, NonPnpEvtDeviceFileCreate) #pragma alloc_text( PAGE, NonPnpEvtFileClose) #pragma alloc_text( PAGE, FileEvtIoRead) #pragma alloc_text( PAGE, FileEvtIoWrite) #pragma alloc_text( PAGE, FileEvtIoDeviceControl) #endif // ALLOC_PRAGMA NTSTATUS DriverEntry( IN OUT PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine is called by the Operating System to initialize the driver. It creates the device object, fills in the dispatch entry points and completes the initialization. Arguments: DriverObject - a pointer to the object that represents this device driver. RegistryPath - a pointer to our Services key in the registry. Return Value: STATUS_SUCCESS if initialized; an error otherwise. --*/ { NTSTATUS status; WDF_DRIVER_CONFIG config; WDFDRIVER hDriver; PWDFDEVICE_INIT pInit = NULL; WDF_OBJECT_ATTRIBUTES attributes; KdPrint(("Driver Frameworks NONPNP Legacy Driver Example\n")); WDF_DRIVER_CONFIG_INIT( &config, WDF_NO_EVENT_CALLBACK // This is a non-pnp driver. ); // // Tell the framework that this is non-pnp driver so that it doesn't // set the default AddDevice routine. // config.DriverInitFlags |= WdfDriverInitNonPnpDriver; // // NonPnp driver must explicitly register an unload routine for // the driver to be unloaded. // config.EvtDriverUnload = NonPnpEvtDriverUnload; // // Register a cleanup callback so that we can call WPP_CLEANUP when // the framework driver object is deleted during driver unload. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.EvtCleanupCallback = NonPnpEvtDriverContextCleanup; // // Create a framework driver object to represent our driver. // status = WdfDriverCreate(DriverObject, RegistryPath, &attributes, &config, &hDriver); if (!NT_SUCCESS(status)) { KdPrint (("NonPnp: WdfDriverCreate failed with status 0x%x\n", status)); return status; } // // Since we are calling WPP_CLEANUP in the DriverContextCleanup // callback we should initialize WPP Tracing after WDFDRIVER // object is created to ensure that we cleanup WPP properly // if we return failure status from DriverEntry. This // eliminates the need to call WPP_CLEANUP in every path // of DriverEntry. // WPP_INIT_TRACING( DriverObject, RegistryPath ); // // On Win2K system, you will experience some delay in getting trace events // due to the way the ETW is activated to accept trace messages. // KdPrint(("NonPnp: DriverEntry: tracing enabled\n")); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Driver Frameworks NONPNP Legacy Driver Example"); // // // In order to create a control device, we first need to allocate a // WDFDEVICE_INIT structure and set all properties. // pInit = WdfControlDeviceInitAllocate( hDriver, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R ); if (pInit == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; return status; } // // Call NonPnpDeviceAdd to create a deviceobject to represent our // software device. // status = NonPnpDeviceAdd(hDriver, pInit); return status; } NTSTATUS NonPnpDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Called by the DriverEntry to create a control-device. This call is responsible for freeing the memory for DeviceInit. Arguments: DriverObject - a pointer to the object that represents this device driver. DeviceInit - Pointer to a driver-allocated WDFDEVICE_INIT structure. Return Value: STATUS_SUCCESS if initialized; an error otherwise. --*/ { NTSTATUS status; WDF_OBJECT_ATTRIBUTES attributes; WDF_IO_QUEUE_CONFIG ioQueueConfig; WDF_FILEOBJECT_CONFIG fileConfig; WDFQUEUE queue; WDFDEVICE controlDevice; DECLARE_CONST_UNICODE_STRING(ntDeviceName, NTDEVICE_NAME_STRING) ; DECLARE_CONST_UNICODE_STRING(symbolicLinkName, SYMBOLIC_NAME_STRING) ; UNREFERENCED_PARAMETER( Driver ); PAGED_CODE(); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "NonPnpDeviceAdd DeviceInit %p\n", DeviceInit); // // Set exclusive to TRUE so that no more than one app can talk to the // control device at any time. // WdfDeviceInitSetExclusive(DeviceInit, TRUE); WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceInitAssignName failed %!STATUS!", status); goto End; } WdfControlDeviceInitSetShutdownNotification(DeviceInit, NonPnpShutdown, WdfDeviceShutdown); // // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the // framework whether you are interested in handling Create, Close and // Cleanup requests that gets generated when an application or another // kernel component opens an handle to the device. If you don't register // the framework default behaviour would be to complete these requests // with STATUS_SUCCESS. A driver might be interested in registering these // events if it wants to do security validation and also wants to maintain // per handle (fileobject) context. // WDF_FILEOBJECT_CONFIG_INIT( &fileConfig, NonPnpEvtDeviceFileCreate, NonPnpEvtFileClose, WDF_NO_EVENT_CALLBACK // not interested in Cleanup ); WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, WDF_NO_OBJECT_ATTRIBUTES); // // In order to support METHOD_NEITHER Device controls, or // NEITHER device I/O type, we need to register for the // EvtDeviceIoInProcessContext callback so that we can handle the request // in the calling threads context. // WdfDeviceInitSetIoInCallerContextCallback(DeviceInit, NonPnpEvtDeviceIoInCallerContext); // // Specify the size of device context // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CONTROL_DEVICE_EXTENSION); status = WdfDeviceCreate(&DeviceInit, &attributes, &controlDevice); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreate failed %!STATUS!", status); goto End; } // // Create a symbolic link for the control object so that usermode can open // the device. // status = WdfDeviceCreateSymbolicLink(controlDevice, &symbolicLinkName); if (!NT_SUCCESS(status)) { // // Control device will be deleted automatically by the framework. // TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreateSymbolicLink failed %!STATUS!", status); goto End; } // // Configure a default queue so that requests that are not // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto // other queues get dispatched here. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoRead = FileEvtIoRead; ioQueueConfig.EvtIoWrite = FileEvtIoWrite; ioQueueConfig.EvtIoDeviceControl = FileEvtIoDeviceControl; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); // // Since we are using Zw function set execution level to passive so that // framework ensures that our Io callbacks called at only passive-level // even if the request came in at DISPATCH_LEVEL from another driver. // //attributes.ExecutionLevel = WdfExecutionLevelPassive; // // By default, Static Driver Verifier (SDV) displays a warning if it // doesn't find the EvtIoStop callback on a power-managed queue. // The 'assume' below causes SDV to suppress this warning. If the driver // has not explicitly set PowerManaged to WdfFalse, the framework creates // power-managed queues when the device is not a filter driver. Normally // the EvtIoStop is required for power-managed queues, but for this driver // it is not needed b/c the driver doesn't hold on to the requests or // forward them to other drivers. This driver completes the requests // directly in the queue's handlers. If the EvtIoStop callback is not // implemented, the framework waits for all driver-owned requests to be // done before moving in the Dx/sleep states or before removing the // device, which is the correct behavior for this type of driver. // If the requests were taking an indeterminate amount of time to complete, // or if the driver forwarded the requests to a lower driver/another stack, // the queue should have an EvtIoStop/EvtIoResume. // __analysis_assume(ioQueueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(controlDevice, &ioQueueConfig, &attributes, &queue // pointer to default queue ); __analysis_assume(ioQueueConfig.EvtIoStop == 0); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfIoQueueCreate failed %!STATUS!", status); goto End; } // // Control devices must notify WDF when they are done initializing. I/O is // rejected until this call is made. // WdfControlFinishInitializing(controlDevice); End: // // If the device is created successfully, framework would clear the // DeviceInit value. Otherwise device create must have failed so we // should free the memory ourself. // if (DeviceInit != NULL) { WdfDeviceInitFree(DeviceInit); } return status; } VOID NonPnpEvtDriverContextCleanup( IN WDFOBJECT Driver ) /*++ Routine Description: Called when the driver object is deleted during driver unload. You can free all the resources created in DriverEntry that are not automatically freed by the framework. Arguments: Driver - Handle to a framework driver object created in DriverEntry Return Value: NTSTATUS --*/ { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Entered NonPnpEvtDriverContextCleanup\n"); PAGED_CODE(); // // No need to free the controldevice object explicitly because it will // be deleted when the Driver object is deleted due to the default parent // child relationship between Driver and ControlDevice. // WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver ) ); } VOID NonPnpEvtDeviceFileCreate ( IN WDFDEVICE Device, IN WDFREQUEST Request, IN WDFFILEOBJECT FileObject ) /*++ Routine Description: The framework calls a driver's EvtDeviceFileCreate callback when it receives an IRP_MJ_CREATE request. The system sends this request when a user application opens the device to perform an I/O operation, such as reading or writing a file. This callback is called synchronously, in the context of the thread that created the IRP_MJ_CREATE request. Arguments: Device - Handle to a framework device object. FileObject - Pointer to fileobject that represents the open handle. CreateParams - Parameters of IO_STACK_LOCATION for create Return Value: NT status code --*/ { PUNICODE_STRING fileName; UNICODE_STRING absFileName, directory; OBJECT_ATTRIBUTES fileAttributes; IO_STATUS_BLOCK ioStatus; PCONTROL_DEVICE_EXTENSION devExt; NTSTATUS status; USHORT length = 0; UNREFERENCED_PARAMETER( FileObject ); PAGED_CODE (); devExt = ControlGetData(Device); // // Assume the directory is a temp directory under %windir% // RtlInitUnicodeString(&directory, L"\\SystemRoot\\temp"); // // Parsed filename has "\" in the begining. The object manager strips // of all "\", except one, after the device name. // fileName = WdfFileObjectGetFileName(FileObject); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "NonPnpEvtDeviceFileCreate %wZ%wZ", &directory, fileName); // // Find the total length of the directory + filename // length = directory.Length + fileName->Length; absFileName.Buffer = ExAllocatePoolWithTag(PagedPool, length, POOL_TAG); if(absFileName.Buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "ExAllocatePoolWithTag failed"); goto End; } absFileName.Length = 0; absFileName.MaximumLength = length; status = RtlAppendUnicodeStringToString(&absFileName, &directory); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "RtlAppendUnicodeStringToString failed with status %!STATUS!", status); goto End; } status = RtlAppendUnicodeStringToString(&absFileName, fileName); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "RtlAppendUnicodeStringToString failed with status %!STATUS!", status); goto End; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Absolute Filename %wZ", &absFileName); InitializeObjectAttributes( &fileAttributes, &absFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, // RootDirectory NULL // SecurityDescriptor ); status = ZwCreateFile ( &devExt->FileHandle, SYNCHRONIZE | GENERIC_WRITE | GENERIC_READ, &fileAttributes, &ioStatus, NULL,// alloc size = none FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT |FILE_NON_DIRECTORY_FILE, NULL,// eabuffer 0// ealength ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "ZwCreateFile failed with status %!STATUS!", status); devExt->FileHandle = NULL; } End: if(absFileName.Buffer != NULL) { ExFreePool(absFileName.Buffer); } WdfRequestComplete(Request, status); return; } VOID NonPnpEvtFileClose ( IN WDFFILEOBJECT FileObject ) /*++ Routine Description: EvtFileClose is called when all the handles represented by the FileObject is closed and all the references to FileObject is removed. This callback may get called in an arbitrary thread context instead of the thread that called CloseHandle. If you want to delete any per FileObject context that must be done in the context of the user thread that made the Create call, you should do that in the EvtDeviceCleanp callback. Arguments: FileObject - Pointer to fileobject that represents the open handle. Return Value: VOID --*/ { PCONTROL_DEVICE_EXTENSION devExt; PAGED_CODE (); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "NonPnpEvtFileClose\n"); devExt = ControlGetData(WdfFileObjectGetDevice(FileObject)); if(devExt->FileHandle) { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Closing File Handle %p", devExt->FileHandle); ZwClose(devExt->FileHandle); } return; } VOID FileEvtIoRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_READ requests. We will just read the file. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. Length - number of bytes to be read. Queue is by default configured to fail zero length read & write requests. Return Value: None. --*/ { NTSTATUS status = STATUS_SUCCESS; PVOID outBuf; IO_STATUS_BLOCK ioStatus; PCONTROL_DEVICE_EXTENSION devExt; FILE_POSITION_INFORMATION position; ULONG_PTR bytesRead = 0; size_t bufLength; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_RW, "FileEvtIoRead: Request: 0x%p, Queue: 0x%p\n", Request, Queue); PAGED_CODE (); // // Get the request buffer. Since the device is set to do buffered // I/O, this function will retrieve Irp->AssociatedIrp.SystemBuffer. // status = WdfRequestRetrieveOutputBuffer(Request, 0, &outBuf, &bufLength); if(!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } devExt = ControlGetData(WdfIoQueueGetDevice(Queue)); if(devExt->FileHandle) { // // Set the file position to the beginning of the file. // position.CurrentByteOffset.QuadPart = 0; status = ZwSetInformationFile(devExt->FileHandle, &ioStatus, &position, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); if (NT_SUCCESS(status)) { status = ZwReadFile (devExt->FileHandle, NULL,// Event, NULL,// PIO_APC_ROUTINE ApcRoutine NULL,// PVOID ApcContext &ioStatus, outBuf, (ULONG)Length, 0, // ByteOffset NULL // Key ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_RW, "ZwReadFile failed with status 0x%x", status); } status = ioStatus.Status; bytesRead = ioStatus.Information; } } WdfRequestCompleteWithInformation(Request, status, bytesRead); } VOID FileEvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_WRITE requests. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. Length - number of bytes to be written. Queue is by default configured to fail zero length read & write requests. Return Value: None --*/ { NTSTATUS status = STATUS_SUCCESS; PVOID inBuf; IO_STATUS_BLOCK ioStatus; PCONTROL_DEVICE_EXTENSION devExt; FILE_POSITION_INFORMATION position; ULONG_PTR bytesWritten = 0; size_t bufLength; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_RW, "FileEvtIoWrite: Request: 0x%p, Queue: 0x%p\n", Request, Queue); PAGED_CODE (); // // Get the request buffer. Since the device is set to do buffered // I/O, this function will retrieve Irp->AssociatedIrp.SystemBuffer. // status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufLength); if(!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } devExt = ControlGetData(WdfIoQueueGetDevice(Queue)); if(devExt->FileHandle) { // // Set the file position to the beginning of the file. // position.CurrentByteOffset.QuadPart = 0; status = ZwSetInformationFile(devExt->FileHandle, &ioStatus, &position, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); if (NT_SUCCESS(status)) { status = ZwWriteFile(devExt->FileHandle, NULL,// Event, NULL,// PIO_APC_ROUTINE ApcRoutine NULL,// PVOID ApcContext &ioStatus, inBuf, (ULONG)Length, 0, // ByteOffset NULL // Key ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_RW, "ZwWriteFile failed with status 0x%x", status); } status = ioStatus.Status; bytesWritten = ioStatus.Information; } } WdfRequestCompleteWithInformation(Request, status, bytesWritten); } VOID FileEvtIoDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { NTSTATUS status = STATUS_SUCCESS;// Assume success PCHAR inBuf = NULL, outBuf = NULL; // pointer to Input and output buffer PCHAR data = "this String is from Device Driver !!!"; ULONG datalen = (ULONG) strlen(data)+1;//Length of data including null PCHAR buffer = NULL; PREQUEST_CONTEXT reqContext = NULL; size_t bufSize; UNREFERENCED_PARAMETER( Queue ); PAGED_CODE(); if(!OutputBufferLength || !InputBufferLength) { WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } // // Determine which I/O control code was specified. // switch (IoControlCode) { case IOCTL_NONPNP_METHOD_BUFFERED: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_BUFFERED\n"); // // For bufffered ioctls WdfRequestRetrieveInputBuffer & // WdfRequestRetrieveOutputBuffer return the same buffer // pointer (Irp->AssociatedIrp.SystemBuffer), so read the // content of the buffer before writing to it. // status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize); if(!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ASSERT(bufSize == InputBufferLength); // // Read the input buffer content. // We are using the following function to print characters instead // TraceEvents with %s format because the string we get may or // may not be null terminated. The buffer may contain non-printable // characters also. // Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n", log_xstr(inBuf, (USHORT)InputBufferLength))); PrintChars(inBuf, InputBufferLength ); status = WdfRequestRetrieveOutputBuffer(Request, 0, &outBuf, &bufSize); if(!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ASSERT(bufSize == OutputBufferLength); // // Writing to the buffer over-writes the input buffer content // RtlCopyMemory(outBuf, data, OutputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data to User : %!HEXDUMP!\n", log_xstr(outBuf, (USHORT)datalen))); PrintChars(outBuf, datalen ); // // Assign the length of the data copied to IoStatus.Information // of the request and complete the request. // WdfRequestSetInformation(Request, OutputBufferLength < datalen? OutputBufferLength:datalen); // // When the request is completed the content of the SystemBuffer // is copied to the User output buffer and the SystemBuffer is // is freed. // break; case IOCTL_NONPNP_METHOD_IN_DIRECT: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_IN_DIRECT\n"); // // Get the Input buffer. WdfRequestRetrieveInputBuffer returns // Irp->AssociatedIrp.SystemBuffer. // status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize); if(!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ASSERT(bufSize == InputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n", log_xstr(inBuf, (USHORT)InputBufferLength))); PrintChars(inBuf, InputBufferLength); // // Get the output buffer. Framework calls MmGetSystemAddressForMdlSafe // on the Irp->MdlAddress and returns the system address. // Oddity: For this method, this buffer is intended for transfering data // from the application to the driver. // status = WdfRequestRetrieveOutputBuffer(Request, 0, &buffer, &bufSize); if(!NT_SUCCESS(status)) { break; } ASSERT(bufSize == OutputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User in OutputBuffer: %!HEXDUMP!\n", log_xstr(buffer, (USHORT)OutputBufferLength))); PrintChars(buffer, OutputBufferLength); // // Return total bytes read from the output buffer. // Note OutputBufferLength = MmGetMdlByteCount(Irp->MdlAddress) // WdfRequestSetInformation(Request, OutputBufferLength); // // NOTE: Changes made to the SystemBuffer are not copied // to the user input buffer by the I/O manager // break; case IOCTL_NONPNP_METHOD_OUT_DIRECT: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_OUT_DIRECT\n"); // // Get the Input buffer. WdfRequestRetrieveInputBuffer returns // Irp->AssociatedIrp.SystemBuffer. // status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize); if(!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ASSERT(bufSize == InputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n", log_xstr(inBuf, (USHORT)InputBufferLength))); PrintChars(inBuf, InputBufferLength); // // Get the output buffer. Framework calls MmGetSystemAddressForMdlSafe // on the Irp->MdlAddress and returns the system address. // For this method, this buffer is intended for transfering data from the // driver to the application. // status = WdfRequestRetrieveOutputBuffer(Request, 0, &buffer, &bufSize); if(!NT_SUCCESS(status)) { break; } ASSERT(bufSize == OutputBufferLength); // // Write data to be sent to the user in this buffer // RtlCopyMemory(buffer, data, OutputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data to User : %!HEXDUMP!\n", log_xstr(buffer, (USHORT)datalen))); PrintChars(buffer, datalen); WdfRequestSetInformation(Request, OutputBufferLength < datalen? OutputBufferLength: datalen); // // NOTE: Changes made to the SystemBuffer are not copied // to the user input buffer by the I/O manager // break; case IOCTL_NONPNP_METHOD_NEITHER: { size_t inBufLength, outBufLength; // // The NonPnpEvtDeviceIoInCallerContext has already probe and locked the // pages and mapped the user buffer into system address space and // stored memory buffer pointers in the request context. We can get the // buffer pointer by calling WdfMemoryGetBuffer. // TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_NEITHER\n"); reqContext = GetRequestContext(Request); inBuf = WdfMemoryGetBuffer(reqContext->InputMemoryBuffer, &inBufLength); outBuf = WdfMemoryGetBuffer(reqContext->OutputMemoryBuffer, &outBufLength); if(inBuf == NULL || outBuf == NULL) { status = STATUS_INVALID_PARAMETER; } ASSERT(inBufLength == InputBufferLength); ASSERT(outBufLength == OutputBufferLength); // // Now you can safely read the data from the buffer in any arbitrary // context. // Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n", log_xstr(inBuf, (USHORT)inBufLength))); PrintChars(inBuf, inBufLength); // // Write to the buffer in any arbitrary context. // RtlCopyMemory(outBuf, data, outBufLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data to User : %!HEXDUMP!\n", log_xstr(outBuf, (USHORT)datalen))); PrintChars(outBuf, datalen); // // Assign the length of the data copied to IoStatus.Information // of the Irp and complete the Irp. // WdfRequestSetInformation(Request, outBufLength < datalen? outBufLength:datalen); break; } default: // // The specified I/O control code is unrecognized by this driver. // status = STATUS_INVALID_DEVICE_REQUEST; TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ERROR: unrecognized IOCTL %x\n", IoControlCode); break; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Completing Request %p with status %X", Request, status ); WdfRequestComplete( Request, status); } VOID NonPnpEvtDeviceIoInCallerContext( IN WDFDEVICE Device, IN WDFREQUEST Request ) /*++ Routine Description: This I/O in-process callback is called in the calling threads context/address space before the request is subjected to any framework locking or queueing scheme based on the device pnp/power or locking attributes set by the driver. The process context of the calling app is guaranteed as long as this driver is a top-level driver and no other filter driver is attached to it. This callback is only required if you are handling method-neither IOCTLs, or want to process requests in the context of the calling process. Driver developers should avoid defining neither IOCTLs and access user buffers, and use much safer I/O tranfer methods such as buffered I/O or direct I/O. Arguments: Device - Handle to a framework device object. Request - Handle to a framework request object. Framework calls PreProcess callback only for Read/Write/ioctls and internal ioctl requests. Return Value: VOID --*/ { NTSTATUS status = STATUS_SUCCESS; PREQUEST_CONTEXT reqContext = NULL; WDF_OBJECT_ATTRIBUTES attributes; WDF_REQUEST_PARAMETERS params; size_t inBufLen, outBufLen; PVOID inBuf, outBuf; PAGED_CODE(); WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(Request, ¶ms ); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Entered NonPnpEvtDeviceIoInCallerContext %p \n", Request); // // Check to see whether we have recevied a METHOD_NEITHER IOCTL. if not // just send the request back to framework because we aren't doing // any pre-processing in the context of the calling thread process. // if(!(params.Type == WdfRequestTypeDeviceControl && params.Parameters.DeviceIoControl.IoControlCode == IOCTL_NONPNP_METHOD_NEITHER)) { // // Forward it for processing by the I/O package // status = WdfDeviceEnqueueRequest(Device, Request); if( !NT_SUCCESS(status) ) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error forwarding Request 0x%x", status); goto End; } return; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "EvtIoPreProcess: received METHOD_NEITHER ioctl \n"); // // In this type of transfer, the I/O manager assigns the user input // to Type3InputBuffer and the output buffer to UserBuffer of the Irp. // The I/O manager doesn't copy or map the buffers to the kernel // buffers. // status = WdfRequestRetrieveUnsafeUserInputBuffer(Request, 0, &inBuf, &inBufLen); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestRetrieveUnsafeUserInputBuffer failed 0x%x", status); goto End; } status = WdfRequestRetrieveUnsafeUserOutputBuffer(Request, 0, &outBuf, &outBufLen); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestRetrieveUnsafeUserOutputBuffer failed 0x%x", status); goto End; } // // Allocate a context for this request so that we can store the memory // objects created for input and output buffer. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); status = WdfObjectAllocateContext(Request, &attributes, &reqContext); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfObjectAllocateContext failed 0x%x", status); goto End; } // // WdfRequestProbleAndLockForRead/Write function checks to see // whether the caller in the right thread context, creates an MDL, // probe and locks the pages, and map the MDL to system address // space and finally creates a WDFMEMORY object representing this // system buffer address. This memory object is associated with the // request. So it will be freed when the request is completed. If we // are accessing this memory buffer else where, we should store these // pointers in the request context. // #pragma prefast(suppress:6387, "If inBuf==NULL at this point, then inBufLen==0") status = WdfRequestProbeAndLockUserBufferForRead(Request, inBuf, inBufLen, &reqContext->InputMemoryBuffer); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestProbeAndLockUserBufferForRead failed 0x%x", status); goto End; } #pragma prefast(suppress:6387, "If outBuf==NULL at this point, then outBufLen==0") status = WdfRequestProbeAndLockUserBufferForWrite(Request, outBuf, outBufLen, &reqContext->OutputMemoryBuffer); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestProbeAndLockUserBufferForWrite failed 0x%x", status); goto End; } // // Finally forward it for processing by the I/O package // status = WdfDeviceEnqueueRequest(Device, Request); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfDeviceEnqueueRequest failed 0x%x", status); goto End; } return; End: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "EvtIoPreProcess failed %x \n", status); WdfRequestComplete(Request, status); return; } VOID NonPnpShutdown( WDFDEVICE Device ) /*++ Routine Description: Callback invoked when the machine is shutting down. If you register for a last chance shutdown notification you cannot do the following: o Call any pageable routines o Access pageable memory o Perform any file I/O operations If you register for a normal shutdown notification, all of these are available to you. This function implementation does nothing, but if you had any outstanding file handles open, this is where you would close them. Arguments: Device - The device which registered the notification during init Return Value: None --*/ { UNREFERENCED_PARAMETER(Device); return; } VOID NonPnpEvtDriverUnload( IN WDFDRIVER Driver ) /*++ Routine Description: Called by the I/O subsystem just before unloading the driver. You can free the resources created in the DriverEntry either in this routine or in the EvtDriverContextCleanup callback. Arguments: Driver - Handle to a framework driver object created in DriverEntry Return Value: NTSTATUS --*/ { UNREFERENCED_PARAMETER(Driver); PAGED_CODE(); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Entered NonPnpDriverUnload\n"); return; } VOID PrintChars( _In_reads_(CountChars) PCHAR BufferAddress, _In_ size_t CountChars ) { if (CountChars) { while (CountChars--) { if (*BufferAddress > 31 && *BufferAddress != 127) { KdPrint (( "%c", *BufferAddress) ); } else { KdPrint(( ".") ); } BufferAddress++; } KdPrint (("\n")); } return; } ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/driver/nonpnp.h ================================================ /*++ Copyright (c) 1997 Microsoft Corporation Module Name: nonpnp.h Abstract: Contains function prototypes and includes other neccessary header files. Environment: Kernel mode only. --*/ #include #include #define NTSTRSAFE_LIB #include #include // for SDDLs #include "public.h" // contains IOCTL definitions #include "Trace.h" // contains macros for WPP tracing #define NTDEVICE_NAME_STRING L"\\Device\\NONPNP" #define SYMBOLIC_NAME_STRING L"\\DosDevices\\NONPNP" #define POOL_TAG 'ELIF' typedef struct _CONTROL_DEVICE_EXTENSION { HANDLE FileHandle; // Store your control data here } CONTROL_DEVICE_EXTENSION, *PCONTROL_DEVICE_EXTENSION; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CONTROL_DEVICE_EXTENSION, ControlGetData) // // Following request context is used only for the method-neither ioctl case. // typedef struct _REQUEST_CONTEXT { WDFMEMORY InputMemoryBuffer; WDFMEMORY OutputMemoryBuffer; } REQUEST_CONTEXT, *PREQUEST_CONTEXT; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, GetRequestContext) // // Device driver routine declarations. // DRIVER_INITIALIZE DriverEntry; // // Don't use EVT_WDF_DRIVER_DEVICE_ADD for NonPnpDeviceAdd even though // the signature is same because this is not an event called by the // framework. // NTSTATUS NonPnpDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ); EVT_WDF_DRIVER_UNLOAD NonPnpEvtDriverUnload; EVT_WDF_DEVICE_CONTEXT_CLEANUP NonPnpEvtDriverContextCleanup; EVT_WDF_DEVICE_SHUTDOWN_NOTIFICATION NonPnpShutdown; EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL FileEvtIoDeviceControl; EVT_WDF_IO_QUEUE_IO_READ FileEvtIoRead; EVT_WDF_IO_QUEUE_IO_WRITE FileEvtIoWrite; EVT_WDF_IO_IN_CALLER_CONTEXT NonPnpEvtDeviceIoInCallerContext; EVT_WDF_DEVICE_FILE_CREATE NonPnpEvtDeviceFileCreate; EVT_WDF_FILE_CLOSE NonPnpEvtFileClose; VOID PrintChars( _In_reads_(CountChars) PCHAR BufferAddress, _In_ size_t CountChars ); #pragma warning(disable:4127) ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/driver/nonpnp.rc ================================================ #include #include #define VER_FILETYPE VFT_DRV #define VER_FILESUBTYPE VFT2_DRV_SYSTEM #define VER_FILEDESCRIPTION_STR "Sample Non-PNP Driver using WDF" #define VER_INTERNALNAME_STR "NONPNP.sys" #include "common.ver" ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/driver/trace.h ================================================ /*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: TRACE.h Abstract: Header file for the debug tracing related function defintions and macros. Environment: Kernel mode --*/ // // If software tracing is defined in the sources file.. // WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver. // *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID *** // WPP_DEFINE_BIT allows setting debug bit masks to selectively print. // The names defined in the WPP_DEFINE_BIT call define the actual names // that are used to control the level of tracing for the control guid // specified. // // {71ae54db-0862-41bf-a24f-5330cec3c7f6} // #define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings #define WPP_CONTROL_GUIDS \ WPP_DEFINE_CONTROL_GUID( FileIoTraceGuid, \ (71ae54db,0862,41bf,a24f,5330cec3c7f6), \ WPP_DEFINE_BIT(DBG_INIT) \ WPP_DEFINE_BIT(DBG_RW) \ WPP_DEFINE_BIT(DBG_IOCTL) \ ) #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) #pragma warning(disable:4204) // C4204 nonstandard extension used : non-constant aggregate initializer // // Define the 'xstr' structure for logging buffer and length pairs // and the 'log_xstr' function which returns it to create one in-place. // this enables logging of complex data types. // typedef struct xstr { char * _buf; short _len; } xstr_t; __inline xstr_t log_xstr(void * p, short l) { xstr_t xs = {(char*)p,l}; return xs; } #pragma warning(default:4204) // // Define the macro required for a hexdump use as: // // Hexdump((FLAG,"%!HEXDUMP!\n", log_xstr(buffersize,(char *)buffer) )); // // #define WPP_LOGHEXDUMP(x) WPP_LOGPAIR(2, &((x)._len)) WPP_LOGPAIR((x)._len, (x)._buf) ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/exe/install.c ================================================ /*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: install.c Abstract: Win32 routines to dynamically load and unload a Windows NT kernel-mode driver using the Service Control Manager APIs. Environment: User mode only --*/ #include _Analysis_mode_(_Analysis_code_type_user_code_) #include #include #include #include #include #include "public.h" #include #define ARRAY_SIZE(x) (sizeof(x) /sizeof(x[0])) extern PCHAR GetCoinstallerVersion( VOID ) ; BOOLEAN InstallDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName, IN LPCTSTR ServiceExe ); BOOLEAN RemoveDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ); BOOLEAN StartDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ); BOOLEAN StopDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ); #define SYSTEM32_DRIVERS "\\System32\\Drivers\\" #define NONPNP_INF_FILENAME L"\\nonpnp.inf" #define WDF_SECTION_NAME L"nonpnp.NT.Wdf" //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- PFN_WDFPREDEVICEINSTALLEX pfnWdfPreDeviceInstallEx; PFN_WDFPOSTDEVICEINSTALL pfnWdfPostDeviceInstall; PFN_WDFPREDEVICEREMOVE pfnWdfPreDeviceRemove; PFN_WDFPOSTDEVICEREMOVE pfnWdfPostDeviceRemove; //----------------------------------------------------------------------------- // 4127 -- Conditional Expression is Constant warning //----------------------------------------------------------------------------- #define WHILE(a) \ __pragma(warning(suppress:4127)) while(a) LONG GetPathToInf( _Out_writes_(InfFilePathSize) PWCHAR InfFilePath, IN ULONG InfFilePathSize ) { LONG error = ERROR_SUCCESS; if (GetCurrentDirectoryW(InfFilePathSize, InfFilePath) == 0) { error = GetLastError(); printf("InstallDriver failed! Error = %d \n", error); return error; } if (FAILED( StringCchCatW(InfFilePath, InfFilePathSize, NONPNP_INF_FILENAME) )) { error = ERROR_BUFFER_OVERFLOW; return error; } return error; } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- BOOLEAN InstallDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName, IN LPCTSTR ServiceExe ) /*++ Routine Description: Arguments: Return Value: --*/ { SC_HANDLE schService; DWORD err; WCHAR infPath[MAX_PATH]; WDF_COINSTALLER_INSTALL_OPTIONS clientOptions; WDF_COINSTALLER_INSTALL_OPTIONS_INIT(&clientOptions); // // NOTE: This creates an entry for a standalone driver. If this // is modified for use with a driver that requires a Tag, // Group, and/or Dependencies, it may be necessary to // query the registry for existing driver information // (in order to determine a unique Tag, etc.). // // // PRE-INSTALL for WDF support // err = GetPathToInf(infPath, ARRAY_SIZE(infPath) ); if (err != ERROR_SUCCESS) { return FALSE; } err = pfnWdfPreDeviceInstallEx(infPath, WDF_SECTION_NAME, &clientOptions); if (err != ERROR_SUCCESS) { if (err == ERROR_SUCCESS_REBOOT_REQUIRED) { printf("System needs to be rebooted, before the driver installation can proceed.\n"); } return FALSE; } // // Create a new a service object. // schService = CreateService(SchSCManager, // handle of service control manager database DriverName, // address of name of service to start DriverName, // address of display name SERVICE_ALL_ACCESS, // type of access to service SERVICE_KERNEL_DRIVER, // type of service SERVICE_DEMAND_START, // when to start service SERVICE_ERROR_NORMAL, // severity if service fails to start ServiceExe, // address of name of binary file NULL, // service does not belong to a group NULL, // no tag requested NULL, // no dependency names NULL, // use LocalSystem account NULL // no password for service account ); if (schService == NULL) { err = GetLastError(); if (err == ERROR_SERVICE_EXISTS) { // // Ignore this error. // return TRUE; } else { printf("CreateService failed! Error = %d \n", err ); // // Indicate an error. // return FALSE; } } // // Close the service object. // CloseServiceHandle(schService); // // POST-INSTALL for WDF support // err = pfnWdfPostDeviceInstall( infPath, WDF_SECTION_NAME ); if (err != ERROR_SUCCESS) { return FALSE; } // // Indicate success. // return TRUE; } // InstallDriver BOOLEAN ManageDriver( IN LPCTSTR DriverName, IN LPCTSTR ServiceName, IN USHORT Function ) { SC_HANDLE schSCManager; BOOLEAN rCode = TRUE; // // Insure (somewhat) that the driver and service names are valid. // if (!DriverName || !ServiceName) { printf("Invalid Driver or Service provided to ManageDriver() \n"); return FALSE; } // // Connect to the Service Control Manager and open the Services database. // schSCManager = OpenSCManager(NULL, // local machine NULL, // local database SC_MANAGER_ALL_ACCESS // access required ); if (!schSCManager) { printf("Open SC Manager failed! Error = %d \n", GetLastError()); return FALSE; } // // Do the requested function. // switch( Function ) { case DRIVER_FUNC_INSTALL: // // Install the driver service. // if (InstallDriver(schSCManager, DriverName, ServiceName )) { // // Start the driver service (i.e. start the driver). // rCode = StartDriver(schSCManager, DriverName ); } else { // // Indicate an error. // rCode = FALSE; } break; case DRIVER_FUNC_REMOVE: // // Stop the driver. // StopDriver(schSCManager, DriverName ); // // Remove the driver service. // RemoveDriver(schSCManager, DriverName ); // // Ignore all errors. // rCode = TRUE; break; default: printf("Unknown ManageDriver() function. \n"); rCode = FALSE; break; } // // Close handle to service control manager. // CloseServiceHandle(schSCManager); return rCode; } // ManageDriver BOOLEAN RemoveDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) { SC_HANDLE schService; BOOLEAN rCode; DWORD err; WCHAR infPath[MAX_PATH]; err = GetPathToInf(infPath, ARRAY_SIZE(infPath) ); if (err != ERROR_SUCCESS) { return FALSE; } // // PRE-REMOVE of WDF support // err = pfnWdfPreDeviceRemove( infPath, WDF_SECTION_NAME ); if (err != ERROR_SUCCESS) { return FALSE; } // // Open the handle to the existing service. // schService = OpenService(SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { printf("OpenService failed! Error = %d \n", GetLastError()); // // Indicate error. // return FALSE; } // // Mark the service for deletion from the service control manager database. // if (DeleteService(schService)) { // // Indicate success. // rCode = TRUE; } else { printf("DeleteService failed! Error = %d \n", GetLastError()); // // Indicate failure. Fall through to properly close the service handle. // rCode = FALSE; } // // Close the service object. // CloseServiceHandle(schService); // // POST-REMOVE of WDF support // err = pfnWdfPostDeviceRemove(infPath, WDF_SECTION_NAME ); if (err != ERROR_SUCCESS) { rCode = FALSE; } return rCode; } // RemoveDriver BOOLEAN StartDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) { SC_HANDLE schService; DWORD err; BOOL ok; // // Open the handle to the existing service. // schService = OpenService(SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { // // Indicate failure. // printf("OpenService failed! Error = %d\n", GetLastError()); return FALSE; } // // Start the execution of the service (i.e. start the driver). // ok = StartService( schService, 0, NULL ); if (!ok) { err = GetLastError(); if (err == ERROR_SERVICE_ALREADY_RUNNING) { // // Ignore this error. // return TRUE; } else { // // Indicate failure. // Fall through to properly close the service handle. // printf("StartService failure! Error = %d\n", err ); return FALSE; } } // // Close the service object. // CloseServiceHandle(schService); return TRUE; } // StartDriver BOOLEAN StopDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) { BOOLEAN rCode = TRUE; SC_HANDLE schService; SERVICE_STATUS serviceStatus; // // Open the handle to the existing service. // schService = OpenService(SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { printf("OpenService failed! Error = %d \n", GetLastError()); return FALSE; } // // Request that the service stop. // if (ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus )) { // // Indicate success. // rCode = TRUE; } else { printf("ControlService failed! Error = %d \n", GetLastError() ); // // Indicate failure. Fall through to properly close the service handle. // rCode = FALSE; } // // Close the service object. // CloseServiceHandle (schService); return rCode; } // StopDriver // // Caller must free returned pathname string. // PCHAR BuildDriversDirPath( _In_ PSTR DriverName ) { size_t remain; size_t len; PCHAR dir; if (!DriverName || strlen(DriverName) == 0) { return NULL; } remain = MAX_PATH; // // Allocate string space // dir = (PCHAR) malloc( remain + 1 ); if (!dir) { return NULL; } // // Get the base windows directory path. // len = GetWindowsDirectory( dir, (UINT) remain ); if (len == 0 || (remain - len) < sizeof(SYSTEM32_DRIVERS)) { free(dir); return NULL; } remain -= len; // // Build dir to have "%windir%\System32\Drivers\". // if (FAILED( StringCchCat(dir, remain, SYSTEM32_DRIVERS) )) { free(dir); return NULL; } remain -= sizeof(SYSTEM32_DRIVERS); len += sizeof(SYSTEM32_DRIVERS); len += strlen(DriverName); if (remain < len) { free(dir); return NULL; } if (FAILED( StringCchCat(dir, remain, DriverName) )) { free(dir); return NULL; } dir[len] = '\0'; // keeps prefast happy return dir; } BOOLEAN SetupDriverName( _Inout_updates_all_(BufferLength) PCHAR DriverLocation, _In_ ULONG BufferLength ) { HANDLE fileHandle; DWORD driverLocLen = 0; BOOL ok; PCHAR driversDir; // // Setup path name to driver file. // driverLocLen = GetCurrentDirectory(BufferLength, DriverLocation); if (!driverLocLen) { printf("GetCurrentDirectory failed! Error = %d \n", GetLastError()); return FALSE; } if (FAILED( StringCchCat(DriverLocation, BufferLength, "\\" DRIVER_NAME ".sys") )) { return FALSE; } // // Insure driver file is in the specified directory. // fileHandle = CreateFile( DriverLocation, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (fileHandle == INVALID_HANDLE_VALUE) { // // Indicate failure. // printf("Driver: %s.SYS is not in the %s directory. \n", DRIVER_NAME, DriverLocation ); return FALSE; } // // Build %windir%\System32\Drivers\ path. // Copy the driver to %windir%\system32\drivers // driversDir = BuildDriversDirPath( DRIVER_NAME ".sys" ); if (!driversDir) { printf("BuildDriversDirPath failed!\n"); return FALSE; } ok = CopyFile( DriverLocation, driversDir, FALSE ); if(!ok) { printf("CopyFile failed: error(%d) - \"%s\"\n", GetLastError(), driversDir ); free(driversDir); return FALSE; } if (FAILED( StringCchCopy(DriverLocation, BufferLength, driversDir) )) { free(driversDir); return FALSE; } free(driversDir); // // Close open file handle. // if (fileHandle) { CloseHandle(fileHandle); } // // Indicate success. // return TRUE; } // SetupDriverName HMODULE LoadWdfCoInstaller( VOID ) { HMODULE library = NULL; DWORD error = ERROR_SUCCESS; CHAR szCurDir[MAX_PATH]; CHAR tempCoinstallerName[MAX_PATH]; PCHAR coinstallerVersion; do { if (GetCurrentDirectory(MAX_PATH, szCurDir) == 0) { printf("GetCurrentDirectory failed! Error = %d \n", GetLastError()); break; } coinstallerVersion = GetCoinstallerVersion(); if (FAILED( StringCchPrintf(tempCoinstallerName, MAX_PATH, "\\WdfCoInstaller%s.dll", coinstallerVersion) )) { break; } if (FAILED( StringCchCat(szCurDir, MAX_PATH, tempCoinstallerName) )) { break; } library = LoadLibrary(szCurDir); if (library == NULL) { error = GetLastError(); printf("LoadLibrary(%s) failed: %d\n", szCurDir, error); break; } pfnWdfPreDeviceInstallEx = (PFN_WDFPREDEVICEINSTALLEX) GetProcAddress( library, "WdfPreDeviceInstallEx" ); if (pfnWdfPreDeviceInstallEx == NULL) { error = GetLastError(); printf("GetProcAddress(\"WdfPreDeviceInstallEx\") failed: %d\n", error); return NULL; } pfnWdfPostDeviceInstall = (PFN_WDFPOSTDEVICEINSTALL) GetProcAddress( library, "WdfPostDeviceInstall" ); if (pfnWdfPostDeviceInstall == NULL) { error = GetLastError(); printf("GetProcAddress(\"WdfPostDeviceInstall\") failed: %d\n", error); return NULL; } pfnWdfPreDeviceRemove = (PFN_WDFPREDEVICEREMOVE) GetProcAddress( library, "WdfPreDeviceRemove" ); if (pfnWdfPreDeviceRemove == NULL) { error = GetLastError(); printf("GetProcAddress(\"WdfPreDeviceRemove\") failed: %d\n", error); return NULL; } pfnWdfPostDeviceRemove = (PFN_WDFPREDEVICEREMOVE) GetProcAddress( library, "WdfPostDeviceRemove" ); if (pfnWdfPostDeviceRemove == NULL) { error = GetLastError(); printf("GetProcAddress(\"WdfPostDeviceRemove\") failed: %d\n", error); return NULL; } } WHILE (0); if (error != ERROR_SUCCESS) { if (library) { FreeLibrary( library ); } library = NULL; } return library; } VOID UnloadWdfCoInstaller( HMODULE Library ) { if (Library) { FreeLibrary( Library ); } } ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/exe/nonpnp.inf ================================================ [Version] Signature="$WINDOWS NT$" [nonpnp.NT.Wdf] KmdfService = nonpnp, nonpnp_Service_kmdfInst [nonpnp_Service_kmdfInst] KmdfLibraryVersion = 1.11 ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/exe/testapp.c ================================================ /*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: testapp.c Abstract: Purpose of this app to test the NONPNP sample driver. The app makes four different ioctl calls to test all the buffer types, write some random buffer content to a file created by the driver in \SystemRoot\Temp directory, and reads the same file and matches the content. If -l option is specified, it does the write and read operation in a loop until the app is terminated by pressing ^C. Make sure you have the \SystemRoot\Temp directory exists before you run the test. Environment: Win32 console application. --*/ #include _Analysis_mode_(_Analysis_code_type_user_code_) #include #pragma warning(disable:4201) // nameless struct/union #include #pragma warning(default:4201) #include #include #include #include #include #include "public.h" BOOLEAN ManageDriver( IN LPCTSTR DriverName, IN LPCTSTR ServiceName, IN USHORT Function ); HMODULE LoadWdfCoInstaller( VOID ); VOID UnloadWdfCoInstaller( HMODULE Library ); BOOLEAN SetupDriverName( _Inout_updates_all_(BufferLength) PCHAR DriverLocation, _In_ ULONG BufferLength ); BOOLEAN DoFileReadWrite( HANDLE HDevice ); VOID DoIoctls( HANDLE hDevice ); // for example, WDF 1.9 is "01009". the size 6 includes the ending NULL marker // #define MAX_VERSION_SIZE 6 CHAR G_coInstallerVersion[MAX_VERSION_SIZE] = {0}; BOOLEAN G_fLoop = FALSE; BOOL G_versionSpecified = FALSE; //----------------------------------------------------------------------------- // 4127 -- Conditional Expression is Constant warning //----------------------------------------------------------------------------- #define WHILE(constant) \ __pragma(warning(disable: 4127)) while(constant); __pragma(warning(default: 4127)) #define USAGE \ "Usage: nonpnpapp <-V version> <-l> \n" \ " -V version {if no version is specified the version specified in the build environment will be used.}\n" \ " The version is the version of the KMDF coinstaller to use \n" \ " The format of version is MMmmm where MM -- major #, mmm - serial# \n" \ " -l { option to continuously read & write to the file} \n" BOOL ValidateCoinstallerVersion( _In_ PSTR Version ) { BOOL ok = FALSE; INT i; for(i= 0; i 1 ) {// give usage if invoked with no parms error = Parse(argc, argv); if (error != ERROR_SUCCESS) { return; } } if (!G_versionSpecified ) { coinstallerVersion = GetCoinstallerVersion(); // // if no version is specified or an invalid one is specified use default version // printf("No version specified. Using default version:%s\n", coinstallerVersion); } else { coinstallerVersion = (PCHAR)&G_coInstallerVersion; } // // open the device // hDevice = CreateFile(DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hDevice == INVALID_HANDLE_VALUE) { errNum = GetLastError(); if (!(errNum == ERROR_FILE_NOT_FOUND || errNum == ERROR_PATH_NOT_FOUND)) { printf("CreateFile failed! ERROR_FILE_NOT_FOUND = %d\n", errNum); return ; } // // Load WdfCoInstaller.dll. // library = LoadWdfCoInstaller(); if (library == NULL) { printf("The WdfCoInstaller%s.dll library needs to be " "in same directory as nonpnpapp.exe\n", coinstallerVersion); return; } // // The driver is not started yet so let us the install the driver. // First setup full path to driver name. // ok = SetupDriverName( driverLocation, MAX_PATH ); if (!ok) { return ; } ok = ManageDriver( DRIVER_NAME, driverLocation, DRIVER_FUNC_INSTALL ); if (!ok) { printf("Unable to install driver. \n"); // // Error - remove driver. // ManageDriver( DRIVER_NAME, driverLocation, DRIVER_FUNC_REMOVE ); return; } hDevice = CreateFile( DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hDevice == INVALID_HANDLE_VALUE) { printf ( "Error: CreatFile Failed : %d\n", GetLastError()); return; } } DoIoctls(hDevice); do { if(!DoFileReadWrite(hDevice)) { break; } if(!G_fLoop) { break; } Sleep(1000); // sleep for 1 sec. } WHILE (TRUE); // // Close the handle to the device before unloading the driver. // CloseHandle ( hDevice ); // // Unload the driver. Ignore any errors. // ManageDriver( DRIVER_NAME, driverLocation, DRIVER_FUNC_REMOVE ); // // Unload WdfCoInstaller.dll // if ( library ) { UnloadWdfCoInstaller( library ); } return; } VOID DoIoctls( HANDLE hDevice ) { char OutputBuffer[100]; char InputBuffer[200]; BOOL bRc; ULONG bytesReturned; // // Printing Input & Output buffer pointers and size // printf("InputBuffer Pointer = %p, BufLength = %Id\n", InputBuffer, sizeof(InputBuffer)); printf("OutputBuffer Pointer = %p BufLength = %Id\n", OutputBuffer, sizeof(OutputBuffer)); // // Performing METHOD_BUFFERED // if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer), "this String is from User Application; using METHOD_BUFFERED"))){ return; } printf("\nCalling DeviceIoControl METHOD_BUFFERED:\n"); memset(OutputBuffer, 0, sizeof(OutputBuffer)); bRc = DeviceIoControl ( hDevice, (DWORD) IOCTL_NONPNP_METHOD_BUFFERED, InputBuffer, (DWORD) strlen( InputBuffer )+1, OutputBuffer, sizeof( OutputBuffer), &bytesReturned, NULL ); if ( !bRc ) { printf ( "Error in DeviceIoControl : %d", GetLastError()); return; } printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer); // // Performing METHOD_NIETHER // printf("\nCalling DeviceIoControl METHOD_NEITHER\n"); if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer), "this String is from User Application; using METHOD_NEITHER"))) { return; } memset(OutputBuffer, 0, sizeof(OutputBuffer)); bRc = DeviceIoControl ( hDevice, (DWORD) IOCTL_NONPNP_METHOD_NEITHER, InputBuffer, (DWORD) strlen( InputBuffer )+1, OutputBuffer, sizeof( OutputBuffer), &bytesReturned, NULL ); if ( !bRc ) { printf ( "Error in DeviceIoControl : %d\n", GetLastError()); return; } printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer); // // Performing METHOD_IN_DIRECT // printf("\nCalling DeviceIoControl METHOD_IN_DIRECT\n"); if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer), "this String is from User Application; using METHOD_IN_DIRECT"))) { return; } if(FAILED(StringCchCopy(OutputBuffer, sizeof(OutputBuffer), "This String is from User Application in OutBuffer; using METHOD_IN_DIRECT"))) { return; } bRc = DeviceIoControl ( hDevice, (DWORD) IOCTL_NONPNP_METHOD_IN_DIRECT, InputBuffer, (DWORD) strlen( InputBuffer )+1, OutputBuffer, sizeof( OutputBuffer), &bytesReturned, NULL ); if ( !bRc ) { printf ( "Error in DeviceIoControl : : %d", GetLastError()); return; } printf(" Number of bytes transfered from OutBuffer: %d\n", bytesReturned); // // Performing METHOD_OUT_DIRECT // printf("\nCalling DeviceIoControl METHOD_OUT_DIRECT\n"); if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer), "this String is from User Application; using METHOD_OUT_DIRECT"))){ return; } memset(OutputBuffer, 0, sizeof(OutputBuffer)); bRc = DeviceIoControl ( hDevice, (DWORD) IOCTL_NONPNP_METHOD_OUT_DIRECT, InputBuffer, (DWORD) strlen( InputBuffer )+1, OutputBuffer, sizeof( OutputBuffer), &bytesReturned, NULL ); if ( !bRc ) { printf ( "Error in DeviceIoControl : : %d", GetLastError()); return; } printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer); return; } BOOLEAN DoFileReadWrite( HANDLE HDevice ) { ULONG bufLength, index; PUCHAR readBuf = NULL; PUCHAR writeBuf = NULL; BOOLEAN ret; ULONG bytesWritten, bytesRead; // // Seed the random-number generator with current time so that // the numbers will be different every time we run. // srand( (unsigned)time( NULL ) ); // // rand function returns a pseudorandom integer in the range 0 to RAND_MAX // (0x7fff) // bufLength = rand(); // // Try until the bufLength is not zero. // while(bufLength == 0) { bufLength = rand(); } // // Allocate a buffer of that size to use for write operation. // writeBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufLength); if(!writeBuf) { ret = FALSE; goto End; } // // Fill the buffer with randon number less than UCHAR_MAX. // index = bufLength; while(index){ writeBuf[index-1] = (UCHAR) rand() % UCHAR_MAX; index--; } printf("Write %d bytes to file\n", bufLength); // // Tell the driver to write the buffer content to the file from the // begining of the file. // if (!WriteFile(HDevice, writeBuf, bufLength, &bytesWritten, NULL)) { printf("ReadFile failed with error 0x%x\n", GetLastError()); ret = FALSE; goto End; } // // Allocate another buffer of same size. // readBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufLength); if(!readBuf) { ret = FALSE; goto End; } printf("Read %d bytes from the same file\n", bufLength); // // Tell the driver to read the file from the begining. // if (!ReadFile(HDevice, readBuf, bufLength, &bytesRead, NULL)) { printf("Error: ReadFile failed with error 0x%x\n", GetLastError()); ret = FALSE; goto End; } // // Now compare the readBuf and writeBuf content. They should be the same. // if(bytesRead != bytesWritten) { printf("bytesRead(%d) != bytesWritten(%d)\n", bytesRead, bytesWritten); ret = FALSE; goto End; } if(memcmp(readBuf, writeBuf, bufLength) != 0){ printf("Error: ReadBuf and WriteBuf contents are not the same\n"); ret = FALSE; goto End; } ret = TRUE; End: if(readBuf){ HeapFree (GetProcessHeap(), 0, readBuf); } if(writeBuf){ HeapFree (GetProcessHeap(), 0, writeBuf); } return ret; } ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/localwpp.ini ================================================ // // This defines how to log a len/buffer pair. // This function should be in trace.h // DEFINE_CPLX_TYPE(HEXDUMP, WPP_LOGHEXDUMP, xstr_t, ItemHEXDump,"s", _HEX_, 0,2); // DEFINE_CPLX_TYPE( // name, // i.e. HEXDUMP // %!HEXDUMP! // macro, // i.e. WPP_LOGHEXDUMP // Marshalling macro, defined in trace.h // structure, // i.e. xstr_t // Argument type (structure to be created by above macro) // item type, // i.e. ItemHEXDump // MOF type that TracePrt can understand // format specifier, // i.e. "s" // a format specifier that TracePrt can understand // ???? // i.e. _HEX_ // Type signature (becomes a part of function name) // ???? // i.e. 0 // Weight (0 is variable data length) // ???? // i.e. 2 // Slots used by this entry (optional, 1 default) // ) ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/public.h ================================================ /*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: PUBLIC.H Abstract: Defines the IOCTL codes that will be used by this driver. The IOCTL code contains a command identifier, plus other information about the device, the type of access with which the file must have been opened, and the type of buffering. Environment: Kernel mode only. --*/ // // Device type -- in the "User Defined" range." // #define FILEIO_TYPE 40001 // // The IOCTL function codes from 0x800 to 0xFFF are for customer use. // #define IOCTL_NONPNP_METHOD_IN_DIRECT \ CTL_CODE( FILEIO_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS ) #define IOCTL_NONPNP_METHOD_OUT_DIRECT \ CTL_CODE( FILEIO_TYPE, 0x901, METHOD_OUT_DIRECT , FILE_ANY_ACCESS ) #define IOCTL_NONPNP_METHOD_BUFFERED \ CTL_CODE( FILEIO_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS ) #define IOCTL_NONPNP_METHOD_NEITHER \ CTL_CODE( FILEIO_TYPE, 0x903, METHOD_NEITHER , FILE_ANY_ACCESS ) #define DRIVER_FUNC_INSTALL 0x01 #define DRIVER_FUNC_REMOVE 0x02 #define DRIVER_NAME "NONPNP" #define DEVICE_NAME "\\\\.\\NONPNP\\nonpnpsamp.log" ================================================ FILE: tests/projects/windows/driver/kmdf/ioctl/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_includedirs(".") target("nonpnp") add_rules("wdk.env.kmdf", "wdk.driver") add_values("wdk.tracewpp.flags", "-func:TraceEvents(LEVEL,FLAGS,MSG,...)", "-func:Hexdump((LEVEL,FLAGS,MSG,...))") add_files("driver/*.c", {rules = "wdk.tracewpp"}) add_files("driver/*.rc") target("app") add_rules("wdk.env.kmdf", "wdk.binary") add_files("exe/*.c") add_files("exe/*.inf") ================================================ FILE: tests/projects/windows/driver/kmdf/serial/error.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: error.c Abstract: This module contains the code that is very specific to error operations in the serial driver Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "error.tmh" #endif VOID SerialCommError( IN WDFDPC Dpc ) /*++ Routine Description: This routine is invoked at dpc level to in response to a comm error. All comm errors complete all read and writes Arguments: Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION Extension = NULL; Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc)); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, ">SerialCommError(%p)\n", Extension); SerialFlushRequests( Extension->WriteQueue, &Extension->CurrentWriteRequest ); SerialFlushRequests( Extension->ReadQueue, &Extension->CurrentReadRequest ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, "SerialFlush(%p, %p)\n", Device, Irp); PAGED_CODE(); WdfIoQueueStopSynchronously(extension->WriteQueue); // // Flush is done - restart the queue // WdfIoQueueStart(extension->WriteQueue); Irp->IoStatus.Information = 0L; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "CurrentImmediateRequest); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, ">SerialStartImmediate(%p)\n", Extension); UseATimer = FALSE; reqContext->Status = STATUS_PENDING; // // Calculate the timeout value needed for the // request. Note that the values stored in the // timeout record are in milliseconds. Note that // if the timeout values are zero then we won't start // the timer. // Timeouts = Extension->Timeouts; if (Timeouts.WriteTotalTimeoutConstant || Timeouts.WriteTotalTimeoutMultiplier) { UseATimer = TRUE; // // We have some timer values to calculate. // TotalTime.QuadPart = (LONGLONG)((ULONG)Timeouts.WriteTotalTimeoutMultiplier); TotalTime.QuadPart += Timeouts.WriteTotalTimeoutConstant; TotalTime.QuadPart *= -10000; } // // As the request might be going to the isr, this is a good time // to initialize the reference count. // SERIAL_INIT_REFERENCE(reqContext); // // We give the request to to the isr to write out. // We set a cancel routine that knows how to // grab the current write away from the isr. // SerialSetCancelRoutine(Extension->CurrentImmediateRequest, SerialCancelImmediate); if (UseATimer) { BOOLEAN result; result = SerialSetTimer( Extension->ImmediateTotalTimer, TotalTime ); if(result == FALSE) { // // Since the timer knows about the request we increment // the reference count. // SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_TOTAL_TIMER ); } } WdfInterruptSynchronize( Extension->WdfInterrupt, SerialGiveImmediateToIsr, Extension ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "SerialCompleteImmediate(%p)\n", Extension); SerialTryToCompleteCurrent( Extension, NULL, STATUS_SUCCESS, &Extension->CurrentImmediateRequest, NULL, NULL, Extension->ImmediateTotalTimer, NULL, SerialGetNextImmediate, SERIAL_REF_ISR ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "SerialTimeoutImmediate(%p)\n", Extension); SerialTryToCompleteCurrent( Extension, SerialGrabImmediateFromIsr, STATUS_TIMEOUT, &Extension->CurrentImmediateRequest, NULL, NULL, Extension->ImmediateTotalTimer, NULL, SerialGetNextImmediate, SERIAL_REF_TOTAL_TIMER ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "TotalCharsQueued >= 1); Extension->TotalCharsQueued--; *CurrentOpRequest = NULL; *NewRequest = NULL; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialProcessEmptyTransmit, Extension ); SerialCompleteRequest(oldRequest, reqContext->Status, reqContext->Information); } VOID SerialCancelImmediate( IN WDFREQUEST Request ) /*++ Routine Description: This routine is used to cancel a request that is waiting on a comm event. Arguments: Request - Pointer to the WDFREQUEST for the current request Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION Extension = NULL; WDFDEVICE device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)); UNREFERENCED_PARAMETER(Request); Extension = SerialGetDeviceExtension(device); SerialTryToCompleteCurrent( Extension, SerialGrabImmediateFromIsr, STATUS_CANCELLED, &Extension->CurrentImmediateRequest, NULL, NULL, Extension->ImmediateTotalTimer, NULL, SerialGetNextImmediate, SERIAL_REF_CANCEL ); } BOOLEAN SerialGiveImmediateToIsr( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: Try to start off the write by slipping it in behind a transmit immediate char, or if that isn't available and the transmit holding register is empty, "tickle" the UART into interrupting with a transmit buffer empty. NOTE: This routine is called by WdfInterruptSynchronize. NOTE: This routine assumes that it is called with the cancel spin lock held. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(Extension->CurrentImmediateRequest); Extension->TransmitImmediate = TRUE; Extension->ImmediateChar = *((UCHAR *) (reqContext->SystemBuffer)); // // The isr now has a reference to the request. // SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_ISR ); // // Check first to see if a write is going on. If // there is then we'll just slip in during the write. // if (!Extension->WriteLength) { // // If there is no normal write transmitting then we // will "re-enable" the transmit holding register empty // interrupt. The 8250 family of devices will always // signal a transmit holding register empty interrupt // *ANY* time this bit is set to one. By doing things // this way we can simply use the normal interrupt code // to start off this write. // // We've been keeping track of whether the transmit holding // register is empty so it we only need to do this // if the register is empty. // if (Extension->HoldingEmpty) { DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller); ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller); } } return FALSE; } BOOLEAN SerialGrabImmediateFromIsr( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to grab the current request, which could be timing out or canceling, from the ISR NOTE: This routine is being called from WdfInterruptSynchronize. NOTE: This routine assumes that the cancel spin lock is held when this routine is called. Arguments: Context - Really a pointer to the device extension. Return Value: Always false. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(Extension->CurrentImmediateRequest); if (Extension->TransmitImmediate) { Extension->TransmitImmediate = FALSE; // // Since the isr no longer references this request, we can // decrement it's reference count. // SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_ISR ); } return FALSE; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/initunlo.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: initunlo.c Abstract: This module contains the code that is very specific to initialization and unload operations in the serial driver WDF Version of serial sample doesn't support: 1) Multiport Serial devices. 2) Enumeration of Non PNP serial devices that are not detected by BIOS (IO address range 0x2F0-0x2F7 using IRQ 9) Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "initunlo.tmh" #endif static const PHYSICAL_ADDRESS SerialPhysicalZero = {0}; // // We use this to query into the registry as to whether we // should break at driver entry. // SERIAL_FIRMWARE_DATA driverDefaults; // // This is exported from the kernel. It is used to point // to the address that the kernel debugger is using. // extern PUCHAR *KdComPortInUse; // // INIT - only needed during init and then can be disposed // PAGESRP0 - always paged / never locked // PAGESER - must be locked when a device is open, else paged // // // INIT is used for DriverEntry() specific code // // PAGESRP0 is used for code that is not often called and has nothing // to do with I/O performance. An example, passive-level PNP // support functions // // PAGESER is used for code that needs to be locked after an open for both // performance and IRQL reasons. // ULONG DebugLevel = TRACE_LEVEL_INFORMATION; ULONG DebugFlag = 0xf;//0x46;//0x4FF; //0x00000006; #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(PAGE, SerialEvtDriverContextCleanup) #endif NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: The entry point that the system point calls to initialize any driver. Arguments: DriverObject - Just what it says, really of little use to the driver itself, it is something that the IO system cares more about. PathToRegistry - points to the entry for this driver in the current control set of the registry. Return Value: Always STATUS_SUCCESS --*/ { WDF_DRIVER_CONFIG config; WDFDRIVER hDriver; NTSTATUS status; WDF_OBJECT_ATTRIBUTES attributes; // // Initialize WPP Tracing // WPP_INIT_TRACING( DriverObject, RegistryPath ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, "Serial Sample (WDF Version)\n"); // // Register a cleanup callback so that we can call WPP_CLEANUP when // the framework driver object is deleted during driver unload. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.EvtCleanupCallback = SerialEvtDriverContextCleanup; WDF_DRIVER_CONFIG_INIT(&config, SerialEvtDeviceAdd); status = WdfDriverCreate(DriverObject, RegistryPath, &attributes, &config, &hDriver); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDriverCreate failed with status 0x%x\n", status); // // Cleanup tracing here because DriverContextCleanup will not be called // as we have failed to create WDFDRIVER object itself. // Please note that if your return failure from DriverEntry after the // WDFDRIVER object is created successfully, you don't have to // call WPP cleanup because in those cases DriverContextCleanup // will be executed when the framework deletes the DriverObject. // WPP_CLEANUP(DriverObject); return status; } // // Call to find out default values to use for all the devices that the // driver controls, including whether or not to break on entry. // SerialGetConfigDefaults(&driverDefaults, hDriver); // // Break on entry if requested via registry // if (driverDefaults.ShouldBreakOnEntry) { DbgBreakPoint(); } return status; } _Use_decl_annotations_ VOID SerialEvtDriverContextCleanup( WDFOBJECT Driver ) /*++ Routine Description: Free all the resources allocated in DriverEntry. Arguments: Driver - handle to a WDF Driver object. Return Value: VOID. --*/ { UNREFERENCED_PARAMETER(Driver); PAGED_CODE (); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> SerialEvtDriverContextCleanup\n"); // // Stop WPP Tracing // WPP_CLEANUP( WdfDriverWdmGetDriverObject(Driver) ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- SerialEvtDriverContextCleanup\n"); } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/ioctl.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: ioctl.c Abstract: This module contains the ioctl dispatcher as well as a couple of routines that are generally just called in response to ioctl calls. Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "ioctl.tmh" #endif EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGetModemUpdate; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGetCommStatus; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetEscapeChar; PCHAR SerialGetIoctlName( IN ULONG IoControlCode ) /*++ Routine Description: SerialGetIoctlName returns the name of the ioctl --*/ { switch (IoControlCode) { case IOCTL_SERIAL_SET_BAUD_RATE : return "IOCTL_SERIAL_SET_BAUD_RATE"; case IOCTL_SERIAL_GET_BAUD_RATE: return "IOCTL_SERIAL_GET_BAUD_RATE"; case IOCTL_SERIAL_GET_MODEM_CONTROL: return "IOCTL_SERIAL_GET_MODEM_CONTROL"; case IOCTL_SERIAL_SET_MODEM_CONTROL: return "IOCTL_SERIAL_SET_MODEM_CONTROL"; case IOCTL_SERIAL_SET_FIFO_CONTROL: return "IOCTL_SERIAL_SET_FIFO_CONTROL"; case IOCTL_SERIAL_SET_LINE_CONTROL: return "IOCTL_SERIAL_SET_LINE_CONTROL"; case IOCTL_SERIAL_GET_LINE_CONTROL: return "IOCTL_SERIAL_GET_LINE_CONTROL"; case IOCTL_SERIAL_SET_TIMEOUTS: return "IOCTL_SERIAL_SET_TIMEOUTS"; case IOCTL_SERIAL_GET_TIMEOUTS: return "IOCTL_SERIAL_GET_TIMEOUTS"; case IOCTL_SERIAL_SET_CHARS: return "IOCTL_SERIAL_SET_CHARS"; case IOCTL_SERIAL_GET_CHARS: return "IOCTL_SERIAL_GET_CHARS"; case IOCTL_SERIAL_SET_DTR: return "IOCTL_SERIAL_SET_DTR"; case IOCTL_SERIAL_CLR_DTR: return "IOCTL_SERIAL_SET_DTR"; case IOCTL_SERIAL_RESET_DEVICE: return "IOCTL_SERIAL_RESET_DEVICE"; case IOCTL_SERIAL_SET_RTS: return "IOCTL_SERIAL_SET_RTS"; case IOCTL_SERIAL_CLR_RTS: return "IOCTL_SERIAL_CLR_RTS"; case IOCTL_SERIAL_SET_XOFF: return "IOCTL_SERIAL_SET_XOFF"; case IOCTL_SERIAL_SET_XON: return "IOCTL_SERIAL_SET_XON"; case IOCTL_SERIAL_SET_BREAK_ON: return "IOCTL_SERIAL_SET_BREAK_ON"; case IOCTL_SERIAL_SET_BREAK_OFF: return "IOCTL_SERIAL_SET_BREAK_OFF"; case IOCTL_SERIAL_SET_QUEUE_SIZE: return "IOCTL_SERIAL_SET_QUEUE_SIZE"; case IOCTL_SERIAL_GET_WAIT_MASK: return "IOCTL_SERIAL_GET_WAIT_MASK"; case IOCTL_SERIAL_SET_WAIT_MASK: return "IOCTL_SERIAL_SET_WAIT_MASK"; case IOCTL_SERIAL_WAIT_ON_MASK: return "IOCTL_SERIAL_WAIT_ON_MASK"; case IOCTL_SERIAL_IMMEDIATE_CHAR: return "IOCTL_SERIAL_IMMEDIATE_CHAR"; case IOCTL_SERIAL_PURGE: return "IOCTL_SERIAL_PURGE"; case IOCTL_SERIAL_GET_HANDFLOW: return "IOCTL_SERIAL_GET_HANDFLOW"; case IOCTL_SERIAL_SET_HANDFLOW: return "IOCTL_SERIAL_SET_HANDFLOW"; case IOCTL_SERIAL_GET_MODEMSTATUS: return "IOCTL_SERIAL_GET_MODEMSTATUS"; case IOCTL_SERIAL_GET_DTRRTS: return "IOCTL_SERIAL_GET_DTRRTS"; case IOCTL_SERIAL_GET_COMMSTATUS: return "IOCTL_SERIAL_GET_COMMSTATUS"; case IOCTL_SERIAL_GET_PROPERTIES: return "IOCTL_SERIAL_GET_PROPERTIES"; case IOCTL_SERIAL_XOFF_COUNTER: return "IOCTL_SERIAL_XOFF_COUNTER"; case IOCTL_SERIAL_LSRMST_INSERT: return "IOCTL_SERIAL_LSRMST_INSERT"; case IOCTL_SERIAL_CONFIG_SIZE: return "IOCTL_SERIAL_CONFIG_SIZE"; case IOCTL_SERIAL_GET_STATS: return "IOCTL_SERIAL_GET_STATS"; case IOCTL_SERIAL_CLEAR_STATS: return "IOCTL_SERIAL_CLEAR_STATS"; default: return "UnKnown ioctl"; } } BOOLEAN SerialGetStats( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: In sync with the interrpt service routine (which sets the perf stats) return the perf stats to the caller. Arguments: Context - Pointer to a the request. Return Value: This routine always returns FALSE. --*/ { PREQUEST_CONTEXT reqContext = (PREQUEST_CONTEXT)Context; PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(WdfInterruptGetDevice(Interrupt)); PSERIALPERF_STATS sp = reqContext->SystemBuffer; UNREFERENCED_PARAMETER(Interrupt); *sp = extension->PerfStats; return FALSE; } BOOLEAN SerialClearStats( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: In sync with the interrpt service routine (which sets the perf stats) clear the perf stats. Arguments: Context - Pointer to a the extension. Return Value: This routine always returns FALSE. --*/ { UNREFERENCED_PARAMETER(Interrupt); RtlZeroMemory( &((PSERIAL_DEVICE_EXTENSION)Context)->PerfStats, sizeof(SERIALPERF_STATS) ); RtlZeroMemory(&((PSERIAL_DEVICE_EXTENSION)Context)->WmiPerfData, sizeof(SERIAL_WMI_PERF_DATA)); return FALSE; } BOOLEAN SerialSetChars( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to set the special characters for the driver. Arguments: Context - Pointer to a structure that contains a pointer to the device extension and a pointer to a special characters structure. Return Value: This routine always returns FALSE. --*/ { UNREFERENCED_PARAMETER(Interrupt); ((PSERIAL_IOCTL_SYNC)Context)->Extension->SpecialChars = *((PSERIAL_CHARS)(((PSERIAL_IOCTL_SYNC)Context)->Data)); return FALSE; } BOOLEAN SerialSetBaud( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to set the baud rate of the device. Arguments: Context - Pointer to a structure that contains a pointer to the device extension and what should be the current baud rate. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension; USHORT Appropriate = PtrToUshort(((PSERIAL_IOCTL_SYNC)Context)->Data); UNREFERENCED_PARAMETER(Interrupt); WRITE_DIVISOR_LATCH( Extension, Extension->Controller, Appropriate ); return FALSE; } BOOLEAN SerialSetLineControl( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to set the buad rate of the device. Arguments: Context - Pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UNREFERENCED_PARAMETER(Interrupt); WRITE_LINE_CONTROL(Extension, Extension->Controller, Extension->LineControl ); return FALSE; } BOOLEAN SerialGetModemUpdate( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is simply used to call the interrupt level routine that handles modem status update. Arguments: Context - Pointer to a structure that contains a pointer to the device extension and a pointer to a ulong. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension; ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data); UNREFERENCED_PARAMETER(Interrupt); *Result = SerialHandleModemUpdate( Extension, FALSE ); return FALSE; } BOOLEAN SerialSetMCRContents( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is simply used to set the contents of the MCR Arguments: Context - Pointer to a structure that contains a pointer to the device extension and a pointer to a ulong. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension; ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data); UNREFERENCED_PARAMETER(Interrupt); // // This is severe casting abuse!!! // WRITE_MODEM_CONTROL(Extension, Extension->Controller, (UCHAR)PtrToUlong(Result)); return FALSE; } BOOLEAN SerialGetMCRContents( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is simply used to get the contents of the MCR Arguments: Context - Pointer to a structure that contains a pointer to the device extension and a pointer to a ulong. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension; ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data); UNREFERENCED_PARAMETER(Interrupt); *Result = READ_MODEM_CONTROL(Extension, Extension->Controller); return FALSE; } BOOLEAN SerialSetFCRContents( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is simply used to set the contents of the FCR Arguments: Context - Pointer to a structure that contains a pointer to the device extension and a pointer to a ulong. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension; ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data); UNREFERENCED_PARAMETER(Interrupt); // // This is severe casting abuse!!! // WRITE_FIFO_CONTROL(Extension, Extension->Controller, (UCHAR)*Result); return FALSE; } BOOLEAN SerialGetCommStatus( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This is used to get the current state of the serial driver. Arguments: Context - Pointer to a structure that contains a pointer to the device extension and a pointer to a serial status record. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension; PSERIAL_STATUS Stat = ((PSERIAL_IOCTL_SYNC)Context)->Data; UNREFERENCED_PARAMETER(Interrupt); Stat->Errors = Extension->ErrorWord; Extension->ErrorWord = 0; // // Eof isn't supported in binary mode // Stat->EofReceived = FALSE; Stat->AmountInInQueue = Extension->CharsInInterruptBuffer; Stat->AmountInOutQueue = Extension->TotalCharsQueued; if (Extension->WriteLength) { // // By definition if we have a writelength the we have // a current write request. // PREQUEST_CONTEXT reqContext = NULL; ASSERT(Extension->CurrentWriteRequest); ASSERT(Stat->AmountInOutQueue >= Extension->WriteLength); reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest); Stat->AmountInOutQueue -= reqContext->Length - (Extension->WriteLength); } Stat->WaitForImmediate = Extension->TransmitImmediate; Stat->HoldReasons = 0; if (Extension->TXHolding) { if (Extension->TXHolding & SERIAL_TX_CTS) { Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS; } if (Extension->TXHolding & SERIAL_TX_DSR) { Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DSR; } if (Extension->TXHolding & SERIAL_TX_DCD) { Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DCD; } if (Extension->TXHolding & SERIAL_TX_XOFF) { Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_XON; } if (Extension->TXHolding & SERIAL_TX_BREAK) { Stat->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK; } } if (Extension->RXHolding & SERIAL_RX_DSR) { Stat->HoldReasons |= SERIAL_RX_WAITING_FOR_DSR; } if (Extension->RXHolding & SERIAL_RX_XOFF) { Stat->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT; } return FALSE; } BOOLEAN SerialSetEscapeChar( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This is used to set the character that will be used to escape line status and modem status information when the application has set up that line status and modem status should be passed back in the data stream. Arguments: Context - Pointer to the request that is specify the escape character. Implicitly - An escape character of 0 means no escaping will occur. Return Value: This routine always returns FALSE. --*/ { PREQUEST_CONTEXT reqContext = (PREQUEST_CONTEXT)Context; PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(WdfInterruptGetDevice(Interrupt)); UNREFERENCED_PARAMETER(Interrupt); extension->EscapeChar = *(PUCHAR)reqContext->SystemBuffer; return FALSE; } VOID SerialEvtIoDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This routine provides the initial processing for all of the Ioctrls for the serial device. Arguments: Request - Pointer to the WDFREQUEST for the current request Return Value: The function value is the final status of the call --*/ { // // The status that gets returned to the caller and // set in the Request. // NTSTATUS Status; // // Just what it says. This is the serial specific device // extension of the device object create for the serial driver. // PSERIAL_DEVICE_EXTENSION Extension = NULL; PVOID buffer; PREQUEST_CONTEXT reqContext; size_t bufSize; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); reqContext = SerialGetRequestContext(Request); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "%s for: %p\n", SerialGetIoctlName(IoControlCode), Request); Extension = SerialGetDeviceExtension(WdfIoQueueGetDevice(Queue)); // // We expect to be open so all our pages are locked down. This is, after // all, an IO operation, so the device should be open first. // if (Extension->DeviceIsOpened != TRUE) { SerialCompleteRequest(Request, STATUS_INVALID_DEVICE_REQUEST, 0); return; } if (SerialCompleteIfError(Extension, Request) != STATUS_SUCCESS) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Information = 0; reqContext->Status = STATUS_SUCCESS; reqContext->MajorFunction = IRP_MJ_DEVICE_CONTROL; Status = STATUS_SUCCESS; switch (IoControlCode) { case IOCTL_SERIAL_SET_BAUD_RATE : { ULONG BaudRate; // // Will hold the value of the appropriate divisor for // the requested baud rate. If the baudrate is invalid // (because the device won't support that baud rate) then // this value is undefined. // // Note: in one sense the concept of a valid baud rate // is cloudy. We could allow the user to request any // baud rate. We could then calculate the divisor needed // for that baud rate. As long as the divisor wasn't less // than one we would be "ok". (The percentage difference // between the "true" divisor and the "rounded" value given // to the hardware might make it unusable, but... ) It would // really be up to the user to "Know" whether the baud rate // is suitable. So much for theory, *We* only support a given // set of baud rates. // SHORT AppropriateDivisor; Status = WdfRequestRetrieveInputBuffer (Request, sizeof(SERIAL_BAUD_RATE), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } BaudRate = ((PSERIAL_BAUD_RATE)(buffer))->BaudRate; // // Get the baud rate from the request. We pass it // to a routine which will set the correct divisor. // Status = SerialGetDivisorFromBaud( Extension->ClockRate, BaudRate, &AppropriateDivisor ); if (NT_SUCCESS(Status)) { SERIAL_IOCTL_SYNC S; Extension->CurrentBaud = BaudRate; Extension->WmiCommData.BaudRate = BaudRate; S.Extension = Extension; S.Data = (PVOID) (ULONG_PTR) AppropriateDivisor; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialSetBaud, &S ); } break; } case IOCTL_SERIAL_GET_BAUD_RATE: { PSERIAL_BAUD_RATE Br; Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_BAUD_RATE), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } Br = (PSERIAL_BAUD_RATE)buffer; Br->BaudRate = Extension->CurrentBaud; reqContext->Information = sizeof(SERIAL_BAUD_RATE); break; } case IOCTL_SERIAL_GET_MODEM_CONTROL: { SERIAL_IOCTL_SYNC S; Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->Information = sizeof(ULONG); S.Extension = Extension; S.Data = buffer; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialGetMCRContents, &S ); break; } case IOCTL_SERIAL_SET_MODEM_CONTROL: { SERIAL_IOCTL_SYNC S; Status = WdfRequestRetrieveInputBuffer (Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } S.Extension = Extension; S.Data = buffer; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialSetMCRContents, &S ); break; } case IOCTL_SERIAL_SET_FIFO_CONTROL: { SERIAL_IOCTL_SYNC S; Status = WdfRequestRetrieveInputBuffer (Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } S.Extension = Extension; S.Data = buffer; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialSetFCRContents, &S ); break; } case IOCTL_SERIAL_SET_LINE_CONTROL: { PSERIAL_LINE_CONTROL Lc; UCHAR LData; UCHAR LStop; UCHAR LParity; UCHAR Mask = 0xff; Status = WdfRequestRetrieveInputBuffer (Request, sizeof(SERIAL_LINE_CONTROL), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } // // Points to the line control record in the Request. // Lc = (PSERIAL_LINE_CONTROL)buffer; switch (Lc->WordLength) { case 5: { LData = SERIAL_5_DATA; Mask = 0x1f; break; } case 6: { LData = SERIAL_6_DATA; Mask = 0x3f; break; } case 7: { LData = SERIAL_7_DATA; Mask = 0x7f; break; } case 8: { LData = SERIAL_8_DATA; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } } Extension->WmiCommData.BitsPerByte = Lc->WordLength; switch (Lc->Parity) { case NO_PARITY: { Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; LParity = SERIAL_NONE_PARITY; break; } case EVEN_PARITY: { Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN; LParity = SERIAL_EVEN_PARITY; break; } case ODD_PARITY: { Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD; LParity = SERIAL_ODD_PARITY; break; } case SPACE_PARITY: { Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE; LParity = SERIAL_SPACE_PARITY; break; } case MARK_PARITY: { Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK; LParity = SERIAL_MARK_PARITY; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; break; } } switch (Lc->StopBits) { case STOP_BIT_1: { Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1; LStop = SERIAL_1_STOP; break; } case STOP_BITS_1_5: { if (LData != SERIAL_5_DATA) { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5; LStop = SERIAL_1_5_STOP; break; } case STOP_BITS_2: { if (LData == SERIAL_5_DATA) { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_2; LStop = SERIAL_2_STOP; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } } Extension->LineControl = (UCHAR)((Extension->LineControl & SERIAL_LCR_BREAK) | (LData | LParity | LStop)); Extension->ValidDataMask = Mask; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialSetLineControl, Extension ); break; } case IOCTL_SERIAL_GET_LINE_CONTROL: { PSERIAL_LINE_CONTROL Lc; Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_LINE_CONTROL), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } Lc = (PSERIAL_LINE_CONTROL)buffer; RtlZeroMemory(buffer, OutputBufferLength); if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) { Lc->WordLength = 5; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_6_DATA) { Lc->WordLength = 6; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_7_DATA) { Lc->WordLength = 7; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_8_DATA) { Lc->WordLength = 8; } if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_NONE_PARITY) { Lc->Parity = NO_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_ODD_PARITY) { Lc->Parity = ODD_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_EVEN_PARITY) { Lc->Parity = EVEN_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_MARK_PARITY) { Lc->Parity = MARK_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_SPACE_PARITY) { Lc->Parity = SPACE_PARITY; } if (Extension->LineControl & SERIAL_2_STOP) { if (Lc->WordLength == 5) { Lc->StopBits = STOP_BITS_1_5; } else { Lc->StopBits = STOP_BITS_2; } } else { Lc->StopBits = STOP_BIT_1; } reqContext->Information = sizeof(SERIAL_LINE_CONTROL); break; } case IOCTL_SERIAL_SET_TIMEOUTS: { PSERIAL_TIMEOUTS NewTimeouts; Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_TIMEOUTS), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } NewTimeouts =(PSERIAL_TIMEOUTS)buffer; if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) && (NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) && (NewTimeouts->ReadTotalTimeoutConstant == MAXULONG)) { Status = STATUS_INVALID_PARAMETER; break; } Extension->Timeouts.ReadIntervalTimeout = NewTimeouts->ReadIntervalTimeout; Extension->Timeouts.ReadTotalTimeoutMultiplier = NewTimeouts->ReadTotalTimeoutMultiplier; Extension->Timeouts.ReadTotalTimeoutConstant = NewTimeouts->ReadTotalTimeoutConstant; Extension->Timeouts.WriteTotalTimeoutMultiplier = NewTimeouts->WriteTotalTimeoutMultiplier; Extension->Timeouts.WriteTotalTimeoutConstant = NewTimeouts->WriteTotalTimeoutConstant; break; } case IOCTL_SERIAL_GET_TIMEOUTS: { Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_TIMEOUTS), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } *((PSERIAL_TIMEOUTS)buffer) = Extension->Timeouts; reqContext->Information = sizeof(SERIAL_TIMEOUTS); break; } case IOCTL_SERIAL_SET_CHARS: { SERIAL_IOCTL_SYNC S; PSERIAL_CHARS NewChars; Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_CHARS), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } NewChars = (PSERIAL_CHARS)buffer; // // The only thing that can be wrong with the chars // is that the xon and xoff characters are the // same. // #if 0 if (NewChars->XonChar == NewChars->XoffChar) { Status = STATUS_INVALID_PARAMETER; break; } #endif // // We acquire the control lock so that only // one request can GET or SET the characters // at a time. The sets could be synchronized // by the interrupt spinlock, but that wouldn't // prevent multiple gets at the same time. // S.Extension = Extension; S.Data = NewChars; // // Under the protection of the lock, make sure that // the xon and xoff characters aren't the same as // the escape character. // if (Extension->EscapeChar) { if ((Extension->EscapeChar == NewChars->XonChar) || (Extension->EscapeChar == NewChars->XoffChar)) { Status = STATUS_INVALID_PARAMETER; break; } } Extension->WmiCommData.XonCharacter = NewChars->XonChar; Extension->WmiCommData.XoffCharacter = NewChars->XoffChar; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialSetChars, &S ); break; } case IOCTL_SERIAL_GET_CHARS: { Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_CHARS), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } *((PSERIAL_CHARS)buffer) = Extension->SpecialChars; reqContext->Information = sizeof(SERIAL_CHARS); break; } case IOCTL_SERIAL_SET_DTR: case IOCTL_SERIAL_CLR_DTR: { // // We acquire the lock so that we can check whether // automatic dtr flow control is enabled. If it is // then we return an error since the app is not allowed // to touch this if it is automatic. // if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { Status = STATUS_INVALID_PARAMETER; } else { WdfInterruptSynchronize( Extension->WdfInterrupt, ((IoControlCode == IOCTL_SERIAL_SET_DTR)? (SerialSetDTR):(SerialClrDTR)), Extension ); } break; } case IOCTL_SERIAL_RESET_DEVICE: { break; } case IOCTL_SERIAL_SET_RTS: case IOCTL_SERIAL_CLR_RTS: { // // We acquire the lock so that we can check whether // automatic rts flow control or transmit toggleing // is enabled. If it is then we return an error since // the app is not allowed to touch this if it is automatic // or toggling. // if (((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) || ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { Status = STATUS_INVALID_PARAMETER; } else { WdfInterruptSynchronize( Extension->WdfInterrupt, ((IoControlCode == IOCTL_SERIAL_SET_RTS)? (SerialSetRTS):(SerialClrRTS)), Extension ); } break; } case IOCTL_SERIAL_SET_XOFF: { WdfInterruptSynchronize( Extension->WdfInterrupt, SerialPretendXoff, Extension ); break; } case IOCTL_SERIAL_SET_XON: { WdfInterruptSynchronize( Extension->WdfInterrupt, SerialPretendXon, Extension ); break; } case IOCTL_SERIAL_SET_BREAK_ON: { WdfInterruptSynchronize( Extension->WdfInterrupt, SerialTurnOnBreak, Extension ); break; } case IOCTL_SERIAL_SET_BREAK_OFF: { WdfInterruptSynchronize( Extension->WdfInterrupt, SerialTurnOffBreak, Extension ); break; } case IOCTL_SERIAL_SET_QUEUE_SIZE: { // // Type ahead buffer is fixed, so we just validate // the the users request is not bigger that our // own internal buffer size. // PSERIAL_QUEUE_SIZE Rs; Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_QUEUE_SIZE), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } ASSERT(Extension->InterruptReadBuffer); Rs = (PSERIAL_QUEUE_SIZE)buffer; reqContext->SystemBuffer = buffer; // // We have to allocate the memory for the new // buffer while we're still in the context of the // caller. We don't even try to protect this // with a lock because the value could be stale // as soon as we release the lock - The only time // we will know for sure is when we actually try // to do the resize. // if (Rs->InSize <= Extension->BufferSize) { Status = STATUS_SUCCESS; break; } reqContext->Type3InputBuffer = ExAllocatePoolWithQuotaTag( NonPagedPoolNx | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, Rs->InSize, POOL_TAG ); if (!reqContext->Type3InputBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } // // Well the data passed was big enough. Do the request. // // There are two reason we place it in the read queue: // // 1) We want to serialize these resize requests so that // they don't contend with each other. // // 2) We want to serialize these requests with reads since // we don't want reads and resizes contending over the // read buffer. // SerialStartOrQueue( Extension, Request, Extension->ReadQueue, &Extension->CurrentReadRequest, SerialStartRead ); return; } case IOCTL_SERIAL_GET_WAIT_MASK: { Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } // // Simple scalar read. No reason to acquire a lock. // reqContext->Information = sizeof(ULONG); *((ULONG *)buffer) = Extension->IsrWaitMask; break; } case IOCTL_SERIAL_SET_WAIT_MASK: { ULONG NewMask; SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "In Ioctl processing for set mask\n"); Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } NewMask = *((ULONG *)buffer); reqContext->SystemBuffer = buffer; // // Make sure that the mask only contains valid // waitable events. // if (NewMask & ~(SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2)) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Unknown mask %x\n", NewMask); Status = STATUS_INVALID_PARAMETER; break; } // // Either start this request or put it on the // queue. // SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Starting or queuing set mask request %p" "\n", Request); SerialStartOrQueue(Extension, Request, Extension->MaskQueue, &Extension->CurrentMaskRequest, SerialStartMask); return; } case IOCTL_SERIAL_WAIT_ON_MASK: { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "In Ioctl processing for wait mask\n"); Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->SystemBuffer = buffer; // // Either start this request or put it on the // queue. // SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Starting or queuing wait mask request" "%p\n", Request); SerialStartOrQueue( Extension, Request, Extension->MaskQueue, &Extension->CurrentMaskRequest, SerialStartMask ); return; } case IOCTL_SERIAL_IMMEDIATE_CHAR: { Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(UCHAR), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->SystemBuffer = buffer; if (Extension->CurrentImmediateRequest) { Status = STATUS_INVALID_PARAMETER; } else { // // We can queue the char. We need to set // a cancel routine because flow control could // keep the char from transmitting. Make sure // that the request hasn't already been canceled. // Extension->CurrentImmediateRequest = Request; Extension->TotalCharsQueued++; SerialStartImmediate(Extension); return; } break; } case IOCTL_SERIAL_PURGE: { ULONG Mask; Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } // // Check to make sure that the mask only has // 0 or the other appropriate values. // Mask = *((ULONG *)(buffer)); if ((!Mask) || (Mask & (~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR ) ) )) { Status = STATUS_INVALID_PARAMETER; break; } reqContext->SystemBuffer = buffer; // // Either start this request or put it on the // queue. // SerialStartOrQueue( Extension, Request, Extension->PurgeQueue, &Extension->CurrentPurgeRequest, SerialStartPurge ); return; } case IOCTL_SERIAL_GET_HANDFLOW: { Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_HANDFLOW), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->Information = sizeof(SERIAL_HANDFLOW); *((PSERIAL_HANDFLOW)buffer) = Extension->HandFlow; break; } case IOCTL_SERIAL_SET_HANDFLOW: { SERIAL_IOCTL_SYNC S; PSERIAL_HANDFLOW HandFlow; // // Make sure that the hand shake and control is the // right size. // Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_HANDFLOW), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } HandFlow = (PSERIAL_HANDFLOW)buffer; // // Make sure that there are no invalid bits set in // the control and handshake. // if (HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) { Status = STATUS_INVALID_PARAMETER; break; } if (HandFlow->FlowReplace & SERIAL_FLOW_INVALID) { Status = STATUS_INVALID_PARAMETER; break; } // // Make sure that the app hasn't set an invlid DTR mode. // if ((HandFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK) { Status = STATUS_INVALID_PARAMETER; break; } // // Make sure that haven't set totally invalid xon/xoff // limits. // if ((HandFlow->XonLimit < 0) || ((ULONG)HandFlow->XonLimit > Extension->BufferSize)) { Status = STATUS_INVALID_PARAMETER; break; } if ((HandFlow->XoffLimit < 0) || ((ULONG)HandFlow->XoffLimit > Extension->BufferSize)) { Status = STATUS_INVALID_PARAMETER; break; } S.Extension = Extension; S.Data = HandFlow; // // Under the protection of the lock, make sure that // we aren't turning on error replacement when we // are doing line status/modem status insertion. // if (Extension->EscapeChar) { if (HandFlow->FlowReplace & SERIAL_ERROR_CHAR) { Status = STATUS_INVALID_PARAMETER; break; } } WdfInterruptSynchronize( Extension->WdfInterrupt, SerialSetHandFlow, &S ); break; } case IOCTL_SERIAL_GET_MODEMSTATUS: { SERIAL_IOCTL_SYNC S; Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->Information = sizeof(ULONG); S.Extension = Extension; S.Data = buffer; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialGetModemUpdate, &S ); break; } case IOCTL_SERIAL_GET_DTRRTS: { ULONG ModemControl; Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->Information = sizeof(ULONG); reqContext->Status = STATUS_SUCCESS; // // Reading this hardware has no effect on the device. // ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller); ModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE; *(PULONG)buffer = ModemControl; break; } case IOCTL_SERIAL_GET_COMMSTATUS: { SERIAL_IOCTL_SYNC S; Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_STATUS), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->Information = sizeof(SERIAL_STATUS); S.Extension = Extension; S.Data = buffer; // // Acquire the cancel spin lock so nothing much // changes while were getting the state. // //IoAcquireCancelSpinLock(&OldIrql); WdfInterruptSynchronize( Extension->WdfInterrupt, SerialGetCommStatus, &S ); //IoReleaseCancelSpinLock(OldIrql); break; } case IOCTL_SERIAL_GET_PROPERTIES: { Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_COMMPROP), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } // // No synchronization is required since this information // is "static". // SerialGetProperties( Extension, buffer ); reqContext->Information = sizeof(SERIAL_COMMPROP); reqContext->Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_XOFF_COUNTER: { PSERIAL_XOFF_COUNTER Xc; Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_XOFF_COUNTER), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } Xc = (PSERIAL_XOFF_COUNTER)buffer; if (Xc->Counter <= 0) { Status = STATUS_INVALID_PARAMETER; break; } reqContext->SystemBuffer = buffer; // // There is no output, so make that clear now // reqContext->Information = 0; // // So far so good. Put the request onto the write queue. // SerialStartOrQueue( Extension, Request, Extension->WriteQueue, &Extension->CurrentWriteRequest, SerialStartWrite ); return; } case IOCTL_SERIAL_LSRMST_INSERT: { PUCHAR escapeChar; SERIAL_IOCTL_SYNC S; // // Make sure we get a byte. // Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(UCHAR), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->SystemBuffer = buffer; escapeChar = (PUCHAR)buffer; if (*escapeChar) { // // We've got some escape work to do. We will make sure that // the character is not the same as the Xon or Xoff character, // or that we are already doing error replacement. // if ((*escapeChar == Extension->SpecialChars.XoffChar) || (*escapeChar == Extension->SpecialChars.XonChar) || (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)) { Status = STATUS_INVALID_PARAMETER; break; } } S.Extension = Extension; S.Data = buffer; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialSetEscapeChar, reqContext ); break; } case IOCTL_SERIAL_CONFIG_SIZE: { Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->Information = sizeof(ULONG); reqContext->Status = STATUS_SUCCESS; *(PULONG)buffer = 0; break; } case IOCTL_SERIAL_GET_STATS: { Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIALPERF_STATS), &buffer, &bufSize ); if( !NT_SUCCESS(Status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", Status); break; } reqContext->SystemBuffer = buffer; reqContext->Information = sizeof(SERIALPERF_STATS); reqContext->Status = STATUS_SUCCESS; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialGetStats, reqContext ); break; } case IOCTL_SERIAL_CLEAR_STATS: { WdfInterruptSynchronize( Extension->WdfInterrupt, SerialClearStats, Extension ); break; } default: { Status = STATUS_INVALID_PARAMETER; break; } } DoneWithIoctl:; reqContext->Status = Status; SerialCompleteRequest(Request, Status, reqContext->Information); return; } VOID SerialGetProperties( IN PSERIAL_DEVICE_EXTENSION Extension, IN PSERIAL_COMMPROP Properties ) /*++ Routine Description: This function returns the capabilities of this particular serial device. Arguments: Extension - The serial device extension. Properties - The structure used to return the properties Return Value: None. --*/ { RtlZeroMemory( Properties, sizeof(SERIAL_COMMPROP) ); Properties->PacketLength = sizeof(SERIAL_COMMPROP); Properties->PacketVersion = 2; Properties->ServiceMask = SERIAL_SP_SERIALCOMM; Properties->MaxTxQueue = 0; Properties->MaxRxQueue = 0; Properties->MaxBaud = SERIAL_BAUD_USER; Properties->SettableBaud = Extension->SupportedBauds; Properties->ProvSubType = SERIAL_SP_RS232; Properties->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_RTSCTS | SERIAL_PCF_CD | SERIAL_PCF_PARITY_CHECK | SERIAL_PCF_XONXOFF | SERIAL_PCF_SETXCHAR | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS; Properties->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_PARITY_CHECK | SERIAL_SP_CARRIER_DETECT; Properties->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8; Properties->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE; Properties->CurrentTxQueue = 0; Properties->CurrentRxQueue = Extension->BufferSize; } VOID SerialEvtIoInternalDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This routine provides the initial processing for all of the internal Ioctrls for the serial device. Arguments: PDevObj - Pointer to the device object for this device PIrp - Pointer to the WDFREQUEST for the current request Return Value: The function value is the final status of the call --*/ { NTSTATUS status; PSERIAL_DEVICE_EXTENSION pDevExt = NULL; PVOID buffer; PREQUEST_CONTEXT reqContext; WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; size_t bufSize; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "SerialEvtIoInternalDeviceControl for: %p\n", Request); pDevExt = SerialGetDeviceExtension(WdfIoQueueGetDevice(Queue)); if (SerialCompleteIfError(pDevExt, Request) != STATUS_SUCCESS) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Information = 0; reqContext->Status = STATUS_SUCCESS; reqContext->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; switch (IoControlCode) { case IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE: // // Init wait-wake policy structure. // WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); // // Override the default settings from allow user control to do not allow. // wakeSettings.UserControlOfWakeSettings = IdleDoNotAllowUserControl; status = WdfDeviceAssignSxWakeSettings(pDevExt->WdfDevice, &wakeSettings); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceAssignSxWakeSettings failed %x \n", status); break; } pDevExt->IsWakeEnabled = TRUE; status = STATUS_SUCCESS; break; case IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE: WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); // // Override the default settings. // wakeSettings.Enabled = WdfFalse; // Disables wait-wake wakeSettings.UserControlOfWakeSettings = IdleDoNotAllowUserControl; status = WdfDeviceAssignSxWakeSettings(pDevExt->WdfDevice, &wakeSettings); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceAssignSxWakeSettings failed %x \n", status); break; } pDevExt->IsWakeEnabled = FALSE; status = STATUS_SUCCESS; break; // // Put the serial port in a "filter-driver" appropriate state // // WARNING: This code assumes it is being called by a trusted kernel // entity and no checking is done on the validity of the settings // passed to IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS // // If validity checking is desired, the regular ioctl's should be used // case IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS: case IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS: { SERIAL_BASIC_SETTINGS basic; PSERIAL_BASIC_SETTINGS pBasic; SERIAL_IOCTL_SYNC S; if (IoControlCode == IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS) { // // Check the buffer size // status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_BASIC_SETTINGS), &buffer, &bufSize ); if( !NT_SUCCESS(status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", status); break; } reqContext->SystemBuffer = buffer; // // Everything is 0 -- timeouts and flow control and fifos. If // We add additional features, this zero memory method // may not work. // RtlZeroMemory(&basic, sizeof(SERIAL_BASIC_SETTINGS)); basic.TxFifo = 1; basic.RxFifo = SERIAL_1_BYTE_HIGH_WATER; reqContext->Information = sizeof(SERIAL_BASIC_SETTINGS); pBasic = (PSERIAL_BASIC_SETTINGS)buffer; // // Save off the old settings // RtlCopyMemory(&pBasic->Timeouts, &pDevExt->Timeouts, sizeof(SERIAL_TIMEOUTS)); RtlCopyMemory(&pBasic->HandFlow, &pDevExt->HandFlow, sizeof(SERIAL_HANDFLOW)); pBasic->RxFifo = pDevExt->RxFifoTrigger; pBasic->TxFifo = pDevExt->TxFifoAmount; // // Point to our new settings // pBasic = &basic; } else { // restoring settings status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_BASIC_SETTINGS), &buffer, &bufSize ); if( !NT_SUCCESS(status) ) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, "Could not get request memory buffer %X\n", status); break; } pBasic = (PSERIAL_BASIC_SETTINGS)buffer; } // // Set the timeouts // RtlCopyMemory(&pDevExt->Timeouts, &pBasic->Timeouts, sizeof(SERIAL_TIMEOUTS)); // // Set flowcontrol // S.Extension = pDevExt; S.Data = &pBasic->HandFlow; WdfInterruptSynchronize(pDevExt->WdfInterrupt, SerialSetHandFlow, &S); if (pDevExt->FifoPresent) { pDevExt->TxFifoAmount = pBasic->TxFifo; pDevExt->RxFifoTrigger = (UCHAR)pBasic->RxFifo; WRITE_FIFO_CONTROL(pDevExt, pDevExt->Controller, (UCHAR)0); READ_RECEIVE_BUFFER(pDevExt, pDevExt->Controller); WRITE_FIFO_CONTROL(pDevExt, pDevExt->Controller, (UCHAR)(SERIAL_FCR_ENABLE | pDevExt->RxFifoTrigger | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)); } else { pDevExt->TxFifoAmount = pDevExt->RxFifoTrigger = 0; WRITE_FIFO_CONTROL(pDevExt, pDevExt->Controller, (UCHAR)0); } break; } default: status = STATUS_INVALID_PARAMETER; break; } reqContext->Status = status; SerialCompleteRequest(Request, reqContext->Status, reqContext->Information); return; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/isr.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: isr.c Abstract: This module contains the interrupt service routine for the serial driver. Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "isr.tmh" #endif NTSTATUS SerialEvtInterruptEnable( IN WDFINTERRUPT Interrupt, IN WDFDEVICE AssociatedDevice ) /*++ Routine Description: This event is called when the Framework moves the device to D0, and after EvtDeviceD0Entry. The driver should enable its interrupt here. This function will be called at the device's assigned interrupt IRQL (DIRQL.) Arguments: Interrupt - Handle to a Framework interrupt object. AssociatedDevice - Handle to a Framework device object. Return Value: BOOLEAN - TRUE indicates that the interrupt was successfully enabled. --*/ { UNREFERENCED_PARAMETER(Interrupt); UNREFERENCED_PARAMETER(AssociatedDevice); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> SerialEvtInterruptEnable\n"); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- SerialEvtInterruptEnable\n"); return STATUS_SUCCESS; } NTSTATUS SerialEvtInterruptDisable( IN WDFINTERRUPT Interrupt, IN WDFDEVICE AssociatedDevice ) /*++ Routine Description: This event is called before the Framework moves the device to D1, D2 or D3 and before EvtDeviceD0Exit. The driver should disable its interrupt here. This function will be called at the device's assigned interrupt IRQL (DIRQL.) Arguments: Interrupt - Handle to a Framework interrupt object. AssociatedDevice - Handle to a Framework device object. Return Value: BOOLEAN - TRUE indicates that the interrupt was successfully disabled. --*/ { UNREFERENCED_PARAMETER(Interrupt); UNREFERENCED_PARAMETER(AssociatedDevice); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> SerialEvtInterruptDisable\n"); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- SerialEvtInterruptDisable\n"); return STATUS_SUCCESS; } BOOLEAN SerialISR( IN WDFINTERRUPT Interrupt, IN ULONG MessageID ) /*++ Routine Description: This is the interrupt service routine for the serial port driver. It will determine whether the serial port is the source of this interrupt. If it is, then this routine will do the minimum of processing to quiet the interrupt. It will store any information necessary for later processing. Arguments: InterruptObject - Points to the interrupt object declared for this device. We *do not* use this parameter. Return Value: This function will return TRUE if the serial port is the source of this interrupt, FALSE otherwise. --*/ { // // Holds the information specific to handling this device. // PSERIAL_DEVICE_EXTENSION Extension = NULL; // // Holds the contents of the interrupt identification record. // A low bit of zero in this register indicates that there is // an interrupt pending on this device. // UCHAR InterruptIdReg; // // Will hold whether we've serviced any interrupt causes in this // routine. // BOOLEAN ServicedAnInterrupt; UCHAR tempLSR; PREQUEST_CONTEXT reqContext = NULL; UNREFERENCED_PARAMETER(MessageID); Extension = SerialGetDeviceExtension(WdfInterruptGetDevice(Interrupt)); // // Make sure we have an interrupt pending. If we do then // we need to make sure that the device is open. If the // device isn't open or powered down then quiet the device. Note that // if the device isn't opened when we enter this routine // it can't open while we're in it. // InterruptIdReg = READ_INTERRUPT_ID_REG(Extension, Extension->Controller); if ((InterruptIdReg & SERIAL_IIR_NO_INTERRUPT_PENDING)) { ServicedAnInterrupt = FALSE; } else if (!Extension->DeviceIsOpened/* || (Extension->PowerState != PowerDeviceD0)*/) { // // We got an interrupt with the device being closed or when the // device is supposed to be powered down. This // is not unlikely with a serial device. We just quietly // keep servicing the causes until it calms down. // ServicedAnInterrupt = TRUE; do { InterruptIdReg &= (~SERIAL_IIR_FIFOS_ENABLED); switch (InterruptIdReg) { case SERIAL_IIR_RLS: { READ_LINE_STATUS(Extension, Extension->Controller); break; } case SERIAL_IIR_RDA: case SERIAL_IIR_CTI: { READ_RECEIVE_BUFFER(Extension, Extension->Controller); break; } case SERIAL_IIR_THR: { // // Alread clear from reading the iir. // // We want to keep close track of whether // the holding register is empty. // Extension->HoldingEmpty = TRUE; break; } case SERIAL_IIR_MS: { READ_MODEM_STATUS(Extension, Extension->Controller); break; } default: { ASSERT(FALSE); break; } } } while (!((InterruptIdReg = READ_INTERRUPT_ID_REG(Extension, Extension->Controller)) & SERIAL_IIR_NO_INTERRUPT_PENDING)); } else { ServicedAnInterrupt = TRUE; do { // // We only care about bits that can denote an interrupt. // InterruptIdReg &= SERIAL_IIR_RLS | SERIAL_IIR_RDA | SERIAL_IIR_CTI | SERIAL_IIR_THR | SERIAL_IIR_MS; // // We have an interrupt. We look for interrupt causes // in priority order. The presence of a higher interrupt // will mask out causes of a lower priority. When we service // and quiet a higher priority interrupt we then need to check // the interrupt causes to see if a new interrupt cause is // present. // switch (InterruptIdReg) { case SERIAL_IIR_RLS: { SerialProcessLSR(Extension); break; } case SERIAL_IIR_RDA: case SERIAL_IIR_CTI: { // // Reading the receive buffer will quiet this interrupt. // // It may also reveal a new interrupt cause. // UCHAR ReceivedChar; do { ReceivedChar = READ_RECEIVE_BUFFER(Extension, Extension->Controller); Extension->PerfStats.ReceivedCount++; Extension->WmiPerfData.ReceivedCount++; ReceivedChar &= Extension->ValidDataMask; if (!ReceivedChar && (Extension->HandFlow.FlowReplace & SERIAL_NULL_STRIPPING)) { // // If what we got is a null character // and we're doing null stripping, then // we simply act as if we didn't see it. // goto ReceiveDoLineStatus; } if ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) && ((ReceivedChar == Extension->SpecialChars.XonChar) || (ReceivedChar == Extension->SpecialChars.XoffChar))) { // // No matter what happens this character // will never get seen by the app. // if (ReceivedChar == Extension->SpecialChars.XoffChar) { Extension->TXHolding |= SERIAL_TX_XOFF; if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } } else { if (Extension->TXHolding & SERIAL_TX_XOFF) { // // We got the xon char **AND*** we // were being held up on transmission // by xoff. Clear that we are holding // due to xoff. Transmission will // automatically restart because of // the code outside the main loop that // catches problems chips like the // SMC and the Winbond. // Extension->TXHolding &= ~SERIAL_TX_XOFF; } } goto ReceiveDoLineStatus; } // // Check to see if we should note // the receive character or special // character event. // if (Extension->IsrWaitMask) { if (Extension->IsrWaitMask & SERIAL_EV_RXCHAR) { Extension->HistoryMask |= SERIAL_EV_RXCHAR; } if ((Extension->IsrWaitMask & SERIAL_EV_RXFLAG) && (Extension->SpecialChars.EventChar == ReceivedChar)) { Extension->HistoryMask |= SERIAL_EV_RXFLAG; } if (Extension->IrpMaskLocation && Extension->HistoryMask) { *Extension->IrpMaskLocation = Extension->HistoryMask; Extension->IrpMaskLocation = NULL; Extension->HistoryMask = 0; reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest); reqContext->Information = sizeof(ULONG); SerialInsertQueueDpc( Extension->CommWaitDpc ); } } SerialPutChar( Extension, ReceivedChar ); // // If we're doing line status and modem // status insertion then we need to insert // a zero following the character we just // placed into the buffer to mark that this // was reception of what we are using to // escape. // if (Extension->EscapeChar && (Extension->EscapeChar == ReceivedChar)) { SerialPutChar( Extension, SERIAL_LSRMST_ESCAPE ); } ReceiveDoLineStatus: ; // // This reads the interrupt ID register and detemines if bits are 0 // If either of the reserved bits are 1, we stop servicing interrupts // Since this detection method is not guarenteed this is enabled via // a registry entry "UartDetectRemoval" and intialized on DriverEntry. // This is disabled by default and will only be enabled on Stratus systems // that allow hot replacement of serial cards // if(Extension->UartRemovalDetect) { UCHAR DetectRemoval; DetectRemoval = READ_INTERRUPT_ID_REG(Extension, Extension->Controller); if(DetectRemoval & SERIAL_IIR_MUST_BE_ZERO) { // break out of this loop and stop processing interrupts break; } } if (!((tempLSR = SerialProcessLSR(Extension)) & SERIAL_LSR_DR)) { // // No more characters, get out of the // loop. // break; } if ((tempLSR & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT | SERIAL_LSR_DR)) && Extension->EscapeChar) { // // An error was indicated and inserted into the // stream, get out of the loop. // break; } } WHILE (TRUE); break; } case SERIAL_IIR_THR: { doTrasmitStuff:; Extension->HoldingEmpty = TRUE; if (Extension->WriteLength || Extension->TransmitImmediate || Extension->SendXoffChar || Extension->SendXonChar) { // // Even though all of the characters being // sent haven't all been sent, this variable // will be checked when the transmit queue is // empty. If it is still true and there is a // wait on the transmit queue being empty then // we know we finished transmitting all characters // following the initiation of the wait since // the code that initiates the wait will set // this variable to false. // // One reason it could be false is that // the writes were cancelled before they // actually started, or that the writes // failed due to timeouts. This variable // basically says a character was written // by the isr at some point following the // initiation of the wait. // Extension->EmptiedTransmit = TRUE; // // If we have output flow control based on // the modem status lines, then we have to do // all the modem work before we output each // character. (Otherwise we might miss a // status line change.) // if (Extension->HandFlow.ControlHandShake & SERIAL_OUT_HANDSHAKEMASK) { SerialHandleModemUpdate( Extension, TRUE ); } // // We can only send the xon character if // the only reason we are holding is because // of the xoff. (Hardware flow control or // sending break preclude putting a new character // on the wire.) // if (Extension->SendXonChar && !(Extension->TXHolding & ~SERIAL_TX_XOFF)) { if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // // We have to raise if we're sending // this character. // SerialSetRTS(Extension->WdfInterrupt, Extension); Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller, Extension->SpecialChars.XonChar); SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } else { Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller, Extension->SpecialChars.XonChar); } Extension->SendXonChar = FALSE; Extension->HoldingEmpty = FALSE; // // If we send an xon, by definition we // can't be holding by Xoff. // Extension->TXHolding &= ~SERIAL_TX_XOFF; // // If we are sending an xon char then // by definition we can't be "holding" // up reception by Xoff. // Extension->RXHolding &= ~SERIAL_RX_XOFF; } else if (Extension->SendXoffChar && !Extension->TXHolding) { if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // // We have to raise if we're sending // this character. // SerialSetRTS(Extension->WdfInterrupt, Extension); Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller, Extension->SpecialChars.XoffChar); SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } else { Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller, Extension->SpecialChars.XoffChar); } // // We can't be sending an Xoff character // if the transmission is already held // up because of Xoff. Therefore, if we // are holding then we can't send the char. // // // If the application has set xoff continue // mode then we don't actually stop sending // characters if we send an xoff to the other // side. // if (!(Extension->HandFlow.FlowReplace & SERIAL_XOFF_CONTINUE)) { Extension->TXHolding |= SERIAL_TX_XOFF; if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } } Extension->SendXoffChar = FALSE; Extension->HoldingEmpty = FALSE; // // Even if transmission is being held // up, we should still transmit an immediate // character if all that is holding us // up is xon/xoff (OS/2 rules). // } else if (Extension->TransmitImmediate && (!Extension->TXHolding || (Extension->TXHolding == SERIAL_TX_XOFF) )) { Extension->TransmitImmediate = FALSE; if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // // We have to raise if we're sending // this character. // SerialSetRTS(Extension->WdfInterrupt, Extension); Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller, Extension->ImmediateChar); SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } else { Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller, Extension->ImmediateChar); } Extension->HoldingEmpty = FALSE; SerialInsertQueueDpc( Extension->CompleteImmediateDpc ); } else if (!Extension->TXHolding) { ULONG amountToWrite; if (Extension->FifoPresent) { amountToWrite = (Extension->TxFifoAmount < Extension->WriteLength)? Extension->TxFifoAmount: Extension->WriteLength; } else { amountToWrite = 1; } if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // // We have to raise if we're sending // this character. // SerialSetRTS(Extension->WdfInterrupt, Extension); if (amountToWrite == 1) { Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller, *(Extension->WriteCurrentChar)); } else { Extension->PerfStats.TransmittedCount += amountToWrite; Extension->WmiPerfData.TransmittedCount += amountToWrite; WRITE_TRANSMIT_FIFO_HOLDING(Extension, Extension->Controller, Extension->WriteCurrentChar, amountToWrite); } SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } else { if (amountToWrite == 1) { Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller, *(Extension->WriteCurrentChar)); } else { Extension->PerfStats.TransmittedCount += amountToWrite; Extension->WmiPerfData.TransmittedCount += amountToWrite; WRITE_TRANSMIT_FIFO_HOLDING(Extension, Extension->Controller, Extension->WriteCurrentChar, amountToWrite); } } Extension->HoldingEmpty = FALSE; Extension->WriteCurrentChar += amountToWrite; Extension->WriteLength -= amountToWrite; if (!Extension->WriteLength) { // // No More characters left. This // write is complete. Take care // when updating the information field, // we could have an xoff counter masquerading // as a write request. // reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest); reqContext->Information = (reqContext->MajorFunction == IRP_MJ_WRITE)? (reqContext->Length): (1); SerialInsertQueueDpc( Extension->CompleteWriteDpc ); } } } break; } case SERIAL_IIR_MS: { SerialHandleModemUpdate( Extension, FALSE ); break; } } } while (!((InterruptIdReg = READ_INTERRUPT_ID_REG(Extension, Extension->Controller)) & SERIAL_IIR_NO_INTERRUPT_PENDING)); // // Besides catching the WINBOND and SMC chip problems this // will also cause transmission to restart incase of an xon // char being received. Don't remove. // if (SerialProcessLSR(Extension) & SERIAL_LSR_THRE) { if (!Extension->TXHolding && (Extension->WriteLength || Extension->TransmitImmediate)) { goto doTrasmitStuff; } } } return ServicedAnInterrupt; } VOID SerialPutChar( IN PSERIAL_DEVICE_EXTENSION Extension, IN UCHAR CharToPut ) /*++ Routine Description: This routine, which only runs at device level, takes care of placing a character into the typeahead (receive) buffer. Arguments: Extension - The serial device extension. Return Value: None. --*/ { PREQUEST_CONTEXT reqContext = NULL; // // If we have dsr sensitivity enabled then // we need to check the modem status register // to see if it has changed. // if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) { SerialHandleModemUpdate( Extension, FALSE ); if (Extension->RXHolding & SERIAL_RX_DSR) { // // We simply act as if we haven't // seen the character if we have dsr // sensitivity and the dsr line is low. // return; } } // // If the xoff counter is non-zero then decrement it. // If the counter then goes to zero, complete that request. // if (Extension->CountSinceXoff) { Extension->CountSinceXoff--; if (!Extension->CountSinceXoff) { reqContext = SerialGetRequestContext(Extension->CurrentXoffRequest); reqContext->Status = STATUS_SUCCESS; reqContext->Information = 0; SerialInsertQueueDpc( Extension->XoffCountCompleteDpc ); } } // // Check to see if we are copying into the // users buffer or into the interrupt buffer. // // If we are copying into the user buffer // then we know there is always room for one more. // (We know this because if there wasn't room // then that read would have completed and we // would be using the interrupt buffer.) // // If we are copying into the interrupt buffer // then we will need to check if we have enough // room. // if (Extension->ReadBufferBase != Extension->InterruptReadBuffer) { // // Increment the following value so // that the interval timer (if one exists // for this read) can know that a character // has been read. // Extension->ReadByIsr++; // // We are in the user buffer. Place the // character into the buffer. See if the // read is complete. // *Extension->CurrentCharSlot = CharToPut; if (Extension->CurrentCharSlot == Extension->LastCharSlot) { // // We've filled up the users buffer. // Switch back to the interrupt buffer // and send off a DPC to Complete the read. // // It is inherent that when we were using // a user buffer that the interrupt buffer // was empty. // Extension->ReadBufferBase = Extension->InterruptReadBuffer; Extension->CurrentCharSlot = Extension->InterruptReadBuffer; Extension->FirstReadableChar = Extension->InterruptReadBuffer; Extension->LastCharSlot = Extension->InterruptReadBuffer + (Extension->BufferSize - 1); Extension->CharsInInterruptBuffer = 0; reqContext = SerialGetRequestContext(Extension->CurrentReadRequest); reqContext->Information = reqContext->Length; SerialInsertQueueDpc( Extension->CompleteReadDpc ); } else { // // Not done with the users read. // Extension->CurrentCharSlot++; } } else { // // We need to see if we reached our flow // control threshold. If we have then // we turn on whatever flow control the // owner has specified. If no flow // control was specified, well..., we keep // trying to receive characters and hope that // we have enough room. Note that no matter // what flow control protocol we are using, it // will not prevent us from reading whatever // characters are available. // if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { // // If we are already doing a // dtr hold then we don't have // to do anything else. // if (!(Extension->RXHolding & SERIAL_RX_DTR)) { if ((Extension->BufferSize - Extension->HandFlow.XoffLimit) <= (Extension->CharsInInterruptBuffer+1)) { Extension->RXHolding |= SERIAL_RX_DTR; SerialClrDTR(Extension->WdfInterrupt, Extension); } } } if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) { // // If we are already doing a // rts hold then we don't have // to do anything else. // if (!(Extension->RXHolding & SERIAL_RX_RTS)) { if ((Extension->BufferSize - Extension->HandFlow.XoffLimit) <= (Extension->CharsInInterruptBuffer+1)) { Extension->RXHolding |= SERIAL_RX_RTS; SerialClrRTS(Extension->WdfInterrupt, Extension); } } } if (Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) { // // If we are already doing a // xoff hold then we don't have // to do anything else. // if (!(Extension->RXHolding & SERIAL_RX_XOFF)) { if ((Extension->BufferSize - Extension->HandFlow.XoffLimit) <= (Extension->CharsInInterruptBuffer+1)) { Extension->RXHolding |= SERIAL_RX_XOFF; // // If necessary cause an // off to be sent. // SerialProdXonXoff( Extension, FALSE ); } } } if (Extension->CharsInInterruptBuffer < Extension->BufferSize) { *Extension->CurrentCharSlot = CharToPut; Extension->CharsInInterruptBuffer++; // // If we've become 80% full on this character // and this is an interesting event, note it. // if (Extension->CharsInInterruptBuffer == Extension->BufferSizePt8) { if (Extension->IsrWaitMask & SERIAL_EV_RX80FULL) { Extension->HistoryMask |= SERIAL_EV_RX80FULL; if (Extension->IrpMaskLocation) { *Extension->IrpMaskLocation = Extension->HistoryMask; Extension->IrpMaskLocation = NULL; Extension->HistoryMask = 0; reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest); reqContext->Information = sizeof(ULONG); SerialInsertQueueDpc( Extension->CommWaitDpc ); } } } // // Point to the next available space // for a received character. Make sure // that we wrap around to the beginning // of the buffer if this last character // received was placed at the last slot // in the buffer. // if (Extension->CurrentCharSlot == Extension->LastCharSlot) { Extension->CurrentCharSlot = Extension->InterruptReadBuffer; } else { Extension->CurrentCharSlot++; } } else { // // We have a new character but no room for it. // Extension->PerfStats.BufferOverrunErrorCount++; Extension->WmiPerfData.BufferOverrunErrorCount++; Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN; if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) { // // Place the error character into the last // valid place for a character. Be careful!, // that place might not be the previous location! // if (Extension->CurrentCharSlot == Extension->InterruptReadBuffer) { *(Extension->InterruptReadBuffer+ (Extension->BufferSize-1)) = Extension->SpecialChars.ErrorChar; } else { *(Extension->CurrentCharSlot-1) = Extension->SpecialChars.ErrorChar; } } // // If the application has requested it, abort all reads // and writes on an error. // if (Extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) { SerialInsertQueueDpc( Extension->CommErrorDpc ); } } } } UCHAR SerialProcessLSR( IN PSERIAL_DEVICE_EXTENSION Extension ) /*++ Routine Description: This routine, which only runs at device level, reads the ISR and totally processes everything that might have changed. Arguments: Extension - The serial device extension. Return Value: The value of the line status register. --*/ { PREQUEST_CONTEXT reqContext = NULL; UCHAR LineStatus = READ_LINE_STATUS(Extension, Extension->Controller); Extension->HoldingEmpty = (LineStatus & SERIAL_LSR_THRE) ? TRUE : FALSE; // // If the line status register is just the fact that // the trasmit registers are empty or a character is // received then we want to reread the interrupt // identification register so that we just pick up that. // if (LineStatus & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT | SERIAL_LSR_DR)) { // // We have some sort of data problem in the receive. // For any of these errors we may abort all current // reads and writes. // // // If we are inserting the value of the line status // into the data stream then we should put the escape // character in now. // if (Extension->EscapeChar) { SerialPutChar( Extension, Extension->EscapeChar ); SerialPutChar( Extension, (UCHAR)((LineStatus & SERIAL_LSR_DR)? (SERIAL_LSRMST_LSR_DATA):(SERIAL_LSRMST_LSR_NODATA)) ); SerialPutChar( Extension, LineStatus ); if (LineStatus & SERIAL_LSR_DR) { Extension->PerfStats.ReceivedCount++; Extension->WmiPerfData.ReceivedCount++; SerialPutChar( Extension, READ_RECEIVE_BUFFER(Extension, Extension->Controller) ); } } if (LineStatus & SERIAL_LSR_OE) { Extension->PerfStats.SerialOverrunErrorCount++; Extension->WmiPerfData.SerialOverrunErrorCount++; Extension->ErrorWord |= SERIAL_ERROR_OVERRUN; if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) { SerialPutChar( Extension, Extension->SpecialChars.ErrorChar ); if (LineStatus & SERIAL_LSR_DR) { Extension->PerfStats.ReceivedCount++; Extension->WmiPerfData.ReceivedCount++; READ_RECEIVE_BUFFER(Extension, Extension->Controller); } } else { if (LineStatus & SERIAL_LSR_DR) { Extension->PerfStats.ReceivedCount++; Extension->WmiPerfData.ReceivedCount++; SerialPutChar( Extension, READ_RECEIVE_BUFFER(Extension, Extension->Controller ) ); } } } if (LineStatus & SERIAL_LSR_BI) { Extension->ErrorWord |= SERIAL_ERROR_BREAK; if (Extension->HandFlow.FlowReplace & SERIAL_BREAK_CHAR) { SerialPutChar( Extension, Extension->SpecialChars.BreakChar ); } } else { // // Framing errors only count if they // occur exclusive of a break being // received. // if (LineStatus & SERIAL_LSR_PE) { Extension->PerfStats.ParityErrorCount++; Extension->WmiPerfData.ParityErrorCount++; Extension->ErrorWord |= SERIAL_ERROR_PARITY; if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) { SerialPutChar( Extension, Extension->SpecialChars.ErrorChar ); if (LineStatus & SERIAL_LSR_DR) { Extension->PerfStats.ReceivedCount++; Extension->WmiPerfData.ReceivedCount++; READ_RECEIVE_BUFFER(Extension, Extension->Controller); } } } if (LineStatus & SERIAL_LSR_FE) { Extension->PerfStats.FrameErrorCount++; Extension->WmiPerfData.FrameErrorCount++; Extension->ErrorWord |= SERIAL_ERROR_FRAMING; if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) { SerialPutChar( Extension, Extension->SpecialChars.ErrorChar ); if (LineStatus & SERIAL_LSR_DR) { Extension->PerfStats.ReceivedCount++; Extension->WmiPerfData.ReceivedCount++; READ_RECEIVE_BUFFER(Extension, Extension->Controller); } } } } // // If the application has requested it, // abort all the reads and writes // on an error. // if (Extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) { SerialInsertQueueDpc( Extension->CommErrorDpc ); } // // Check to see if we have a wait // pending on the comm error events. If we // do then we schedule a dpc to satisfy // that wait. // if (Extension->IsrWaitMask) { if ((Extension->IsrWaitMask & SERIAL_EV_ERR) && (LineStatus & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE))) { Extension->HistoryMask |= SERIAL_EV_ERR; } if ((Extension->IsrWaitMask & SERIAL_EV_BREAK) && (LineStatus & SERIAL_LSR_BI)) { Extension->HistoryMask |= SERIAL_EV_BREAK; } if (Extension->IrpMaskLocation && Extension->HistoryMask) { *Extension->IrpMaskLocation = Extension->HistoryMask; Extension->IrpMaskLocation = NULL; Extension->HistoryMask = 0; reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest); reqContext->Information = sizeof(ULONG); SerialInsertQueueDpc( Extension->CommWaitDpc ); } } if (LineStatus & SERIAL_LSR_THRE) { // // There is a hardware bug in some versions // of the 16450 and 550. If THRE interrupt // is pending, but a higher interrupt comes // in it will only return the higher and // *forget* about the THRE. // // A suitable workaround - whenever we // are *all* done reading line status // of the device we check to see if the // transmit holding register is empty. If it is // AND we are currently transmitting data // enable the interrupts which should cause // an interrupt indication which we quiet // when we read the interrupt id register. // if (Extension->WriteLength | Extension->TransmitImmediate) { DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller ); ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller ); } } } return LineStatus; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/log.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: log.c Abstract: Debug log Code for serial. Environment: kernel mode only --*/ #include "precomp.h" extern ULONG DebugLevel; extern ULONG DebugFlag; #if !defined(EVENT_TRACING) VOID SerialDbgPrintEx ( IN ULONG TraceEventsLevel, IN ULONG TraceEventsFlag, IN PCCHAR DebugMessage, ... ) /*++ Routine Description: Debug print for the sample driver. Arguments: TraceEventsLevel - print level between 0 and 3, with 3 the most verbose Return Value: None. --*/ { #if DBG #define TEMP_BUFFER_SIZE 1024 va_list list; CHAR debugMessageBuffer [TEMP_BUFFER_SIZE]; NTSTATUS status; va_start(list, DebugMessage); if (DebugMessage) { // // Using new safe string functions instead of _vsnprintf. // This function takes care of NULL terminating if the message // is longer than the buffer. // status = RtlStringCbVPrintfA( debugMessageBuffer, sizeof(debugMessageBuffer), DebugMessage, list ); if(!NT_SUCCESS(status)) { KdPrint((_DRIVER_NAME_": RtlStringCbVPrintfA failed %x\n", status)); return; } if (TraceEventsLevel < TRACE_LEVEL_INFORMATION || (TraceEventsLevel <= DebugLevel && ((TraceEventsFlag & DebugFlag) == TraceEventsFlag))) { KdPrint((debugMessageBuffer)); } } va_end(list); return; #else UNREFERENCED_PARAMETER(TraceEventsLevel); UNREFERENCED_PARAMETER(TraceEventsFlag); UNREFERENCED_PARAMETER(DebugMessage); #endif } #endif ================================================ FILE: tests/projects/windows/driver/kmdf/serial/log.h ================================================ /*++ Copyright (c) 1993 Microsoft Corporation :ts=4 Module Name: log.h Abstract: debug macros Environment: Kernel & user mode --*/ #ifndef __LOG_H__ #define __LOG_H__ #if !defined(EVENT_TRACING) VOID SerialDbgPrintEx ( IN ULONG DebugPrintLevel, IN ULONG DebugPrintFlag, IN PCCHAR DebugMessage, ... ); #endif #endif // __LOG_H__ ================================================ FILE: tests/projects/windows/driver/kmdf/serial/modmflow.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: modmflow.c Abstract: This module contains *MOST* of the code used to manipulate the modem control and status registers. The vast majority of the remainder of flow control is concentrated in the Interrupt service routine. A very small amount resides in the read code that pull characters out of the interrupt buffer. Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "modmflow.tmh" #endif EVT_WDF_INTERRUPT_SYNCHRONIZE SerialDecrementRTSCounter; BOOLEAN SerialSetDTR( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine which is only called at interrupt level is used to set the DTR in the modem control register. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UCHAR ModemControl; UNREFERENCED_PARAMETER(Interrupt); ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller); ModemControl |= SERIAL_MCR_DTR; SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Setting DTR for %p\n", Extension->Controller); WRITE_MODEM_CONTROL(Extension, Extension->Controller, ModemControl); return FALSE; } BOOLEAN SerialClrDTR( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine which is only called at interrupt level is used to clear the DTR in the modem control register. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UCHAR ModemControl; UNREFERENCED_PARAMETER(Interrupt); ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller); ModemControl &= ~SERIAL_MCR_DTR; SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Clearing DTR for %p\n", Extension->Controller); WRITE_MODEM_CONTROL(Extension, Extension->Controller, ModemControl); return FALSE; } BOOLEAN SerialSetRTS( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine which is only called at interrupt level is used to set the RTS in the modem control register. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UCHAR ModemControl; UNREFERENCED_PARAMETER(Interrupt); ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller); ModemControl |= SERIAL_MCR_RTS; SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Setting Rts for %p\n", Extension->Controller); WRITE_MODEM_CONTROL(Extension, Extension->Controller, ModemControl); return FALSE; } BOOLEAN SerialClrRTS( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine which is only called at interrupt level is used to clear the RTS in the modem control register. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UCHAR ModemControl; UNREFERENCED_PARAMETER(Interrupt); ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller); ModemControl &= ~SERIAL_MCR_RTS; SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Clearing Rts for %p\n", Extension->Controller); WRITE_MODEM_CONTROL(Extension, Extension->Controller, ModemControl); return FALSE; } BOOLEAN SerialSetupNewHandFlow( IN PSERIAL_DEVICE_EXTENSION Extension, IN PSERIAL_HANDFLOW NewHandFlow ) /*++ Routine Description: This routine adjusts the flow control based on new control flow. Arguments: Extension - A pointer to the serial device extension. NewHandFlow - A pointer to a serial handflow structure that is to become the new setup for flow control. Return Value: This routine always returns FALSE. --*/ { SERIAL_HANDFLOW New = *NewHandFlow; // // If the Extension->DeviceIsOpened is FALSE that means // we are entering this routine in response to an open request. // If that is so, then we always proceed with the work regardless // of whether things have changed. // // // First we take care of the DTR flow control. We only // do work if something has changed. // if ((!Extension->DeviceIsOpened) || ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) != (New.ControlHandShake & SERIAL_DTR_MASK))) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Processing DTR flow for %p\n", Extension->Controller); if (New.ControlHandShake & SERIAL_DTR_MASK) { // // Well we might want to set DTR. // // Before we do, we need to check whether we are doing // dtr flow control. If we are then we need to check // if then number of characters in the interrupt buffer // exceeds the XoffLimit. If it does then we don't // enable DTR AND we set the RXHolding to record that // we are holding because of the dtr. // if ((New.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { if ((Extension->BufferSize - New.XoffLimit) > Extension->CharsInInterruptBuffer) { // // However if we are already holding we don't want // to turn it back on unless we exceed the Xon // limit. // if (Extension->RXHolding & SERIAL_RX_DTR) { // // We can assume that its DTR line is already low. // if (Extension->CharsInInterruptBuffer > (ULONG)New.XonLimit) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Removing DTR block on " "reception for %p\n", Extension->Controller); Extension->RXHolding &= ~SERIAL_RX_DTR; SerialSetDTR(Extension->WdfInterrupt, Extension); } } else { SerialSetDTR(Extension->WdfInterrupt, Extension); } } else { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Setting DTR block on reception " "for %p\n", Extension->Controller); Extension->RXHolding |= SERIAL_RX_DTR; SerialClrDTR(Extension->WdfInterrupt, Extension); } } else { // // Note that if we aren't currently doing dtr flow control then // we MIGHT have been. So even if we aren't currently doing // DTR flow control, we should still check if RX is holding // because of DTR. If it is, then we should clear the holding // of this bit. // if (Extension->RXHolding & SERIAL_RX_DTR) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Removing dtr block of reception " "for %p\n", Extension->Controller); Extension->RXHolding &= ~SERIAL_RX_DTR; } SerialSetDTR(Extension->WdfInterrupt, Extension); } } else { // // The end result here will be that DTR is cleared. // // We first need to check whether reception is being held // up because of previous DTR flow control. If it is then // we should clear that reason in the RXHolding mask. // if (Extension->RXHolding & SERIAL_RX_DTR) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "removing dtr block of reception for" " %p\n", Extension->Controller); Extension->RXHolding &= ~SERIAL_RX_DTR; } SerialClrDTR(Extension->WdfInterrupt, Extension); } } // // Time to take care of the RTS Flow control. // // First we only do work if something has changed. // if ((!Extension->DeviceIsOpened) || ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) != (New.FlowReplace & SERIAL_RTS_MASK))) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Processing RTS flow %p\n", Extension->Controller); if ((New.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) { // // Well we might want to set RTS. // // Before we do, we need to check whether we are doing // rts flow control. If we are then we need to check // if then number of characters in the interrupt buffer // exceeds the XoffLimit. If it does then we don't // enable RTS AND we set the RXHolding to record that // we are holding because of the rts. // if ((Extension->BufferSize - New.XoffLimit) > Extension->CharsInInterruptBuffer) { // // However if we are already holding we don't want // to turn it back on unless we exceed the Xon // limit. // if (Extension->RXHolding & SERIAL_RX_RTS) { // // We can assume that its RTS line is already low. // if (Extension->CharsInInterruptBuffer > (ULONG)New.XonLimit) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Removing rts block of " "reception for %p\n", Extension->Controller); Extension->RXHolding &= ~SERIAL_RX_RTS; SerialSetRTS(Extension->WdfInterrupt, Extension); } } else { SerialSetRTS(Extension->WdfInterrupt, Extension); } } else { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Setting rts block of reception for " "%p\n", Extension->Controller); Extension->RXHolding |= SERIAL_RX_RTS; SerialClrRTS(Extension->WdfInterrupt, Extension); } } else if ((New.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_CONTROL) { // // Note that if we aren't currently doing rts flow control then // we MIGHT have been. So even if we aren't currently doing // RTS flow control, we should still check if RX is holding // because of RTS. If it is, then we should clear the holding // of this bit. // if (Extension->RXHolding & SERIAL_RX_RTS) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Clearing rts block of reception for " "%p\n", Extension->Controller); Extension->RXHolding &= ~SERIAL_RX_RTS; } SerialSetRTS(Extension->WdfInterrupt, Extension); } else if ((New.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // // We first need to check whether reception is being held // up because of previous RTS flow control. If it is then // we should clear that reason in the RXHolding mask. // if (Extension->RXHolding & SERIAL_RX_RTS) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "TOGGLE Clearing rts block of " "reception for %p\n", Extension->Controller); Extension->RXHolding &= ~SERIAL_RX_RTS; } // // We have to place the rts value into the Extension // now so that the code that tests whether the // rts line should be lowered will find that we // are "still" doing transmit toggling. The code // for lowering can be invoked later by a timer so // it has to test whether it still needs to do its // work. // Extension->HandFlow.FlowReplace &= ~SERIAL_RTS_MASK; Extension->HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE; // // The order of the tests is very important below. // // If there is a break then we should turn on the RTS. // // If there isn't a break but there are characters in // the hardware, then turn on the RTS. // // If there are writes pending that aren't being held // up, then turn on the RTS. // if ((Extension->TXHolding & SERIAL_TX_BREAK) || ((SerialProcessLSR(Extension) & (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) != (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) || (Extension->CurrentWriteRequest || Extension->TransmitImmediate || (!IsQueueEmpty(Extension->WriteQueue)) && (!Extension->TXHolding))) { SerialSetRTS(Extension->WdfInterrupt, Extension); } else { // // This routine will check to see if it is time // to lower the RTS because of transmit toggle // being on. If it is ok to lower it, it will, // if it isn't ok, it will schedule things so // that it will get lowered later. // Extension->CountOfTryingToLowerRTS++; SerialPerhapsLowerRTS(Extension->WdfInterrupt, Extension); } } else { // // The end result here will be that RTS is cleared. // // We first need to check whether reception is being held // up because of previous RTS flow control. If it is then // we should clear that reason in the RXHolding mask. // if (Extension->RXHolding & SERIAL_RX_RTS) { SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Clearing rts block of reception for" " %p\n", Extension->Controller); Extension->RXHolding &= ~SERIAL_RX_RTS; } SerialClrRTS(Extension->WdfInterrupt, Extension); } } // // We now take care of automatic receive flow control. // We only do work if things have changed. // if ((!Extension->DeviceIsOpened) || ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) != (New.FlowReplace & SERIAL_AUTO_RECEIVE))) { if (New.FlowReplace & SERIAL_AUTO_RECEIVE) { // // We wouldn't be here if it had been on before. // // We should check to see whether we exceed the turn // off limits. // // Note that since we are following the OS/2 flow // control rules we will never send an xon if // when enabling xon/xoff flow control we discover that // we could receive characters but we are held up do // to a previous Xoff. // if ((Extension->BufferSize - New.XoffLimit) <= Extension->CharsInInterruptBuffer) { // // Cause the Xoff to be sent. // Extension->RXHolding |= SERIAL_RX_XOFF; SerialProdXonXoff( Extension, FALSE ); } } else { // // The app has disabled automatic receive flow control. // // If transmission was being held up because of // an automatic receive Xoff, then we should // cause an Xon to be sent. // if (Extension->RXHolding & SERIAL_RX_XOFF) { Extension->RXHolding &= ~SERIAL_RX_XOFF; // // Cause the Xon to be sent. // SerialProdXonXoff( Extension, TRUE ); } } } // // We now take care of automatic transmit flow control. // We only do work if things have changed. // if ((!Extension->DeviceIsOpened) || ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) != (New.FlowReplace & SERIAL_AUTO_TRANSMIT))) { if (New.FlowReplace & SERIAL_AUTO_TRANSMIT) { // // We wouldn't be here if it had been on before. // // There is some belief that if autotransmit // was just enabled, I should go look in what we // already received, and if we find the xoff character // then we should stop transmitting. I think this // is an application bug. For now we just care about // what we see in the future. // ; } else { // // The app has disabled automatic transmit flow control. // // If transmission was being held up because of // an automatic transmit Xoff, then we should // cause an Xon to be sent. // if (Extension->TXHolding & SERIAL_TX_XOFF) { Extension->TXHolding &= ~SERIAL_TX_XOFF; // // Cause the Xon to be sent. // SerialProdXonXoff( Extension, TRUE ); } } } // // At this point we can simply make sure that entire // handflow structure in the extension is updated. // Extension->HandFlow = New; return FALSE; } BOOLEAN SerialSetHandFlow( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to set the handshake and control flow in the device extension. Arguments: Context - Pointer to a structure that contains a pointer to the device extension and a pointer to a handflow structure.. Return Value: This routine always returns FALSE. --*/ { PSERIAL_IOCTL_SYNC S = Context; PSERIAL_DEVICE_EXTENSION Extension = S->Extension; PSERIAL_HANDFLOW HandFlow = S->Data; UNREFERENCED_PARAMETER(Interrupt); SerialSetupNewHandFlow( Extension, HandFlow ); SerialHandleModemUpdate( Extension, FALSE ); return FALSE; } BOOLEAN SerialTurnOnBreak( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine will turn on break in the hardware and record the fact the break is on, in the extension variable that holds reasons that transmission is stopped. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UCHAR OldLineControl; UNREFERENCED_PARAMETER(Interrupt); if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { SerialSetRTS(Extension->WdfInterrupt, Extension); } OldLineControl = READ_LINE_CONTROL(Extension, Extension->Controller); OldLineControl |= SERIAL_LCR_BREAK; WRITE_LINE_CONTROL(Extension, Extension->Controller, OldLineControl ); Extension->TXHolding |= SERIAL_TX_BREAK; return FALSE; } BOOLEAN SerialTurnOffBreak( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine will turn off break in the hardware and record the fact the break is off, in the extension variable that holds reasons that transmission is stopped. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UCHAR OldLineControl; UNREFERENCED_PARAMETER(Interrupt); if (Extension->TXHolding & SERIAL_TX_BREAK) { // // We actually have a good reason for testing if transmission // is holding instead of blindly clearing the bit. // // If transmission actually was holding and the result of // clearing the bit is that we should restart transmission // then we will poke the interrupt enable bit, which will // cause an actual interrupt and transmission will then // restart on its own. // // If transmission wasn't holding and we poked the bit // then we would interrupt before a character actually made // it out and we could end up over writing a character in // the transmission hardware. OldLineControl = READ_LINE_CONTROL(Extension, Extension->Controller); OldLineControl &= ~SERIAL_LCR_BREAK; WRITE_LINE_CONTROL(Extension, Extension->Controller, OldLineControl ); Extension->TXHolding &= ~SERIAL_TX_BREAK; if (!Extension->TXHolding && (Extension->TransmitImmediate || Extension->WriteLength) && Extension->HoldingEmpty) { DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller); ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller); } else { // // The following routine will lower the rts if we // are doing transmit toggleing and there is no // reason to keep it up. // Extension->CountOfTryingToLowerRTS++; SerialPerhapsLowerRTS(Extension->WdfInterrupt, Extension); } } return FALSE; } BOOLEAN SerialPretendXoff( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to process the Ioctl that request the driver to act as if an Xoff was received. Even if the driver does not have automatic Xoff/Xon flowcontrol - This still will stop the transmission. This is the OS/2 behavior and is not well specified for Windows. Therefore we adopt the OS/2 behavior. Note: If the driver does not have automatic Xoff/Xon enabled then the only way to restart transmission is for the application to request we "act" as if we saw the xon. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UNREFERENCED_PARAMETER(Interrupt); Extension->TXHolding |= SERIAL_TX_XOFF; if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } return FALSE; } BOOLEAN SerialPretendXon( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to process the Ioctl that request the driver to act as if an Xon was received. Note: If the driver does not have automatic Xoff/Xon enabled then the only way to restart transmission is for the application to request we "act" as if we saw the xon. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UNREFERENCED_PARAMETER(Interrupt); if (Extension->TXHolding) { // // We actually have a good reason for testing if transmission // is holding instead of blindly clearing the bit. // // If transmission actually was holding and the result of // clearing the bit is that we should restart transmission // then we will poke the interrupt enable bit, which will // cause an actual interrupt and transmission will then // restart on its own. // // If transmission wasn't holding and we poked the bit // then we would interrupt before a character actually made // it out and we could end up over writing a character in // the transmission hardware. Extension->TXHolding &= ~SERIAL_TX_XOFF; if (!Extension->TXHolding && (Extension->TransmitImmediate || Extension->WriteLength) && Extension->HoldingEmpty) { DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller); ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller); } } return FALSE; } VOID SerialHandleReducedIntBuffer( IN PSERIAL_DEVICE_EXTENSION Extension ) /*++ Routine Description: This routine is called to handle a reduction in the number of characters in the interrupt (typeahead) buffer. It will check the current output flow control and re-enable transmission as needed. NOTE: This routine assumes that it is working at interrupt level. Arguments: Extension - A pointer to the device extension. Return Value: None. --*/ { // // If we are doing receive side flow control and we are // currently "holding" then because we've emptied out // some characters from the interrupt buffer we need to // see if we can "re-enable" reception. // if (Extension->RXHolding) { if (Extension->CharsInInterruptBuffer <= (ULONG)Extension->HandFlow.XonLimit) { if (Extension->RXHolding & SERIAL_RX_DTR) { Extension->RXHolding &= ~SERIAL_RX_DTR; SerialSetDTR(Extension->WdfInterrupt, Extension); } if (Extension->RXHolding & SERIAL_RX_RTS) { Extension->RXHolding &= ~SERIAL_RX_RTS; SerialSetRTS(Extension->WdfInterrupt, Extension); } if (Extension->RXHolding & SERIAL_RX_XOFF) { // // Prod the transmit code to send xon. // SerialProdXonXoff( Extension, TRUE ); } } } } VOID SerialProdXonXoff( IN PSERIAL_DEVICE_EXTENSION Extension, IN BOOLEAN SendXon ) /*++ Routine Description: This routine will set up the SendXxxxChar variables if necessary and determine if we are going to be interrupting because of current transmission state. It will cause an interrupt to occur if neccessary, to send the xon/xoff char. NOTE: This routine assumes that it is called at interrupt level. Arguments: Extension - A pointer to the serial device extension. SendXon - If a character is to be send, this indicates whether it should be an Xon or an Xoff. Return Value: None. --*/ { // // We assume that if the prodding is called more than // once that the last prod has set things up appropriately. // // We could get called before the character is sent out // because the send of the character was blocked because // of hardware flow control (or break). // if (!Extension->SendXonChar && !Extension->SendXoffChar && Extension->HoldingEmpty) { DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller); ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller); } if (SendXon) { Extension->SendXonChar = TRUE; Extension->SendXoffChar = FALSE; } else { Extension->SendXonChar = FALSE; Extension->SendXoffChar = TRUE; } } ULONG SerialHandleModemUpdate( IN PSERIAL_DEVICE_EXTENSION Extension, IN BOOLEAN DoingTX ) /*++ Routine Description: This routine will be to check on the modem status, and handle any appropriate event notification as well as any flow control appropriate to modem status lines. NOTE: This routine assumes that it is called at interrupt level. Arguments: Extension - A pointer to the serial device extension. DoingTX - This boolean is used to indicate that this call came from the transmit processing code. If this is true then there is no need to cause a new interrupt since the code will be trying to send the next character as soon as this call finishes. Return Value: This returns the old value of the modem status register (extended into a ULONG). --*/ { // // We keep this local so that after we are done // examining the modem status and we've updated // the transmission holding value, we know whether // we've changed from needing to hold up transmission // to transmission being able to proceed. // ULONG OldTXHolding = Extension->TXHolding; // // Holds the value in the mode status register. // UCHAR ModemStatus; PREQUEST_CONTEXT reqContext; ModemStatus = READ_MODEM_STATUS(Extension, Extension->Controller); // // If we are placeing the modem status into the data stream // on every change, we should do it now. // if (Extension->EscapeChar) { if (ModemStatus & (SERIAL_MSR_DCTS | SERIAL_MSR_DDSR | SERIAL_MSR_TERI | SERIAL_MSR_DDCD)) { SerialPutChar( Extension, Extension->EscapeChar ); SerialPutChar( Extension, SERIAL_LSRMST_MST ); SerialPutChar( Extension, ModemStatus ); } } // // Take care of input flow control based on sensitivity // to the DSR. This is done so that the application won't // see spurious data generated by odd devices. // // Basically, if we are doing dsr sensitivity then the // driver should only accept data when the dsr bit is // set. // if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) { if (ModemStatus & SERIAL_MSR_DSR) { // // The line is high. Simply make sure that // RXHolding does't have the DSR bit. // Extension->RXHolding &= ~SERIAL_RX_DSR; } else { Extension->RXHolding |= SERIAL_RX_DSR; } } else { // // We don't have sensitivity due to DSR. Make sure we // arn't holding. (We might have been, but the app just // asked that we don't hold for this reason any more.) // Extension->RXHolding &= ~SERIAL_RX_DSR; } // // Check to see if we have a wait // pending on the modem status events. If we // do then we schedule a dpc to satisfy // that wait. // if (Extension->IsrWaitMask) { if ((Extension->IsrWaitMask & SERIAL_EV_CTS) && (ModemStatus & SERIAL_MSR_DCTS)) { Extension->HistoryMask |= SERIAL_EV_CTS; } if ((Extension->IsrWaitMask & SERIAL_EV_DSR) && (ModemStatus & SERIAL_MSR_DDSR)) { Extension->HistoryMask |= SERIAL_EV_DSR; } if ((Extension->IsrWaitMask & SERIAL_EV_RING) && (ModemStatus & SERIAL_MSR_TERI)) { Extension->HistoryMask |= SERIAL_EV_RING; } if ((Extension->IsrWaitMask & SERIAL_EV_RLSD) && (ModemStatus & SERIAL_MSR_DDCD)) { Extension->HistoryMask |= SERIAL_EV_RLSD; } if (Extension->IrpMaskLocation && Extension->HistoryMask) { *Extension->IrpMaskLocation = Extension->HistoryMask; Extension->IrpMaskLocation = NULL; Extension->HistoryMask = 0; reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest); reqContext->Information = sizeof(ULONG); SerialInsertQueueDpc( Extension->CommWaitDpc ); } } // // If the app has modem line flow control then // we check to see if we have to hold up transmission. // if (Extension->HandFlow.ControlHandShake & SERIAL_OUT_HANDSHAKEMASK) { if (Extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) { if (ModemStatus & SERIAL_MSR_CTS) { Extension->TXHolding &= ~SERIAL_TX_CTS; } else { Extension->TXHolding |= SERIAL_TX_CTS; } } else { Extension->TXHolding &= ~SERIAL_TX_CTS; } if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) { if (ModemStatus & SERIAL_MSR_DSR) { Extension->TXHolding &= ~SERIAL_TX_DSR; } else { Extension->TXHolding |= SERIAL_TX_DSR; } } else { Extension->TXHolding &= ~SERIAL_TX_DSR; } if (Extension->HandFlow.ControlHandShake & SERIAL_DCD_HANDSHAKE) { if (ModemStatus & SERIAL_MSR_DCD) { Extension->TXHolding &= ~SERIAL_TX_DCD; } else { Extension->TXHolding |= SERIAL_TX_DCD; } } else { Extension->TXHolding &= ~SERIAL_TX_DCD; } // // If we hadn't been holding, and now we are then // queue off a dpc that will lower the RTS line // if we are doing transmit toggling. // if (!OldTXHolding && Extension->TXHolding && ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } // // We've done any adjusting that needed to be // done to the holding mask given updates // to the modem status. If the Holding mask // is clear (and it wasn't clear to start) // and we have "write" work to do set things // up so that the transmission code gets invoked. // if (!DoingTX && OldTXHolding && !Extension->TXHolding) { if (!Extension->TXHolding && (Extension->TransmitImmediate || Extension->WriteLength) && Extension->HoldingEmpty) { DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller); ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller); } } } else { // // We need to check if transmission is holding // up because of modem status lines. What // could have occured is that for some strange // reason, the app has asked that we no longer // stop doing output flow control based on // the modem status lines. If however, we // *had* been held up because of the status lines // then we need to clear up those reasons. // if (Extension->TXHolding & (SERIAL_TX_DCD | SERIAL_TX_DSR | SERIAL_TX_CTS)) { Extension->TXHolding &= ~(SERIAL_TX_DCD | SERIAL_TX_DSR | SERIAL_TX_CTS); if (!DoingTX && OldTXHolding && !Extension->TXHolding) { if (!Extension->TXHolding && (Extension->TransmitImmediate || Extension->WriteLength) && Extension->HoldingEmpty) { DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller); ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller); } } } } return ((ULONG)ModemStatus); } BOOLEAN SerialPerhapsLowerRTS( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine checks that the software reasons for lowering the RTS lines are present. If so, it will then cause the line status register to be read (and any needed processing implied by the status register to be done), and if the shift register is empty it will lower the line. If the shift register isn't empty, this routine will queue off a dpc that will start a timer, that will basically call us back to try again. NOTE: This routine assumes that it is called at interrupt level. Arguments: Context - Really a pointer to the device extension. Return Value: Always FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UNREFERENCED_PARAMETER(Interrupt); // // We first need to test if we are actually still doing // transmit toggle flow control. If we aren't then // we have no reason to try be here. // if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // // The order of the tests is very important below. // // If there is a break then we should leave on the RTS, // because when the break is turned off, it will submit // the code to shut down the RTS. // // If there are writes pending that aren't being held // up, then leave on the RTS, because the end of the write // code will cause this code to be reinvoked. If the writes // are being held up, its ok to lower the RTS because the // upon trying to write the first character after transmission // is restarted, we will raise the RTS line. // if ((Extension->TXHolding & SERIAL_TX_BREAK) || (Extension->CurrentWriteRequest || Extension->TransmitImmediate || (!IsQueueEmpty(Extension->WriteQueue)) && (!Extension->TXHolding))) { NOTHING; } else { // // Looks good so far. Call the line status check and processing // code, it will return the "current" line status value. If // the holding and shift register are clear, lower the RTS line, // if they aren't clear, queue of a dpc that will cause a timer // to reinvoke us later. We do this code here because no one // but this routine cares about the characters in the hardware, // so no routine by this routine will bother invoking to test // if the hardware is empty. // if ((SerialProcessLSR(Extension) & (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) != (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) { // // Well it's not empty, try again later. // SerialInsertQueueDpc( Extension->StartTimerLowerRTSDpc )?Extension->CountOfTryingToLowerRTS++:0; } else { // // Nothing in the hardware, Lower the RTS. // SerialClrRTS(Extension->WdfInterrupt, Extension); } } } // // We decement the counter to indicate that we've reached // the end of the execution path that is trying to push // down the RTS line. // Extension->CountOfTryingToLowerRTS--; return FALSE; } VOID SerialStartTimerLowerRTS( IN WDFDPC Dpc ) /*++ Routine Description: This routine starts a timer that when it expires will start a dpc that will check if it can lower the rts line because there are no characters in the hardware. Arguments: Dpc - Not Used. DeferredContext - Really points to the device extension. SystemContext1 - Not Used. SystemContext2 - Not Used. Return Value: None. --*/ { LARGE_INTEGER CharTime; PSERIAL_DEVICE_EXTENSION Extension = NULL; Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc)); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, ">SerialStartTimerLowerRTS(%p)\n", Extension); // // Since all the callbacks into the driver are serialized, we don't have // synchronize the access to any of the Extension variables. // CharTime = SerialGetCharTime(Extension); CharTime.QuadPart = -CharTime.QuadPart; if (SerialSetTimer( Extension->LowerRTSTimer, CharTime )) { // // The timer was already in the timer queue. This implies // that one path of execution that was trying to lower // the RTS has "died". Synchronize with the ISR so that // we can lower the count. // WdfInterruptSynchronize( Extension->WdfInterrupt, SerialDecrementRTSCounter, Extension ); } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "WdfInterrupt, SerialPerhapsLowerRTS, Extension ); } BOOLEAN SerialDecrementRTSCounter( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine checks that the software reasons for lowering the RTS lines are present. If so, it will then cause the line status register to be read (and any needed processing implied by the status register to be done), and if the shift register is empty it will lower the line. If the shift register isn't empty, this routine will queue off a dpc that will start a timer, that will basically call us back to try again. NOTE: This routine assumes that it is called at interrupt level. Arguments: Context - Really a pointer to the device extension. Return Value: Always FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UNREFERENCED_PARAMETER(Interrupt); Extension->CountOfTryingToLowerRTS--; return FALSE; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/openclos.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: openclos.c Abstract: This module contains the code that is very specific to opening, closing, and cleaning up in the serial driver. Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "openclos.tmh" #endif #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGESER,SerialGetCharTime) #pragma alloc_text(PAGESER,SerialEvtFileClose) #pragma alloc_text(PAGESER,SerialDrainUART) #pragma alloc_text(PAGESRP0,SerialEvtDeviceFileCreate) #pragma alloc_text(PAGESRP0,SerialCreateTimersAndDpcs) #endif // ALLOC_PRAGMA VOID SerialEvtDeviceFileCreate ( IN WDFDEVICE Device, IN WDFREQUEST Request, IN WDFFILEOBJECT FileObject ) /*++ Routine Description: The framework calls a driver's EvtDeviceFileCreate callback when the framework receives an IRP_MJ_CREATE request. The system sends this request when a user application opens the device to perform an I/O operation, such as reading or writing a file. This callback is called synchronously, in the context of the thread that created the IRP_MJ_CREATE request. Arguments: Device - Handle to a framework device object. FileObject - Pointer to fileobject that represents the open handle. CreateParams - Copy of the Create IO_STACK_LOCATION Return Value: VOID. --*/ { NTSTATUS status; PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device); UNREFERENCED_PARAMETER(FileObject); PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE, "SerialEvtDeviceFileCreate %wZ\n", &extension->DeviceName); status = SerialDeviceFileCreateWorker(Device); // // Complete the WDF request. // WdfRequestComplete(Request, status); return; } NTSTATUS SerialWdmDeviceFileCreate ( IN WDFDEVICE Device, IN PIRP Irp ) /*++ Routine Description: This is the dispatch routine for IRP_MJ_CREATE. The system sends this request when a user application opens the device to perform an I/O operation, such as reading or writing a file. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: NT status code --*/ { NTSTATUS status; PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE, "SerialWdmDeviceFileCreate %wZ\n", &extension->DeviceName); status = SerialDeviceFileCreateWorker(Device); // // Complete the WDM request. // Irp->IoStatus.Information = 0L; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } NTSTATUS SerialDeviceFileCreateWorker ( IN WDFDEVICE Device ) { NTSTATUS status; PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device); // // Create a buffer for the RX data when no reads are outstanding. // extension->InterruptReadBuffer = NULL; extension->BufferSize = 0; switch (MmQuerySystemSize()) { case MmLargeSystem: { extension->BufferSize = 4096; extension->InterruptReadBuffer = ExAllocatePoolWithTag( NonPagedPoolNx, extension->BufferSize, POOL_TAG ); if (extension->InterruptReadBuffer) { break; } } case MmMediumSystem: { extension->BufferSize = 1024; extension->InterruptReadBuffer = ExAllocatePoolWithTag( NonPagedPoolNx, extension->BufferSize, POOL_TAG ); if (extension->InterruptReadBuffer) { break; } } case MmSmallSystem: { extension->BufferSize = 128; extension->InterruptReadBuffer = ExAllocatePoolWithTag( NonPagedPoolNx, extension->BufferSize, POOL_TAG ); } } if (!extension->InterruptReadBuffer) { return STATUS_INSUFFICIENT_RESOURCES; } // // By taking a power reference by calling WdfDeviceStopIdle, we prevent the // framework from powering down our device due to idle timeout when there // is an open handle. Power reference also moves the device to D0 if we are // idled out. If you fail create anywhere later in this routine, do make sure // drop the reference. // status = WdfDeviceStopIdle(Device, TRUE); if (!NT_SUCCESS(status)) { return status; } // // wakeup is not currently enabled // extension->IsWakeEnabled = FALSE; // // On a new open we "flush" the read queue by initializing the // count of characters. // extension->CharsInInterruptBuffer = 0; extension->LastCharSlot = extension->InterruptReadBuffer + (extension->BufferSize - 1); extension->ReadBufferBase = extension->InterruptReadBuffer; extension->CurrentCharSlot = extension->InterruptReadBuffer; extension->FirstReadableChar = extension->InterruptReadBuffer; extension->TotalCharsQueued = 0; // // We set up the default xon/xoff limits. // extension->HandFlow.XoffLimit = extension->BufferSize >> 3; extension->HandFlow.XonLimit = extension->BufferSize >> 1; extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit; extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit; extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+ (extension->BufferSize>>4)); // // Mark the device as busy for WMI // extension->WmiCommData.IsBusy = TRUE; extension->IrpMaskLocation = NULL; extension->HistoryMask = 0; extension->IsrWaitMask = 0; extension->SendXonChar = FALSE; extension->SendXoffChar = FALSE; #if !DBG // // Clear out the statistics. // WdfInterruptSynchronize( extension->WdfInterrupt, SerialClearStats, extension ); #endif // // The escape char replacement must be reset upon every open. // extension->EscapeChar = 0; // // We don't want the device to be removed or stopped when there is an handle // // Note to anyone copying this sample as a starting point: // // This works in this driver simply because this driver supports exactly // one open handle at a time. If it supported more, then it would need // counting logic to determine when all the reasons for failing Stop/Remove // were gone. // WdfDeviceSetStaticStopRemove(Device, FALSE); // // Synchronize with the ISR and let it know that the device // has been successfully opened. // WdfInterruptSynchronize( extension->WdfInterrupt, SerialMarkOpen, extension ); return STATUS_SUCCESS; } VOID SerialEvtFileClose( IN WDFFILEOBJECT FileObject ) /*++ EvtFileClose is called when all the handles represented by the FileObject is closed and all the references to FileObject is removed. This callback may get called in an arbitrary thread context instead of the thread that called CloseHandle. If you want to delete any per FileObject context that must be done in the context of the user thread that made the Create call, you should do that in the EvtDeviceCleanp callback. Arguments: FileObject - Pointer to fileobject that represents the open handle. Return Value: VOID --*/ { PAGED_CODE(); SerialFileCloseWorker(WdfFileObjectGetDevice(FileObject)); return; } NTSTATUS SerialWdmFileClose ( IN WDFDEVICE Device, IN PIRP Irp ) /*++ Routine Description: This is the dispatch routine for IRP_MJ_CLOSE. This is called when all the handles represented by the FileObject is closed and all the references to the FileObject is removed. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: NT status code --*/ { SerialFileCloseWorker(Device); Irp->IoStatus.Information = 0L; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } VOID SerialFileCloseWorker( IN WDFDEVICE Device ) { ULONG flushCount; // // This "timer value" is used to wait 10 character times // after the hardware is empty before we actually "run down" // all of the flow control/break junk. // LARGE_INTEGER tenCharDelay; // // Holds a character time. // LARGE_INTEGER charTime; PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(Device); PSERIAL_INTERRUPT_CONTEXT interruptContext = SerialGetInterruptContext(extension->WdfInterrupt); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE, "In SerialEvtFileClose %wZ\n", &extension->DeviceName); // // Acquire the interrupt state lock. // WdfWaitLockAcquire(interruptContext->InterruptStateLock, NULL); // // If the Interrupts are connected, then the hardware state has to be // cleaned up now. Note that the EvtFileClose callback gets called for // an open file object even though the interrupts have been disabled // possibly due to a Surprise Remove PNP event. In such a case, the // Interrupt object should not be used. // if (interruptContext->IsInterruptConnected) { charTime.QuadPart = -SerialGetCharTime(extension).QuadPart; // // Do this now so that if the isr gets called it won't do anything // to cause more chars to get sent. We want to run down the hardware. // SetDeviceIsOpened(extension, FALSE, FALSE); // // Synchronize with the isr to turn off break if it // is already on. // WdfInterruptSynchronize( extension->WdfInterrupt, SerialTurnOffBreak, extension ); // // Wait a reasonable amount of time (20 * fifodepth) until all characters // have been emptied out of the hardware. // for (flushCount = (20 * 16); flushCount != 0; flushCount--) { if ((READ_LINE_STATUS(extension, extension->Controller) & (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) != (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) { KeDelayExecutionThread(KernelMode, FALSE, &charTime); } else { break; } } if (flushCount == 0) { SerialMarkHardwareBroken(extension); } // // Synchronize with the ISR to let it know that interrupts are // no longer important. // WdfInterruptSynchronize( extension->WdfInterrupt, SerialMarkClose, extension ); // // If the driver has automatically transmitted an Xoff in // the context of automatic receive flow control then we // should transmit an Xon. // if (extension->RXHolding & SERIAL_RX_XOFF) { // // Loop until the holding register is empty. // while (!(READ_LINE_STATUS(extension, extension->Controller) & SERIAL_LSR_THRE)) { KeDelayExecutionThread( KernelMode, FALSE, &charTime ); } WRITE_TRANSMIT_HOLDING(extension, extension->Controller, extension->SpecialChars.XonChar ); // // Wait a reasonable amount of time for the characters // to be emptied out of the hardware. // for (flushCount = (20 * 16); flushCount != 0; flushCount--) { if ((READ_LINE_STATUS(extension, extension->Controller) & (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) != (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) { KeDelayExecutionThread(KernelMode, FALSE, &charTime); } else { break; } } if (flushCount == 0) { SerialMarkHardwareBroken(extension); } } // // The hardware is empty. Delay 10 character times before // shut down all the flow control. // tenCharDelay.QuadPart = charTime.QuadPart * 10; KeDelayExecutionThread( KernelMode, TRUE, &tenCharDelay ); #pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, "This warning is because we are calling interrupt synchronize routine directly.") SerialClrDTR(extension->WdfInterrupt, extension); // // We have to be very careful how we clear the RTS line. // Transmit toggling might have been on at some point. // // We know that there is nothing left that could start // out the "polling" execution path. We need to // check the counter that indicates that the execution // path is active. If it is then we loop delaying one // character time. After each delay we check to see if // the counter has gone to zero. When it has we know that // the execution path should be just about finished. We // make sure that we still aren't in the routine that // synchronized execution with the ISR by synchronizing // ourselve with the ISR. // if (extension->CountOfTryingToLowerRTS) { do { #pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_HIGH, "This warning is due to suppressing the previous one.") KeDelayExecutionThread( KernelMode, FALSE, &charTime ); } while (extension->CountOfTryingToLowerRTS); // // The execution path should no longer exist that // is trying to push down the RTS. Well just // make sure it's down by falling through to // code that forces it down. // } #pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, "This warning is because we are calling interrupt synchronize routine directly.") SerialClrRTS(extension->WdfInterrupt, extension); // // Clean out the holding reasons (since we are closed). // extension->RXHolding = 0; extension->TXHolding = 0; // // Mark device as not busy for WMI // extension->WmiCommData.IsBusy = FALSE; } // // Release the Interrupt state lock. // WdfWaitLockRelease(interruptContext->InterruptStateLock); // // All is done. The port has been disabled from interrupting // so there is no point in keeping the memory around. // extension->BufferSize = 0; if (extension->InterruptReadBuffer != NULL) { ExFreePool(extension->InterruptReadBuffer); } extension->InterruptReadBuffer = NULL; // // Make sure the wake is disabled. // ASSERT(!extension->IsWakeEnabled); SerialDrainTimersAndDpcs(extension); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_CREATE_CLOSE, "DPC's drained:\n"); // // It's fine for the device to be powered off if there are no open handles. // WdfDeviceResumeIdle(Device); // // It's okay to allow the device to be stopped or removed. // // Note to anyone copying this sample as a starting point: // // This works in this driver simply because this driver supports exactly // one open handle at a time. If it supported more, then it would need // counting logic to determine when all the reasons for failing Stop/Remove // were gone. // WdfDeviceSetStaticStopRemove(Device, TRUE); return; } BOOLEAN SerialMarkOpen( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine merely sets a boolean to true to mark the fact that somebody opened the device and its worthwhile to pay attention to interrupts. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION extension = Context; UNREFERENCED_PARAMETER(Interrupt); SerialReset(extension->WdfInterrupt, extension); // // Prepare for the opening by re-enabling interrupts. // // We do this my modifying the OUT2 line in the modem control. // In PC's this bit is "anded" with the interrupt line. // WRITE_MODEM_CONTROL(extension, extension->Controller, (UCHAR)(READ_MODEM_CONTROL(extension, extension->Controller) | SERIAL_MCR_OUT2) ); extension->DeviceIsOpened = TRUE; extension->ErrorWord = 0; return FALSE; } VOID SerialDrainUART(IN PSERIAL_DEVICE_EXTENSION PDevExt, IN PLARGE_INTEGER PDrainTime) { PAGED_CODE(); // // Wait until all characters have been emptied out of the hardware. // while ((READ_LINE_STATUS(PDevExt, PDevExt->Controller) & (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) != (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) { KeDelayExecutionThread(KernelMode, FALSE, PDrainTime); } } VOID SerialDisableUART(IN PVOID Context) /*++ Routine Description: This routine disables the UART and puts it in a "safe" state when not in use (like a close or powerdown). Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION extension = Context; // // Prepare for the closing by stopping interrupts. // // We do this by adjusting the OUT2 line in the modem control. // In PC's this bit is "anded" with the interrupt line. // WRITE_MODEM_CONTROL(extension, extension->Controller, (UCHAR)(READ_MODEM_CONTROL(extension, extension->Controller) & ~SERIAL_MCR_OUT2)); if (extension->FifoPresent) { WRITE_FIFO_CONTROL(extension, extension->Controller, (UCHAR)0); } } BOOLEAN SerialMarkClose( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine merely sets a boolean to false to mark the fact that somebody closed the device and it's no longer worthwhile to pay attention to interrupts. It also disables the UART. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION extension = Context; UNREFERENCED_PARAMETER(Interrupt); SerialDisableUART(Context); extension->DeviceIsOpened = FALSE; extension->DeviceState.Reopen = FALSE; return FALSE; } LARGE_INTEGER SerialGetCharTime( IN PSERIAL_DEVICE_EXTENSION Extension ) /*++ Routine Description: This function will return the number of 100 nanosecond intervals there are in one character time (based on the present form of flow control. Arguments: Extension - Just what it says. Return Value: 100 nanosecond intervals in a character time. --*/ { ULONG dataSize = 0; ULONG paritySize; ULONG stopSize; ULONG charTime; ULONG bitTime; LARGE_INTEGER tmp; PAGED_CODE(); if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) { dataSize = 5; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_6_DATA) { dataSize = 6; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_7_DATA) { dataSize = 7; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_8_DATA) { dataSize = 8; } paritySize = 1; if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_NONE_PARITY) { paritySize = 0; } if (Extension->LineControl & SERIAL_2_STOP) { // // Even if it is 1.5, for sanities sake were going // to say 2. // stopSize = 2; } else { stopSize = 1; } // // First we calculate the number of 100 nanosecond intervals // are in a single bit time (Approximately). // bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud; charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime); tmp.QuadPart = charTime; return tmp; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/pnp.c ================================================ /*++ Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation Module Name: pnp.c Abstract: This module contains the code that handles the plug and play IRPs for the serial driver. Environment: Kernel mode --*/ #include "precomp.h" #include #include #include #if defined(EVENT_TRACING) #include "pnp.tmh" #endif static const PHYSICAL_ADDRESS SerialPhysicalZero = {0}; static const SUPPORTED_BAUD_RATES SupportedBaudRates[] = { {75, SERIAL_BAUD_075}, {110, SERIAL_BAUD_110}, {135, SERIAL_BAUD_134_5}, {150, SERIAL_BAUD_150}, {300, SERIAL_BAUD_300}, {600, SERIAL_BAUD_600}, {1200, SERIAL_BAUD_1200}, {1800, SERIAL_BAUD_1800}, {2400, SERIAL_BAUD_2400}, {4800, SERIAL_BAUD_4800}, {7200, SERIAL_BAUD_7200}, {9600, SERIAL_BAUD_9600}, {14400, SERIAL_BAUD_14400}, {19200, SERIAL_BAUD_19200}, {38400, SERIAL_BAUD_38400}, {56000, SERIAL_BAUD_56K}, {57600, SERIAL_BAUD_57600}, {115200, SERIAL_BAUD_115200}, {128000, SERIAL_BAUD_128K}, {SERIAL_BAUD_INVALID, SERIAL_BAUD_USER} }; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGESRP0, SerialEvtDeviceAdd) #pragma alloc_text(PAGESRP0, SerialEvtPrepareHardware) #pragma alloc_text(PAGESRP0, SerialEvtReleaseHardware) #pragma alloc_text(PAGESRP0, SerialEvtDeviceD0ExitPreInterruptsDisabled) #pragma alloc_text(PAGESRP0, SerialMapHWResources) #pragma alloc_text(PAGESRP0, SerialUnmapHWResources) #pragma alloc_text(PAGESRP0, SerialEvtDeviceContextCleanup) #pragma alloc_text(PAGESRP0, SerialDoExternalNaming) #pragma alloc_text(PAGESRP0, SerialReportMaxBaudRate) #pragma alloc_text(PAGESRP0, SerialUndoExternalNaming) #pragma alloc_text(PAGESRP0, SerialInitController) #pragma alloc_text(PAGESRP0, SerialGetMappedAddress) #pragma alloc_text(PAGESRP0, SerialSetPowerPolicy) #pragma alloc_text(PAGESRP0, SerialReadSymName) #endif // ALLOC_PRAGMA PVOID LocalMmMapIoSpace( _In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ SIZE_T NumberOfBytes ) { typedef PVOID (*PFN_MM_MAP_IO_SPACE_EX) ( _In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Protect ); UNICODE_STRING name; PFN_MM_MAP_IO_SPACE_EX pMmMapIoSpaceEx; RtlInitUnicodeString(&name, L"MmMapIoSpaceEx"); pMmMapIoSpaceEx = (PFN_MM_MAP_IO_SPACE_EX) (ULONG_PTR)MmGetSystemRoutineAddress(&name); if (pMmMapIoSpaceEx != NULL){ // // Call WIN10 API if available // return pMmMapIoSpaceEx(PhysicalAddress, NumberOfBytes, PAGE_READWRITE | PAGE_NOCACHE); } // // Supress warning that MmMapIoSpace allocates executable memory. // This function is only used if the preferred API, MmMapIoSpaceEx // is not present. MmMapIoSpaceEx is available starting in WIN10. // #pragma warning(suppress: 30029) return MmMapIoSpace(PhysicalAddress, NumberOfBytes, MmNonCached); } NTSTATUS SerialEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { NTSTATUS status; PSERIAL_DEVICE_EXTENSION pDevExt; static ULONG currentInstance = 0; WDF_FILEOBJECT_CONFIG fileobjectConfig; WDFDEVICE device; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES attributes; WDF_IO_QUEUE_CONFIG queueConfig; WDFQUEUE defaultqueue; ULONG isMulti; PULONG countSoFar; WDF_INTERRUPT_CONFIG interruptConfig; PSERIAL_INTERRUPT_CONTEXT interruptContext; ULONG relinquishPowerPolicy; DECLARE_UNICODE_STRING_SIZE(deviceName, DEVICE_OBJECT_NAME_LENGTH); PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "-->SerialEvtDeviceAdd\n"); status = RtlUnicodeStringPrintf(&deviceName, L"%ws%u", L"\\Device\\Serial", currentInstance++); if (!NT_SUCCESS(status)) { return status; } status = WdfDeviceInitAssignName(DeviceInit,& deviceName); if (!NT_SUCCESS(status)) { return status; } WdfDeviceInitSetExclusive(DeviceInit, TRUE); WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SERIAL_PORT); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); WdfDeviceInitSetRequestAttributes(DeviceInit, &attributes); // // Zero out the PnpPowerCallbacks structure. // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // Set Callbacks for any of the functions we are interested in. // If no callback is set, Framework will take the default action // by itself. These next two callbacks set up and tear down hardware state, // specifically that which only has to be done once. // pnpPowerCallbacks.EvtDevicePrepareHardware = SerialEvtPrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = SerialEvtReleaseHardware; // // These two callbacks set up and tear down hardware state that must be // done every time the device moves in and out of the D0-working state. // pnpPowerCallbacks.EvtDeviceD0Entry = SerialEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = SerialEvtDeviceD0Exit; // // Specify the callback for monitoring when the device's interrupt are // enabled or about to be disabled. // pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = SerialEvtDeviceD0EntryPostInterruptsEnabled; pnpPowerCallbacks.EvtDeviceD0ExitPreInterruptsDisabled = SerialEvtDeviceD0ExitPreInterruptsDisabled; // // Register the PnP and power callbacks. // WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); if ( !NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceInitSetPnpPowerEventCallbacks failed %!STATUS!\n", status); return status; } // // Find out if we own power policy // SerialGetFdoRegistryKeyValue( DeviceInit, L"SerialRelinquishPowerPolicy", &relinquishPowerPolicy ); if(relinquishPowerPolicy) { // // FDO's are assumed to be power policy owner by default. So tell // the framework explicitly to relinquish the power policy ownership. // SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "RelinquishPowerPolicy due to registry settings\n"); WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE); } // // For Windows XP and below, we will register for the WDM Preprocess callback // for IRP_MJ_CREATE. This is done because, the Serenum filter doesn't handle // creates that are marked pending. Since framework always marks the IRP pending, // we are registering this WDM preprocess handler so that we can bypass the // framework and handle the create and close ourself. This workaround is need // only if you intend to install the Serenum as an upper filter. // if (RtlIsNtDdiVersionAvailable(NTDDI_VISTA) == FALSE) { status = WdfDeviceInitAssignWdmIrpPreprocessCallback( DeviceInit, SerialWdmDeviceFileCreate, IRP_MJ_CREATE, NULL, // pointer minor function table 0); // number of entries in the table if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\n", status); return status; } status = WdfDeviceInitAssignWdmIrpPreprocessCallback( DeviceInit, SerialWdmFileClose, IRP_MJ_CLOSE, NULL, // pointer minor function table 0); // number of entries in the table if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\n", status); return status; } } else { // // FileEvents can opt for Device level synchronization only if the ExecutionLevel // of the Device is passive. Since we can't choose passive execution-level for // device because we have chose to synchronize timers & dpcs with the device, // we will opt out of synchonization with the device for fileobjects. // Note: If the driver has to synchronize Create with the other I/O events, // it can create a queue and configure-dispatch create requests to the queue. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.SynchronizationScope = WdfSynchronizationScopeNone; // // Set Entry points for Create and Close.. // WDF_FILEOBJECT_CONFIG_INIT( &fileobjectConfig, SerialEvtDeviceFileCreate, SerialEvtFileClose, WDF_NO_EVENT_CALLBACK // Cleanup ); WdfDeviceInitSetFileObjectConfig( DeviceInit, &fileobjectConfig, &attributes ); } // // Since framework queues doesn't handle IRP_MJ_FLUSH_BUFFERS, // IRP_MJ_QUERY_INFORMATION and IRP_MJ_SET_INFORMATION requests, // we will register a preprocess callback to handle them. // status = WdfDeviceInitAssignWdmIrpPreprocessCallback( DeviceInit, SerialFlush, IRP_MJ_FLUSH_BUFFERS, NULL, // pointer minor function table 0); // number of entries in the table if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\n", status); return status; } status = WdfDeviceInitAssignWdmIrpPreprocessCallback( DeviceInit, SerialQueryInformationFile, IRP_MJ_QUERY_INFORMATION, NULL, // pointer minor function table 0); // number of entries in the table if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\n", status); return status; } status = WdfDeviceInitAssignWdmIrpPreprocessCallback( DeviceInit, SerialSetInformationFile, IRP_MJ_SET_INFORMATION, NULL, // pointer minor function table 0); // number of entries in the table if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\n", status); return status; } // // Create a device // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE (&attributes, SERIAL_DEVICE_EXTENSION); // // Provide a callback to cleanup the context. This will be called // when the device is removed. // attributes.EvtCleanupCallback = SerialEvtDeviceContextCleanup; // // By opting for SynchronizationScopeDevice, we tell the framework to // synchronize callbacks events of all the objects directly associated // with the device. In this driver, we will associate queues, dpcs, // and timers. By doing that we don't have to worrry about synchronizing // access to device-context by Io Events, cancel-routine, timer and dpc // callbacks. // attributes.SynchronizationScope = WdfSynchronizationScopeDevice; status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "SerialAddDevice - WdfDeviceCreate failed %!STATUS!\n", status); return status; } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "Created device (%p) %wZ\n", device, &deviceName); pDevExt = SerialGetDeviceExtension (device); pDevExt->DriverObject = WdfDriverWdmGetDriverObject(Driver); // // This sample doesn't support multiport serial devices. // Multiport devices allow other pseudo-serial devices with extra // resources to specify another range of I/O ports. // if(!SerialGetRegistryKeyValue(device, L"MultiportDevice", &isMulti)) { isMulti = 0; } if(isMulti) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "This sample doesn't support multiport devices\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } // // Set up the device extension. // pDevExt = SerialGetDeviceExtension (device); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "AddDevice PDO(0x%p) FDO(0x%p), Lower(0x%p) DevExt (0x%p)\n", WdfDeviceWdmGetPhysicalDevice (device), WdfDeviceWdmGetDeviceObject (device), WdfDeviceWdmGetAttachedDevice(device), pDevExt); pDevExt->DeviceIsOpened = FALSE; pDevExt->DeviceObject = WdfDeviceWdmGetDeviceObject(device); pDevExt->WdfDevice = device; pDevExt->TxFifoAmount = driverDefaults.TxFIFODefault; pDevExt->UartRemovalDetect = driverDefaults.UartRemovalDetect; pDevExt->CreatedSymbolicLink = FALSE; pDevExt->OwnsPowerPolicy = relinquishPowerPolicy ? FALSE : TRUE; status = SerialSetPowerPolicy(pDevExt); if(!NT_SUCCESS(status)){ return status; } // // We create four manual queues below. // Read Queue..(how about using serial queue for read). Since requests // jump from queue to queue, we cannot configure the queues to receive a // particular type of request. For example, some of the IOCTLs end up // in read and write queue. // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); queueConfig.EvtIoStop = SerialEvtIoStop; queueConfig.EvtIoResume = SerialEvtIoResume; queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue; status = WdfIoQueueCreate (device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevExt->ReadQueue ); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, " WdfIoQueueCreate for Read failed %!STATUS!\n", status); return status; } // // Write Queue.. // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); queueConfig.EvtIoStop = SerialEvtIoStop; queueConfig.EvtIoResume = SerialEvtIoResume; queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue; status = WdfIoQueueCreate (device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevExt->WriteQueue ); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, " WdfIoQueueCreate for Write failed %!STATUS!\n", status); return status; } // // Mask Queue... // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual ); queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue; queueConfig.EvtIoStop = SerialEvtIoStop; queueConfig.EvtIoResume = SerialEvtIoResume; status = WdfIoQueueCreate (device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevExt->MaskQueue ); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, " WdfIoQueueCreate for Mask failed %!STATUS!\n", status); return status; } // // Purge Queue.. // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual ); queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue; queueConfig.EvtIoStop = SerialEvtIoStop; queueConfig.EvtIoResume = SerialEvtIoResume; status = WdfIoQueueCreate (device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevExt->PurgeQueue ); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, " WdfIoQueueCreate for Purge failed %!STATUS!\n", status); return status; } // // All the incoming I/O requests are routed to the default queue and dispatch to the // appropriate callback events. These callback event will check to see if another // request is currently active. If so then it will forward it to other manual queues. // All the queues are auto managed by the framework in response to the PNP // and Power events. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &queueConfig, WdfIoQueueDispatchParallel ); queueConfig.EvtIoRead = SerialEvtIoRead; queueConfig.EvtIoWrite = SerialEvtIoWrite; queueConfig.EvtIoDeviceControl = SerialEvtIoDeviceControl; queueConfig.EvtIoInternalDeviceControl = SerialEvtIoInternalDeviceControl; queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue; queueConfig.EvtIoStop = SerialEvtIoStop; queueConfig.EvtIoResume = SerialEvtIoResume; status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &defaultqueue ); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed %!STATUS!\n", status); return status; } // // Create WDFINTERRUPT object. Let us leave the ShareVector to default value and // let the framework decide whether to share the interrupt or not based on the // ShareDisposition provided by the bus driver in the resource descriptor. // WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, SerialISR, NULL); interruptConfig.EvtInterruptDisable = SerialEvtInterruptDisable; interruptConfig.EvtInterruptEnable = SerialEvtInterruptEnable; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, SERIAL_INTERRUPT_CONTEXT); status = WdfInterruptCreate(device, &interruptConfig, &attributes, &pDevExt->WdfInterrupt); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Couldn't create interrupt for %wZ\n", &pDevExt->DeviceName); return status; } // // Interrupt state wait lock... // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = pDevExt->WdfInterrupt; interruptContext = SerialGetInterruptContext(pDevExt->WdfInterrupt); status = WdfWaitLockCreate(&attributes, &interruptContext->InterruptStateLock ); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, " WdfWaitLockCreate for InterruptStateLock failed %!STATUS!\n", status); return status; } // // Set interrupt policy // SerialSetInterruptPolicy(pDevExt->WdfInterrupt); // // Timers and DPCs... // status = SerialCreateTimersAndDpcs(pDevExt); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "SerialCreateTimersAndDpcs failed %x\n", status); return status; } // // Register with WMI. // status = SerialWmiRegistration(device); if(!NT_SUCCESS (status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "SerialWmiRegistration failed %!STATUS!\n", status); return status; } // // Upto this point, if we fail, we don't have to worry about freeing any resource because // framework will free all the objects. // // // Do the external naming. // status = SerialDoExternalNaming(pDevExt); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "External Naming Failed - Status %!STATUS!\n", status); return status; } // // Finally increment the global system configuration that keeps track of number of serial ports. // countSoFar = &IoGetConfigurationInformation()->SerialCount; (*countSoFar)++; pDevExt->IsSystemConfigInfoUpdated = TRUE; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "<--SerialEvtDeviceAdd\n"); return status; } #pragma warning(push) #pragma warning(disable:28118) // this callback will run at IRQL=PASSIVE_LEVEL _Use_decl_annotations_ VOID SerialEvtDeviceContextCleanup ( WDFOBJECT Device ) /*++ Routine Description: EvtDeviceContextCleanup event callback cleans up anything done in EvtDeviceAdd, except those things that are automatically cleaned up by the Framework. In a driver derived from this sample, it's quite likely that this function could be deleted. Arguments: Device - Handle to a framework device object. Return Value: VOID --*/ { PSERIAL_DEVICE_EXTENSION deviceExtension; PULONG countSoFar; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> SerialDeviceContextCleanup\n"); PAGED_CODE(); deviceExtension = SerialGetDeviceExtension (Device); if (deviceExtension->InterruptReadBuffer != NULL) { ExFreePool(deviceExtension->InterruptReadBuffer); deviceExtension->InterruptReadBuffer = NULL; } // // Update the global configuration count for serial device. // if(deviceExtension->IsSystemConfigInfoUpdated) { countSoFar = &IoGetConfigurationInformation()->SerialCount; (*countSoFar)--; } SerialUndoExternalNaming(deviceExtension); return; } #pragma warning(pop) // enable 28118 again NTSTATUS SerialEvtPrepareHardware( WDFDEVICE Device, WDFCMRESLIST Resources, WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: SerialEvtPrepareHardware event callback performs operations that are necessary to make the device operational. The framework calls the driver's SerialEvtPrepareHardware callback when the PnP manager sends an IRP_MN_START_DEVICE request to the driver stack. Arguments: Device - Handle to a framework device object. Resources - Handle to a collection of framework resource objects. This collection identifies the raw (bus-relative) hardware resources that have been assigned to the device. ResourcesTranslated - Handle to a collection of framework resource objects. This collection identifies the translated (system-physical) hardware resources that have been assigned to the device. The resources appear from the CPU's point of view. Use this list of resources to map I/O space and device-accessible memory into virtual address space Return Value: WDF status code --*/ { PSERIAL_DEVICE_EXTENSION pDevExt; NTSTATUS status; CONFIG_DATA config; PCONFIG_DATA pConfig = &config; ULONG defaultClockRate = 1843200; PAGED_CODE(); SerialDbgPrintEx (TRACE_LEVEL_INFORMATION, DBG_PNP, "--> SerialEvtPrepareHardware\n"); // // Get the Device Extension.. // pDevExt = SerialGetDeviceExtension (Device); RtlZeroMemory(pConfig, sizeof(CONFIG_DATA)); // // Initialize a config data structure with default values for those that // may not already be initialized. // pConfig->LogFifo = driverDefaults.LogFifoDefault; // // Get the hw resources for the device. // status = SerialMapHWResources(Device, Resources, ResourcesTranslated, pConfig); if (!NT_SUCCESS(status)) { goto End; } // // Open the "Device Parameters" section of registry for this device and get parameters. // if(!SerialGetRegistryKeyValue (Device, L"DisablePort", &pConfig->DisablePort)){ pConfig->DisablePort = 0; } if(!SerialGetRegistryKeyValue (Device, L"ForceFifoEnable", &pConfig->ForceFifoEnable)){ pConfig->ForceFifoEnable = driverDefaults.ForceFifoEnableDefault; } if(!SerialGetRegistryKeyValue (Device, L"RxFIFO", &pConfig->RxFIFO)){ pConfig->RxFIFO = driverDefaults.RxFIFODefault; } if(!SerialGetRegistryKeyValue (Device, L"TxFIFO", &pConfig->TxFIFO)){ pConfig->TxFIFO = driverDefaults.TxFIFODefault; } if(!SerialGetRegistryKeyValue (Device, L"Share System Interrupt", &pConfig->PermitShare)){ pConfig->PermitShare = driverDefaults.PermitShareDefault; } if(!SerialGetRegistryKeyValue (Device, L"ClockRate", &pConfig->ClockRate)) { pConfig->ClockRate = defaultClockRate; } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "Com Port ClockRate: %x\n", pConfig->ClockRate); if(!SerialGetRegistryKeyValue(Device, L"TL16C550C Auto Flow Control", &pConfig->TL16C550CAFC)){ pConfig->TL16C550CAFC = 0; } status = SerialInitController(pDevExt, pConfig); if (NT_SUCCESS(status)) { } End: SerialDbgPrintEx (TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- SerialEvtPrepareHardware 0x%x\n", status); return status; } NTSTATUS SerialEvtReleaseHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: EvtDeviceReleaseHardware is called by the framework whenever the PnP manager is revoking ownership of our resources. This may be in response to either IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. The callback is made before passing down the IRP to the lower driver. In this callback, do anything necessary to free those resources. In this driver, we will not receive this callback when there is open handle to the device. We explicitly tell the framework (WdfDeviceSetStaticStopRemove) to fail stop and query-remove when handle is open. Arguments: Device - Handle to a framework device object. ResourcesTranslated - Handle to a collection of framework resource objects. This collection identifies the translated (system-physical) hardware resources that have been assigned to the device. The resources appear from the CPU's point of view. Use this list of resources to map I/O space and device-accessible memory into virtual address space Return Value: NTSTATUS - Failures will be logged, but not acted on. --*/ { PSERIAL_DEVICE_EXTENSION pDevExt; UNREFERENCED_PARAMETER(ResourcesTranslated); PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> SerialEvtReleaseHardware\n"); pDevExt = SerialGetDeviceExtension (Device); // // Reset and put the device into a known initial state before releasing the hw resources. // In this driver we can recieve this callback only when there is no handle open because // we tell the framework to disable stop by calling WdfDeviceSetStaticStopRemove. // Since we have already reset the device in our close handler, we don't have to // do anything other than unmapping the I/O resources. // // // Unmap any Memory-Mapped registers. Disconnecting from the interrupt will // be done automatically by the framework. // SerialUnmapHWResources(pDevExt); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- SerialEvtReleaseHardware\n"); return STATUS_SUCCESS; } NTSTATUS SerialEvtDeviceD0EntryPostInterruptsEnabled( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE PreviousState ) /*++ Routine Description: EvtDeviceD0EntryPostInterruptsEnabled is called by the framework after the driver has enabled the device's hardware interrupts. This function is not marked pageable because this function is in the device power up path. When a function is marked pagable and the code section is paged out, it will generate a page fault which could impact the fast resume behavior because the client driver will have to wait until the system drivers can service this page fault. Arguments: Device - Handle to a framework device object. PreviousState - A WDF_POWER_DEVICE_STATE-typed enumerator that identifies the previous device power state. Return Value: NTSTATUS - Failures will be logged, but not acted on. --*/ { PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(Device); PSERIAL_INTERRUPT_CONTEXT interruptContext = SerialGetInterruptContext(extension->WdfInterrupt); WDF_INTERRUPT_INFO info; UNREFERENCED_PARAMETER(PreviousState); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> SerialEvtDeviceD0EntryPostInterruptsEnabled\n"); // // The following lines of code show how to call WdfInterruptGetInfo. // WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(extension->WdfInterrupt, &info); WdfWaitLockAcquire(interruptContext->InterruptStateLock, NULL); interruptContext->IsInterruptConnected = TRUE; WdfWaitLockRelease(interruptContext->InterruptStateLock); return STATUS_SUCCESS; } NTSTATUS SerialEvtDeviceD0ExitPreInterruptsDisabled( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE TargetState ) /*++ Routine Description: EvtDeviceD0ExitPreInterruptsDisabled is called by the framework before the driver disables the device's hardware interrupts. Arguments: Device - Handle to a framework device object. TargetState - A WDF_POWER_DEVICE_STATE-typed enumerator that identifies the device power state that the device is about to enter. Return Value: NTSTATUS - Failures will be logged, but not acted on. --*/ { PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(Device); PSERIAL_INTERRUPT_CONTEXT interruptContext = SerialGetInterruptContext(extension->WdfInterrupt); UNREFERENCED_PARAMETER(TargetState); PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> SerialEvtDeviceD0ExitPreInterruptsDisabled\n"); WdfWaitLockAcquire(interruptContext->InterruptStateLock, NULL); interruptContext->IsInterruptConnected = FALSE; WdfWaitLockRelease(interruptContext->InterruptStateLock); return STATUS_SUCCESS; } NTSTATUS SerialSetPowerPolicy( IN PSERIAL_DEVICE_EXTENSION DeviceExtension ) { WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; //WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks; NTSTATUS status = STATUS_SUCCESS; WDFDEVICE hDevice = DeviceExtension->WdfDevice; ULONG powerOnClose; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> SerialSetPowerPolicy\n"); PAGED_CODE(); // // Find out whether we want to power down the device when there no handles open. // SerialGetRegistryKeyValue(hDevice, L"EnablePowerManagement", &powerOnClose); DeviceExtension->RetainPowerOnClose = powerOnClose ? TRUE : FALSE; // // In some drivers, the device must be specifically programmed to enable // wake signals. UARTs were designed long, long before such a concept. So // this driver, which just drives UARTs, doesn't register wake arm/disarm // callbacks. Arming or disarming for UARTs has to be handled by side-band // code that controls hardware designed more recently. In this case, ACPI // is handling it. If one were to write a driver which implemented a more // modern serial device, one might need to use these callbacks. // // // Init the power policy callbacks // //WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks); // // This group of three callbacks allows this sample driver to manage // arming the device for wake from the S0 state. // //powerPolicyCallbacks.EvtDeviceArmWakeFromS0 = SerialEvtDeviceWakeArmS0; //powerPolicyCallbacks.EvtDeviceDisarmWakeFromS0 = SerialEvtDeviceWakeDisarmS0; //powerPolicyCallbacks.EvtDeviceWakeFromS0Triggered = SerialEvtDeviceWakeTriggeredS0; // // This group of three callbacks allows the device to be armed for wake // from Sx (S1, S2, S3 or S4.) Networking devices can optionally be put // into a state where a packet sent to them will cause the device's wake // signal to be triggered, which causes the machine to wake, moving back // into the S0 state. // //powerPolicyCallbacks.EvtDeviceArmWakeFromSx = SerialEvtDeviceWakeArmSx; //powerPolicyCallbacks.EvtDeviceDisarmWakeFromSx = SerialEvtDeviceWakeDisarmSx; //powerPolicyCallbacks.EvtDeviceWakeFromSxTriggered = SerialEvtDeviceWakeTriggeredSx; // // Register the power policy callbacks. // //WdfDeviceSetPowerPolicyEventCallbacks(hDevice, &powerPolicyCallbacks); // // Init the idle policy structure. By setting IdleCannotWakeFromS0 we tell the framework // to power down the device without arming for wake. The only way the device can come // back to D0 is when we call WdfDeviceStopIdle in SerialEvtDeviceFileCreate. // We can't choose IdleCanWakeFromS0 by default is because onboard serial ports typically // don't have wake capability. If the driver is used for plugin boards that does support // wait-wake, you can update the settings to match that. If MS provided modem driver // is used on ports that does support wake on ring, then it will update the settings // by sending an internal ioctl to us. // WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCannotWakeFromS0); if(DeviceExtension->OwnsPowerPolicy && !DeviceExtension->RetainPowerOnClose) { // // Since we don't have to retain power when there are no open handles, we // register for idle power management to save power. Check the use of // WdfDeviceStopIdle in SerialEvtDeviceFileCreate. // idleSettings.UserControlOfIdleSettings = IdleAllowUserControl; status = WdfDeviceAssignS0IdleSettings(hDevice, &idleSettings); if ( !NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceSetPowerPolicyS0IdlePolicy failed %x \n", status); return status; } } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- SerialSetPowerPolicy\n"); return status; } UINT32 SerialReportMaxBaudRate(ULONG Bauds) /*++ Routine Description: This routine returns the max baud rate given a selection of rates Arguments: Bauds - Bit-encoded list of supported bauds Return Value: The max baud rate listed in Bauds --*/ { int i; PAGED_CODE(); for(i=0; SupportedBaudRates[i].BaudRate != SERIAL_BAUD_INVALID; i++) { if(Bauds & SupportedBaudRates[i].Mask) { return SupportedBaudRates[i].BaudRate; } } // // We're in bad shape // return 0; } NTSTATUS SerialInitController( IN PSERIAL_DEVICE_EXTENSION pDevExt, IN PCONFIG_DATA PConfigData ) /*++ Routine Description: Really too many things to mention here. In general initializes kernel synchronization structures, allocates the typeahead buffer, sets up defaults, etc. Arguments: PDevObj - Device object for the device to be started PConfigData - Pointer to a record for a single port. Return Value: STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status otherwise. --*/ { NTSTATUS status = STATUS_SUCCESS; SHORT junk; int i; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> SerialInitController for %wZ\n", &pDevExt->DeviceName); // // Save the value of clock input to the part. We use this to calculate // the divisor latch value. The value is in Hertz. // pDevExt->ClockRate = PConfigData->ClockRate; // // Save if we have to enable TI's auto flow control // pDevExt->TL16C550CAFC = PConfigData->TL16C550CAFC; // // Map the memory for the control registers for the serial device // into virtual memory. // pDevExt->Controller = SerialGetMappedAddress(PConfigData->TrController, PConfigData->SpanOfController, (BOOLEAN)PConfigData->AddressSpace, &pDevExt->UnMapRegisters); if (!pDevExt->Controller) { SerialLogError( pDevExt->DriverObject, pDevExt->DeviceObject, PConfigData->TrController, SerialPhysicalZero, 0, 0, 0, 7, STATUS_SUCCESS, SERIAL_REGISTERS_NOT_MAPPED, pDevExt->DeviceName.Length+sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL ); SerialDbgPrintEx(TRACE_LEVEL_WARNING, DBG_PNP, "Could not map memory for device " "registers for %wZ\n", &pDevExt->DeviceName); pDevExt->UnMapRegisters = FALSE; status = STATUS_NONE_MAPPED; goto ExtensionCleanup; } pDevExt->AddressSpace = PConfigData->AddressSpace; pDevExt->SpanOfController = PConfigData->SpanOfController; // // Save off the interface type and the bus number. // pDevExt->Vector = PConfigData->TrVector; pDevExt->Irql = (UCHAR)PConfigData->TrIrql; pDevExt->InterruptMode = PConfigData->InterruptMode; pDevExt->Affinity = PConfigData->Affinity; // // If the user said to permit sharing within the device, propagate this // through. // pDevExt->PermitShare = PConfigData->PermitShare; // // Before we test whether the port exists (which will enable the FIFO) // convert the rx trigger value to what should be used in the register. // // If a bogus value was given - crank them down to 1. // // If this is a "souped up" UART with like a 64 byte FIFO, they // should use the appropriate "spoofing" value to get the desired // results. I.e., if on their chip 0xC0 in the FCR is for 64 bytes, // they should specify 14 in the registry. // switch (PConfigData->RxFIFO) { case 1: pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER; break; case 4: pDevExt->RxFifoTrigger = SERIAL_4_BYTE_HIGH_WATER; break; case 8: pDevExt->RxFifoTrigger = SERIAL_8_BYTE_HIGH_WATER; break; case 14: pDevExt->RxFifoTrigger = SERIAL_14_BYTE_HIGH_WATER; break; default: pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER; break; } if (PConfigData->TxFIFO < 1) { pDevExt->TxFifoAmount = 1; } else { pDevExt->TxFifoAmount = PConfigData->TxFIFO; } if (!SerialDoesPortExist( pDevExt, &pDevExt->DeviceName, PConfigData->ForceFifoEnable, PConfigData->LogFifo )) { // // We couldn't verify that there was actually a // port. No need to log an error as the port exist // code will log exactly why. // SerialDbgPrintEx(TRACE_LEVEL_WARNING, DBG_PNP, "DoesPortExist test failed for " "%wZ\n", &pDevExt->DeviceName); status = STATUS_NO_SUCH_DEVICE; goto ExtensionCleanup; } // // If the user requested that we disable the port, then // do it now. Log the fact that the port has been disabled. // if (PConfigData->DisablePort) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "disabled port %wZ as requested in " "configuration\n", &pDevExt->DeviceName); status = STATUS_NO_SUCH_DEVICE; SerialLogError( pDevExt->DriverObject, pDevExt->DeviceObject, PConfigData->TrController, SerialPhysicalZero, 0, 0, 0, 57, STATUS_SUCCESS, SERIAL_DISABLED_PORT, pDevExt->DeviceName.Length+sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL ); goto ExtensionCleanup; } // // Set up the default device control fields. // Note that if the values are changed after // the file is open, they do NOT revert back // to the old value at file close. // pDevExt->SpecialChars.XonChar = SERIAL_DEF_XON; pDevExt->SpecialChars.XoffChar = SERIAL_DEF_XOFF; pDevExt->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL; pDevExt->HandFlow.FlowReplace = SERIAL_RTS_CONTROL; // // Default Line control protocol. 7E1 // // Seven data bits. // Even parity. // 1 Stop bits. // pDevExt->LineControl = SERIAL_7_DATA | SERIAL_EVEN_PARITY | SERIAL_NONE_PARITY; pDevExt->ValidDataMask = 0x7f; pDevExt->CurrentBaud = 1200; // // We set up the default xon/xoff limits. // // This may be a bogus value. It looks like the BufferSize // is not set up until the device is actually opened. // pDevExt->HandFlow.XoffLimit = pDevExt->BufferSize >> 3; pDevExt->HandFlow.XonLimit = pDevExt->BufferSize >> 1; pDevExt->BufferSizePt8 = ((3*(pDevExt->BufferSize>>2))+ (pDevExt->BufferSize>>4)); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, " The default interrupt read buffer size is: %d\n" "------ The XoffLimit is : %d\n" "------ The XonLimit is : %d\n" "------ The pt 8 size is : %d\n", pDevExt->BufferSize, pDevExt->HandFlow.XoffLimit, pDevExt->HandFlow.XonLimit, pDevExt->BufferSizePt8); // // Go through all the "named" baud rates to find out which ones // can be supported with this port. // // pDevExt->SupportedBauds = SERIAL_BAUD_USER; for(i=0; SupportedBaudRates[i].BaudRate != SERIAL_BAUD_INVALID; i++) { if (!NT_ERROR(SerialGetDivisorFromBaud( pDevExt->ClockRate, (LONG)SupportedBaudRates[i].BaudRate, &junk ))) { pDevExt->SupportedBauds |= SupportedBaudRates[i].Mask; } } // // Mark this device as not being opened by anyone. We keep a // variable around so that spurious interrupts are easily // dismissed by the ISR. // SetDeviceIsOpened(pDevExt, FALSE, FALSE); // // Store values into the extension for interval timing. // // // If the interval timer is less than a second then come // in with a short "polling" loop. // // For large (> then 2 seconds) use a 1 second poller. // pDevExt->ShortIntervalAmount.QuadPart = -1; pDevExt->LongIntervalAmount.QuadPart = -10000000; pDevExt->CutOverAmount.QuadPart = 200000000; DISABLE_ALL_INTERRUPTS (pDevExt, pDevExt->Controller); WRITE_MODEM_CONTROL(pDevExt, pDevExt->Controller, (UCHAR)0); // make sure there is no escape character currently set pDevExt->EscapeChar = 0; // // This should set up everything as it should be when // a device is to be opened. We do need to lower the // modem lines, and disable the recalcitrant fifo // so that it will show up if the user boots to dos. // // __WARNING_IRQ_SET_TOO_HIGH: we are calling interrupt synchronize routine directly. Suppress it because interrupt is not connected yet. // __WARNING_INVALID_PARAM_VALUE_1: Interrupt is UNREFERENCED_PARAMETER, so it can be NULL #pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1) SerialReset(NULL, pDevExt); #pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1) SerialMarkClose(NULL, pDevExt); #pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1) SerialClrRTS(NULL, pDevExt); #pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1) SerialClrDTR(NULL, pDevExt); // // Fill in WMI hardware data // pDevExt->WmiHwData.IrqNumber = pDevExt->Irql; pDevExt->WmiHwData.IrqLevel = pDevExt->Irql; pDevExt->WmiHwData.IrqVector = pDevExt->Vector; pDevExt->WmiHwData.IrqAffinityMask = pDevExt->Affinity; pDevExt->WmiHwData.InterruptType = pDevExt->InterruptMode == Latched ? SERIAL_WMI_INTTYPE_LATCHED : SERIAL_WMI_INTTYPE_LEVEL; pDevExt->WmiHwData.BaseIOAddress = (ULONG_PTR)pDevExt->Controller; // // Fill in WMI device state data (as defaults) // pDevExt->WmiCommData.BaudRate = pDevExt->CurrentBaud; pDevExt->WmiCommData.BitsPerByte = (pDevExt->LineControl & 0x03) + 5; pDevExt->WmiCommData.ParityCheckEnable = (pDevExt->LineControl & 0x08) ? TRUE : FALSE; switch (pDevExt->LineControl & SERIAL_PARITY_MASK) { case SERIAL_NONE_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; break; case SERIAL_ODD_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD; break; case SERIAL_EVEN_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN; break; case SERIAL_MARK_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK; break; case SERIAL_SPACE_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE; break; default: ASSERTMSG(0, "Illegal Parity setting for WMI"); pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; break; } pDevExt->WmiCommData.StopBits = pDevExt->LineControl & SERIAL_STOP_MASK ? (pDevExt->WmiCommData.BitsPerByte == 5 ? SERIAL_WMI_STOP_1_5 : SERIAL_WMI_STOP_2) : SERIAL_WMI_STOP_1; pDevExt->WmiCommData.XoffCharacter = pDevExt->SpecialChars.XoffChar; pDevExt->WmiCommData.XoffXmitThreshold = pDevExt->HandFlow.XoffLimit; pDevExt->WmiCommData.XonCharacter = pDevExt->SpecialChars.XonChar; pDevExt->WmiCommData.XonXmitThreshold = pDevExt->HandFlow.XonLimit; pDevExt->WmiCommData.MaximumBaudRate = SerialReportMaxBaudRate(pDevExt->SupportedBauds); pDevExt->WmiCommData.MaximumOutputBufferSize = (UINT32)((ULONG)-1); pDevExt->WmiCommData.MaximumInputBufferSize = (UINT32)((ULONG)-1); pDevExt->WmiCommData.Support16BitMode = FALSE; pDevExt->WmiCommData.SupportDTRDSR = TRUE; pDevExt->WmiCommData.SupportIntervalTimeouts = TRUE; pDevExt->WmiCommData.SupportParityCheck = TRUE; pDevExt->WmiCommData.SupportRTSCTS = TRUE; pDevExt->WmiCommData.SupportXonXoff = TRUE; pDevExt->WmiCommData.SettableBaudRate = TRUE; pDevExt->WmiCommData.SettableDataBits = TRUE; pDevExt->WmiCommData.SettableFlowControl = TRUE; pDevExt->WmiCommData.SettableParity = TRUE; pDevExt->WmiCommData.SettableParityCheck = TRUE; pDevExt->WmiCommData.SettableStopBits = TRUE; pDevExt->WmiCommData.IsBusy = FALSE; // // Common error path cleanup. If the status is // bad, get rid of the device extension, device object // and any memory associated with it. // ExtensionCleanup: ; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- SerialInitController %x\n", status); return status; } NTSTATUS SerialMapHWResources( IN WDFDEVICE Device, IN WDFCMRESLIST PResList, IN WDFCMRESLIST PTrResList, OUT PCONFIG_DATA PConfig ) /*++ Routine Description: This routine will get the configuration information and put it and the translated values into CONFIG_DATA structures. Arguments: Device - Handle to a framework device object. Resources - Handle to a collection of framework resource objects. This collection identifies the raw (bus-relative) hardware resources that have been assigned to the device. ResourcesTranslated - Handle to a collection of framework resource objects. This collection identifies the translated (system-physical) hardware resources that have been assigned to the device. The resources appear from the CPU's point of view. Use this list of resources to map I/O space and device-accessible memory into virtual address space Return Value: STATUS_SUCCESS if consistant configuration was found - otherwise. returns STATUS_SERIAL_NO_DEVICE_INITED. --*/ { PSERIAL_DEVICE_EXTENSION pDevExt; NTSTATUS status = STATUS_SUCCESS; ULONG i; PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialTrResourceDesc, pPartialRawResourceDesc; ULONG gotInt = 0; ULONG gotIO = 0; ULONG ioResIndex = 0; ULONG curIoIndex = 0; ULONG gotMem = 0; BOOLEAN DebugPortInUse = FALSE; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> SerialMapHWResources\n"); // // Get the DeviceExtension.. // pDevExt = SerialGetDeviceExtension (Device); if ((PResList == NULL) || (PTrResList == NULL)) { ASSERT(PResList != NULL); ASSERT(PTrResList != NULL); status = STATUS_INSUFFICIENT_RESOURCES; goto End; } for (i = 0; i < WdfCmResourceListGetCount(PTrResList); i++) { pPartialTrResourceDesc = WdfCmResourceListGetDescriptor(PTrResList, i); pPartialRawResourceDesc = WdfCmResourceListGetDescriptor(PResList, i); switch (pPartialTrResourceDesc->Type) { case CmResourceTypePort: ASSERT(!(pPartialTrResourceDesc->u.Port.Length == SERIAL_STATUS_LENGTH)); if (gotIO == 0) { if (curIoIndex == ioResIndex) { gotIO = 1; PConfig->TrController = pPartialTrResourceDesc->u.Port.Start; if (!PConfig->TrController.LowPart) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Bogus port address %x\n", PConfig->TrController.LowPart); status = STATUS_DEVICE_CONFIGURATION_ERROR; goto End; } // // We need the raw address to check if the debugger is using the com port // PConfig->Controller = pPartialRawResourceDesc->u.Port.Start; PConfig->AddressSpace = pPartialTrResourceDesc->Flags; pDevExt->SerialReadUChar = SerialReadPortUChar; pDevExt->SerialWriteUChar = SerialWritePortUChar; } else { curIoIndex++; } } break; // // If this is 8 bytes long and we haven't found any I/O range, // then this is probably a fancy-pants machine with memory replacing // IO space // case CmResourceTypeMemory: ASSERT(!(pPartialTrResourceDesc->u.Port.Length == SERIAL_STATUS_LENGTH)); if ((gotMem == 0) && (gotIO == 0) && (pPartialTrResourceDesc->u.Memory.Length == (SERIAL_REGISTER_SPAN + SERIAL_STATUS_LENGTH))) { gotMem = 1; PConfig->TrController = pPartialTrResourceDesc->u.Memory.Start; if (!PConfig->TrController.LowPart) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Bogus I/O memory address %x\n", PConfig->TrController.LowPart); status = STATUS_DEVICE_CONFIGURATION_ERROR; goto End; } PConfig->Controller = pPartialRawResourceDesc->u.Memory.Start; PConfig->AddressSpace = CM_RESOURCE_PORT_MEMORY; PConfig->SpanOfController = SERIAL_REGISTER_SPAN; pDevExt->SerialReadUChar = SerialReadRegisterUChar; pDevExt->SerialWriteUChar = SerialWriteRegisterUChar; } break; case CmResourceTypeInterrupt: if (gotInt == 0) { gotInt = 1; PConfig->TrVector = pPartialTrResourceDesc->u.Interrupt.Vector; if (!PConfig->TrVector) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Bogus vector 0\n"); status = STATUS_DEVICE_CONFIGURATION_ERROR; goto End; } if (pPartialTrResourceDesc->ShareDisposition == CmResourceShareShared) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "Sharing interrupt with other devices \n"); } else { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "Interrupt is not shared with other devices\n"); } PConfig->TrIrql = pPartialTrResourceDesc->u.Interrupt.Level; PConfig->Affinity = pPartialTrResourceDesc->u.Interrupt.Affinity; } break; default: break; } // switch (pPartialTrResourceDesc->Type) } // for (i = 0; i < WdfCollectionGetCount if(!((gotMem || gotIO) && gotInt) ) { status = STATUS_INSUFFICIENT_RESOURCES; goto End; } // // First check what type of AddressSpace this port is in. Then check // if the debugger is using this port. If it is, set DebugPortInUse to TRUE. // if(PConfig->AddressSpace == CM_RESOURCE_PORT_MEMORY) { PHYSICAL_ADDRESS KdComPhysical; KdComPhysical = MmGetPhysicalAddress(*KdComPortInUse); if(KdComPhysical.LowPart == PConfig->Controller.LowPart) { DebugPortInUse = TRUE; } } else { // // This compare is done using **untranslated** values since that is what // the kernel shoves in regardless of the architecture. // if ((*KdComPortInUse) == (ULongToPtr(PConfig->Controller.LowPart))) { DebugPortInUse = TRUE; } } if (DebugPortInUse) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Kernel debugger is using port at " "address %p\n", *KdComPortInUse); SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Serial driver will not load port\n"); SerialLogError( pDevExt->DriverObject, NULL, PConfig->TrController, SerialPhysicalZero, 0, 0, 0, 3, STATUS_SUCCESS, SERIAL_KERNEL_DEBUGGER_ACTIVE, pDevExt->DeviceName.Length+sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL ); status = STATUS_INSUFFICIENT_RESOURCES; goto End; } End: SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- SerialMapHWResources %x\n", status); return status; } VOID SerialUnmapHWResources( IN PSERIAL_DEVICE_EXTENSION PDevExt ) /*++ Routine Description: Releases resources (not pool) stored in the device extension. Arguments: PDevExt - Pointer to the device extension to release resources from. Return Value: VOID --*/ { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "-->SerialUnMapResources(%p)\n", PDevExt); PAGED_CODE(); // // If necessary, unmap the device registers. // if (PDevExt->UnMapRegisters) { MmUnmapIoSpace(PDevExt->Controller, PDevExt->SpanOfController); PDevExt->UnMapRegisters = FALSE; } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "<--SerialUnMapResources\n"); } NTSTATUS SerialReadSymName( IN WDFDEVICE Device, _Out_writes_bytes_(*SizeOfRegName) PWSTR RegName, _Inout_ PUSHORT SizeOfRegName ) { NTSTATUS status; WDFKEY hKey; UNICODE_STRING value; UNICODE_STRING valueName; USHORT requiredLength; PAGED_CODE(); value.Buffer = RegName; value.MaximumLength = *SizeOfRegName; value.Length = 0; status = WdfDeviceOpenRegistryKey(Device, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey); if (NT_SUCCESS (status)) { // // Fetch PortName which contains the suggested REG_SZ symbolic name. // RtlInitUnicodeString(&valueName, L"PortName"); status = WdfRegistryQueryUnicodeString (hKey, &valueName, &requiredLength, &value); if (!NT_SUCCESS (status)) { // // This is for PCMCIA which currently puts the name under Identifier. // RtlInitUnicodeString(&valueName, L"Identifier"); status = WdfRegistryQueryUnicodeString (hKey, &valueName, &requiredLength, &value); if (!NT_SUCCESS(status)) { // // Hmm. Either we have to pick a name or bail... // SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Getting PortName/Identifier failed - %x\n", status); } } WdfRegistryClose(hKey); } if(NT_SUCCESS(status)) { // // NULL terminate the string and return number of characters in the string. // if(value.Length > *SizeOfRegName - sizeof(WCHAR)) { return STATUS_UNSUCCESSFUL; } *SizeOfRegName = value.Length; RegName[*SizeOfRegName/sizeof(WCHAR)] = UNICODE_NULL; } return status; } NTSTATUS SerialDoExternalNaming(IN PSERIAL_DEVICE_EXTENSION PDevExt) /*++ Routine Description: This routine will be used to create a symbolic link to the driver name in the given object directory. It will also create an entry in the device map for this device - IF we could create the symbolic link. Arguments: Extension - Pointer to the device extension. Return Value: None. --*/ { NTSTATUS status = STATUS_SUCCESS; WCHAR pRegName[SYMBOLIC_NAME_LENGTH]; USHORT nameSize = sizeof(pRegName); WDFSTRING stringHandle = NULL; WDF_OBJECT_ATTRIBUTES attributes; DECLARE_UNICODE_STRING_SIZE(symbolicLinkName,SYMBOLIC_NAME_LENGTH ) ; PAGED_CODE(); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = PDevExt->WdfDevice; status = WdfStringCreate(NULL, &attributes, &stringHandle); if(!NT_SUCCESS(status)){ goto SerialDoExternalNamingError; } status = WdfDeviceRetrieveDeviceName(PDevExt->WdfDevice, stringHandle); if(!NT_SUCCESS(status)){ goto SerialDoExternalNamingError; } // // Since we are storing the buffer pointer of the string handle in our // extension, we will hold onto string handle until the device is deleted. // WdfStringGetUnicodeString(stringHandle, &PDevExt->DeviceName); SerialGetRegistryKeyValue(PDevExt->WdfDevice, L"SerialSkipExternalNaming", &PDevExt->SkipNaming); if (PDevExt->SkipNaming) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Skipping external naming due to registry settings\n"); return STATUS_SUCCESS; } status = SerialReadSymName(PDevExt->WdfDevice, pRegName, &nameSize); if (!NT_SUCCESS(status)) { goto SerialDoExternalNamingError; } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "DosName is %ws\n", pRegName); status = RtlUnicodeStringPrintf(&symbolicLinkName, L"%ws%ws", L"\\DosDevices\\", pRegName); if (!NT_SUCCESS(status)) { goto SerialDoExternalNamingError; } status = WdfDeviceCreateSymbolicLink(PDevExt->WdfDevice, &symbolicLinkName); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Couldn't create the symbolic link for port %wZ\n", &symbolicLinkName); goto SerialDoExternalNamingError; } PDevExt->CreatedSymbolicLink = TRUE; status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, PDevExt->DeviceName.Buffer, REG_SZ, pRegName, nameSize + sizeof(WCHAR)); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Couldn't create the device map entry\n" "------- for port %ws\n", PDevExt->DeviceName.Buffer); goto SerialDoExternalNamingError; } PDevExt->CreatedSerialCommEntry = TRUE; // // Make the device visible via a device association as well. // The reference string is the eight digit device index // status = WdfDeviceCreateDeviceInterface(PDevExt->WdfDevice, (LPGUID) &GUID_DEVINTERFACE_COMPORT, NULL); if (!NT_SUCCESS (status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Couldn't register class association\n" "for port %wZ\n", &PDevExt->DeviceName); goto SerialDoExternalNamingError; } return status; SerialDoExternalNamingError:; // // Clean up error conditions // PDevExt->DeviceName.Buffer = NULL; if (PDevExt->CreatedSerialCommEntry) { _Analysis_assume_(NULL != PDevExt->DeviceName.Buffer); RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, PDevExt->DeviceName.Buffer); } if(stringHandle) { WdfObjectDelete(stringHandle); } return status; } VOID SerialUndoExternalNaming(IN PSERIAL_DEVICE_EXTENSION Extension) /*++ Routine Description: This routine will be used to delete a symbolic link to the driver name in the given object directory. It will also delete an entry in the device map for this device if the symbolic link had been created. Arguments: Extension - Pointer to the device extension. Return Value: None. --*/ { NTSTATUS status; PWCHAR deviceName = Extension->DeviceName.Buffer; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "In SerialUndoExternalNaming for extension: " "%p of port %ws\n", Extension, deviceName); // // Maybe there is nothing for us to do // if (Extension->SkipNaming) { return; } // // We're cleaning up here. One reason we're cleaning up // is that we couldn't allocate space for the NtNameOfPort. // if ((deviceName != NULL) && Extension->CreatedSerialCommEntry) { status = RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, deviceName); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "Couldn't delete value entry %ws\n", deviceName); } } } VOID SerialPurgePendingRequests(PSERIAL_DEVICE_EXTENSION pDevExt) /*++ Routine Description: This routine completes any irps pending for the passed device object. Arguments: PDevObj - Pointer to the device object whose irps must die. Return Value: VOID --*/ { NTSTATUS status; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, ">SerialPurgePendingRequests(%p)\n", pDevExt); // // Then cancel all the reads and writes. // SerialPurgeRequests(pDevExt->WriteQueue, &pDevExt->CurrentWriteRequest); SerialPurgeRequests(pDevExt->ReadQueue, &pDevExt->CurrentReadRequest); // // Next get rid of purges. // SerialPurgeRequests(pDevExt->PurgeQueue, &pDevExt->CurrentPurgeRequest); // // Get rid of any mask operations. // SerialPurgeRequests( pDevExt->MaskQueue, &pDevExt->CurrentMaskRequest); // // Now get rid of pending wait mask request. // if (pDevExt->CurrentWaitRequest) { status = SerialClearCancelRoutine(pDevExt->CurrentWaitRequest, TRUE ); if (NT_SUCCESS(status)) { SerialCompleteRequest(pDevExt->CurrentWaitRequest, STATUS_CANCELLED, 0); pDevExt->CurrentWaitRequest = NULL; } } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "Controller); // // Make sure that we are *aren't* accessing the divsior latch. // WRITE_LINE_CONTROL(Extension, Extension->Controller, (UCHAR)(oldLCRContents & ~SERIAL_LCR_DLAB) ); oldIERContents = READ_INTERRUPT_ENABLE(Extension, Extension->Controller); // // Go up to power level for a very short time to prevent // any interrupts from this device from coming in. // KeRaiseIrql( POWER_LEVEL, &oldIrql ); WRITE_INTERRUPT_ENABLE(Extension, Extension->Controller, 0x0f ); value1 = READ_INTERRUPT_ENABLE(Extension, Extension->Controller); value1 = value1 << 8; value1 |= READ_RECEIVE_BUFFER(Extension, Extension->Controller); READ_DIVISOR_LATCH(Extension, Extension->Controller, (PSHORT) &value2 ); WRITE_LINE_CONTROL(Extension, Extension->Controller, oldLCRContents ); // // Put the ier back to where it was before. If we are on a // level sensitive port this should prevent the interrupts // from coming in. If we are on a latched, we don't care // cause the interrupts generated will just get dropped. // WRITE_INTERRUPT_ENABLE(Extension, Extension->Controller, oldIERContents ); KeLowerIrql(oldIrql); if (value1 == value2) { SerialLogError( Extension->DeviceObject->DriverObject, Extension->DeviceObject, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 62, STATUS_SUCCESS, SERIAL_DLAB_INVALID, InsertString->Length+sizeof(WCHAR), InsertString->Buffer, 0, NULL ); returnValue = FALSE; goto AllDone; } AllDone: ; // // If we think that there is a serial device then we determine // if a fifo is present. // if (returnValue) { // // Well, we think it's a serial device. Absolutely // positively, prevent interrupts from occuring. // // We disable all the interrupt enable bits, and // push down all the lines in the modem control // We only needed to push down OUT2 which in // PC's must also be enabled to get an interrupt. // DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller); WRITE_MODEM_CONTROL(Extension, Extension->Controller, (UCHAR)0); // // See if this is a 16550. We do this by writing to // what would be the fifo control register with a bit // pattern that tells the device to enable fifo's. // We then read the iterrupt Id register to see if the // bit pattern is present that identifies the 16550. // WRITE_FIFO_CONTROL(Extension, Extension->Controller, SERIAL_FCR_ENABLE ); regContents = READ_INTERRUPT_ID_REG(Extension, Extension->Controller); if (regContents & SERIAL_IIR_FIFOS_ENABLED) { // // Save off that the device supports fifos. // Extension->FifoPresent = TRUE; // // There is a fine new "super" IO chip out there that // will get stuck with a line status interrupt if you // attempt to clear the fifo and enable it at the same // time if data is present. The best workaround seems // to be that you should turn off the fifo read a single // byte, and then re-enable the fifo. // WRITE_FIFO_CONTROL(Extension, Extension->Controller, (UCHAR)0 ); READ_RECEIVE_BUFFER(Extension, Extension->Controller); // // There are fifos on this card. Set the value of the // receive fifo to interrupt when 4 characters are present. // WRITE_FIFO_CONTROL(Extension, Extension->Controller, (UCHAR)(SERIAL_FCR_ENABLE | Extension->RxFifoTrigger | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)); } // // The !Extension->FifoPresent is included in the test so that // broken chips like the WinBond will still work after we test // for the fifo. // if (!ForceFifo || !Extension->FifoPresent) { Extension->FifoPresent = FALSE; WRITE_FIFO_CONTROL(Extension, Extension->Controller, (UCHAR)0 ); } if (Extension->FifoPresent) { if (LogFifo) { SerialLogError( Extension->DeviceObject->DriverObject, Extension->DeviceObject, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 15, STATUS_SUCCESS, SERIAL_FIFO_PRESENT, InsertString->Length+sizeof(WCHAR), InsertString->Buffer, 0, NULL ); } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, "Fifo's detected at port address: %p\n", Extension->Controller); } } return returnValue; } BOOLEAN SerialReset( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This places the hardware in a standard configuration. NOTE: This assumes that it is called at interrupt level. Arguments: Context - The device extension for serial device being managed. Return Value: Always FALSE. --*/ { PSERIAL_DEVICE_EXTENSION extension = Context; UCHAR regContents; UCHAR oldModemControl; ULONG i; UNREFERENCED_PARAMETER(Interrupt); // // Adjust the out2 bit. // This will also prevent any interrupts from occuring. // oldModemControl = READ_MODEM_CONTROL(extension, extension->Controller); WRITE_MODEM_CONTROL(extension, extension->Controller, (UCHAR)(oldModemControl & ~SERIAL_MCR_OUT2)); // // Reset the fifo's if there are any. // if (extension->FifoPresent) { // // There is a fine new "super" IO chip out there that // will get stuck with a line status interrupt if you // attempt to clear the fifo and enable it at the same // time if data is present. The best workaround seems // to be that you should turn off the fifo read a single // byte, and then re-enable the fifo. // WRITE_FIFO_CONTROL(extension, extension->Controller, (UCHAR)0 ); READ_RECEIVE_BUFFER(extension, extension->Controller); WRITE_FIFO_CONTROL(extension, extension->Controller, (UCHAR)(SERIAL_FCR_ENABLE | extension->RxFifoTrigger | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET) ); } // // Make sure that the line control set up correct. // // 1) Make sure that the Divisor latch select is set // up to select the transmit and receive register. // // 2) Make sure that we aren't in a break state. // regContents = READ_LINE_CONTROL(extension, extension->Controller); regContents &= ~(SERIAL_LCR_DLAB | SERIAL_LCR_BREAK); WRITE_LINE_CONTROL(extension, extension->Controller, regContents ); // // Read the receive buffer until the line status is // clear. (Actually give up after a 5 reads.) // for (i = 0; i < 5; i++ ) { #pragma warning(disable: 4127) if (IsNotNEC_98) { #pragma warning(default: 4127) READ_RECEIVE_BUFFER(extension, extension->Controller); if (!(READ_LINE_STATUS(extension, extension->Controller) & 1)) { break; } } else { // // I get incorrect data when read enpty buffer. // But do not read no data! for PC98! // if (!(READ_LINE_STATUS(extension, extension->Controller) & 1)) { break; } READ_RECEIVE_BUFFER(extension, extension->Controller); } } // // Read the modem status until the low 4 bits are // clear. (Actually give up after a 5 reads.) // for (i = 0; i < 1000; i++ ) { if (!(READ_MODEM_STATUS(extension, extension->Controller) & 0x0f)) { break; } } // // Now we set the line control, modem control, and the // baud to what they should be. // // // See if we have to enable special Auto Flow Control // if (extension->TL16C550CAFC) { oldModemControl = READ_MODEM_CONTROL(extension, extension->Controller); WRITE_MODEM_CONTROL(extension, extension->Controller, (UCHAR)(oldModemControl | SERIAL_MCR_TL16C550CAFE)); } SerialSetLineControl(extension->WdfInterrupt, extension); SerialSetupNewHandFlow( extension, &extension->HandFlow ); SerialHandleModemUpdate( extension, FALSE ); { SHORT appropriateDivisor; SERIAL_IOCTL_SYNC s; SerialGetDivisorFromBaud( extension->ClockRate, extension->CurrentBaud, &appropriateDivisor ); s.Extension = extension; s.Data = (PVOID) (ULONG_PTR) appropriateDivisor; SerialSetBaud(extension->WdfInterrupt, &s); } // // Enable which interrupts we want to receive. // // NOTE NOTE: This does not actually let interrupts // occur. We must still raise the OUT2 bit in the // modem control register. We will do that on open. // ENABLE_ALL_INTERRUPTS(extension, extension->Controller); // // Read the interrupt id register until the low bit is // set. (Actually give up after a 5 reads.) // for (i = 0; i < 5; i++ ) { if (READ_INTERRUPT_ID_REG(extension, extension->Controller) & 0x01) { break; } } // // Now we know that nothing could be transmitting at this point // so we set the HoldingEmpty indicator. // extension->HoldingEmpty = TRUE; return FALSE; } PVOID SerialGetMappedAddress( PHYSICAL_ADDRESS IoAddress, ULONG NumberOfBytes, ULONG AddressSpace, PBOOLEAN MappedAddress ) /*++ Routine Description: This routine maps an IO address to system address space. Arguments: IoAddress - base device address to be mapped. NumberOfBytes - number of bytes for which address is valid. AddressSpace - Denotes whether the address is in io space or memory. MappedAddress - indicates whether the address was mapped. This only has meaning if the address returned is non-null. Return Value: Mapped address --*/ { PVOID address; PAGED_CODE(); // // Map the device base address into the virtual address space // if the address is in memory space. // if (!AddressSpace) { address = LocalMmMapIoSpace(IoAddress, NumberOfBytes); *MappedAddress = (BOOLEAN)((address)?(TRUE):(FALSE)); } else { address = ULongToPtr(IoAddress.LowPart); *MappedAddress = FALSE; } return address; } VOID SerialSetInterruptPolicy( _In_ WDFINTERRUPT WdfInterrupt ) /*++ Routine Description: This routine shows how to set the interrupt policy preferences. Arguments: WdfInterrupt - Interrupt object handle. Return Value: None --*/ { WDF_INTERRUPT_EXTENDED_POLICY policyAndGroup; #ifdef SERIAL_SELECT_INTERRUPT_GROUP USHORT groupCount = 1; USHORT group = 0; UNICODE_STRING funcName; PFN_KE_GET_ACTIVE_GROUP_COUNT fnKeQueryActiveGroupCount; PFN_KE_QUERY_GROUP_AFFINITY fnKeQueryGroupAffinity; KAFFINITY groupAffinity = (KAFFINITY)1; #endif WDF_INTERRUPT_EXTENDED_POLICY_INIT(&policyAndGroup); policyAndGroup.Priority = WdfIrqPriorityNormal; #ifdef SERIAL_SELECT_INTERRUPT_GROUP // // If OS supports groups, find how many they are. // RtlInitUnicodeString(&funcName, L"KeQueryActiveGroupCount"); fnKeQueryActiveGroupCount = (PFN_KE_GET_ACTIVE_GROUP_COUNT) MmGetSystemRoutineAddress(&funcName); if (fnKeQueryActiveGroupCount != NULL) { groupCount = fnKeQueryActiveGroupCount(); // // Make sure there is at least one group for the boot processor. // if (0 == groupCount) { groupCount = 1; } } if (groupCount <= SERIAL_PREFERRED_INTERRUPT_GROUP) { group = groupCount - 1; } else { group = SERIAL_PREFERRED_INTERRUPT_GROUP; } // // Get the group affinity. // RtlInitUnicodeString(&funcName, L"KeQueryGroupAffinity"); fnKeQueryGroupAffinity = (PFN_KE_QUERY_GROUP_AFFINITY) MmGetSystemRoutineAddress(&funcName); if (fnKeQueryGroupAffinity != NULL) { groupAffinity = fnKeQueryGroupAffinity(group); // // Active groups have at least one processor. // if ((KAFFINITY)0 == groupAffinity) { groupAffinity = (KAFFINITY)1; } } // // Initialize group. // policyAndGroup.Policy = WdfIrqPolicySpecifiedProcessors; policyAndGroup.TargetProcessorSetAndGroup.Group = group; policyAndGroup.TargetProcessorSetAndGroup.Mask = groupAffinity; #endif // // Set interrupt policy and group preference. // WdfInterruptSetExtendedPolicy(WdfInterrupt, &policyAndGroup); } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/power.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: power.c Abstract: This module contains the code that handles the power IRPs for the serial driver. Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "power.tmh" #endif PCHAR DbgDevicePowerString( IN WDF_POWER_DEVICE_STATE Type ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGESER,SerialEvtDeviceD0Exit) #pragma alloc_text(PAGESER,SerialSaveDeviceState) #endif // ALLOC_PRAGMA PCHAR DbgDevicePowerString( IN WDF_POWER_DEVICE_STATE Type ) /*++ Updated Routine Description: DbgDevicePowerString does not change in this stage of the function driver. --*/ { switch (Type) { case WdfPowerDeviceInvalid: return "WdfPowerDeviceInvalid"; case WdfPowerDeviceD0: return "WdfPowerDeviceD0"; case WdfPowerDeviceD1: return "WdfPowerDeviceD1"; case WdfPowerDeviceD2: return "WdfPowerDeviceD2"; case WdfPowerDeviceD3: return "WdfPowerDeviceD3"; case WdfPowerDeviceD3Final: return "WdfPowerDeviceD3Final"; case WdfPowerDevicePrepareForHibernation: return "WdfPowerDevicePrepareForHibernation"; case WdfPowerDeviceMaximum: return "WdfPowerDeviceMaximum"; default: return "UnKnown Device Power State"; } } NTSTATUS SerialEvtDeviceD0Entry( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE PreviousState ) /*++ Routine Description: EvtDeviceD0Entry event callback must perform any operations that are necessary before the specified device is used. It will be called every time the hardware needs to be (re-)initialized. This includes after IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE, IRP_MN_SET_POWER-D0. This function is not marked pageable because this function is in the device power up path. When a function is marked pagable and the code section is paged out, it will generate a page fault which could impact the fast resume behavior because the client driver will have to wait until the system drivers can service this page fault. This function runs at PASSIVE_LEVEL, even though it is not paged. A driver can optionally make this function pageable if DO_POWER_PAGABLE is set. Even if DO_POWER_PAGABLE isn't set, this function still runs at PASSIVE_LEVEL. In this case, though, the function absolutely must not do anything that will cause a page fault. Arguments: Device - Handle to a framework device object. PreviousState - Device power state which the device was in most recently. If the device is being newly started, this will be PowerDeviceUnspecified. Return Value: NTSTATUS --*/ { PSERIAL_DEVICE_EXTENSION deviceExtension; PSERIAL_DEVICE_STATE pDevState; SHORT divisor; SERIAL_IOCTL_SYNC S; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "-->SerialEvtDeviceD0Entry - coming from %s\n", DbgDevicePowerString(PreviousState)); deviceExtension = SerialGetDeviceExtension (Device); pDevState = &deviceExtension->DeviceState; // // Restore the state of the UART. First, that involves disabling // interrupts both via OUT2 and IER. // WRITE_MODEM_CONTROL(deviceExtension, deviceExtension->Controller, 0); DISABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller); // // Set the baud rate // SerialGetDivisorFromBaud(deviceExtension->ClockRate, deviceExtension->CurrentBaud, &divisor); S.Extension = deviceExtension; S.Data = (PVOID) (ULONG_PTR) divisor; #pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, "PFD warning that we are calling interrupt synchronize routine directly. Suppress it because interrupt is disabled above.") SerialSetBaud(deviceExtension->WdfInterrupt, &S); // // Reset / Re-enable the FIFO's // if (deviceExtension->FifoPresent) { WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)0); READ_RECEIVE_BUFFER(deviceExtension, deviceExtension->Controller); WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)(SERIAL_FCR_ENABLE | deviceExtension->RxFifoTrigger | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)); } else { WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)0); } // // Restore a couple more registers // WRITE_INTERRUPT_ENABLE(deviceExtension, deviceExtension->Controller, pDevState->IER); WRITE_LINE_CONTROL(deviceExtension, deviceExtension->Controller, pDevState->LCR); // // Clear out any stale interrupts // READ_INTERRUPT_ID_REG(deviceExtension, deviceExtension->Controller); READ_LINE_STATUS(deviceExtension, deviceExtension->Controller); READ_MODEM_STATUS(deviceExtension, deviceExtension->Controller); // // TODO: move this code to EvtInterruptEnable. // if (deviceExtension->DeviceState.Reopen == TRUE) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "Reopening device\n"); SetDeviceIsOpened(deviceExtension, TRUE, FALSE); // // This enables interrupts on the device! // WRITE_MODEM_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)(pDevState->MCR | SERIAL_MCR_OUT2)); // // Refire the state machine // DISABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller); ENABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller); } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--SerialEvtDeviceD0Entry\n"); return STATUS_SUCCESS; } NTSTATUS SerialEvtDeviceD0Exit( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE TargetState ) /*++ Routine Description: EvtDeviceD0Exit event callback must perform any operations that are necessary before the specified device is moved out of the D0 state. If the driver needs to save hardware state before the device is powered down, then that should be done here. This function runs at PASSIVE_LEVEL, though it is generally not paged. A driver can optionally make this function pageable if DO_POWER_PAGABLE is set. Even if DO_POWER_PAGABLE isn't set, this function still runs at PASSIVE_LEVEL. In this case, though, the function absolutely must not do anything that will cause a page fault. Arguments: Device - Handle to a framework device object. TargetState - Device power state which the device will be put in once this callback is complete. Return Value: NTSTATUS --*/ { PSERIAL_DEVICE_EXTENSION deviceExtension; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "-->SerialEvtDeviceD0Exit - moving to %s\n", DbgDevicePowerString(TargetState)); PAGED_CODE(); deviceExtension = SerialGetDeviceExtension (Device); if (deviceExtension->DeviceIsOpened == TRUE) { LARGE_INTEGER charTime; SetDeviceIsOpened(deviceExtension, FALSE, TRUE); charTime.QuadPart = -SerialGetCharTime(deviceExtension).QuadPart; // // Shut down the chip // SerialDisableUART(deviceExtension); // // Drain the device // SerialDrainUART(deviceExtension, &charTime); // // Save the device state // SerialSaveDeviceState(deviceExtension); } else { SetDeviceIsOpened(deviceExtension, FALSE, FALSE); } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--SerialEvtDeviceD0Exit\n"); return STATUS_SUCCESS; } VOID SerialSaveDeviceState(IN PSERIAL_DEVICE_EXTENSION PDevExt) /*++ Routine Description: This routine saves the device state of the UART Arguments: PDevExt - Pointer to the device extension for the devobj to save the state for. Return Value: VOID --*/ { PSERIAL_DEVICE_STATE pDevState = &PDevExt->DeviceState; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "Entering SerialSaveDeviceState\n"); // // Read necessary registers direct // pDevState->IER = READ_INTERRUPT_ENABLE(PDevExt, PDevExt->Controller); pDevState->MCR = READ_MODEM_CONTROL(PDevExt, PDevExt->Controller); pDevState->LCR = READ_LINE_CONTROL(PDevExt, PDevExt->Controller); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "Leaving SerialSaveDeviceState\n"); } VOID SetDeviceIsOpened(IN PSERIAL_DEVICE_EXTENSION PDevExt, IN BOOLEAN DeviceIsOpened, IN BOOLEAN Reopen) { PDevExt->DeviceIsOpened = DeviceIsOpened; PDevExt->DeviceState.Reopen = Reopen; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/precomp.h ================================================ #include #include #define WIN9X_COMPAT_SPINLOCK #include "ntddk.h" #include #define NTSTRSAFE_LIB #include #include "ntddser.h" #include #include // required for GUID definitions #include #include "serial.h" #include "serialp.h" #include "serlog.h" #include "log.h" #include "trace.h" ================================================ FILE: tests/projects/windows/driver/kmdf/serial/precompsrc.c ================================================ #include "precomp.h" ================================================ FILE: tests/projects/windows/driver/kmdf/serial/purge.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: purge.c Abstract: This module contains the code that is very specific to purge operations in the serial driver Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "purge.tmh" #endif VOID SerialStartPurge( IN PSERIAL_DEVICE_EXTENSION Extension ) /*++ Routine Description: Depending on the mask in the current request, purge the interrupt buffer, the read queue, or the write queue, or all of the above. Arguments: Extension - Pointer to the device extension. Return Value: Will return STATUS_SUCCESS always. This is reasonable since the DPC completion code that calls this routine doesn't care and the purge request always goes through to completion once it's started. --*/ { WDFREQUEST NewRequest; PREQUEST_CONTEXT reqContext; do { ULONG Mask; reqContext = SerialGetRequestContext(Extension->CurrentPurgeRequest); Mask = *((ULONG *) (reqContext->SystemBuffer)); if (Mask & SERIAL_PURGE_TXABORT) { SerialFlushRequests( Extension->WriteQueue, &Extension->CurrentWriteRequest ); SerialFlushRequests( Extension->WriteQueue, &Extension->CurrentXoffRequest ); } if (Mask & SERIAL_PURGE_RXABORT) { SerialFlushRequests( Extension->ReadQueue, &Extension->CurrentReadRequest ); } if (Mask & SERIAL_PURGE_RXCLEAR) { // // Clean out the interrupt buffer. // // Note that we do this under protection of the // the drivers control lock so that we don't hose // the pointers if there is currently a read that // is reading out of the buffer. // WdfInterruptSynchronize( Extension->WdfInterrupt, SerialPurgeInterruptBuff, Extension ); } reqContext->Status = STATUS_SUCCESS; reqContext->Information = 0; SerialGetNextRequest( &Extension->CurrentPurgeRequest, Extension->PurgeQueue, &NewRequest, TRUE, Extension ); } while (NewRequest); return; } BOOLEAN SerialPurgeInterruptBuff( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine simply resets the interrupt (typeahead) buffer. NOTE: This routine is being called from WdfInterruptSynchronize. Arguments: Context - Really a pointer to the device extension. Return Value: Always false. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; UNREFERENCED_PARAMETER(Interrupt); // // The typeahead buffer is by definition empty if there // currently is a read owned by the isr. // if (Extension->ReadBufferBase == Extension->InterruptReadBuffer) { Extension->CurrentCharSlot = Extension->InterruptReadBuffer; Extension->FirstReadableChar = Extension->InterruptReadBuffer; Extension->LastCharSlot = Extension->InterruptReadBuffer + (Extension->BufferSize - 1); Extension->CharsInInterruptBuffer = 0; SerialHandleReducedIntBuffer(Extension); } return FALSE; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/qsfile.c ================================================ /*++ Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation Module Name: qsfile.c Abstract: This module contains the code that is very specific to query/set file operations in the serial driver. Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "qsfile.tmh" #endif #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGESRP0,SerialQueryInformationFile) #pragma alloc_text(PAGESRP0,SerialSetInformationFile) #endif NTSTATUS SerialQueryInformationFile( IN WDFDEVICE Device, IN PIRP Irp ) /*++ Routine Description: This routine is used to query the end of file information on the opened serial port. Any other file information request is retured with an invalid parameter. This routine always returns an end of file of 0. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, ">SerialQueryInformationFile(%p, %p)\n", Device, Irp); PAGED_CODE(); IrpSp = IoGetCurrentIrpStackLocation(Irp); Irp->IoStatus.Information = 0L; Status = STATUS_SUCCESS; if (IrpSp->Parameters.QueryFile.FileInformationClass == FileStandardInformation) { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(FILE_STANDARD_INFORMATION)) { Status = STATUS_BUFFER_TOO_SMALL; } else { PFILE_STANDARD_INFORMATION Buf = Irp->AssociatedIrp.SystemBuffer; Buf->AllocationSize.QuadPart = 0; Buf->EndOfFile = Buf->AllocationSize; Buf->NumberOfLinks = 0; Buf->DeletePending = FALSE; Buf->Directory = FALSE; Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION); } } else if (IrpSp->Parameters.QueryFile.FileInformationClass == FilePositionInformation) { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(FILE_POSITION_INFORMATION)) { Status = STATUS_BUFFER_TOO_SMALL; } else { ((PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)-> CurrentByteOffset.QuadPart = 0; Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION); } } else { Status = STATUS_INVALID_PARAMETER; } Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } NTSTATUS SerialSetInformationFile( IN WDFDEVICE Device, IN PIRP Irp ) /*++ Routine Description: This routine is used to set the end of file information on the opened parallel port. Any other file information request is retured with an invalid parameter. This routine always ignores the actual end of file since the query information code always returns an end of file of 0. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call --*/ { NTSTATUS Status; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, ">SerialSetInformationFile(%p, %p)\n", Device, Irp); Irp->IoStatus.Information = 0L; if ((IoGetCurrentIrpStackLocation(Irp)-> Parameters.SetFile.FileInformationClass == FileEndOfFileInformation) || (IoGetCurrentIrpStackLocation(Irp)-> Parameters.SetFile.FileInformationClass == FileAllocationInformation)) { Status = STATUS_SUCCESS; } else { Status = STATUS_INVALID_PARAMETER; } Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/read.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: read.c Abstract: This module contains the code that is very specific to read operations in the serial driver Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "read.tmh" #endif EVT_WDF_REQUEST_CANCEL SerialCancelCurrentRead; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabReadFromIsr; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialUpdateReadByIsr; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialUpdateInterruptBuffer; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialUpdateAndSwitchToUser; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialUpdateAndSwitchToNew; ULONG SerialGetCharsFromIntBuffer( PSERIAL_DEVICE_EXTENSION Extension ); NTSTATUS SerialResizeBuffer( IN PSERIAL_DEVICE_EXTENSION Extension ); ULONG SerialMoveToNewIntBuffer( PSERIAL_DEVICE_EXTENSION Extension, PUCHAR NewBuffer ); VOID SerialEvtIoRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: This is the dispatch routine for reading. It validates the parameters for the read request and if all is ok then it places the request on the work queue. Arguments: Queue - Queue handle Request - Handle to the read request Lenght - Length of the data buffer associated with the request. The default property of the queue is to not dispatch zero lenght read & write requests to the driver and complete is with status success. So we will never get a zero length request. Return Value: --*/ { PSERIAL_DEVICE_EXTENSION extension; NTSTATUS status; WDFDEVICE hDevice; WDF_REQUEST_PARAMETERS params; PREQUEST_CONTEXT reqContext; size_t bufLen; hDevice = WdfIoQueueGetDevice(Queue); extension = SerialGetDeviceExtension(hDevice); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, ">SerialEvtIoRead(%p, 0x%I64x)\n", Request, Length); if (SerialCompleteIfError(extension, Request) != STATUS_SUCCESS) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, "MajorFunction = params.Type; reqContext->Length = (ULONG) Length; status = WdfRequestRetrieveOutputBuffer (Request, Length, &reqContext->SystemBuffer, &bufLen); if (!NT_SUCCESS (status)) { SerialCompleteRequest(Request , status, 0); SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_READ, "Length); // // Well it looks like we actually have to do some // work. Put the read on the queue so that we can // process it when our previous reads are done. // SerialStartOrQueue(extension, Request, extension->ReadQueue, &extension->CurrentReadRequest, SerialStartRead); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, "SerialStartRead(%p)\n", Extension); updateChar.Extension = Extension; do { reqContext = SerialGetRequestContext(Extension->CurrentReadRequest); // // Check to see if this is a resize request. If it is // then go to a routine that specializes in that. // if (reqContext->MajorFunction != IRP_MJ_READ) { NTSTATUS localStatus = SerialResizeBuffer(Extension); UNREFERENCED_PARAMETER(localStatus); ASSERT(NT_SUCCESS(localStatus)); } else { Extension->NumberNeededForRead = reqContext->Length; // // Calculate the timeout value needed for the // request. Note that the values stored in the // timeout record are in milliseconds. // useTotalTimer = FALSE; returnWithWhatsPresent = FALSE; os2ssreturn = FALSE; crunchDownToOne = FALSE; useIntervalTimer = FALSE; // // // CIMEXCIMEX -- this is a lie // // Always initialize the timer objects so that the // completion code can tell when it attempts to // cancel the timers whether the timers had ever // been Set. // // CIMEXCIMEX -- this is the truth // // What we want to do is just make sure the timers are // cancelled to the best of our ability and move on with // life. // SerialCancelTimer(Extension->ReadRequestTotalTimer, Extension); SerialCancelTimer(Extension->ReadRequestIntervalTimer, Extension); // // We get the *current* timeout values to use for timing // this read. // timeoutsForIrp = Extension->Timeouts; // // Calculate the interval timeout for the read. // if (timeoutsForIrp.ReadIntervalTimeout && (timeoutsForIrp.ReadIntervalTimeout != MAXULONG)) { useIntervalTimer = TRUE; Extension->IntervalTime.QuadPart = UInt32x32To64( timeoutsForIrp.ReadIntervalTimeout, 10000 ); if (Extension->IntervalTime.QuadPart >= Extension->CutOverAmount.QuadPart) { Extension->IntervalTimeToUse = &Extension->LongIntervalAmount; } else { Extension->IntervalTimeToUse = &Extension->ShortIntervalAmount; } } if (timeoutsForIrp.ReadIntervalTimeout == MAXULONG) { // // We need to do special return quickly stuff here. // // 1) If both constant and multiplier are // 0 then we return immediately with whatever // we've got, even if it was zero. // // 2) If constant and multiplier are not MAXULONG // then return immediately if any characters // are present, but if nothing is there, then // use the timeouts as specified. // // 3) If multiplier is MAXULONG then do as in // "2" but return when the first character // arrives. // if (!timeoutsForIrp.ReadTotalTimeoutConstant && !timeoutsForIrp.ReadTotalTimeoutMultiplier) { returnWithWhatsPresent = TRUE; } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG) && (timeoutsForIrp.ReadTotalTimeoutMultiplier != MAXULONG)) { useTotalTimer = TRUE; os2ssreturn = TRUE; multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier; constantVal = timeoutsForIrp.ReadTotalTimeoutConstant; } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG) && (timeoutsForIrp.ReadTotalTimeoutMultiplier == MAXULONG)) { useTotalTimer = TRUE; os2ssreturn = TRUE; crunchDownToOne = TRUE; multiplierVal = 0; constantVal = timeoutsForIrp.ReadTotalTimeoutConstant; } } else { // // If both the multiplier and the constant are // zero then don't do any total timeout processing. // if (timeoutsForIrp.ReadTotalTimeoutMultiplier || timeoutsForIrp.ReadTotalTimeoutConstant) { // // We have some timer values to calculate. // useTotalTimer = TRUE; multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier; constantVal = timeoutsForIrp.ReadTotalTimeoutConstant; } } if (useTotalTimer) { totalTime.QuadPart = ((LONGLONG)(UInt32x32To64( Extension->NumberNeededForRead, multiplierVal ) + constantVal)) * -10000; } // // We do this copy in the hope of getting most (if not // all) of the characters out of the interrupt buffer. // // Note that we need to protect this operation with a // spinlock since we don't want a purge to hose us. // updateChar.CharsCopied = SerialGetCharsFromIntBuffer(Extension); // // See if we have any cause to return immediately. // if (returnWithWhatsPresent || (!Extension->NumberNeededForRead) || (os2ssreturn && reqContext->Information)) { // // We got all we needed for this read. // Update the number of characters in the // interrupt read buffer. // WdfInterruptSynchronize( Extension->WdfInterrupt, SerialUpdateInterruptBuffer, &updateChar ); reqContext->Status = STATUS_SUCCESS; } else { // // The request might go under control of the isr. It // won't hurt to initialize the reference count // right now. // SERIAL_INIT_REFERENCE(reqContext); // // If we are supposed to crunch the read down to // one character, then update the read length // in the request and truncate the number needed for // read down to one. Note that if we are doing // this crunching, then the information must be // zero (or we would have completed above) and // the number needed for the read must still be // equal to the read length. // if (crunchDownToOne) { ASSERT( (!reqContext->Information) && (Extension->NumberNeededForRead == reqContext->Length) ); Extension->NumberNeededForRead = 1; reqContext->Length = 1; } // // We still need to get more characters for this read. // synchronize with the isr so that we can update the // number of characters and if necessary it will have the // isr switch to copying into the users buffer. // WdfInterruptSynchronize( Extension->WdfInterrupt, SerialUpdateAndSwitchToUser, &updateChar ); if (!updateChar.Completed) { SerialSetCancelRoutine(Extension->CurrentReadRequest, SerialCancelCurrentRead); // // The request still isn't complete. The // completion routines will end up reinvoking // this routine. So we simply leave. // // First thought we should start off the total // timer for the read and increment the reference // count that the total timer has on the current // request. Note that this is safe, because even if // the io has been satisfied by the isr it can't // complete yet because we still own the cancel // spinlock. // if (useTotalTimer) { BOOLEAN result; result = SerialSetTimer( Extension->ReadRequestTotalTimer, totalTime ); if(result == FALSE) { SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_TOTAL_TIMER ); } } if (useIntervalTimer) { BOOLEAN result; KeQuerySystemTime( &Extension->LastReadTime ); result = SerialSetTimer( Extension->ReadRequestIntervalTimer, *Extension->IntervalTimeToUse ); if(result == FALSE) { SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_INT_TIMER ); } } break; } else { reqContext->Status = STATUS_SUCCESS; } } } // // Well the operation is complete. // SerialGetNextRequest(&Extension->CurrentReadRequest, Extension->ReadQueue, &newRequest, TRUE, Extension); } while (newRequest); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, "SerialCompleteRead(%p)\n", extension); // // We set this to indicate to the interval timer // that the read has completed. // // Recall that the interval timer dpc can be lurking in some // DPC queue. // extension->CountOnLastRead = SERIAL_COMPLETE_READ_COMPLETE; SerialTryToCompleteCurrent( extension, NULL, STATUS_SUCCESS, &extension->CurrentReadRequest, extension->ReadQueue, extension->ReadRequestIntervalTimer, extension->ReadRequestTotalTimer, SerialStartRead, SerialGetNextRequest, SERIAL_REF_ISR ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, "CountOnLastRead = SERIAL_COMPLETE_READ_CANCEL; SerialTryToCompleteCurrent( extension, SerialGrabReadFromIsr, STATUS_CANCELLED, &extension->CurrentReadRequest, extension->ReadQueue, extension->ReadRequestIntervalTimer, extension->ReadRequestTotalTimer, SerialStartRead, SerialGetNextRequest, SERIAL_REF_CANCEL ); } BOOLEAN SerialGrabReadFromIsr( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to grab (if possible) the request from the isr. If it finds that the isr still owns the request it grabs the ipr away (updating the number of characters copied into the users buffer). If it grabs it away it also decrements the reference count on the request since it no longer belongs to the isr (and the dpc that would complete it). NOTE: This routine assumes that if the current buffer that the ISR is copying characters into is the interrupt buffer then the dpc has already been queued. NOTE: This routine is being called from WdfInterruptSynchronize. NOTE: This routine assumes that it is called with the cancel spin lock held. Arguments: Context - Really a pointer to the device extension. Return Value: Always false. --*/ { PSERIAL_DEVICE_EXTENSION extension = Context; PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(extension->CurrentReadRequest); if (extension->ReadBufferBase != extension->InterruptReadBuffer) { // // We need to set the information to the number of characters // that the read wanted minus the number of characters that // didn't get read into the interrupt buffer. // reqContext->Information = reqContext->Length - ((extension->LastCharSlot - extension->CurrentCharSlot) + 1); // // Switch back to the interrupt buffer. // extension->ReadBufferBase = extension->InterruptReadBuffer; extension->CurrentCharSlot = extension->InterruptReadBuffer; extension->FirstReadableChar = extension->InterruptReadBuffer; extension->LastCharSlot = extension->InterruptReadBuffer + (extension->BufferSize - 1); extension->CharsInInterruptBuffer = 0; SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_ISR ); } return FALSE; } VOID SerialReadTimeout( IN WDFTIMER Timer ) /*++ Routine Description: This routine is used to complete a read because its total timer has expired. Arguments: Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION extension = NULL; extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer)); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, ">SerialReadTimeout(%p)\n", extension); // // We set this to indicate to the interval timer // that the read has completed due to total timeout. // // Recall that the interval timer dpc can be lurking in some // DPC queue. // extension->CountOnLastRead = SERIAL_COMPLETE_READ_TOTAL; SerialTryToCompleteCurrent( extension, SerialGrabReadFromIsr, STATUS_TIMEOUT, &extension->CurrentReadRequest, extension->ReadQueue, extension->ReadRequestIntervalTimer, extension->ReadRequestTotalTimer, SerialStartRead, SerialGetNextRequest, SERIAL_REF_TOTAL_TIMER ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, "CountOnLastRead = extension->ReadByIsr; extension->ReadByIsr = 0; return FALSE; } VOID SerialIntervalReadTimeout( IN WDFTIMER Timer ) /*++ Routine Description: This routine is used timeout the request if the time between characters exceed the interval time. A global is kept in the device extension that records the count of characters read the last the last time this routine was invoked (This dpc will resubmit the timer if the count has changed). If the count has not changed then this routine will attempt to complete the request. Note the special case of the last count being zero. The timer isn't really in effect until the first character is read. Arguments: Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION extension = NULL; extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer)); //SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, ">SerialIntervalReadTimeout(%p)\n", // extension); if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_TOTAL) { // // This value is only set by the total // timer to indicate that it has fired. // If so, then we should simply try to complete. // SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, "in SERIAL_COMPLETE_READ_TOTAL\n"); SerialTryToCompleteCurrent( extension, SerialGrabReadFromIsr, STATUS_TIMEOUT, &extension->CurrentReadRequest, extension->ReadQueue, extension->ReadRequestIntervalTimer, extension->ReadRequestTotalTimer, SerialStartRead, SerialGetNextRequest, SERIAL_REF_INT_TIMER ); } else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_COMPLETE) { // // This value is only set by the regular // completion routine. // // If so, then we should simply try to complete. // SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, "in SERIAL_COMPLETE_READ_COMPLETE\n"); SerialTryToCompleteCurrent( extension, SerialGrabReadFromIsr, STATUS_SUCCESS, &extension->CurrentReadRequest, extension->ReadQueue, extension->ReadRequestIntervalTimer, extension->ReadRequestTotalTimer, SerialStartRead, SerialGetNextRequest, SERIAL_REF_INT_TIMER ); } else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_CANCEL) { // // This value is only set by the cancel // read routine. // // If so, then we should simply try to complete. // SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, "in SERIAL_COMPLETE_READ_CANCEL\n"); SerialTryToCompleteCurrent( extension, SerialGrabReadFromIsr, STATUS_CANCELLED, &extension->CurrentReadRequest, extension->ReadQueue, extension->ReadRequestIntervalTimer, extension->ReadRequestTotalTimer, SerialStartRead, SerialGetNextRequest, SERIAL_REF_INT_TIMER ); } else if (extension->CountOnLastRead || extension->ReadByIsr) { // // Something has happened since we last came here. We // check to see if the ISR has read in any more characters. // If it did then we should update the isr's read count // and resubmit the timer. // if (extension->ReadByIsr) { WdfInterruptSynchronize( extension->WdfInterrupt, SerialUpdateReadByIsr, extension ); // // Save off the "last" time something was read. // As we come back to this routine we will compare // the current time to the "last" time. If the // difference is ever larger then the interval // requested by the user, then time out the request. // KeQuerySystemTime( &extension->LastReadTime ); SerialSetTimer( extension->ReadRequestIntervalTimer, *extension->IntervalTimeToUse ); } else { // // Take the difference between the current time // and the last time we had characters and // see if it is greater then the interval time. // if it is, then time out the request. Otherwise // go away again for a while. // // // No characters read in the interval time. Kill // this read. // LARGE_INTEGER currentTime; KeQuerySystemTime( ¤tTime ); if ((currentTime.QuadPart - extension->LastReadTime.QuadPart) >= extension->IntervalTime.QuadPart) { SerialTryToCompleteCurrent( extension, SerialGrabReadFromIsr, STATUS_TIMEOUT, &extension->CurrentReadRequest, extension->ReadQueue, extension->ReadRequestIntervalTimer, extension->ReadRequestTotalTimer, SerialStartRead, SerialGetNextRequest, SERIAL_REF_INT_TIMER ); } else { SerialSetTimer( extension->ReadRequestIntervalTimer, *extension->IntervalTimeToUse ); } } } else { // // Timer doesn't really start until the first character. // So we should simply resubmit ourselves. // SerialSetTimer( extension->ReadRequestIntervalTimer, *extension->IntervalTimeToUse ); } //SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, "CurrentReadRequest); // // The minimum of the number of characters we need and // the number of characters available // numberOfCharsToGet = Extension->CharsInInterruptBuffer; if (numberOfCharsToGet > Extension->NumberNeededForRead) { numberOfCharsToGet = Extension->NumberNeededForRead; } if (numberOfCharsToGet) { // // This will hold the number of characters between the // first available character and the end of the buffer. // Note that the buffer could wrap around but for the // purposes of the first copy we don't care about that. // firstTryNumberToGet = (ULONG)(Extension->LastCharSlot - Extension->FirstReadableChar) + 1; if (firstTryNumberToGet > numberOfCharsToGet) { // // The characters don't wrap. Actually they may wrap but // we don't care for the purposes of this read since the // characters we need are available before the wrap. // RtlMoveMemory( ((PUCHAR)(reqContext->SystemBuffer)) + (reqContext->Length - Extension->NumberNeededForRead), Extension->FirstReadableChar, numberOfCharsToGet ); Extension->NumberNeededForRead -= numberOfCharsToGet; // // We now will move the pointer to the first character after // what we just copied into the users buffer. // // We need to check if the stream of readable characters // is wrapping around to the beginning of the buffer. // // Note that we may have just taken the last characters // at the end of the buffer. // if ((Extension->FirstReadableChar + (numberOfCharsToGet - 1)) == Extension->LastCharSlot) { Extension->FirstReadableChar = Extension->InterruptReadBuffer; } else { Extension->FirstReadableChar += numberOfCharsToGet; } } else { // // The characters do wrap. Get up until the end of the buffer. // RtlMoveMemory( ((PUCHAR)(reqContext->SystemBuffer)) + (reqContext->Length - Extension->NumberNeededForRead), Extension->FirstReadableChar, firstTryNumberToGet ); Extension->NumberNeededForRead -= firstTryNumberToGet; // // Now get the rest of the characters from the beginning of the // buffer. // RtlMoveMemory( ((PUCHAR)(reqContext->SystemBuffer)) + (reqContext->Length - Extension->NumberNeededForRead), Extension->InterruptReadBuffer, numberOfCharsToGet - firstTryNumberToGet ); Extension->FirstReadableChar = Extension->InterruptReadBuffer + (numberOfCharsToGet - firstTryNumberToGet); Extension->NumberNeededForRead -= (numberOfCharsToGet - firstTryNumberToGet); } } reqContext->Information += numberOfCharsToGet; return numberOfCharsToGet; } BOOLEAN SerialUpdateInterruptBuffer( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to update the number of characters that remain in the interrupt buffer. We need to use this routine since the count could be updated during the update by execution of the ISR. NOTE: This is called by WdfInterruptSynchronize. Arguments: Context - Points to a structure that contains a pointer to the device extension and count of the number of characters that we previously copied into the users buffer. The structure actually has a third field that we don't use in this routine. Return Value: Always FALSE. --*/ { PSERIAL_UPDATE_CHAR update = Context; PSERIAL_DEVICE_EXTENSION extension = update->Extension; UNREFERENCED_PARAMETER(Interrupt); ASSERT(extension->CharsInInterruptBuffer >= update->CharsCopied); extension->CharsInInterruptBuffer -= update->CharsCopied; // // Deal with flow control if necessary. // SerialHandleReducedIntBuffer(extension); return FALSE; } BOOLEAN SerialUpdateAndSwitchToUser( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine gets the (hopefully) few characters that remain in the interrupt buffer after the first time we tried to get them out. If we still don't have enough characters to satisfy the read it will then we set things up so that the ISR uses the user buffer copy into. This routine is also used to update a count that is maintained by the ISR to keep track of the number of characters in its buffer. NOTE: This is called by WdfInterruptSynchronize. Arguments: Context - Points to a structure that contains a pointer to the device extension, a count of the number of characters that we previously copied into the users buffer, and a boolean that we will set that defines whether we switched the ISR to copy into the users buffer. Return Value: Always FALSE. --*/ { PSERIAL_UPDATE_CHAR updateChar = Context; PSERIAL_DEVICE_EXTENSION extension = updateChar->Extension; PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(extension->CurrentReadRequest); SerialUpdateInterruptBuffer(extension->WdfInterrupt, Context); // // There are more characters to get to satisfy this read. // Copy any characters that have arrived since we got // the last batch. // updateChar->CharsCopied = SerialGetCharsFromIntBuffer(extension); SerialUpdateInterruptBuffer(extension->WdfInterrupt, Context); // // No more new characters will be "received" until we exit // this routine. We again check to make sure that we // haven't satisfied this read, and if we haven't we set things // up so that the ISR copies into the user buffer. // if (extension->NumberNeededForRead) { // // We shouldn't be switching unless there are no // characters left. // ASSERT(!extension->CharsInInterruptBuffer); // // We use the following to values to do inteval timing. // // CountOnLastRead is mostly used to simply prevent // the interval timer from timing out before any characters // are read. (Interval timing should only be effective // after the first character is read.) // // After the first time the interval timer fires and // characters have be read we will simply update with // the value of ReadByIsr and then set ReadByIsr to zero. // (We do that in a synchronization routine. // // If the interval timer dpc routine ever encounters // ReadByIsr == 0 when CountOnLastRead is non-zero it // will timeout the read. // // (Note that we have a special case of CountOnLastRead // < 0. This is done by the read completion routines other // than the total timeout dpc to indicate that the total // timeout has expired.) // extension->CountOnLastRead = (LONG)reqContext->Information; extension->ReadByIsr = 0; // // By compareing the read buffer base address to the // the base address of the interrupt buffer the ISR // can determine whether we are using the interrupt // buffer or the user buffer. // extension->ReadBufferBase = reqContext->SystemBuffer; // // The current char slot is after the last copied in // character. We know there is always room since we // we wouldn't have gotten here if there wasn't. // extension->CurrentCharSlot = extension->ReadBufferBase + reqContext->Information; // // The last position that a character can go is on the // last byte of user buffer. While the actual allocated // buffer space may be bigger, we know that there is at // least as much as the read length. // extension->LastCharSlot = extension->ReadBufferBase + (reqContext->Length - 1); #if 0 // We set the cancel before calling this routine in StartRead // // Mark the request as being in a cancelable state. // IoSetCancelRoutine( extension->CurrentReadIrp, SerialCancelCurrentRead ); SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_CANCEL ); #endif // // Increment the reference count twice. // // Once for the Isr owning the request and once // because the cancel routine has a reference // to it. // SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_ISR ); updateChar->Completed = FALSE; } else { updateChar->Completed = TRUE; } return FALSE; } // // We use this structure only to communicate to the synchronization // routine when we are switching to the resized buffer. // typedef struct _SERIAL_RESIZE_PARAMS { PSERIAL_DEVICE_EXTENSION Extension; PUCHAR OldBuffer; PUCHAR NewBuffer; ULONG NewBufferSize; ULONG NumberMoved; } SERIAL_RESIZE_PARAMS,*PSERIAL_RESIZE_PARAMS; NTSTATUS SerialResizeBuffer( IN PSERIAL_DEVICE_EXTENSION Extension ) /*++ Routine Description: This routine will process the resize buffer request. If size requested for the RX buffer is smaller than the current buffer then we will simply return STATUS_SUCCESS. (We don't want to make buffers smaller. If we did that then we all of a sudden have "overrun" problems to deal with as well as flow control to deal with - very painful.) We ignore the TX buffer size request since we don't use a TX buffer. Arguments: Extension - Pointer to the device extension for the port. Return Value: STATUS_SUCCESS if everything worked out ok. STATUS_INSUFFICIENT_RESOURCES if we couldn't allocate the memory for the buffer. --*/ { PREQUEST_CONTEXT reqContext = SerialGetRequestContext(Extension->CurrentReadRequest); PSERIAL_QUEUE_SIZE rs = reqContext->SystemBuffer; PVOID newBuffer = reqContext->Type3InputBuffer; reqContext->Type3InputBuffer = NULL; reqContext->Information = 0L; reqContext->Status = STATUS_SUCCESS; if (rs->InSize <= Extension->BufferSize) { // // Nothing to do. We don't make buffers smaller. Just // agree with the user. We must deallocate the memory // that was already allocated in the ioctl dispatch routine. // ExFreePool(newBuffer); } else { SERIAL_RESIZE_PARAMS rp; // // Hmmm, looks like we actually have to go // through with this. We need to move all the // data that is in the current buffer into this // new buffer. We'll do this in two steps. // // First we go up to dispatch level and try to // move as much as we can without stopping the // ISR from running. We go up to dispatch level // by acquiring the control lock. We do it at // dispatch using the control lock so that: // // 1) We can't be context switched in the middle // of the move. Our pointers into the buffer // could be *VERY* stale by the time we got back. // // 2) We use the control lock since we don't want // some pesky purge request to come along while // we are trying to move. // // After the move, but while we still hold the control // lock, we synch with the ISR and get those last // (hopefully) few characters that have come in since // we started the copy. We switch all of our pointers, // counters, and such to point to this new buffer. NOTE: // we need to be careful. If the buffer we were using // was not the default one created when we initialized // the device (i.e. it was created via a previous WDFREQUEST of // this type), we should deallocate it. // rp.Extension = Extension; rp.OldBuffer = Extension->InterruptReadBuffer; rp.NewBuffer = newBuffer; rp.NewBufferSize = rs->InSize; rp.NumberMoved = SerialMoveToNewIntBuffer( Extension, newBuffer ); WdfInterruptSynchronize( Extension->WdfInterrupt, SerialUpdateAndSwitchToNew, &rp ); // // Free up the memory that the old buffer consumed. // ExFreePool(rp.OldBuffer); } return STATUS_SUCCESS; } ULONG SerialMoveToNewIntBuffer( PSERIAL_DEVICE_EXTENSION Extension, PUCHAR NewBuffer ) /*++ Routine Description: This routine is used to copy any characters out of the interrupt buffer into the "new" buffer. It will be reading values that are updated with the ISR but this is safe since this value is only decremented by synchronization routines. This routine will return the number of characters copied so some other routine can call a synchronization routine to update what is seen at interrupt level. Arguments: Extension - A pointer to the device extension. NewBuffer - Where the characters are to be move to. Return Value: The number of characters that were copied into the user buffer. --*/ { ULONG numberOfCharsMoved = Extension->CharsInInterruptBuffer; if (numberOfCharsMoved) { // // This holds the number of characters between the first // readable character and the last character we will read or // the real physical end of the buffer (not the last readable // character). // ULONG firstTryNumberToGet = (ULONG)(Extension->LastCharSlot - Extension->FirstReadableChar) + 1; if (firstTryNumberToGet >= numberOfCharsMoved) { // // The characters don't wrap. // RtlMoveMemory( NewBuffer, Extension->FirstReadableChar, numberOfCharsMoved ); if ((Extension->FirstReadableChar+(numberOfCharsMoved-1)) == Extension->LastCharSlot) { Extension->FirstReadableChar = Extension->InterruptReadBuffer; } else { Extension->FirstReadableChar += numberOfCharsMoved; } } else { // // The characters do wrap. Get up until the end of the buffer. // RtlMoveMemory( NewBuffer, Extension->FirstReadableChar, firstTryNumberToGet ); // // Now get the rest of the characters from the beginning of the // buffer. // RtlMoveMemory( NewBuffer+firstTryNumberToGet, Extension->InterruptReadBuffer, numberOfCharsMoved - firstTryNumberToGet ); Extension->FirstReadableChar = Extension->InterruptReadBuffer + numberOfCharsMoved - firstTryNumberToGet; } } return numberOfCharsMoved; } BOOLEAN SerialUpdateAndSwitchToNew( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine gets the (hopefully) few characters that remain in the interrupt buffer after the first time we tried to get them out. NOTE: This is called by WdfInterruptSynchronize. Arguments: Context - Points to a structure that contains a pointer to the device extension, a pointer to the buffer we are moving to, and a count of the number of characters that we previously copied into the new buffer, and the actual size of the new buffer. Return Value: Always FALSE. --*/ { PSERIAL_RESIZE_PARAMS params = Context; PSERIAL_DEVICE_EXTENSION extension = params->Extension; ULONG tempCharsInInterruptBuffer = extension->CharsInInterruptBuffer; UNREFERENCED_PARAMETER(Interrupt); ASSERT(extension->CharsInInterruptBuffer >= params->NumberMoved); // // We temporarily reduce the chars in interrupt buffer to // "fool" the move routine. We will restore it after the // move. // extension->CharsInInterruptBuffer -= params->NumberMoved; if (extension->CharsInInterruptBuffer) { SerialMoveToNewIntBuffer( extension, params->NewBuffer + params->NumberMoved ); } extension->CharsInInterruptBuffer = tempCharsInInterruptBuffer; extension->LastCharSlot = params->NewBuffer + (params->NewBufferSize - 1); extension->FirstReadableChar = params->NewBuffer; extension->ReadBufferBase = params->NewBuffer; extension->InterruptReadBuffer = params->NewBuffer; extension->BufferSize = params->NewBufferSize; // // We *KNOW* that the new interrupt buffer is larger than the // old buffer. We don't need to worry about it being full. // extension->CurrentCharSlot = extension->InterruptReadBuffer + extension->CharsInInterruptBuffer; // // We set up the default xon/xoff limits. // extension->HandFlow.XoffLimit = extension->BufferSize >> 3; extension->HandFlow.XonLimit = extension->BufferSize >> 1; extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit; extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit; extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+ (extension->BufferSize>>4)); // // Since we (essentially) reduced the percentage of the interrupt // buffer being full, we need to handle any flow of control. // SerialHandleReducedIntBuffer(extension); return FALSE; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/registry.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: registry.c Abstract: This module contains the code that is used to get values from the registry and to manipulate entries in the registry. Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "registry.tmh" #endif #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,SerialGetConfigDefaults) #pragma alloc_text(PAGESRP0,SerialGetRegistryKeyValue) #pragma alloc_text(PAGESRP0,SerialPutRegistryKeyValue) #pragma alloc_text(PAGESRP0,SerialGetFdoRegistryKeyValue) #endif // ALLOC_PRAGMA #define PARAMATER_NAME_LEN 80 NTSTATUS SerialGetConfigDefaults( IN PSERIAL_FIRMWARE_DATA DriverDefaultsPtr, IN WDFDRIVER Driver ) /*++ Routine Description: This routine reads the default configuration data from the registry for the serial driver. It also builds fields in the registry for several configuration options if they don't exist. Arguments: DriverDefaultsPtr - Pointer to a structure that will contain the default configuration values. RegistryPath - points to the entry for this driver in the current control set of the registry. Return Value: STATUS_SUCCESS if we got the defaults, otherwise we failed. The only way to fail this call is if the STATUS_INSUFFICIENT_RESOURCES. --*/ { NTSTATUS status = STATUS_SUCCESS; // return value WDFKEY hKey; DECLARE_UNICODE_STRING_SIZE(valueName,PARAMATER_NAME_LEN); status = WdfDriverOpenParametersRegistryKey(Driver, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey); if (!NT_SUCCESS (status)) { return status; } status = RtlUnicodeStringPrintf(&valueName,L"BreakOnEntry"); if (!NT_SUCCESS (status)) { goto End; } status = WdfRegistryQueryULong (hKey, &valueName, &DriverDefaultsPtr->ShouldBreakOnEntry); if (!NT_SUCCESS (status)) { DriverDefaultsPtr->ShouldBreakOnEntry = 0; } status = RtlUnicodeStringPrintf(&valueName,L"DebugLevel"); if (!NT_SUCCESS (status)) { goto End; } status = WdfRegistryQueryULong (hKey, &valueName, &DriverDefaultsPtr->DebugLevel); if (!NT_SUCCESS (status)) { DriverDefaultsPtr->DebugLevel = 0; } status = RtlUnicodeStringPrintf(&valueName,L"ForceFifoEnable"); if (!NT_SUCCESS (status)) { goto End; } status = WdfRegistryQueryULong (hKey, &valueName, &DriverDefaultsPtr->ForceFifoEnableDefault); if (!NT_SUCCESS (status)) { // // If it isn't then write out values so that it could // be adjusted later. // DriverDefaultsPtr->ForceFifoEnableDefault = SERIAL_FORCE_FIFO_DEFAULT; status = WdfRegistryAssignULong(hKey, &valueName, DriverDefaultsPtr->ForceFifoEnableDefault ); if (!NT_SUCCESS (status)) { goto End; } } status = RtlUnicodeStringPrintf(&valueName,L"RxFIFO"); if (!NT_SUCCESS (status)) { goto End; } status = WdfRegistryQueryULong (hKey, &valueName, &DriverDefaultsPtr->RxFIFODefault); if (!NT_SUCCESS (status)) { DriverDefaultsPtr->RxFIFODefault = SERIAL_RX_FIFO_DEFAULT; status = WdfRegistryAssignULong(hKey, &valueName, DriverDefaultsPtr->RxFIFODefault ); if (!NT_SUCCESS (status)) { goto End; } } status = RtlUnicodeStringPrintf(&valueName,L"TxFIFO"); if (!NT_SUCCESS (status)) { goto End; } status = WdfRegistryQueryULong (hKey, &valueName, &DriverDefaultsPtr->TxFIFODefault); if (!NT_SUCCESS (status)) { DriverDefaultsPtr->TxFIFODefault = SERIAL_TX_FIFO_DEFAULT; status = WdfRegistryAssignULong(hKey, &valueName, DriverDefaultsPtr->TxFIFODefault ); if (!NT_SUCCESS (status)) { goto End; } } status = RtlUnicodeStringPrintf(&valueName,L"PermitShare"); if (!NT_SUCCESS (status)) { goto End; } status = WdfRegistryQueryULong (hKey, &valueName, &DriverDefaultsPtr->PermitShareDefault); if (!NT_SUCCESS (status)) { DriverDefaultsPtr->PermitShareDefault = SERIAL_PERMIT_SHARE_DEFAULT; status = WdfRegistryAssignULong(hKey, &valueName, DriverDefaultsPtr->PermitShareDefault ); if (!NT_SUCCESS (status)) { goto End; } } status = RtlUnicodeStringPrintf(&valueName,L"LogFifo"); if (!NT_SUCCESS (status)) { goto End; } status = WdfRegistryQueryULong (hKey, &valueName, &DriverDefaultsPtr->LogFifoDefault); if (!NT_SUCCESS (status)) { DriverDefaultsPtr->LogFifoDefault = SERIAL_LOG_FIFO_DEFAULT; status = WdfRegistryAssignULong(hKey, &valueName, DriverDefaultsPtr->LogFifoDefault ); if (!NT_SUCCESS (status)) { goto End; } DriverDefaultsPtr->LogFifoDefault = 1; } status = RtlUnicodeStringPrintf(&valueName,L"UartRemovalDetect"); if (!NT_SUCCESS (status)) { goto End; } status = WdfRegistryQueryULong (hKey, &valueName, &DriverDefaultsPtr->UartRemovalDetect); if (!NT_SUCCESS (status)) { DriverDefaultsPtr->UartRemovalDetect = 0; } End: WdfRegistryClose(hKey); return (status); } BOOLEAN SerialGetRegistryKeyValue( IN WDFDEVICE WdfDevice, _In_ PCWSTR Name, OUT PULONG Value ) /*++ Routine Description: Can be used to read any REG_DWORD registry value stored under Device Parameter. Arguments: FdoData - pointer to the device extension Name - Name of the registry value Value - Return Value: TRUE if successful FALSE if not present/error in reading registry --*/ { WDFKEY hKey = NULL; NTSTATUS status; BOOLEAN retValue = FALSE; UNICODE_STRING valueName; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, ">SerialGetRegistryKeyValue(XXX)\n"); *Value = 0; status = WdfDeviceOpenRegistryKey(WdfDevice, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey); if (NT_SUCCESS (status)) { RtlInitUnicodeString(&valueName,Name); status = WdfRegistryQueryULong (hKey, &valueName, Value); if (NT_SUCCESS (status)) { retValue = TRUE; } WdfRegistryClose(hKey); } SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "<--SerialGetRegistryKeyValue %ws %d \n", Name, *Value); return retValue; } #define PARAMATER_NAME_LEN 80 BOOLEAN SerialPutRegistryKeyValue( IN WDFDEVICE WdfDevice, _In_ PCWSTR Name, IN ULONG Value ) /*++ Routine Description: Can be used to write any REG_DWORD registry value stored under Device Parameter. Arguments: Return Value: TRUE - if write is successful FALSE - otherwise --*/ { WDFKEY hKey = NULL; NTSTATUS status; BOOLEAN retValue = FALSE; UNICODE_STRING valueName; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "Entered PciDrvWriteRegistryValue\n"); // // write the value out to the registry // status = WdfDeviceOpenRegistryKey(WdfDevice, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey); if (NT_SUCCESS (status)) { RtlInitUnicodeString(&valueName,Name); status = WdfRegistryAssignULong (hKey, &valueName, Value ); if (NT_SUCCESS (status)) { retValue = TRUE; } WdfRegistryClose(hKey); } return retValue; } BOOLEAN SerialGetFdoRegistryKeyValue( IN PWDFDEVICE_INIT DeviceInit, _In_ PCWSTR Name, OUT PULONG Value ) /*++ Routine Description: Can be used to read any REG_DWORD registry value stored under Device Parameter. Arguments: FdoData - pointer to the device extension Name - Name of the registry value Value - Return Value: TRUE if successful FALSE if not present/error in reading registry --*/ { WDFKEY hKey = NULL; NTSTATUS status; BOOLEAN retValue = FALSE; UNICODE_STRING valueName; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "-->SerialGetFdoRegistryKeyValue\n"); *Value = 0; status = WdfFdoInitOpenRegistryKey(DeviceInit, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey); if (NT_SUCCESS (status)) { RtlInitUnicodeString(&valueName,Name); status = WdfRegistryQueryULong (hKey, &valueName, Value); if (NT_SUCCESS (status)) { retValue = TRUE; } WdfRegistryClose(hKey); } SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "<--SerialGetFdoRegistryKeyValue %ws %d \n", Name, *Value); return retValue; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/serial.h ================================================ /*++ Copyright (c) 1990, 1991, 1992, 1993 - 1997 Microsoft Corporation Module Name : serial.h Abstract: Type definitions and data for the serial port driver --*/ #define POOL_TAG 'XMOC' // // Some default driver values. We will check the registry for // them first. // #define SERIAL_UNINITIALIZED_DEFAULT 1234567 #define SERIAL_FORCE_FIFO_DEFAULT 1 #define SERIAL_RX_FIFO_DEFAULT 8 #define SERIAL_TX_FIFO_DEFAULT 14 #define SERIAL_PERMIT_SHARE_DEFAULT 0 #define SERIAL_LOG_FIFO_DEFAULT 0 // // This define gives the default Object directory // that we should use to insert the symbolic links // between the NT device name and namespace used by // that object directory. #define DEFAULT_DIRECTORY L"DosDevices" // // For the above directory, the serial port will // use the following name as the suffix of the serial // ports for that directory. It will also append // a number onto the end of the name. That number // will start at 1. #define DEFAULT_SERIAL_NAME L"COM" // // // This define gives the default NT name for // for serial ports detected by the firmware. // This name will be appended to Device prefix // with a number following it. The number is // incremented each time encounter a serial // port detected by the firmware. Note that // on a system with multiple busses, this means // that the first port on a bus is not necessarily // \Device\Serial0. // #define DEFAULT_NT_SUFFIX L"Serial" #define _DRIVER_NAME_ "Serial.sys" #define DEVICE_OBJECT_NAME_LENGTH 128 #define SYMBOLIC_NAME_LENGTH 128 #define SERIAL_DEVICE_MAP L"SERIALCOMM" // // GUID_DEVINTERFACE_COMPORT is not defined in the Win2K // headers, so we will need this definition to avoid compilation // errors. // #define GUID_DEVINTERFACE_COMPORT GUID_CLASS_COMPORT // // This value - which could be redefined at compile // time, define the stride between registers // #if !defined(SERIAL_REGISTER_STRIDE) #define SERIAL_REGISTER_STRIDE 1 #endif // // Offsets from the base register address of the // various registers for the 8250 family of UARTS. // #define RECEIVE_BUFFER_REGISTER ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE)) #define TRANSMIT_HOLDING_REGISTER ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE)) #define INTERRUPT_ENABLE_REGISTER ((ULONG)((0x01)*SERIAL_REGISTER_STRIDE)) #define INTERRUPT_IDENT_REGISTER ((ULONG)((0x02)*SERIAL_REGISTER_STRIDE)) #define FIFO_CONTROL_REGISTER ((ULONG)((0x02)*SERIAL_REGISTER_STRIDE)) #define LINE_CONTROL_REGISTER ((ULONG)((0x03)*SERIAL_REGISTER_STRIDE)) #define MODEM_CONTROL_REGISTER ((ULONG)((0x04)*SERIAL_REGISTER_STRIDE)) #define LINE_STATUS_REGISTER ((ULONG)((0x05)*SERIAL_REGISTER_STRIDE)) #define MODEM_STATUS_REGISTER ((ULONG)((0x06)*SERIAL_REGISTER_STRIDE)) #define DIVISOR_LATCH_LSB ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE)) #define DIVISOR_LATCH_MSB ((ULONG)((0x01)*SERIAL_REGISTER_STRIDE)) #define SERIAL_REGISTER_SPAN ((ULONG)(7*SERIAL_REGISTER_STRIDE)) // // If we have an interrupt status register this is its assumed // length. // #define SERIAL_STATUS_LENGTH ((ULONG)(1*SERIAL_REGISTER_STRIDE)) // // Bitmask definitions for accessing the 8250 device registers. // // // These bits define the number of data bits trasmitted in // the Serial Data Unit (SDU - Start,data, parity, and stop bits) // #define SERIAL_DATA_LENGTH_5 0x00 #define SERIAL_DATA_LENGTH_6 0x01 #define SERIAL_DATA_LENGTH_7 0x02 #define SERIAL_DATA_LENGTH_8 0x03 // // These masks define the interrupts that can be enabled or disabled. // // // This interrupt is used to notify that there is new incomming // data available. The SERIAL_RDA interrupt is enabled by this bit. // #define SERIAL_IER_RDA 0x01 // // This interrupt is used to notify that there is space available // in the transmitter for another character. The SERIAL_THR // interrupt is enabled by this bit. // #define SERIAL_IER_THR 0x02 // // This interrupt is used to notify that some sort of error occured // with the incomming data. The SERIAL_RLS interrupt is enabled by // this bit. #define SERIAL_IER_RLS 0x04 // // This interrupt is used to notify that some sort of change has // taken place in the modem control line. The SERIAL_MS interrupt is // enabled by this bit. // #define SERIAL_IER_MS 0x08 // // These masks define the values of the interrupt identification // register. The low bit must be clear in the interrupt identification // register for any of these interrupts to be valid. The interrupts // are defined in priority order, with the highest value being most // important. See above for a description of what each interrupt // implies. // #define SERIAL_IIR_RLS 0x06 #define SERIAL_IIR_RDA 0x04 #define SERIAL_IIR_CTI 0x0c #define SERIAL_IIR_THR 0x02 #define SERIAL_IIR_MS 0x00 // // This bit mask get the value of the high two bits of the // interrupt id register. If this is a 16550 class chip // these bits will be a one if the fifo's are enbled, otherwise // they will always be zero. // #define SERIAL_IIR_FIFOS_ENABLED 0xc0 // // If the low bit is logic one in the interrupt identification register // this implies that *NO* interrupts are pending on the device. // #define SERIAL_IIR_NO_INTERRUPT_PENDING 0x01 // // Use these bits to detect removal of serial card for Stratus implementation // #define SERIAL_IIR_MUST_BE_ZERO 0x30 // // These masks define access to the fifo control register. // // // Enabling this bit in the fifo control register will turn // on the fifos. If the fifos are enabled then the high two // bits of the interrupt id register will be set to one. Note // that this only occurs on a 16550 class chip. If the high // two bits in the interrupt id register are not one then // we know we have a lower model chip. // // #define SERIAL_FCR_ENABLE ((UCHAR)0x01) #define SERIAL_FCR_RCVR_RESET ((UCHAR)0x02) #define SERIAL_FCR_TXMT_RESET ((UCHAR)0x04) // // This set of values define the high water marks (when the // interrupts trip) for the receive fifo. // #define SERIAL_1_BYTE_HIGH_WATER ((UCHAR)0x00) #define SERIAL_4_BYTE_HIGH_WATER ((UCHAR)0x40) #define SERIAL_8_BYTE_HIGH_WATER ((UCHAR)0x80) #define SERIAL_14_BYTE_HIGH_WATER ((UCHAR)0xc0) // // These masks define access to the line control register. // // // This defines the bit used to control the definition of the "first" // two registers for the 8250. These registers are the input/output // register and the interrupt enable register. When the DLAB bit is // enabled these registers become the least significant and most // significant bytes of the divisor value. // #define SERIAL_LCR_DLAB 0x80 // // This defines the bit used to control whether the device is sending // a break. When this bit is set the device is sending a space (logic 0). // // Most protocols will assume that this is a hangup. // #define SERIAL_LCR_BREAK 0x40 // // These defines are used to set the line control register. // #define SERIAL_5_DATA ((UCHAR)0x00) #define SERIAL_6_DATA ((UCHAR)0x01) #define SERIAL_7_DATA ((UCHAR)0x02) #define SERIAL_8_DATA ((UCHAR)0x03) #define SERIAL_DATA_MASK ((UCHAR)0x03) #define SERIAL_1_STOP ((UCHAR)0x00) #define SERIAL_1_5_STOP ((UCHAR)0x04) // Only valid for 5 data bits #define SERIAL_2_STOP ((UCHAR)0x04) // Not valid for 5 data bits #define SERIAL_STOP_MASK ((UCHAR)0x04) #define SERIAL_NONE_PARITY ((UCHAR)0x00) #define SERIAL_ODD_PARITY ((UCHAR)0x08) #define SERIAL_EVEN_PARITY ((UCHAR)0x18) #define SERIAL_MARK_PARITY ((UCHAR)0x28) #define SERIAL_SPACE_PARITY ((UCHAR)0x38) #define SERIAL_PARITY_MASK ((UCHAR)0x38) // // These masks define access the modem control register. // // // This bit controls the data terminal ready (DTR) line. When // this bit is set the line goes to logic 0 (which is then inverted // by normal hardware). This is normally used to indicate that // the device is available to be used. Some odd hardware // protocols (like the kernel debugger) use this for handshaking // purposes. // #define SERIAL_MCR_DTR 0x01 // // This bit controls the ready to send (RTS) line. When this bit // is set the line goes to logic 0 (which is then inverted by the normal // hardware). This is used for hardware handshaking. It indicates that // the hardware is ready to send data and it is waiting for the // receiving end to set clear to send (CTS). // #define SERIAL_MCR_RTS 0x02 // // This bit is used for general purpose output. // #define SERIAL_MCR_OUT1 0x04 // // This bit is used for general purpose output. // #define SERIAL_MCR_OUT2 0x08 // // This bit controls the loopback testing mode of the device. Basically // the outputs are connected to the inputs (and vice versa). // #define SERIAL_MCR_LOOP 0x10 // // This bit enables auto flow control on a TI TL16C550C/TL16C550CI // #define SERIAL_MCR_TL16C550CAFE 0x20 // // These masks define access to the line status register. The line // status register contains information about the status of data // transfer. The first five bits deal with receive data and the // last two bits deal with transmission. An interrupt is generated // whenever bits 1 through 4 in this register are set. // // // This bit is the data ready indicator. It is set to indicate that // a complete character has been received. This bit is cleared whenever // the receive buffer register has been read. // #define SERIAL_LSR_DR 0x01 // // This is the overrun indicator. It is set to indicate that the receive // buffer register was not read befor a new character was transferred // into the buffer. This bit is cleared when this register is read. // #define SERIAL_LSR_OE 0x02 // // This is the parity error indicator. It is set whenever the hardware // detects that the incoming serial data unit does not have the correct // parity as defined by the parity select in the line control register. // This bit is cleared by reading this register. // #define SERIAL_LSR_PE 0x04 // // This is the framing error indicator. It is set whenever the hardware // detects that the incoming serial data unit does not have a valid // stop bit. This bit is cleared by reading this register. // #define SERIAL_LSR_FE 0x08 // // This is the break interrupt indicator. It is set whenever the data // line is held to logic 0 for more than the amount of time it takes // to send one serial data unit. This bit is cleared whenever the // this register is read. // #define SERIAL_LSR_BI 0x10 // // This is the transmit holding register empty indicator. It is set // to indicate that the hardware is ready to accept another character // for transmission. This bit is cleared whenever a character is // written to the transmit holding register. // #define SERIAL_LSR_THRE 0x20 // // This bit is the transmitter empty indicator. It is set whenever the // transmit holding buffer is empty and the transmit shift register // (a non-software accessable register that is used to actually put // the data out on the wire) is empty. Basically this means that all // data has been sent. It is cleared whenever the transmit holding or // the shift registers contain data. // #define SERIAL_LSR_TEMT 0x40 // // This bit indicates that there is at least one error in the fifo. // The bit will not be turned off until there are no more errors // in the fifo. // #define SERIAL_LSR_FIFOERR 0x80 // // These masks are used to access the modem status register. // Whenever one of the first four bits in the modem status // register changes state a modem status interrupt is generated. // // // This bit is the delta clear to send. It is used to indicate // that the clear to send bit (in this register) has *changed* // since this register was last read by the CPU. // #define SERIAL_MSR_DCTS 0x01 // // This bit is the delta data set ready. It is used to indicate // that the data set ready bit (in this register) has *changed* // since this register was last read by the CPU. // #define SERIAL_MSR_DDSR 0x02 // // This is the trailing edge ring indicator. It is used to indicate // that the ring indicator input has changed from a low to high state. // #define SERIAL_MSR_TERI 0x04 // // This bit is the delta data carrier detect. It is used to indicate // that the data carrier bit (in this register) has *changed* // since this register was last read by the CPU. // #define SERIAL_MSR_DDCD 0x08 // // This bit contains the (complemented) state of the clear to send // (CTS) line. // #define SERIAL_MSR_CTS 0x10 // // This bit contains the (complemented) state of the data set ready // (DSR) line. // #define SERIAL_MSR_DSR 0x20 // // This bit contains the (complemented) state of the ring indicator // (RI) line. // #define SERIAL_MSR_RI 0x40 // // This bit contains the (complemented) state of the data carrier detect // (DCD) line. // #define SERIAL_MSR_DCD 0x80 // // This should be more than enough space to hold then // numeric suffix of the device name. // #define DEVICE_NAME_DELTA 20 // // Up to 16 Ports Per card. However for sixteen // port cards the interrupt status register must me // the indexing kind rather then the bitmask kind. // // #define SERIAL_MAX_PORTS_INDEXED (16) #define SERIAL_MAX_PORTS_NONINDEXED (8) typedef struct _CONFIG_DATA { PHYSICAL_ADDRESS Controller; PHYSICAL_ADDRESS TrController; ULONG SpanOfController; ULONG ClockRate; ULONG AddressSpace; ULONG DisablePort; ULONG ForceFifoEnable; ULONG RxFIFO; ULONG TxFIFO; ULONG PermitShare; ULONG PermitSystemWideShare; ULONG LogFifo; KINTERRUPT_MODE InterruptMode; ULONG TrVector; ULONG TrIrql; KAFFINITY Affinity; ULONG TL16C550CAFC; } CONFIG_DATA,*PCONFIG_DATA; // // This structure contains configuration data, much of which // is read from the registry. // typedef struct _SERIAL_FIRMWARE_DATA { PDRIVER_OBJECT DriverObject; ULONG ControllersFound; ULONG ForceFifoEnableDefault; ULONG DebugLevel; ULONG ShouldBreakOnEntry; ULONG RxFIFODefault; ULONG TxFIFODefault; ULONG PermitShareDefault; ULONG PermitSystemWideShare; ULONG LogFifoDefault; ULONG UartRemovalDetect; UNICODE_STRING Directory; UNICODE_STRING NtNameSuffix; UNICODE_STRING DirectorySymbolicName; LIST_ENTRY ConfigList; } SERIAL_FIRMWARE_DATA,*PSERIAL_FIRMWARE_DATA; // // Default xon/xoff characters. // #define SERIAL_DEF_XON 0x11 #define SERIAL_DEF_XOFF 0x13 // // Reasons that recption may be held up. // #define SERIAL_RX_DTR ((ULONG)0x01) #define SERIAL_RX_XOFF ((ULONG)0x02) #define SERIAL_RX_RTS ((ULONG)0x04) #define SERIAL_RX_DSR ((ULONG)0x08) // // Reasons that transmission may be held up. // #define SERIAL_TX_CTS ((ULONG)0x01) #define SERIAL_TX_DSR ((ULONG)0x02) #define SERIAL_TX_DCD ((ULONG)0x04) #define SERIAL_TX_XOFF ((ULONG)0x08) #define SERIAL_TX_BREAK ((ULONG)0x10) // // These values are used by the routines that can be used // to complete a read (other than interval timeout) to indicate // to the interval timeout that it should complete. // #define SERIAL_COMPLETE_READ_CANCEL ((LONG)-1) #define SERIAL_COMPLETE_READ_TOTAL ((LONG)-2) #define SERIAL_COMPLETE_READ_COMPLETE ((LONG)-3) // // These are default values that shouldn't appear in the registry // #define SERIAL_BAD_VALUE ((ULONG)-1) typedef struct _SERIAL_DEVICE_STATE { // // TRUE if we need to set the state to open // on a powerup // BOOLEAN Reopen; // // Hardware registers // UCHAR IER; // FCR is known by other values UCHAR LCR; UCHAR MCR; // LSR is never written // MSR is never written // SCR is either scratch or interrupt status } SERIAL_DEVICE_STATE, *PSERIAL_DEVICE_STATE; typedef UCHAR (*PREAD_PORT_UCHAR)( IN UCHAR *Register ); typedef VOID (*PWRITE_PORT_UCHAR)( IN UCHAR *Register, IN UCHAR Value ); typedef struct _SERIAL_DEVICE_EXTENSION { // // WDF device handle // WDFDEVICE WdfDevice; // // Points to the device object that contains // this device extension. // PDEVICE_OBJECT DeviceObject; // // We keep a pointer around to our device name for dumps // and for creating "external" symbolic links to this // device. // UNICODE_STRING DeviceName; // // Pointer to the driver object // PDRIVER_OBJECT DriverObject; // // Records whether we actually created the symbolic link name // at driver load time. If we didn't create it, we won't try // to destroy it when we unload. // BOOLEAN CreatedSymbolicLink; // // Records whether we actually created an entry in SERIALCOMM // at driver load time. If we didn't create it, we won't try // to destroy it when the device is removed. // BOOLEAN CreatedSerialCommEntry; // // Did we update system count for serial ports // BOOLEAN IsSystemConfigInfoUpdated; // // Should we expose external interfaces? // ULONG SkipNaming; // // Support the TI TL16C550C and TL16C550CI auto flow control // ULONG TL16C550CAFC; // // Detect removed hardware in intterrupt routine flag // ULONG UartRemovalDetect; // // We keep track of whether the somebody has the device currently // opened with a simple boolean. We need to know this so that // spurious interrupts from the device (especially during initialization) // will be ignored. This value is only accessed in the ISR and // is only set via synchronization routines. We may be able // to get rid of this boolean when the code is more fleshed out. // BOOLEAN DeviceIsOpened; // // Current state during powerdown // SERIAL_DEVICE_STATE DeviceState; // // TRUE if we own power policy // BOOLEAN OwnsPowerPolicy; // // TRUE if we should retain power on close and not aggressively // reduce power consumption // BOOLEAN RetainPowerOnClose; // // Should we enable wakeup // BOOLEAN IsWakeEnabled; // // This list head is used to contain the time ordered list // of read requests. Access to this list is protected by // the global cancel spinlock. // WDFQUEUE ReadQueue; // // This list head is used to contain the time ordered list // of write requests. Access to this list is protected by // the global cancel spinlock. // WDFQUEUE WriteQueue; // // This list head is used to contain the time ordered list // of set and wait mask requests. Access to this list is protected by // the global cancel spinlock. // WDFQUEUE MaskQueue; // // Holds the serialized list of purge requests. // WDFQUEUE PurgeQueue; // // This points to the request that is currently being processed // for the read queue. This field is initialized by the open to // NULL. // // This value is only set at dispatch level. It may be // read at interrupt level. // WDFREQUEST CurrentReadRequest; // // This points to the request that is currently being processed // for the write queue. // // This value is only set at dispatch level. It may be // read at interrupt level. // WDFREQUEST CurrentWriteRequest; // // Points to the request that is currently being processed to // affect the wait mask operations. // WDFREQUEST CurrentMaskRequest; // // Points to the request that is currently being processed to // purge the read/write queues and buffers. // WDFREQUEST CurrentPurgeRequest; // // Points to the current request that is waiting on a comm event. // WDFREQUEST CurrentWaitRequest; // // Points to the request that is being used to send an immediate // character. // WDFREQUEST CurrentImmediateRequest; // // Points to the request that is being used to count the number // of characters received after an xoff (as currently defined // by the IOCTL_SERIAL_XOFF_COUNTER ioctl) is sent. // WDFREQUEST CurrentXoffRequest; // // The base address for the set of device registers // of the serial port. // PUCHAR Controller; // // This value holds the span (in units of bytes) of the register // set controlling this port. This is constant over the life // of the port. // ULONG SpanOfController; // // Address space // ULONG AddressSpace; PREAD_PORT_UCHAR SerialReadUChar; PWRITE_PORT_UCHAR SerialWriteUChar; // // Hold the clock rate input to the serial part. // ULONG ClockRate; // // The number of characters to push out if a fifo is present. // ULONG TxFifoAmount; // // Set to indicate that it is ok to share interrupts within the device. // ULONG PermitShare; // // Points to the interrupt object for used by this device. // WDFINTERRUPT WdfInterrupt; // // Translated vector // ULONG Vector; // // Translated Irql // KIRQL Irql; KINTERRUPT_MODE InterruptMode; KAFFINITY Affinity; // // This value is set by the read code to hold the time value // used for read interval timing. We keep it in the extension // so that the interval timer dpc routine determine if the // interval time has passed for the IO. // LARGE_INTEGER IntervalTime; // // These two values hold the "constant" time that we should use // to delay for the read interval time. // LARGE_INTEGER ShortIntervalAmount; LARGE_INTEGER LongIntervalAmount; // // This holds the value that we use to determine if we should use // the long interval delay or the short interval delay. // LARGE_INTEGER CutOverAmount; // // This holds the system time when we last time we had // checked that we had actually read characters. Used // for interval timing. // LARGE_INTEGER LastReadTime; // // This points the the delta time that we should use to // delay for interval timing. // PLARGE_INTEGER IntervalTimeToUse; // // Set at intialization to indicate that on the current // architecture we need to unmap the base register address // when we unload the driver. // BOOLEAN UnMapRegisters; // // Holds the number of bytes remaining in the current write // request. // // This location is only accessed while at interrupt level. // ULONG WriteLength; // // Holds a pointer to the current character to be sent in // the current write. // // This location is only accessed while at interrupt level. // PUCHAR WriteCurrentChar; // // This is a buffer for the read processing. // // The buffer works as a ring. When the character is read from // the device it will be place at the end of the ring. // // Characters are only placed in this buffer at interrupt level // although character may be read at any level. The pointers // that manage this buffer may not be updated except at interrupt // level. // PUCHAR InterruptReadBuffer; // // This is a pointer to the first character of the buffer into // which the interrupt service routine is copying characters. // PUCHAR ReadBufferBase; // // This is a count of the number of characters in the interrupt // buffer. This value is set and read at interrupt level. Note // that this value is only *incremented* at interrupt level so // it is safe to read it at any level. When characters are // copied out of the read buffer, this count is decremented by // a routine that synchronizes with the ISR. // ULONG CharsInInterruptBuffer; // // Points to the first available position for a newly received // character. This variable is only accessed at interrupt level and // buffer initialization code. // PUCHAR CurrentCharSlot; // // This variable is used to contain the last available position // in the read buffer. It is updated at open and at interrupt // level when switching between the users buffer and the interrupt // buffer. // PUCHAR LastCharSlot; // // This marks the first character that is available to satisfy // a read request. Note that while this always points to valid // memory, it may not point to a character that can be sent to // the user. This can occur when the buffer is empty. // PUCHAR FirstReadableChar; // // Pointer to the lock variable returned for this extension when // locking down the driver // PVOID LockPtr; // // This variable holds the size of whatever buffer we are currently // using. // ULONG BufferSize; // // This variable holds .8 of BufferSize. We don't want to recalculate // this real often - It's needed when so that an application can be // "notified" that the buffer is getting full. // ULONG BufferSizePt8; // // This value holds the number of characters desired for a // particular read. It is initially set by read length in the // WDFREQUEST. It is decremented each time more characters are placed // into the "users" buffer buy the code that reads characters // out of the typeahead buffer into the users buffer. If the // typeahead buffer is exhausted by the read, and the reads buffer // is given to the isr to fill, this value is becomes meaningless. // ULONG NumberNeededForRead; // // This mask will hold the bitmask sent down via the set mask // ioctl. It is used by the interrupt service routine to determine // if the occurence of "events" (in the serial drivers understanding // of the concept of an event) should be noted. // ULONG IsrWaitMask; // // This mask will always be a subset of the IsrWaitMask. While // at device level, if an event occurs that is "marked" as interesting // in the IsrWaitMask, the driver will turn on that bit in this // history mask. The driver will then look to see if there is a // request waiting for an event to occur. If there is one, it // will copy the value of the history mask into the wait request, zero // the history mask, and complete the wait request. If there is no // waiting request, the driver will be satisfied with just recording // that the event occured. If a wait request should be queued, // the driver will look to see if the history mask is non-zero. If // it is non-zero, the driver will copy the history mask into the // request, zero the history mask, and then complete the request. // ULONG HistoryMask; // // This is a pointer to the where the history mask should be // placed when completing a wait. It is only accessed at // device level. // // We have a pointer here to assist us to synchronize completing a wait. // If this is non-zero, then we have wait outstanding, and the isr still // knows about it. We make this pointer null so that the isr won't // attempt to complete the wait. // // We still keep a pointer around to the wait request, since the actual // pointer to the wait request will be used for the "common" request completion // path. // ULONG *IrpMaskLocation; // // This mask holds all of the reason that transmission // is not proceeding. Normal transmission can not occur // if this is non-zero. // // This is only written from interrupt level. // This could be (but is not) read at any level. // ULONG TXHolding; // // This mask holds all of the reason that reception // is not proceeding. Normal reception can not occur // if this is non-zero. // // This is only written from interrupt level. // This could be (but is not) read at any level. // ULONG RXHolding; // // This holds the reasons that the driver thinks it is in // an error state. // // This is only written from interrupt level. // This could be (but is not) read at any level. // ULONG ErrorWord; // // This keeps a total of the number of characters that // are in all of the "write" irps that the driver knows // about. It is only accessed with the cancel spinlock // held. // ULONG TotalCharsQueued; // // This holds a count of the number of characters read // the last time the interval timer dpc fired. It // is a long (rather than a ulong) since the other read // completion routines use negative values to indicate // to the interval timer that it should complete the read // if the interval timer DPC was lurking in some DPC queue when // some other way to complete occurs. // LONG CountOnLastRead; // // This is a count of the number of characters read by the // isr routine. It is *ONLY* written at isr level. We can // read it at dispatch level. // ULONG ReadByIsr; // // This holds the current baud rate for the device. // ULONG CurrentBaud; // // This is the number of characters read since the XoffCounter // was started. This variable is only accessed at device level. // If it is greater than zero, it implies that there is an // XoffCounter ioctl in the queue. // LONG CountSinceXoff; // // This ulong is incremented each time something trys to start // the execution path that tries to lower the RTS line when // doing transmit toggling. If it "bumps" into another path // (indicated by a false return value from queueing a dpc // and a TRUE return value tring to start a timer) it will // decrement the count. These increments and decrements // are all done at device level. Note that in the case // of a bump while trying to start the timer, we have to // go up to device level to do the decrement. // ULONG CountOfTryingToLowerRTS; // // This ULONG is used to keep track of the "named" (in ntddser.h) // baud rates that this particular device supports. // ULONG SupportedBauds; // // Holds the timeout controls for the device. This value // is set by the Ioctl processing. // // It should only be accessed under protection of the control // lock since more than one request can be in the control dispatch // routine at one time. // SERIAL_TIMEOUTS Timeouts; // // This holds the various characters that are used // for replacement on errors and also for flow control. // // They are only set at interrupt level. // SERIAL_CHARS SpecialChars; // // This structure holds the handshake and control flow // settings for the serial driver. // // It is only set at interrupt level. It can be // be read at any level with the control lock held. // SERIAL_HANDFLOW HandFlow; // // Holds performance statistics that applications can query. // Reset on each open. Only set at device level. // SERIALPERF_STATS PerfStats; // // This holds what we beleive to be the current value of // the line control register. // // It should only be accessed under protection of the control // lock since more than one request can be in the control dispatch // routine at one time. // UCHAR LineControl; // // This is only accessed at interrupt level. It keeps track // of whether the holding register is empty. // BOOLEAN HoldingEmpty; // // This variable is only accessed at interrupt level. It // indicates that we want to transmit a character immediately. // That is - in front of any characters that could be transmitting // from a normal write. // BOOLEAN TransmitImmediate; // // This variable is only accessed at interrupt level. Whenever // a wait is initiated this variable is set to false. // Whenever any kind of character is written it is set to true. // Whenever the write queue is found to be empty the code that // is processing that completing request will synchonize with the interrupt. // If this synchronization code finds that the variable is true and that // there is a wait on the transmit queue being empty then it is // certain that the queue was emptied and that it has happened since // the wait was initiated. // BOOLEAN EmptiedTransmit; // // We keep the following values around so that we can connect // to the interrupt and report resources after the configuration // record is gone. // // // We hold the character that should be transmitted immediately. // // Note that we can't use this to determine whether there is // a character to send because the character to send could be // zero. // UCHAR ImmediateChar; // // This holds the mask that will be used to mask off unwanted // data bits of the received data (valid data bits can be 5,6,7,8) // The mask will normally be 0xff. This is set while the control // lock is held since it wouldn't have adverse effects on the // isr if it is changed in the middle of reading characters. // (What it would do to the app is another question - but then // the app asked the driver to do it.) // UCHAR ValidDataMask; // // The application can turn on a mode,via the // IOCTL_SERIAL_LSRMST_INSERT ioctl, that will cause the // serial driver to insert the line status or the modem // status into the RX stream. The parameter with the ioctl // is a pointer to a UCHAR. If the value of the UCHAR is // zero, then no insertion will ever take place. If the // value of the UCHAR is non-zero (and not equal to the // xon/xoff characters), then the serial driver will insert. // UCHAR EscapeChar; // // These two booleans are used to indicate to the isr transmit // code that it should send the xon or xoff character. They are // only accessed at open and at interrupt level. // BOOLEAN SendXonChar; BOOLEAN SendXoffChar; // // This boolean will be true if a 16550 is present *and* enabled. // BOOLEAN FifoPresent; // // This is the water mark that the rxfifo should be // set to when the fifo is turned on. This is not the actual // value, but the encoded value that goes into the register. // UCHAR RxFifoTrigger; // // This points to a DPC used to complete write requests. // WDFDPC CompleteWriteDpc; // // This points to a DPC used to complete read requests. // WDFDPC CompleteReadDpc; // // This dpc is fired off if a comm error occurs. It will // execute a dpc routine that will cancel all pending reads // and writes. // WDFDPC CommErrorDpc; // // This dpc is fired off if an event occurs and there was // a request waiting on that event. A dpc routine will execute // that completes the request. // WDFDPC CommWaitDpc; // // This dpc is fired off when the transmit immediate char // character is given to the hardware. It will simply complete // the request. // WDFDPC CompleteImmediateDpc; // // This dpc is fired off if the xoff counter actually runs down // to zero. // WDFDPC XoffCountCompleteDpc; // // This dpc is fired off only from device level to start off // a timer that will queue a dpc to check if the RTS line // should be lowered when we are doing transmit toggling. // WDFDPC StartTimerLowerRTSDpc; // // This timer used to handle total read request timing. // WDFTIMER ReadRequestTotalTimer; // // This timer used to handle interval read request timing. // WDFTIMER ReadRequestIntervalTimer; // // This timer used to handle total write request timing. // WDFTIMER WriteRequestTotalTimer; // // This is timer structure used to handle total time request timing. // WDFTIMER ImmediateTotalTimer; // // This timer is used to timeout the xoff counter io. // WDFTIMER XoffCountTimer; // // This timer is used to invoke a dpc one character time // after the timer is set. That dpc will be used to check // whether we should lower the RTS line if we are doing // transmit toggling. // WDFTIMER LowerRTSTimer; // // WMI Information // // // WMI Comm Data // SERIAL_WMI_COMM_DATA WmiCommData; // // WMI HW Data // SERIAL_WMI_HW_DATA WmiHwData; // // WMI Performance Data // SERIAL_WMI_PERF_DATA WmiPerfData; } SERIAL_DEVICE_EXTENSION,*PSERIAL_DEVICE_EXTENSION; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(SERIAL_DEVICE_EXTENSION, SerialGetDeviceExtension) // // This is the scratch area for every request. // We will copy some of the frequently used information of the request // into our context area so that way we don't have to call WdfRequestGetParams // function everytime. // typedef struct _REQUEST_CONTEXT { ULONG_PTR Information; NTSTATUS Status; ULONG Length; PVOID RefCount; PVOID SystemBuffer; UCHAR MajorFunction; PFN_WDF_REQUEST_CANCEL CancelRoutine; BOOLEAN Cancelled; PVOID Type3InputBuffer; PSERIAL_DEVICE_EXTENSION Extension; ULONG IoctlCode; BOOLEAN MarkCancelableOnResume; } REQUEST_CONTEXT, *PREQUEST_CONTEXT; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, SerialGetRequestContext) // // This is the Interrupt context for the Serial device. This structure is used // for keeping track of whether the Interrupt is connected or not. // typedef struct _SERIAL_INTERRUPT_CONTEXT { // // This boolean value indicates whether Interrupt is connected. // BOOLEAN IsInterruptConnected; // // This lock is used to synchronize the file close logic and // the Surprise Removal logic. When a surprise remove happens, // the device interrupts are disabled. When this occurs, the // file close logic should not attempt to use the interrupt // object. // WDFWAITLOCK InterruptStateLock; } SERIAL_INTERRUPT_CONTEXT, *PSERIAL_INTERRUPT_CONTEXT; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(SERIAL_INTERRUPT_CONTEXT, SerialGetInterruptContext) #define SERIAL_FLAGS_CLEAR 0x0L #define SERIAL_FLAGS_STARTED 0x1L #define SERIAL_FLAGS_STOPPED 0x2L #define SERIAL_FLAGS_BROKENHW 0x4L #define SERIAL_FLAGS_LEGACY_ENUMED 0x8L __inline UCHAR SerialReadPortUChar ( IN UCHAR * x ) { return READ_PORT_UCHAR (x); } __inline VOID SerialWritePortUChar ( IN UCHAR * x, IN UCHAR y ) { WRITE_PORT_UCHAR (x,y); } __inline UCHAR SerialReadRegisterUChar ( IN UCHAR * x ) { return READ_REGISTER_UCHAR (x); } __inline VOID SerialWriteRegisterUChar ( IN UCHAR * x, IN UCHAR y ) { WRITE_REGISTER_UCHAR (x,y); } // // Sets the divisor latch register. The divisor latch register // is used to control the baud rate of the 8250. // // As with all of these routines it is assumed that it is called // at a safe point to access the hardware registers. In addition // it also assumes that the data is correct. // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // DesiredDivisor - The value to which the divisor latch register should // be set. // #define WRITE_DIVISOR_LATCH(Extension, BaseAddress,DesiredDivisor) \ do \ { \ PUCHAR Address = BaseAddress; \ SHORT Divisor = DesiredDivisor; \ UCHAR LineControl; \ LineControl = Extension->SerialReadUChar(Address+LINE_CONTROL_REGISTER); \ Extension->SerialWriteUChar( \ Address+LINE_CONTROL_REGISTER, \ (UCHAR)(LineControl | SERIAL_LCR_DLAB) \ ); \ Extension->SerialWriteUChar( \ Address+DIVISOR_LATCH_LSB, \ (UCHAR)(Divisor & 0xff) \ ); \ Extension->SerialWriteUChar( \ Address+DIVISOR_LATCH_MSB, \ (UCHAR)((Divisor & 0xff00) >> 8) \ ); \ Extension->SerialWriteUChar( \ Address+LINE_CONTROL_REGISTER, \ LineControl \ ); \ } WHILE (0) // // Reads the divisor latch register. The divisor latch register // is used to control the baud rate of the 8250. // // As with all of these routines it is assumed that it is called // at a safe point to access the hardware registers. In addition // it also assumes that the data is correct. // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // DesiredDivisor - A pointer to the 2 byte word which will contain // the value of the divisor. // #define READ_DIVISOR_LATCH(Extension, BaseAddress,PDesiredDivisor) \ do \ { \ PUCHAR Address = BaseAddress; \ PSHORT PDivisor = PDesiredDivisor; \ UCHAR LineControl; \ UCHAR Lsb; \ UCHAR Msb; \ LineControl = Extension->SerialReadUChar(Address+LINE_CONTROL_REGISTER); \ Extension->SerialWriteUChar( \ Address+LINE_CONTROL_REGISTER, \ (UCHAR)(LineControl | SERIAL_LCR_DLAB) \ ); \ Lsb = Extension->SerialReadUChar(Address+DIVISOR_LATCH_LSB); \ Msb = Extension->SerialReadUChar(Address+DIVISOR_LATCH_MSB); \ *PDivisor = Lsb; \ *PDivisor = *PDivisor | (((USHORT)Msb) << 8); \ Extension->SerialWriteUChar( \ Address+LINE_CONTROL_REGISTER, \ LineControl \ ); \ } WHILE (0) // // This macro reads the interrupt enable register. // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // #define READ_INTERRUPT_ENABLE(Extension, BaseAddress) \ (Extension->SerialReadUChar((BaseAddress)+INTERRUPT_ENABLE_REGISTER)) // // This macro writes the interrupt enable register. // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // Values - The values to write to the interrupt enable register. // #define WRITE_INTERRUPT_ENABLE(Extension, BaseAddress,Values) \ do \ { \ Extension->SerialWriteUChar( \ BaseAddress+INTERRUPT_ENABLE_REGISTER, \ Values \ ); \ } WHILE (0) // // This macro disables all interrupts on the hardware. // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // #define DISABLE_ALL_INTERRUPTS(Extension, BaseAddress) \ do \ { \ WRITE_INTERRUPT_ENABLE(Extension, BaseAddress,0); \ } WHILE (0) // // This macro enables all interrupts on the hardware. // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // #define ENABLE_ALL_INTERRUPTS(Extension, BaseAddress) \ do \ { \ \ WRITE_INTERRUPT_ENABLE( \ (Extension), (BaseAddress), \ (UCHAR)(SERIAL_IER_RDA | SERIAL_IER_THR | \ SERIAL_IER_RLS | SERIAL_IER_MS) \ ); \ \ } WHILE (0) // // This macro reads the interrupt identification register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // Note that this routine potententially quites a transmitter // empty interrupt. This is because one way that the transmitter // empty interrupt is cleared is to simply read the interrupt id // register. // // #define READ_INTERRUPT_ID_REG(Extension, BaseAddress) \ (Extension->SerialReadUChar((BaseAddress)+INTERRUPT_IDENT_REGISTER)) // // This macro reads the modem control register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // #define READ_MODEM_CONTROL(Extension, BaseAddress) \ (Extension->SerialReadUChar((BaseAddress)+MODEM_CONTROL_REGISTER)) // // This macro reads the modem status register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // #define READ_MODEM_STATUS(Extension, BaseAddress) \ (Extension->SerialReadUChar((BaseAddress)+MODEM_STATUS_REGISTER)) // // This macro reads a value out of the receive buffer // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // #define READ_RECEIVE_BUFFER(Extension, BaseAddress) \ (Extension->SerialReadUChar((BaseAddress)+RECEIVE_BUFFER_REGISTER)) // // This macro reads the line status register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // #define READ_LINE_STATUS(Extension, BaseAddress) \ (Extension->SerialReadUChar((BaseAddress)+LINE_STATUS_REGISTER)) // // This macro writes the line control register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // #define WRITE_LINE_CONTROL(Extension, BaseAddress,NewLineControl) \ do \ { \ Extension->SerialWriteUChar( \ (BaseAddress)+LINE_CONTROL_REGISTER, \ (NewLineControl) \ ); \ } WHILE (0) // // This macro reads the line control register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // #define READ_LINE_CONTROL(Extension, BaseAddress) \ (Extension->SerialReadUChar((BaseAddress)+LINE_CONTROL_REGISTER)) // // This macro writes to the transmit register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // TransmitChar - The character to send down the wire. // // #define WRITE_TRANSMIT_HOLDING(Extension, BaseAddress,TransmitChar) \ do \ { \ Extension->SerialWriteUChar( \ (BaseAddress)+TRANSMIT_HOLDING_REGISTER, \ (TransmitChar) \ ); \ } WHILE (0) // // This macro writes to the transmit FIFO register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // TransmitChars - Pointer to the characters to send down the wire. // // TxN - number of charactes to send. // // #define WRITE_TRANSMIT_FIFO_HOLDING(Extension, BaseAddress,TransmitChars,TxN) \ do \ { \ WRITE_PORT_BUFFER_UCHAR( \ (BaseAddress)+TRANSMIT_HOLDING_REGISTER, \ (TransmitChars), \ (TxN) \ ); \ } WHILE (0) // // This macro writes to the control register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // ControlValue - The value to set the fifo control register too. // // #define WRITE_FIFO_CONTROL(Extension, BaseAddress,ControlValue) \ do \ { \ Extension->SerialWriteUChar( \ (BaseAddress)+FIFO_CONTROL_REGISTER, \ (ControlValue) \ ); \ } WHILE (0) // // This macro writes to the modem control register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. // // ModemControl - The control bits to send to the modem control. // // #define WRITE_MODEM_CONTROL(Extension, BaseAddress,ModemControl) \ do \ { \ Extension->SerialWriteUChar( \ (BaseAddress)+MODEM_CONTROL_REGISTER, \ (ModemControl) \ ); \ } WHILE (0) #define WRITE_INTERRUPT_STATUS(Extension, BaseAddress,Status) \ do \ { \ Extension->SerialWriteUChar(BaseAddress, Status); \ } WHILE (0) // // This macro reads the interrupt status register // // Arguments: // // BaseAddress - A pointer to the address from which the hardware // device registers are located. BaseAddress is gotten // from PSERIAL_MULTIPORT_DISPATCH->InterruptStatus which // already has the complete address // // AddressSpace - Flag indicating where port is located, MMIO or IO // space // // #define READ_INTERRUPT_STATUS(Extension, BaseAddress) \ Extension->SerialReadUChar(BaseAddress)) // // We use this to query into the registry as to whether we // should break at driver entry. // extern SERIAL_FIRMWARE_DATA driverDefaults; // // This is exported from the kernel. It is used to point // to the address that the kernel debugger is using. // extern PUCHAR *KdComPortInUse; typedef enum _SERIAL_MEM_COMPARES { AddressesAreEqual, AddressesOverlap, AddressesAreDisjoint } SERIAL_MEM_COMPARES,*PSERIAL_MEM_COMPARES; #define SERIAL_BAUD_INVALID 0xFFFFFFFF typedef struct _SUPPORTED_BAUD_RATES { UINT32 BaudRate; ULONG Mask; }SUPPORTED_BAUD_RATES; ================================================ FILE: tests/projects/windows/driver/kmdf/serial/serial.rc ================================================ #include #include #define VER_FILETYPE VFT_DRV #define VER_FILESUBTYPE VFT2_DRV_SYSTEM #define VER_FILEDESCRIPTION_STR "Serial Device Driver" #define VER_INTERNALNAME_STR "serial.sys" #define VER_ORIGINALFILENAME_STR "serial.sys" #include "common.ver" #include "serlog.rc" ================================================ FILE: tests/projects/windows/driver/kmdf/serial/serialp.h ================================================ /*++ Copyright (c) Microsoft Corporation Module Name : serialp.h Abstract: Prototypes and macros that are used throughout the driver. --*/ //----------------------------------------------------------------------------- // 4127 -- Conditional Expression is Constant warning //----------------------------------------------------------------------------- #define WHILE(constant) \ __pragma(warning(suppress: 4127)) while(constant) typedef VOID (*PSERIAL_START_ROUTINE) ( IN PSERIAL_DEVICE_EXTENSION ); typedef VOID (*PSERIAL_GET_NEXT_ROUTINE) ( IN WDFREQUEST *CurrentOpRequest, IN WDFQUEUE QueueToProcess, OUT WDFREQUEST *NewRequest, IN BOOLEAN CompleteCurrent, PSERIAL_DEVICE_EXTENSION Extension ); DRIVER_INITIALIZE DriverEntry; EVT_WDF_DRIVER_DEVICE_ADD SerialEvtDeviceAdd; EVT_WDF_OBJECT_CONTEXT_CLEANUP SerialEvtDriverContextCleanup; EVT_WDF_DEVICE_CONTEXT_CLEANUP SerialEvtDeviceContextCleanup; EVT_WDF_DEVICE_D0_ENTRY SerialEvtDeviceD0Entry; EVT_WDF_DEVICE_D0_EXIT SerialEvtDeviceD0Exit; EVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED SerialEvtDeviceD0EntryPostInterruptsEnabled; EVT_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED SerialEvtDeviceD0ExitPreInterruptsDisabled; EVT_WDF_DEVICE_PREPARE_HARDWARE SerialEvtPrepareHardware; EVT_WDF_DEVICE_RELEASE_HARDWARE SerialEvtReleaseHardware; EVT_WDF_DEVICE_FILE_CREATE SerialEvtDeviceFileCreate; EVT_WDF_FILE_CLOSE SerialEvtFileClose; EVT_WDF_IO_QUEUE_IO_READ SerialEvtIoRead; EVT_WDF_IO_QUEUE_IO_WRITE SerialEvtIoWrite; EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL SerialEvtIoDeviceControl; EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL SerialEvtIoInternalDeviceControl; EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE SerialEvtCanceledOnQueue; EVT_WDF_IO_QUEUE_IO_STOP SerialEvtIoStop; EVT_WDF_IO_QUEUE_IO_RESUME SerialEvtIoResume; EVT_WDF_INTERRUPT_ENABLE SerialEvtInterruptEnable; EVT_WDF_INTERRUPT_DISABLE SerialEvtInterruptDisable; EVT_WDF_DPC SerialCompleteRead; EVT_WDF_DPC SerialCompleteWrite; EVT_WDF_DPC SerialCommError; EVT_WDF_DPC SerialCompleteImmediate; EVT_WDF_DPC SerialCompleteXoff; EVT_WDF_DPC SerialCompleteWait; EVT_WDF_DPC SerialStartTimerLowerRTS; EVT_WDF_TIMER SerialReadTimeout; EVT_WDF_TIMER SerialIntervalReadTimeout; EVT_WDF_TIMER SerialWriteTimeout; EVT_WDF_TIMER SerialTimeoutImmediate; EVT_WDF_TIMER SerialTimeoutXoff; EVT_WDF_TIMER SerialInvokePerhapsLowerRTS; VOID SerialStartRead( IN PSERIAL_DEVICE_EXTENSION Extension ); VOID SerialStartWrite( IN PSERIAL_DEVICE_EXTENSION Extension ); VOID SerialStartMask( IN PSERIAL_DEVICE_EXTENSION Extension ); VOID SerialStartImmediate( IN PSERIAL_DEVICE_EXTENSION Extension ); VOID SerialStartPurge( IN PSERIAL_DEVICE_EXTENSION Extension ); VOID SerialGetNextWrite( IN WDFREQUEST *CurrentOpRequest, IN WDFQUEUE QueueToProcess, IN WDFREQUEST *NewRequest, IN BOOLEAN CompleteCurrent, IN PSERIAL_DEVICE_EXTENSION Extension ); EVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialWdmDeviceFileCreate; EVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialWdmFileClose; EVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialFlush; EVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialQueryInformationFile; EVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialSetInformationFile; NTSTATUS SerialDeviceFileCreateWorker ( IN WDFDEVICE Device ); VOID SerialFileCloseWorker( IN WDFDEVICE Device ); EVT_WDF_INTERRUPT_SYNCHRONIZE SerialProcessEmptyTransmit; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetDTR; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialClrDTR; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetRTS; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialClrRTS; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetBaud; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetLineControl; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetHandFlow; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialTurnOnBreak; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialTurnOffBreak; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialPretendXoff; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialPretendXon; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialReset; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialPerhapsLowerRTS; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialMarkOpen; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialMarkClose; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGetStats; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialClearStats; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetChars; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetMCRContents; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGetMCRContents; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetFCRContents; BOOLEAN SerialSetupNewHandFlow( IN PSERIAL_DEVICE_EXTENSION Extension, IN PSERIAL_HANDFLOW NewHandFlow ); VOID SerialHandleReducedIntBuffer( IN PSERIAL_DEVICE_EXTENSION Extension ); VOID SerialProdXonXoff( IN PSERIAL_DEVICE_EXTENSION Extension, IN BOOLEAN SendXon ); EVT_WDF_REQUEST_CANCEL SerialCancelWait; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialPurgeInterruptBuff; VOID SerialPurgeRequests( IN WDFQUEUE QueueToClean, IN WDFREQUEST *CurrentOpRequest ); VOID SerialFlushRequests( IN WDFQUEUE QueueToClean, IN WDFREQUEST *CurrentOpRequest ); VOID SerialGetNextRequest( IN WDFREQUEST *CurrentOpRequest, IN WDFQUEUE QueueToProcess, OUT WDFREQUEST *NextIrp, IN BOOLEAN CompleteCurrent, IN PSERIAL_DEVICE_EXTENSION extension ); VOID SerialTryToCompleteCurrent( IN PSERIAL_DEVICE_EXTENSION Extension, IN PFN_WDF_INTERRUPT_SYNCHRONIZE SynchRoutine OPTIONAL, IN NTSTATUS StatusToUse, IN WDFREQUEST *CurrentOpRequest, IN WDFQUEUE QueueToProcess, IN WDFTIMER IntervalTimer, IN WDFTIMER TotalTimer, IN PSERIAL_START_ROUTINE Starter, IN PSERIAL_GET_NEXT_ROUTINE GetNextIrp, IN LONG RefType ); VOID SerialStartOrQueue( IN PSERIAL_DEVICE_EXTENSION Extension, IN WDFREQUEST Request, IN WDFQUEUE QueueToExamine, IN WDFREQUEST *CurrentOpRequest, IN PSERIAL_START_ROUTINE Starter ); NTSTATUS SerialCompleteIfError( PSERIAL_DEVICE_EXTENSION extension, WDFREQUEST Request ); ULONG SerialHandleModemUpdate( IN PSERIAL_DEVICE_EXTENSION Extension, IN BOOLEAN DoingTX ); EVT_WDF_INTERRUPT_ISR SerialISR; NTSTATUS SerialGetDivisorFromBaud( IN ULONG ClockRate, IN LONG DesiredBaud, OUT PSHORT AppropriateDivisor ); VOID SerialCleanupDevice( IN PSERIAL_DEVICE_EXTENSION Extension ); UCHAR SerialProcessLSR( IN PSERIAL_DEVICE_EXTENSION Extension ); LARGE_INTEGER SerialGetCharTime( IN PSERIAL_DEVICE_EXTENSION Extension ); VOID SerialPutChar( IN PSERIAL_DEVICE_EXTENSION Extension, IN UCHAR CharToPut ); NTSTATUS SerialGetConfigDefaults( IN PSERIAL_FIRMWARE_DATA DriverDefaultsPtr, IN WDFDRIVER Driver ); VOID SerialGetProperties( IN PSERIAL_DEVICE_EXTENSION Extension, IN PSERIAL_COMMPROP Properties ); VOID SerialLogError( _In_ PDRIVER_OBJECT DriverObject, _In_opt_ PDEVICE_OBJECT DeviceObject, _In_ PHYSICAL_ADDRESS P1, _In_ PHYSICAL_ADDRESS P2, _In_ ULONG SequenceNumber, _In_ UCHAR MajorFunctionCode, _In_ UCHAR RetryCount, _In_ ULONG UniqueErrorValue, _In_ NTSTATUS FinalStatus, _In_ NTSTATUS SpecificIOStatus, _In_ ULONG LengthOfInsert1, _In_reads_bytes_opt_(LengthOfInsert1) PWCHAR Insert1, _In_ ULONG LengthOfInsert2, _In_reads_bytes_opt_(LengthOfInsert2) PWCHAR Insert2 ); NTSTATUS SerialMapHWResources( IN WDFDEVICE Device, IN WDFCMRESLIST PResList, IN WDFCMRESLIST PTrResList, OUT PCONFIG_DATA PConfig ); VOID SerialUnmapHWResources( IN PSERIAL_DEVICE_EXTENSION PDevExt ); BOOLEAN SerialGetRegistryKeyValue ( IN WDFDEVICE WdfDevice, _In_ PCWSTR Name, OUT PULONG Value ); BOOLEAN SerialPutRegistryKeyValue ( IN WDFDEVICE WdfDevice, _In_ PCWSTR Name, IN ULONG Value ); NTSTATUS SerialInitController( IN PSERIAL_DEVICE_EXTENSION pDevExt, IN PCONFIG_DATA PConfigData ); BOOLEAN SerialCIsrSw( IN WDFINTERRUPT Interrupt, IN ULONG MessageID ); NTSTATUS SerialDoExternalNaming( IN PSERIAL_DEVICE_EXTENSION PDevExt ); PVOID SerialGetMappedAddress( PHYSICAL_ADDRESS IoAddress, ULONG NumberOfBytes, ULONG AddressSpace, PBOOLEAN MappedAddress ); BOOLEAN SerialDoesPortExist( IN PSERIAL_DEVICE_EXTENSION Extension, PUNICODE_STRING InsertString, IN ULONG ForceFifo, IN ULONG LogFifo ); SERIAL_MEM_COMPARES SerialMemCompare( IN PHYSICAL_ADDRESS A, IN ULONG SpanOfA, IN PHYSICAL_ADDRESS B, IN ULONG SpanOfB ); VOID SerialUndoExternalNaming( IN PSERIAL_DEVICE_EXTENSION Extension ); VOID SerialReleaseResources( IN PSERIAL_DEVICE_EXTENSION PDevExt ); VOID SerialPurgePendingRequests( PSERIAL_DEVICE_EXTENSION pDevExt ); VOID SerialDisableUART( IN PVOID Context ); VOID SerialDrainUART( IN PSERIAL_DEVICE_EXTENSION PDevExt, IN PLARGE_INTEGER PDrainTime ); VOID SerialSaveDeviceState( IN PSERIAL_DEVICE_EXTENSION PDevExt ); NTSTATUS SerialSetPowerPolicy( IN PSERIAL_DEVICE_EXTENSION DeviceExtension ); UINT32 SerialReportMaxBaudRate( ULONG Bauds ); BOOLEAN SerialInsertQueueDpc( IN WDFDPC Dpc ); BOOLEAN SerialSetTimer( IN WDFTIMER Timer, IN LARGE_INTEGER DueTime ); BOOLEAN SerialCancelTimer( IN WDFTIMER Timer, IN PSERIAL_DEVICE_EXTENSION PDevExt ); VOID SerialUnlockPages( IN WDFDPC PDpc, IN PVOID PDeferredContext, IN PVOID PSysContext1, IN PVOID PSysContext2) ; VOID SerialMarkHardwareBroken( IN PSERIAL_DEVICE_EXTENSION PDevExt ); VOID SerialDisableInterfacesResources( IN PSERIAL_DEVICE_EXTENSION PDevExt, IN BOOLEAN DisableUART ); VOID SerialSetDeviceFlags( IN PSERIAL_DEVICE_EXTENSION PDevExt, OUT PULONG PFlags, IN ULONG Value, IN BOOLEAN Set ); VOID SetDeviceIsOpened( IN PSERIAL_DEVICE_EXTENSION PDevExt, IN BOOLEAN DeviceIsOpened, IN BOOLEAN Reopen ); BOOLEAN IsQueueEmpty( IN WDFQUEUE Queue ); NTSTATUS SerialCreateTimersAndDpcs( IN PSERIAL_DEVICE_EXTENSION PDevExt ); VOID SerialDrainTimersAndDpcs( IN PSERIAL_DEVICE_EXTENSION PDevExt ); VOID SerialSetCancelRoutine( IN WDFREQUEST Request, IN PFN_WDF_REQUEST_CANCEL CancelRoutine ); NTSTATUS SerialClearCancelRoutine( IN WDFREQUEST Request, IN BOOLEAN ClearReference ); NTSTATUS SerialWmiRegistration( WDFDEVICE Device ); NTSTATUS SerialReadSymName( IN WDFDEVICE Device, _Out_writes_bytes_(*SizeOfRegName) PWSTR RegName, _Inout_ PUSHORT SizeOfRegName ); VOID SerialCompleteRequest( IN WDFREQUEST Request, IN NTSTATUS Status, IN ULONG_PTR Info ); BOOLEAN SerialGetFdoRegistryKeyValue( IN PWDFDEVICE_INIT DeviceInit, _In_ PCWSTR Name, OUT PULONG Value ); VOID SerialSetInterruptPolicy( _In_ WDFINTERRUPT WdfInterrupt ); typedef struct _SERIAL_UPDATE_CHAR { PSERIAL_DEVICE_EXTENSION Extension; ULONG CharsCopied; BOOLEAN Completed; } SERIAL_UPDATE_CHAR,*PSERIAL_UPDATE_CHAR; // // The following simple structure is used to send a pointer // the device extension and an ioctl specific pointer // to data. // typedef struct _SERIAL_IOCTL_SYNC { PSERIAL_DEVICE_EXTENSION Extension; PVOID Data; } SERIAL_IOCTL_SYNC,*PSERIAL_IOCTL_SYNC; // // The following three macros are used to initialize, set // and clear references in IRPs that are used by // this driver. The reference is stored in the fourth // argument of the request, which is never used by any operation // accepted by this driver. // #define SERIAL_REF_ISR (0x00000001) #define SERIAL_REF_CANCEL (0x00000002) #define SERIAL_REF_TOTAL_TIMER (0x00000004) #define SERIAL_REF_INT_TIMER (0x00000008) #define SERIAL_REF_XOFF_REF (0x00000010) #define SERIAL_INIT_REFERENCE(ReqContext) { \ (ReqContext)->RefCount = NULL; \ } #define SERIAL_SET_REFERENCE(ReqContext, RefType) \ do { \ LONG _refType = (RefType); \ PULONG_PTR _arg4 = (PVOID)&(ReqContext)->RefCount; \ ASSERT(!(*_arg4 & _refType)); \ *_arg4 |= _refType; \ } WHILE (0) #define SERIAL_CLEAR_REFERENCE(ReqContext, RefType) \ do { \ LONG _refType = (RefType); \ PULONG_PTR _arg4 = (PVOID)&(ReqContext)->RefCount; \ ASSERT(*_arg4 & _refType); \ *_arg4 &= ~_refType; \ } WHILE (0) #define SERIAL_REFERENCE_COUNT(ReqContext) \ ((ULONG_PTR)(((ReqContext)->RefCount))) #define SERIAL_TEST_REFERENCE(ReqContext, RefType) ((ULONG_PTR)ReqContext ->RefCount & RefType) // // Prototypes and defines to handle processor groups. // typedef USHORT (*PFN_KE_GET_ACTIVE_GROUP_COUNT)( VOID ); typedef KAFFINITY (*PFN_KE_QUERY_GROUP_AFFINITY) ( _In_ USHORT GroupNumber ); // // Force the serial interrupt to run on the last interrupt group. // //#define SERIAL_SELECT_INTERRUPT_GROUP 1 #define SERIAL_LAST_INTERRUPT_GROUP 0xFFFF #define SERIAL_PREFERRED_INTERRUPT_GROUP SERIAL_LAST_INTERRUPT_GROUP ================================================ FILE: tests/projects/windows/driver/kmdf/serial/serlog.mc ================================================ ;/*++ BUILD Version: 0001 // Increment this if a change has global effects ; ;Copyright (c) 1992, 1993 Microsoft Corporation ; ;Module Name: ; ; ntiologc.h ; ;Abstract: ; ; Constant definitions for the I/O error code log values. ; ;--*/ ; ;#ifndef _SERLOG_ ;#define _SERLOG_ ; ;// ;// Status values are 32 bit values layed out as follows: ;// ;// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 ;// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 ;// +---+-+-------------------------+-------------------------------+ ;// |Sev|C| Facility | Code | ;// +---+-+-------------------------+-------------------------------+ ;// ;// where ;// ;// Sev - is the severity code ;// ;// 00 - Success ;// 01 - Informational ;// 10 - Warning ;// 11 - Error ;// ;// C - is the Customer code flag ;// ;// Facility - is the facility code ;// ;// Code - is the facility's status code ;// ; MessageIdTypedef=NTSTATUS SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS Informational=0x1:STATUS_SEVERITY_INFORMATIONAL Warning=0x2:STATUS_SEVERITY_WARNING Error=0x3:STATUS_SEVERITY_ERROR ) FacilityNames=(System=0x0 RpcRuntime=0x2:FACILITY_RPC_RUNTIME RpcStubs=0x3:FACILITY_RPC_STUBS Io=0x4:FACILITY_IO_ERROR_CODE Serial=0x6:FACILITY_SERIAL_ERROR_CODE ) MessageId=0x0001 Facility=Serial Severity=Informational SymbolicName=SERIAL_KERNEL_DEBUGGER_ACTIVE Language=English The kernel debugger is already using %2. . MessageId=0x0002 Facility=Serial Severity=Informational SymbolicName=SERIAL_FIFO_PRESENT Language=English While validating that %2 was really a serial port, a fifo was detected. The fifo will be used. . MessageId=0x0003 Facility=Serial Severity=Informational SymbolicName=SERIAL_USER_OVERRIDE Language=English User configuration data for parameter %2 overriding firmware configuration data. . MessageId=0x0004 Facility=Serial Severity=Warning SymbolicName=SERIAL_NO_SYMLINK_CREATED Language=English Unable to create the symbolic link for %2. . MessageId=0x0005 Facility=Serial Severity=Warning SymbolicName=SERIAL_NO_DEVICE_MAP_CREATED Language=English Unable to create the device map entry for %2. . MessageId=0x0006 Facility=Serial Severity=Warning SymbolicName=SERIAL_NO_DEVICE_MAP_DELETED Language=English Unable to delete the device map entry for %2. . MessageId=0x0007 Facility=Serial Severity=Error SymbolicName=SERIAL_UNREPORTED_IRQL_CONFLICT Language=English Another driver on the system, which did not report its resources, has already claimed the interrupt used by %2. . MessageId=0x0008 Facility=Serial Severity=Error SymbolicName=SERIAL_INSUFFICIENT_RESOURCES Language=English Not enough resources were available for the driver. . MessageId=0x0009 Facility=Serial Severity=Error SymbolicName=SERIAL_UNSUPPORTED_CLOCK_RATE Language=English The baud clock rate configuration is not supported on device %2. . MessageId=0x000A Facility=Serial Severity=Error SymbolicName=SERIAL_REGISTERS_NOT_MAPPED Language=English The hardware locations for %2 could not be translated to something the memory management system could understand. . MessageId=0x000B Facility=Serial Severity=Error SymbolicName=SERIAL_RESOURCE_CONFLICT Language=English The hardware resources for %2 are already in use by another device. . MessageId=0x000C Facility=Serial Severity=Error SymbolicName=SERIAL_NO_BUFFER_ALLOCATED Language=English No memory could be allocated in which to place new data for %2. . MessageId=0x000D Facility=Serial Severity=Error SymbolicName=SERIAL_IER_INVALID Language=English While validating that %2 was really a serial port, the interrupt enable register contained enabled bits in a must be zero bitfield. The device is assumed not to be a serial port and will be deleted. . MessageId=0x000E Facility=Serial Severity=Error SymbolicName=SERIAL_MCR_INVALID Language=English While validating that %2 was really a serial port, the modem control register contained enabled bits in a must be zero bitfield. The device is assumed not to be a serial port and will be deleted. . MessageId=0x000F Facility=Serial Severity=Error SymbolicName=SERIAL_IIR_INVALID Language=English While validating that %2 was really a serial port, the interrupt id register contained enabled bits in a must be zero bitfield. The device is assumed not to be a serial port and will be deleted. . MessageId=0x0010 Facility=Serial Severity=Error SymbolicName=SERIAL_DL_INVALID Language=English While validating that %2 was really a serial port, the baud rate register could not be set consistantly. The device is assumed not to be a serial port and will be deleted. . MessageId=0x0011 Facility=Serial Severity=Error SymbolicName=SERIAL_NOT_ENOUGH_CONFIG_INFO Language=English Some firmware configuration information was incomplete. . MessageId=0x0012 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_PARAMETERS_INFO Language=English No Parameters subkey was found for user defined data. This is odd, and it also means no user configuration can be found. . MessageId=0x0013 Facility=Serial Severity=Error SymbolicName=SERIAL_UNABLE_TO_ACCESS_CONFIG Language=English Specific user configuration data is unretrievable. . MessageId=0x0014 Facility=Serial Severity=Error SymbolicName=SERIAL_INVALID_PORT_INDEX Language=English On parameter %2 which indicates a multiport card, must have a port index specified greater than 0. . MessageId=0x0015 Facility=Serial Severity=Error SymbolicName=SERIAL_PORT_INDEX_TOO_HIGH Language=English On parameter %2 which indicates a multiport card, the port index for the multiport card is too large. . MessageId=0x0016 Facility=Serial Severity=Error SymbolicName=SERIAL_UNKNOWN_BUS Language=English The bus type for %2 is not recognizable. . MessageId=0x0017 Facility=Serial Severity=Error SymbolicName=SERIAL_BUS_NOT_PRESENT Language=English The bus type for %2 is not available on this computer. . MessageId=0x0018 Facility=Serial Severity=Error SymbolicName=SERIAL_BUS_INTERRUPT_CONFLICT Language=English The bus specified for %2 does not support the specified method of interrupt. . MessageId=0x0019 Facility=Serial Severity=Error SymbolicName=SERIAL_INVALID_USER_CONFIG Language=English User configuration for parameter %2 must have %3. . MessageId=0x001A Facility=Serial Severity=Error SymbolicName=SERIAL_DEVICE_TOO_HIGH Language=English The user specified port for %2 is way too high in physical memory. . MessageId=0x001B Facility=Serial Severity=Error SymbolicName=SERIAL_STATUS_TOO_HIGH Language=English The status port for %2 is way too high in physical memory. . MessageId=0x001C Facility=Serial Severity=Error SymbolicName=SERIAL_STATUS_CONTROL_CONFLICT Language=English The status port for %2 overlaps the control registers for the device. . MessageId=0x001D Facility=Serial Severity=Error SymbolicName=SERIAL_CONTROL_OVERLAP Language=English The control registers for %2 overlaps with the %3 control registers. . MessageId=0x001E Facility=Serial Severity=Error SymbolicName=SERIAL_STATUS_OVERLAP Language=English The status register for %2 overlaps the %3 control registers. . MessageId=0x001F Facility=Serial Severity=Error SymbolicName=SERIAL_STATUS_STATUS_OVERLAP Language=English The status register for %2 overlaps with the %3 status register. . MessageId=0x0020 Facility=Serial Severity=Error SymbolicName=SERIAL_CONTROL_STATUS_OVERLAP Language=English The control registers for %2 overlaps the %3 status register. . MessageId=0x0021 Facility=Serial Severity=Error SymbolicName=SERIAL_MULTI_INTERRUPT_CONFLICT Language=English Two ports, %2 and %3, on a single multiport card can't have two different interrupts. . MessageId=0x0022 Facility=Serial Severity=Informational SymbolicName=SERIAL_DISABLED_PORT Language=English Disabling %2 as requested by the configuration data. . MessageId=0x0023 Facility=Serial Severity=Error SymbolicName=SERIAL_GARBLED_PARAMETER Language=English Parameter %2 data is unretrievable from the registry. . MessageId=0x0024 Facility=Serial Severity=Error SymbolicName=SERIAL_DLAB_INVALID Language=English While validating that %2 was really a serial port, the contents of the divisor latch register was identical to the interrupt enable and the receive registers. The device is assumed not to be a serial port and will be deleted. . MessageId=0x0025 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_TRANSLATE_PORT Language=English Could not translate the user reported I/O port for %2. . MessageId=0x0026 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_GET_INTERRUPT Language=English Could not get the user reported interrupt for %2 from the HAL. . MessageId=0x0027 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_TRANSLATE_ISR Language=English Could not translate the user reported Interrupt Status Register for %2. . MessageId=0x0028 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_DEVICE_REPORT Language=English Could not report the discovered legacy device %2 to the IO subsystem. . MessageId=0x0029 Facility=Serial Severity=Error SymbolicName=SERIAL_REGISTRY_WRITE_FAILED Language=English Error writing to the registry. . MessageId=0x002A Facility=Serial Severity=Warning SymbolicName=SERIAL_MOUSE_CONFLICT_IRQ Language=English There is a serial mouse using the same interrupt as %2. Therefore, %2 will not be started. . MessageId=0x002B Facility=Serial Severity=Warning SymbolicName=SERIAL_MOUSE_ON_PORT Language=English There was a serial mouse found on %2. Therefore, %2 will be assigned to the mouse. . MessageId=0x002C Facility=Serial Severity=Error SymbolicName=SERIAL_NO_DEVICE_REPORT_RES Language=English Could not report device %2 to IO subsystem due to a resource conflict. . MessageId=0x002D Facility=Serial Severity=Error SymbolicName=SERIAL_HARDWARE_FAILURE Language=English The serial driver detected a hardware failure on device %2 and will disable this device. . ;#endif /* _NTIOLOGC_ */ ================================================ FILE: tests/projects/windows/driver/kmdf/serial/trace.h ================================================ /*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: TRACE.h Abstract: Header file for the debug tracing related function defintions and macros. Environment: Kernel mode --*/ #include // For TRACE_LEVEL definitions #if !defined(EVENT_TRACING) // // TODO: These defines are missing in evntrace.h // in some DDK build environments (XP). // #if !defined(TRACE_LEVEL_NONE) #define TRACE_LEVEL_NONE 0 #define TRACE_LEVEL_CRITICAL 1 #define TRACE_LEVEL_FATAL 1 #define TRACE_LEVEL_ERROR 2 #define TRACE_LEVEL_WARNING 3 #define TRACE_LEVEL_INFORMATION 4 #define TRACE_LEVEL_VERBOSE 5 #define TRACE_LEVEL_RESERVED6 6 #define TRACE_LEVEL_RESERVED7 7 #define TRACE_LEVEL_RESERVED8 8 #define TRACE_LEVEL_RESERVED9 9 #endif // // Define Debug Flags // #define DBG_INIT 0x00000001 #define DBG_PNP 0x00000002 #define DBG_POWER 0x00000004 #define DBG_WMI 0x00000008 #define DBG_CREATE_CLOSE 0x00000010 #define DBG_IOCTLS 0x00000020 #define DBG_WRITE 0x00000040 #define DBG_READ 0x00000080 #define DBG_DPC 0x00000100 #define DBG_INTERRUPT 0x00000200 #define DBG_LOCKS 0x00000400 #define DBG_QUEUEING 0x00000800 #define DBG_HW_ACCESS 0x00001000 VOID TraceEvents ( IN ULONG DebugPrintLevel, IN ULONG DebugPrintFlag, IN PCCHAR DebugMessage, ... ); #define WPP_INIT_TRACING(DriverObject, RegistryPath) #define WPP_CLEANUP(DriverObject) #else // // If software tracing is defined in the sources file.. // WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver. // *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID *** // WPP_DEFINE_BIT allows setting debug bit masks to selectively print. // The names defined in the WPP_DEFINE_BIT call define the actual names // that are used to control the level of tracing for the control guid // specified. // // Name of the logger is Serial and the guid is // {F3A79AB6-9827-4419-9465-45CF949EF659} // (0xf3a79ab6, 0x9827, 0x4419, 0x94, 0x65, 0x45, 0xcf, 0x94, 0x9e, 0xf6, 0x59); // #define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings #define WPP_CONTROL_GUIDS \ WPP_DEFINE_CONTROL_GUID(SerialTraceGuid,(bc6c9364,fc67,42c5,acf7,abed3b12ecc6), \ WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ WPP_DEFINE_BIT(DBG_IOCTLS) /* bit 5 = 0x00000020 */ \ WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ WPP_DEFINE_BIT(DBG_DPC) /* bit 8 = 0x00000100 */ \ WPP_DEFINE_BIT(DBG_INTERRUPT) /* bit 9 = 0x00000200 */ \ WPP_DEFINE_BIT(DBG_LOCKS) /* bit 10 = 0x00000400 */ \ WPP_DEFINE_BIT(DBG_QUEUEING) /* bit 11 = 0x00000800 */ \ WPP_DEFINE_BIT(DBG_HW_ACCESS) /* bit 12 = 0x00001000 */ \ /* You can have up to 32 defines. If you want more than that,\ you have to provide another trace control GUID */\ ) #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) #endif ================================================ FILE: tests/projects/windows/driver/kmdf/serial/utils.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: utils.c Abstract: This module contains code that perform queueing and completion manipulation on requests. Also module generic functions such as error logging. Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "utils.tmh" #endif #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGESRP0,SerialMemCompare) #pragma alloc_text(PAGESRP0,SerialLogError) #pragma alloc_text(PAGESRP0,SerialMarkHardwareBroken) #endif // ALLOC_PRAGMA VOID SerialRundownIrpRefs( IN WDFREQUEST *CurrentOpRequest, IN WDFTIMER IntervalTimer, IN WDFTIMER TotalTimer, IN PSERIAL_DEVICE_EXTENSION PDevExt, IN LONG RefType ); static const PHYSICAL_ADDRESS SerialPhysicalZero = {0}; VOID SerialPurgeRequests( IN WDFQUEUE QueueToClean, IN WDFREQUEST *CurrentOpRequest ) /*++ Routine Description: This function is used to cancel all queued and the current irps for reads or for writes. Called at DPC level. Arguments: QueueToClean - A pointer to the queue which we're going to clean out. CurrentOpRequest - Pointer to a pointer to the current request. Return Value: None. --*/ { NTSTATUS status; PREQUEST_CONTEXT reqContext; WdfIoQueuePurge(QueueToClean, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); // // The queue is clean. Now go after the current if // it's there. // if (*CurrentOpRequest) { PFN_WDF_REQUEST_CANCEL CancelRoutine; reqContext = SerialGetRequestContext(*CurrentOpRequest); CancelRoutine = reqContext->CancelRoutine; // // Clear the common cancel routine but don't clear the reference because the // request specific cancel routine called below will clear the reference. // status = SerialClearCancelRoutine(*CurrentOpRequest, FALSE); if (NT_SUCCESS(status)) { // // Let us just call the CancelRoutine to start the next request. // if(CancelRoutine) { CancelRoutine(*CurrentOpRequest); } } } } VOID SerialFlushRequests( IN WDFQUEUE QueueToClean, IN WDFREQUEST *CurrentOpRequest ) /*++ Routine Description: This function is used to cancel all queued and the current irps for reads or for writes. Called at DPC level. Arguments: QueueToClean - A pointer to the queue which we're going to clean out. CurrentOpRequest - Pointer to a pointer to the current request. Return Value: None. --*/ { SerialPurgeRequests(QueueToClean, CurrentOpRequest); // // Since purge puts the queue state to fail requests, we have to explicitly // change the queue state to accept requests. // WdfIoQueueStart(QueueToClean); } VOID SerialGetNextRequest( IN WDFREQUEST * CurrentOpRequest, IN WDFQUEUE QueueToProcess, OUT WDFREQUEST * NextRequest, IN BOOLEAN CompleteCurrent, IN PSERIAL_DEVICE_EXTENSION Extension ) /*++ Routine Description: This function is used to make the head of the particular queue the current request. It also completes the what was the old current request if desired. Arguments: CurrentOpRequest - Pointer to a pointer to the currently active request for the particular work list. Note that this item is not actually part of the list. QueueToProcess - The list to pull the new item off of. NextIrp - The next Request to process. Note that CurrentOpRequest will be set to this value under protection of the cancel spin lock. However, if *NextIrp is NULL when this routine returns, it is not necessaryly true the what is pointed to by CurrentOpRequest will also be NULL. The reason for this is that if the queue is empty when we hold the cancel spin lock, a new request may come in immediately after we release the lock. CompleteCurrent - If TRUE then this routine will complete the request pointed to by the pointer argument CurrentOpRequest. Return Value: None. --*/ { WDFREQUEST oldRequest = NULL; PREQUEST_CONTEXT reqContext; NTSTATUS status; UNREFERENCED_PARAMETER(Extension); oldRequest = *CurrentOpRequest; *CurrentOpRequest = NULL; // // Check to see if there is a new request to start up. // status = WdfIoQueueRetrieveNextRequest( QueueToProcess, CurrentOpRequest ); if(!NT_SUCCESS(status)) { ASSERTMSG("WdfIoQueueRetrieveNextRequest failed", status == STATUS_NO_MORE_ENTRIES); } *NextRequest = *CurrentOpRequest; if (CompleteCurrent) { if (oldRequest) { reqContext = SerialGetRequestContext(oldRequest); SerialCompleteRequest(oldRequest, reqContext->Status, reqContext->Information); } } } VOID SerialTryToCompleteCurrent( IN PSERIAL_DEVICE_EXTENSION Extension, IN PFN_WDF_INTERRUPT_SYNCHRONIZE SynchRoutine OPTIONAL, IN NTSTATUS StatusToUse, IN WDFREQUEST *CurrentOpRequest, IN WDFQUEUE QueueToProcess OPTIONAL, IN WDFTIMER IntervalTimer OPTIONAL, IN WDFTIMER TotalTimer OPTIONAL, IN PSERIAL_START_ROUTINE Starter OPTIONAL, IN PSERIAL_GET_NEXT_ROUTINE GetNextRequest OPTIONAL, IN LONG RefType ) /*++ Routine Description: This routine attempts to remove all of the reasons there are references on the current read/write. If everything can be completed it will complete this read/write and try to start another. NOTE: This routine assumes that it is called with the cancel spinlock held. Arguments: Extension - Simply a pointer to the device extension. SynchRoutine - A routine that will synchronize with the isr and attempt to remove the knowledge of the current request from the isr. NOTE: This pointer can be null. IrqlForRelease - This routine is called with the cancel spinlock held. This is the irql that was current when the cancel spinlock was acquired. StatusToUse - The request's status field will be set to this value, if this routine can complete the request. Return Value: None. --*/ { PREQUEST_CONTEXT reqContext; ASSERTMSG("SerialTryToCompleteCurrent: CurrentOpRequest is NULL", *CurrentOpRequest); reqContext = SerialGetRequestContext(*CurrentOpRequest); if(RefType == SERIAL_REF_ISR || RefType == SERIAL_REF_XOFF_REF) { // // We can decrement the reference to "remove" the fact // that the caller no longer will be accessing this request. // SERIAL_CLEAR_REFERENCE( reqContext, RefType ); } if (SynchRoutine) { WdfInterruptSynchronize( Extension->WdfInterrupt, SynchRoutine, Extension ); } // // Try to run down all other references to this request. // SerialRundownIrpRefs( CurrentOpRequest, IntervalTimer, TotalTimer, Extension, RefType ); if(StatusToUse == STATUS_CANCELLED) { // // This function is called from a cancelroutine. So mark // the request as cancelled. We need to do this because // we may not complete the request below if somebody // else has a reference to it. // This state variable was added to avoid calling // WdfRequestMarkCancelable second time on a request that // has cancelled but wasn't completed in the cancel routine. // reqContext->Cancelled = TRUE; } // // See if the ref count is zero after trying to complete everybody else. // if (!SERIAL_REFERENCE_COUNT(reqContext)) { WDFREQUEST newRequest; // // The ref count was zero so we should complete this // request. // // The following call will also cause the current request to be // completed. // reqContext->Status = StatusToUse; if (StatusToUse == STATUS_CANCELLED) { reqContext->Information = 0; } if (GetNextRequest) { GetNextRequest( CurrentOpRequest, QueueToProcess, &newRequest, TRUE, Extension ); if (newRequest) { Starter(Extension); } } else { WDFREQUEST oldRequest = *CurrentOpRequest; // // There was no get next routine. We will simply complete // the request. We should make sure that we null out the // pointer to the pointer to this request. // *CurrentOpRequest = NULL; SerialCompleteRequest(oldRequest, reqContext->Status, reqContext->Information); } } else { } } VOID SerialEvtIoStop( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG ActionFlags ) /*++ Routine Description: This callback is invoked for every request pending in the driver (not queue) - in-flight request. The Action parameter tells us why the callback is invoked - because the device is being stopped, removed or suspended. In this driver, we have told the framework not to stop or remove when there are pending requests, so only reason for this callback is when the system is suspending. Arguments: Queue - Queue the request currently belongs to Request - Request that is currently out of queue and being processed by the driver Action - Reason for this callback Return Value: None. Acknowledge the request so that framework can contiue suspending the device. --*/ { PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Queue); reqContext = SerialGetRequestContext(Request); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--> SerialEvtIoStop %x %p\n", ActionFlags, Request); // // System suspends all the timers before asking the driver to goto // sleep. So let us not worry about cancelling the timers. Also the // framework will disconnect the interrupt before calling our // D0Exit handler so we can be sure that nobody will touch the hardware. // So just acknowledge callback to say that we are okay to stop due to // system suspend. Please note that since we have taken a power reference // we will never idle out when there is an open handle. Also we have told // the framework to not stop for resource rebalancing or remove when there are // open handles, so let us not worry about that either. // if (ActionFlags & WdfRequestStopRequestCancelable) { PFN_WDF_REQUEST_CANCEL cancelRoutine; // // Request is in a cancelable state. So unmark cancelable before you // acknowledge. We will mark the request cancelable when we resume. // cancelRoutine = reqContext->CancelRoutine; SerialClearCancelRoutine(Request, TRUE); // // SerialClearCancelRoutine clears the cancel-routine. So set it back // in the context. We will need that when we resume. // reqContext->CancelRoutine = cancelRoutine; reqContext->MarkCancelableOnResume = TRUE; ActionFlags &= ~WdfRequestStopRequestCancelable; } ASSERT(ActionFlags == WdfRequestStopActionSuspend); WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue the request SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "<-- SerialEvtIoStop \n"); } VOID SerialEvtIoResume( IN WDFQUEUE Queue, IN WDFREQUEST Request ) /*++ Routine Description: This callback is invoked for every request pending in the driver - in-flight request - to notify that the hardware is ready for contiuing the processing of the request. Arguments: Queue - Queue the request currently belongs to Request - Request that is currently out of queue and being processed by the driver Return Value: None. --*/ { PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Queue); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--> SerialEvtIoResume %p \n", Request); reqContext = SerialGetRequestContext(Request); // // If we unmarked cancelable on suspend, let us mark it cancelable again. // if (reqContext->MarkCancelableOnResume) { SerialSetCancelRoutine(Request, reqContext->CancelRoutine); reqContext->MarkCancelableOnResume = FALSE; } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "<-- SerialEvtIoResume \n"); } VOID SerialRundownIrpRefs( IN WDFREQUEST *CurrentOpRequest, IN WDFTIMER IntervalTimer OPTIONAL, IN WDFTIMER TotalTimer OPTIONAL, IN PSERIAL_DEVICE_EXTENSION PDevExt, IN LONG RefType ) /*++ Routine Description: This routine runs through the various items that *could* have a reference to the current read/write. It try's to remove the reason. If it does succeed in removing the reason it will decrement the reference count on the request. NOTE: This routine assumes that it is called with the cancel spin lock held. Arguments: CurrentOpRequest - Pointer to a pointer to current request for the particular operation. IntervalTimer - Pointer to the interval timer for the operation. NOTE: This could be null. TotalTimer - Pointer to the total timer for the operation. NOTE: This could be null. PDevExt - Pointer to device extension Return Value: None. --*/ { PREQUEST_CONTEXT reqContext; WDFREQUEST request = *CurrentOpRequest; reqContext = SerialGetRequestContext(request); if(RefType == SERIAL_REF_CANCEL) { // // Caller is a cancel routine. So just clear the reference. // SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_CANCEL ); reqContext->CancelRoutine = NULL; } else { // // Try to clear the cancelable state. // SerialClearCancelRoutine(request, TRUE); } if (IntervalTimer) { // // Try to cancel the operations interval timer. If the operation // returns true then the timer did have a reference to the // request. Since we've canceled this timer that reference is // no longer valid and we can decrement the reference count. // // If the cancel returns false then this means either of two things: // // a) The timer has already fired. // // b) There never was an interval timer. // // In the case of "b" there is no need to decrement the reference // count since the "timer" never had a reference to it. // // In the case of "a", then the timer itself will be coming // along and decrement it's reference. Note that the caller // of this routine might actually be the this timer, so // decrement the reference. // if (SerialCancelTimer(IntervalTimer, PDevExt)) { SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_INT_TIMER ); } else if(RefType == SERIAL_REF_INT_TIMER) { // caller is the timer SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_INT_TIMER ); } } if (TotalTimer) { // // Try to cancel the operations total timer. If the operation // returns true then the timer did have a reference to the // request. Since we've canceled this timer that reference is // no longer valid and we can decrement the reference count. // // If the cancel returns false then this means either of two things: // // a) The timer has already fired. // // b) There never was an total timer. // // In the case of "b" there is no need to decrement the reference // count since the "timer" never had a reference to it. // // In the case of "a", then the timer itself will be coming // along and decrement it's reference. Note that the caller // of this routine might actually be the this timer, so // decrement the reference. // if (SerialCancelTimer(TotalTimer, PDevExt)) { SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_TOTAL_TIMER ); } else if(RefType == SERIAL_REF_TOTAL_TIMER) { // caller is the timer SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_TOTAL_TIMER ); } } } VOID SerialStartOrQueue( IN PSERIAL_DEVICE_EXTENSION Extension, IN WDFREQUEST Request, IN WDFQUEUE QueueToExamine, IN WDFREQUEST *CurrentOpRequest, IN PSERIAL_START_ROUTINE Starter ) /*++ Routine Description: This routine is used to either start or queue any requst that can be queued in the driver. Arguments: Extension - Points to the serial device extension. Request - The request to either queue or start. In either case the request will be marked pending. QueueToExamine - The queue the request will be place on if there is already an operation in progress. CurrentOpRequest - Pointer to a pointer to the request the is current for the queue. The pointer pointed to will be set with to Request if what CurrentOpRequest points to is NULL. Starter - The routine to call if the queue is empty. Return Value: --*/ { NTSTATUS status; PREQUEST_CONTEXT reqContext; WDF_REQUEST_PARAMETERS params; reqContext = SerialGetRequestContext(Request); WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters( Request, ¶ms); // // If this is a write request then take the amount of characters // to write and add it to the count of characters to write. // if (params.Type == WdfRequestTypeWrite) { Extension->TotalCharsQueued += reqContext->Length; } else if ((params.Type == WdfRequestTypeDeviceControl) && ((params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) || (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER))) { reqContext->IoctlCode = params.Parameters.DeviceIoControl.IoControlCode; // We need this in the destroy callback Extension->TotalCharsQueued++; } if (IsQueueEmpty(QueueToExamine) && !(*CurrentOpRequest)) { // // There were no current operation. Mark this one as // current and start it up. // *CurrentOpRequest = Request; Starter(Extension); return; } else { // // We don't know how long the request will be in the // queue. If it gets cancelled while waiting in the queue, we will // be notified by EvtCanceledOnQueue callback so that we can readjust // the lenght or free the buffer. // reqContext->Extension = Extension; // We need this in the destroy callback status = WdfRequestForwardToIoQueue(Request, QueueToExamine); if(!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestForwardToIoQueue failed%X\n", status); ASSERTMSG("WdfRequestForwardToIoQueue failed ", FALSE); SerialCompleteRequest(Request, status, 0); } return; } } VOID SerialEvtCanceledOnQueue( IN WDFQUEUE Queue, IN WDFREQUEST Request ) /*++ Routine Description: Called when the request is cancelled while it's waiting on the queue. This callback is used instead of EvtCleanupCallback on the request because this one will be called with the presentation lock held. Arguments: Queue - Queue in which the request currently waiting Request - Request being cancelled Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION extension = NULL; PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Queue); reqContext = SerialGetRequestContext(Request); extension = reqContext->Extension; // // If this is a write request then take the amount of characters // to write and subtract it from the count of characters to write. // if (reqContext->MajorFunction == IRP_MJ_WRITE) { extension->TotalCharsQueued -= reqContext->Length; } else if (reqContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) { // // If it's an immediate then we need to decrement the // count of chars queued. If it's a resize then we // need to deallocate the pool that we're passing on // to the "resizing" routine. // if (( reqContext->IoctlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) || (reqContext->IoctlCode == IOCTL_SERIAL_XOFF_COUNTER)) { extension->TotalCharsQueued--; } else if (reqContext->IoctlCode == IOCTL_SERIAL_SET_QUEUE_SIZE) { // // We shoved the pointer to the memory into the // the type 3 buffer pointer which we KNOW we // never use. // ASSERT(reqContext->Type3InputBuffer); ExFreePool(reqContext->Type3InputBuffer); reqContext->Type3InputBuffer = NULL; } } SerialCompleteRequest(Request, WdfRequestGetStatus(Request), 0); } NTSTATUS SerialCompleteIfError( PSERIAL_DEVICE_EXTENSION extension, WDFREQUEST Request ) /*++ Routine Description: If the current request is not an IOCTL_SERIAL_GET_COMMSTATUS request and there is an error and the application requested abort on errors, then cancel the request. Arguments: extension - Pointer to the device context Request - Pointer to the WDFREQUEST to test. Return Value: STATUS_SUCCESS or STATUS_CANCELLED. --*/ { WDF_REQUEST_PARAMETERS params; NTSTATUS status = STATUS_SUCCESS; if ((extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) && extension->ErrorWord) { WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters( Request, ¶ms ); // // There is a current error in the driver. No requests should // come through except for the GET_COMMSTATUS. // if ((params.Type != WdfRequestTypeDeviceControl) || (params.Parameters.DeviceIoControl.IoControlCode != IOCTL_SERIAL_GET_COMMSTATUS)) { status = STATUS_CANCELLED; SerialCompleteRequest(Request, status, 0); } } return status; } NTSTATUS SerialCreateTimersAndDpcs( IN PSERIAL_DEVICE_EXTENSION pDevExt ) /*++ Routine Description: This function creates all the timers and DPC objects. All the objects are associated with the WDFDEVICE and the callbacks are serialized with the device callbacks. Also these objects will be deleted automatically when the device is deleted, so there is no need for the driver to explicitly delete the objects. Arguments: PDevExt - Pointer to the device extension for the device Return Value: return NTSTATUS --*/ { WDF_DPC_CONFIG dpcConfig; WDF_TIMER_CONFIG timerConfig; NTSTATUS status; WDF_OBJECT_ATTRIBUTES dpcAttributes; WDF_OBJECT_ATTRIBUTES timerAttributes; // // Initialize all the timers used to timeout operations. // // // This timer dpc is fired off if the timer for the total timeout // for the read expires. It will cause the current read to complete. // WDF_TIMER_CONFIG_INIT(&timerConfig, SerialReadTimeout); timerConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); timerAttributes.ParentObject = pDevExt->WdfDevice; status = WdfTimerCreate(&timerConfig, &timerAttributes, &pDevExt->ReadRequestTotalTimer); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfTimerCreate(ReadRequestTotalTimer) failed [%#08lx]\n", status); return status; } // // This dpc is fired off if the timer for the interval timeout // expires. If no more characters have been read then the // dpc routine will cause the read to complete. However, if // more characters have been read then the dpc routine will // resubmit the timer. // WDF_TIMER_CONFIG_INIT(&timerConfig, SerialIntervalReadTimeout); timerConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); timerAttributes.ParentObject = pDevExt->WdfDevice; status = WdfTimerCreate(&timerConfig, &timerAttributes, &pDevExt->ReadRequestIntervalTimer); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfTimerCreate(ReadRequestIntervalTimer) failed [%#08lx]\n", status); return status; } // // This dpc is fired off if the timer for the total timeout // for the write expires. It will queue a dpc routine that // will cause the current write to complete. // // WDF_TIMER_CONFIG_INIT(&timerConfig, SerialWriteTimeout); timerConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); timerAttributes.ParentObject = pDevExt->WdfDevice; status = WdfTimerCreate(&timerConfig, &timerAttributes, &pDevExt->WriteRequestTotalTimer); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfTimerCreate(WriteRequestTotalTimer) failed [%#08lx]\n", status); return status; } // // This dpc is fired off if the transmit immediate char // character times out. The dpc routine will "grab" the // request from the isr and time it out. // WDF_TIMER_CONFIG_INIT(&timerConfig, SerialTimeoutImmediate); timerConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); timerAttributes.ParentObject = pDevExt->WdfDevice; status = WdfTimerCreate(&timerConfig, &timerAttributes, &pDevExt->ImmediateTotalTimer); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfTimerCreate(ImmediateTotalTimer) failed [%#08lx]\n", status); return status; } // // This dpc is fired off if the timer used to "timeout" counting // the number of characters received after the Xoff ioctl is started // expired. // WDF_TIMER_CONFIG_INIT(&timerConfig, SerialTimeoutXoff); timerConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); timerAttributes.ParentObject = pDevExt->WdfDevice; status = WdfTimerCreate(&timerConfig, &timerAttributes, &pDevExt->XoffCountTimer); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfTimerCreate(XoffCountTimer) failed [%#08lx]\n", status); return status; } // // This dpc is fired off when a timer expires (after one // character time), so that code can be invoked that will // check to see if we should lower the RTS line when // doing transmit toggling. // WDF_TIMER_CONFIG_INIT(&timerConfig, SerialInvokePerhapsLowerRTS); timerConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); timerAttributes.ParentObject = pDevExt->WdfDevice; status = WdfTimerCreate(&timerConfig, &timerAttributes, &pDevExt->LowerRTSTimer); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfTimerCreate(LowerRTSTimer) failed [%#08lx]\n", status); return status; } // // Create a DPC to complete read requests. // WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteWrite); dpcConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes); dpcAttributes.ParentObject = pDevExt->WdfDevice; status = WdfDpcCreate(&dpcConfig, &dpcAttributes, &pDevExt->CompleteWriteDpc); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDpcCreate(CompleteWriteDpc) failed [%#08lx]\n", status); return status; } // // Create a DPC to complete read requests. // WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteRead); dpcConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes); dpcAttributes.ParentObject = pDevExt->WdfDevice; status = WdfDpcCreate(&dpcConfig, &dpcAttributes, &pDevExt->CompleteReadDpc); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDpcCreate(CompleteReadDpc) failed [%#08lx]\n", status); return status; } // // This dpc is fired off if a comm error occurs. It will // cancel all pending reads and writes. // WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCommError); dpcConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes); dpcAttributes.ParentObject = pDevExt->WdfDevice; status = WdfDpcCreate(&dpcConfig, &dpcAttributes, &pDevExt->CommErrorDpc); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDpcCreate(CommErrorDpc) failed [%#08lx]\n", status); return status; } // // This dpc is fired off when the transmit immediate char // character is given to the hardware. It will simply complete // the request. // WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteImmediate); dpcConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes); dpcAttributes.ParentObject = pDevExt->WdfDevice; status = WdfDpcCreate(&dpcConfig, &dpcAttributes, &pDevExt->CompleteImmediateDpc); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDpcCreate(CompleteImmediateDpc) failed [%#08lx]\n", status); return status; } // // This dpc is fired off if an event occurs and there was // a request waiting on that event. A dpc routine will execute // that completes the request. // WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteWait); dpcConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes); dpcAttributes.ParentObject = pDevExt->WdfDevice; status = WdfDpcCreate(&dpcConfig, &dpcAttributes, &pDevExt->CommWaitDpc); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDpcCreate(CommWaitDpc) failed [%#08lx]\n", status); return status; } // // This dpc is fired off if the xoff counter actually runs down // to zero. // WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteXoff); dpcConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes); dpcAttributes.ParentObject = pDevExt->WdfDevice; status = WdfDpcCreate(&dpcConfig, &dpcAttributes, &pDevExt->XoffCountCompleteDpc); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDpcCreate(XoffCountCompleteDpc) failed [%#08lx]\n", status); return status; } // // This dpc is fired off only from device level to start off // a timer that will queue a dpc to check if the RTS line // should be lowered when we are doing transmit toggling. // WDF_DPC_CONFIG_INIT(&dpcConfig, SerialStartTimerLowerRTS); dpcConfig.AutomaticSerialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes); dpcAttributes.ParentObject = pDevExt->WdfDevice; status = WdfDpcCreate(&dpcConfig, &dpcAttributes, &pDevExt->StartTimerLowerRTSDpc); if (!NT_SUCCESS(status)) { SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDpcCreate(StartTimerLowerRTSDpc) failed [%#08lx]\n", status); return status; } return status; } BOOLEAN SerialInsertQueueDpc(IN WDFDPC PDpc) /*++ Routine Description: This function must be called to queue DPC's for the serial driver. Arguments: PDpc - Pointer to the Dpc object Return Value: Kicks up return value from KeInsertQueueDpc() --*/ { // // If the specified DPC object is not currently in the queue, WdfDpcEnqueue // queues the DPC and returns TRUE. // return WdfDpcEnqueue(PDpc); } BOOLEAN SerialSetTimer(IN WDFTIMER Timer, IN LARGE_INTEGER DueTime) /*++ Routine Description: This function must be called to set timers for the serial driver. Arguments: Timer - pointer to timer dispatcher object DueTime - time at which the timer should expire Return Value: Kicks up return value from KeSetTimerEx() --*/ { BOOLEAN result; // // If the timer object was already in the system timer queue, WdfTimerStart returns TRUE // result = WdfTimerStart(Timer, DueTime.QuadPart); return result; } VOID SerialDrainTimersAndDpcs( IN PSERIAL_DEVICE_EXTENSION PDevExt ) /*++ Routine Description: This function cancels all the timers and Dpcs and waits for them to run to completion if they are already fired. Arguments: PDevExt - Pointer to the device extension for the device that needs to set a timer Return Value: --*/ { WdfTimerStop(PDevExt->ReadRequestTotalTimer, TRUE); WdfTimerStop(PDevExt->ReadRequestIntervalTimer, TRUE); WdfTimerStop(PDevExt->WriteRequestTotalTimer, TRUE); WdfTimerStop(PDevExt->ImmediateTotalTimer, TRUE); WdfTimerStop(PDevExt->XoffCountTimer, TRUE); WdfTimerStop(PDevExt->LowerRTSTimer, TRUE); WdfDpcCancel(PDevExt->CompleteWriteDpc, TRUE); WdfDpcCancel(PDevExt->CompleteReadDpc, TRUE); WdfDpcCancel(PDevExt->CommErrorDpc, TRUE); WdfDpcCancel(PDevExt->CompleteImmediateDpc, TRUE); WdfDpcCancel(PDevExt->CommWaitDpc, TRUE); WdfDpcCancel(PDevExt->XoffCountCompleteDpc, TRUE); WdfDpcCancel(PDevExt->StartTimerLowerRTSDpc, TRUE); return; } BOOLEAN SerialCancelTimer( IN WDFTIMER Timer, IN PSERIAL_DEVICE_EXTENSION PDevExt ) /*++ Routine Description: This function must be called to cancel timers for the serial driver. Arguments: Timer - pointer to timer dispatcher object PDevExt - Pointer to the device extension for the device that needs to set a timer Return Value: True if timer was cancelled --*/ { UNREFERENCED_PARAMETER(PDevExt); return WdfTimerStop(Timer, FALSE); } SERIAL_MEM_COMPARES SerialMemCompare( IN PHYSICAL_ADDRESS A, IN ULONG SpanOfA, IN PHYSICAL_ADDRESS B, IN ULONG SpanOfB ) /*++ Routine Description: Compare two phsical address. Arguments: A - One half of the comparison. SpanOfA - In units of bytes, the span of A. B - One half of the comparison. SpanOfB - In units of bytes, the span of B. Return Value: The result of the comparison. --*/ { LARGE_INTEGER a; LARGE_INTEGER b; LARGE_INTEGER lower; ULONG lowerSpan; LARGE_INTEGER higher; PAGED_CODE(); a = A; b = B; if (a.QuadPart == b.QuadPart) { return AddressesAreEqual; } if (a.QuadPart > b.QuadPart) { higher = a; lower = b; lowerSpan = SpanOfB; } else { higher = b; lower = a; lowerSpan = SpanOfA; } if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) { return AddressesAreDisjoint; } return AddressesOverlap; } VOID SerialLogError( _In_ PDRIVER_OBJECT DriverObject, _In_opt_ PDEVICE_OBJECT DeviceObject, _In_ PHYSICAL_ADDRESS P1, _In_ PHYSICAL_ADDRESS P2, _In_ ULONG SequenceNumber, _In_ UCHAR MajorFunctionCode, _In_ UCHAR RetryCount, _In_ ULONG UniqueErrorValue, _In_ NTSTATUS FinalStatus, _In_ NTSTATUS SpecificIOStatus, _In_ ULONG LengthOfInsert1, _In_reads_bytes_opt_(LengthOfInsert1) PWCHAR Insert1, _In_ ULONG LengthOfInsert2, _In_reads_bytes_opt_(LengthOfInsert2) PWCHAR Insert2 ) /*++ Routine Description: This routine allocates an error log entry, copies the supplied data to it, and requests that it be written to the error log file. Arguments: DriverObject - A pointer to the driver object for the device. DeviceObject - A pointer to the device object associated with the device that had the error, early in initialization, one may not yet exist. P1,P2 - If phyical addresses for the controller ports involved with the error are available, put them through as dump data. SequenceNumber - A ulong value that is unique to an WDFREQUEST over the life of the request in this driver - 0 generally means an error not associated with an request. MajorFunctionCode - If there is an error associated with the request, this is the major function code of that request. RetryCount - The number of times a particular operation has been retried. UniqueErrorValue - A unique long word that identifies the particular call to this function. FinalStatus - The final status given to the request that was associated with this error. If this log entry is being made during one of the retries this value will be STATUS_SUCCESS. SpecificIOStatus - The IO status for a particular error. LengthOfInsert1 - The length in bytes (including the terminating NULL) of the first insertion string. Insert1 - The first insertion string. LengthOfInsert2 - The length in bytes (including the terminating NULL) of the second insertion string. NOTE, there must be a first insertion string for their to be a second insertion string. Insert2 - The second insertion string. Return Value: None. --*/ { PIO_ERROR_LOG_PACKET errorLogEntry; PVOID objectToUse; SHORT dumpToAllocate = 0; PUCHAR ptrToFirstInsert; PUCHAR ptrToSecondInsert; PAGED_CODE(); if (Insert1 == NULL) { LengthOfInsert1 = 0; } if (Insert2 == NULL) { LengthOfInsert2 = 0; } if (ARGUMENT_PRESENT(DeviceObject)) { objectToUse = DeviceObject; } else { objectToUse = DriverObject; } if (SerialMemCompare( P1, (ULONG)1, SerialPhysicalZero, (ULONG)1 ) != AddressesAreEqual) { dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS); } if (SerialMemCompare( P2, (ULONG)1, SerialPhysicalZero, (ULONG)1 ) != AddressesAreEqual) { dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS); } errorLogEntry = IoAllocateErrorLogEntry( objectToUse, (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + dumpToAllocate + LengthOfInsert1 + LengthOfInsert2) ); if ( errorLogEntry != NULL ) { errorLogEntry->ErrorCode = SpecificIOStatus; errorLogEntry->SequenceNumber = SequenceNumber; errorLogEntry->MajorFunctionCode = MajorFunctionCode; errorLogEntry->RetryCount = RetryCount; errorLogEntry->UniqueErrorValue = UniqueErrorValue; errorLogEntry->FinalStatus = FinalStatus; errorLogEntry->DumpDataSize = dumpToAllocate; if (dumpToAllocate) { RtlCopyMemory( &errorLogEntry->DumpData[0], &P1, sizeof(PHYSICAL_ADDRESS) ); if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) { RtlCopyMemory( ((PUCHAR)&errorLogEntry->DumpData[0]) +sizeof(PHYSICAL_ADDRESS), &P2, sizeof(PHYSICAL_ADDRESS) ); ptrToFirstInsert = ((PUCHAR)&errorLogEntry->DumpData[0])+(2*sizeof(PHYSICAL_ADDRESS)); } else { ptrToFirstInsert = ((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS); } } else { ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0]; } ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1; if (LengthOfInsert1) { errorLogEntry->NumberOfStrings = 1; errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert - (PUCHAR)errorLogEntry); RtlCopyMemory( ptrToFirstInsert, Insert1, LengthOfInsert1 ); if (LengthOfInsert2) { errorLogEntry->NumberOfStrings = 2; RtlCopyMemory( ptrToSecondInsert, Insert2, LengthOfInsert2 ); } } IoWriteErrorLogEntry(errorLogEntry); } } VOID SerialMarkHardwareBroken(IN PSERIAL_DEVICE_EXTENSION PDevExt) /*++ Routine Description: Marks a UART as broken. This causes the driver stack to stop accepting requests and eventually be removed. Arguments: PDevExt - Device extension attached to PDevObj Return Value: None. --*/ { PAGED_CODE(); // // Write a log entry // SerialLogError(PDevExt->DriverObject, NULL, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 88, STATUS_SUCCESS, SERIAL_HARDWARE_FAILURE, PDevExt->DeviceName.Length + sizeof(WCHAR), PDevExt->DeviceName.Buffer, 0, NULL); SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_INIT, "Device is broken. Request a restart...\n"); WdfDeviceSetFailed(PDevExt->WdfDevice, WdfDeviceFailedAttemptRestart); } NTSTATUS SerialGetDivisorFromBaud( IN ULONG ClockRate, IN LONG DesiredBaud, OUT PSHORT AppropriateDivisor ) /*++ Routine Description: This routine will determine a divisor based on an unvalidated baud rate. Arguments: ClockRate - The clock input to the controller. DesiredBaud - The baud rate for whose divisor we seek. AppropriateDivisor - Given that the DesiredBaud is valid, the LONG pointed to by this parameter will be set to the appropriate value. NOTE: The long is undefined if the DesiredBaud is not supported. Return Value: This function will return STATUS_SUCCESS if the baud is supported. If the value is not supported it will return a status such that NT_ERROR(Status) == FALSE. --*/ { NTSTATUS status = STATUS_SUCCESS; SHORT calculatedDivisor; ULONG denominator; ULONG remainder; // // Allow up to a 1 percent error // ULONG maxRemain18 = 18432; ULONG maxRemain30 = 30720; ULONG maxRemain42 = 42336; ULONG maxRemain80 = 80000; ULONG maxRemain; // // Reject any non-positive bauds. // denominator = DesiredBaud*(ULONG)16; if (DesiredBaud <= 0) { *AppropriateDivisor = -1; } else if ((LONG)denominator < DesiredBaud) { // // If the desired baud was so huge that it cause the denominator // calculation to wrap, don't support it. // *AppropriateDivisor = -1; } else { if (ClockRate == 1843200) { maxRemain = maxRemain18; } else if (ClockRate == 3072000) { maxRemain = maxRemain30; } else if (ClockRate == 4233600) { maxRemain = maxRemain42; } else { maxRemain = maxRemain80; } calculatedDivisor = (SHORT)(ClockRate / denominator); remainder = ClockRate % denominator; // // Round up. // if (((remainder*2) > ClockRate) && (DesiredBaud != 110)) { calculatedDivisor++; } // // Only let the remainder calculations effect us if // the baud rate is > 9600. // if (DesiredBaud >= 9600) { // // If the remainder is less than the maximum remainder (wrt // the ClockRate) or the remainder + the maximum remainder is // greater than or equal to the ClockRate then assume that the // baud is ok. // if ((remainder >= maxRemain) && ((remainder+maxRemain) < ClockRate)) { calculatedDivisor = -1; } } // // Don't support a baud that causes the denominator to // be larger than the clock. // if (denominator > ClockRate) { calculatedDivisor = -1; } // // Ok, Now do some special casing so that things can actually continue // working on all platforms. // if (ClockRate == 1843200) { if (DesiredBaud == 56000) { calculatedDivisor = 2; } } else if (ClockRate == 3072000) { if (DesiredBaud == 14400) { calculatedDivisor = 13; } } else if (ClockRate == 4233600) { if (DesiredBaud == 9600) { calculatedDivisor = 28; } else if (DesiredBaud == 14400) { calculatedDivisor = 18; } else if (DesiredBaud == 19200) { calculatedDivisor = 14; } else if (DesiredBaud == 38400) { calculatedDivisor = 7; } else if (DesiredBaud == 56000) { calculatedDivisor = 5; } } else if (ClockRate == 8000000) { if (DesiredBaud == 14400) { calculatedDivisor = 35; } else if (DesiredBaud == 56000) { calculatedDivisor = 9; } } *AppropriateDivisor = calculatedDivisor; } if (*AppropriateDivisor == -1) { status = STATUS_INVALID_PARAMETER; } return status; } BOOLEAN IsQueueEmpty( IN WDFQUEUE Queue ) { WDF_IO_QUEUE_STATE queueStatus; queueStatus = WdfIoQueueGetState( Queue, NULL, NULL ); return (WDF_IO_QUEUE_IDLE(queueStatus)) ? TRUE : FALSE; } VOID SerialSetCancelRoutine( IN WDFREQUEST Request, IN PFN_WDF_REQUEST_CANCEL CancelRoutine) { PREQUEST_CONTEXT reqContext = SerialGetRequestContext(Request); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "-->SerialSetCancelRoutine %p \n", Request); WdfRequestMarkCancelable(Request, CancelRoutine); SERIAL_SET_REFERENCE(reqContext, SERIAL_REF_CANCEL); reqContext->CancelRoutine = CancelRoutine; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "<-- SerialSetCancelRoutine \n"); return; } NTSTATUS SerialClearCancelRoutine( IN WDFREQUEST Request, IN BOOLEAN ClearReference ) { NTSTATUS status = STATUS_SUCCESS; PREQUEST_CONTEXT reqContext = SerialGetRequestContext(Request); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "-->SerialClearCancelRoutine %p %x\n", Request, ClearReference); if(SERIAL_TEST_REFERENCE(reqContext, SERIAL_REF_CANCEL)) { status = WdfRequestUnmarkCancelable(Request); if (NT_SUCCESS(status)) { reqContext->CancelRoutine = NULL; if(ClearReference) { SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_CANCEL ); } } else { ASSERT(status == STATUS_CANCELLED); } } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "-->SerialClearCancelRoutine %p\n", Request); return status; } VOID SerialCompleteRequest( IN WDFREQUEST Request, IN NTSTATUS Status, IN ULONG_PTR Info ) { PREQUEST_CONTEXT reqContext; reqContext = SerialGetRequestContext(Request); ASSERT(reqContext->RefCount == 0); SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, "Complete Request: %p %X 0x%I64x\n", (Request), (Status), (Info)); WdfRequestCompleteWithInformation((Request), (Status), (Info)); } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/waitmask.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: waitmask.c Abstract: This module contains the code that is very specific to get/set/wait on event mask operations in the serial driver Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "waitmask.tmh" #endif EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabWaitFromIsr; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGiveWaitToIsr; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialFinishOldWait; VOID SerialStartMask( IN PSERIAL_DEVICE_EXTENSION Extension ) /*++ Routine Description: This routine is used to process the set mask and wait mask ioctls. Calls to this routine are serialized by placing irps in the list under the protection of the cancel spin lock. Arguments: Extension - A pointer to the serial device extension. Return Value: Will return pending for everything put the first request that we actually process. Even in that case it will return pending unless it can complete it right away. --*/ { WDFREQUEST NewRequest; PREQUEST_CONTEXT reqContext; WDF_REQUEST_PARAMETERS params; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "In SerialStartMask\n"); ASSERT(Extension->CurrentMaskRequest); do { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "STARTMASK - CurrentMaskRequest: %p\n", Extension->CurrentMaskRequest); WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters( Extension->CurrentMaskRequest, ¶ms ); reqContext = SerialGetRequestContext(Extension->CurrentMaskRequest); ASSERT((params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) || (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_WAIT_MASK)); if (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_WAIT_MASK) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "SERIAL - %p is a SETMASK request\n", Extension->CurrentMaskRequest); // // Complete the old wait if there is one. // WdfInterruptSynchronize( Extension->WdfInterrupt, SerialFinishOldWait, Extension ); // // Any current waits should be on its way to completion // at this point. There certainly shouldn't be any // request mask location. // ASSERT(!Extension->IrpMaskLocation); reqContext->Status = STATUS_SUCCESS; // // The following call will also cause the current // call to be completed. // SerialGetNextRequest( &Extension->CurrentMaskRequest, Extension->MaskQueue, &NewRequest, TRUE, Extension ); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Perhaps another mask request was found in " "the queue\n" "------- %p/%p <- values should be the same\n", Extension->CurrentMaskRequest, NewRequest); } else { // // First make sure that we have a non-zero mask. // If the app queues a wait on a zero mask it can't // be statisfied so it makes no sense to start it. // if ((!Extension->IsrWaitMask) || (Extension->CurrentWaitRequest)) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "WaitIrp is invalid\n" "------- IsrWaitMask: %x\n" "------- CurrentWaitRequest: %p\n", Extension->IsrWaitMask, Extension->CurrentWaitRequest); reqContext->Status = STATUS_INVALID_PARAMETER; SerialGetNextRequest(&Extension->CurrentMaskRequest, Extension->MaskQueue, &NewRequest, TRUE, Extension); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Perhaps another mask request was found " "in the queue\n" "------- %p/%p <- values should be the same\n", Extension->CurrentMaskRequest,NewRequest); } else { // // Make the current mask request the current wait request and // get a new current mask request. Note that when we get // the new current mask request we DO NOT complete the // old current mask request (which is now the current wait // request. // // Then under the protection of the cancel spin lock // we check to see if the current wait request needs to // be canceled // SERIAL_INIT_REFERENCE(reqContext); SerialSetCancelRoutine(Extension->CurrentMaskRequest, SerialCancelWait); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "%p will become the current " "wait request\n", Extension->CurrentMaskRequest); // // There should never be a mask location when // there isn't a current wait request. At this point // there shouldn't be a current wait request also. // ASSERT(!Extension->IrpMaskLocation); ASSERT(!Extension->CurrentWaitRequest); Extension->CurrentWaitRequest = Extension->CurrentMaskRequest; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialGiveWaitToIsr, Extension ); // // Since it isn't really the mask request anymore, // null out that pointer. // Extension->CurrentMaskRequest = NULL; // // This will release the cancel spinlock for us // SerialGetNextRequest(&Extension->CurrentMaskRequest, Extension->MaskQueue, &NewRequest, FALSE, Extension); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Perhaps another mask request was " "found in the queue\n" "------- %p/%p <- values should be the " "same\n", Extension->CurrentMaskRequest, NewRequest); } } } while (NewRequest); return; } BOOLEAN SerialGrabWaitFromIsr( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine will check to see if the ISR still knows about a wait request by checking to see if the IrpMaskLocation is non-null. If it is then it will zero the Irpmasklocation (which in effect grabs the request away from the isr). This routine is only called buy the cancel code for the wait. NOTE: This is called by WdfInterruptSynchronize. Arguments: Context - A pointer to the device extension Return Value: Always FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "In SerialGrabWaitFromIsr\n"); if (Extension->IrpMaskLocation) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "The isr still owns the request %p, mask " "location is %p\n" "------- and system buffer is %p\n", Extension->CurrentWaitRequest,Extension->IrpMaskLocation, reqContext->SystemBuffer); // // The isr still "owns" the request. // *Extension->IrpMaskLocation = 0; Extension->IrpMaskLocation = NULL; reqContext->Information = sizeof(ULONG); // // Since the isr no longer references the request we need to // decrement the reference count. // SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_ISR ); } return FALSE; } BOOLEAN SerialGiveWaitToIsr( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine simply sets a variable in the device extension so that the isr knows that we have a wait request. NOTE: This is called by WdfInterruptSynchronize. NOTE: This routine assumes that it is called with the cancel spinlock held. Arguments: Context - Simply a pointer to the device extension. Return Value: Always FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "In SerialGiveWaitToIsr\n"); // // There certainly shouldn't be a current mask location at // this point since we have a new current wait request. // ASSERT(!Extension->IrpMaskLocation); // // The isr may or may not actually reference this request. It // won't if the wait can be satisfied immediately. However, // since it will then go through the normal completion sequence, // we need to have an incremented reference count anyway. // SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_ISR ); if (!Extension->HistoryMask) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "No events occured prior to the wait call" "\n"); // // Although this wait might not be for empty transmit // queue, it doesn't hurt anything to set it to false. // Extension->EmptiedTransmit = FALSE; // // Record where the "completion mask" should be set. // Extension->IrpMaskLocation = reqContext->SystemBuffer; SerialDbgPrintEx( TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "The isr owns the request %p, mask location is " "%p\n" "------- and system buffer is %p\n", Extension->CurrentWaitRequest,Extension->IrpMaskLocation, reqContext->SystemBuffer); } else { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "%x occurred prior to the wait - starting " "the\n" "------- completion code for %p\n", Extension->HistoryMask,Extension->CurrentWaitRequest); *((ULONG *)reqContext->SystemBuffer) = Extension->HistoryMask; Extension->HistoryMask = 0; reqContext->Information = sizeof(ULONG); reqContext->Status = STATUS_SUCCESS; SerialInsertQueueDpc(Extension->CommWaitDpc); } return FALSE; } BOOLEAN SerialFinishOldWait( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine will check to see if the ISR still knows about a wait request by checking to see if the Irpmasklocation is non-null. If it is then it will zero the Irpmasklocation (which in effect grabs the request away from the isr). This routine is only called buy the cancel code for the wait. NOTE: This is called by WdfInterruptSynchronize. Arguments: Context - A pointer to the device extension Return Value: Always FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; PREQUEST_CONTEXT reqContext = NULL; PREQUEST_CONTEXT reqContextMask; UNREFERENCED_PARAMETER(Interrupt); reqContextMask = SerialGetRequestContext(Extension->CurrentMaskRequest); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "In SerialFinishOldWait\n"); if (Extension->IrpMaskLocation) { reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "The isr still owns the request %p, mask " "location is %p\n" "------- and system buffer is %p\n", Extension->CurrentWaitRequest,Extension->IrpMaskLocation, reqContext->SystemBuffer); // // The isr still "owns" the request. // *Extension->IrpMaskLocation = 0; Extension->IrpMaskLocation = NULL; reqContext->Information = sizeof(ULONG); // // We don't decrement the reference since the completion routine // will do that. // SerialInsertQueueDpc(Extension->CommWaitDpc); } // // Don't wipe out any historical data we are still interested in. // Extension->HistoryMask &= *((ULONG *)reqContextMask->SystemBuffer); Extension->IsrWaitMask = *((ULONG *)reqContextMask->SystemBuffer); SerialDbgPrintEx( TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Set mask location of %p, in request %p, with " "system buffer of %p\n", Extension->IrpMaskLocation, Extension->CurrentMaskRequest, reqContextMask->SystemBuffer); return FALSE; } VOID SerialCancelWait( IN WDFREQUEST Request ) /*++ Routine Description: This routine is used to cancel a request that is waiting on a comm event. Arguments: Device - Wdf handle for the device Request - Pointer to the WDFREQUEST for the current request Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION Extension; WDFDEVICE device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)); UNREFERENCED_PARAMETER(Request); Extension = SerialGetDeviceExtension(device); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Canceling wait for request %p\n", Extension->CurrentWaitRequest); SerialTryToCompleteCurrent(Extension, SerialGrabWaitFromIsr, STATUS_CANCELLED, &Extension->CurrentWaitRequest, NULL, NULL, NULL, NULL, NULL, SERIAL_REF_CANCEL); } VOID SerialCompleteWait( IN WDFDPC Dpc ) { PSERIAL_DEVICE_EXTENSION Extension = NULL; Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc)); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, ">SerialCompleteWait(%p)\n", Extension); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Completing wait for request %p\n", Extension->CurrentWaitRequest); SerialTryToCompleteCurrent(Extension, NULL, STATUS_SUCCESS, &Extension->CurrentWaitRequest, NULL, NULL, NULL, NULL, NULL, SERIAL_REF_ISR); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, " #if defined(EVENT_TRACING) #include "wmi.tmh" #endif EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortName; EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortCommData; EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortHWData; EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortPerfData; EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortPropData; NTSTATUS SerialWmiRegisterInstance( WDFDEVICE Device, const GUID* Guid, ULONG MinInstanceBufferSize, PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGESRP0, SerialWmiRegistration) #pragma alloc_text(PAGESRP0, SerialWmiRegisterInstance) #pragma alloc_text(PAGESRP0, EvtWmiQueryPortName) #pragma alloc_text(PAGESRP0, EvtWmiQueryPortCommData) #pragma alloc_text(PAGESRP0, EvtWmiQueryPortHWData) #pragma alloc_text(PAGESRP0, EvtWmiQueryPortPerfData) #pragma alloc_text(PAGESRP0, EvtWmiQueryPortPropData) #endif NTSTATUS SerialWmiRegisterInstance( WDFDEVICE Device, const GUID* Guid, ULONG MinInstanceBufferSize, PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance ) { WDF_WMI_PROVIDER_CONFIG providerConfig; WDF_WMI_INSTANCE_CONFIG instanceConfig; PAGED_CODE(); // // Create and register WMI providers and instances blocks // WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, Guid); providerConfig.MinInstanceBufferSize = MinInstanceBufferSize; WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig); instanceConfig.Register = TRUE; instanceConfig.EvtWmiInstanceQueryInstance = EvtWmiInstanceQueryInstance; return WdfWmiInstanceCreate(Device, &instanceConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); } NTSTATUS SerialWmiRegistration( WDFDEVICE Device ) /*++ Routine Description Registers with WMI as a data provider for this instance of the device --*/ { NTSTATUS status = STATUS_SUCCESS; PSERIAL_DEVICE_EXTENSION pDevExt; PAGED_CODE(); pDevExt = SerialGetDeviceExtension (Device); // // Fill in wmi perf data (all zero's) // RtlZeroMemory(&pDevExt->WmiPerfData, sizeof(pDevExt->WmiPerfData)); status = SerialWmiRegisterInstance(Device, &MSSerial_PortName_GUID, 0, EvtWmiQueryPortName); if (!NT_SUCCESS(status)) { return status; } status = SerialWmiRegisterInstance(Device, &MSSerial_CommInfo_GUID, sizeof(SERIAL_WMI_COMM_DATA), EvtWmiQueryPortCommData); if (!NT_SUCCESS(status)) { return status; } status = SerialWmiRegisterInstance(Device, &MSSerial_HardwareConfiguration_GUID, sizeof(SERIAL_WMI_HW_DATA), EvtWmiQueryPortHWData); if (!NT_SUCCESS(status)) { return status; } status = SerialWmiRegisterInstance(Device, &MSSerial_PerformanceInformation_GUID, sizeof(SERIAL_WMI_PERF_DATA), EvtWmiQueryPortPerfData); if (!NT_SUCCESS(status)) { return status; } status = SerialWmiRegisterInstance(Device, &MSSerial_CommProperties_GUID, sizeof(SERIAL_COMMPROP) + sizeof(ULONG), EvtWmiQueryPortPropData); if (!NT_SUCCESS(status)) { return status; } return status; } // // WMI Call back functions // NTSTATUS EvtWmiQueryPortName( IN WDFWMIINSTANCE WmiInstance, IN ULONG OutBufferSize, IN PVOID OutBuffer, OUT PULONG BufferUsed ) { WDFDEVICE device; WCHAR pRegName[SYMBOLIC_NAME_LENGTH]; UNICODE_STRING string; USHORT nameSize = sizeof(pRegName); NTSTATUS status; PAGED_CODE(); device = WdfWmiInstanceGetDevice(WmiInstance); status = SerialReadSymName(device, pRegName, &nameSize); if (!NT_SUCCESS(status)) { return status; } RtlInitUnicodeString(&string, pRegName); return WDF_WMI_BUFFER_APPEND_STRING(OutBuffer, OutBufferSize, &string, BufferUsed); } NTSTATUS EvtWmiQueryPortCommData( IN WDFWMIINSTANCE WmiInstance, IN ULONG OutBufferSize, IN PVOID OutBuffer, OUT PULONG BufferUsed ) { PSERIAL_DEVICE_EXTENSION pDevExt; UNREFERENCED_PARAMETER(OutBufferSize); PAGED_CODE(); pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance)); *BufferUsed = sizeof(SERIAL_WMI_COMM_DATA); if (OutBufferSize < *BufferUsed) { return STATUS_INSUFFICIENT_RESOURCES; } *(PSERIAL_WMI_COMM_DATA)OutBuffer = pDevExt->WmiCommData; return STATUS_SUCCESS; } NTSTATUS EvtWmiQueryPortHWData( IN WDFWMIINSTANCE WmiInstance, IN ULONG OutBufferSize, IN PVOID OutBuffer, OUT PULONG BufferUsed ) { PSERIAL_DEVICE_EXTENSION pDevExt; UNREFERENCED_PARAMETER(OutBufferSize); PAGED_CODE(); pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance)); *BufferUsed = sizeof(SERIAL_WMI_HW_DATA); if (OutBufferSize < *BufferUsed) { return STATUS_INSUFFICIENT_RESOURCES; } *(PSERIAL_WMI_HW_DATA)OutBuffer = pDevExt->WmiHwData; return STATUS_SUCCESS; } NTSTATUS EvtWmiQueryPortPerfData( IN WDFWMIINSTANCE WmiInstance, IN ULONG OutBufferSize, IN PVOID OutBuffer, OUT PULONG BufferUsed ) { PSERIAL_DEVICE_EXTENSION pDevExt; UNREFERENCED_PARAMETER(OutBufferSize); PAGED_CODE(); pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance)); *BufferUsed = sizeof(SERIAL_WMI_PERF_DATA); if (OutBufferSize < *BufferUsed) { return STATUS_INSUFFICIENT_RESOURCES; } *(PSERIAL_WMI_PERF_DATA)OutBuffer = pDevExt->WmiPerfData; return STATUS_SUCCESS; } NTSTATUS EvtWmiQueryPortPropData( IN WDFWMIINSTANCE WmiInstance, IN ULONG OutBufferSize, IN PVOID OutBuffer, OUT PULONG BufferUsed ) { PSERIAL_DEVICE_EXTENSION pDevExt; UNREFERENCED_PARAMETER(OutBufferSize); PAGED_CODE(); pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance)); *BufferUsed = sizeof(SERIAL_COMMPROP) + sizeof(ULONG); if (OutBufferSize < *BufferUsed) { return STATUS_INSUFFICIENT_RESOURCES; } SerialGetProperties( pDevExt, (PSERIAL_COMMPROP)OutBuffer ); *((PULONG)(((PSERIAL_COMMPROP)OutBuffer)->ProvChar)) = 0; return STATUS_SUCCESS; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/write.c ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: write.c Abstract: This module contains the code that is very specific to write operations in the serial driver Environment: Kernel mode --*/ #include "precomp.h" #if defined(EVENT_TRACING) #include "write.tmh" #endif EVT_WDF_REQUEST_CANCEL SerialCancelCurrentWrite; EVT_WDF_REQUEST_CANCEL SerialCancelCurrentXoff; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGiveWriteToIsr; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGiveXoffToIsr; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabWriteFromIsr; EVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabXoffFromIsr; VOID SerialEvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: This is the dispatch routine for write. It validates the parameters for the write request and if all is ok then it places the request on the work queue. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Pointer to the WDFREQUEST for the current request Length - Length of the IO operation The default property of the queue is to not dispatch zero lenght read & write requests to the driver and complete is with status success. So we will never get a zero length request. Return Value: --*/ { PSERIAL_DEVICE_EXTENSION extension; NTSTATUS status; WDFDEVICE hDevice; WDF_REQUEST_PARAMETERS params; PREQUEST_CONTEXT reqContext; size_t bufLen; hDevice = WdfIoQueueGetDevice(Queue); extension = SerialGetDeviceExtension(hDevice); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, ">SerialEvtIoWrite(%p, 0x%I64x)\n", Request, Length); if (SerialCompleteIfError(extension, Request) != STATUS_SUCCESS) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "MajorFunction = params.Type; reqContext->Length = (ULONG) Length; status = WdfRequestRetrieveInputBuffer (Request, Length, &reqContext->SystemBuffer, &bufLen); if (!NT_SUCCESS (status)) { SerialCompleteRequest(Request , status, 0); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "WriteQueue, &extension->CurrentWriteRequest, SerialStartWrite); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "SerialStartWrite(%p)\n", Extension); TotalTime.QuadPart = 0; do { reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest); // // If there is an xoff counter then complete it. // // // We see if there is a actually an Xoff counter request. // // If there is, we put the write request back on the head // of the write list. We then complete the xoff counter. // The xoff counter completing code will actually make the // xoff counter back into the current write request, and // in the course of completing the xoff (which is now // the current write) we will restart this request. // if (Extension->CurrentXoffRequest) { reqContextXoff = SerialGetRequestContext(Extension->CurrentXoffRequest); if (SERIAL_REFERENCE_COUNT(reqContextXoff)) { // // The reference count is non-zero. This implies that // the xoff request has not made it through the completion // path yet. We will increment the reference count // and attempt to complete it ourseleves. // SERIAL_SET_REFERENCE( reqContextXoff, SERIAL_REF_XOFF_REF ); reqContextXoff->Information = 0; // // The following call will actually release the // cancel spin lock. // SerialTryToCompleteCurrent( Extension, SerialGrabXoffFromIsr, STATUS_SERIAL_MORE_WRITES, &Extension->CurrentXoffRequest, NULL, NULL, Extension->XoffCountTimer, NULL, NULL, SERIAL_REF_XOFF_REF ); } else { // // The request is well on its way to being finished. // We can let the regular completion code do the // work. Just release the spin lock. // } } UseATimer = FALSE; // // Calculate the timeout value needed for the // request. Note that the values stored in the // timeout record are in milliseconds. Note that // if the timeout values are zero then we won't start // the timer. // Timeouts = Extension->Timeouts; if (Timeouts.WriteTotalTimeoutConstant || Timeouts.WriteTotalTimeoutMultiplier) { UseATimer = TRUE; // // We have some timer values to calculate. // // Take care, we might have an xoff counter masquerading // as a write. // TotalTime.QuadPart = ((LONGLONG)((UInt32x32To64( (reqContext->MajorFunction == IRP_MJ_WRITE)? (reqContext->Length) : (1), Timeouts.WriteTotalTimeoutMultiplier ) + Timeouts.WriteTotalTimeoutConstant))) * -10000; } // // The request may be going to the isr shortly. Now // is a good time to initialize its reference counts. // SERIAL_INIT_REFERENCE(reqContext); // // We give the request to to the isr to write out. // We set a cancel routine that knows how to // grab the current write away from the isr. // SerialSetCancelRoutine(Extension->CurrentWriteRequest, SerialCancelCurrentWrite); if (UseATimer) { BOOLEAN result; result = SerialSetTimer( Extension->WriteRequestTotalTimer, TotalTime ); if(result == FALSE) { // // This timer now has a reference to the request. // SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_TOTAL_TIMER ); } } WdfInterruptSynchronize( Extension->WdfInterrupt, SerialGiveWriteToIsr, Extension ); } WHILE (FALSE); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "SerialGetNextWrite\n"); do { reqContext = SerialGetRequestContext(*CurrentOpRequest); // // We could be completing a flush. // if (reqContext->MajorFunction == IRP_MJ_WRITE) { ASSERT(Extension->TotalCharsQueued >= reqContext->Length); Extension->TotalCharsQueued -= reqContext->Length; } else if (reqContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) { WDFREQUEST request = *CurrentOpRequest; PSERIAL_XOFF_COUNTER Xc; Xc = reqContext->SystemBuffer; // // We should never have a xoff counter when we // get to this point. // ASSERT(!Extension->CurrentXoffRequest); // // This could only be a xoff counter masquerading as // a write request. // Extension->TotalCharsQueued--; // // Check to see of the xoff request has been set with success. // This means that the write completed normally. If that // is the case, and it hasn't been set to cancel in the // meanwhile, then go on and make it the CurrentXoffRequest. // if (reqContext->Status != STATUS_SUCCESS || reqContext->Cancelled) { // TODO: I see Xoff request getting abandoned due to loss of // Total timer - SERIAL_REF_TOTAL_TIMER // // Oh well, we can just finish it off. // NOTHING; } else { SerialSetCancelRoutine(request, SerialCancelCurrentXoff); // // We don't want to complete the current request now. This // will now get completed by the Xoff counter code. // CompleteCurrent = FALSE; // // Give the counter to the isr. // Extension->CurrentXoffRequest = request; WdfInterruptSynchronize( Extension->WdfInterrupt, SerialGiveXoffToIsr, Extension ); // // Start the timer for the counter and increment // the reference count since the timer has a // reference to the request. // if (Xc->Timeout) { LARGE_INTEGER delta; BOOLEAN result; delta.QuadPart = -((LONGLONG)UInt32x32To64( 1000, Xc->Timeout )); result = SerialSetTimer( Extension->XoffCountTimer, delta ); if(result == FALSE) { SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_TOTAL_TIMER ); } } } } // // Note that the following call will (probably) also cause // the current request to be completed. // SerialGetNextRequest( CurrentOpRequest, QueueToProcess, NewRequest, CompleteCurrent, Extension ); if (!*NewRequest) { WdfInterruptSynchronize( Extension->WdfInterrupt, SerialProcessEmptyTransmit, Extension ); break; } else if (SerialGetRequestContext(*NewRequest)->MajorFunction == IRP_MJ_FLUSH_BUFFERS) { // // If we encounter a flush request we just want to get // the next request and complete the flush. // // Note that if NewRequest is non-null then it is also // equal to CurrentWriteRequest. // ASSERT((*NewRequest) == (*CurrentOpRequest)); SerialGetRequestContext(*NewRequest)->Status = STATUS_SUCCESS; } else { break; } } WHILE (TRUE); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "SerialCompleteWrite(%p)\n", Extension); SerialTryToCompleteCurrent(Extension, NULL, STATUS_SUCCESS, &Extension->CurrentWriteRequest, Extension->WriteQueue, NULL, Extension->WriteRequestTotalTimer, SerialStartWrite, SerialGetNextWrite, SERIAL_REF_ISR); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "IsrWaitMask && (Extension->IsrWaitMask & SERIAL_EV_TXEMPTY) && Extension->EmptiedTransmit && (!Extension->TransmitImmediate) && (!Extension->CurrentWriteRequest) && IsQueueEmpty(Extension->WriteQueue)) { Extension->HistoryMask |= SERIAL_EV_TXEMPTY; if (Extension->IrpMaskLocation) { *Extension->IrpMaskLocation = Extension->HistoryMask; Extension->IrpMaskLocation = NULL; Extension->HistoryMask = 0; SerialGetRequestContext(Extension->CurrentWaitRequest)->Information = sizeof(ULONG); SerialInsertQueueDpc( Extension->CommWaitDpc ); } Extension->CountOfTryingToLowerRTS++; SerialPerhapsLowerRTS(Extension->WdfInterrupt, Extension); } return FALSE; } BOOLEAN SerialGiveWriteToIsr( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: Try to start off the write by slipping it in behind a transmit immediate char, or if that isn't available and the transmit holding register is empty, "tickle" the UART into interrupting with a transmit buffer empty. NOTE: This routine is called by WdfInterruptSynchronize. NOTE: This routine assumes that it is called with the cancel spin lock held. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; // // The current stack location. This contains all of the // information we need to process this particular request. // PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest); // // We might have a xoff counter request masquerading as a // write. The length of these requests will always be one // and we can get a pointer to the actual character from // the data supplied by the user. // if (reqContext->MajorFunction == IRP_MJ_WRITE) { Extension->WriteLength = reqContext->Length; Extension->WriteCurrentChar = reqContext->SystemBuffer; } else { Extension->WriteLength = 1; Extension->WriteCurrentChar = ((PUCHAR)reqContext->SystemBuffer) + FIELD_OFFSET( SERIAL_XOFF_COUNTER, XoffChar ); } // // The isr now has a reference to the request. // SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_ISR ); // // Check first to see if an immediate char is transmitting. // If it is then we'll just slip in behind it when its // done. // if (!Extension->TransmitImmediate) { // // If there is no immediate char transmitting then we // will "re-enable" the transmit holding register empty // interrupt. The 8250 family of devices will always // signal a transmit holding register empty interrupt // *ANY* time this bit is set to one. By doing things // this way we can simply use the normal interrupt code // to start off this write. // // We've been keeping track of whether the transmit holding // register is empty so it we only need to do this // if the register is empty. // if (Extension->HoldingEmpty) { DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller); ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller); } } // // The rts line may already be up from previous writes, // however, it won't take much additional time to turn // on the RTS line if we are doing transmit toggling. // if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { SerialSetRTS(Extension->WdfInterrupt, Extension); } return FALSE; } VOID SerialCancelCurrentWrite( IN WDFREQUEST Request ) /*++ Routine Description: This routine is used to cancel the current write. Arguments: Device - Wdf handle for the device Request - Pointer to the WDFREQUEST to be canceled. Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION Extension; WDFDEVICE device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)); UNREFERENCED_PARAMETER(Request); Extension = SerialGetDeviceExtension(device); SerialTryToCompleteCurrent( Extension, SerialGrabWriteFromIsr, STATUS_CANCELLED, &Extension->CurrentWriteRequest, Extension->WriteQueue, NULL, Extension->WriteRequestTotalTimer, SerialStartWrite, SerialGetNextWrite, SERIAL_REF_CANCEL ); } VOID SerialWriteTimeout( IN WDFTIMER Timer ) /*++ Routine Description: This routine will try to timeout the current write. Arguments: Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION Extension = NULL; Extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer)); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, ">SerialWriteTimeout(%p)\n", Extension); SerialTryToCompleteCurrent(Extension, SerialGrabWriteFromIsr, STATUS_TIMEOUT, &Extension->CurrentWriteRequest, Extension->WriteQueue, NULL, Extension->WriteRequestTotalTimer, SerialStartWrite, SerialGetNextWrite, SERIAL_REF_TOTAL_TIMER); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "CurrentWriteRequest); // // Check if the write length is non-zero. If it is non-zero // then the ISR still owns the request. We calculate the the number // of characters written and update the information field of the // request with the characters written. We then clear the write length // the isr sees. // if (Extension->WriteLength) { // // We could have an xoff counter masquerading as a // write request. If so, don't update the write length. // if (reqContext->MajorFunction == IRP_MJ_WRITE) { reqContext->Information = reqContext->Length -Extension->WriteLength; } else { reqContext->Information = 0; } // // Since the isr no longer references this request, we can // decrement it's reference count. // SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_ISR ); Extension->WriteLength = 0; } return FALSE; } BOOLEAN SerialGrabXoffFromIsr( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine is used to grab an xoff counter request from the isr when it is no longer masquerading as a write request. This routine is called by the cancel and timeout code for the xoff counter ioctl. NOTE: This routine is being called from WdfInterruptSynchronize. NOTE: This routine assumes that the cancel spin lock is held when this routine is called. Arguments: Context - Really a pointer to the device extension. Return Value: Always false. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(Extension->CurrentXoffRequest); if (Extension->CountSinceXoff) { // // This is only non-zero when there actually is a Xoff ioctl // counting down. // Extension->CountSinceXoff = 0; // // We decrement the count since the isr no longer owns // the request. // SERIAL_CLEAR_REFERENCE( reqContext, SERIAL_REF_ISR ); } return FALSE; } VOID SerialCompleteXoff( IN WDFDPC Dpc ) /*++ Routine Description: This routine is merely used to truely complete an xoff counter request. It assumes that the status and the information fields of the request are already correctly filled in. Arguments: Dpc - Not Used. DeferredContext - Really points to the device extension. SystemContext1 - Not Used. SystemContext2 - Not Used. Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION Extension = NULL; Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc)); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, ">SerialCompleteXoff(%p)\n", Extension); SerialTryToCompleteCurrent(Extension, NULL, STATUS_SUCCESS, &Extension->CurrentXoffRequest, NULL, NULL, Extension->XoffCountTimer, NULL, NULL, SERIAL_REF_ISR); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "SerialTimeoutXoff(%p)\n", Extension); SerialTryToCompleteCurrent(Extension, SerialGrabXoffFromIsr, STATUS_SERIAL_COUNTER_TIMEOUT, &Extension->CurrentXoffRequest, NULL, NULL, NULL, NULL, NULL, SERIAL_REF_TOTAL_TIMER); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, "CurrentXoffRequest, NULL, NULL, Extension->XoffCountTimer, NULL, NULL, SERIAL_REF_CANCEL ); } BOOLEAN SerialGiveXoffToIsr( IN WDFINTERRUPT Interrupt, IN PVOID Context ) /*++ Routine Description: This routine starts off the xoff counter. It merely has to set the xoff count and increment the reference count to denote that the isr has a reference to the request. NOTE: This routine is called by WdfInterruptSynchronize. NOTE: This routine assumes that it is called with the cancel spin lock held. Arguments: Context - Really a pointer to the device extension. Return Value: This routine always returns FALSE. --*/ { PSERIAL_DEVICE_EXTENSION Extension = Context; PREQUEST_CONTEXT reqContext; PSERIAL_XOFF_COUNTER Xc = NULL; UNREFERENCED_PARAMETER(Interrupt); reqContext = SerialGetRequestContext(Extension->CurrentXoffRequest); Xc = reqContext->SystemBuffer; // // The current stack location. This contains all of the // information we need to process this particular request. // ASSERT(Extension->CurrentXoffRequest); Extension->CountSinceXoff = Xc->Counter; // // The isr now has a reference to the request. // SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_ISR ); return FALSE; } ================================================ FILE: tests/projects/windows/driver/kmdf/serial/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("wdfserial") add_rules("wdk.env.kmdf", "wdk.driver") add_values("wdk.tracewpp.flags", "-func:SerialDbgPrintEx(LEVEL,FLAGS,MSG,...)") add_values("wdk.mc.header", "serlog.h") add_files("*.c", {rules = "wdk.tracewpp"}) add_files("*.mc", "*.rc", "*.inx") ================================================ FILE: tests/projects/windows/driver/umdf/echo/driver/device.c ================================================ /*++ Copyright (c) 1990-2000 Microsoft Corporation Module Name: device.c - Device handling events for example driver. Abstract: This is a C version of a very simple sample driver that illustrates how to use the driver framework and demonstrates best practices. --*/ #include "driver.h" NTSTATUS EchoDeviceCreate( PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: DeviceInit - Pointer to an opaque init structure. Memory for this structure will be freed by the framework when the WdfDeviceCreate succeeds. So don't access the structure after that point. Return Value: NTSTATUS --*/ { WDF_OBJECT_ATTRIBUTES deviceAttributes; PDEVICE_CONTEXT deviceContext; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDFDEVICE device; NTSTATUS status; WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // Register pnp/power callbacks so that we can start and stop the timer as the device // gets started and stopped. // pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart; pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend; #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks") pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart; // // Register the PnP and power callbacks. Power policy related callbacks will be registered // later in SotwareInit. // WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); if (NT_SUCCESS(status)) { // // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the // device.h header file. This function will do the type checking and return // the device context. If you pass a wrong object handle // it will return NULL and assert if run under framework verifier mode. // deviceContext = WdfObjectGet_DEVICE_CONTEXT(device); deviceContext->PrivateDeviceData = 0; // // Create a device interface so that application can find and talk // to us. // status = WdfDeviceCreateDeviceInterface( device, &GUID_DEVINTERFACE_ECHO, NULL // ReferenceString ); if (NT_SUCCESS(status)) { // // Initialize the I/O Package and any Queues // status = EchoQueueInitialize(device); } } return status; } NTSTATUS EchoEvtDeviceSelfManagedIoStart( IN WDFDEVICE Device ) /*++ Routine Description: This event is called by the Framework when the device is started or restarted after a suspend operation. This function is not marked pageable because this function is in the device power up path. When a function is marked pagable and the code section is paged out, it will generate a page fault which could impact the fast resume behavior because the client driver will have to wait until the system drivers can service this page fault. Arguments: Device - Handle to a framework device object. Return Value: NTSTATUS - Failures will result in the device stack being torn down. --*/ { PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); LARGE_INTEGER DueTime; KdPrint(("--> EchoEvtDeviceSelfManagedIoInit\n")); // // Restart the queue and the periodic timer. We stopped them before going // into low power state. // WdfIoQueueStart(WdfDeviceGetDefaultQueue(Device)); DueTime.QuadPart = WDF_REL_TIMEOUT_IN_MS(100); WdfTimerStart(queueContext->Timer, DueTime.QuadPart); KdPrint(( "<-- EchoEvtDeviceSelfManagedIoInit\n")); return STATUS_SUCCESS; } NTSTATUS EchoEvtDeviceSelfManagedIoSuspend( IN WDFDEVICE Device ) /*++ Routine Description: This event is called by the Framework when the device is stopped for resource rebalance or suspended when the system is entering Sx state. Arguments: Device - Handle to a framework device object. Return Value: NTSTATUS - The driver is not allowed to fail this function. If it does, the device stack will be torn down. --*/ { PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); PAGED_CODE(); KdPrint(("--> EchoEvtDeviceSelfManagedIoSuspend\n")); // // Before we stop the timer we should make sure there are no outstanding // i/o. We need to do that because framework cannot suspend the device // if there are requests owned by the driver. There are two ways to solve // this issue: 1) We can wait for the outstanding I/O to be complete by the // periodic timer 2) Register EvtIoStop callback on the queue and acknowledge // the request to inform the framework that it's okay to suspend the device // with outstanding I/O. In this sample we will use the 1st approach // because it's pretty easy to do. We will restart the queue when the // device is restarted. // WdfIoQueueStopSynchronously(WdfDeviceGetDefaultQueue(Device)); // // Stop the watchdog timer and wait for DPC to run to completion if it's already fired. // WdfTimerStop(queueContext->Timer, TRUE); KdPrint(( "<-- EchoEvtDeviceSelfManagedIoSuspend\n")); return STATUS_SUCCESS; } ================================================ FILE: tests/projects/windows/driver/umdf/echo/driver/device.h ================================================ /*++ Copyright (c) 1990-2000 Microsoft Corporation Module Name: device.h Abstract: This is a C version of a very simple sample driver that illustrates how to use the driver framework and demonstrates best practices. --*/ #include "public.h" // // The device context performs the same job as // a WDM device extension in the driver frameworks // typedef struct _DEVICE_CONTEXT { ULONG PrivateDeviceData; // just a placeholder } DEVICE_CONTEXT, *PDEVICE_CONTEXT; // // This macro will generate an inline function called WdfObjectGet_DEVICE_CONTEXT // which will be used to get a pointer to the device context memory // in a type safe manner. // WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT) // // Function to initialize the device and its callbacks // NTSTATUS EchoDeviceCreate( PWDFDEVICE_INIT DeviceInit ); // // Device events // EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT EchoEvtDeviceSelfManagedIoStart; EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EchoEvtDeviceSelfManagedIoSuspend; ================================================ FILE: tests/projects/windows/driver/umdf/echo/driver/driver.c ================================================ /*++ Copyright (c) 1990-2000 Microsoft Corporation Module Name: driver.c Abstract: This driver demonstrates use of a default I/O Queue, its request start events, cancellation event, and a synchronized DPC. To demonstrate asynchronous operation, the I/O requests are not completed immediately, but stored in the drivers private data structure, and a timer will complete it next time the Timer callback runs. During the time the request is waiting for the timer callback to run, it is made cancellable by the call WdfRequestMarkCancelable. This allows the test program to cancel the request and exit instantly. This rather complicated set of events is designed to demonstrate the driver frameworks synchronization of access to a device driver data structure, and a pointer which can be a proxy for device hardware registers or resources. This common data structure, or resource is accessed by new request events arriving, the Timer callback that completes it, and cancel processing. Notice the lack of specific lock/unlock operations. Even though this example utilizes a serial queue, a parallel queue would not need any additional explicit synchronization, just a strategy for managing multiple requests outstanding. --*/ #include "driver.h" NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: DriverEntry initializes the driver and is the first routine called by the system after the driver is loaded. DriverEntry specifies the other entry points in the function driver, such as EvtDevice and DriverUnload. Parameters Description: DriverObject - represents the instance of the function driver that is loaded into memory. DriverEntry must initialize members of DriverObject before it returns to the caller. DriverObject is allocated by the system before the driver is loaded, and it is released by the system after the system unloads the function driver from memory. RegistryPath - represents the driver specific path in the Registry. The function driver can use the path to store driver related data between reboots. The path does not store hardware instance specific data. Return Value: STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise. --*/ { WDF_DRIVER_CONFIG config; NTSTATUS status; WDF_DRIVER_CONFIG_INIT(&config, EchoEvtDeviceAdd ); status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE); if (!NT_SUCCESS(status)) { KdPrint(("Error: WdfDriverCreate failed 0x%x\n", status)); return status; } #if DBG EchoPrintDriverVersion(); #endif return status; } NTSTATUS EchoEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. We create and initialize a device object to represent a new instance of the device. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { NTSTATUS status; UNREFERENCED_PARAMETER(Driver); KdPrint(("Enter EchoEvtDeviceAdd\n")); status = EchoDeviceCreate(DeviceInit); return status; } NTSTATUS EchoPrintDriverVersion( ) /*++ Routine Description: This routine shows how to retrieve framework version string and also how to find out to which version of framework library the client driver is bound to. Arguments: Return Value: NTSTATUS --*/ { NTSTATUS status; WDFSTRING string; UNICODE_STRING us; WDF_DRIVER_VERSION_AVAILABLE_PARAMS ver; // // 1) Retreive version string and print that in the debugger. // status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &string); if (!NT_SUCCESS(status)) { KdPrint(("Error: WdfStringCreate failed 0x%x\n", status)); return status; } status = WdfDriverRetrieveVersionString(WdfGetDriver(), string); if (!NT_SUCCESS(status)) { // // No need to worry about delete the string object because // by default it's parented to the driver and it will be // deleted when the driverobject is deleted when the DriverEntry // returns a failure status. // KdPrint(("Error: WdfDriverRetrieveVersionString failed 0x%x\n", status)); return status; } WdfStringGetUnicodeString(string, &us); KdPrint(("Echo Sample %wZ\n", &us)); WdfObjectDelete(string); string = NULL; // To avoid referencing a deleted object. // // 2) Find out to which version of framework this driver is bound to. // WDF_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&ver, 1, 0); if (WdfDriverIsVersionAvailable(WdfGetDriver(), &ver) == TRUE) { KdPrint(("Yes, framework version is 1.0\n")); }else { KdPrint(("No, framework verison is not 1.0\n")); } return STATUS_SUCCESS; } ================================================ FILE: tests/projects/windows/driver/umdf/echo/driver/driver.h ================================================ /*++ Copyright (c) 1990-2000 Microsoft Corporation Module Name: driver.h Abstract: This is a C version of a very simple sample driver that illustrates how to use the driver framework and demonstrates best practices. --*/ #define INITGUID #include #include #include "device.h" #include "queue.h" #ifndef ASSERT #if DBG #define ASSERT( exp ) \ ((!(exp)) ? \ (KdPrint(( "\n*** Assertion failed: " #exp "\n\n")), \ DebugBreak(), \ FALSE) : \ TRUE) #else #define ASSERT( exp ) #endif // DBG #endif // ASSERT // // WDFDRIVER Events // DRIVER_INITIALIZE DriverEntry; EVT_WDF_DRIVER_DEVICE_ADD EchoEvtDeviceAdd; NTSTATUS EchoPrintDriverVersion( ); ================================================ FILE: tests/projects/windows/driver/umdf/echo/driver/queue.c ================================================ /*++ Copyright (c) 1990-2000 Microsoft Corporation Module Name: queue.c Abstract: This is a C version of a very simple sample driver that illustrates how to use the driver framework and demonstrates best practices. --*/ #include "driver.h" NTSTATUS EchoQueueInitialize( WDFDEVICE Device ) /*++ Routine Description: The I/O dispatch callbacks for the frameworks device object are configured in this function. A single default I/O Queue is configured for serial request processing, and a driver context memory allocation is created to hold our structure QUEUE_CONTEXT. This memory may be used by the driver automatically synchronized by the Queue's presentation lock. The lifetime of this memory is tied to the lifetime of the I/O Queue object, and we register an optional destructor callback to release any private allocations, and/or resources. Arguments: Device - Handle to a framework device object. Return Value: NTSTATUS --*/ { WDFQUEUE queue; NTSTATUS status; PQUEUE_CONTEXT queueContext; WDF_IO_QUEUE_CONFIG queueConfig; WDF_OBJECT_ATTRIBUTES queueAttributes; // // Configure a default queue so that requests that are not // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto // other queues get dispatched here. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &queueConfig, WdfIoQueueDispatchSequential ); queueConfig.EvtIoRead = EchoEvtIoRead; queueConfig.EvtIoWrite = EchoEvtIoWrite; // // Fill in a callback for destroy, and our QUEUE_CONTEXT size // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_CONTEXT); // // Set synchronization scope on queue and have the timer to use queue as // the parent object so that queue and timer callbacks are synchronized // with the same lock. // queueAttributes.SynchronizationScope = WdfSynchronizationScopeQueue; queueAttributes.EvtDestroyCallback = EchoEvtIoQueueContextDestroy; status = WdfIoQueueCreate( Device, &queueConfig, &queueAttributes, &queue ); if( !NT_SUCCESS(status) ) { KdPrint(("WdfIoQueueCreate failed 0x%x\n",status)); return status; } // Get our Driver Context memory from the returned Queue handle queueContext = QueueGetContext(queue); queueContext->WriteMemory = NULL; queueContext->Timer = NULL; queueContext->CurrentRequest = NULL; queueContext->CurrentStatus = STATUS_INVALID_DEVICE_REQUEST; // // Create the Queue timer // status = EchoTimerCreate(&queueContext->Timer, queue); if (!NT_SUCCESS(status)) { KdPrint(("Error creating timer 0x%x\n",status)); return status; } return status; } NTSTATUS EchoTimerCreate( IN WDFTIMER* Timer, IN WDFQUEUE Queue ) /*++ Routine Description: Subroutine to create timer. By associating the timerobject with the queue, we are basically telling the framework to serialize the queue callbacks with the timer callback. By doing so, we don't have to worry about protecting queue-context structure from multiple threads accessing it simultaneously. Arguments: Return Value: NTSTATUS --*/ { NTSTATUS Status; WDF_TIMER_CONFIG timerConfig; WDF_OBJECT_ATTRIBUTES timerAttributes; // // Create a non-periodic timer since WDF does not allow periodic timer // at passive level, which is the level UMDF callbacks are invoked at. // The workaround is to always restart the timer in the timer callback. // // WDF_TIMER_CONFIG_INIT sets AutomaticSerialization to TRUE by default. // WDF_TIMER_CONFIG_INIT(&timerConfig, EchoEvtTimerFunc); WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); timerAttributes.ParentObject = Queue; // Synchronize with the I/O Queue timerAttributes.ExecutionLevel = WdfExecutionLevelPassive; Status = WdfTimerCreate(&timerConfig, &timerAttributes, Timer // Output handle ); return Status; } VOID EchoEvtIoQueueContextDestroy( WDFOBJECT Object ) /*++ Routine Description: This is called when the Queue that our driver context memory is associated with is destroyed. Arguments: Context - Context that's being freed. Return Value: VOID --*/ { PQUEUE_CONTEXT queueContext = QueueGetContext(Object); // // Release any resources pointed to in the queue context. // // The body of the queue context will be released after // this callback handler returns // // // If Queue context has an I/O buffer, release it // if( queueContext->WriteMemory != NULL ) { WdfObjectDelete(queueContext->WriteMemory); queueContext->WriteMemory = NULL; } return; } VOID EchoEvtRequestCancel( IN WDFREQUEST Request ) /*++ Routine Description: Called when an I/O request is cancelled after the driver has marked the request cancellable. This callback is automatically synchronized with the I/O callbacks since we have chosen to use frameworks Device level locking. Arguments: Request - Request being cancelled. Return Value: VOID --*/ { PQUEUE_CONTEXT queueContext = QueueGetContext(WdfRequestGetIoQueue(Request)); KdPrint(("EchoEvtRequestCancel called on Request 0x%p\n", Request)); // // The following is race free by the callside or DPC side // synchronizing completion by calling // WdfRequestMarkCancelable(Queue, Request, FALSE) before // completion and not calling WdfRequestComplete if the // return status == STATUS_CANCELLED. // WdfRequestCompleteWithInformation(Request, STATUS_CANCELLED, 0L); // // This book keeping is synchronized by the common // Queue presentation lock // ASSERT(queueContext->CurrentRequest == Request); queueContext->CurrentRequest = NULL; return; } VOID EchoEvtIoRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_READ request. It will copy the content from the queue-context buffer to the request buffer. If the driver hasn't received any write request earlier, the read returns zero. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. Length - number of bytes to be read. The default property of the queue is to not dispatch zero lenght read & write requests to the driver and complete is with status success. So we will never get a zero length request. Return Value: VOID --*/ { NTSTATUS Status; PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); WDFMEMORY memory; size_t writeMemoryLength; _Analysis_assume_(Length > 0); KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n", Queue,Request,Length)); // // No data to read // if( (queueContext->WriteMemory == NULL) ) { WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L); return; } // // Read what we have // WdfMemoryGetBuffer(queueContext->WriteMemory, &writeMemoryLength); _Analysis_assume_(writeMemoryLength > 0); if( writeMemoryLength < Length ) { Length = writeMemoryLength; } // // Get the request memory // Status = WdfRequestRetrieveOutputMemory(Request, &memory); if( !NT_SUCCESS(Status) ) { KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n", Status)); WdfVerifierDbgBreakPoint(); WdfRequestCompleteWithInformation(Request, Status, 0L); return; } // Copy the memory out Status = WdfMemoryCopyFromBuffer( memory, // destination 0, // offset into the destination memory WdfMemoryGetBuffer(queueContext->WriteMemory, NULL), Length ); if( !NT_SUCCESS(Status) ) { KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status)); WdfRequestComplete(Request, Status); return; } // Set transfer information WdfRequestSetInformation(Request, (ULONG_PTR)Length); // Mark the request is cancelable WdfRequestMarkCancelable(Request, EchoEvtRequestCancel); // Defer the completion to another thread from the timer dpc queueContext->CurrentRequest = Request; queueContext->CurrentStatus = Status; return; } VOID EchoEvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: This event is invoked when the framework receives IRP_MJ_WRITE request. This routine allocates memory buffer, copies the data from the request to it, and stores the buffer pointer in the queue-context with the length variable representing the buffers length. The actual completion of the request is defered to the periodic timer dpc. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. Length - number of bytes to be read. The default property of the queue is to not dispatch zero lenght read & write requests to the driver and complete is with status success. So we will never get a zero length request. Return Value: VOID --*/ { NTSTATUS Status; WDFMEMORY memory; PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); PVOID writeBuffer = NULL; _Analysis_assume_(Length > 0); KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n", Queue,Request,Length)); if( Length > MAX_WRITE_LENGTH ) { KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n", Length,MAX_WRITE_LENGTH)); WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L); return; } // Get the memory buffer Status = WdfRequestRetrieveInputMemory(Request, &memory); if( !NT_SUCCESS(Status) ) { KdPrint(("EchoEvtIoWrite Could not get request memory buffer 0x%x\n", Status)); WdfVerifierDbgBreakPoint(); WdfRequestComplete(Request, Status); return; } // Release previous buffer if set if( queueContext->WriteMemory != NULL ) { WdfObjectDelete(queueContext->WriteMemory); queueContext->WriteMemory = NULL; } Status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES, NonPagedPoolNx, 'sam1', Length, &queueContext->WriteMemory, &writeBuffer ); if(!NT_SUCCESS(Status)) { KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n", Length)); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } // Copy the memory in Status = WdfMemoryCopyToBuffer( memory, 0, // offset into the source memory writeBuffer, Length ); if( !NT_SUCCESS(Status) ) { KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status)); WdfVerifierDbgBreakPoint(); WdfObjectDelete(queueContext->WriteMemory); queueContext->WriteMemory = NULL; WdfRequestComplete(Request, Status); return; } // Set transfer information WdfRequestSetInformation(Request, (ULONG_PTR)Length); // Specify the request is cancelable WdfRequestMarkCancelable(Request, EchoEvtRequestCancel); // Defer the completion to another thread from the timer dpc queueContext->CurrentRequest = Request; queueContext->CurrentStatus = Status; return; } VOID EchoEvtTimerFunc( IN WDFTIMER Timer ) /*++ Routine Description: This is the TimerDPC the driver sets up to complete requests. This function is registered when the WDFTIMER object is created, and will automatically synchronize with the I/O Queue callbacks and cancel routine. Arguments: Timer - Handle to a framework Timer object. Return Value: VOID --*/ { NTSTATUS Status; WDFREQUEST Request; WDFQUEUE queue; PQUEUE_CONTEXT queueContext ; queue = WdfTimerGetParentObject(Timer); queueContext = QueueGetContext(queue); // // DPC is automatically synchronized to the Queue lock, // so this is race free without explicit driver managed locking. // Request = queueContext->CurrentRequest; if( Request != NULL ) { // // Attempt to remove cancel status from the request. // // The request is not completed if it is already cancelled // since the EchoEvtIoCancel function has run, or is about to run // and we are racing with it. // Status = WdfRequestUnmarkCancelable(Request); if( Status != STATUS_CANCELLED ) { queueContext->CurrentRequest = NULL; Status = queueContext->CurrentStatus; KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status)); WdfRequestComplete(Request, Status); } else { KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n", Request)); } } // // Restart the Timer since WDF does not allow periodic timer // with autosynchronization at passive level // WdfTimerStart(Timer, WDF_REL_TIMEOUT_IN_MS(TIMER_PERIOD)); return; } ================================================ FILE: tests/projects/windows/driver/umdf/echo/driver/queue.h ================================================ /*++ Copyright (c) 1990-2000 Microsoft Corporation Module Name: queue.h Abstract: This is a C version of a very simple sample driver that illustrates how to use the driver framework and demonstrates best practices. --*/ // Set max write length for testing #define MAX_WRITE_LENGTH 1024*40 // Set timer period in ms #define TIMER_PERIOD 1000*2 // // This is the context that can be placed per queue // and would contain per queue information. // typedef struct _QUEUE_CONTEXT { // Here we allocate a buffer from a test write so it can be read back WDFMEMORY WriteMemory; // Timer DPC for this queue WDFTIMER Timer; // Virtual I/O WDFREQUEST CurrentRequest; NTSTATUS CurrentStatus; } QUEUE_CONTEXT, *PQUEUE_CONTEXT; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext) NTSTATUS EchoQueueInitialize( WDFDEVICE hDevice ); EVT_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK EchoEvtIoQueueContextDestroy; // // Events from the IoQueue object // EVT_WDF_REQUEST_CANCEL EchoEvtRequestCancel; EVT_WDF_IO_QUEUE_IO_READ EchoEvtIoRead; EVT_WDF_IO_QUEUE_IO_WRITE EchoEvtIoWrite; NTSTATUS EchoTimerCreate( IN WDFTIMER* pTimer, IN WDFQUEUE Queue ); EVT_WDF_TIMER EchoEvtTimerFunc; ================================================ FILE: tests/projects/windows/driver/umdf/echo/exe/echoapp.cpp ================================================ /*++ Copyright (c) Microsoft Corporation Module Name: EchoApp.cpp Abstract: An application to exercise the WDF "echo" sample driver. Environment: user mode only --*/ #include _Analysis_mode_(_Analysis_code_type_user_code_) #define INITGUID #include #include #include #include #include #include "public.h" #define NUM_ASYNCH_IO 100 #define BUFFER_SIZE (40*1024) #define READER_TYPE 1 #define WRITER_TYPE 2 #define MAX_DEVPATH_LENGTH 256 BOOLEAN G_PerformAsyncIo; BOOLEAN G_LimitedLoops; ULONG G_AsyncIoLoopsNum; WCHAR G_DevicePath[MAX_DEVPATH_LENGTH]; ULONG AsyncIo( PVOID ThreadParameter ); BOOLEAN PerformWriteReadTest( IN HANDLE hDevice, IN ULONG TestLength ); BOOL GetDevicePath( IN LPGUID InterfaceGuid, _Out_writes_(BufLen) PWCHAR DevicePath, _In_ size_t BufLen ); int __cdecl main( _In_ int argc, _In_reads_(argc) char* argv[] ) { HANDLE hDevice = INVALID_HANDLE_VALUE; HANDLE th1 = NULL; BOOLEAN result = TRUE; if (argc > 1) { if(!_strnicmp (argv[1], "-Async", 6) ) { G_PerformAsyncIo = TRUE; if (argc > 2) { G_AsyncIoLoopsNum = atoi(argv[2]); G_LimitedLoops = TRUE; } else { G_LimitedLoops = FALSE; } } else { printf("Usage:\n"); printf(" Echoapp.exe --- Send single write and read request synchronously\n"); printf(" Echoapp.exe -Async --- Send reads and writes asynchronously without terminating\n"); printf(" Echoapp.exe -Async --- Send reads and writes asynchronously\n"); printf("Exit the app anytime by pressing Ctrl-C\n"); result = FALSE; goto exit; } } if ( !GetDevicePath( (LPGUID) &GUID_DEVINTERFACE_ECHO, G_DevicePath, sizeof(G_DevicePath)/sizeof(G_DevicePath[0])) ) { result = FALSE; goto exit; } printf("DevicePath: %ws\n", G_DevicePath); hDevice = CreateFile(G_DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (hDevice == INVALID_HANDLE_VALUE) { printf("Failed to open device. Error %d\n",GetLastError()); result = FALSE; goto exit; } printf("Opened device successfully\n"); if(G_PerformAsyncIo) { printf("Starting AsyncIo\n"); // // Create a reader thread // th1 = CreateThread( NULL, // Default Security Attrib. 0, // Initial Stack Size, (LPTHREAD_START_ROUTINE) AsyncIo, // Thread Func (LPVOID)READER_TYPE, 0, // Creation Flags NULL ); // Don't need the Thread Id. if (th1 == NULL) { printf("Couldn't create reader thread - error %d\n", GetLastError()); result = FALSE; goto exit; } // // Use this thread for peforming write. // result = (BOOLEAN)AsyncIo((PVOID)WRITER_TYPE); }else { // // Write pattern buffers and read them back, then verify them // result = PerformWriteReadTest(hDevice, 512); if(!result) { goto exit; } result = PerformWriteReadTest(hDevice, 30*1024); if(!result) { goto exit; } } exit: if (th1 != NULL) { WaitForSingleObject(th1, INFINITE); CloseHandle(th1); } if (hDevice != INVALID_HANDLE_VALUE) { CloseHandle(hDevice); } return ((result == TRUE) ? 0 : 1); } PUCHAR CreatePatternBuffer( IN ULONG Length ) { unsigned int i; PUCHAR p, pBuf; pBuf = (PUCHAR)malloc(Length); if( pBuf == NULL ) { printf("Could not allocate %d byte buffer\n",Length); return NULL; } p = pBuf; for(i=0; i < Length; i++ ) { *p = (UCHAR)i; p++; } return pBuf; } BOOLEAN VerifyPatternBuffer( _In_reads_bytes_(Length) PUCHAR pBuffer, _In_ ULONG Length ) { unsigned int i; PUCHAR p = pBuffer; for( i=0; i < Length; i++ ) { if( *p != (UCHAR)(i & 0xFF) ) { printf("Pattern changed. SB 0x%x, Is 0x%x\n", (UCHAR)(i & 0xFF), *p); return FALSE; } p++; } return TRUE; } BOOLEAN PerformWriteReadTest( IN HANDLE hDevice, IN ULONG TestLength ) /* */ { ULONG bytesReturned =0; PUCHAR WriteBuffer = NULL, ReadBuffer = NULL; BOOLEAN result = TRUE; WriteBuffer = CreatePatternBuffer(TestLength); if( WriteBuffer == NULL ) { result = FALSE; goto Cleanup; } ReadBuffer = (PUCHAR)malloc(TestLength); if( ReadBuffer == NULL ) { printf("PerformWriteReadTest: Could not allocate %d " "bytes ReadBuffer\n",TestLength); result = FALSE; goto Cleanup; } // // Write the pattern to the device // bytesReturned = 0; if (!WriteFile ( hDevice, WriteBuffer, TestLength, &bytesReturned, NULL)) { printf ("PerformWriteReadTest: WriteFile failed: " "Error %d\n", GetLastError()); result = FALSE; goto Cleanup; } else { if( bytesReturned != TestLength ) { printf("bytes written is not test length! Written %d, " "SB %d\n",bytesReturned, TestLength); result = FALSE; goto Cleanup; } printf ("%d Pattern Bytes Written successfully\n", bytesReturned); } bytesReturned = 0; if ( !ReadFile (hDevice, ReadBuffer, TestLength, &bytesReturned, NULL)) { printf ("PerformWriteReadTest: ReadFile failed: " "Error %d\n", GetLastError()); result = FALSE; goto Cleanup; } else { if( bytesReturned != TestLength ) { printf("bytes Read is not test length! Read %d, " "SB %d\n",bytesReturned, TestLength); // // Note: Is this a Failure Case?? // result = FALSE; goto Cleanup; } printf ("%d Pattern Bytes Read successfully\n",bytesReturned); } // // Now compare // if( !VerifyPatternBuffer(ReadBuffer, TestLength) ) { printf("Verify failed\n"); result = FALSE; goto Cleanup; } printf("Pattern Verified successfully\n"); Cleanup: // // Free WriteBuffer if non NULL. // if (WriteBuffer) { free (WriteBuffer); } // // Free ReadBuffer if non NULL // if (ReadBuffer) { free (ReadBuffer); } return result; } ULONG AsyncIo( PVOID ThreadParameter ) { HANDLE hDevice = INVALID_HANDLE_VALUE; HANDLE hCompletionPort = NULL; OVERLAPPED *pOvList = NULL; PUCHAR buf = NULL; ULONG numberOfBytesTransferred; OVERLAPPED *completedOv; ULONG_PTR i; ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; ULONG_PTR key; ULONG error; BOOLEAN result = TRUE; ULONG maxPendingRequests = NUM_ASYNCH_IO; ULONG remainingRequestsToSend = 0; ULONG remainingRequestsToReceive = 0; hDevice = CreateFile(G_DevicePath, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); if (hDevice == INVALID_HANDLE_VALUE) { printf("Cannot open %ws error %d\n", G_DevicePath, GetLastError()); result = FALSE; goto Error; } hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); if (hCompletionPort == NULL) { printf("Cannot open completion port %d \n",GetLastError()); result = FALSE; goto Error; } // // We will only have NUM_ASYNCH_IO or G_AsyncIoLoopsNum pending at any // time (whichever is less) // if (G_LimitedLoops == TRUE) { remainingRequestsToReceive = G_AsyncIoLoopsNum; if (G_AsyncIoLoopsNum > NUM_ASYNCH_IO) { // // After we send the initial NUM_ASYNCH_IO, we will have additional // (G_AsyncIoLoopsNum - NUM_ASYNCH_IO) I/Os to send // maxPendingRequests = NUM_ASYNCH_IO; remainingRequestsToSend = G_AsyncIoLoopsNum - NUM_ASYNCH_IO; } else { maxPendingRequests = G_AsyncIoLoopsNum; remainingRequestsToSend = 0; } } pOvList = (OVERLAPPED *)malloc(maxPendingRequests * sizeof(OVERLAPPED)); if (pOvList == NULL) { printf("Cannot allocate overlapped array \n"); result = FALSE; goto Error; } buf = (PUCHAR)malloc(maxPendingRequests * BUFFER_SIZE); if (buf == NULL) { printf("Cannot allocate buffer \n"); result = FALSE; goto Error; } ZeroMemory(pOvList, maxPendingRequests * sizeof(OVERLAPPED)); ZeroMemory(buf, maxPendingRequests * BUFFER_SIZE); // // Issue asynch I/O // for (i = 0; i < maxPendingRequests; i++) { if (ioType == READER_TYPE) { if ( ReadFile( hDevice, buf + (i* BUFFER_SIZE), BUFFER_SIZE, NULL, &pOvList[i]) == 0) { error = GetLastError(); if (error != ERROR_IO_PENDING) { printf(" %dth Read failed %d \n", (ULONG) i, GetLastError()); result = FALSE; goto Error; } } } else { if ( WriteFile( hDevice, buf + (i* BUFFER_SIZE), BUFFER_SIZE, NULL, &pOvList[i]) == 0) { error = GetLastError(); if (error != ERROR_IO_PENDING) { printf(" %dth Write failed %d \n", (ULONG) i, GetLastError()); result = FALSE; goto Error; } } } } // // Wait for the I/Os to complete. If one completes then reissue the I/O // WHILE (1) { if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, &key, &completedOv, INFINITE) == 0) { printf("GetQueuedCompletionStatus failed %d\n", GetLastError()); result = FALSE; goto Error; } // // Read successfully completed. If we're doing unlimited I/Os then Issue another one. // if (ioType == READER_TYPE) { i = completedOv - pOvList; printf("Number of bytes read by request number %Id is %d\n", i, numberOfBytesTransferred); // // If we're done with the I/Os, then exit // if (G_LimitedLoops == TRUE) { if ((--remainingRequestsToReceive) == 0) { break; } if (remainingRequestsToSend == 0) { continue; } else { remainingRequestsToSend--; } } if ( ReadFile( hDevice, buf + (i * BUFFER_SIZE), BUFFER_SIZE, NULL, completedOv) == 0) { error = GetLastError(); if (error != ERROR_IO_PENDING) { printf("%Idth Read failed %d \n", i, GetLastError()); result = FALSE; goto Error; } } } else { i = completedOv - pOvList; printf("Number of bytes written by request number %Id is %d\n", i, numberOfBytesTransferred); // // If we're done with the I/Os, then exit // if (G_LimitedLoops == TRUE) { if ((--remainingRequestsToReceive) == 0) { break; } if (remainingRequestsToSend == 0) { continue; } else { remainingRequestsToSend--; } } if ( WriteFile( hDevice, buf + (i * BUFFER_SIZE), BUFFER_SIZE, NULL, completedOv) == 0) { error = GetLastError(); if (error != ERROR_IO_PENDING) { printf("%Idth write failed %d \n", i, GetLastError()); result = FALSE; goto Error; } } } } Error: if(hDevice != INVALID_HANDLE_VALUE) { CloseHandle(hDevice); } if(hCompletionPort) { CloseHandle(hCompletionPort); } if(buf) { free(buf); } if(pOvList) { free(pOvList); } return (ULONG)result; } BOOL GetDevicePath( _In_ LPGUID InterfaceGuid, _Out_writes_(BufLen) PWCHAR DevicePath, _In_ size_t BufLen ) { CONFIGRET cr = CR_SUCCESS; PWSTR deviceInterfaceList = NULL; ULONG deviceInterfaceListLength = 0; PWSTR nextInterface; HRESULT hr = E_FAIL; BOOL bRet = TRUE; cr = CM_Get_Device_Interface_List_Size( &deviceInterfaceListLength, InterfaceGuid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); if (cr != CR_SUCCESS) { printf("Error 0x%x retrieving device interface list size.\n", cr); goto clean0; } if (deviceInterfaceListLength <= 1) { bRet = FALSE; printf("Error: No active device interfaces found.\n" " Is the sample driver loaded?"); goto clean0; } deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); if (deviceInterfaceList == NULL) { printf("Error allocating memory for device interface list.\n"); goto clean0; } ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); cr = CM_Get_Device_Interface_List( InterfaceGuid, NULL, deviceInterfaceList, deviceInterfaceListLength, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); if (cr != CR_SUCCESS) { printf("Error 0x%x retrieving device interface list.\n", cr); goto clean0; } nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1; if (*nextInterface != UNICODE_NULL) { printf("Warning: More than one device interface instance found. \n" "Selecting first matching device.\n\n"); } hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); if (FAILED(hr)) { bRet = FALSE; printf("Error: StringCchCopy failed with HRESULT 0x%x", hr); goto clean0; } clean0: if (deviceInterfaceList != NULL) { free(deviceInterfaceList); } if (CR_SUCCESS != cr) { bRet = FALSE; } return bRet; } ================================================ FILE: tests/projects/windows/driver/umdf/echo/exe/public.h ================================================ /*++ Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved Module Name: public.h Abstract: This module contains the common declarations shared by driver and user applications. Environment: user and kernel --*/ #define WHILE(a) \ __pragma(warning(suppress:4127)) while(a) // // Define an Interface Guid so that app can find the device and talk to it. // DEFINE_GUID (GUID_DEVINTERFACE_ECHO, 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a); // {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A} ================================================ FILE: tests/projects/windows/driver/umdf/echo/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_defines("_UNICODE", "UNICODE") target("echo") add_rules("wdk.env.umdf", "wdk.driver") -- set test sign -- set_values("wdk.sign.mode", "test") -- set release sign -- set_values("wdk.sign.mode", "release") -- set_values("wdk.sign.certfile", path.join(os.projectdir(), "xxx.cer")) add_files("driver/*.c") add_files("driver/*.inx") add_includedirs("exe") target("app") add_rules("wdk.env.umdf", "wdk.binary") add_files("exe/*.cpp") ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/Skeleton.rc ================================================ //--------------------------------------------------------------------------- // Skeleton.rc // // Copyright (c) Microsoft Corporation, All Rights Reserved //--------------------------------------------------------------------------- #include #include // // TODO: Change the file description and file names to match your binary. // #define VER_FILETYPE VFT_DLL #define VER_FILESUBTYPE VFT_UNKNOWN #define VER_FILEDESCRIPTION_STR "WDF:UMDF Skeleton User-Mode Driver Sample" #define VER_INTERNALNAME_STR "UMDFSkeleton" #define VER_ORIGINALFILENAME_STR "UMDFSkeleton.dll" #include "common.ver" ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/comsup.cpp ================================================ /*++ Copyright (C) Microsoft Corporation, All Rights Reserved Module Name: ComSup.cpp Abstract: This module contains implementations for the functions and methods used for providing COM support. Environment: Windows User-Mode Driver Framework (WUDF) --*/ #include "internal.h" #include "comsup.tmh" // // Implementation of CUnknown methods. // CUnknown::CUnknown( VOID ) : m_ReferenceCount(1) /*++ Routine Description: Constructor for an instance of the CUnknown class. This simply initializes the reference count of the object to 1. The caller is expected to call Release() if it wants to delete the object once it has been allocated. Arguments: None Return Value: None --*/ { // do nothing. } HRESULT STDMETHODCALLTYPE CUnknown::QueryInterface( _In_ REFIID InterfaceId, _Out_ PVOID *Object ) /*++ Routine Description: This method provides the basic support for query interface on CUnknown. If the interface requested is IUnknown it references the object and returns an interface pointer. Otherwise it returns an error. Arguments: InterfaceId - the IID being requested Object - a location to store the interface pointer to return. Return Value: S_OK or E_NOINTERFACE --*/ { if (IsEqualIID(InterfaceId, __uuidof(IUnknown))) { *Object = QueryIUnknown(); return S_OK; } else { *Object = NULL; return E_NOINTERFACE; } } IUnknown * CUnknown::QueryIUnknown( VOID ) /*++ Routine Description: This helper method references the object and returns a pointer to the object's IUnknown interface. This allows other methods to convert a CUnknown pointer into an IUnknown pointer without a typecast and without calling QueryInterface and dealing with the return value. Arguments: None Return Value: A pointer to the object's IUnknown interface. --*/ { AddRef(); return static_cast(this); } ULONG STDMETHODCALLTYPE CUnknown::AddRef( VOID ) /*++ Routine Description: This method adds one to the object's reference count. Arguments: None Return Value: The new reference count. The caller should only use this for debugging as the object's actual reference count can change while the caller examines the return value. --*/ { return InterlockedIncrement(&m_ReferenceCount); } ULONG STDMETHODCALLTYPE CUnknown::Release( VOID ) /*++ Routine Description: This method subtracts one to the object's reference count. If the count goes to zero, this method deletes the object. Arguments: None Return Value: The new reference count. If the caller uses this value it should only be to check for zero (i.e. this call caused or will cause deletion) or non-zero (i.e. some other call may have caused deletion, but this one didn't). --*/ { ULONG count = InterlockedDecrement(&m_ReferenceCount); if (count == 0) { delete this; } return count; } // // Implementation of CClassFactory methods. // // // Define storage for the factory's static lock count variable. // LONG CClassFactory::s_LockCount = 0; IClassFactory * CClassFactory::QueryIClassFactory( VOID ) /*++ Routine Description: This helper method references the object and returns a pointer to the object's IClassFactory interface. This allows other methods to convert a CClassFactory pointer into an IClassFactory pointer without a typecast and without dealing with the return value QueryInterface. Arguments: None Return Value: A referenced pointer to the object's IClassFactory interface. --*/ { AddRef(); return static_cast(this); } HRESULT CClassFactory::QueryInterface( _In_ REFIID InterfaceId, _Out_ PVOID *Object ) /*++ Routine Description: This method attempts to retrieve the requested interface from the object. If the interface is found then the reference count on that interface (and thus the object itself) is incremented. Arguments: InterfaceId - the interface the caller is requesting. Object - a location to store the interface pointer. Return Value: S_OK or E_NOINTERFACE --*/ { // // This class only supports IClassFactory so check for that. // if (IsEqualIID(InterfaceId, __uuidof(IClassFactory))) { *Object = QueryIClassFactory(); return S_OK; } else { // // See if the base class supports the interface. // return CUnknown::QueryInterface(InterfaceId, Object); } } HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance( _In_opt_ IUnknown * /* OuterObject */, _In_ REFIID InterfaceId, _Out_ PVOID *Object ) /*++ Routine Description: This COM method is the factory routine - it creates instances of the driver callback class and returns the specified interface on them. Arguments: OuterObject - only used for aggregation, which our driver callback class does not support. InterfaceId - the interface ID the caller would like to get from our new object. Object - a location to store the referenced interface pointer to the new object. Return Value: Status. --*/ { HRESULT hr; PCMyDriver driver; *Object = NULL; hr = CMyDriver::CreateInstance(&driver); if (SUCCEEDED(hr)) { hr = driver->QueryInterface(InterfaceId, Object); driver->Release(); } return hr; } HRESULT STDMETHODCALLTYPE CClassFactory::LockServer( _In_ BOOL Lock ) /*++ Routine Description: This COM method can be used to keep the DLL in memory. However since the driver's DllCanUnloadNow function always returns false, this has little effect. Still it tracks the number of lock and unlock operations. Arguments: Lock - Whether the caller wants to lock or unlock the "server" Return Value: S_OK --*/ { if (Lock) { InterlockedIncrement(&s_LockCount); } else { InterlockedDecrement(&s_LockCount); } return S_OK; } ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/comsup.h ================================================ /*++ Copyright (C) Microsoft Corporation, All Rights Reserved Module Name: ComSup.h Abstract: This module contains classes and functions use for providing COM support code. Environment: Windows User-Mode Driver Framework (WUDF) --*/ #pragma once // // Forward type declarations. They are here rather than in internal.h as // you only need them if you choose to use these support classes. // typedef class CUnknown *PCUnknown; typedef class CClassFactory *PCClassFactory; // // Base class to implement IUnknown. You can choose to derive your COM // classes from this class, or simply implement IUnknown in each of your // classes. // class CUnknown : public IUnknown { // // Private data members and methods. These are only accessible by the methods // of this class. // private: // // The reference count for this object. Initialized to 1 in the // constructor. // LONG m_ReferenceCount; // // Protected data members and methods. These are accessible by the subclasses // but not by other classes. // protected: // // The constructor and destructor are protected to ensure that only the // subclasses of CUnknown can create and destroy instances. // CUnknown( VOID ); // // The destructor MUST be virtual. Since any instance of a CUnknown // derived class should only be deleted from within CUnknown::Release, // the destructor MUST be virtual or only CUnknown::~CUnknown will get // invoked on deletion. // // If you see that your CMyDevice specific destructor is never being // called, make sure you haven't deleted the virtual destructor here. // virtual ~CUnknown( VOID ) { // Do nothing } // // Public Methods. These are accessible by any class. // public: IUnknown * QueryIUnknown( VOID ); // // COM Methods. // public: // // IUnknown methods // virtual ULONG STDMETHODCALLTYPE AddRef( VOID ); virtual ULONG STDMETHODCALLTYPE Release( VOID ); virtual HRESULT STDMETHODCALLTYPE QueryInterface( _In_ REFIID InterfaceId, _Out_ PVOID *Object ); }; // // Class factory support class. Create an instance of this from your // DllGetClassObject method and modify the implementation to create // an instance of your driver event handler class. // class CClassFactory : public CUnknown, public IClassFactory { // // Private data members and methods. These are only accessible by the methods // of this class. // private: // // The lock count. This is shared across all instances of IClassFactory // and can be queried through the public IsLocked method. // static LONG s_LockCount; // // Public Methods. These are accessible by any class. // public: IClassFactory * QueryIClassFactory( VOID ); // // COM Methods. // public: // // IUnknown methods // virtual ULONG STDMETHODCALLTYPE AddRef( VOID ) { return __super::AddRef(); } _At_(this, __drv_freesMem(object)) virtual ULONG STDMETHODCALLTYPE Release( VOID ) { return __super::Release(); } virtual HRESULT STDMETHODCALLTYPE QueryInterface( _In_ REFIID InterfaceId, _Out_ PVOID *Object ); // // IClassFactory methods. // virtual HRESULT STDMETHODCALLTYPE CreateInstance( _In_opt_ IUnknown *OuterObject, _In_ REFIID InterfaceId, _Out_ PVOID *Object ); virtual HRESULT STDMETHODCALLTYPE LockServer( _In_ BOOL Lock ); }; ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/device.cpp ================================================ /*++ Copyright (C) Microsoft Corporation, All Rights Reserved. Module Name: Device.cpp Abstract: This module contains the implementation of the UMDF Skeleton sample driver's device callback object. The skeleton sample device does very little. It does not implement either of the PNP interfaces so once the device is setup, it won't ever get any callbacks until the device is removed. Environment: Windows User-Mode Driver Framework (WUDF) --*/ #include "internal.h" #include "device.tmh" HRESULT CMyDevice::CreateInstance( _In_ IWDFDriver *FxDriver, _In_ IWDFDeviceInitialize * FxDeviceInit, _Out_ PCMyDevice *Device ) /*++ Routine Description: This method creates and initializs an instance of the skeleton driver's device callback object. Arguments: FxDeviceInit - the settings for the device. Device - a location to store the referenced pointer to the device object. Return Value: Status --*/ { PCMyDevice device; HRESULT hr; // // Allocate a new instance of the device class. // device = new CMyDevice(); if (NULL == device) { return E_OUTOFMEMORY; } // // Initialize the instance. // hr = device->Initialize(FxDriver, FxDeviceInit); if (SUCCEEDED(hr)) { *Device = device; } else { device->Release(); } return hr; } HRESULT CMyDevice::Initialize( _In_ IWDFDriver * FxDriver, _In_ IWDFDeviceInitialize * FxDeviceInit ) /*++ Routine Description: This method initializes the device callback object and creates the partner device object. The method should perform any device-specific configuration that: * could fail (these can't be done in the constructor) * must be done before the partner object is created -or- * can be done after the partner object is created and which aren't influenced by any device-level parameters the parent (the driver in this case) might set. Arguments: FxDeviceInit - the settings for this device. Return Value: status. --*/ { IWDFDevice *fxDevice; HRESULT hr; // // Configure things like the locking model before we go to create our // partner device. // // // Set no locking unless you need an automatic callbacks synchronization // FxDeviceInit->SetLockingConstraint(None); // // TODO: If you're writing a filter driver then indicate that here. // // FxDeviceInit->SetFilter(); // // // TODO: Any per-device initialization which must be done before // creating the partner object. // // // Create a new FX device object and assign the new callback object to // handle any device level events that occur. // // // QueryIUnknown references the IUnknown interface that it returns // (which is the same as referencing the device). We pass that to // CreateDevice, which takes its own reference if everything works. // { IUnknown *unknown = this->QueryIUnknown(); hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice); unknown->Release(); } // // If that succeeded then set our FxDevice member variable. // if (SUCCEEDED(hr)) { m_FxDevice = fxDevice; // // Drop the reference we got from CreateDevice. Since this object // is partnered with the framework object they have the same // lifespan - there is no need for an additional reference. // fxDevice->Release(); } return hr; } HRESULT CMyDevice::Configure( VOID ) /*++ Routine Description: This method is called after the device callback object has been initialized and returned to the driver. It would setup the device's queues and their corresponding callback objects. Arguments: FxDevice - the framework device object for which we're handling events. Return Value: status --*/ { // // TODO: Setup your device queues and I/O forwarding. // return S_OK; } HRESULT CMyDevice::QueryInterface( _In_ REFIID InterfaceId, _Out_ PVOID *Object ) /*++ Routine Description: This method is called to get a pointer to one of the object's callback interfaces. Since the skeleton driver doesn't support any of the device events, this method simply calls the base class's BaseQueryInterface. If the skeleton is extended to include device event interfaces then this method must be changed to check the IID and return pointers to them as appropriate. Arguments: InterfaceId - the interface being requested Object - a location to store the interface pointer if successful Return Value: S_OK or E_NOINTERFACE --*/ { return CUnknown::QueryInterface(InterfaceId, Object); } ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/device.h ================================================ /*++ Copyright (C) Microsoft Corporation, All Rights Reserved Module Name: Device.h Abstract: This module contains the type definitions for the UMDF Skeleton sample driver's device callback class. Environment: Windows User-Mode Driver Framework (WUDF) --*/ #pragma once // // Class for the iotrace driver. // class CMyDevice : public CUnknown { // // Private data members. // private: IWDFDevice *m_FxDevice; // // Private methods. // private: CMyDevice( VOID ) { m_FxDevice = NULL; } HRESULT Initialize( _In_ IWDFDriver *FxDriver, _In_ IWDFDeviceInitialize *FxDeviceInit ); // // Public methods // public: // // The factory method used to create an instance of this driver. // static HRESULT CreateInstance( _In_ IWDFDriver *FxDriver, _In_ IWDFDeviceInitialize *FxDeviceInit, _Out_ PCMyDevice *Device ); HRESULT Configure( VOID ); // // COM methods // public: // // IUnknown methods. // virtual ULONG STDMETHODCALLTYPE AddRef( VOID ) { return __super::AddRef(); } _At_(this, __drv_freesMem(object)) virtual ULONG STDMETHODCALLTYPE Release( VOID ) { return __super::Release(); } virtual HRESULT STDMETHODCALLTYPE QueryInterface( _In_ REFIID InterfaceId, _Out_ PVOID *Object ); }; ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/dllsup.cpp ================================================ /*++ Copyright (C) Microsoft Corporation, All Rights Reserved. Module Name: dllsup.cpp Abstract: This module contains the implementation of the UMDF Skeleton Sample Driver's entry point and its exported functions for providing COM support. This module can be copied without modification to a new UMDF driver. It depends on some of the code in comsup.cpp & comsup.h to handle DLL registration and creating the first class factory. This module is dependent on the following defines: MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing tracing. For example the skeleton uses L"Microsoft\\UMDF\\Skeleton" MYDRIVER_CLASS_ID - A GUID encoded in struct format used to initialize the driver's ClassID. These are defined in internal.h for the sample. If you choose to use a different primary include file, you should ensure they are defined there as well. Environment: WDF User-Mode Driver Framework (WDF:UMDF) --*/ #include "internal.h" #include "dllsup.tmh" const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; BOOL WINAPI DllMain( HINSTANCE ModuleHandle, DWORD Reason, PVOID /* Reserved */ ) /*++ Routine Description: This is the entry point and exit point for the I/O trace driver. This does very little as the I/O trace driver has minimal global data. This method initializes tracing. Arguments: ModuleHandle - the DLL handle for this module. Reason - the reason this entry point was called. Reserved - unused Return Value: TRUE --*/ { UNREFERENCED_PARAMETER( ModuleHandle ); if (DLL_PROCESS_ATTACH == Reason) { // // Initialize tracing. // WPP_INIT_TRACING(MYDRIVER_TRACING_ID); } else if (DLL_PROCESS_DETACH == Reason) { // // Cleanup tracing. // WPP_CLEANUP(); } return TRUE; } HRESULT STDAPICALLTYPE DllGetClassObject( _In_ REFCLSID ClassId, _In_ REFIID InterfaceId, _Outptr_ LPVOID *Interface ) /*++ Routine Description: This routine is called by COM in order to instantiate the driver callback object and do an initial query interface on it. This method only creates an instance of the driver's class factory, as this is the minimum required to support UMDF. Arguments: ClassId - the CLSID of the object being "gotten" InterfaceId - the interface the caller wants from that object. Interface - a location to store the referenced interface pointer Return Value: S_OK if the function succeeds or error indicating the cause of the failure. --*/ { PCClassFactory factory; HRESULT hr = S_OK; *Interface = NULL; // // If the CLSID doesn't match that of our "coclass" (defined in the IDL // file) then we can't create the object the caller wants. This may // indicate that the COM registration is incorrect, and another CLSID // is referencing this drvier. // if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false) { Trace( TRACE_LEVEL_ERROR, L"ERROR: Called to create instance of unrecognized class (%!GUID!)", &ClassId ); return CLASS_E_CLASSNOTAVAILABLE; } // // Create an instance of the class factory for the caller. // factory = new CClassFactory(); if (NULL == factory) { hr = E_OUTOFMEMORY; } // // Query the object we created for the interface the caller wants. After // that we release the object. This will drive the reference count to // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed). // In the later case the object is automatically deleted. // if (SUCCEEDED(hr)) { hr = factory->QueryInterface(InterfaceId, Interface); factory->Release(); } return hr; } ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/driver.cpp ================================================ /*++ Copyright (C) Microsoft Corporation, All Rights Reserved. Module Name: Driver.cpp Abstract: This module contains the implementation of the UMDF Skeleton Sample's core driver callback object. Environment: Windows User-Mode Driver Framework (WUDF) --*/ #include "internal.h" #include "driver.tmh" HRESULT CMyDriver::CreateInstance( _Out_ PCMyDriver *Driver ) /*++ Routine Description: This static method is invoked in order to create and initialize a new instance of the driver class. The caller should arrange for the object to be released when it is no longer in use. Arguments: Driver - a location to store a referenced pointer to the new instance Return Value: S_OK if successful, or error otherwise. --*/ { PCMyDriver driver; HRESULT hr; // // Allocate the callback object. // driver = new CMyDriver(); if (NULL == driver) { return E_OUTOFMEMORY; } // // Initialize the callback object. // hr = driver->Initialize(); if (SUCCEEDED(hr)) { // // Store a pointer to the new, initialized object in the output // parameter. // *Driver = driver; } else { // // Release the reference on the driver object to get it to delete // itself. // driver->Release(); } return hr; } HRESULT CMyDriver::Initialize( VOID ) /*++ Routine Description: This method is called to initialize a newly created driver callback object before it is returned to the creator. Unlike the constructor, the Initialize method contains operations which could potentially fail. Arguments: None Return Value: None --*/ { return S_OK; } HRESULT CMyDriver::QueryInterface( _In_ REFIID InterfaceId, _Out_ PVOID *Interface ) /*++ Routine Description: This method returns a pointer to the requested interface on the callback object.. Arguments: InterfaceId - the IID of the interface to query/reference Interface - a location to store the interface pointer. Return Value: S_OK if the interface is supported. E_NOINTERFACE if it is not supported. --*/ { if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry))) { *Interface = QueryIDriverEntry(); return S_OK; } else { return CUnknown::QueryInterface(InterfaceId, Interface); } } HRESULT CMyDriver::OnDeviceAdd( _In_ IWDFDriver *FxWdfDriver, _In_ IWDFDeviceInitialize *FxDeviceInit ) /*++ Routine Description: The FX invokes this method when it wants to install our driver on a device stack. This method creates a device callback object, then calls the Fx to create an Fx device object and associate the new callback object with it. Arguments: FxWdfDriver - the Fx driver object. FxDeviceInit - the initialization information for the device. Return Value: status --*/ { HRESULT hr; PCMyDevice device = NULL; // // TODO: Do any per-device initialization (reading settings from the // registry for example) that's necessary before creating your // device callback object here. Otherwise you can leave such // initialization to the initialization of the device event // handler. // // // Create a new instance of our device callback object // hr = CMyDevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device); // // TODO: Change any per-device settings that the object exposes before // calling Configure to let it complete its initialization. // // // If that succeeded then call the device's construct method. This // allows the device to create any queues or other structures that it // needs now that the corresponding fx device object has been created. // if (SUCCEEDED(hr)) { hr = device->Configure(); } // // Release the reference on the device callback object now that it's been // associated with an fx device object. // if (NULL != device) { device->Release(); } return hr; } ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/driver.h ================================================ /*++ Copyright (C) Microsoft Corporation, All Rights Reserved Module Name: Driver.h Abstract: This module contains the type definitions for the UMDF Skeleton sample's driver callback class. Environment: Windows User-Mode Driver Framework (WUDF) --*/ #pragma once // // This class handles driver events for the skeleton sample. In particular // it supports the OnDeviceAdd event, which occurs when the driver is called // to setup per-device handlers for a new device stack. // class CMyDriver : public CUnknown, public IDriverEntry { // // Private data members. // private: // // Private methods. // private: // // Returns a refernced pointer to the IDriverEntry interface. // IDriverEntry * QueryIDriverEntry( VOID ) { AddRef(); return static_cast(this); } HRESULT Initialize( VOID ); // // Public methods // public: // // The factory method used to create an instance of this driver. // static HRESULT CreateInstance( _Out_ PCMyDriver *Driver ); // // COM methods // public: // // IDriverEntry methods // virtual HRESULT STDMETHODCALLTYPE OnInitialize( _In_ IWDFDriver *FxWdfDriver ) { UNREFERENCED_PARAMETER( FxWdfDriver ); return S_OK; } virtual HRESULT STDMETHODCALLTYPE OnDeviceAdd( _In_ IWDFDriver *FxWdfDriver, _In_ IWDFDeviceInitialize *FxDeviceInit ); virtual VOID STDMETHODCALLTYPE OnDeinitialize( _In_ IWDFDriver *FxWdfDriver ) { UNREFERENCED_PARAMETER( FxWdfDriver ); return; } // // IUnknown methods. // // We have to implement basic ones here that redirect to the // base class becuase of the multiple inheritance. // virtual ULONG STDMETHODCALLTYPE AddRef( VOID ) { return __super::AddRef(); } _At_(this, __drv_freesMem(object)) virtual ULONG STDMETHODCALLTYPE Release( VOID ) { return __super::Release(); } virtual HRESULT STDMETHODCALLTYPE QueryInterface( _In_ REFIID InterfaceId, _Out_ PVOID *Object ); }; ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/exports.def ================================================ ; Skeleton.def : Declares the module parameters. ; ; TODO: Change the library name here to match your binary name. ; LIBRARY "UMDFSkeleton.DLL" EXPORTS DllGetClassObject PRIVATE ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/internal.h ================================================ /*++ Copyright (C) Microsoft Corporation, All Rights Reserved Module Name: Internal.h Abstract: This module contains the local type definitions for the UMDF Skeleton driver sample. Environment: Windows User-Mode Driver Framework (WUDF) --*/ #pragma once #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif // // Include the WUDF DDI // #include "wudfddi.h" // // Use specstrings for in/out annotation of function parameters. // #include "specstrings.h" // // Forward definitions of classes in the other header files. // typedef class CMyDriver *PCMyDriver; typedef class CMyDevice *PCMyDevice; // // Define the tracing flags. // // TODO: Choose a different trace control GUID // #define WPP_CONTROL_GUIDS \ WPP_DEFINE_CONTROL_GUID( \ MyDriverTraceControl, (e7541cdd,30e8,4b50,aeb0,51927330ae64), \ \ WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ ) #define WPP_FLAG_LEVEL_LOGGER(flag, level) \ WPP_LEVEL_LOGGER(flag) #define WPP_FLAG_LEVEL_ENABLED(flag, level) \ (WPP_LEVEL_ENABLED(flag) && \ WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) // // This comment block is scanned by the trace preprocessor to define our // Trace function. // // begin_wpp config // FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); // end_wpp // // // Driver specific #defines // // TODO: Change these values to be appropriate for your driver. // #define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\Skeleton" #define MYDRIVER_CLASS_ID { 0xd4112073, 0xd09b, 0x458f, { 0xa5, 0xaa, 0x35, 0xef, 0x21, 0xee, 0xf5, 0xde } } // // Include the type specific headers. // #include "comsup.h" #include "driver.h" #include "device.h" ================================================ FILE: tests/projects/windows/driver/umdf/skeleton/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_defines("_UNICODE", "UNICODE") target("UMDFSkeleton") add_rules("wdk.env.umdf", "wdk.driver") add_values("wdk.tracewpp.flags", "-scan:internal.h") add_files("*.cpp", {rules = "wdk.tracewpp"}) add_files("*.rc", "*.inx") set_values("wdk.umdf.sdkver", "1.9") add_files("exports.def") on_config(function(target) if target:has_tool("sh", "clang", "clangxx") then target:add("shflags", "-Wl,/ENTRY:_DllMainCRTStartup" .. (is_arch("x86") and "@12" or ""), {force = true}) else target:add("shflags", "/ENTRY:_DllMainCRTStartup" .. (is_arch("x86") and "@12" or ""), {force = true}) end end) ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/dsmmain.c ================================================ /*++ Copyright (C) 2004-2010 Microsoft Corporation Module Name: dsmmain.c Abstract: This driver is the Microsoft Device Specific Module (DSM). It exports behaviours that mpio.sys will use to determine how to multipath SPC-3 conforming devices. This file contains routines that are internal to MSDSM. Environment: kernel mode only Notes: --*/ #include "precomp.h" #ifdef DEBUG_USE_WPP #include "dsmmain.tmh" #endif #pragma warning (disable:4305) extern BOOLEAN DoAssert; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, DsmpRegisterPersistentReservationKeys) #endif VOID DsmpFreeDSMResources( _In_ IN PDSM_CONTEXT DsmContext ) /*++ Routine Description: This routine will free the resources allocated by the DSM. This routine should be called when the DSM is being unloaded. Arguements: DsmContext - DSM context given to MPIO during initialization Return Value: None --*/ { PDSM_WMILIB_CONTEXT wmiInfo; PVOID tempAddress = (PVOID)DsmContext; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DsmpFreeDSMResources (DsmCtxt %p): Entering function.\n", DsmContext)); // // First free the buffer allocated for storing the registry path. // wmiInfo = &gDsmInitData.DsmWmiInfo; if (wmiInfo->RegistryPath.Buffer) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DsmpFreeDSMResources (DsmCtxt %p): Freeing wmiInfo's registry buffer.\n", DsmContext)); DsmpFreePool(wmiInfo->RegistryPath.Buffer); } if (DsmContext) { PLIST_ENTRY entry; PDSM_DEVICE_INFO deviceInfo; PDSM_GROUP_ENTRY groupEntry; PDSM_FAILOVER_GROUP failGroup; PDSM_CONTROLLER_LIST_ENTRY controllerEntry; ExDeleteNPagedLookasideList(&(DsmContext->CompletionContextList)); // // Free up the devices (DeviceInfo) list. // while (!IsListEmpty(&DsmContext->DeviceList)) { entry = DsmContext->DeviceList.Flink; NT_ASSERT(entry); deviceInfo = CONTAINING_RECORD(entry, DSM_DEVICE_INFO, ListEntry); if (deviceInfo) { DsmpRemoveDeviceFailGroup(DsmContext, deviceInfo->FailGroup, deviceInfo, TRUE); DsmpRemoveDeviceEntry(DsmContext, deviceInfo->Group, deviceInfo); } } NT_ASSERT(!DsmContext->NumberDevices && !DsmContext->NumberFOGroups && !DsmContext->NumberGroups); // // By now, there should be no group entries left but play it safe and // free up the GROUP list. // while (!IsListEmpty(&DsmContext->GroupList)) { entry = DsmContext->GroupList.Flink; NT_ASSERT(entry); groupEntry = CONTAINING_RECORD(entry, DSM_GROUP_ENTRY, ListEntry); if (groupEntry) { DsmpRemoveGroupEntry(DsmContext, groupEntry, TRUE); DsmpFreePool(groupEntry); } } // // By now there should be no FOG entries left but we play it safe and // free up the FOG list. // while (!IsListEmpty(&DsmContext->FailGroupList)) { entry = RemoveHeadList(&DsmContext->FailGroupList); if (entry) { failGroup = CONTAINING_RECORD(entry, DSM_FAILOVER_GROUP, ListEntry); if (failGroup) { PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry = NULL; PLIST_ENTRY deviceEntry = NULL; while (!IsListEmpty(&failGroup->FOG_DeviceList)) { deviceEntry = RemoveHeadList(&failGroup->FOG_DeviceList); if (deviceEntry) { fogDeviceListEntry = CONTAINING_RECORD(deviceEntry, DSM_FOG_DEVICELIST_ENTRY, ListEntry); if (!fogDeviceListEntry) { continue; } (fogDeviceListEntry->DeviceInfo)->FailGroup = NULL; DsmpFreePool(fogDeviceListEntry); InterlockedDecrement((LONG volatile*)&failGroup->Count); } } DsmpFreeZombieGroupList(failGroup); DsmpFreePool(failGroup); InterlockedDecrement((LONG volatile*)&DsmContext->NumberFOGroups); } } } // // Free up the controller list. // while (!IsListEmpty(&DsmContext->ControllerList)) { entry = RemoveHeadList(&DsmContext->ControllerList); if (entry) { controllerEntry = CONTAINING_RECORD(entry, DSM_CONTROLLER_LIST_ENTRY, ListEntry); if (controllerEntry) { DsmpFreeControllerEntry(DsmContext, controllerEntry); InterlockedDecrement((LONG volatile*)&DsmContext->NumberControllers); } } } NT_ASSERT(!DsmContext->NumberControllers); // // Free up the stale FOG list. // while (!IsListEmpty(&DsmContext->StaleFailGroupList)) { entry = RemoveHeadList(&DsmContext->StaleFailGroupList); if (entry) { failGroup = CONTAINING_RECORD(entry, DSM_FAILOVER_GROUP, ListEntry); if (failGroup) { InterlockedDecrement((LONG volatile*)&DsmContext->NumberStaleFOGroups); NT_ASSERT(IsListEmpty(&failGroup->FOG_DeviceList)); DsmpFreeZombieGroupList(failGroup); DsmpFreePool(failGroup); } } } // // Free up the supported devices list buffer. // DsmpFreePool(DsmContext->SupportedDevices.Buffer); // // It's the responsibility of the mpio bus driver to have already // destroyed all devices and paths. As those functions free allocations // for the objects, the only thing needed here is to free the DsmContext. // TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DsmpFreeDSMResources (DsmCtxt %p): Freeing the DsmContext.\n", DsmContext)); DsmpFreePool(DsmContext); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DsmpFreeDSMResources (DsmCtxt %p): Exiting function.\n", tempAddress)); return; } PDSM_GROUP_ENTRY DsmpFindDevice( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN BOOLEAN AcquireDSMLockExclusive ) /*++ Routine Description: This routine searches for a serial number match between DeviceInfo and the rest of the devices currently being driven by this DSM. Arguments: DsmContext - DSM context given to MPIO during initialization DeviceInfo - The deviceInfo containing serial number for which to search. AcquireDSMLockExclusive - If TRUE this routine should acquire DsmContextLock Exclusively Return Value: The multi-path group entry in which the device resides. --*/ { PDSM_DEVICE_INFO deviceInfo; PLIST_ENTRY entry; PDSM_GROUP_ENTRY groupEntry = NULL; ULONG i; KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpFindDevice (DevInfo %p): Entering function.\n", DeviceInfo)); if (AcquireDSMLockExclusive) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); } // // Run through the DeviceInfo List // entry = DsmContext->DeviceList.Flink; for (i = 0; i < DsmContext->NumberDevices; i++, entry = entry->Flink) { // // Extract the deviceInfo structure. // deviceInfo = CONTAINING_RECORD(entry, DSM_DEVICE_INFO, ListEntry); DSM_ASSERT(deviceInfo); if (deviceInfo) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpFindDevice (DevInfo %p): Comparing with %p.\n", DeviceInfo, deviceInfo)); // // Call the Serial Number compare routine. // if (DsmCompareDevices(DsmContext, DeviceInfo, deviceInfo)) { groupEntry = deviceInfo->Group; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpFindDevice (DevInfo %p): Found matching multi-path group %p.\n", DeviceInfo, groupEntry)); break; } } } if (AcquireDSMLockExclusive) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpFindDevice (DevInfo %p): Exiting function with groupEntry %p.\n", DeviceInfo, groupEntry)); return groupEntry; } PDSM_GROUP_ENTRY DsmpBuildGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo ) /*++ Routine Description: This will allocate and partially initialise a multi-path group entry. N.B: This routine must be called with DsmContextLock held in Exclusive mode. Arguments: DsmContext - DSM context given to MPIO during initialization DeviceInfo - The first device to be added to the group. Return Value: The new group entry. --*/ { PDSM_GROUP_ENTRY group; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildGroupEntry (DevInfo %p): Entering function.\n", DeviceInfo)); // // Allocate the memory for the multi-path group. // group = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_GROUP_ENTRY), DSM_TAG_GROUP_ENTRY); if (group) { InitializeListHead(&group->FailingDevInfoList); group->GroupNumber = InterlockedIncrement((LONG volatile*)&DsmContext->NumberGroups); group->GroupSig = DSM_GROUP_SIG; group->State = DSM_GP_NORMAL; // // Add it to the list of multi-path groups. // InsertTailList(&DsmContext->GroupList, &group->ListEntry); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildGroupEntry (DevInfo %p): Failed to allocate memory for the group.\n", DeviceInfo)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildGroupEntry (DevInfo %p): Exiting function with group %p.\n", DeviceInfo, group)); return group; } NTSTATUS DsmpParseTargetPortGroupsInformation( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_reads_bytes_(TargetPortGroupsInfoLength) IN PUCHAR TargetPortGroupsInfo, _In_ IN ULONG TargetPortGroupsInfoLength ) /*++ Routine Description: This will parse the information returned back from a previously made call to ReportTargetPortGroups and build new TPG entries or update old ones. N.B: This routine must be called with DsmContextLock held in Exclusive mode. Arguments: DsmContext - DsmContext Group - group entry TargetPortGroupsInfo - Pointer to the ReportTPG returned buffer. TargetPortGroupsInfoLength - length of the buffer. Return Value: STATUS_SUCCESS or appropriate error code. --*/ { PUCHAR targetPortGroupsInfoIndex; ULONG bytes = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE; PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroupEntry = NULL; ULONG descriptorSize = 0; NTSTATUS status = STATUS_SUCCESS; ULONG index; DSM_DEVICE_STATE tpgState = DSM_DEV_NOT_USED_STATE; ULONG bytesLeft; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpParseTargetPortGroupsInformation (Group %p): Entering function.\n", Group)); targetPortGroupsInfoIndex = TargetPortGroupsInfo + bytes; bytesLeft = TargetPortGroupsInfoLength - bytes; while (bytes < TargetPortGroupsInfoLength && NT_SUCCESS(status)) { targetPortGroupEntry = DsmpFindTargetPortGroupEntry(DsmContext, Group, targetPortGroupsInfoIndex, bytesLeft); if (targetPortGroupEntry) { targetPortGroupEntry = DsmpUpdateTargetPortGroupEntry(DsmContext, targetPortGroupEntry, targetPortGroupsInfoIndex, bytesLeft, &descriptorSize); } else { targetPortGroupEntry = DsmpBuildTargetPortGroupEntry(DsmContext, Group, targetPortGroupsInfoIndex, bytesLeft, &descriptorSize); if (targetPortGroupEntry) { // // Insert this TPG entry into array // for (index = 0; index < DSM_MAX_PATHS; index++) { if (!Group->TargetPortGroupList[index]) { Group->TargetPortGroupList[index] = targetPortGroupEntry; InterlockedIncrement((LONG volatile*)&Group->NumberTargetPortGroups); targetPortGroupEntry->Group = Group; break; } } if (index == DSM_MAX_PATHS) { NT_ASSERT(index < DSM_MAX_PATHS); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpParseTargetPortGroupsInformation (Group %p): Number of paths exceeded max supported.\n", Group)); status = STATUS_UNSUCCESSFUL; goto __Exit_DsmpParseTargetPortGroupsInformation; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpParseTargetPortGroupsInformation (Group %p): Insufficient resources to build TPG.\n", Group)); status = STATUS_INSUFFICIENT_RESOURCES; } } if (NT_SUCCESS(status)) { // // If this is the first TPG being parsed, save off its AA state. // if (tpgState == DSM_DEV_NOT_USED_STATE) { tpgState = targetPortGroupEntry->AsymmetricAccessState; } else { // // Check if this TPG's AA state differs from the previous one's. // Symmetric LU access means that TPG access states must be the // same for TPGs. If this one is different, we know that the // device supports Asymmetric LU access. // if (tpgState != targetPortGroupEntry->AsymmetricAccessState) { Group->Symmetric = FALSE; } } } if (targetPortGroupEntry) { // // Set the flag to indicate that we've encountered this TPG in the RTPG information. // targetPortGroupEntry->Traversed = TRUE; } bytes += descriptorSize; targetPortGroupsInfoIndex += descriptorSize; bytesLeft -= descriptorSize; } // // Since we've gone through the entire information reported by back RTPG, it // is now time to delete the stale entries. // for (index = 0; index < DSM_MAX_PATHS; index++) { targetPortGroupEntry = Group->TargetPortGroupList[index]; if (targetPortGroupEntry) { if (targetPortGroupEntry->Traversed) { // // Entry needs to continue to exist. Reset the flag and continue. // targetPortGroupEntry->Traversed = FALSE; continue; } else { PLIST_ENTRY entry; PLIST_ENTRY tempEntry; PDSM_TARGET_PORT_LIST_ENTRY targetPort; // // For this target port group, clean up all its target ports if // the port doesn't expose any instance of this device. // for (entry = targetPortGroupEntry->TargetPortList.Flink; entry != NULL && entry != &targetPortGroupEntry->TargetPortList; entry = entry->Flink) { targetPort = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry); if (targetPort) { // // If the TP doesn't expose this device, it is safe // to delete it. // if (IsListEmpty(&targetPort->TP_DeviceList)) { tempEntry = entry; entry = entry->Blink; RemoveEntryList(tempEntry); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpParseTargetPortGroupsInformation (Group %p): Deleting empty target port %p from TPG %p list.\n", Group, targetPort, targetPortGroupEntry)); DsmpFreePool(targetPort); InterlockedDecrement((LONG volatile*)&targetPortGroupEntry->NumberTargetPorts); } } } // // If the TPG doesn't have any TPs, it is safe to delete it. // if (!targetPortGroupEntry->NumberTargetPorts) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpParseTargetPortGroupsInformation (Group %p): Deleting target port group %p.\n", Group, targetPortGroupEntry)); DsmpFreePool(targetPortGroupEntry); InterlockedDecrement((LONG volatile*)&Group->NumberTargetPortGroups); Group->TargetPortGroupList[index] = NULL; } } } } __Exit_DsmpParseTargetPortGroupsInformation: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpParseTargetPortGroupsInformation (Group %p): Exiting function with status %x\n", Group, status)); return status; } PDSM_TARGET_PORT_GROUP_ENTRY DsmpFindTargetPortGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor, _In_ IN ULONG TPGs_BufferLength ) /*++ Routine Description: This will search the group's TPG array to look for an identifier match. N.B: This routine must be called with DsmContextLock held in either Shared or Exclusive mode. Arguments: DsmContext - DsmContext Group - group entry TargetPortGroupsDescriptor - Pointer to the TPG descriptor. TPGs_BufferLength - Length of the passed in TargetPortGroupsDescriptor buffer. Return Value: Pointer to the array element that matches, else NULL. --*/ { PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = NULL; PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR descriptor = (PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR)TargetPortGroupsDescriptor; ULONG index; BOOLEAN found = FALSE; USHORT identifier = ((descriptor->TPG_Identifier & 0x00FF) << 8) | ((descriptor->TPG_Identifier & 0xFF00) >> 8); UNREFERENCED_PARAMETER(TPGs_BufferLength); UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindTargetPortGroupEntry (Group %p): Entering function.\n", Group)); for (index = 0; index < DSM_MAX_PATHS && !found; index++) { targetPortGroup = Group->TargetPortGroupList[index]; if (targetPortGroup) { if (targetPortGroup->Identifier == identifier) { found = TRUE; } } } if (!found) { targetPortGroup = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindTargetPortGroupEntry (Group %p): Exiting function with targetPortGroup %p.\n", Group, targetPortGroup)); return targetPortGroup; } _Success_(return!=0) PDSM_TARGET_PORT_GROUP_ENTRY DsmpUpdateTargetPortGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor, _In_ IN ULONG TPGs_BufferLength, _Out_ OUT PULONG DescriptorSize ) /*++ Routine Description: This routine will update the target port group with information contained in the passed in descriptor. N.B: This routine must be called with DsmContextLock held in Exclusive mode. Arguments: DsmContext - DsmContext TargetPortGroup - Pointer to the TPG entry to update. TargetPortGroupsDescriptor - Pointer to the TPG descriptor. TPGs_BufferLength - Length of the passed in TargetPortGroupsDescriptor buffer. DescriptorSize - return value of the size of the descriptor. Return Value: The updated target port group entry on success, NULL in case of failure. --*/ { PLIST_ENTRY entry; PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = TargetPortGroup; PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR descriptor = (PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR)TargetPortGroupsDescriptor; ULONG numberTargetPorts = 0; PULONG descriptorIndex; ULONG index; PDSM_TARGET_PORT_LIST_ENTRY listEntry; NTSTATUS status = STATUS_SUCCESS; ULONG identifier; PLIST_ENTRY tempEntry = NULL; ULONG delCount; PUCHAR endOfBuffer = TargetPortGroupsDescriptor + TPGs_BufferLength - 1; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupEntry (TPG %p): Entering function.\n", TargetPortGroup)); if (DescriptorSize == NULL) { status = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupEntry (TPG %p): Status %x due to null passed in DescriptorSize pointer\n", TargetPortGroup, status)); goto __Exit_DsmpUpdateTargetPortGroupEntry; } *DescriptorSize = sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) + (targetPortGroup->NumberTargetPorts * sizeof(ULONG)); if (((PUCHAR)descriptor + sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) - 1) > endOfBuffer) { status = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupEntry (TPG %p): Status %x due to incorrect passed in TPG buffer size (%u).\n", TargetPortGroup, status, TPGs_BufferLength)); goto __Exit_DsmpUpdateTargetPortGroupEntry; } identifier = ((descriptor->TPG_Identifier & 0x00FF) << 8) | ((descriptor->TPG_Identifier & 0xFF00) >> 8); NT_ASSERT(targetPortGroup->Identifier == (USHORT)identifier); NT_ASSERT(targetPortGroup->ActiveOptimizedSupported == (descriptor->ActiveOptimizedSupported) ? TRUE : FALSE); NT_ASSERT(targetPortGroup->ActiveUnoptimizedSupported == (descriptor->ActiveUnoptimizedSupported) ? TRUE : FALSE); NT_ASSERT(targetPortGroup->StandBySupported == (descriptor->StandbySupported) ? TRUE : FALSE); NT_ASSERT(targetPortGroup->UnavailableSupported == (descriptor->UnavailableSupported) ? TRUE : FALSE); NT_ASSERT(targetPortGroup->TransitioningSupported == (descriptor->TransitioningSupported) ? TRUE : FALSE); DSM_ASSERT(targetPortGroup->VendorUnique == descriptor->VendorUnique); // // It is possible that the asymmetric access state, status code and number of port // may have changed // if ((targetPortGroup->AsymmetricAccessState) != (descriptor->AsymmetricAccessState & 0xF)) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupEntry (TPG %p): Asymmetric access state has changed.\n", TargetPortGroup)); targetPortGroup->AsymmetricAccessState = descriptor->AsymmetricAccessState & 0xF; } targetPortGroup->Preferred = (descriptor->Preferred) ? TRUE : FALSE; targetPortGroup->StatusCode = descriptor->StatusCode; numberTargetPorts = descriptor->NumberTargetPorts; NT_ASSERT(numberTargetPorts > 0); // // Point to first target port identifier // descriptorIndex = descriptor->TargetPortIds; for (index = 0; index < numberTargetPorts && NT_SUCCESS(status); index++) { if (((PUCHAR)descriptorIndex + ((index + 1) * sizeof(ULONG)) - 1) > endOfBuffer) { status = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupEntry (TPG %p): Status %x due to incorrect TPG buffer size (%u) passed in.\n", TargetPortGroup, status, TPGs_BufferLength)); goto __Exit_DsmpUpdateTargetPortGroupEntry; } GetUlongFrom4ByteArray((PUCHAR)(&descriptorIndex[index]), identifier); listEntry = DsmpFindTargetPortListEntry(DsmContext, targetPortGroup, identifier); if (listEntry) { RemoveEntryList(&listEntry->ListEntry); InsertHeadList(&targetPortGroup->TargetPortList, &listEntry->ListEntry); } else { listEntry = DsmpBuildTargetPortListEntry(DsmContext, targetPortGroup, identifier); if (listEntry) { InsertHeadList(&targetPortGroup->TargetPortList, &listEntry->ListEntry); InterlockedIncrement((LONG volatile*)&targetPortGroup->NumberTargetPorts); } else { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupEntry (TPG %p): Failed to allocate TargetPort (identifier %x).\n", TargetPortGroup, identifier)); } } } // // Ignore the status & carry on. Even if we weren't able to build TP entries // for the new target ports, we are no worse off than before. // DSM_ASSERT(NT_SUCCESS(status)); *DescriptorSize = sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) + (numberTargetPorts * sizeof(ULONG)); for (index = 0, entry = targetPortGroup->TargetPortList.Flink; index < numberTargetPorts; index++, entry = entry->Flink); delCount = targetPortGroup->NumberTargetPorts - numberTargetPorts; for (index = 0; index < delCount; index++) { tempEntry = entry; entry = entry->Flink; RemoveEntryList(tempEntry); InterlockedDecrement((LONG volatile*)&targetPortGroup->NumberTargetPorts); listEntry = CONTAINING_RECORD(tempEntry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry); NT_ASSERT(listEntry); if (listEntry) { PLIST_ENTRY deviceEntry; PDSM_TARGET_PORT_DEVICELIST_ENTRY tp_device; while (!IsListEmpty(&listEntry->TP_DeviceList)) { deviceEntry = RemoveHeadList(&listEntry->TP_DeviceList); InterlockedDecrement((LONG volatile*)&listEntry->Count); if (deviceEntry) { tp_device = CONTAINING_RECORD(deviceEntry, DSM_TARGET_PORT_DEVICELIST_ENTRY, ListEntry); if (tp_device) { if (tp_device->DeviceInfo) { tp_device->DeviceInfo->TargetPort = NULL; } DsmpFreePool(tp_device); } } } DsmpFreePool(listEntry); } } __Exit_DsmpUpdateTargetPortGroupEntry: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupEntry (TPG %p): Exiting function.\n", targetPortGroup)); return targetPortGroup; } PDSM_TARGET_PORT_GROUP_ENTRY DsmpBuildTargetPortGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor, _In_ IN ULONG TPGs_BufferLength, _Out_ OUT PULONG DescriptorSize ) /*++ Routine Description: This will allocate and partially initialise a target port group entry. N.B: This routine must be called with DsmContextLock held in Exclusive mode. Arguments: DsmContext - DsmContext Group - The group that this newly going to be built TPG belongs to. TargetPortGroupsDescriptor - Pointer to the TPG descriptor. TPGs_BufferLength - Length of the passed in TargetPortGroupsDescriptor buffer. DescriptorSize - return value of the size of the descriptor. Return Value: The new target port group entry. --*/ { PDSM_TARGET_PORT_GROUP_ENTRY entry = NULL; PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR descriptor = (PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR)TargetPortGroupsDescriptor; ULONG numberTargetPorts = 0; PULONG descriptorIndex; ULONG index = 0; PDSM_TARGET_PORT_LIST_ENTRY listEntry; NTSTATUS status = STATUS_SUCCESS; ULONG identifier; PUCHAR endOfBuffer = TargetPortGroupsDescriptor + TPGs_BufferLength - 1; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Entering function.\n", Group)); if (DescriptorSize == NULL) { status = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Status %x due to null passed in DescriptorSize pointer\n", Group, status)); goto __Exit_DsmpBuildTargetPortGroupEntry; } *DescriptorSize = 0; if (((PUCHAR)descriptor + sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) - 1) > endOfBuffer) { status = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Status %x due to incorrect passed in TPG buffer size (%u).\n", Group, status, TPGs_BufferLength)); goto __Exit_DsmpBuildTargetPortGroupEntry; } // // Allocate the memory for the multi-path group. // entry = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_TARGET_PORT_GROUP_ENTRY), DSM_TAG_TARGET_PORT_GROUP_ENTRY); if (entry) { entry->TargetPortGroupSig = DSM_TARGET_PORT_GROUP_SIG; // // Target Port Group's access state // entry->AsymmetricAccessState = descriptor->AsymmetricAccessState & 0xF; // // Target Port Group's supported states // entry->ActiveOptimizedSupported = (descriptor->ActiveOptimizedSupported) ? TRUE : FALSE; entry->ActiveUnoptimizedSupported = (descriptor->ActiveUnoptimizedSupported) ? TRUE : FALSE; entry->StandBySupported = (descriptor->StandbySupported) ? TRUE : FALSE; entry->UnavailableSupported = (descriptor->UnavailableSupported) ? TRUE : FALSE; // // Target Port Group's Preference and support for reporting transitioning // entry->Preferred = (descriptor->Preferred) ? TRUE : FALSE; entry->TransitioningSupported = (descriptor->TransitioningSupported) ? TRUE : FALSE; // // Target Port Group's identifier // entry->Identifier = ((descriptor->TPG_Identifier & 0x00FF) << 8) | ((descriptor->TPG_Identifier & 0xFF00) >> 8); // // Target Port Group's status code // entry->StatusCode = descriptor->StatusCode; // // Vendor unique // entry->VendorUnique = descriptor->VendorUnique; // // Number of target ports // numberTargetPorts = descriptor->NumberTargetPorts; NT_ASSERT(numberTargetPorts > 0); // // Point to first target port identifier // descriptorIndex = descriptor->TargetPortIds; InitializeListHead(&entry->TargetPortList); for (index = 0; index < numberTargetPorts && NT_SUCCESS(status); index++) { if (((PUCHAR)descriptorIndex + ((index + 1) * sizeof(ULONG)) - 1) > endOfBuffer) { status = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Status %x due to incorrect TPG buffer size (%u) passed in.\n", Group, status, TPGs_BufferLength)); break; } GetUlongFrom4ByteArray((PUCHAR)(&descriptorIndex[index]), identifier); listEntry = DsmpBuildTargetPortListEntry(DsmContext, entry, identifier); if (listEntry) { InsertTailList(&entry->TargetPortList, &listEntry->ListEntry); InterlockedIncrement((LONG volatile*)&entry->NumberTargetPorts); } else { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Failed to allocate memory for TP (identifier %x) of TPG %p.\n", Group, identifier, entry)); } } if (NT_SUCCESS(status)) { *DescriptorSize = sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) + (numberTargetPorts * sizeof(ULONG)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Failed to allocate memory for the TPG.\n", Group)); status = STATUS_INSUFFICIENT_RESOURCES; } if (!NT_SUCCESS(status)) { // // Delete the target port list and the target port group entry // numberTargetPorts = index - 1; if (entry) { PLIST_ENTRY delEntry; for (index = 0; index < numberTargetPorts; index++) { delEntry = RemoveHeadList(&entry->TargetPortList); listEntry = CONTAINING_RECORD(delEntry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Cleaning up TPG %p's TP %x.\n", Group, entry, listEntry->Identifier)); DsmpFreePool(listEntry); } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Cleaning up TPG %p.\n", Group, entry)); DsmpFreePool(entry); entry = NULL; } } __Exit_DsmpBuildTargetPortGroupEntry: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortGroupEntry (Group %p): Exiting function with entry %p.\n", Group, entry)); return entry; } PDSM_TARGET_PORT_LIST_ENTRY DsmpFindTargetPortListEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_ IN ULONG RelativeTargetPortId ) /*++ Routine Description: This will search the passed in TPG's target port list for an identifier match. N.B: This routine must be called with DsmContextLock held in either Shared or Exclusive mode. Arguments: DsmContext - DsmContext TargetPortGroup - The Target Port Group whose target ports need to be searched. RelativeTargetPortId - Identifier of the target port entry being matched. Return Value: The target port list entry if match found, else NULL. --*/ { PLIST_ENTRY entry = NULL; PDSM_TARGET_PORT_LIST_ENTRY targetPort = NULL; BOOLEAN found = FALSE; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindTargetPortListEntry (TPG %p): Entering function.\n", TargetPortGroup)); for (entry = TargetPortGroup->TargetPortList.Flink; entry != &TargetPortGroup->TargetPortList && !found; entry = entry->Flink) { targetPort = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry); NT_ASSERT(targetPort); if (targetPort) { if (targetPort->Identifier == RelativeTargetPortId) { NT_ASSERT(targetPort->TargetPortGroup == TargetPortGroup); found = TRUE; } } } if (!found) { targetPort = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindTargetPortListEntry (TPG %p): Exiting function with target port %p.\n", TargetPortGroup, targetPort)); return targetPort; } PDSM_TARGET_PORT_LIST_ENTRY DsmpBuildTargetPortListEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_ IN ULONG RelativeTargetPortId ) /*++ Routine Description: This will allocate and partially initialize a target port list entry. N.B: This routine must be called with DsmContextLock held in Exclusive mode. Arguments: DsmContext - DsmContext TargetPortGroup - The Target Port Group that this target port belongs to. RelativeTargetPortId - Identifier of the target port entry being added. Return Value: The new target port list entry. --*/ { PDSM_TARGET_PORT_LIST_ENTRY entry; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortListEntry (TPG %p): Entering function.\n", TargetPortGroup)); entry = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_TARGET_PORT_LIST_ENTRY), DSM_TAG_TARGET_PORT_LIST_ENTRY); if (entry) { InitializeListHead(&entry->TP_DeviceList); entry->Identifier = RelativeTargetPortId; entry->TargetPortGroup = TargetPortGroup; entry->TargetPortSig = DSM_TARGET_PORT_SIG; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortListEntry (TPG %p): Failed to allocate memory for target port (identifier %x).\n", TargetPortGroup, RelativeTargetPortId)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpBuildTargetPortListEntry (TPG %p): Exiting function with entry %p.\n", TargetPortGroup, entry)); return entry; } PDSM_TARGET_PORT_GROUP_ENTRY DsmpFindTargetPortGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PUSHORT TargetPortGroupId ) /*++ Routine Description: This routine searches the list of TargetPortGroups of a Group to find a match for the passed in TargetPortGroupId. N.B: This routine must be called with DsmContextLock held in either Shared or Exclusive mode. Arguments: DsmContext - DSM context. Group - The group whose target port groups to search for a match. TargetPortGroupId - Identifier of the target port group entry being searched. Return Value: The target port group entry which matches the passed in identifier. --*/ { ULONG index; PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroupEntry = NULL; BOOLEAN found = FALSE; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindTargetPortGroup (Group %p): Entering function.\n", Group)); // // Run through the target port group array // for (index = 0; index < DSM_MAX_PATHS && !found; index++) { targetPortGroupEntry = Group->TargetPortGroupList[index]; if (targetPortGroupEntry) { if (targetPortGroupEntry->Identifier == *TargetPortGroupId) { found = TRUE; } } } if (!found) { targetPortGroupEntry = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindTargetPortGroup (Group %p): Exiting function with targetPortGroupEntry %p.\n", Group, targetPortGroupEntry)); return targetPortGroupEntry; } PDSM_TARGET_PORT_LIST_ENTRY DsmpFindTargetPort( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_ IN PULONG TargetPortGroupId ) /*++ Routine Description: This routine searches the list of TargetPorts to find a match for the passed in TargetPortGroup and RelativeTargetPortId. N.B. Spin lock must be held by caller. Arguments: DsmContext - DSM context. TargetPortGroup - the Target Port Group of which this target port is a member. RelativeTargetPortId - Identifier of the target port entry being searched. Return Value: The target port entry which matches the passed in identifier. --*/ { PLIST_ENTRY entry; PDSM_TARGET_PORT_LIST_ENTRY targetPortListEntry = NULL; BOOLEAN found = FALSE; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindTargetPort (TPG %p): Entering function.\n", TargetPortGroup)); // // Run through the Target Port List // for (entry = TargetPortGroup->TargetPortList.Flink; entry != &TargetPortGroup->TargetPortList && !found; entry = entry->Flink) { // // Extract the target port group structure. // targetPortListEntry = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry); NT_ASSERT(targetPortListEntry); if (targetPortListEntry) { NT_ASSERT(TargetPortGroup == targetPortListEntry->TargetPortGroup); // // Compare with passed in identifier. // if (targetPortListEntry->Identifier == *TargetPortGroupId) { found = TRUE; } } } if (!found) { targetPortListEntry = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindTargetPort (TPG %p): Exiting function with targetPortListEntry %p.\n", TargetPortGroup, targetPortListEntry)); return targetPortListEntry; } NTSTATUS DsmpAddDeviceEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO DeviceInfo ) /*++ Routine Description: This routine adds DeviceInfo to an existing multi-path group. N.B: This routine MUST be called with DsmContextLock held in Exclusive mode. Arguments: DsmContext - DSM context given to MPIO during initialization Group - The multi-path group to which DeviceInfo should be added. DeviceInfo - The new device. DeviceState - The initial device state (active, passive,...) Return Value: UNSUCCESSFUL - If there are too many paths already. SUCCESS --*/ { ULONG numberDevices; NTSTATUS status = STATUS_SUCCESS; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpAddDeviceEntry (DevInfo %p): Entering function.\n", DeviceInfo)); // // Ensure that this is a valid config - namely, it hasn't // exceeded the number of paths supported. // numberDevices = * (volatile ULONG *) &Group->NumberDevices; if (numberDevices < DSM_MAX_PATHS) { #if DBG ULONG i; // // Ensure that this isn't a second copy of the same pdo. // for (i = 0; i < numberDevices; i++) { if (Group->DeviceList[i]->PortPdo == DeviceInfo->PortPdo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpAddDeviceEntry (DevInfo %p): Received same PDO %p twice.\n", DeviceInfo, DeviceInfo->PortPdo)); } } #endif // // Indicate one more device is present in this group. // Group->DeviceList[numberDevices] = DeviceInfo; // // Indicate one more in the list. // InterlockedIncrement((LONG volatile*)&Group->NumberDevices); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpAddDeviceEntry (DevInfo %p): Adding Device to Group %p\n", DeviceInfo, Group)); // // Set-up this device's group id. // DeviceInfo->Group = Group; // // One more deviceInfo entry. // InterlockedIncrement((LONG volatile*)&DsmContext->NumberDevices); // // Finally, add it to the global list of devices. // InsertTailList(&DsmContext->DeviceList, &DeviceInfo->ListEntry); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpAddDeviceEntry (DevInfo %p): Max Paths already added for Group %p.\n", DeviceInfo, Group)); status = STATUS_UNSUCCESSFUL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpAddDeviceEntry (DevInfo %p): Exiting function with status %x.\n", DeviceInfo, status)); return status; } PDSM_CONTROLLER_LIST_ENTRY DsmpFindControllerEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDEVICE_OBJECT PortObject, _In_ IN PSCSI_ADDRESS ScsiAddress, _In_reads_(ControllerSerialNumberLength) IN PSTR ControllerSerialNumber, _In_ IN SIZE_T ControllerSerialNumberLength, _In_ IN STORAGE_IDENTIFIER_CODE_SET CodeSet, _In_ IN BOOLEAN AcquireLock ) /*++ Routine Description: This routine compares the passed in serial number and SCSI address with the entries in the list of controller objects. Arguments: DsmContext - DSM context given to MPIO during initialization. PortObject - Port FDO exposing the controller. ScsiAddress - The scsi address to match. ControllerSerialNumber - The serial number for which to find a match. ControllerSerialNumberLength - Length of the passed in serial number, in bytes. CodeSet - Code set used when building the passed in serial number. AcquireLock - FALSE indicates that the caller has already acquired the spin lock. Return Value: Controller list entry if a match is found, else NULL --*/ { KIRQL oldIrql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error PLIST_ENTRY entry; PDSM_CONTROLLER_LIST_ENTRY controllerEntry = NULL; BOOLEAN found = FALSE; PDSM_CONTROLLER_LIST_ENTRY candidate = NULL; UNREFERENCED_PARAMETER(CodeSet); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpFindControllerEntry (SN %s): Entering function.\n", ControllerSerialNumber)); if (AcquireLock) { oldIrql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); } for (entry = DsmContext->ControllerList.Flink; entry != &DsmContext->ControllerList && !found; entry = entry->Flink) { controllerEntry = CONTAINING_RECORD(entry, DSM_CONTROLLER_LIST_ENTRY, ListEntry); NT_ASSERT(controllerEntry); if (!controllerEntry) { continue; } // // Serial numbers and Portal, Bus, and Target of the SCSI address must match. // if (!strncmp((const char*)controllerEntry->Identifier, ControllerSerialNumber, ControllerSerialNumberLength) && (controllerEntry->ScsiAddress->PortNumber == ScsiAddress->PortNumber && controllerEntry->ScsiAddress->PathId == ScsiAddress->PathId && controllerEntry->ScsiAddress->TargetId == ScsiAddress->TargetId)) { if (controllerEntry->IdLength == ControllerSerialNumberLength) { found = TRUE; } else { if ((!candidate) || (controllerEntry->IdLength > ControllerSerialNumberLength && ControllerSerialNumberLength == 32)) { candidate = controllerEntry; } } } } if (!found) { if (candidate) { controllerEntry = candidate; } else { controllerEntry = NULL; } } // // If we found a matching controller entry, we need to make sure the Port // Object (FDO) is updated. We also don't care about the LUN part of the // SCSI address so we just set it to zero. // if (controllerEntry) { controllerEntry->PortObject = PortObject; controllerEntry->ScsiAddress->Lun = 0; } if (AcquireLock) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), oldIrql); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpFindControllerEntry (SN %s): Exiting function with controllerEntry %p\n", ControllerSerialNumber, controllerEntry)); return controllerEntry; } _Ret_maybenull_ _Must_inspect_result_ _When_(return != NULL, __drv_allocatesMem(Mem)) PDSM_CONTROLLER_LIST_ENTRY DsmpBuildControllerEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_opt_ IN PDEVICE_OBJECT DeviceObject, _In_ IN PDEVICE_OBJECT PortObject, _In_ IN PSCSI_ADDRESS ScsiAddress, _In_ IN PSTR ControllerSerialNumber, _In_ IN STORAGE_IDENTIFIER_CODE_SET CodeSet, _In_ IN BOOLEAN AcquireLock ) /*++ Routine Description: This routine builds a new controller list entry with the passed in serial number info. Arguments: DsmContext - DSM context given to MPIO during initialization. DeviceObject - Controller's PDO. PortObject - Port FDO exposing the controller. ScsiAddress - scsi address of the controller. ControllerSerialNumber - The serial number to associate with new entry. CodeSet - Code set of the identifier that was used to build the serial number. AcquireLock - TRUE indicates that the function must grab the spinlock. FALSE indicates that caller has the spin lock held. Return Value: New controller list entry if we successfully built one, else NULL --*/ { KIRQL oldIrql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error PDSM_CONTROLLER_LIST_ENTRY controllerEntry = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildControllerEntry (SN %s): Entering function - Controller %p seen through PortFDO %p.\n", ControllerSerialNumber, DeviceObject, PortObject)); if (AcquireLock) { oldIrql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); } controllerEntry = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_CONTROLLER_LIST_ENTRY), DSM_TAG_CONTROLLER_LIST_ENTRY); if (controllerEntry) { // // Note: // ControllerSerialNumber's length fits in a 32-bit value. // See implementation in DsmpParseDeviceID() // ULONG length = (ULONG)strlen(ControllerSerialNumber); controllerEntry->Identifier = DsmpAllocatePool(NonPagedPoolNx, length + 1, DSM_TAG_SERIAL_NUM); if (controllerEntry->Identifier) { controllerEntry->ScsiAddress = DsmpAllocatePool(NonPagedPoolNx, sizeof(SCSI_ADDRESS), DSM_TAG_SCSI_ADDRESS); if (controllerEntry->ScsiAddress) { RtlCopyMemory(controllerEntry->ScsiAddress, ScsiAddress, sizeof(SCSI_ADDRESS)); controllerEntry->DeviceObject = DeviceObject; controllerEntry->PortObject = PortObject; controllerEntry->ControllerSig = DSM_CONTROLLER_SIG; controllerEntry->IdLength = length; controllerEntry->IdCodeSet = CodeSet; RtlCopyMemory(controllerEntry->Identifier, ControllerSerialNumber, length); controllerEntry->RefCount = 0; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildControllerEntry (SN %s): Failed to allocate resources for scsiaddress (controllerEntry %p).\n", ControllerSerialNumber, controllerEntry)); DsmpFreePool(controllerEntry->Identifier); controllerEntry->Identifier = NULL; DsmpFreePool(controllerEntry); controllerEntry = NULL; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildControllerEntry (SN %s): Failed to allocate resources for identifier (controllerEntry %p).\n", ControllerSerialNumber, controllerEntry)); DsmpFreePool(controllerEntry); controllerEntry = NULL; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildControllerEntry (SN %s): Failed to allocate memory for ControllerEntry.\n", ControllerSerialNumber)); } if (AcquireLock) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), oldIrql); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildControllerEntry (SN %s): Exiting function with controllerEntry %p\n", ControllerSerialNumber, controllerEntry)); return controllerEntry; } VOID DsmpFreeControllerEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ __drv_freesMem(Mem) IN PDSM_CONTROLLER_LIST_ENTRY ControllerEntry ) /*++ Routine Description: This routine frees the allocations of the passed in controller list entry. Arguments: DsmContext - DSM context given to MPIO during initialization. ControllerEntry - Controller list entry. Return Value: Nothing --*/ { PVOID tempAddress = (PVOID)ControllerEntry; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpFreeControllerEntry (Entry %p): Entering function.\n", ControllerEntry)); if (ControllerEntry->Identifier) { DsmpFreePool(ControllerEntry->Identifier); } if (ControllerEntry->ScsiAddress) { DsmpFreePool(ControllerEntry->ScsiAddress); } DsmpFreePool(ControllerEntry); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpFreeControllerEntry (Entry %p): Exiting function.\n", tempAddress)); return; } BOOLEAN DsmpIsDeviceBelongsToController( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN PDSM_CONTROLLER_LIST_ENTRY ControllerEntry ) /*++ Routine Description: This routine determines if the device passed in was exposed via the passed in controller. The match is to be based on VID and SCSI Address (using the Port, Bus and Target comparison). Arguments: DsmContext - DSM context given to MPIO during initialization. DeviceInfo - The device instance to match. ControllerEntry - The controller object which we need to determine whether DeviceInfo is exposed from. Return Value: TRUE - if the controller's VID and scsi address match FALSE - not matched --*/ { BOOLEAN saMatch = FALSE; BOOLEAN vMatch = FALSE; BOOLEAN match = FALSE; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpIsDeviceBelongsToController (DevInfo %p): Entering function - ControllerEntry is %p.\n", DeviceInfo, ControllerEntry)); if (DeviceInfo->ScsiAddress && ControllerEntry->ScsiAddress) { saMatch = (DeviceInfo->ScsiAddress->PathId == ControllerEntry->ScsiAddress->PathId && DeviceInfo->ScsiAddress->PortNumber == ControllerEntry->ScsiAddress->PortNumber && DeviceInfo->ScsiAddress->TargetId == ControllerEntry->ScsiAddress->TargetId); } if (saMatch) { INQUIRYDATA inquiryData = {0}; UCHAR controllerVID[9] = {0}; UCHAR deviceVID[9] = {0}; if (NT_SUCCESS(DsmpGetStandardInquiryData(ControllerEntry->DeviceObject, &inquiryData))) { RtlStringCchCopyA((PSTR)controllerVID, ARRAYSIZE(controllerVID), (PCSTR)(&inquiryData.VendorId)); RtlStringCchCopyA((PSTR)deviceVID, ARRAYSIZE(deviceVID), (PCSTR)(&DeviceInfo->Descriptor) + DeviceInfo->Descriptor.VendorIdOffset); if (!strcmp((const char*)controllerVID, (const char*)deviceVID)) { vMatch = TRUE; } } } match = saMatch & vMatch; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpIsDeviceBelongsToController (DevInfo %p): ControllerEntry %p. Exiting function with match = %x.\n", DeviceInfo, ControllerEntry, match)); return match; } PDSM_DEVICE_INFO DsmpFindDevInfoFromGroupAndFOGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_FAILOVER_GROUP FOGroup ) /*++ Routine Description: This routine will find the deviceInfo that is part of both the passed in Group as well as passed in Fail-Over group. N.B: This routine MUST be called with DsmContextLock held in either Shared or Exclusive mode. Arguments: DsmContext - DSM context given to MPIO during initialization Group - The group that represents the device. FOGroup - The FOG that the device is part of. Return Value: The deviceInfo that is part of both. NULL - if not found. --*/ { ULONG i; PDSM_DEVICE_INFO deviceInfo = NULL; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpFindDevInfoFromGroupAndFOGroup (Group %p FOG %p): Entering function.\n", Group, FOGroup)); if (Group && FOGroup) { // // Run through the list of devInfos in passed in Group // for (i = 0; i < DSM_MAX_PATHS; i++) { deviceInfo = Group->DeviceList[i]; if (deviceInfo) { if (deviceInfo->FailGroup == FOGroup) { break; } else { deviceInfo = NULL; } } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpFindFOGroup (Group %p FOG %p): Exiting function with deviceInfo %p.\n", Group, FOGroup, deviceInfo)); return deviceInfo; } PDSM_FAILOVER_GROUP DsmpFindFOGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PVOID PathId ) /*++ Routine Description: This routine will find the Fail-Over group that corresponds to PathId. N.B: This routine MUST be called with DsmContextLock held in either Shared or Exclusive mode. Arguments: DsmContext - DSM context given to MPIO during initialization PathId - The Path Identifier that corresponds to an adapter/adapter-controller Return Value: The fail-over group. NULL - if not found. --*/ { PDSM_FAILOVER_GROUP failOverGroup = NULL; PDSM_FAILOVER_GROUP retFOGroup = NULL; PLIST_ENTRY entry; ULONG i; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindFOGroup (PathId %p): Entering function.\n", PathId)); // // Run through the list of Fail-Over Groups // entry = DsmContext->FailGroupList.Flink; for (i = 0; i < DsmContext->NumberFOGroups; i++, entry = entry->Flink) { // // Extract the fail-over group structure. // failOverGroup = CONTAINING_RECORD(entry, DSM_FAILOVER_GROUP, ListEntry); NT_ASSERT(failOverGroup); if (!failOverGroup) { continue; } // // Check for a match of the PathId. // if (failOverGroup->PathId == PathId) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpFindFOGroup (PathId %p): Found a FO group %p.\n", PathId, failOverGroup)); retFOGroup = failOverGroup; break; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindFOGroup (PathId %p): Exiting function with retFOGroup %p.\n", PathId, retFOGroup)); return retFOGroup; } PDSM_FAILOVER_GROUP DsmpBuildFOGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN PVOID *PathId ) /*++ Routine Description: This routine will build and partially initialise a fail-over group entry. The FOG corresponds to the device list which will fail as a group. N.B: This routine MUST be called with DsmContextLock held in Exclusive mode. Arguments: DsmContext - DSM context given to MPIO during initialization DeviceInfo - The first device to add to the group. PathId - An identifier that is returned to mpio that id's the path. Return Value: The fail-over group entry. NULL - on failed allocation. --*/ { PDSM_FAILOVER_GROUP failOverGroup; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildFOGroup (PathId %p): Entering function.\n", PathId)); // // Allocate a new Fail Over Group // failOverGroup = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_FAILOVER_GROUP), DSM_TAG_FO_GROUP); if (failOverGroup) { InitializeListHead(&failOverGroup->FOG_DeviceList); InitializeListHead(&failOverGroup->ZombieGroupList); // // Get the current number of groups, and add the one that's being created. // InterlockedIncrement((LONG volatile*)&DsmContext->NumberFOGroups); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpBuildFOGroup (PathId %p): Path that will be used for %p is %p.\n", PathId, DeviceInfo, *PathId)); failOverGroup->PathId = *PathId; // // Set the initial state to NORMAL. // failOverGroup->State = DSM_FG_NORMAL; failOverGroup->FailOverSig = DSM_FOG_SIG; // // Add it to the global list. // InsertTailList(&DsmContext->FailGroupList, &failOverGroup->ListEntry); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpBuildFOGroup (PathId %p): Added new FOGroup %p with path %p. Count of FO Group %d.\n", PathId, failOverGroup, *PathId, DsmContext->NumberFOGroups)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildFOGroup (PathId %p): Failed to allocate memory for FailOverGroup.\n", PathId)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildFOGroup (PathId %p): Exiting function with failOverGroup %p.\n", PathId, failOverGroup)); return failOverGroup; } NTSTATUS DsmpUpdateFOGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_FAILOVER_GROUP FailGroup, _In_ IN PDSM_DEVICE_INFO DeviceInfo ) /*++ Routine Description: This routine will add DeviceInfo to an existing FOG. N.B: This routine MUST be called with DsmContextLock held in Exclusive mode. Arguments: DsmContext - DSM context given to MPIO during initialization FailGroup - The fail-over group entry. DeviceInfo - The new device. Return Value: STATUS_SUCCESS or appropriate error code. --*/ { NTSTATUS status = STATUS_SUCCESS; PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpUpdateFOGroup (FOG %p): Entering function. DeviceInfo %p.\n", FailGroup, DeviceInfo)); if (DeviceInfo && FailGroup) { fogDeviceListEntry = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_FOG_DEVICELIST_ENTRY), DSM_TAG_FOG_DEV_ENTRY); if (fogDeviceListEntry) { // // Add the device to the list of devices that are on this path. // fogDeviceListEntry->DeviceInfo = DeviceInfo; InterlockedIncrement((LONG volatile*)&FailGroup->Count); InsertTailList(&FailGroup->FOG_DeviceList, &fogDeviceListEntry->ListEntry); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpUpdateFOGroup (FOG %p): DevInfo %p added (current count: %d)\n", FailGroup, DeviceInfo, FailGroup->Count)); // // Set the device's F.O. Group. // DeviceInfo->FailGroup = FailGroup; } else { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpUpdateFOGroup (FOG %p): Failed to allocate memory for FOG devlist entry.\n", FailGroup)); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpUpdateFOGroup (FOG %p): Exiting function with status %x.\n", FailGroup, status)); return status; } VOID DsmpRemoveDeviceFailGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_FAILOVER_GROUP FailGroup, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN BOOLEAN AcquireDSMLockExclusive ) /*++ Routine Description: This routine will remove DeviceInfo from the FOG. This routine is called in response to a removal of the device. Arguments: DsmContext - DSM context given to MPIO during initialization FailGroup - The FOG from which DeviceInfo should be removed. DeviceInfo - The now missing device. AcquireDSMLockExclusive - If TRUE this routine should acquire DsmContextLock Exclusively Return Value: NOTHING --*/ { KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 warnings PLIST_ENTRY entry; PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry; PLIST_ENTRY zombieEntry; PDSM_ZOMBIEGROUP_ENTRY zombieGroup; PDSM_ZOMBIEGROUP_ENTRY newZombieGroup; BOOLEAN groupInZombieList = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveDeviceFailGroup (FOG %p): Entering function. DeviceInfo %p.\n", FailGroup, DeviceInfo)); if (FailGroup && DeviceInfo) { if (AcquireDSMLockExclusive) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); } for (entry = FailGroup->FOG_DeviceList.Flink; entry != &FailGroup->FOG_DeviceList; entry = entry->Flink) { fogDeviceListEntry = CONTAINING_RECORD(entry, DSM_FOG_DEVICELIST_ENTRY, ListEntry); DSM_ASSERT(fogDeviceListEntry); if (!fogDeviceListEntry) { continue; } if (fogDeviceListEntry->DeviceInfo == DeviceInfo) { DeviceInfo->FailGroup = NULL; RemoveEntryList(entry); DsmpFreePool(fogDeviceListEntry); InterlockedDecrement((LONG volatile*)&FailGroup->Count); // // If a DeviceInfo is removed, we need to keep its group in a // "zombie" list so that we can still access a fail-over group's // associated groups even when all its devices are gone. // for (zombieEntry = FailGroup->ZombieGroupList.Flink; zombieEntry != &(FailGroup->ZombieGroupList); zombieEntry = zombieEntry->Flink) { zombieGroup = CONTAINING_RECORD(zombieEntry, DSM_ZOMBIEGROUP_ENTRY, ListEntry); if (zombieGroup != NULL && zombieGroup->Group != NULL && zombieGroup->Group == DeviceInfo->Group) { groupInZombieList = TRUE; break; } } // // Create a new entry if the group does not exist in the zombie group list. // if (groupInZombieList == FALSE) { newZombieGroup = (PDSM_ZOMBIEGROUP_ENTRY)DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_ZOMBIEGROUP_ENTRY), DSM_TAG_ZOMBIEGROUP_ENTRY); if (newZombieGroup != NULL) { newZombieGroup->Group = DeviceInfo->Group; InsertTailList(&FailGroup->ZombieGroupList, &newZombieGroup->ListEntry); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRemoveDeviceFailGroup (DevInfo %p): Failed to allocate memory for the zombie group.\n", DeviceInfo)); } } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpRemoveDeviceFailGroup (FOG %p): DevInfo %p removed from FOG (current count: %d)\n", FailGroup, DeviceInfo, FailGroup->Count)); break; } } if (AcquireDSMLockExclusive) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveDeviceFailGroup (FOG %p): Exiting function.\n", FailGroup)); return; } ULONG DsmpRemoveDeviceEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO DeviceInfo ) /*++ Routine Description: This routine will remove DeviceInfo from Group. If it is the last DeviceInfo in the Group, it has the added side-effect of cleaning up the Group entry also. Arguments: DsmContext - DSM context given to MPIO during initialization Group - The multi-path group from which DeviceInfo should be removed. DeviceInfo - The device to remove. Return Value: Number of devices left in group. --*/ { KIRQL irql; ULONG i; ULONG j; ULONG numberDevices; BOOLEAN freeGroup = FALSE; PVOID tempAddress = (PVOID)Group; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveDeviceEntry (Group %p): Entering function. DeviceInfo %p.\n", Group, DeviceInfo)); irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); // // Find it's offset in the array of devices. // for (i = 0; i < Group->NumberDevices; i++) { if (Group->DeviceList[i] == DeviceInfo) { // // Zero out it's entry. // Group->DeviceList[i] = NULL; // // Reduce the number in the group. // InterlockedDecrement((LONG volatile*)&Group->NumberDevices); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpRemoveDeviceEntry (Group %p): Removing Device %p (desiredState %u) from Group\n", Group, DeviceInfo, DeviceInfo->DesiredState)); // // Collapse the array. // Holding the spinlock, so that the state is consistent in other // routines. // for (j = i; j < Group->NumberDevices; j++) { // // Shuffle all entries down to fill the hole. // Group->DeviceList[j] = Group->DeviceList[j + 1]; } // // Zero out the last one. // Group->DeviceList[j] = NULL; break; } } // // Remove this devInfo from the TargetPort deviceList // DsmpRemoveDeviceFromTargetPortList(DeviceInfo); numberDevices = Group->NumberDevices; // // See if anything is left in the Group. // if (Group->NumberDevices == 0) { Group->State = DSM_GP_FAILED; // // Yank it from the Group list. // DsmpRemoveGroupEntry(DsmContext, Group, FALSE); freeGroup = TRUE; } // // Yank the device out of the Global list. // RemoveEntryList(&DeviceInfo->ListEntry); InterlockedDecrement((LONG volatile*)&DsmContext->NumberDevices); // // If the serial number buffer was allocated, need to free it. // if (DeviceInfo->SerialNumberAllocated) { DsmpFreePool(DeviceInfo->SerialNumber); } if (DeviceInfo->ScsiAddress) { DsmpFreePool(DeviceInfo->ScsiAddress); } // // Fix up the Reservation List, if needed. // if (!freeGroup && Group->ReservationList) { ULONG oldList; // // Capture the list for debugging. // oldList = Group->ReservationList; Group->ReservationList = 0; // // Go through all devices in this group and find the one(s) registered. // for (i = 0; i < Group->NumberDevices; i++) { if (Group->DeviceList[i]->RegisterServiced) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmRemoveDeviceEntry (Group %p): Device %p at %d registered.\n", Group, Group->DeviceList[i], i)); // // Indicate its place. // Group->ReservationList |= (1 << i); } } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmRemoveDeviceEntry (Group %p): Reservations Old (%x) New (%x).\n", Group, oldList, Group->ReservationList)); } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); // // Free the allocation. // DsmpFreePool(DeviceInfo); if (freeGroup) { // // Free the allocations. // if (Group->RegistryKeyName) { DsmpFreePool(Group->RegistryKeyName); } if (Group->HardwareId) { DsmpFreePool(Group->HardwareId); } DsmpFreePool(Group); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveDeviceEntry (Group %p): Exiting function - numberDevices = %x.\n", tempAddress, numberDevices)); return numberDevices; } VOID DsmpRemoveDeviceFromTargetPortList( _In_ IN PDSM_DEVICE_INFO DeviceInfo ) /*++ Routine Description: This will remove a DeviceInfo from its target port device list. The caller should ensure that the DsmContext->SpinLock is held before calling this function. Arguments: DeviceInfo - The DeviceInfo to be removed. Return Value: None --*/ { if (DeviceInfo->TargetPort) { PLIST_ENTRY entry; PDSM_TARGET_PORT_DEVICELIST_ENTRY listEntry; for (entry = DeviceInfo->TargetPort->TP_DeviceList.Flink; entry != NULL && entry != &DeviceInfo->TargetPort->TP_DeviceList; entry = entry->Flink) { listEntry = CONTAINING_RECORD(entry, DSM_TARGET_PORT_DEVICELIST_ENTRY, ListEntry); if (listEntry) { if (listEntry->DeviceInfo == DeviceInfo) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpRemoveDeviceFromTargetPortList: Removing device %p from target port entry %p.\n", DeviceInfo, listEntry)); RemoveEntryList(entry); InterlockedDecrement((LONG volatile*)&DeviceInfo->TargetPort->Count); DsmpFreePool(listEntry); DeviceInfo->TargetPort = NULL; DeviceInfo->TargetPortGroup = NULL; break; } } } } } VOID DsmpRemoveZombieGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY ZombieGroup ) /* ++ Routine Description: This will scan through all the Failover Groups and remove the given Group from each Failover Group's zombie group list. The DSM lock should be aquired by the caller. Arguments: DsmContext - DSM context given to MPIO during initialization ZombieGroup - Group entry that should be removed from FOGs' ZombieGroupList Return Value: None -- */ { // // Run through the list of Fail-Over Groups // ULONG i; PDSM_FAILOVER_GROUP failOverGroup = NULL; PLIST_ENTRY fogEntry; PLIST_ENTRY groupEntry; PDSM_ZOMBIEGROUP_ENTRY zombieGroupEntry; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveZombieGroupEntry (Group %p): Entering function.\n", ZombieGroup)); fogEntry = DsmContext->FailGroupList.Flink; for (i = 0; fogEntry != NULL && i < DsmContext->NumberFOGroups; i++, fogEntry = fogEntry->Flink) { failOverGroup = CONTAINING_RECORD(fogEntry, DSM_FAILOVER_GROUP, ListEntry); if (failOverGroup != NULL) { for (groupEntry = failOverGroup->ZombieGroupList.Flink; groupEntry != &(failOverGroup->ZombieGroupList); groupEntry = groupEntry->Flink) { zombieGroupEntry = CONTAINING_RECORD(groupEntry, DSM_ZOMBIEGROUP_ENTRY, ListEntry); if (zombieGroupEntry != NULL && zombieGroupEntry->Group != NULL && zombieGroupEntry->Group == ZombieGroup) { RemoveEntryList(groupEntry); DsmpFreePool(zombieGroupEntry); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveZombieGroupEntry (Group %p): Found and removed a zombie group in (FOG %p)\n", ZombieGroup, failOverGroup)); // // We removed the zombie group entry from this fail-over // group, so we can move on to the next fail-over group. // break; } } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveZombieGroupEntry (Group %p): Exiting function.\n", ZombieGroup)); } VOID DsmpRemoveGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY GroupEntry, _In_ IN BOOLEAN AcquireDSMLockExclusive ) /*++ Routine Description: This will remove a group entry from the DSM's list. Arguments: DsmContext - DSM context given to MPIO during initialization GroupEntry - Group entry that should be removed from DSM's list AcquireDSMLockExclusive - If TRUE this routine should acquire DsmContextLock Exclusively Return Value: None --*/ { KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 warnings ULONG index; PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup; PLIST_ENTRY entry; PDSM_TARGET_PORT_LIST_ENTRY targetPort; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveGroupEntry (Group %p): Entering function.\n", GroupEntry)); if (AcquireDSMLockExclusive) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); } NT_ASSERT(GroupEntry && GroupEntry->ListEntry.Flink && GroupEntry->ListEntry.Blink); // // Since this group is being removed, we need to make sure it is also // removed from all fail-over groups' zombie group lists. // DsmpRemoveZombieGroupEntry(DsmContext, GroupEntry); // // Add it to the list of multi-path groups. // RemoveEntryList(&GroupEntry->ListEntry); GroupEntry->ListEntry.Flink = GroupEntry->ListEntry.Blink = NULL; InterlockedDecrement((LONG volatile*)&DsmContext->NumberGroups); for (index = 0; index < DSM_MAX_PATHS; index++) { // // Clean up all its Target Port Groups // targetPortGroup = GroupEntry->TargetPortGroupList[index]; if (targetPortGroup) { GroupEntry->TargetPortGroupList[index] = NULL; // // For each target port group, clean up all its target ports // while (!IsListEmpty(&targetPortGroup->TargetPortList)) { entry = RemoveHeadList(&targetPortGroup->TargetPortList); if (entry) { targetPort = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry); if (targetPort) { PLIST_ENTRY deviceEntry; PDSM_TARGET_PORT_DEVICELIST_ENTRY listEntry; while (!IsListEmpty(&targetPort->TP_DeviceList)) { deviceEntry = RemoveHeadList(&targetPort->TP_DeviceList); if (deviceEntry) { listEntry = CONTAINING_RECORD(deviceEntry, DSM_TARGET_PORT_DEVICELIST_ENTRY, ListEntry); if (listEntry) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpRemoveGroupEntry (Group %p): Deleting device %p from TP %p list (TPG %p).\n", GroupEntry, listEntry->DeviceInfo, targetPort, targetPortGroup)); DsmpFreePool(listEntry); InterlockedDecrement((LONG volatile*)&targetPort->Count); } } } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpRemoveGroupEntry (Group %p): Deleting target port %p from TPG %p list.\n", GroupEntry, targetPort, targetPortGroup)); DsmpFreePool(targetPort); InterlockedDecrement((LONG volatile*)&targetPortGroup->NumberTargetPorts); } } } NT_ASSERT(targetPortGroup->NumberTargetPorts == 0); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpRemoveGroupEntry (Group %p): Deleting target port group %p.\n", GroupEntry, targetPortGroup)); DsmpFreePool(targetPortGroup); InterlockedDecrement((LONG volatile*)&GroupEntry->NumberTargetPortGroups); } } NT_ASSERT(GroupEntry->NumberTargetPortGroups == 0); if (AcquireDSMLockExclusive) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRemoveGroupEntry (Group %p): Exiting function.\n", GroupEntry)); return; } PDSM_FAILOVER_GROUP DsmpSetNewPath( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO FailingDevice ) /*++ Routine Description: This routine will assign a new path to the multi-path group in which FailingDevice resides. Caller must NOT hold spin lock. Arguments: DsmContext - DSM context given to MPIO during initialization FailingDevice - The device-path that is being moved (due to failure, or admin. request) Return Value: The FOG containing the new path. --*/ { ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpSetNewPath (DevInfo %p): Entering function.\n", FailingDevice)); if (DsmpIsSymmetricAccess(FailingDevice)) { DsmpSetLBForPathRemoval(DsmContext, FailingDevice, NULL, SpecialHandlingFlag); } else { DsmpSetLBForPathRemovalALUA(DsmContext, FailingDevice, NULL, SpecialHandlingFlag); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpSetNewPath (DevInfo %p): Exiting function with path (failGroup) %p.\n", FailingDevice, FailingDevice->Group->PathToBeUsed)); return FailingDevice->Group->PathToBeUsed; } PDSM_FAILOVER_GROUP DsmpSetNewPathUsingGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group ) /*++ Routine Description: This routine will try to assign a new path using the given multi-path group. This function should only be called during failover in the event that there is no DeviceInfo with which to call DsmpSetNewPath(). Typically this will be called with one of a fail-over group's zombie groups. Caller must NOT hold spin lock. Arguments: DsmContext - DSM context given to MPIO during initialization. Group - The multi-path group which to assign a new path. Return Value: The FOG containing the new path or NULL if no path was found. --*/ { ULONG i; PDSM_DEVICE_INFO pDevInfo = NULL; ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpSetNewPathUsingGroup (Group %p): Entering function.\n", Group)); // // Get the first available DeviceInfo. // for (i = 0; i < DSM_MAX_PATHS; i ++) { if (Group->DeviceList[i] != NULL) { pDevInfo = Group->DeviceList[i]; break; } } if (pDevInfo == NULL) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpSetNewPathForZombieGroup (ZombieGroup %p): No failover group can be found.\n", Group)); return NULL; } if (DsmpIsSymmetricAccess(pDevInfo)) { DsmpSetLBForPathRemoval(DsmContext, pDevInfo, Group, SpecialHandlingFlag); } else { DsmpSetLBForPathRemovalALUA(DsmContext, pDevInfo, Group, SpecialHandlingFlag); } TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpSetNewPathForZombieGroup (ZombieGroup %p): Exiting function with path (failGroup) %p.\n", Group, Group->PathToBeUsed)); return Group->PathToBeUsed; } NTSTATUS DsmpUpdateTargetPortGroupDevicesStates( _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_ IN DSM_DEVICE_STATE NewState ) /*++ Routine Description: This routine will update the target port group and all its appropriate devInfos (ones not in remove pending, removed, or invalidated) with the new state. The ALUAState will only be updated, NOT the real State. Caller needs to update the real State based on the current LB policy. Note: This should be called with DsmContext Lock held and should only be called after a SetTargetPortGroups request was sent down. Arguments: TargetPortGroup - TargetPortGroup whose state and deviceInfos need to be updated NewState - The new state Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { NTSTATUS status = STATUS_SUCCESS; PLIST_ENTRY entry = NULL; PDSM_TARGET_PORT_LIST_ENTRY targetPort = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupDevicesStates (TPG %p): Entering function.\n", TargetPortGroup)); if (!TargetPortGroup) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupDevicesStates (TPG %p): Invalid TPG passed in.\n", TargetPortGroup)); status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpUpdateTargetPortGroupDevicesStates; } // // First update TPG's asymmetric access state. // TargetPortGroup->AsymmetricAccessState = NewState; // // Now update state of each of the devices belonging to this TPG. // for (entry = TargetPortGroup->TargetPortList.Flink; entry != &TargetPortGroup->TargetPortList; entry = entry->Flink) { targetPort = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry); NT_ASSERT(targetPort); if (targetPort) { PLIST_ENTRY deviceEntry; PDSM_TARGET_PORT_DEVICELIST_ENTRY tp_device; for (deviceEntry = targetPort->TP_DeviceList.Flink; deviceEntry != &targetPort->TP_DeviceList; deviceEntry = deviceEntry->Flink) { tp_device = CONTAINING_RECORD(deviceEntry, DSM_TARGET_PORT_DEVICELIST_ENTRY, ListEntry); if (tp_device) { tp_device->DeviceInfo->ALUAState = NewState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupDevicesStates (TPG %p): Updated device %p alua state to %x.\n", TargetPortGroup, tp_device->DeviceInfo, tp_device->DeviceInfo->ALUAState)); } } } } __Exit_DsmpUpdateTargetPortGroupDevicesStates: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpUpdateTargetPortGroupDevicesStates (TPG %p): Exiting function with status %x.\n", TargetPortGroup, status)); return status; } VOID DsmpIncrementCounters( _In_ PDSM_FAILOVER_GROUP FailGroup, _In_ PSCSI_REQUEST_BLOCK Srb ) { ULONG bytes = 0; PCDB cdb = NULL; ULONG cdbLength = 0; BOOLEAN isReadWrite = FALSE; ULONGLONG lastLba = 0; ULONG numBlocks = 0; ULONGLONG startLba = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpIncrementCounters (FOG %p): Entering function.\n", FailGroup)); if (Srb) { cdb = SrbGetCdb(Srb); if (cdb && DsmIsReadWrite(cdb->AsByte[0])) { isReadWrite = TRUE; } } InterlockedIncrement(&FailGroup->NumberOfRequestsInFlight); // // Update counters that apply to read/write requests // if (isReadWrite) { bytes = SrbGetDataTransferLength(Srb); InterlockedExchangeAdd64((LONGLONG volatile*)&FailGroup->OutstandingBytesOfIO, bytes); cdbLength = SrbGetCdbLength(Srb); if (cdbLength == 16) { REVERSE_BYTES_QUAD(&startLba, &cdb->CDB16.LogicalBlock); REVERSE_BYTES(&numBlocks, &cdb->CDB16.TransferLength); } else { REVERSE_BYTES(&startLba, &cdb->CDB10.LogicalBlockByte0); REVERSE_BYTES_SHORT(&numBlocks, &cdb->CDB10.TransferBlocksMsb); } lastLba = startLba + numBlocks - 1; InterlockedExchange64((LONGLONG volatile*)&FailGroup->LastLba, lastLba); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpIncrementCounters (FOG %p): Exiting function.\n", FailGroup)); return; } BOOLEAN DsmpDecrementCounters( _In_ PDSM_FAILOVER_GROUP FailGroup, _In_ PSCSI_REQUEST_BLOCK Srb ) { ULONG bytes = 0; PCDB cdb = NULL; BOOLEAN isReadWrite = FALSE; BOOLEAN isDeletionEligible = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpDecrementCounters (FOG %p): Entering function.\n", FailGroup)); if (Srb) { cdb = SrbGetCdb(Srb); if (cdb && DsmIsReadWrite(cdb->AsByte[0])) { isReadWrite = TRUE; } } // // Update counters that apply to read/write requests // if (isReadWrite) { bytes = SrbGetDataTransferLength(Srb); InterlockedExchangeAdd64((LONGLONG volatile*)&FailGroup->OutstandingBytesOfIO, -(LONGLONG)bytes); } NT_ASSERT(FailGroup->NumberOfRequestsInFlight > 0); if (InterlockedCompareExchange(&FailGroup->NumberOfRequestsInFlight, 0, 0) > 0) { if(InterlockedDecrement(&FailGroup->NumberOfRequestsInFlight) == 0){ // // If the inflight requests on the path is zero, if needed path can be removed. // isDeletionEligible = TRUE; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpDecrementCounters (FOG %p): Exiting function.\n", FailGroup)); return isDeletionEligible; } PDSM_FAILOVER_GROUP DsmpGetPath( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmList, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine will pick a path, for processing a request, based on the current LoadBalance policy that is set. N.B: This routine must be called with DSM Context Lock held in Shared mode. Arguments: DsmContext - DSM context given to MPIO during initialization DsmList - List of DSM Ids sent by MPIO Srb - The read/write/verify request SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: FailOver Group that should be used for processing the request --*/ { // // Algorithm: // ========== // Failover-only: // -------------- // If symmetric LUA (ie. ALUA not supported, or symmetric LUA using ALUA semantics (viz. storage reports // implicit-only transitions and all TPGs in A/O): // One path AO, <- this will be the only path used for I/O // M paths in SB, <- one of these will be made active on failure of the above active path // Rest of the paths Failed (Invalidated/PendingRemove/Removed) // // If ALUA: // One path AO, <- this will be the only path used for I/O // M paths in AU, SB or UA <- one of these made active on failover. Pref: AU > SB > UA. Also, controller affinity. // Rest of the paths Failed // // Automatic failback will happen only if Preferred path has been set. // This is the only policy that will support failback. // // Round-Robin: // ------------ // If symmetric LUA: // N paths AO, <- round robin among these // Rest of the paths Failed // // If ALUA: // Round Robin policy not supported since all paths can't be in A/O state. // // Round-Robin With Subset: // ------------------------ // If symmetric LUA: // N paths AO, <- round robin among these // M paths SB, <- if no active paths left, make one of these active // Rest of the paths Failed // // If ALUA: // N paths AO, <- round robin among these (NOTE: paths in AU not considered) // M paths AU, SB or UA <- if no active paths, make subset of these active (based on TPG states after transition) // Rest of the paths Failed // // Least-Queue Depth: // ------------------ // If symmetric LUA: // N paths AO, <- one with least outstanding I/O is chosen // Rest of the paths Failed // // If ALUA: // N paths AO, <- one with least outstanding I/O is chosen // M paths AU, SB or UA <- if no AO paths available, subset of these become active (based on TPG // states after transition) - one with least outstanding I/O is chosen. // Rest of the paths Failed // // Least-Weighted: // --------------- // If symmetric LUA: // N paths AO, <- every path has an associated weight, path with least weight is used. // Rest of the paths Failed // // If ALUA: // N paths AO, // M paths AU, SB or UA <- if no AO paths available, subset of these become active (based on TPG // states after transition) - path with least weight used. // Rest of the paths Failed // // Least-Blocks: // ------------- // If symmetric LUA: // N paths AO, <- one with least cumulative outstanding IO is chosen // Rest of the paths Failed // // If ALUA: // N paths AO, <- one with least cumulative outstanding IO is chosen // M paths AU, SB or UA <- if no AO paths available, subset of these become active (based on TPG // states after transition) - one with least cumulative outstanding is chosen. // // Actual implementation of algorithm happens in the following routines: DsmpGetAnyActivePath, // DsmpGetActivePathToBeUsed, flavors of DsmpSetLBForPathXXX. // PDSM_FAILOVER_GROUP failGroup = NULL; PDSM_DEVICE_INFO deviceInfo = DsmList->IdList[0]; PDSM_GROUP_ENTRY groupEntry; ULONG inx = 0; UNREFERENCED_PARAMETER(DsmContext); UNREFERENCED_PARAMETER(SpecialHandlingFlag); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Entering function.\n", DsmList)); if (!(DsmList->Count && deviceInfo)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Called with no available paths.\n", DsmList)); goto __Exit_DsmpGetPath; } groupEntry = deviceInfo->Group; DSM_ASSERT(groupEntry->GroupSig == DSM_GROUP_SIG); switch (groupEntry->LoadBalanceType) { case DSM_LB_FAILOVER: case DSM_LB_WEIGHTED_PATHS: { // // For FailOverOnly there is only one active path so we can // just grab it from the cached location and go with it. // For LeastWeightPath we always choose the lowest weighted // one so we grab that and go // failGroup = groupEntry->PathToBeUsed; break; } case DSM_LB_ROUND_ROBIN: case DSM_LB_ROUND_ROBIN_WITH_SUBSET: { PDSM_DEVICE_INFO candidateDevice = NULL; PDSM_GROUP_ENTRY newGroup = NULL; ULONG newPath; BOOLEAN foundPath = FALSE; ULONG jnx = 0; ULONG counter = 0; BOOLEAN reset = FALSE; for (inx = 0; inx < DsmList->Count; inx++) { deviceInfo = DsmList->IdList[inx]; if (!(deviceInfo && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo))) { continue; } if (deviceInfo->FailGroup == groupEntry->PathToBeUsed) { // // We've reached the devInfo that corresponds to the path // that we should be using. If this devInfo is not in the // right state to be used, we need to find the first candidate // starting from this one to satisfy the request. // To play it safe, we may have already considered a previous // devInfo to be a candidate, that now needs to be reset to // the one that we now find. // reset = TRUE; } #if DBG if (deviceInfo->TargetPortGroup && !DsmpIsDeviceFailedState(deviceInfo->State)) { if (deviceInfo->State != deviceInfo->ALUAState) { DSM_ASSERT(groupEntry->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET && deviceInfo->State == DSM_DEV_ACTIVE_UNOPTIMIZED && deviceInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED); } } #endif if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) { if (!candidateDevice || reset) { candidateDevice = deviceInfo; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Candidate device %p.\n", DsmList, candidateDevice)); jnx = inx; } if (!groupEntry->PathToBeUsed || deviceInfo->FailGroup == groupEntry->PathToBeUsed) { // // The devInfo that corresponds to the path that we were // supposed to use, is in a state that makes it usable. // So we've found our devInfo. // InterlockedExchangePointer(&(groupEntry->PathToBeUsed), (PVOID)deviceInfo->FailGroup); foundPath = TRUE; candidateDevice = NULL; break; } } } if (!foundPath) { if (candidateDevice) { InterlockedExchangePointer(&(groupEntry->PathToBeUsed), (PVOID)candidateDevice->FailGroup); inx = jnx; candidateDevice = NULL; } else { inx = 0; } } failGroup = groupEntry->PathToBeUsed; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Path to be used is %p.\n", DsmList, groupEntry->PathToBeUsed)); // // The current chosen path is given by failGroup. Find the next path // that should be chosen in the RoundRobin policy. Start with the // device at index inx + 1, and look for the one with Active state. // for (counter = 0, jnx = inx + 1; counter < DsmList->Count && !newGroup; counter++, jnx++) { newPath = jnx % DsmList->Count; deviceInfo = DsmList->IdList[newPath]; if (!(deviceInfo && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo))) { continue; } if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) { newGroup = deviceInfo->Group; DSM_ASSERT(newGroup == groupEntry); InterlockedExchangePointer(&(newGroup->PathToBeUsed), (PVOID)deviceInfo->FailGroup); TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): New Path is %p.\n", DsmList, newGroup->PathToBeUsed)); break; } } break; } case DSM_LB_DYN_LEAST_QUEUE_DEPTH: { LONG leastQueueDepth = 0x7FFFFFFF; for (inx = 0; inx < DsmList->Count; inx++) { deviceInfo = DsmList->IdList[inx]; if (!(deviceInfo && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo))) { continue; } if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED && deviceInfo->FailGroup->NumberOfRequestsInFlight < leastQueueDepth) { leastQueueDepth = deviceInfo->FailGroup->NumberOfRequestsInFlight; failGroup = deviceInfo->FailGroup; } } if (failGroup) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Path to be used for LQD is %p.\n", DsmList, failGroup)); } else { // // For ALUA storage there are two cases where we are left with no // TPG in the A/O state: // 1) On storage that supports implicit transitions, a transition // was initiated that left no TPG in the A/O state. // 2) On storage that has explicit only transitions enabled, we tried // making at least one path as A/O and failed. This can happen, // for example, when STPG fails because this initiator is not // registered or does not hold exclusive reservation over the // target. // // For such storages, we should return some path instead of just // failing the I/O. The path will likely be an A/U path until the // storage does a transition to make a TPG A/O. // if (!DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmList->IdList[0])) { // // Use the same path as the one used for the previous request. // failGroup = groupEntry->PathToBeUsed; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpGetPath (DsmIds %p): Using same path (FOG %p) as previous request for LQD.\n", DsmList, failGroup)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Failed to find a path for LQD.\n", DsmList)); } } break; } case DSM_LB_LEAST_BLOCKS: { ULONG bytes = 0; PCDB cdb = NULL; ULONG cdbLength = 0; BOOLEAN isRead = FALSE; BOOLEAN isWrite = FALSE; PDSM_FAILOVER_GROUP lastPathUsed = groupEntry->PathToBeUsed; ULONGLONG leastOutstandingIO = MAXULONGLONG; ULONGLONG startLba = 0; // // Use the last path under the following conditions: // // 1. This is not a read/write request or // 2. This is a read/write request and // a. The request is sequential and // b. The cache is not exhausted // if (Srb) { cdb = SrbGetCdb(Srb); if (cdb && DsmIsReadRequest(cdb->AsByte[0])) { isRead = TRUE; } if (cdb && DsmIsWriteRequest(cdb->AsByte[0])) { isWrite = TRUE; } } if (isRead || isWrite) { if (groupEntry->UseCacheForLeastBlocks) { bytes = SrbGetDataTransferLength(Srb); cdbLength = SrbGetCdbLength(Srb); if (cdbLength == 16) { REVERSE_BYTES_QUAD(&startLba, &cdb->CDB16.LogicalBlock); } else { REVERSE_BYTES(&startLba, &cdb->CDB10.LogicalBlockByte0); } // // Check if: // 1. The IO is sequential, AND // 2. It is either: // a. read request, OR // b. write request and outstanding bytes will be within the cache limit // if ((lastPathUsed != NULL) && (startLba >= lastPathUsed->LastLba) && ((isRead) || (isWrite && lastPathUsed->OutstandingBytesOfIO + bytes <= groupEntry->CacheSizeForLeastBlocks))) { failGroup = groupEntry->PathToBeUsed; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Sequential IO, so using same path %p for LeastBlocks.\n", DsmList, failGroup)); } } } else { // // The request is neither a read nor a write so use the same path. // failGroup = groupEntry->PathToBeUsed; } if (!failGroup) { // // Choose whichever Active/Optimized path has the least outstanding bytes. // for (inx = 0; inx < DsmList->Count; inx++) { deviceInfo = DsmList->IdList[inx]; if (!(deviceInfo && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo))) { continue; } if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED && deviceInfo->FailGroup->OutstandingBytesOfIO < leastOutstandingIO) { leastOutstandingIO = deviceInfo->FailGroup->OutstandingBytesOfIO; failGroup = deviceInfo->FailGroup; } } } if (failGroup) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Path to be used for LeastBlocks is %p.\n", DsmList, failGroup)); } else { // // For ALUA storage there are two cases where we are left with no // TPG in the A/O state: // 1) On storage that supports implicit transitions, a transition // was initiated that left no TPG in the A/O state. // 2) On storage that has explicit only transitions enabled, we tried // making at least one path as A/O and failed. This can happen, // for example, when STPG fails because this initiator is not // registered or does not hold exclusive reservation over the // target. // // For such storages, we should return some path instead of just // failing the I/O. The path will likely be an A/U path until the // storage does a transition to make a TPG A/O. // if (!DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmList->IdList[0])) { // // Use the same path as the one used for the previous request. // failGroup = groupEntry->PathToBeUsed; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpGetPath (DsmIds %p): Using same path (FOG %p) as previous request for LeastBlocks.\n", DsmList, failGroup)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Failed to find a path for LeastBlocks.\n", DsmList)); } } break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Invalid LB Type %d set for group %p.\n", DsmList, groupEntry->LoadBalanceType, groupEntry)); DSM_ASSERT(FALSE); break; } } __Exit_DsmpGetPath: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpGetPath (DsmIds %p): Exiting function with failGroup %p.\n", DsmList, failGroup)); return failGroup; } PVOID DsmpGetPathIdFromPassThroughPath( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmList, _In_ PIRP Irp, _Inout_ IN OUT NTSTATUS *Status ) /*++ Routine Description: This routine will pick the path that corresponds to the PathId in the mpio pass through structure. NOTE: Caller must ensure that the IRP is either MPTP or MPTPD. Arguments: DsmContext - DSM context given to MPIO during initialization DsmList - List of DSM Ids sent by MPIO Irp - The MPTP or MPTPD request Status - Returned status Return Value: The PathId to which the request should be sent --*/ { PDSM_FAILOVER_GROUP failGroup = NULL; PDSM_GROUP_ENTRY groupEntry; PDSM_DEVICE_INFO deviceInfo; ULONG inx = 0; NTSTATUS status = STATUS_INVALID_PARAMETER; KIRQL irql; PVOID newPath = NULL; BOOLEAN found = FALSE; BOOLEAN useScsiAddress = FALSE; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; UCHAR pathId = 0; UCHAR targetId = 0; UCHAR portNumber = 0; ULONGLONG mpioPathId = 0; #if DBG BOOLEAN useMpioPathId = FALSE; #endif // // Extract the parameters from the passthrough based on the bitness of the // process (32 or 64) and the type of passthrough (legacy or extended). // #if defined (_WIN64) if (IoIs32bitProcess(Irp)) { if (DsmpIsMPIOPassThroughEx(controlCode)) { PMPIO_PASS_THROUGH_PATH32_EX mpioPassThroughPath32 = (PMPIO_PASS_THROUGH_PATH32_EX)(Irp->AssociatedIrp.SystemBuffer); PSCSI_PASS_THROUGH32_EX passThrough32 = (PSCSI_PASS_THROUGH32_EX)((PUCHAR)mpioPassThroughPath32 + mpioPassThroughPath32->PassThroughOffset); useScsiAddress = mpioPassThroughPath32->Flags & MPIO_IOCTL_FLAG_USE_SCSIADDRESS; #if DBG useMpioPathId = mpioPassThroughPath32->Flags & MPIO_IOCTL_FLAG_USE_PATHID; #endif if (useScsiAddress) { PSTOR_ADDRESS address; if (passThrough32->StorAddressOffset < sizeof(SCSI_PASS_THROUGH_EX) || passThrough32->StorAddressLength < sizeof(STOR_ADDRESS)) { *Status = STATUS_INVALID_PARAMETER; return NULL; } address = (PSTOR_ADDRESS)((PUCHAR)passThrough32 + passThrough32->StorAddressOffset); if (address->Type != STOR_ADDRESS_TYPE_BTL8 || address->AddressLength < STOR_ADDR_BTL8_ADDRESS_LENGTH) { *Status = STATUS_INVALID_PARAMETER; return NULL; } pathId = ((PSTOR_ADDR_BTL8)address)->Path; targetId = ((PSTOR_ADDR_BTL8)address)->Target; portNumber = mpioPassThroughPath32->PortNumber; } else { mpioPathId = mpioPassThroughPath32->MpioPathId; } } else { PMPIO_PASS_THROUGH_PATH32 mpioPassThroughPath32 = (PMPIO_PASS_THROUGH_PATH32)(Irp->AssociatedIrp.SystemBuffer); useScsiAddress = mpioPassThroughPath32->Flags & MPIO_IOCTL_FLAG_USE_SCSIADDRESS; #if DBG useMpioPathId = mpioPassThroughPath32->Flags & MPIO_IOCTL_FLAG_USE_PATHID; #endif if (useScsiAddress) { pathId = mpioPassThroughPath32->PassThrough.PathId; targetId = mpioPassThroughPath32->PassThrough.TargetId; portNumber = mpioPassThroughPath32->PortNumber; } else { mpioPathId = mpioPassThroughPath32->MpioPathId; } } } else #endif if (DsmpIsMPIOPassThroughEx(controlCode)) { PMPIO_PASS_THROUGH_PATH_EX mpioPassThroughPath = (PMPIO_PASS_THROUGH_PATH_EX)(Irp->AssociatedIrp.SystemBuffer); PSCSI_PASS_THROUGH_EX passThrough = (PSCSI_PASS_THROUGH_EX)((PUCHAR)mpioPassThroughPath + mpioPassThroughPath->PassThroughOffset); useScsiAddress = mpioPassThroughPath->Flags & MPIO_IOCTL_FLAG_USE_SCSIADDRESS; #if DBG useMpioPathId = mpioPassThroughPath->Flags & MPIO_IOCTL_FLAG_USE_PATHID; #endif if (useScsiAddress) { PSTOR_ADDRESS address; if (passThrough->StorAddressOffset < sizeof(SCSI_PASS_THROUGH_EX) || passThrough->StorAddressLength < sizeof(STOR_ADDRESS)) { *Status = STATUS_INVALID_PARAMETER; return NULL; } address = (PSTOR_ADDRESS)((PUCHAR)passThrough + passThrough->StorAddressOffset); if (address->Type != STOR_ADDRESS_TYPE_BTL8 || address->AddressLength < STOR_ADDR_BTL8_ADDRESS_LENGTH) { *Status = STATUS_INVALID_PARAMETER; return NULL; } pathId = ((PSTOR_ADDR_BTL8)address)->Path; targetId = ((PSTOR_ADDR_BTL8)address)->Target; portNumber = mpioPassThroughPath->PortNumber; } else { mpioPathId = mpioPassThroughPath->MpioPathId; } } else { PMPIO_PASS_THROUGH_PATH mpioPassThroughPath = (PMPIO_PASS_THROUGH_PATH)(Irp->AssociatedIrp.SystemBuffer); useScsiAddress = mpioPassThroughPath->Flags & MPIO_IOCTL_FLAG_USE_SCSIADDRESS; #if DBG useMpioPathId = mpioPassThroughPath->Flags & MPIO_IOCTL_FLAG_USE_PATHID; #endif if (useScsiAddress) { pathId = mpioPassThroughPath->PassThrough.PathId; targetId = mpioPassThroughPath->PassThrough.TargetId; portNumber = mpioPassThroughPath->PortNumber; } else { mpioPathId = mpioPassThroughPath->MpioPathId; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpGetPathIdFromPassThroughPath (DsmIds %p): Entering function.\n", DsmList)); irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); deviceInfo = DsmList->IdList[0]; groupEntry = deviceInfo->Group; DSM_ASSERT(groupEntry->GroupSig == DSM_GROUP_SIG); // // useMpioPathId is BOOLEAN (0 or 1) since MPIO_IOCTL_FLAG_USE_PATHID = 1 // But since MPIO_IOCTL_FLAG_USE_SCSIADDRESS = 0x2, // useScsiAddress could have a value of 2 if set. Use logical NOT to make boolean before comparing below // DSM_ASSERT(useMpioPathId == !useScsiAddress); for (inx = 0; inx < DSM_MAX_PATHS; inx++) { deviceInfo = groupEntry->DeviceList[inx]; if (deviceInfo) { failGroup = deviceInfo->FailGroup; if (failGroup) { if (useScsiAddress) { if (portNumber == deviceInfo->ScsiAddress->PortNumber && pathId == deviceInfo->ScsiAddress->PathId && targetId == deviceInfo->ScsiAddress->TargetId) { found = TRUE; break; } } else { NT_ASSERT(useMpioPathId); if ((ULONGLONG)((ULONG_PTR)(failGroup->PathId)) == mpioPathId) { found = TRUE; break; } } } } } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); if (found) { newPath = failGroup->PathId; status = STATUS_SUCCESS; // // This should not affect the next path chosen based on the // current LB policy, so do NOT update groupEntry->PathToBeUsed // } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpGetPathIdFromPassThroughPath (DsmIds %p): Failed to get corresponding path.\n", DsmList)); } if (Status) { *Status = status; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpGetPathIdFromPassThroughPath (DsmIds %p): Exiting function with path %p and status %x.\n", DsmList, newPath, status)); return newPath; } BOOLEAN DsmpShouldRetryTPGRequest( _In_ IN PVOID SenseData, _In_ IN UCHAR SenseDataSize ) /*++ Routine Description: This routine determines if a Report/Set TargetPortGroup request (sent either as a passThrough or as an IRP_MJ_SCSI) needs to be retried. Arguments: SenseData - Pointer to Sense Data information buffer. SenseDataSize - Size of the passed in sense data buffer. Return Value: TRUE if sense information indicates a retry-able error, else FALSE. --*/ { BOOLEAN retry = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpShouldRetryTPGRequest (SenseData %p): Entering function.\n", SenseData)); // // Two types of conditions need to be retried: // 1. Asymmetric Access State Changed // 2. Asymmetric Access State Transition // // // Check if asymmetric access state changed // retry = DsmpShouldRetryPassThroughRequest(SenseData, SenseDataSize); if (!retry) { BOOLEAN validSense = FALSE; UCHAR senseKey = 0; UCHAR addSenseCode = 0; UCHAR addSenseCodeQualifier = 0; validSense = ScsiGetSenseKeyAndCodes(SenseData, SenseDataSize, SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, &senseKey, &addSenseCode, &addSenseCodeQualifier); if (validSense) { if (senseKey == SCSI_SENSE_NOT_READY) { switch (addSenseCode) { case SCSI_ADSENSE_LUN_NOT_READY: { // // Check if asymmetric access state transitioning // if (addSenseCodeQualifier == SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION) { retry = TRUE; } break; } case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: { if (addSenseCodeQualifier == SCSI_SENSEQ_REPORTED_LUNS_DATA_CHANGED) { retry = TRUE; } break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpShouldRetryTPGRequest (SenseData %p): AddSenseCode %x. Not retrying.\n", SenseData, addSenseCode)); retry = FALSE; break; } } } } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpShouldRetryTPGRequest (SenseData %p): Sense data size %d not big enough.\n", SenseData, SenseDataSize)); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpShouldRetryTPGRequest (SenseData %p): Exiting function with retry %x.\n", SenseData, retry)); return retry; } BOOLEAN DsmpIsDeviceRemoved( _In_ IN PVOID SenseData, _In_ IN UCHAR SenseDataSize ) /*++ Routine Description: This routine evaluate Sense Data and determine if LUN is available or not. Arguments: SenseData - Pointer to Sense Data information buffer. SenseDataSize - Size of the passed in sense data buffer. Return Value: TRUE if device is no longer available, else FALSE. --*/ { BOOLEAN validSense = FALSE; UCHAR senseKey = 0; UCHAR addSenseCode = 0; UCHAR addSenseCodeQualifier = 0; BOOLEAN bRemoved = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpIsDeviceRemoved (SenseData %p): Entering function.\n", SenseData)); validSense = ScsiGetSenseKeyAndCodes(SenseData, SenseDataSize, SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, &senseKey, &addSenseCode, &addSenseCodeQualifier); if (validSense) { // // SPC 3 6.25 suggests response should follow Test Unit Ready responses // For now, we accept Ileegal Request as an indication of device not in available // state. // if (senseKey == SCSI_SENSE_ILLEGAL_REQUEST) { ASSERT(addSenseCodeQualifier == 0); //LOGICAL UNIT NOT SUPPORTED bRemoved = TRUE; } TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpIsDeviceRemoved (SenseData %p): SenseKey %x AddSenseCode %x. Remove %x\n", SenseData, senseKey, addSenseCode, bRemoved)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpIsDeviceRemoved (SenseData %p): Exiting function. Removed %x.\n", SenseData, bRemoved)); return bRemoved; } BOOLEAN DsmpReservationCommand( _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb ) /*++ Routine Description: This routine examines the DeviceIoControlCode and Srb OpCode to determine if this is PR request. Arguments: Irp - The Irp containing Srb. Srb - The current non-read/write Srb. Return Value: TRUE - If it's a special-case command (some reservation-handling request). --*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); UCHAR opCode = 0; BOOLEAN isReservationCommand = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpReservationCommand (Irp %p): Entering function.\n", Irp)); // // Ensure it's a scsi request before checking the opcode. // if (irpStack->MajorFunction == IRP_MJ_SCSI) { PCDB cdb = SrbGetCdb(Srb); if (cdb != NULL) { opCode = cdb->AsByte[0]; if (opCode == SCSIOP_PERSISTENT_RESERVE_IN || opCode == SCSIOP_PERSISTENT_RESERVE_OUT) { // // Set or release a reservation. // isReservationCommand = TRUE; } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpReservationCommand (Irp %p): Exiting function - IsReservationCmd %x.\n", Irp, isReservationCommand)); return isReservationCommand; } BOOLEAN DsmpMpioPassThroughPathCommand( _In_ IN PIRP Irp ) /*++ Routine Description: This routine examines the DeviceIoControlCode to determine whether this is either a mpio pass through or a mpio pass through direct. If so, it needs to be handled via a specific path indicated by the caller. Arguments: Irp - The Irp. Return Value: TRUE - If it is either MPTP or MPTPD. FALSE - Otherwise. --*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ULONG ioctlCode; BOOLEAN isMPTPCommand = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpMpioPassThroughPathCommand (Irp %p): Entering function.\n", Irp)); if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { // // Check whether this is a MPTP, MPTPD, or an extended flavor. // ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; if (ioctlCode == IOCTL_MPIO_PASS_THROUGH_PATH || ioctlCode == IOCTL_MPIO_PASS_THROUGH_PATH_DIRECT || ioctlCode == IOCTL_MPIO_PASS_THROUGH_PATH_EX || ioctlCode == IOCTL_MPIO_PASS_THROUGH_PATH_DIRECT_EX) { isMPTPCommand = TRUE; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpMpioPassThroughPathCommand (Irp %p): Exiting function - IsMpioPassThruPathCmd %!bool!.\n", Irp, isMPTPCommand)); return isMPTPCommand; } VOID DsmpRequestComplete( _In_ IN PVOID DsmId, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PVOID DsmContext ) /*++ Routine Description: This routine is called from mpio's completion routine when the Irp has been completed by the port driver. Currently, it updates some counters and free's the context back to the look-aside list. Arguments: DsmIds - The collection of DSM IDs that pertain to the MPDISK. Irp - Irp containing SRB. Srb - Scsi request block DsmContext - DSM context given to MPIO during initialization Return Value: NONE --*/ { PDSM_DEVICE_INFO deviceInfo = DsmId; PDSM_CONTEXT dsmContext = (PDSM_CONTEXT)DsmContext; UCHAR opCode = 0xFF; ULONG dataTransferLength = 0; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PDSM_FAILOVER_GROUP failGroup = irpStack->Parameters.Others.Argument3; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpRequestComplete (DevInfo %p): Entering function.\n", DsmId)); DSM_ASSERT(DsmContext); if (Srb) { PCDB cdb = SrbGetCdb(Srb); if (cdb) { opCode = cdb->AsByte[0]; } dataTransferLength = SrbGetDataTransferLength(Srb); } // // Extract the interesting bits from the context struct. // if (failGroup) { if (DsmpDecrementCounters(failGroup, Srb)) { // // If there are no requests on a path that is supposed to be removed, remove it now. // if (failGroup->State == DSM_FG_PENDING_REMOVE) { KIRQL oldIrql; NT_ASSERT(failGroup->Count == 0); oldIrql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock)); RemoveEntryList(&failGroup->ListEntry); InterlockedDecrement((LONG volatile*)&dsmContext->NumberStaleFOGroups); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpRequestComplete (DevInfo %p): Removing FOGroup %p with path %p.\n", DsmId, failGroup, failGroup->PathId)); DsmpFreePool(failGroup); ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), oldIrql); } } } // // Note: We use the deviceInfo passed in since the one saved off in the // context may be stale in the case of a retried I/O // if (deviceInfo) { // // If statistics gathering is enabled update the inflight request count // for this device-path pairing. // if (!dsmContext->DisableStatsGathering) { // // Indicate one less request on this device. // Update the path that on which the increment was done. // if (InterlockedCompareExchange((LONG volatile*)&deviceInfo->NumberOfRequestsInProgress, 0, 0) > 0) { InterlockedDecrement(&(deviceInfo->NumberOfRequestsInProgress)); } } // // If statistics gathering is enabled, we are interested in read/write requests // if (!dsmContext->DisableStatsGathering) { // // If it's a read or a write, update the stats. // Use the path that was cached during dispatch. // if (DsmIsReadRequest(opCode)) { if (deviceInfo->DeviceStats.NumberReads <= MAXULONG) { InterlockedIncrement((LONG volatile*)&deviceInfo->DeviceStats.NumberReads); } if ((MAXULONGLONG - dataTransferLength) > deviceInfo->DeviceStats.BytesRead) { deviceInfo->DeviceStats.BytesRead += dataTransferLength; } else { deviceInfo->DeviceStats.BytesRead = MAXULONGLONG; } } else if (DsmIsWriteRequest(opCode)) { if (deviceInfo->DeviceStats.NumberWrites <= MAXULONG) { InterlockedIncrement((LONG volatile*)&deviceInfo->DeviceStats.NumberWrites); } if ((MAXULONGLONG - dataTransferLength) > deviceInfo->DeviceStats.BytesWritten) { deviceInfo->DeviceStats.BytesWritten += dataTransferLength; } else { deviceInfo->DeviceStats.BytesWritten = MAXULONGLONG; } } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpRequestComplete (DevInfo %p): Exiting function.\n", DsmId)); return; } NTSTATUS DsmpRegisterPersistentReservationKeys( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN BOOLEAN Register ) /*++ Routine Description: This routine is used to build and send down the request to register or unregister the persistent reservation keys to the device down the path given by DeviceInfo. Arguments: DeviceInfo - Device-path pair to use for sending down the request Register - Flag to indicate whether to register or unregister the keys. Return Value: STATUS_SUCCESS on success, else appropriate failure code. --*/ { PSCSI_PASS_THROUGH_WITH_BUFFERS passThrough = NULL; PCDB cdb; PPRO_PARAMETER_LIST parameters; IO_STATUS_BLOCK ioStatus; NTSTATUS status = STATUS_SUCCESS; ULONG length; PDSM_DEVICE_INFO deviceInfo = DeviceInfo; PDSM_GROUP_ENTRY group; ULONGLONG saKey; PAGED_CODE(); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpRegisterPersistentReservationKeys (DevInfo %p): Entering function - Register = %x.\n", deviceInfo, Register)); group = DeviceInfo->Group; NT_ASSERT(group && group->PRKeyValid); if (DeviceInfo->State >= DSM_DEV_FAILED) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpRegisterPersistentReservationKeys (DevInfo %p): Unusable - state %d.\n", deviceInfo, deviceInfo->State)); status = STATUS_UNSUCCESSFUL; goto __Exit_DsmpRegisterPersistentReservationKeys; } // // Build a pass through command to process Persistent Reserve Out // for registering the device. // length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS); passThrough = DsmpAllocatePool(NonPagedPoolNx, length, DSM_TAG_PASS_THRU); if (!passThrough) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpRegisterPersistentReservationKeys (DevInfo %p): Failed to allocate memory for persistent reserve.\n", deviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegisterPersistentReservationKeys; } REVERSE_BYTES_QUAD(&saKey, &group->PersistentReservationRegisteredKey); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpRegisterPersistentReservationKeys (DevInfo %p): Attempting PR-Out SA %u, Type %u, Scope %u, PR-Key %I64x.\n", deviceInfo, group->PRServiceAction, group->PRType, group->PRScope, saKey)); __RetryRequest: // // Build the cdb to reserve the device (Logical Unit). The type of reservation // scope and service action is whatever cluster service provided at the time of // sending down registration to this device before this particular path was available. // cdb = (PCDB) passThrough->ScsiPassThrough.Cdb; cdb->PERSISTENT_RESERVE_OUT.OperationCode = SCSIOP_PERSISTENT_RESERVE_OUT; cdb->PERSISTENT_RESERVE_OUT.ServiceAction = group->PRServiceAction; cdb->PERSISTENT_RESERVE_OUT.Scope = group->PRScope; cdb->PERSISTENT_RESERVE_OUT.Type = group->PRType; cdb->PERSISTENT_RESERVE_OUT.ParameterListLength[1] = sizeof(PRO_PARAMETER_LIST); passThrough->ScsiPassThrough.Length = sizeof(SCSI_PASS_THROUGH); passThrough->ScsiPassThrough.CdbLength = 10; passThrough->ScsiPassThrough.SenseInfoLength = SPTWB_SENSE_LENGTH; passThrough->ScsiPassThrough.DataIn = 0; passThrough->ScsiPassThrough.DataTransferLength = sizeof(PRO_PARAMETER_LIST); passThrough->ScsiPassThrough.TimeOutValue = 20; passThrough->ScsiPassThrough.SenseInfoOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseInfoBuffer); passThrough->ScsiPassThrough.DataBufferOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuffer); parameters = (PPRO_PARAMETER_LIST)(passThrough->DataBuffer); // // Copy the persistent reservation key given by cluster service to // Service Action Reservation Key. This key will be registered // with the device. // // Set ServiceActionReservationKey to the well-known key if we are registering. // Note that to unregister ServiceActionReservationKey needs to be set to 0. // if (Register) { RtlCopyMemory(parameters->ServiceActionReservationKey, group->PersistentReservationRegisteredKey, 8); } else { RtlCopyMemory(parameters->ReservationKey, group->PersistentReservationRegisteredKey, 8); RtlZeroMemory(parameters->ServiceActionReservationKey, 8); } DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH, DeviceInfo->TargetObject, passThrough, passThrough, length, length, FALSE, &ioStatus); status = ioStatus.Status; if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(ioStatus.Status))) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpRegisterPersistentReservationKeys (DevInfo %p): Persistent Reserve (Register Key) succeeded using %p.\n", deviceInfo, DeviceInfo)); } else { PUCHAR senseData; UCHAR senseInfoLength; senseData = (PUCHAR)(passThrough->SenseInfoBuffer); senseInfoLength = passThrough->ScsiPassThrough.SenseInfoLength; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpRegisterPersistentReservationKeys (DevInfo %p): DevInfo %p, Register keys (%d): NTStatus %x, ScsiStatus %x.\n", deviceInfo, DeviceInfo, Register, ioStatus.Status, passThrough->ScsiPassThrough.ScsiStatus)); if (DsmpShouldRetryPassThroughRequest((PVOID)senseData, senseInfoLength)) { length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS); RtlZeroMemory(passThrough, length); goto __RetryRequest; } else if (NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpRegisterPersistentReservationKeys (DevInfo %p): Will change success to error status for register\n", deviceInfo)); status = STATUS_INVALID_DEVICE_REQUEST; } } // // Free the passthrough + data buffer. // DsmpFreePool(passThrough); __Exit_DsmpRegisterPersistentReservationKeys: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpRegisterPersistentReservationKeys (DevInfo %p): Exiting function with status %x.\n", DeviceInfo, status)); return status; } BOOLEAN DsmpShouldRetryPassThroughRequest( _In_ IN PVOID SenseData, _In_ IN UCHAR SenseDataSize ) /*++ Routine Description: This routine determines if a passthrough request needs to be retried based on the information in the passed in sense data. Arguments: SenseData - Pointer to Sense Data information buffer. SenseDataSize - Size of the passed in sense data buffer. Return Value: TRUE if sense information indicates a retry-able error, else FALSE. --*/ { BOOLEAN validSense = FALSE; UCHAR senseKey = 0; UCHAR addSenseCode = 0; BOOLEAN retry = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpShouldRetryPassThroughRequest (SenseData %p): Entering function.\n", SenseData)); #if DBG if (SenseDataSize > 0) { ULONG inx; PUCHAR senseInfo; senseInfo = (PUCHAR) SenseData; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpShouldRetryPassThroughRequest (SenseData %p): Sense info length %d. Sense Info : ", SenseData, SenseDataSize)); for (inx = 0; inx < SenseDataSize; inx++) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "%x ", senseInfo[inx])); } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "\n")); } #endif validSense = ScsiGetSenseKeyAndCodes(SenseData, SenseDataSize, SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, &senseKey, &addSenseCode, NULL); if (validSense) { if (senseKey == SCSI_SENSE_UNIT_ATTENTION) { switch (addSenseCode) { case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: case SCSI_ADSENSE_BUS_RESET: case SCSI_ADSENSE_PARAMETERS_CHANGED: { retry = TRUE; break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpShouldRetryPassThroughRequest (SenseData %p): AddSenseCode %x. Not retrying.\n", SenseData, addSenseCode)); retry = FALSE; break; } } } } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpShouldRetryPassThroughRequest (SenseData %p): Sense data size %d not big enough.\n", SenseData, SenseDataSize)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpShouldRetryPassThroughRequest (SenseData %p): Exiting function with retry %x.\n", SenseData, retry)); return retry; } BOOLEAN DsmpShouldRetryPersistentReserveCommand( _In_ IN PVOID SenseData, _In_ IN UCHAR SenseDataSize ) /*++ Routine Description: This routine determines if a a PR request needs to be retried based on the information in the passed in sense data. Arguments: SenseData - Pointer to Sense Data information buffer. SenseDataSize - Size of the passed in sense data buffer. Return Value: TRUE if sense information indicates a retry-able error, else FALSE. --*/ { BOOLEAN retry = FALSE; BOOLEAN validSense = FALSE; UCHAR senseKey = 0; UCHAR addSenseCode = 0; UCHAR addSenseCodeQualifier = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpShouldRetryPersistentReserveCommand (SenseData %p): Entering function.\n", SenseData)); retry = DsmpShouldRetryPassThroughRequest(SenseData, SenseDataSize); if (!retry) { validSense = ScsiGetSenseKeyAndCodes(SenseData, SenseDataSize, SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, &senseKey, &addSenseCode, &addSenseCodeQualifier); if (validSense) { // // If the TPG is in transitioning state, retry the request // if ((senseKey == SCSI_SENSE_UNIT_ATTENTION || senseKey == SCSI_SENSE_NOT_READY) && (addSenseCode == SCSI_ADSENSE_LUN_NOT_READY && addSenseCodeQualifier == SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION)) { retry = TRUE; } } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpShouldRetryPersistentReserveCommand (SenseData %p): Sense data size %d not big enough.\n", SenseData, SenseDataSize)); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpShouldRetryPersistentReserveCommand (SenseData %p): Exiting function with retry %x.\n", SenseData, retry)); return retry; } VOID DsmpAllowStandbyPathsToRest( _In_ PDSM_GROUP_ENTRY Group ) /*++ Routine Description: This routine is called when a new path is available for a device and has a desired state of ACTIVE_O. Since this will be an ACTIVE_O path we see if there are any paths with a desired state of Standby but that are currently active. These paths can be safely moved by to standby. This routine assumes that the lock is held Arguements: Group is the multipath group Return Value: None --*/ { PDSM_DEVICE_INFO existingDeviceInfo; ULONG inx; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpAllowStandbyPathsToRest (Group %p): Entering function.\n", Group)); for (inx = 0; inx < Group->NumberDevices; inx++) { existingDeviceInfo = Group->DeviceList[inx]; if ((existingDeviceInfo->DesiredState == DSM_DEV_STANDBY) && (existingDeviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED)) { existingDeviceInfo->State = DSM_DEV_STANDBY; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpAllowStandbyPathsToRest (Group %p): DevInfo %p changed to state %d at %d\n", Group, existingDeviceInfo, existingDeviceInfo->State, __LINE__)); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpAllowStandbyPathsToRest (Group %p): Exiting function.\n", Group)); return; } PDSM_DEVICE_INFO DsmpGetAnyActivePath( _In_ PDSM_GROUP_ENTRY Group, _In_ BOOLEAN Exception, _In_opt_ PDSM_DEVICE_INFO DeviceInfo, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine will return an active path from the list This routine assumes that the DSM lock is held Arguements: Group is the multipath group Exception - if TRUE, indicates that the returned devInfo must not be the same as the one passed in. DeviceInfo - the must-not-match devInfo. Valid parameter only if Exception is TRUE. SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: active path or NULL --*/ { PDSM_DEVICE_INFO existingDeviceInfo; PDSM_DEVICE_INFO candidateDevInfo = NULL; ULONG inx; UNREFERENCED_PARAMETER(SpecialHandlingFlag); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpGetAnyActivePath (Group %p): Entering function.\n", Group)); for (inx = 0; inx < DSM_MAX_PATHS; inx++) { existingDeviceInfo = Group->DeviceList[inx]; if (existingDeviceInfo && existingDeviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED && DsmpIsDeviceInitialized(existingDeviceInfo) && DsmpIsDeviceUsable(existingDeviceInfo) && DsmpIsDeviceUsablePR(existingDeviceInfo)) { if (Exception && existingDeviceInfo == DeviceInfo) { continue; } candidateDevInfo = existingDeviceInfo; break; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpGetAnyActivePath (Group %p): Exiting function with DevInfo %p\n", Group, candidateDevInfo)); return candidateDevInfo; } PDSM_DEVICE_INFO DsmpGetActivePathToBeUsed( _In_ PDSM_GROUP_ENTRY Group, _In_ BOOLEAN Symmetric, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine will return an active path from the list that should be the next one used by the DSM This routine assumes that the DSM lock is held Arguements: Group is the multipath group SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: active path or NULL --*/ { PDSM_DEVICE_INFO deviceInfo; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpGetActivePathToBeUsed (Group %p): Entering function.\n", Group)); deviceInfo = NULL; switch (Group->LoadBalanceType) { case DSM_LB_LEAST_BLOCKS: case DSM_LB_DYN_LEAST_QUEUE_DEPTH: { // // Since we choose the path with the smallest queue or cumulative size in // DsmpGetPath, we just pick any path now // // fall through } case DSM_LB_ROUND_ROBIN_WITH_SUBSET: case DSM_LB_ROUND_ROBIN: { // // For RR and RRS we just pick any active path to start with // and the DsmpGetPath will do the round robining // } case DSM_LB_FAILOVER: { deviceInfo = DsmpGetAnyActivePath(Group, FALSE, NULL, SpecialHandlingFlag); break; } case DSM_LB_WEIGHTED_PATHS: { PDSM_DEVICE_INFO workDeviceInfo; ULONG weight = (ULONG) -1; ULONG inx; for (inx = 0; inx < Group->NumberDevices; inx++) { workDeviceInfo = Group->DeviceList[inx]; if ((workDeviceInfo) && (DsmpIsDeviceInitialized(workDeviceInfo)) && (DsmpIsDeviceUsable(workDeviceInfo)) && (DsmpIsDeviceUsablePR(workDeviceInfo)) && (workDeviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) && (workDeviceInfo->PathWeight < weight)) { // // We found a path that is active and is at // the lowest weight. Remember it. // weight = workDeviceInfo->PathWeight; deviceInfo = workDeviceInfo; } } break; } default: { break; } } if (!deviceInfo && !Symmetric) { // // In the case of implicit transitions, it is possible that a TPG hasn't yet // been made A/O. So instead of not setting any path, fall back to using some // other path. IO sent down this path may fail, but will be retried in // InterpretError(). Hopefully by then, at least one TPG will have transitioned // to A/O state. // // The same argument holds true if the storage supports both implicit and // explicit transitions, since it is possible that after we explicitly changed // the TPG states, an implicit transition left us with no path in A/O state. // // In the case of explicit only transitions, we tried making at least one path // as A/O and failed. This can happen, for example, when STPG fails because // this initiator is not registered or does not hold exclusive reservation over // the target. Instead of not using any path, we can consider a path in A/U state, // A/U being just a functional path state. // BOOLEAN sendTPG = FALSE; deviceInfo = DsmpFindStandbyPathToActivateALUA(Group, &sendTPG, SpecialHandlingFlag); if ((deviceInfo != NULL) && ((deviceInfo->ALUASupport != DSM_DEVINFO_ALUA_EXPLICIT) || ((deviceInfo->ALUASupport == DSM_DEVINFO_ALUA_EXPLICIT) && (deviceInfo->State <= DSM_DEV_ACTIVE_UNOPTIMIZED)))) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpGetActivePathToBeUsed (Group %p): Using best alternative candidate device %p\n", Group, deviceInfo)); } else { deviceInfo = NULL; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpGetActivePathToBeUsed (Group %p): No active/alternative path available for group\n", Group)); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpGetActivePathToBeUsed (Group %p): Exiting function with devInfo %p.\n", Group, deviceInfo)); return deviceInfo; } PDSM_DEVICE_INFO DsmpFindStandbyPathToActivate( _In_ PDSM_GROUP_ENTRY Group, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine will find another path in the group that is active This routine assumes that the DSM lock is held This is used by devices that support symmetric LUA. Arguements: Group is the multipath group SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Standby path or NULL if no standby path is available --*/ { PDSM_DEVICE_INFO existingDeviceInfo; ULONG inx; PDSM_DEVICE_INFO candidateDevInfo = NULL; UNREFERENCED_PARAMETER(SpecialHandlingFlag); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindStandbyPathToActivate(Group %p): Entering function.\n", Group)); for (inx = 0; inx < Group->NumberDevices; inx++) { existingDeviceInfo = Group->DeviceList[inx]; if (existingDeviceInfo && existingDeviceInfo->State == DSM_DEV_STANDBY && DsmpIsDeviceInitialized(existingDeviceInfo) && DsmpIsDeviceUsable(existingDeviceInfo) && DsmpIsDeviceUsablePR(existingDeviceInfo)) { // // If we don't as yet have a candidate, pick the first available one. // However, our preference is one that is through the preferred TPG. // if (!candidateDevInfo || existingDeviceInfo->TargetPortGroup && existingDeviceInfo->TargetPortGroup->Preferred) { candidateDevInfo = existingDeviceInfo; } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindStandbyPathToActivate (Group %p): Exiting function with devInfo %p.\n", Group, candidateDevInfo)); return candidateDevInfo; } PDSM_DEVICE_INFO DsmpFindStandbyPathToActivateALUA( _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PBOOLEAN SendTPG, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine will find another path in the group that is active This is used by devices that don't support symmetric LUA. N.B: This routine MUST be called with DsmContextLock held in either Shared or Exclusive mode. Arguements: Group is the multipath group SendTPG - output parameter that indicates if TPG command need to be sent down. SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Standby path or NULL if no standby path is available --*/ { PDSM_DEVICE_INFO existingDeviceInfo; ULONG inx; PDSM_DEVICE_INFO candidateDevInfo = NULL; UNREFERENCED_PARAMETER(SpecialHandlingFlag); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindStandbyPathToActivateALUA (Group %p): Entering function.\n", Group)); for (inx = 0; inx < Group->NumberDevices; inx++) { existingDeviceInfo = Group->DeviceList[inx]; // // The candidate for making A/O obviously mustn't be in a failed state // and should have a path assigned. // if (existingDeviceInfo && !DsmpIsDeviceFailedState(existingDeviceInfo->State) && DsmpIsDeviceInitialized(existingDeviceInfo) && DsmpIsDeviceUsable(existingDeviceInfo) && DsmpIsDeviceUsablePR(existingDeviceInfo)) { // // If we don't have any candidate currently, choose the very first // one that is in a non-failure state, regardless of what state it // may be in. // if (!candidateDevInfo) { candidateDevInfo = existingDeviceInfo; *SendTPG = TRUE; } // // Might as well use one that the Admin desires for to be in A/O // if (existingDeviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) { // // However, such a devInfo is not a better candidate if our candidate // devInfo is also one that the Admin desires be in A/O, and it is // through a preferred TPG. // if (!(existingDeviceInfo->DesiredState == candidateDevInfo->DesiredState && candidateDevInfo->TargetPortGroup->Preferred)) { candidateDevInfo = existingDeviceInfo; *SendTPG = TRUE; } } // // Check if the current one is at least better than the candidate. // if (DsmpIsBetterDeviceState(candidateDevInfo->State, existingDeviceInfo->State)) { candidateDevInfo = existingDeviceInfo; *SendTPG = TRUE; } // // We found one that we may have just masked as non-A/O. This is the // best option as we don't have to send down an STPG. // if (existingDeviceInfo->ALUAState == DSM_DEV_ACTIVE_OPTIMIZED) { candidateDevInfo = existingDeviceInfo; *SendTPG = FALSE; break; } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindStandbyPathToActivateALUA (Group %p): Exiting function with devInfo %p.\n", Group, candidateDevInfo)); return candidateDevInfo; } PDSM_DEVICE_INFO DsmpFindStandbyPathInAlternateTpgALUA( _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine will find another path in the group that is not in the same TPG as the passed in DeviceInfo. This routine assumes that the DSM lock is held This is used by devices that support ALUA. Arguements: Group is the multipath group DeviceInfo is the devInfo whose TPG must not be matched SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Standby path not in same TPG as passed in DeviceInfo or NULL if no standby path is available --*/ { PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = DeviceInfo->TargetPortGroup; PDSM_DEVICE_INFO existingDeviceInfo; ULONG inx; PDSM_DEVICE_INFO candidateDevInfo = NULL; UNREFERENCED_PARAMETER(SpecialHandlingFlag); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindStandbyPathInAlternateTpgALUA (DevInfo %p): Entering function.\n", DeviceInfo)); for (inx = 0; inx < Group->NumberDevices; inx++) { existingDeviceInfo = Group->DeviceList[inx]; // // We only care about deviceInfo if TPG is different // if (existingDeviceInfo && existingDeviceInfo->TargetPortGroup != targetPortGroup) { // // The candidate for making A/O obviously mustn't be in a failed state // and must be initialized // if (!DsmpIsDeviceFailedState(existingDeviceInfo->State) && DsmpIsDeviceInitialized(existingDeviceInfo) && DsmpIsDeviceUsable(existingDeviceInfo) && DsmpIsDeviceUsablePR(existingDeviceInfo)) { // // If we don't have any candidate currently, choose the very first // one that is in a non-failure state, regardless of what state it // may be in. // if (!candidateDevInfo) { candidateDevInfo = existingDeviceInfo; continue; } // // Check if the current one is at least better than the candidate. // if (DsmpIsBetterDeviceState(candidateDevInfo->State, existingDeviceInfo->State)) { candidateDevInfo = existingDeviceInfo; } } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFindStandbyPathInAlternateTpgALUA (DevInfo %p): Exiting function with devInfo %p.\n", DeviceInfo, candidateDevInfo)); return candidateDevInfo; } NTSTATUS DsmpSetLBForDsmPolicyAdjustment( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONGLONG PreferredPath ) /*++ Routine Description: This routine is called when a change is made to the DSM-wide default load balance policy. It goes through each LUN representation (ie. Group entry) and updates the appropriate ones (ie. ones for which the policy was not chosen based on VID/PID or because of an explicit settings on the LUN). It also then updates the path states in accordance with the new LB policy. Arguements: DsmContext is the DSM context LoadBalanceType is the new load balance policy to be applied PreferredPath is the preferred failback path to be used (applicable only if LB policy is Failover) Return Value: Success --*/ { NTSTATUS status = STATUS_SUCCESS; KIRQL oldIrql; PLIST_ENTRY entry; ULONG groupIndex = 0; ULONG devInfoIndex; PDSM_GROUP_ENTRY group; PDSM_DEVICE_INFO devInfo; DSM_LOAD_BALANCE_TYPE newLoadBalancePolicy; ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSetLBForDsmPolicyAdjustment (DsmContext %p): Entering function.\n", DsmContext)); oldIrql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); for (entry = DsmContext->GroupList.Flink; entry != &(DsmContext->GroupList); entry = entry->Flink, groupIndex++) { group = CONTAINING_RECORD(entry, DSM_GROUP_ENTRY, ListEntry); newLoadBalancePolicy = LoadBalanceType; // // Only LUNs that don't have their policy explicitly set // and ones that don't have it set based on VID/PID are // of interest to us here. // if (group->LBPolicySelection == DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY || group->LBPolicySelection == DSM_DEFAULT_LB_POLICY_DSM_WIDE) { // // Also, if the caller is trying to clear the DSM-wide // default policy, then we don't even care about those // LUNs whose policies were not set using this value. // if (newLoadBalancePolicy < DSM_LB_FAILOVER && group->LBPolicySelection != DSM_DEFAULT_LB_POLICY_DSM_WIDE) { continue; } // // If the DSM-wide setting is being cleared, we need to fall back // to using the default based on the array's ALUA capabilities. // if (newLoadBalancePolicy < DSM_LB_FAILOVER) { newLoadBalancePolicy = DSM_LB_ROUND_ROBIN; group->PreferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG); group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY; } else { // // Since a new policy has been selected for the DSM-wide // one, it needs to be applied to this LUN. // group->PreferredPath = (ULONGLONG)((ULONG_PTR)PreferredPath); group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_DSM_WIDE; } // // If Round Robin is set and ALUA is enabled, we need to change the // policy to Round Robin with Subset. // if (!DsmpIsSymmetricAccess(group->DeviceList[0]) && newLoadBalancePolicy == DSM_LB_ROUND_ROBIN) { newLoadBalancePolicy = DSM_LB_ROUND_ROBIN_WITH_SUBSET; } // // Finally set the new load balance policy. // group->LoadBalanceType = newLoadBalancePolicy; // // Path states need to be updated in accordance with the new policy. // for (devInfoIndex = 0; devInfoIndex < DSM_MAX_PATHS; devInfoIndex++) { devInfo = group->DeviceList[devInfoIndex]; DsmpSetNewDefaultLBPolicy(DsmContext, devInfo, group->LoadBalanceType, SpecialHandlingFlag); } } } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), oldIrql); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSetLBForDsmPolicyAdjustment (DsmContext %p): Exiting function with status %x\n", DsmContext, status)); return status; } NTSTATUS DsmpSetLBForVidPidPolicyAdjustment( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PWSTR TargetHardwareId, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONGLONG PreferredPath ) /*++ Routine Description: This routine is called when a change is made to the default load balance policy for a VID/PID. It goes through each LUN representation (ie. Group entry) and updates the appropriate ones (ie. ones for which the policy was not because of an explicit settings on the LUN). It also then updates the path states in accordance with the new LB policy. Arguements: DsmContext is the DSM context TargetHardwareId is the VID/PID whose matching LUNs policy need to be updated LoadBalanceType is the new load balance policy to be applied PreferredPath is the preferred failback path to be used (applicable only if LB policy is Failover) Return Value: Success --*/ { NTSTATUS status = STATUS_SUCCESS; KIRQL oldIrql; PLIST_ENTRY entry; ULONG groupIndex = 0; ULONG devInfoIndex; PDSM_GROUP_ENTRY group; PDSM_DEVICE_INFO devInfo; DSM_LOAD_BALANCE_TYPE dsmLoadBalanceType; ULONGLONG dsmPreferredPath; BOOLEAN useDsmLBSettings = FALSE; ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSetLBForVidPidPolicyAdjustment (%ws): Entering function.\n", TargetHardwareId)); status = DsmpQueryDsmLBPolicyFromRegistry(&dsmLoadBalanceType, &dsmPreferredPath); if (NT_SUCCESS(status)) { useDsmLBSettings = TRUE; } else { if (status == STATUS_OBJECT_NAME_NOT_FOUND) { status = STATUS_SUCCESS; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DsmpSetLBForVidPidPolicyAdjustment (%ws): MSDSM-wide default LB policy not set.\n", TargetHardwareId)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLBForVidPidPolicyAdjustment (%ws): Failed to query MSDMS-wide default LB setting. Status %x.\n", TargetHardwareId, status)); } } oldIrql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); for (entry = DsmContext->GroupList.Flink; entry != &(DsmContext->GroupList); entry = entry->Flink, groupIndex++) { group = CONTAINING_RECORD(entry, DSM_GROUP_ENTRY, ListEntry); // // Only LUNs that don't have their policy explicitly set // are of interest to us here. // if (group->LBPolicySelection < DSM_DEFAULT_LB_POLICY_LUN_EXPLICIT) { // // Figure out if this LUN matches the VID/PID of interest // Device not of interest if it doesn't match the passed in target ID // if (wcscmp(group->HardwareId, TargetHardwareId) != 0) { continue; } // // Also, if the caller is trying to clear the VID/PID // default policy, then we don't even care about those // LUNs whose policies were not set using this value. // if (LoadBalanceType < DSM_LB_FAILOVER && group->LBPolicySelection != DSM_DEFAULT_LB_POLICY_VID_PID) { continue; } // // If the VID/PID setting is being cleared, we need to fall back // to using the DSM-wide default policy if it has been set, else // we need to use the default based on the array's ALUA capabilities. // if (LoadBalanceType < DSM_LB_FAILOVER) { if (useDsmLBSettings) { // // Even if the MSDSM-wide policy is specified as RR, if the storage // is ALUA, we can't have the policy as RR, so we'll change it to // RRWS instead. // if (!DsmpIsSymmetricAccess(group->DeviceList[0]) && dsmLoadBalanceType == DSM_LB_ROUND_ROBIN) { group->LoadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET; } else { group->LoadBalanceType = dsmLoadBalanceType; } group->PreferredPath = (ULONGLONG)((ULONG_PTR)dsmPreferredPath); group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_DSM_WIDE; } else { // // Default LB type: // is Round Robin if ALUA is not supported, or if ALUA support is implicit but access is symmetric, // else Round Robin With Subset (since in ALUA, all paths aren't in A/O). // if (DsmpIsSymmetricAccess(group->DeviceList[0])) { group->LoadBalanceType = DSM_LB_ROUND_ROBIN; } else { group->LoadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET; } group->PreferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG); group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY; } } else { // // Since a new policy has been selected for the DSM-wide // one, it needs to be applied to this LUN. // // However, if the VID/PID policy is specified as RR but the storage // is ALUA, we can't have the policy as RR, so we'll change it to // RRWS instead. // if (!DsmpIsSymmetricAccess(group->DeviceList[0]) && LoadBalanceType == DSM_LB_ROUND_ROBIN) { group->LoadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET; } else { group->LoadBalanceType = LoadBalanceType; } group->PreferredPath = (ULONGLONG)((ULONG_PTR)PreferredPath); group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_VID_PID; } // // Path states need to be updated in accordance with the new policy. // for (devInfoIndex = 0; devInfoIndex < DSM_MAX_PATHS; devInfoIndex++) { devInfo = group->DeviceList[devInfoIndex]; DsmpSetNewDefaultLBPolicy(DsmContext, devInfo, group->LoadBalanceType, SpecialHandlingFlag); } } } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), oldIrql); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSetLBForVidPidPolicyAdjustment (%ws): Exiting function with status %x\n", TargetHardwareId, status)); return status; } NTSTATUS DsmpSetNewDefaultLBPolicy( _In_ IN PDSM_CONTEXT DsmContext, _In_opt_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine is called to adjust the path state of an instance of a LUN for which a new default load balance policy was applied following an admin request for such a change. This routine must be called with spinlock held. Arguements: DsmContext is the DSM context DeviceInfo is the device info on which the new path state needs to be set LoadBalanceType is the load balance policy in accordance with which the path state needs to be adjusted SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Status --*/ { PDSM_GROUP_ENTRY group; NTSTATUS status = STATUS_SUCCESS; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSetNewDefaultLBPolicy (DevInfo %p): Entering function\n", DeviceInfo)); if (!DeviceInfo) { status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpSetNewDefaultLBPolicy; } if (!(DsmpIsDeviceInitialized(DeviceInfo) && DsmpIsDeviceUsable(DeviceInfo) && DsmpIsDeviceUsablePR(DeviceInfo)) || DsmpIsDeviceFailedState(DeviceInfo->State)) { status = STATUS_UNSUCCESSFUL; goto __Exit_DsmpSetNewDefaultLBPolicy; } group = DeviceInfo->Group; if (!DsmpIsSymmetricAccess(DeviceInfo)) { DsmpAdjustDeviceStatesALUA(group, NULL, SpecialHandlingFlag); } else { switch (LoadBalanceType) { // // For failover, it is important the right path is // chosen, ie. preferred path needs to be taken into // consideration. // case DSM_LB_FAILOVER: { DsmpSetLBForPathArrival(DsmContext, DeviceInfo, SpecialHandlingFlag); break; } // // For all other policies, the state must be A/O. // default: { DeviceInfo->PreviousState = DeviceInfo->State; DeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; break; } } } __Exit_DsmpSetNewDefaultLBPolicy: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSetNewDefaultLBPolicy (DevInfo %p): Exiting function with status %x\n", DeviceInfo, status)); return status; } NTSTATUS DsmpSetLBForPathArrival( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO NewDeviceInfo, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine is called when a new path arrives for a multipath group that doesn't support ALUA. The routine will set the path to the appropriate state and fix up the other paths state if they need to change. This is used by devices NOT supporting ALUA. This routine must be called with spinlock held. Arguements: DsmContext is the DSM context NewDeviceInfo is the device info for the newly arrived path SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Status --*/ { PDSM_GROUP_ENTRY group; PDSM_DEVICE_INFO deviceInfo; NTSTATUS status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (DevInfo %p): Entering function.\n", NewDeviceInfo)); group = NewDeviceInfo->Group; if (!(DsmpIsDeviceInitialized(NewDeviceInfo) && DsmpIsDeviceUsable(NewDeviceInfo) && DsmpIsDeviceUsablePR(NewDeviceInfo))) { // // Bad device instance. Nothing can be done about it. // NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_UNDETERMINED; NT_ASSERT(NewDeviceInfo->FailGroup == NULL); goto __Exit_DsmpSetLBForPathArrival; } if (group->NumberDevices == 1) { // // if this is the only device for the group then we will always // be active as every group must have at least one active path // if (NewDeviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) { // // All's good // goto __Exit_DsmpSetLBForPathArrival; } else { NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (DevInfo %p): State changed to %d at %d\n", NewDeviceInfo, NewDeviceInfo->State, __LINE__)); goto __Exit_DsmpSetLBForPathArrival; } switch(group->LoadBalanceType) { case DSM_LB_FAILOVER: { // // Get the current active path. // deviceInfo = DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag); // // If the newly arriving path is the preferred path, this now should // become our active path. // if (group->PreferredPath == ((ULONGLONG)((ULONG_PTR)(NewDeviceInfo->FailGroup->PathId)))) { // // If current active path is not the preferred path, change its // path state to standby. // if (deviceInfo && deviceInfo != NewDeviceInfo) { deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_STANDBY; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (Group %p): Preferred path back online. DevInfo %p changed to state %d\n", group, deviceInfo, deviceInfo->State)); } NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } else { // // In the case of failover, we must have only a single // active path. If this newly added path is configured as // the one that is desired to be active then we make this // active and set the standby path that was active back to // standby unless the preferred path is the currently active // path. If the newly added path is supposed to be // standby then we leave it as standby. // if (NewDeviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) { if (deviceInfo) { // // If the preferred path is currently active, don't change // it regardless of this path wanting to be in active state. // if (group->PreferredPath == ((ULONGLONG)((ULONG_PTR)(deviceInfo->FailGroup->PathId)))) { if (NewDeviceInfo != deviceInfo) { NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_STANDBY; } } else { // // Since the preferred path is not active, make this // path active since it wants to be so. This means // changing the current active path to standby. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_STANDBY; NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } } else { NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } } else { if (deviceInfo) { if (deviceInfo != NewDeviceInfo) { // // This newly arrived device doesn't want to be in // A/O, and we already have an active path, so make // it standby. // NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_STANDBY; } } else { // // Since we currently don't have an active path, this one // needs to be made active, regardless of its path it wishes // to be in. // NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } } } break; } case DSM_LB_ROUND_ROBIN_WITH_SUBSET: { // // In RRWS, a set of paths can be active and another set of // paths can be standby. We set the new path to the desired // state unless the desired state is standby, but there are // no active paths. Also if the desired state is Active we // need to check if there are any existing paths that are // also active but have a desired state of standby. For // those we can move them back to standby. // if (NewDeviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) { // // We are the active path coming back. Find out who has // been the active one and place him back to standby // DsmpAllowStandbyPathsToRest(group); NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (DevInfo %p): Changed to state %d at %d\n", NewDeviceInfo, NewDeviceInfo->State, __LINE__)); } else { // // if there are no paths already active then we've got // to make this one AO, otherwise we can be non-AO // deviceInfo = DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag); if (!deviceInfo || deviceInfo == NewDeviceInfo) { NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } else { NewDeviceInfo->State = DSM_DEV_STANDBY; } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (%p): Changed to state %d at %d. Status %x\n", NewDeviceInfo, NewDeviceInfo->State, __LINE__, status)); } status = STATUS_SUCCESS; break; } case DSM_LB_LEAST_BLOCKS: case DSM_LB_ROUND_ROBIN: case DSM_LB_DYN_LEAST_QUEUE_DEPTH: case DSM_LB_WEIGHTED_PATHS: { // // In RR, LWP, LB and LQD all paths are active so the new device // becomes AO or AU. // if (NewDeviceInfo->State != DSM_DEV_ACTIVE_OPTIMIZED) { NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (DevInfo %p): Changed to state %d at %d. Status %x\n", NewDeviceInfo, NewDeviceInfo->State, __LINE__, status)); status = STATUS_SUCCESS; break; } default: { status = STATUS_INVALID_PARAMETER; break; } } __Exit_DsmpSetLBForPathArrival: // // Update the next path to be used for the group // deviceInfo = DsmpGetActivePathToBeUsed(group, DsmpIsSymmetricAccess(NewDeviceInfo), SpecialHandlingFlag); if (deviceInfo != NULL) { InterlockedExchangePointer(&(group->PathToBeUsed), (PVOID)deviceInfo->FailGroup); TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (DevInfo %p): Updating PathToBeUsed in %p to %p\n", NewDeviceInfo, group, group->PathToBeUsed)); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (DevInfo %p): No FOG available for group %p\n", NewDeviceInfo, group)); InterlockedExchangePointer(&(group->PathToBeUsed), NULL); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetLBForPathArrival (DevInfo %p): Exiting function with status %x\n", NewDeviceInfo, status)); return status; } NTSTATUS DsmpSetLBForPathArrivalALUA( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO NewDeviceInfo, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine is called when a new path arrives for a multipath group. The routine will set the path to the appropriate state and fix up the other paths state if they need to change. Spin lock must NOT be held by caller Arguements: DsmContext is the DSM context NewDeviceInfo is the device info for the newly arrived path SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Status --*/ { PDSM_GROUP_ENTRY group; PDSM_DEVICE_INFO deviceInfo = NULL; NTSTATUS status = STATUS_SUCCESS; KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 warnings; BOOLEAN lockHeld = FALSE; PDSM_DEVICE_INFO preferredActiveDeviceInfo = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetLBForPathArrivalALUA (DevInfo %p): Entering function.\n", NewDeviceInfo)); group = NewDeviceInfo->Group; if (!(DsmpIsDeviceInitialized(NewDeviceInfo) && DsmpIsDeviceUsable(NewDeviceInfo) && DsmpIsDeviceUsablePR(NewDeviceInfo))) { // // Bad device instance. Nothing can be done about it. // NewDeviceInfo->PreviousState = NewDeviceInfo->State; NewDeviceInfo->State = DSM_DEV_UNDETERMINED; NT_ASSERT(NewDeviceInfo->FailGroup == NULL); goto __Exit_DsmpSetLBForPathArrivalALUA; } irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); lockHeld = TRUE; if (group->NumberDevices == 1) { // // If this is the only device for the group then it should be the // active instance as every group must have at least one active path. // if (NewDeviceInfo->State != DSM_DEV_ACTIVE_OPTIMIZED) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); lockHeld = FALSE; if (NewDeviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) { // // If the device supports explicit transitions, set its state to A/O // status = DsmpSetDeviceALUAState(DsmContext, NewDeviceInfo, DSM_DEV_ACTIVE_OPTIMIZED); } else { // // Since the device supports only implicit transitions, send down // RTPG and hope that the controller has made this one the A/O path. // status = DsmpGetDeviceALUAState(DsmContext, NewDeviceInfo, NULL); if (NT_SUCCESS(status)) { // // Remember that at this point it is possible that this path // is still non-A/O. We'll need to handle this in DsmGetPath // as a special case where we don't find an A/O path but the // storage supports implicit-only transitions. At that time, // we mustn't blindly return a NULL path back. // TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathArrivalALUA (DevInfo %p): RTPG returned state = %x, ALUA state = %x.\n", NewDeviceInfo, NewDeviceInfo->State, NewDeviceInfo->ALUAState)); } } } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathArrivalALUA (DevInfo %p): State changed to %d at %d\n", NewDeviceInfo, NewDeviceInfo->State, __LINE__)); } else { deviceInfo = DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag); // // Irrespecitve of the policy, we must have at least one A/O path. // // For RRWS and FOO, this path is of interest if it is desired to be in A/O. // // Also, for failover-only, this new path is of interest if it is // the preferred path. // // This path is also of interest if it is not A/O and desired state has not // explicitly been set to non-A/O and it has been exposed through the // preferred TPG. // if ((!deviceInfo) || ((NewDeviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) && (group->LoadBalanceType == DSM_LB_FAILOVER || group->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET)) || (group->PreferredPath == (ULONGLONG)((ULONG_PTR)(NewDeviceInfo->FailGroup->PathId)) && group->LoadBalanceType == DSM_LB_FAILOVER) || (NewDeviceInfo->State != DSM_DEV_ACTIVE_OPTIMIZED && NewDeviceInfo->DesiredState == DSM_DEV_UNDETERMINED && NewDeviceInfo->TargetPortGroup->Preferred)) { // // Since this path is supposed to be active, we make it // active and then allow any paths that are supposed to // be standby go back to being standby // ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); lockHeld = FALSE; // // If explicit ALUA is supported, we need to send down STPG to make the change. // if (NewDeviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) { status = DsmpSetDeviceALUAState(DsmContext, NewDeviceInfo, DSM_DEV_ACTIVE_OPTIMIZED); } else { // // If implicit ALUA, the controller may have made some // changes to the TPG states. We just need to query it. // We'll try and honor the Admin's request but can't // guarantee it. // status = DsmpGetDeviceALUAState(DsmContext, NewDeviceInfo, NULL); } // // We prefer this newly arrived devInfo to be A/O // preferredActiveDeviceInfo = NewDeviceInfo; } } if (!lockHeld) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); lockHeld = TRUE; } if (NT_SUCCESS(status)) { DsmpAdjustDeviceStatesALUA(group, preferredActiveDeviceInfo, SpecialHandlingFlag); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathArrivalALUA (DevInfo %p): Trying to query ALUA state failed with %x\n", NewDeviceInfo, status)); } status = STATUS_SUCCESS; __Exit_DsmpSetLBForPathArrivalALUA: // // Update the next path to be used for the group // deviceInfo = DsmpGetActivePathToBeUsed(group, DsmpIsSymmetricAccess(NewDeviceInfo), SpecialHandlingFlag); if (deviceInfo != NULL) { InterlockedExchangePointer(&(group->PathToBeUsed), (PVOID)deviceInfo->FailGroup); TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathArrivalALUA (DevInfo %p): Updating PathToBeUsed in %p to %p\n", NewDeviceInfo, group, group->PathToBeUsed)); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathArrivalALUA (DevInfo %p): No active/alternative path available for group %p\n", NewDeviceInfo, group)); InterlockedExchangePointer(&(group->PathToBeUsed), NULL); } if (lockHeld) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetLBForPathArrivalALUA (DevInfo %p): Exiting function with status %x\n", NewDeviceInfo, status)); return status; } NTSTATUS DsmpSetLBForPathRemoval( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO RemovedDeviceInfo, _In_opt_ IN OPTIONAL PDSM_GROUP_ENTRY Group, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine is called when a path is removed from a multipath group. The routine will set the path to the appropriate state and fix up the other paths state if they need to change. Note: This is used by devices NOT supporting ALUA. Arguements: DsmContext is the DSM context RemovedDeviceInfo is the device info for failing/going-away path Group is an optional group override. That is, if Group is not NULL, this function will run the load balance policy on the given Group and not the Group from the RemovedDeviceInfo. This should only be used when it's impossible to get a pointer to the RemovedDeviceInfo. SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Status --*/ { PDSM_GROUP_ENTRY group; PDSM_DEVICE_INFO deviceInfo; NTSTATUS status = STATUS_SUCCESS; KIRQL irql; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetLBForPathRemoval (DevInfo %p, Group %p): Entering function.\n", RemovedDeviceInfo, Group)); irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); if (Group == NULL) { if (!(DsmpIsDeviceFailedState(RemovedDeviceInfo->State))) { RemovedDeviceInfo->LastKnownGoodState = RemovedDeviceInfo->State; } RemovedDeviceInfo->PreviousState = RemovedDeviceInfo->State; RemovedDeviceInfo->State = DSM_DEV_FAILED; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemoval (DevInfo %p): changed to state %d at %d\n", RemovedDeviceInfo, RemovedDeviceInfo->State, __LINE__)); group = RemovedDeviceInfo->Group; } else { // // The caller has chosen to override the RemovedDeviceInfo->Group. // group = Group; } switch(group->LoadBalanceType) { case DSM_LB_FAILOVER: case DSM_LB_ROUND_ROBIN_WITH_SUBSET: { // // In the case of failover, we must have only a single // active path. If the removed path was the active path we // need to find another path to become active // // In RRWS, a set of paths can be active and another set of // paths can be standby. If the removed path is an active // path then we need to make sure there is another active // path. If there is already another active path then there // is nothing to do. If not then a path needs to be made // active. // if (!DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag)) { deviceInfo = DsmpFindStandbyPathToActivate(group, SpecialHandlingFlag); if (deviceInfo) { deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemoval (DevInfo %p): DevInfo %p changed to state %d at %d\n", RemovedDeviceInfo, deviceInfo, deviceInfo->State, __LINE__)); } } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemoval (DevInfo %p): LB Policy FO/RRWS and other paths active, no path made active at %d\n", RemovedDeviceInfo, __LINE__)); } break; } case DSM_LB_LEAST_BLOCKS: case DSM_LB_ROUND_ROBIN: case DSM_LB_WEIGHTED_PATHS: case DSM_LB_DYN_LEAST_QUEUE_DEPTH: { // // In RR, LQD, LB and LWP, all paths are active so we don't // need to worry about activating a new path // TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemoval (DevInfo %p): LB Policy RR, LWP or LQD, no path made active at %d\n", RemovedDeviceInfo, __LINE__)); break; } default: { status = STATUS_INVALID_PARAMETER; break; } } // // Update the next path to be used for the group // deviceInfo = DsmpGetActivePathToBeUsed(group, DsmpIsSymmetricAccess(RemovedDeviceInfo), SpecialHandlingFlag); if (deviceInfo != NULL) { InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemoval (DevInfo %p): Removal: Updating PathToBeUsed in %p to %p\n", RemovedDeviceInfo, group, group->PathToBeUsed)); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathRemoval (DevInfo %p): After remove No FOG available for group %p\n", RemovedDeviceInfo, group)); InterlockedExchangePointer(&(group->PathToBeUsed), NULL); } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetLBForPathRemoval (DevInfo %p): Exiting function with status %x\n", RemovedDeviceInfo, status)); return status; } NTSTATUS DsmpSetLBForPathRemovalALUA( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO RemovedDeviceInfo, _In_opt_ IN OPTIONAL PDSM_GROUP_ENTRY Group, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine is called when a path is removed from a multipath group. The routine will set the path to the appropriate state and fix up the other paths state if they need to change. Note: This should NOT be called with DsmContext Lock held This is used for devices supporting ALUA. Arguements: DsmContext is the DSM context RemovedDeviceInfo is the device info for the failing/going-away path Group is an optional group override. That is, if Group is not NULL, this function will run the load balance policy on the given Group and not the Group from the RemovedDeviceInfo. This should only be used when it's impossible to get a pointer to the RemovedDeviceInfo. SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Status --*/ { PDSM_GROUP_ENTRY group; PDSM_DEVICE_INFO deviceInfo = NULL; NTSTATUS status = STATUS_SUCCESS; KIRQL irql; BOOLEAN lockHeld = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetLBForPathRemovalALUA (DevInfo %p, Group %p): Entering function.\n", RemovedDeviceInfo, Group)); irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); lockHeld = TRUE; if (Group == NULL) { if (!(DsmpIsDeviceFailedState(RemovedDeviceInfo->State))) { RemovedDeviceInfo->LastKnownGoodState = RemovedDeviceInfo->State; } RemovedDeviceInfo->PreviousState = RemovedDeviceInfo->State; RemovedDeviceInfo->State = DSM_DEV_FAILED; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemovalALUA (DevInfo %p): changed to state %d at %d\n", RemovedDeviceInfo, RemovedDeviceInfo->State, __LINE__)); group = RemovedDeviceInfo->Group; } else { // // The caller has chosen to override the RemovedDeviceInfo->Group. // group = Group; } if (group->LoadBalanceType < DSM_LB_FAILOVER || group->LoadBalanceType > DSM_LB_LEAST_BLOCKS) { status = STATUS_INVALID_PARAMETER; } else { // // In the case of failover, we must have only a single // active path. If the removed path was the active path we // need to find another path to become active // // In rest of policies, set of paths can be active and another set of // paths can be standby. If the removed path is an active // path then we need to make sure there is another active // path. If there is already another active path then there // is nothing to do. If not then a path needs to be made // active. // if (!DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag)) { BOOLEAN sendTPG = TRUE; deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag); if (deviceInfo) { if (sendTPG) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); lockHeld = FALSE; // // If explicit transition supported, we need to send down STPG to make the change. // if (deviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) { status = DsmpSetDeviceALUAState(DsmContext, deviceInfo, DSM_DEV_ACTIVE_OPTIMIZED); } else { // // If implicit ALUA, the controller may have made necessary // changes to the TPG states. We just need to query it. // status = DsmpGetDeviceALUAState(DsmContext, deviceInfo, NULL); } if (!lockHeld) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); lockHeld = TRUE; } if (NT_SUCCESS(status)) { DsmpAdjustDeviceStatesALUA(group, deviceInfo, SpecialHandlingFlag); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathRemovalALUA (DevInfo %p): Trying to query for ALUA state failed with status %x\n", RemovedDeviceInfo, status)); } } else { deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } if (NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemovalALUA (DevInfo %p): Device %p changed to state %d at %d\n", RemovedDeviceInfo, deviceInfo, deviceInfo->State, __LINE__)); } } } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemovalALUA (DevInfo %p): Other paths active, no path made active at %d\n", RemovedDeviceInfo, __LINE__)); } status = STATUS_SUCCESS; } // // Update the next path to be used for the group // deviceInfo = DsmpGetActivePathToBeUsed(group, DsmpIsSymmetricAccess(RemovedDeviceInfo), SpecialHandlingFlag); if (deviceInfo != NULL) { InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpSetLBForPathRemovalALUA (DevInfo %p): Removal: Updating PathToBeUsed in %p to %p\n", RemovedDeviceInfo, group, group->PathToBeUsed)); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpSetLBForPathRemovalALUA (DevInfo %p): No active/alternative path available for group %p\n", RemovedDeviceInfo, group)); InterlockedExchangePointer(&(group->PathToBeUsed), NULL); } if (lockHeld) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetLBForPathRemovalALUA (DevInfo %p): Exiting function with status %x.\n", RemovedDeviceInfo, status)); return status; } NTSTATUS DsmpSetLBForPathFailing( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo, _In_ IN BOOLEAN MarkDevInfoFailed, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine is called when an IO that was sent using this path fails with a fatal error. The routine will set the path to the appropriate state and fix up the other paths state if they need to change. Note: This is used by devices NOT supporting ALUA. Arguements: DsmContext is the DSM context FailingDeviceInfo is the device info for the path on which IO failed SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Status --*/ { NTSTATUS status; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpSetLBForPathFailing (DevInfo %p): Entering function.\n", FailingDeviceInfo)); // // We need to do exactly what DsmpSetLBForPathRemoval() does, except // that the devInfo may not really go away (may come back before a // Pnp remove comes down for the real LUN) // if (MarkDevInfoFailed) { status = DsmpSetLBForPathRemoval(DsmContext, FailingDeviceInfo, NULL, SpecialHandlingFlag); } else { status = DsmpSetLBForPathRemoval(DsmContext, FailingDeviceInfo, FailingDeviceInfo->Group, SpecialHandlingFlag); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpSetLBForPathFailing (DevInfo %p): Exiting function with status %x\n", FailingDeviceInfo, status)); return status; } NTSTATUS DsmpSetLBForPathFailingALUA( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo, _In_ IN BOOLEAN MarkDevInfoFailed, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: This routine is called when an IO that was sent using this path fails with a fatal error. The routine will set the path to the appropriate state and send down a Set Target Port Groups command asynchronously to fix up the other paths state if they need to change (actual work done in the completion routine). Note: This should NOT be called with DsmContext Lock held This is used for devices supporting ALUA. Arguements: DsmContext is the DSM context FailingDeviceInfo is the device info for the failing/going-away path SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: Status --*/ { PDSM_GROUP_ENTRY group; PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL; PDSM_DEVICE_INFO deviceInfo = NULL; NTSTATUS status = STATUS_SUCCESS; KIRQL irql; PUCHAR targetPortGroupsInfo = NULL; ULONG targetPortGroupsInfoLength; PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR tpgDescriptor = NULL; PDSM_COMPLETION_CONTEXT completionContext = NULL; PVOID senseInfo = NULL; PSCSI_REQUEST_BLOCK srb = NULL; PDSM_TPG_COMPLETION_CONTEXT tpgCompletionContext = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Entering function.\n", FailingDeviceInfo)); if (MarkDevInfoFailed) { if (!(DsmpIsDeviceFailedState(FailingDeviceInfo->State))) { FailingDeviceInfo->LastKnownGoodState = FailingDeviceInfo->State; } FailingDeviceInfo->PreviousState = FailingDeviceInfo->State; FailingDeviceInfo->State = DSM_DEV_FAILED; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): changed to state %d at %d\n", FailingDeviceInfo, FailingDeviceInfo->State, __LINE__)); } group = FailingDeviceInfo->Group; if (group->LoadBalanceType < DSM_LB_FAILOVER || group->LoadBalanceType > DSM_LB_LEAST_BLOCKS) { status = STATUS_INVALID_PARAMETER; } else { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); // // Check if there are any active paths that can be used. // deviceInfo = DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag); if (!deviceInfo) { // // Check if an Set/Report TPG has already been sent for this failing devInfo // failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(DsmContext, group, FailingDeviceInfo); if (!failDevInfoListEntry) { BOOLEAN sendTPG = TRUE; deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag); if (deviceInfo) { if (sendTPG) { tpgCompletionContext = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_TPG_COMPLETION_CONTEXT), DSM_TAG_TPG_COMPLETION_CONTEXT); if (tpgCompletionContext) { UCHAR senseInfoLength = SENSE_BUFFER_SIZE_EX; senseInfo = DsmpAllocatePool(NonPagedPoolNx, senseInfoLength, DSM_TAG_SCSI_SENSE_INFO); if (senseInfo) { srb = DsmpAllocatePool(NonPagedPoolNx, sizeof(SCSI_REQUEST_BLOCK), DSM_TAG_SCSI_REQUEST_BLOCK); if (srb) { srb->Length = SCSI_REQUEST_BLOCK_SIZE; srb->Function = SRB_FUNCTION_EXECUTE_SCSI; completionContext = ExAllocateFromNPagedLookasideList(&DsmContext->CompletionContextList); if (completionContext) { // // Update the target port group that needs to be made // active/optimized. We will send down an STPG for // storages that support both implicit and explicit. // If the storage does NOT like our choice of A/O TPG, // it will make an implicit transition. This is still // a better option than solely relying on the storage's // implicit transitions at this stage and ending up with // no path in A/O state. // if (deviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) { targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR); } else { // // Find an active/optimized target port group that should // have been set by the controller // // Take care of worst case scenario, which is: // 1. 4-byte header (for allocation length) // 2. 32 8-byte descriptors (for TPGs) // 3. Each descriptor containing 32 4-byte identifiers (for TPs in each TPG) // targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + (DSM_MAX_PATHS * (sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) + DSM_MAX_PATHS * sizeof(ULONG))); } targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx, targetPortGroupsInfoLength, DSM_TAG_TARGET_PORT_GROUPS); if (targetPortGroupsInfo) { failDevInfoListEntry = DsmpBuildFailPathDevInfoEntry(DsmContext, group, FailingDeviceInfo, deviceInfo); ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); if (failDevInfoListEntry) { tpgDescriptor = (PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)(targetPortGroupsInfo + SPC3_TARGET_PORT_GROUPS_HEADER_SIZE); tpgDescriptor->AsymmetricAccessState = DSM_DEV_ACTIVE_OPTIMIZED; REVERSE_BYTES_SHORT(&tpgDescriptor->TPG_Identifier, &deviceInfo->TargetPortGroup->Identifier); // // Prevent the device info from being removed when a TPG is in-flight. // InterlockedIncrement(&FailingDeviceInfo->BlockRemove); completionContext->DeviceInfo = FailingDeviceInfo; completionContext->DsmContext = DsmContext; completionContext->RequestUnique1 = deviceInfo; completionContext->RequestUnique2 = FALSE; tpgCompletionContext->CompletionContext = completionContext; tpgCompletionContext->Srb = srb; tpgCompletionContext->SenseInfoBuffer = senseInfo; tpgCompletionContext->SenseInfoBufferLength = senseInfoLength; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Sending down TPG asynchronously for %p using devInfo %p (path %p).\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId, deviceInfo, deviceInfo->FailGroup->PathId)); if (deviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) { status = DsmpSetTargetPortGroupsAsync(deviceInfo, DsmpPhase1ProcessPathFailingALUA, tpgCompletionContext, targetPortGroupsInfoLength, targetPortGroupsInfo); } else { status = DsmpReportTargetPortGroupsAsync(deviceInfo, DsmpPhase2ProcessPathFailingALUA, tpgCompletionContext, targetPortGroupsInfoLength, targetPortGroupsInfo); } if (status != STATUS_PENDING) { // // Request not sent down successfully. Free the allocations. // DsmpFreePool(targetPortGroupsInfo); ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext); DsmpFreePool(srb); DsmpFreePool(senseInfo); DsmpFreePool(tpgCompletionContext); // // Allow the failing device to be removed. // InterlockedDecrement(&FailingDeviceInfo->BlockRemove); } } else { // // Fail to build DevInfo entry. Free the allocations. // DsmpFreePool(targetPortGroupsInfo); ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext); DsmpFreePool(srb); DsmpFreePool(senseInfo); DsmpFreePool(tpgCompletionContext); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext); DsmpFreePool(srb); DsmpFreePool(senseInfo); DsmpFreePool(tpgCompletionContext); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); NT_ASSERT(completionContext != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Failed to allocate completion context. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); DsmpFreePool(srb); DsmpFreePool(senseInfo); DsmpFreePool(tpgCompletionContext); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); NT_ASSERT(srb != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Failed to allocate SRB. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); DsmpFreePool(senseInfo); DsmpFreePool(tpgCompletionContext); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); NT_ASSERT(senseInfo != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Failed to allocate senseInfo. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); DsmpFreePool(tpgCompletionContext); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); NT_ASSERT(tpgCompletionContext != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Failed to allocate TPG completion context. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Found alternative devInfo %p for failing path %p without need for TPG\n", FailingDeviceInfo, deviceInfo, FailingDeviceInfo->FailGroup->PathId)); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Couldn't find a standby path to activate for failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); deviceInfo = failDevInfoListEntry->TempDeviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): There is an RTPG/STPG already in progress for this path %p. Returning alternative %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId, deviceInfo)); } } else { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Other paths active, no path made active at %d\n", FailingDeviceInfo, __LINE__)); } status = STATUS_SUCCESS; } if (deviceInfo) { // // Update temporarily the next path to be used for the group as this devInfo // InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Updating PathToBeUsed in %p to %p\n", FailingDeviceInfo, group, group->PathToBeUsed)); } else { InterlockedExchangePointer(&(group->PathToBeUsed), NULL); TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpSetLBForPathRemovalALUA (DevInfo %p): No FOG available for group %p\n", FailingDeviceInfo, group)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpSetLBForPathFailingALUA (DevInfo %p): Exiting function with status %x.\n", FailingDeviceInfo, status)); return status; } NTSTATUS DsmpSetPathForIoRetryALUA( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo, _In_ IN BOOLEAN TPGException, _In_ IN BOOLEAN DeviceInfoException ) /*++ Routine Description: This routine is called when an IO that was sent using this path fails with a retry-able "ALUA" error. What this basically means is that most likely an implicit transition has taken place and we need an RTPG to get the updated path states. The routine will send down a Report Target Port Groups command asynchronously to get the paths states (actual work done in the completion routine). Note: This should NOT be called with DsmContext Lock held This is used for devices supporting ALUA. Arguements: DsmContext is the DSM context FailingDeviceInfo is the device info for the failing/going-away path TPGException is a flag used to indicate if the selected path must be from a TPG that is different from FailingDeviceInfo's. This is special handling for UA with sense "TPG in SB/UA state" DeviceInfoException is a flag used to indicate that the current FailindDeviceInfo itself needs to be used again. This is special handling for UA with sense "Asymmetric Access State Changed" (NOTE: TPGException and DeviceInfoException are mutually exclusive, although it is okay for both to be FALSE) Return Value: Status --*/ { PDSM_GROUP_ENTRY group; PDSM_DEVICE_INFO deviceInfo = NULL; NTSTATUS status = STATUS_SUCCESS; KIRQL irql; PUCHAR targetPortGroupsInfo = NULL; ULONG targetPortGroupsInfoLength; PDSM_COMPLETION_CONTEXT completionContext = NULL; PVOID senseInfo = NULL; PSCSI_REQUEST_BLOCK srb = NULL; PDSM_TPG_COMPLETION_CONTEXT tpgCompletionContext = NULL; NTSTATUS throttleStatus = STATUS_UNSUCCESSFUL; ULONG inflightRTPG; ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Entering function.\n", FailingDeviceInfo)); group = FailingDeviceInfo->Group; if (group->LoadBalanceType < DSM_LB_FAILOVER || group->LoadBalanceType > DSM_LB_LEAST_BLOCKS) { status = STATUS_INVALID_PARAMETER; } else { // // First check to see if we need to find a candidate from a different TPG. // if (TPGException) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); // // Find a candidate in a TPG that is different from this one // deviceInfo = DsmpFindStandbyPathInAlternateTpgALUA(group, FailingDeviceInfo, SpecialHandlingFlag); ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Need to try a different TPG deviceInfo %p.\n", FailingDeviceInfo, deviceInfo)); } else if (DeviceInfoException) { // // Retry on the same path // deviceInfo = FailingDeviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Will retry using same deviceInfo %p.\n", FailingDeviceInfo, deviceInfo)); } // // Check if an Report TPG has already been sent for this group // inflightRTPG = InterlockedCompareExchange((LONG volatile*)&group->InFlightRTPG, 0, 0); // // If there is no RTPG currently in flight, use the best candidate found // above to send down the RTPG. If there is already an RTPG inflight, // we're done. The result of the RTPG should fix the path states. // if (!inflightRTPG) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): No RTPG in flight. Try sending one down.\n", FailingDeviceInfo)); // // If we need a candidate device, first get the currently active one. // If we can't find one that way, resort to finding the best alternative. // Basic idea is find SOME path instead of failing IOs back to the application. // if (!deviceInfo) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); // // Find the best candidate - ie. either a currently A/O path or // the best alternative path to be made A/O. // deviceInfo = DsmpGetAnyActivePath(group, TRUE, deviceInfo, SpecialHandlingFlag); if (!deviceInfo) { BOOLEAN sendTPG = TRUE; deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag); TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): No active path. Best alternative %p.\n", FailingDeviceInfo, deviceInfo)); } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); } if (deviceInfo) { tpgCompletionContext = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_TPG_COMPLETION_CONTEXT), DSM_TAG_TPG_COMPLETION_CONTEXT); if (tpgCompletionContext) { UCHAR senseInfoLength = SENSE_BUFFER_SIZE_EX; senseInfo = DsmpAllocatePool(NonPagedPoolNx, senseInfoLength, DSM_TAG_SCSI_SENSE_INFO); if (senseInfo) { srb = DsmpAllocatePool(NonPagedPoolNx, sizeof(SCSI_REQUEST_BLOCK), DSM_TAG_SCSI_REQUEST_BLOCK); if (srb) { srb->Length = SCSI_REQUEST_BLOCK_SIZE; srb->Function = SRB_FUNCTION_EXECUTE_SCSI; completionContext = ExAllocateFromNPagedLookasideList(&DsmContext->CompletionContextList); if (completionContext) { // // Find an active/optimized target port group that should // have been set by the controller // // Take care of worst case scenario, which is: // 1. 4-byte header (for allocation length) // 2. 32 8-byte descriptors (for TPGs) // 3. Each descriptor containing 32 4-byte identifiers (for TPs in each TPG) // targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + (DSM_MAX_PATHS * (sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) + DSM_MAX_PATHS * sizeof(ULONG))); targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx, targetPortGroupsInfoLength, DSM_TAG_TARGET_PORT_GROUPS); if (targetPortGroupsInfo) { completionContext->DeviceInfo = FailingDeviceInfo; completionContext->DsmContext = DsmContext; completionContext->RequestUnique1 = deviceInfo; completionContext->RequestUnique2 = TRUE; tpgCompletionContext->CompletionContext = completionContext; tpgCompletionContext->Srb = srb; tpgCompletionContext->SenseInfoBuffer = senseInfo; tpgCompletionContext->SenseInfoBufferLength = senseInfoLength; // // Now we are all set to send the RTPG request. // check and set InFlightRTPG to make sure this thread is the only one with // the RTPG active for this group, since it is possible to have more than one // threads reaching up to this point in parallel // inflightRTPG = InterlockedCompareExchange((LONG volatile*)&group->InFlightRTPG, 1, 0); if (inflightRTPG) { DsmpFreePool(targetPortGroupsInfo); ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext); DsmpFreePool(srb); DsmpFreePool(senseInfo); DsmpFreePool(tpgCompletionContext); } else { // // Prevent the device info from being removed when a TPG is in-flight. // InterlockedIncrement(&FailingDeviceInfo->BlockRemove); // // First try and throttle the IO. The completion routine will // take care of resuming the IO. // if (!InterlockedCompareExchange((LONG volatile*)&group->Throttled, 1, 0)) { DsmNotification(((PDSM_CONTEXT)DsmContext)->MPIOContext, ThrottleIO_V2, deviceInfo, FALSE, &throttleStatus, 0); if (NT_SUCCESS(throttleStatus)) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Successfully throttled IO. About to send RTPG. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); } else { // // Throttle can fail when the MPDisk is // 1. Being removed. (or) // 2. In any other state other than Normal or Degraded. // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Throttle before RTPG failed. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); InterlockedDecrement((LONG volatile*)&FailingDeviceInfo->Group->Throttled); } } else { // // Currently we don't expect this to happen // NT_ASSERT(FALSE); } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Sending RTPG asynchronously. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); if (STATUS_PENDING != DsmpReportTargetPortGroupsAsync(deviceInfo, DsmpPhase2ProcessPathFailingALUA, tpgCompletionContext, targetPortGroupsInfoLength, targetPortGroupsInfo)) { // // Request not sent down successfully. Free the allocations. // DsmpFreePool(targetPortGroupsInfo); ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext); DsmpFreePool(srb); DsmpFreePool(senseInfo); DsmpFreePool(tpgCompletionContext); // // Allow the failing device to be removed. // InterlockedDecrement(&FailingDeviceInfo->BlockRemove); // // Resume IO if we throttled requests before calling DsmpReportTargetPortGroupsAsync // if (InterlockedCompareExchange((LONG volatile*)&group->Throttled, 0, 1)) { NTSTATUS resumeStatus = STATUS_UNSUCCESSFUL; DsmNotification(((PDSM_CONTEXT)deviceInfo->DsmContext)->MPIOContext, ResumeIO_V2, deviceInfo, TRUE, &resumeStatus, 0); if (!NT_SUCCESS(resumeStatus)) { // // Resume can fail when // 1. The MPDisk is being removed (or) // 2. The MPDisk is any other state other than throttled (or) // 3. There is a problem dispatching throttled requests. // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Resume IO failed.\n", deviceInfo)); } } InterlockedDecrement((LONG volatile*)&group->InFlightRTPG); } } } else { NT_ASSERT(targetPortGroupsInfo != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate TPG info buffer. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext); ExFreePool(srb); ExFreePool(senseInfo); ExFreePool(tpgCompletionContext); } } else { NT_ASSERT(completionContext != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate completion context. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); ExFreePool(srb); ExFreePool(senseInfo); ExFreePool(tpgCompletionContext); } } else { NT_ASSERT(srb != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate SRB. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); ExFreePool(senseInfo); ExFreePool(tpgCompletionContext); } } else { NT_ASSERT(senseInfo != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate senseInfo. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); ExFreePool(tpgCompletionContext); } } else { NT_ASSERT(tpgCompletionContext != NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate TPG completion context. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't find a path for RTPG. Failing path %p.\n", FailingDeviceInfo, FailingDeviceInfo->FailGroup->PathId)); } } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Other paths active, no path made active at %d\n", FailingDeviceInfo, __LINE__)); } if(!deviceInfo) { // // It is possible that there are only two TPGs with one of them in U/A // state and the other in transitioning state. In such a case, we would // not find an alternative TPG deviceInfo. In addition, if there is an // RTPG in flight, we won't go down the path of forcibly picking any // deviceInfo. This is to cover that scenario, else we're left with no // deviceInfo to do the retry and we'll end up setting the group's PTBU // to NULL thus failing the retried request (if for eg. the LB is RRWS). // Need to ensure that we handle this exception case. // if (inflightRTPG) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); // // Find the best candidate - ie. either a currently A/O path or // the best alternative path to be made A/O. // deviceInfo = DsmpGetAnyActivePath(group, TRUE, deviceInfo, SpecialHandlingFlag); if (!deviceInfo) { BOOLEAN sendTPG = TRUE; deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag); } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); } } if(deviceInfo) { // // Update temporarily the next path to be used for the group as this devInfo // InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Updating PathToBeUsed in %p to %p\n", FailingDeviceInfo, group, group->PathToBeUsed)); } else { InterlockedExchangePointer(&(group->PathToBeUsed), NULL); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): No FOG available for group %p\n", FailingDeviceInfo, group)); } status = STATUS_SUCCESS; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpSetPathForIoRetryALUA (DevInfo %p): Exiting function with status %x.\n", FailingDeviceInfo, status)); return status; } PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY DsmpFindFailPathDevInfoEntry( _In_ IN PDSM_CONTEXT Context, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO FailingDevInfo ) /*++ Routine Description: This routine finds the entry that contains the alternate devInfo to use for a failing one for the passed in devInfo. N.B: This routine MUST be called with DsmContextLock held in either Shared or Exclusive mode. Arguments: Context is the DSM's context info. Group is the group entry representing the device. FailingDevInfo is the device info whose entry needs to be found. Return Value: Pointer to the entry. NULL if it doesn't exist. --*/ { PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL; PLIST_ENTRY entry = NULL; UNREFERENCED_PARAMETER(Context); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpFindFailPathDevInfoEntry (DevInfo %p): Entering function.\n", FailingDevInfo)); for (entry = Group->FailingDevInfoList.Flink; entry != &Group->FailingDevInfoList; entry = entry->Flink) { failDevInfoListEntry = CONTAINING_RECORD(entry, DSM_FAIL_PATH_PROCESSING_LIST_ENTRY, ListEntry); NT_ASSERT(failDevInfoListEntry); if (failDevInfoListEntry) { if (failDevInfoListEntry->FailingDeviceInfo == FailingDevInfo) { break; } else { failDevInfoListEntry = NULL; } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpFindFailPathDevInfoEntry (DevInfo %p): Exiting function returning entry %p.\n", FailingDevInfo, failDevInfoListEntry)); return failDevInfoListEntry; } PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY DsmpBuildFailPathDevInfoEntry( _In_ IN PDSM_CONTEXT Context, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO FailingDevInfo, _In_ IN PDSM_DEVICE_INFO AlternateDevInfo ) /*++ Routine Description: When InterpretError() is called with an IRP that has failed with a fatal error, if the device is ALUA it is possible that STPG needs to be sent to update a new devInfo as being Active/Optimized. However, for in-flight IOs that weren't queued by MPIO, we still need to return a path that can be used. This routine is builds an entry that contains the alternate devInfo to use for a failing one. NOTE: Calling function should be holding the spin lock. Arguments: Context is the DSM's context info. Group is the group entry representing the device. FailingDevInfo is the device info that was used when the IRP failed. AlternateDevInfo is the new one to temporarily use until its state can be properly set. Return Value: Pointer to the newly built entry. NULL if there were any errors building it. --*/ { PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL; UNREFERENCED_PARAMETER(Context); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpBuildFailPathDevInfoEntry (DevInfo %p): Entering function.\n", FailingDevInfo)); failDevInfoListEntry = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_FAIL_PATH_PROCESSING_LIST_ENTRY), DSM_TAG_FAIL_DEVINFO_LIST_ENTRY); if (failDevInfoListEntry) { failDevInfoListEntry->FailingDeviceInfo = FailingDevInfo; failDevInfoListEntry->TempDeviceInfo = AlternateDevInfo; InsertTailList(&Group->FailingDevInfoList, &failDevInfoListEntry->ListEntry); InterlockedIncrement((LONG volatile*)&Group->NumberFailingDevInfos); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpBuildFailPathDevInfoEntry (DevInfo %p): Failed to allocate memory for entry.\n", FailingDevInfo)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpBuildFailPathDevInfoEntry (DevInfo %p): Exiting function returning entry %p.\n", FailingDevInfo, failDevInfoListEntry)); return failDevInfoListEntry; } NTSTATUS DsmpPhase1ProcessPathFailingALUA( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This is the completion routine that is called when the STPG is sent down by DsmpSetLBForPathFailingALUA. The caller SHOULD NOT acquire the DSM Context lock before calling this routine. Arguements: DeviceObject is the target device object to which Irp was sent Irp is the scsi pass through request for STPG Context is the completion context. Return Value: Status --*/ { PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); PDSM_TPG_COMPLETION_CONTEXT context = (PDSM_TPG_COMPLETION_CONTEXT)Context; PSCSI_REQUEST_BLOCK srb = context->Srb; PVOID senseData = context->SenseInfoBuffer; UCHAR senseDataLength = context->SenseInfoBufferLength; NTSTATUS status = Irp->IoStatus.Status; ULONG targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR); PUCHAR targetPortGroupsInfo; PDSM_DEVICE_INFO deviceInfo = (PDSM_DEVICE_INFO)(context->CompletionContext->RequestUnique1); PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL; BOOLEAN releaseCompletionContextResources = TRUE; KIRQL irql; UCHAR scsiStatus = SrbGetScsiStatus(srb); UNREFERENCED_PARAMETER(DeviceObject); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpPhase1ProcessPathFailingALUA (DevInfo %p): Entering function.\n", deviceInfo)); #if DBG KeQuerySystemTime(&context->CompletionContext->TickCount); #endif if ((scsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(status))) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpPhase1ProcessPathFailingALUA (DevInfo %p): STPG succeeded.\n", deviceInfo)); } else if (NT_SUCCESS(status) && scsiStatus == SCSISTAT_CHECK_CONDITION && DsmpShouldRetryTPGRequest(senseData, senseDataLength)) { if ((context->NumberRetries)--) { // // Retry the request // NT_ASSERT(SrbGetDataBuffer(srb) == MmGetMdlVirtualAddress(Irp->MdlAddress)); // // Reset byte count of transfer in SRB Extension. // SrbSetDataTransferLength(srb, Irp->MdlAddress->ByteCount); // // Zero SRB statuses. // srb->SrbStatus = 0; SrbSetScsiStatus(srb, 0); nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; nextIrpStack->MinorFunction = IRP_MN_SCSI_CLASS; // // Save SRB address in next stack for port driver. // nextIrpStack->Parameters.Scsi.Srb = srb; IoSetCompletionRoutine(Irp, DsmpPhase1ProcessPathFailingALUA, Context, TRUE, TRUE, TRUE); IoMarkIrpPending(Irp); // // Send the IRP asynchronously // DsmSendRequestEx(context->CompletionContext->DsmContext->MPIOContext, deviceInfo->TargetObject, Irp, deviceInfo, DSM_CALL_COMPLETION_ON_MPIO_ERROR); // // We know that the completion routine will always be called. // status = STATUS_PENDING; goto __Exit_DsmpPhase1ProcessPathFailingALUA; } } else { irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock)); failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, context->CompletionContext->DeviceInfo); if (failDevInfoListEntry) { DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, failDevInfoListEntry); } ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpPhase1ProcessPathFailingALUA (DevInfo %p): NTStatus 0%x, ScsiStatus 0x%x.\n", deviceInfo, status, scsiStatus)); } if (NT_SUCCESS(status)) { // // An explicit transition may cause changes to some other TPGs. // So we need to query for the states of all the TPGs and update // our internal list and its elements. // // // Take care of worst case scenario, which is: // 1. 4-byte header (for allocation length) // 2. 32 8-byte descriptors (for TPGs) // 3. Each descriptor containing 32 4-byte identifiers (for TPs in each TPG) // targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + (DSM_MAX_PATHS * (sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) + DSM_MAX_PATHS * sizeof(ULONG))); targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx, targetPortGroupsInfoLength, DSM_TAG_TARGET_PORT_GROUPS); if (targetPortGroupsInfo) { if (STATUS_PENDING == DsmpReportTargetPortGroupsAsync(deviceInfo, DsmpPhase2ProcessPathFailingALUA, Context, targetPortGroupsInfoLength, targetPortGroupsInfo)) { releaseCompletionContextResources = FALSE; } else { DsmpFreePool(targetPortGroupsInfo); } } else { irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock)); failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, context->CompletionContext->DeviceInfo); if (failDevInfoListEntry) { DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, failDevInfoListEntry); } ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql); } } // // Free the allocations. // IoFreeMdl(Irp->MdlAddress); Irp->MdlAddress = NULL; DsmpFreePool(Irp->UserBuffer); IoFreeIrp(Irp); Irp = (PIRP) NULL; if (releaseCompletionContextResources) { // // Release our hold on the device info so that it can be removed. // InterlockedDecrement(&context->CompletionContext->DeviceInfo->BlockRemove); ExFreeToNPagedLookasideList(&(context->CompletionContext->DsmContext)->CompletionContextList, context->CompletionContext); DsmpFreePool(context->Srb); DsmpFreePool(context->SenseInfoBuffer); #pragma warning(suppress:6001) // DevDiv 818965 DsmpFreePool(context); } __Exit_DsmpPhase1ProcessPathFailingALUA: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpPhase1ProcessPathFailingALUA (DevInfo %p): Exiting function.\n", deviceInfo)); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS DsmpRemoveFailPathDevInfoEntry( _In_ IN PDSM_CONTEXT Context, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY FailPathDevInfoEntry ) /*++ Routine Description: This routine removes the entry pointed to from the passed in Group's list. NOTE: Calling function should be holding the spin lock. Arguments: Context is the DSM's context info. Group is the group entry representing the device. FailingPathDevInfoEntry is the entry that needs to be removed. Return Value: STATUS_SUCCESS if successful, else appropriate NT error code. --*/ { PLIST_ENTRY entry = &FailPathDevInfoEntry->ListEntry; PDSM_DEVICE_INFO deviceInfo = FailPathDevInfoEntry->FailingDeviceInfo; NTSTATUS status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(Context); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpRemoveFailPathDevInfoEntry (DevInfo %p): Entering function.\n", deviceInfo)); RemoveEntryList(entry); DsmpFreePool(FailPathDevInfoEntry); InterlockedDecrement((LONG volatile*)&Group->NumberFailingDevInfos); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpRemoveFailPathDevInfoEntry (DevInfo %p): Exiting function with status %x.\n", deviceInfo, status)); return status; } NTSTATUS DsmpPhase2ProcessPathFailingALUA( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This is the completion routine that is called when the RTPG is sent down by DsmpPhase1ProcessPathFailingALUA. The caller SHOULD NOT acquire the DSM Context lock before calling this routine. Arguements: DeviceObject is the target device object to which Irp was sent Irp is the scsi pass through request for RTPG Context is the completion context. Return Value: Status --*/ { PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); PDSM_TPG_COMPLETION_CONTEXT context = (PDSM_TPG_COMPLETION_CONTEXT)Context; PSCSI_REQUEST_BLOCK srb = context->Srb; PVOID senseData = context->SenseInfoBuffer; UCHAR senseDataLength = context->SenseInfoBufferLength; NTSTATUS status = Irp->IoStatus.Status; PUCHAR header; ULONG returnedDataLength = 0; PUCHAR targetPortGroupsInfo = NULL; ULONG targetPortGroupsInfoLength = 0; PDSM_DEVICE_INFO deviceInfo = (PDSM_DEVICE_INFO)(context->CompletionContext->RequestUnique1); BOOLEAN decrementRTPGcount = (BOOLEAN)(context->CompletionContext->RequestUnique2); KIRQL irql; ULONG index; PDSM_DEVICE_INFO devInfo; PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = NULL; PDSM_GROUP_ENTRY group = deviceInfo->Group; PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL; UCHAR scsiStatus = SrbGetScsiStatus(srb); UNREFERENCED_PARAMETER(DeviceObject); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpPhase2ProcessPathFailingALUA (DevInfo %p): Entering function.\n", deviceInfo)); #if DBG KeQuerySystemTime(&(context->CompletionContext)->TickCount); #endif if ((status == STATUS_BUFFER_OVERFLOW) || (NT_SUCCESS(status) && (scsiStatus == SCSISTAT_GOOD))) { header = (PUCHAR)((PUCHAR)SrbGetDataBuffer(srb)); GetUlongFrom4ByteArray(header, returnedDataLength); status = STATUS_SUCCESS; if (returnedDataLength > SrbGetDataTransferLength(srb)) { status = STATUS_BUFFER_OVERFLOW; } } if ((scsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(status))) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmpPhase2ProcessPathFailingALUA (DevInfo %p): RTPG using path %p succeeded.\n", deviceInfo, deviceInfo->FailGroup->PathId)); header = (PUCHAR)((PUCHAR)SrbGetDataBuffer(srb)); GetUlongFrom4ByteArray(header, returnedDataLength); // // Allocate a buffer to hold the TPG info. // targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx, SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + returnedDataLength, DSM_TAG_TARGET_PORT_GROUPS); if (targetPortGroupsInfo) { targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + returnedDataLength; // // Copy it over. // RtlCopyMemory(targetPortGroupsInfo, header, targetPortGroupsInfoLength); } else { irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock)); failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, context->CompletionContext->DeviceInfo); if (failDevInfoListEntry) { DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, failDevInfoListEntry); } ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpPhase2ProcessPathFailingALUA (DevInfo %p): Failed to allocate mem for TPG.\n", deviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } else if (NT_SUCCESS(status) && scsiStatus == SCSISTAT_CHECK_CONDITION && DsmpShouldRetryTPGRequest(senseData, senseDataLength)) { if ((context->NumberRetries)--) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpPhase2ProcessPathFailingALUA (DevInfo %p): Retrying check condition using path %p. Retries remaining %u.\n", deviceInfo, deviceInfo->FailGroup->PathId, context->NumberRetries)); // // Retry the request // NT_ASSERT(SrbGetDataBuffer(srb) == MmGetMdlVirtualAddress(Irp->MdlAddress)); // // Reset byte count of transfer in SRB Extension to true length. // SrbSetDataTransferLength(srb, targetPortGroupsInfoLength); // // Zero SRB statuses. // srb->SrbStatus = 0; SrbSetScsiStatus(srb, 0); nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; nextIrpStack->MinorFunction = IRP_MN_SCSI_CLASS; // // Save SRB address in next stack for port driver. // nextIrpStack->Parameters.Scsi.Srb = srb; IoSetCompletionRoutine(Irp, DsmpPhase2ProcessPathFailingALUA, Context, TRUE, TRUE, TRUE); IoMarkIrpPending(Irp); // // Send the IRP asynchronously // DsmSendRequestEx(context->CompletionContext->DsmContext->MPIOContext, deviceInfo->TargetObject, Irp, deviceInfo, DSM_CALL_COMPLETION_ON_MPIO_ERROR); // // We know that the completion routine will always be called. // status = STATUS_PENDING; goto __Exit_DsmpPhase2ProcessPathFailingALUA; } } else { irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock)); failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, context->CompletionContext->DeviceInfo); if (failDevInfoListEntry) { DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, failDevInfoListEntry); } ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpPhase2ProcessPathFailingALUA (DevInfo %p): NTStatus 0%x, ScsiStatus 0x%x.\n", deviceInfo, status, SrbGetScsiStatus(srb))); // Failed to get TPG Info. // Here it is possible status is success, but scsiStatus is not. // If so, set status to unsuccessful. if (NT_SUCCESS(status)) { status = STATUS_UNSUCCESSFUL; } } if (NT_SUCCESS(status)) { irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock)); // // Parse the TPG information and update the device path states // status = DsmpParseTargetPortGroupsInformation(context->CompletionContext->DsmContext, deviceInfo->Group, targetPortGroupsInfo, targetPortGroupsInfoLength); for (index = 0; index < DSM_MAX_PATHS; index++) { targetPortGroup = deviceInfo->Group->TargetPortGroupList[index]; if (targetPortGroup) { DsmpUpdateTargetPortGroupDevicesStates(targetPortGroup, targetPortGroup->AsymmetricAccessState); } } if (NT_SUCCESS(status)) { PDSM_DEVICE_INFO tempDevice = NULL; // // Update all the devInfo states. If the device is AO but // not this device, make it fake AU. // If device not in AO, make sure that it matches the TPG // state. // Ensure that: // 1. All devices match their ALUA state. // 2. For RRWS, if a device's desired state is non-A/O, but ALUA state is A/O, mask it. // 3. For FOO there must be only one A/O device. Preferably the preferred path. // for (index = 0; index < DSM_MAX_PATHS; index++) { devInfo = group->DeviceList[index]; if (devInfo) { if (devInfo->ALUAState == DSM_DEV_ACTIVE_OPTIMIZED) { // // In implicit transitions, there is no guarantee that // the TPG of chosen "deviceInfo" is in A/O state. So // to play it safe, we hang on to the very first devInfo // whose TPG is in A/O state. // if (!tempDevice && !DsmpIsDeviceFailedState(devInfo->State)) { devInfo->PreviousState = devInfo->State; devInfo->State = devInfo->ALUAState; tempDevice = devInfo; } if (devInfo != deviceInfo) { if (!DsmpIsDeviceFailedState(devInfo->State)) { // // For FOO, only one path can be in A/O. // For RRWS, mask an A/O path if that isn't the desired state. // if ((group->LoadBalanceType == DSM_LB_FAILOVER) || (group->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET && devInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED && devInfo->DesiredState != DSM_DEV_UNDETERMINED)) { // // For implicit transitions, we may have saved off an A/O path. // Don't undo that. // if (tempDevice != devInfo) { devInfo->PreviousState = devInfo->State; devInfo->State = DSM_DEV_ACTIVE_UNOPTIMIZED; } } else { devInfo->PreviousState = devInfo->State; devInfo->State = devInfo->ALUAState; } } } else { devInfo->PreviousState = devInfo->State; // // For FOO, only one path can be in A/O state. // The TPG of the selected "deviceInfo" is in A/O, so this // can now very well be made the candidate. However, since // it is possible that we saved off another candidate, we // now need to replace that with this. // if (!DsmpIsDeviceFailedState(devInfo->State) && devInfo->Group->LoadBalanceType == DSM_LB_FAILOVER && tempDevice) { tempDevice->State = DSM_DEV_ACTIVE_UNOPTIMIZED; } devInfo->State = devInfo->ALUAState; tempDevice = devInfo; } } else { if (!DsmpIsDeviceFailedState(devInfo->State)) { devInfo->PreviousState = devInfo->State; devInfo->State = devInfo->ALUAState; } } } } } failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, context->CompletionContext->DeviceInfo); if (failDevInfoListEntry) { DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext, context->CompletionContext->DeviceInfo->Group, failDevInfoListEntry); } ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql); } // // Resume IO if we throttled requests. // if (InterlockedCompareExchange((LONG volatile*)&group->Throttled, 0, 1)) { NTSTATUS resumeStatus = STATUS_UNSUCCESSFUL; DsmNotification(((PDSM_CONTEXT)deviceInfo->DsmContext)->MPIOContext, ResumeIO_V2, deviceInfo, TRUE, &resumeStatus, 0); if (!NT_SUCCESS(resumeStatus)) { // // Resume can fail when // 1. The MPDisk is being removed (or) // 2. The MPDisk is any other state other than throttled (or) // 3. There is a problem dispatching throttled requests. // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmpPhase2ProcessPathFailingALUA (DevObj %p): Resume IO failed.\n", DeviceObject)); } } if (decrementRTPGcount) { // // Resetting InFlightRTPG after resume so that we don't get into situation where // new DsmpSetPathForIoRetryALUA caller thread finds that InFlightRTPG is not set but Throttled is set // ULONG count = InterlockedCompareExchange((LONG volatile*)&group->InFlightRTPG, 0, 1); // // If decrementRTPGCount flag is set, there must be atleast one RTPG in flight. // NT_ASSERT(count); UNREFERENCED_PARAMETER(count); } // // Free the allocations. // if (targetPortGroupsInfo) { DsmpFreePool(targetPortGroupsInfo); } // // Release our hold on the device info so that it can be removed. // InterlockedDecrement(&context->CompletionContext->DeviceInfo->BlockRemove); IoFreeMdl(Irp->MdlAddress); Irp->MdlAddress = NULL; DsmpFreePool(Irp->UserBuffer); IoFreeIrp(Irp); Irp = (PIRP) NULL; ExFreeToNPagedLookasideList(&(context->CompletionContext->DsmContext)->CompletionContextList, context->CompletionContext); DsmpFreePool(srb); DsmpFreePool(senseData); #pragma warning(suppress:6001) // DevDiv 818965 DsmpFreePool(context); __Exit_DsmpPhase2ProcessPathFailingALUA: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpPhase2ProcessPathFailingALUA (DevInfo %p): Exiting function.\n", deviceInfo)); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS DsmpPersistentReserveOut( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PKEVENT Event ) /*++ Routine Description: This routine will handle determine which devices to send the request to based on the service action of the PR-out command. On REGISTER/REGISTER_AND_IGNORE_EXISTING, it will send the command down all paths. If any path succeeds, the PR key will be stored. If failure down any path, return failure. On REGISTER/REGISTER_AND_IGNORE_EXISTING with key == 0 (ie. UNREGISTER), the request is sent down every path. Failure is returned if request fails down any path (but error is ignored if path happens to be one where prior REGISTER/REGISTER_AND_IGNORE_EXISTING had failed in the first place). The stored PR key is cleared irrespective of success/failure being returned. On RESERVE/RELEASE, the command is sent down one path. If it fails, another path is tried. Failure is returned only if none succeed. On CLEAR, command is sent down one path. If it fails, another path is tried. Failure is returned only if none succeed. The stored PR key is cleared irrespective of success/failure being returned. On PREEMPT, command is sent down one path. If it fails, another path is tried. Failure is returned only if none succeed. On PREEMPT_AND_ABORT, command is sent down one path. Failed request is not retried. NOTE: If a path shows up later, REGISTER_AND_IGNORE_EXISTING request is built by the IsPathActive routine using the saved PR key and sent down new path. Arguments: DsmContext - DSM context given to MPIO during initialization DsmIds - The collection of DSM IDs that pertain to the MPDISK. Irp - Irp containing SRB. Srb - Scsi request block Event - The event to Return Value: NTSTATUS of the operation. --*/ { PDSM_DEVICE_INFO deviceInfo; PDSM_DEVICE_INFO servicingDeviceInfo = NULL; PDSM_GROUP_ENTRY group; LONG i; ULONG count; NTSTATUS status = STATUS_UNSUCCESSFUL; PDSM_COMPLETION_CONTEXT completionContext; PCDB cdb = SrbGetCdb(Srb); UCHAR serviceAction; NTSTATUS returnStatus = STATUS_SUCCESS; BOOLEAN sendDownAll = FALSE; BOOLEAN savePRKeyIfAnySucceed = FALSE; BOOLEAN retryOnAnother = FALSE; BOOLEAN passOnlyIfAllSucceed = FALSE; BOOLEAN ignoreIfPreviousFailed = FALSE; BOOLEAN clearPRKey = FALSE; KEVENT event; PPRO_PARAMETER_LIST prOutParam = Irp->AssociatedIrp.SystemBuffer; PUCHAR index = NULL; UCHAR prKey[8] = {0}; PSTORAGE_REQUEST_BLOCK_HEADER srbCopy = NULL; PIO_STACK_LOCATION irpStack; PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); BOOLEAN statusUpdated = FALSE; ULONGLONG currentTickCount; ULONGLONG finalTickCount; ULONG tickLength = KeQueryTimeIncrement(); PVOID senseInfoBuffer = NULL; UCHAR senseInfoBufferLength = 0; BOOLEAN srbCopySucceeded = FALSE; UCHAR prType; UCHAR prScope; ULONGLONG saKey; ULONGLONG resKey; ULONG SpecialHandlingFlag = 0; UNREFERENCED_PARAMETER(Event); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): Entering function.\n", DsmIds)); // // Cache away a copy of the SRB // srbCopy = SrbAllocateCopy(Srb, NonPagedPoolNx, DSM_TAG_SCSI_REQUEST_BLOCK); if (srbCopy == NULL) { returnStatus = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpPersistentReserveOut; } deviceInfo = DsmIds->IdList[0]; group = deviceInfo->Group; prType = cdb->PERSISTENT_RESERVE_OUT.Type; prScope = cdb->PERSISTENT_RESERVE_OUT.Scope; serviceAction = cdb->PERSISTENT_RESERVE_OUT.ServiceAction; NT_ASSERT(serviceAction >= RESERVATION_ACTION_REGISTER && serviceAction <= RESERVATION_ACTION_REGISTER_IGNORE_EXISTING); index = prOutParam->ServiceActionReservationKey; RtlCopyMemory(&prKey, index, 8); REVERSE_BYTES_QUAD(&saKey, &prOutParam->ServiceActionReservationKey); REVERSE_BYTES_QUAD(&resKey, &prOutParam->ReservationKey); switch (serviceAction) { case RESERVATION_ACTION_REGISTER: case RESERVATION_ACTION_REGISTER_IGNORE_EXISTING: { // // The command must be sent down all paths. // sendDownAll = TRUE; // // Return failure if it fails down even one of the paths. // passOnlyIfAllSucceed = TRUE; if (DsmpIsPersistentReservationKeyZeroKey(ARRAY_SIZE(prKey), prKey)) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): NULL PR key, service action %u\n", DsmIds, serviceAction)); // // If unregister fails, don't report it back as error if the // previous register/register_and_ignore_existing down that // path had failed too. // ignoreIfPreviousFailed = TRUE; // // Clear the group PR key irrespective of the status that is // going to be returned to clusdisk. // clearPRKey = TRUE; } else { // // If register/register_and_ignore_existing succeed down any of // the paths, save off the PR key for the group entry. // savePRKeyIfAnySucceed = TRUE; } break; } case RESERVATION_ACTION_RESERVE: case RESERVATION_ACTION_RELEASE: case RESERVATION_ACTION_PREEMPT: case RESERVATION_ACTION_PREEMPT_ABORT: case RESERVATION_ACTION_CLEAR: { if (serviceAction != RESERVATION_ACTION_PREEMPT_ABORT) { // // Apart from preempt_abort, all the others must be retried // (down another path) if they fail down the chosen path. // retryOnAnother = TRUE; } if (serviceAction == RESERVATION_ACTION_CLEAR) { // // Clear the stored PR key for the group entry irrespective of // the status that is going to be returned back. // clearPRKey = TRUE; } break; } default: { returnStatus = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): Invalid service action %u.\n", DsmIds, serviceAction)); goto __Exit_DsmpPersistentReserveOut; } } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): Srb %p, Service Action %u, Type %u, Scope %u, \ \n\t\t\t\tservice action reservation key %I64x, reservation key %I64x.\n", DsmIds, Srb, serviceAction, prType, prScope, saKey, resKey)); // // Allocate a context for the completion routine. // completionContext = ExAllocateFromNPagedLookasideList(&DsmContext->CompletionContextList); if (!completionContext) { returnStatus = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - Failed to allocate completion context.\n", DsmIds, serviceAction)); goto __Exit_DsmpPersistentReserveOut; } KeInitializeEvent(&event, NotificationEvent, FALSE); // // Indicate the target for this request. // completionContext->DsmContext = DsmContext; completionContext->RequestUnique1 = (PVOID)&event; completionContext->RequestUnique2 = cdb->PERSISTENT_RESERVE_OUT.OperationCode; count = group->NumberDevices; for (i = count - 1; i >= 0; i--) { // // A PR command may fail with a "retry-able" UA when reservation is // released or preempted (on every I_T_L nexus except the one on which // it was released/preempted). In such a case we should retry the PR // command on the same path. // KeQueryTickCount((PLARGE_INTEGER)¤tTickCount); finalTickCount = currentTickCount + (DSM_SECONDS_TO_TICKS(group->MaxPRRetryTimeDuringStateTransition) / tickLength); if (!sendDownAll && !retryOnAnother) { // // If the request doesn't need to be retried (down another path) on // failure, better choose the path that has maximum chances of // success. // deviceInfo = DsmpGetActivePathToBeUsed(group, DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmIds->IdList[0]), SpecialHandlingFlag); if (!deviceInfo) { returnStatus = STATUS_UNSUCCESSFUL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - No active/alternative path for device %p.\n", DsmIds, serviceAction, group)); break; } } else { deviceInfo = group->DeviceList[i]; // // Ignore "bad" paths for now. If the path becomes "good" again, // IsPathActive() will send down the register. // Also, don't consider newly arrived paths for which the group has // a reservation but register has not yet been sent down. This rule // applies only to requests that are not Register. // if ((DsmpIsDeviceFailedState(deviceInfo->State) || !DsmpIsDeviceInitialized(deviceInfo)) || (!DsmpIsDeviceUsablePR(deviceInfo) && !sendDownAll)) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): Ignoring bad instance - state %x, init %x, key reg %x (key valid %x).\n", DsmIds, deviceInfo->State, deviceInfo->Initialized, deviceInfo->PRKeyRegistered, deviceInfo->Group->PRKeyValid)); deviceInfo = NULL; } } if (!deviceInfo) { // // Maybe a remove came through and caused a collapse of the device // list, thus making this entry empty. // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - Couldn't find path for device %p.\n", DsmIds, serviceAction, group)); continue; } __DsmpPersistentReserveOut_RetryRequest: IoMarkIrpPending(Irp); completionContext->DeviceInfo = deviceInfo; // // Set-up a completion routine. // IoSetCompletionRoutine(Irp, DsmpPersistentReserveCompletion, completionContext, TRUE, TRUE, TRUE); // // Always send the original request down a new path // irpStack = IoGetNextIrpStackLocation(Irp); srbCopySucceeded = SrbCopySrb(Srb, SrbGetSrbLength(Srb), srbCopy); NT_ASSERT(srbCopySucceeded == TRUE); irpStack->Parameters.Scsi.Srb = Srb; // // Clear the sense buffer if it exists // senseInfoBuffer = SrbGetSenseInfoBuffer(Srb); senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb); if (senseInfoBuffer) { RtlZeroMemory(senseInfoBuffer, senseInfoBufferLength); } servicingDeviceInfo = deviceInfo; // // Issue the request and wait. // status = DsmSendRequest(DsmContext->MPIOContext, deviceInfo->TargetObject, Irp, deviceInfo); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); status = Irp->IoStatus.Status; } if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u sent down successfully on %p.\n", DsmIds, serviceAction, deviceInfo->FailGroup->PathId)); if (!passOnlyIfAllSucceed) { // // Success down any one path means success // returnStatus = status; } if (savePRKeyIfAnySucceed) { RtlCopyMemory(&group->PersistentReservationRegisteredKey, &prKey, 8); group->PRServiceAction = serviceAction; group->PRType = prType; group->PRScope = prScope; group->PRKeyValid = TRUE; deviceInfo->PRKeyRegistered = TRUE; } if (!sendDownAll) { // // Need for retrying on another path only necessary in the case // of request failing down the chosen path. Since the request // succeeded down this path, we are done. // break; } } else { BOOLEAN recordFailure; // // Check to see if the request failed because of a "transient error", // like reservations released for example. If so, this is NOT an actual // error and the request must be retried. Multiple retries may be required // if for example the UA indicates that the TPGs are in transitioning state. // if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID && Srb->SrbStatus & SRB_STATUS_ERROR && SrbGetScsiStatus(Srb) == SCSISTAT_CHECK_CONDITION) { KeQueryTickCount((PLARGE_INTEGER)¤tTickCount); senseInfoBuffer = SrbGetSenseInfoBuffer(Srb); senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb); if (DsmpShouldRetryPersistentReserveCommand(senseInfoBuffer, senseInfoBufferLength) && currentTickCount < finalTickCount) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u returned UA with error %x. Retrying same path %p.\n", DsmIds, serviceAction, status, deviceInfo->FailGroup->PathId)); KeResetEvent(&event); Irp->IoStatus.Status = 0; goto __DsmpPersistentReserveOut_RetryRequest; } } // // The return status is STATUS_SUCCESS by default. This means that if the // request failed on the first path and was retried down every other path // but fails down all of them, the return status is never updated. // So cache the first failure status to cover the above scenario. // if (!statusUpdated) { returnStatus = status; statusUpdated = TRUE; } recordFailure = TRUE; if (ignoreIfPreviousFailed && !deviceInfo->PRKeyRegistered) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - Ignoring status %x for path %p.\n", DsmIds, serviceAction, status, deviceInfo->FailGroup->PathId)); // // Okay to ignore this failure if the previous failed. // recordFailure = FALSE; } if (passOnlyIfAllSucceed && recordFailure) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - Saving status %x for return.\n", DsmIds, serviceAction, status)); // // Save the failure status to return back. // returnStatus = status; } // // If the request is not to be sent down all paths, and also // a retry (along a different path) on failure is not required, // we're done - just return this failure. // if (!(sendDownAll || retryOnAnother)) { returnStatus = status; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u sent down %p failed with %x. Breaking out.\n", DsmIds, serviceAction, deviceInfo->FailGroup->PathId, status)); break; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u sent down %p failed with %x. Sending down another path.\n", DsmIds, serviceAction, deviceInfo->FailGroup->PathId, status)); } } // // If we are here, it is either because the request needs to be sent down // all paths, or because the request failed down the chosen path and needs // to be retried down a new path. // KeResetEvent(&event); Irp->IoStatus.Status = 0; } if (clearPRKey) { for (i = 0; (ULONG)i < group->NumberDevices; i++) { deviceInfo = group->DeviceList[i]; if (deviceInfo) { deviceInfo->RegisterServiced = FALSE; deviceInfo->PRKeyRegistered = FALSE; } } group->PersistentReservationRegisteredKey[0] = group->PersistentReservationRegisteredKey[1] = group->PersistentReservationRegisteredKey[2] = group->PersistentReservationRegisteredKey[3] = group->PersistentReservationRegisteredKey[4] = group->PersistentReservationRegisteredKey[5] = group->PersistentReservationRegisteredKey[6] = group->PersistentReservationRegisteredKey[7] = 0; group->PRKeyValid = FALSE; group->ReservationList = 0; } if (savePRKeyIfAnySucceed && group->PRKeyValid) { ULONG ordinal; for (i = 0; (ULONG)i < group->NumberDevices; i++) { deviceInfo = group->DeviceList[i]; if (deviceInfo) { deviceInfo->RegisterServiced = TRUE; ordinal = (1 << i); group->ReservationList |= ordinal; } } } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): PR_OUT for %u completed with status %x.\n", DsmIds, serviceAction, returnStatus)); ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext); __Exit_DsmpPersistentReserveOut: if (srbCopy != NULL) { DsmpFreePool(srbCopy); } currentIrpStack->Parameters.Others.Argument3 = servicingDeviceInfo; Irp->IoStatus.Status = returnStatus; if ((!NT_SUCCESS(returnStatus)) && (SrbGetSrbStatus(Srb) == SRB_STATUS_SUCCESS)) { SrbSetSrbStatus(Srb, DsmpNtStatusToSrbStatus(returnStatus)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpPersistentReserveOut (DsmIds %p): Exiting function returning IRP status %x.\n", DsmIds, returnStatus)); return returnStatus; } NTSTATUS DsmpPersistentReserveIn( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PKEVENT Event ) /*++ Routine Description: This routine will handle determine which devices to send the request to based on the service action of the PR-in command. On READ KEYS, it will send down one path. In case of failure, other paths will be tried until one succeeds. Failure is returned only if it fails down all paths. On READ_RESERVATION/REPORT_CAPABILITIES, command is sent down one path. Failed request is not retried. Arguments: DsmContext - DSM context given to MPIO during initialization DsmIds - The collection of DSM IDs that pertain to the MPDISK. Irp - Irp containing SRB. Srb - Scsi request block Event - The event to Return Value: NTSTATUS of the operation. --*/ { PDSM_DEVICE_INFO deviceInfo; PDSM_DEVICE_INFO servicingDeviceInfo = NULL; PDSM_GROUP_ENTRY group; LONG i; ULONG count; NTSTATUS status = STATUS_UNSUCCESSFUL; PDSM_COMPLETION_CONTEXT completionContext; PCDB cdb = SrbGetCdb(Srb); UCHAR serviceAction; BOOLEAN retryOnAnother = FALSE; KEVENT event; PSTORAGE_REQUEST_BLOCK_HEADER srbCopy = NULL; PIO_STACK_LOCATION irpStack; PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ULONGLONG currentTickCount; ULONGLONG finalTickCount; ULONG tickLength = KeQueryTimeIncrement(); PVOID senseInfoBuffer = NULL; UCHAR senseInfoBufferLength = 0; BOOLEAN srbCopySucceeded = FALSE; ULONG SpecialHandlingFlag = 0; UNREFERENCED_PARAMETER(Event); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): Entering function.\n", DsmIds)); // // Cache away a copy of the SRB // srbCopy = SrbAllocateCopy(Srb, NonPagedPoolNx, DSM_TAG_SCSI_REQUEST_BLOCK); if (srbCopy == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpPersistentReserveIn; } deviceInfo = DsmIds->IdList[0]; group = deviceInfo->Group; serviceAction = cdb->PERSISTENT_RESERVE_IN.ServiceAction; switch (serviceAction) { case RESERVATION_ACTION_READ_RESERVATIONS: case RESERVATION_ACTION_READ_KEYS: { // // If there is a failure on the chosen path, retry on another path. // retryOnAnother = TRUE; break; } case SPC3_RESERVATION_ACTION_REPORT_CAPABILITIES: { break; } default: { NT_ASSERT(FALSE); status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpPersistentReserveIn; } } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): Srb %p. Service Action %u.\n", DsmIds, Srb, serviceAction)); // // Allocate a context for the completion routine. // completionContext = ExAllocateFromNPagedLookasideList(&DsmContext->CompletionContextList); if (!completionContext) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): PR_IN %u - Failed to allocate completion context.\n", DsmIds, serviceAction)); goto __Exit_DsmpPersistentReserveIn; } KeInitializeEvent(&event, NotificationEvent, FALSE); // // Indicate the target for this request. // completionContext->DsmContext = DsmContext; completionContext->RequestUnique1 = (PVOID)&event; completionContext->RequestUnique2 = cdb->PERSISTENT_RESERVE_IN.OperationCode; count = group->NumberDevices; for (i = count - 1; i >= 0; i--) { // // A PR command may fail with a "retry-able" UA when reservation is // released or preempted (on every I_T_L nexus except the one on which // it was released/preempted). In such a case we should retry the PR // command on the same path. // KeQueryTickCount((PLARGE_INTEGER)¤tTickCount); finalTickCount = currentTickCount + (DSM_SECONDS_TO_TICKS(group->MaxPRRetryTimeDuringStateTransition) / tickLength); if (!retryOnAnother) { // // If the request doesn't need to be retried (down another path) on // failure, better choose the path that has maximum chances of // success. // deviceInfo = DsmpGetActivePathToBeUsed(group, DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmIds->IdList[0]), SpecialHandlingFlag); if (!deviceInfo) { status = STATUS_UNSUCCESSFUL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): PR_IN %u - No active/alternative path for device %p.\n", DsmIds, serviceAction, group)); break; } } else { deviceInfo = group->DeviceList[i]; if (DsmpIsDeviceFailedState(deviceInfo->State) || !DsmpIsDeviceInitialized(deviceInfo)) { // // Ignore "bad" paths for now. // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): Ignoring bad instance - state %x, init %x.\n", DsmIds, deviceInfo->State, deviceInfo->Initialized)); deviceInfo = NULL; } } if (!deviceInfo) { // // Maybe a remove came through and caused a collapse of the device // list, thus making this entry empty. // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): PR_IN %u - Couldn't find path for device %p.\n", DsmIds, serviceAction, group)); continue; } __DsmpPersistentReserveIn_RetryRequest: IoMarkIrpPending(Irp); completionContext->DeviceInfo = deviceInfo; // // Set-up a completion routine. // IoSetCompletionRoutine(Irp, DsmpPersistentReserveCompletion, completionContext, TRUE, TRUE, TRUE); // // Always send the original request down a new path // irpStack = IoGetNextIrpStackLocation(Irp); srbCopySucceeded = SrbCopySrb(Srb, SrbGetSrbLength(Srb), srbCopy); NT_ASSERT(srbCopySucceeded == TRUE); irpStack->Parameters.Scsi.Srb = Srb; // // Clear the sense buffer if it exists // senseInfoBuffer = SrbGetSenseInfoBuffer(Srb); senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb); if (senseInfoBuffer) { RtlZeroMemory(senseInfoBuffer, senseInfoBufferLength); } servicingDeviceInfo = deviceInfo; // // Issue the request and wait. // status = DsmSendRequest(DsmContext->MPIOContext, deviceInfo->TargetObject, Irp, deviceInfo); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); status = Irp->IoStatus.Status; } if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): PR_IN for %u sent down successfully on %p.\n", DsmIds, serviceAction, deviceInfo->FailGroup->PathId)); #if DBG if (serviceAction == RESERVATION_ACTION_READ_KEYS) { PPRI_REGISTRATION_LIST prInRegistrationList = Irp->AssociatedIrp.SystemBuffer; ULONG numberOfKeys; ULONG keyIndex; ULONGLONG prKey; REVERSE_BYTES(&numberOfKeys, &prInRegistrationList->AdditionalLength); numberOfKeys /= 8; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): %u registrations keys present:\n", DsmIds, numberOfKeys)); for (keyIndex = 0; keyIndex < numberOfKeys; keyIndex++) { REVERSE_BYTES_QUAD(&prKey, &(prInRegistrationList->ReservationKeyList[keyIndex])); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): Registration Key %u: %I64x\n", DsmIds, keyIndex, prKey)); } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "\n")); } else if (serviceAction == RESERVATION_ACTION_READ_RESERVATIONS) { PPRI_RESERVATION_LIST prInReservationList = Irp->AssociatedIrp.SystemBuffer; ULONG numberOfDescriptors; PPRI_RESERVATION_DESCRIPTOR prInReservationDescriptor = prInReservationList->Reservations; ULONGLONG prKey = 0; REVERSE_BYTES(&numberOfDescriptors, &prInReservationList->AdditionalLength); numberOfDescriptors /= sizeof(PRI_RESERVATION_DESCRIPTOR); NT_ASSERT(numberOfDescriptors <= 1); if (numberOfDescriptors == 1) { REVERSE_BYTES_QUAD(&prKey, &prInReservationDescriptor->ReservationKey); } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): %u Reservation Key: %I64x\n", DsmIds, numberOfDescriptors, prKey)); } #endif // // Done. // break; } else { // // Check to see if the request failed because of a "transient error", // like reservations released for example. If so, this is NOT an actual // error and the request must be retried. Multiple retries may be required // if for example the UA indicates that the TPGs are in transitioning state. // if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID && Srb->SrbStatus & SRB_STATUS_ERROR && SrbGetScsiStatus(Srb) == SCSISTAT_CHECK_CONDITION) { KeQueryTickCount((PLARGE_INTEGER)¤tTickCount); senseInfoBuffer = SrbGetSenseInfoBuffer(Srb); senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb); if (group->PRKeyValid && DsmpShouldRetryPersistentReserveCommand(senseInfoBuffer, senseInfoBufferLength) && currentTickCount < finalTickCount) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): PR_IN %u returned UA with error %x. Retrying same path %p.\n", DsmIds, serviceAction, status, deviceInfo->FailGroup->PathId)); KeResetEvent(&event); Irp->IoStatus.Status = 0; goto __DsmpPersistentReserveIn_RetryRequest; } } // // If a retry (along a different path) on failure is not required, // we're done - just return this failure. // if (!retryOnAnother) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): PR_IN for %u down %p failed with %x. Breaking out.\n", DsmIds, serviceAction, deviceInfo->FailGroup->PathId, status)); break; } } TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): PR_IN for %u down %p failed with %x. Sending down another path.\n", DsmIds, serviceAction, deviceInfo->FailGroup->PathId, status)); // // If we are here, it is because the request failed down the chosen path // and needs to be retried down a new path. // KeResetEvent(&event); Irp->IoStatus.Status = 0; } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): PR_IN for %u completed with status %x.\n", DsmIds, serviceAction, status)); ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext); __Exit_DsmpPersistentReserveIn: if (srbCopy != NULL) { DsmpFreePool(srbCopy); } currentIrpStack->Parameters.Others.Argument3 = servicingDeviceInfo; Irp->IoStatus.Status = status; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpPersistentReserveIn (DsmIds %p): Exiting function returning IRP status %x.\n", DsmIds, status)); return status; } NTSTATUS DsmpPersistentReserveCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: General-purpose completion routine for PR in and out commands sent synchronously. Arguments: DeviceObject - Target of the request. Irp - Command being sent. Context - The event on which the caller is waiting. Return Value: NTSTATUS --*/ { PDSM_COMPLETION_CONTEXT context = Context; PKEVENT event; // It is required to specify a DSM completion context // when setting DsmpPersistentReserveCompletion as completion routine. _Analysis_assume_(context != NULL); event = (PKEVENT)(context->RequestUnique1); UNREFERENCED_PARAMETER(DeviceObject); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpPersistentReserveCompletion: DevInfo %p, IRP %p, Context %p\n", context->DeviceInfo, Irp, Context)); if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } KeSetEvent(event, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/dsmtrace.mof ================================================ #pragma classflags("forceupdate") #pragma namespace("\\\\.\\root\\WMI") // // Copyright (C) 2004 Microsoft Corporation // // WPP Generated File // //ModuleName = wppCtlGuid (Init called in Function DriverEntry) [Dynamic, Description("MSDSM Driver Tracing Provider"), guid("{DEDADFF5-F99F-4600-B8C9-2D4D9B806B5B}"), locale("MS\\0x409")] class MSDSMGuid : EventTrace { [Description ("Enable Flags"), ValueDescriptions{ "TRACE_FLAG_GENERAL Flag", "TRACE_FLAG_PNP Flag", "TRACE_FLAG_POWER Flag", "TRACE_FLAG_RW Flag", "TRACE_FLAG_IOCTL Flag", "TRACE_FLAG_QUEUE Flag", "TRACE_FLAG_WMI Flag", "TRACE_FLAG_TIMER Flag", "TRACE_FLAG_INIT Flag", "TRACE_FLAG_LOCK Flag", "TRACE_FLAG_DEBUG1 Flag", "TRACE_FLAG_DEBUG2 Flag", "TRACE_FLAG_MCN Flag", "TRACE_FLAG_ISR Flag", "TRACE_FLAG_ENUM Flag"}, DefineValues{ "TRACE_FLAG_GENERAL", "TRACE_FLAG_PNP", "TRACE_FLAG_POWER", "TRACE_FLAG_RW", "TRACE_FLAG_IOCTL", "TRACE_FLAG_QUEUE", "TRACE_FLAG_WMI", "TRACE_FLAG_TIMER", "TRACE_FLAG_INIT", "TRACE_FLAG_LOCK", "TRACE_FLAG_DEBUG1", "TRACE_FLAG_DEBUG2", "TRACE_FLAG_MCN", "TRACE_FLAG_ISR", "TRACE_FLAG_ENUM"}, Values{ "TRACE_FLAG_GENERAL", "TRACE_FLAG_PNP", "TRACE_FLAG_POWER", "TRACE_FLAG_RW", "TRACE_FLAG_IOCTL", "TRACE_FLAG_QUEUE", "TRACE_FLAG_WMI", "TRACE_FLAG_TIMER", "TRACE_FLAG_INIT", "TRACE_FLAG_LOCK", "TRACE_FLAG_DEBUG1", "TRACE_FLAG_DEBUG2", "TRACE_FLAG_MCN", "TRACE_FLAG_ISR", "TRACE_FLAG_ENUM"}, ValueMap{ "0x00000001", "0x00000002", "0x00000004", "0x00000008", "0x00000010", "0x00000020", "0x00000040", "0x00000080", "0x00000100", "0x00000200", "0x00000400", "0x00000800", "0x00001000", "0x00002000", "0x00004000"} ] uint32 Flags; [Description ("Levels"), ValueDescriptions{ "Abnormal exit or termination", "Severe errors that need logging", "Warnings such as allocation failure", "Includes non-error cases", "Detailed traces from intermediate steps" }, DefineValues{ "TRACE_LEVEL_FATAL", "TRACE_LEVEL_ERROR", "TRACE_LEVEL_WARNING" "TRACE_LEVEL_INFORMATION", "TRACE_LEVEL_VERBOSE" }, Values{ "Fatal", "Error", "Warning", "Information", "Verbose" }, ValueMap{ "0x1", "0x2", "0x3", "0x4", "0x5" }, ValueType("index") ] uint32 Level; }; ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/intrface.c ================================================ /*++ Copyright (C) 2004-2010 Microsoft Corporation Module Name: intrface.c Abstract: This driver is the Microsoft Device Specific Module (DSM) devices that conform with SPC-3 specs. It exports behaviors that mpio.sys will use to determine how to multipath these devices. This file contains DriverEntry and all the functions that are exported to MPIO. This DSM is targetted towards Windows 2008 and above. Environment: kernel mode only --*/ #include "precomp.h" #ifdef DEBUG_USE_WPP #include "intrface.tmh" #endif #pragma warning (disable:4305) DSM_INIT_DATA gDsmInitData; // // Flag to indicate whether to NT_ASSERT or ignore a particular condition. // BOOLEAN DoAssert = TRUE; // // OS Version Info // MSDSM is targetted towards Windows Server 2008 and above. // BOOLEAN gServer2008AndAbove = FALSE; // // Global to cache MPIO's Control Object. // PDEVICE_OBJECT gMPIOControlObject = NULL; // // Flag to indicate if the MPIO control object was referenced. // BOOLEAN gMPIOControlObjectRefd = FALSE; // // Global to cache the Driver Object. // PDRIVER_OBJECT gDsmDriverObject = NULL; #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) #endif // // The code. // NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine is called when the driver is loaded. Arguments: DriverObject - Supplies the driver object. RegistryPath - Supplies the registry path. Return Value: NTSTATUS --*/ { PDSM_CONTEXT dsmContext = NULL; PFILE_OBJECT fileObject; WCHAR dosDeviceName[64] = DSM_MPIO_CONTROL_OBJECT_SYMLINK; UNICODE_STRING mpUnicodeName; NTSTATUS status = STATUS_SUCCESS; MPIO_VERSION_INFO versionInfo = {0}; DSM_TYPE dsmMode = DsmType3; DSM_MPIO_CONTEXT mpctlContext; IO_STATUS_BLOCK ioStatus; // // Initialize the tracing subsystem. // Any failure is handled by ETW itself. // WPP_INIT_TRACING(DriverObject, RegistryPath); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): Entering function.\n", DriverObject)); gDsmDriverObject = DriverObject; // // Determine the OS version. // gServer2008AndAbove = RtlIsNtDdiVersionAvailable(NTDDI_VISTA); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): Server2008AndAbove is %!bool!.\n", DriverObject, gServer2008AndAbove)); // // MSDSM is supported only on Server 2008 and above. // if (!gServer2008AndAbove) { status = STATUS_NOT_SUPPORTED; goto __Exit_DriverEntry; } // // Build the mpio symbolic link name. // RtlInitUnicodeString(&mpUnicodeName, dosDeviceName); // // Get a pointer to mpio's deviceObject. // status = IoGetDeviceObjectPointer(&mpUnicodeName, FILE_READ_ATTRIBUTES, &fileObject, &gMPIOControlObject); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): Failed to communicate with MPIO control object. Status %x.\n", DriverObject, status)); goto __Exit_DriverEntry; } ObReferenceObject(gMPIOControlObject); gMPIOControlObjectRefd = TRUE; ObDereferenceObject(fileObject); status = DsmGetVersion(&versionInfo, sizeof(MPIO_VERSION_INFO)); if (!NT_SUCCESS(status)) { // // If we can't get the version, that means we aren't using a compatible // version of MPIO drivers and so should not continue. // TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): MPIO version unknown - DSM exiting.\n", DriverObject)); status = STATUS_UNSUCCESSFUL; goto __Exit_DriverEntry; } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): MPIO version %d.%d.%d.%d.\n", DriverObject, versionInfo.MajorVersion, versionInfo.MinorVersion, versionInfo.ProductBuild, versionInfo.QfeNumber)); RtlZeroMemory(&gDsmInitData, sizeof(DSM_INIT_DATA)); // // Must be newer than 1.0.7.0 to support DSM type 2 upwards. // if ((versionInfo.MajorVersion > 1) || (versionInfo.MinorVersion >= 1) || (versionInfo.ProductBuild > 7) || (versionInfo.QfeNumber >= 1)) { // // Must be newer than 1.18 to support DSM's versioning // if (versionInfo.MajorVersion > 1 || versionInfo.MinorVersion > 17) { dsmMode = DsmType6; { RTL_OSVERSIONINFOW osVersion = {0}; osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); RtlGetVersion(&osVersion); gDsmInitData.DsmVersion.MajorVersion = osVersion.dwMajorVersion; gDsmInitData.DsmVersion.MinorVersion = osVersion.dwMinorVersion; gDsmInitData.DsmVersion.ProductBuild = osVersion.dwBuildNumber; gDsmInitData.DsmVersion.QfeNumber = 0; } } } else { // // We cannot use this DSM with older versions of the MPIO drivers. // TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): MPIO version not supported - DSM exiting.\n", DriverObject)); status = STATUS_UNSUCCESSFUL; goto __Exit_DriverEntry; } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): Setting DSM type to %d.\n", DriverObject, dsmMode)); // // Build the init data structure. // dsmContext = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_CONTEXT), DSM_TAG_DSM_CONTEXT); if (!dsmContext) { TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): Failed to allocate memory for DSM Context.\n", DriverObject)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DriverEntry; } // // Set-up the init data // gDsmInitData.DsmContext = (PVOID) dsmContext; gDsmInitData.InitDataSize = sizeof(DSM_INIT_DATA); gDsmInitData.DsmInquireDriver = DsmInquire; gDsmInitData.DsmCompareDevices = DsmCompareDevices; gDsmInitData.DsmGetControllerInfo = DsmGetControllerInfo; gDsmInitData.DsmSetDeviceInfo = DsmSetDeviceInfo; gDsmInitData.DsmIsPathActive = DsmIsPathActive; gDsmInitData.DsmPathVerify = DsmPathVerify; gDsmInitData.DsmInvalidatePath = DsmInvalidatePath; gDsmInitData.DsmMoveDevice = DsmMoveDevice; gDsmInitData.DsmRemovePending = DsmRemovePending; gDsmInitData.DsmRemoveDevice = DsmRemoveDevice; gDsmInitData.DsmRemovePath = DsmRemovePath; gDsmInitData.DsmSrbDeviceControl = DsmSrbDeviceControl; gDsmInitData.DsmLBGetPath = DsmLBGetPath; gDsmInitData.DsmInterpretErrorEx = DsmInterpretError; gDsmInitData.DsmUnload = DsmUnload; gDsmInitData.DsmSetCompletion = DsmSetCompletion; gDsmInitData.DsmCategorizeRequest = DsmCategorizeRequest; gDsmInitData.DsmBroadcastSrb = DsmBroadcastRequest; gDsmInitData.DsmIsAddressTypeSupported = DsmIsAddressTypeSupported; gDsmInitData.DsmDeviceNotUsed = DsmDeviceNotUsed; // // Since MSDSM is for SPC-3 compliant devices, MPIO should be able to build // a serial number for the device. // gDsmInitData.DsmDeviceSerialNumber = NULL; // // Notifies MPIO of the appropriate Type support // gDsmInitData.DsmType = dsmMode; gDsmInitData.DriverObject = DriverObject; // // Set-up the WMI Info. // DsmpWmiInitialize(&gDsmInitData.DsmWmiInfo, RegistryPath); DsmpDsmWmiInitialize(&gDsmInitData.DsmWmiGlobalInfo, RegistryPath); RtlInitUnicodeString(&gDsmInitData.DisplayName, DSM_FRIENDLY_NAME); // // Initialize some of the fields in DSM Context structure. // KeInitializeSpinLock(&dsmContext->SupportedDevicesListLock); InitializeListHead(&dsmContext->GroupList); InitializeListHead(&dsmContext->DeviceList); InitializeListHead(&dsmContext->FailGroupList); InitializeListHead(&dsmContext->ControllerList); InitializeListHead(&dsmContext->StaleFailGroupList); // // Build the list context structures used for completion processing. // ExInitializeNPagedLookasideList(&dsmContext->CompletionContextList, NULL, NULL, POOL_NX_ALLOCATION, sizeof(DSM_COMPLETION_CONTEXT), DSM_TAG_GENERIC, 0); RtlZeroMemory(&mpctlContext, sizeof(DSM_MPIO_CONTEXT)); // // Send the IOCTL to mpio.sys to register ourselves. // DsmSendDeviceIoControlSynchronous(IOCTL_MPDSM_REGISTER, gMPIOControlObject, &gDsmInitData, &mpctlContext, sizeof(DSM_INIT_DATA), sizeof(DSM_MPIO_CONTEXT), TRUE, &ioStatus); status = ioStatus.Status; if (NT_SUCCESS(status)) { dsmContext->MPIOContext = mpctlContext.MPIOContext; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): Registered with MPIO.\n", DriverObject)); DriverObject->DriverUnload = DsmDriverUnload; // // Query the registry for disabling/enabling statistics gathering // if (STATUS_OBJECT_NAME_NOT_FOUND == DsmpGetStatsGatheringChoice(dsmContext, (PULONG)&dsmContext->DisableStatsGathering)) { // // If the value does not exist, write the default to registry. // DsmpSetStatsGatheringChoice(dsmContext, (ULONG)dsmContext->DisableStatsGathering); } } __Exit_DriverEntry: if (NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): Exiting function successfully.\n", DriverObject)); } else { // // Since the DSM is going to be unloaded but without DriverUnload being // called, we need to perform cleanup here. // if (dsmContext != NULL) { DsmpFreeDSMResources(dsmContext); dsmContext = NULL; } if (gMPIOControlObjectRefd) { // // Drop the reference on MPIO's control object. // ObDereferenceObject(gMPIOControlObject); gMPIOControlObjectRefd = FALSE; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DriverEntry (DrvObj %p): Exiting function with status %x.\n", DriverObject, status)); // // Stop the tracing subsystem. // NOTE: once we unregister ETW, no more TracePrint can be done, so we // must ensure that ETW unregister is the last thing that happens. // WPP_CLEANUP(gDsmDriverObject); } return status; } VOID DsmDriverUnload( _In_ IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This routine is called when the driver is unloaded. Arguments: DriverObject - Supplies the driver object. Return Value: Nothing --*/ { DSM_DEREGISTER_DATA deregisterData; IO_STATUS_BLOCK ioStatus; deregisterData.DeregisterDataSize = sizeof(DSM_DEREGISTER_DATA); deregisterData.DriverObject = DriverObject; deregisterData.DsmContext = gDsmInitData.DsmContext; deregisterData.MpioContext = ((PDSM_CONTEXT)(gDsmInitData.DsmContext))->MPIOContext; // // Send the IOCTL to mpio.sys to de-register ourselves. // DsmSendDeviceIoControlSynchronous(IOCTL_MPDSM_DEREGISTER, gMPIOControlObject, &deregisterData, NULL, sizeof(DSM_DEREGISTER_DATA), 0, TRUE, &ioStatus); NT_ASSERT(NT_SUCCESS(ioStatus.Status)); return; } NTSTATUS DsmInquire( _In_ IN PVOID DsmContext, _In_ IN PDEVICE_OBJECT TargetDevice, _In_ IN PDEVICE_OBJECT PortObject, _In_ IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor, _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceIdList, _Out_ OUT PVOID *DsmIdentifier ) /*++ Routine Description: This routine is used to determine if TargetDevice belongs to the DSM. If this is a supported device DsmIdentifier will be updated with 'deviceInfo'. Arguments: DsmContext - Context value given to the multipath driver during registration. TargetDevice - DeviceObject for the child device. PortObject - The Port driver FDO on which TargetDevice resides. Descriptor - Pointer to the device descriptor corresponding to TargetDevice. Rehash of inquiry data, plus serial number information (if applicable). DeviceIdList - VPD Page 0x83 information. DsmIdentifier - Pointer to be filled in by the DSM on success. Return Value: STATUS_NOT_SUPPORTED - if not on the SupportList. STATUS_INSUFFICIENT_RESOURCES - No mem. STATUS_SUCCESS --*/ { PDSM_CONTEXT dsmContext = DsmContext; PDSM_DEVICE_INFO deviceInfo = NULL; PDSM_GROUP_ENTRY group; BOOLEAN newGroup; PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroupEntry = NULL; PDSM_TARGET_PORT_LIST_ENTRY targetPortEntry = NULL; PSTR serialNumber = NULL; SIZE_T serialNumberLength = 0; NTSTATUS status; ULONG allocationLength; BOOLEAN serialNumberAllocated = FALSE; KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error BOOLEAN supported = FALSE; BOOLEAN spinlockHeld = FALSE; UCHAR vendorId[9] = {0}; UCHAR productId[17] = {0}; INQUIRYDATA inquiryData; UCHAR alua = DSM_DEVINFO_ALUA_NOT_SUPPORTED; ULONG index; PDSM_IDS controllerObjects = NULL; PDEVICE_OBJECT controllerDeviceObject; PLIST_ENTRY entry = NULL; PSTORAGE_DESCRIPTOR_HEADER controllerIdHeader = NULL; PULONG relativeTargetPortId = NULL; PUSHORT targetPortGroupId = NULL; PUCHAR targetPortGroupsInfo = NULL; ULONG targetPortGroupsInfoLength = 0; PSTR controllerSerialNumber; BOOLEAN match = FALSE; BOOLEAN doneUpdating = FALSE; PDSM_CONTROLLER_LIST_ENTRY controllerEntry = NULL; PDSM_TARGET_PORT_DEVICELIST_ENTRY tp_device = NULL; PWSTR hardwareId = NULL; PWCHAR deviceName = NULL; ULONG tempResult = 0; ULONG maxPRRetryTimeDuringStateTransition = DSM_MAX_PR_UNIT_ATTENTION_RETRY_TIME; BOOLEAN useCacheForLeastBlocks = FALSE; ULONGLONG cacheSizeForLeastBlocks = 0; BOOLEAN fakeControllerEntryExists = FALSE; STORAGE_IDENTIFIER_CODE_SET serialNumberCodeSet = StorageIdCodeSetReserved; #if DBG BOOLEAN multiport; #endif TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Entering function.\n", TargetDevice)); // // 1. Get standard inquiry for the device. Check if SPC-3 compliant. // If not compliant, check SupportedDeviceList. // 2. Create device serial number. // 3. Create a partially populated deviceInfo. // DeviceDescriptor. // SCSI address. // Save off serial number. // ALUA, port FDO, etc. // 4. Create device name. // 5. If ALUA support, send down Report Target Port Groups. // 6. Find the group. If none, build one. // 7. If new group, build target port groups and target ports info. // Else, update target port groups and target ports info. // 8. If both implicit as well as explicit transitions allowed, disable implicit. // 9. Get list of controllers objects and get VPD 0x83 for each (only if no // match for existing ones). // Match returned ids of type 0x5 with what was returned in Report Target Port Groups. // If no type 0x5 identifier, use SCSI address. // Create controller list (delete stale entries). // // // Query the registry to find out what devices are being supported // on this machine. // DsmpGetDeviceList(dsmContext); status = DsmpGetStandardInquiryData(TargetDevice, &inquiryData); if (NT_SUCCESS(status)) { supported = DsmpCheckScsiCompliance(TargetDevice, &inquiryData, Descriptor, DeviceIdList); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to get inquiry data with status %x.\n", TargetDevice, status)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } // // Since the device isn't SPC-3 compliant, check if the device is on the // SupportedDeviceList. // if (!supported) { if (!supported) { // // Get the inquiry data embedded in the device descriptor. // RtlStringCchCopyA((LPSTR)vendorId, sizeof(vendorId) / sizeof(vendorId[0]), (LPCSTR)(&inquiryData.VendorId)); RtlStringCchCopyA((LPSTR)productId, sizeof(productId) / sizeof(productId[0]), (LPCSTR)(&inquiryData.ProductId)); supported = DsmpDeviceSupported(dsmContext, (PCSZ)vendorId, (PCSZ)productId); } if (!supported) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Unsupported Device.\n", TargetDevice)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } } // // Find out if device can be accessed via mulitple ports. This info is // important since it will determine whether or not to send down a // ReportTargetPortGroups command. // #if DBG multiport = (inquiryData.MultiPort & 0x10) ? TRUE : FALSE; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Is %ws multiported.\n", TargetDevice, multiport ? L"" : L"not")); #endif // // Query the assymmetric states transition method // switch ((inquiryData.Reserved >> 0x4) & 0x3) { case 1: alua = DSM_DEVINFO_ALUA_IMPLICIT; break; case 2: alua = DSM_DEVINFO_ALUA_EXPLICIT; break; case 3: alua = DSM_DEVINFO_ALUA_IMPLICIT | DSM_DEVINFO_ALUA_EXPLICIT; break; default: alua = DSM_DEVINFO_ALUA_NOT_SUPPORTED; break; } // // Get some information about this device. The preferred info is // from the Device ID Page. // if (DeviceIdList) { // // This will parse out the 'best' identifier and return // a NULL-terminated ascii string. // serialNumber = (PSTR)DsmpParseDeviceID(DeviceIdList, DSM_DEVID_SERIAL_NUMBER, NULL, &serialNumberCodeSet, FALSE); if (!serialNumber) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): NULL serial number.\n", TargetDevice)); // // Either an allocation failed, or the DeviceIdList is malformed. // status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } // // Indicate that the serialnumber buffer is allocated. // serialNumberAllocated = TRUE; serialNumberLength = strlen((const char*)serialNumber); } else { // // Get the serial number of this device. Use the serial number // page (0x80). Ensure that the device's serial number is // present. If not, can't claim support for this drive. // if (!Descriptor || (Descriptor->SerialNumberOffset == MAXULONG) || (Descriptor->SerialNumberOffset == 0)) { // // The port driver currently doesn't get the VPD page 0x80, // if the device doesn't support GET_SUPPORTED_PAGES. Check to // see whether there actually is a serial number. // serialNumber = DsmpGetSerialNumber(TargetDevice); if (!serialNumber) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): serialNumber = NULL.\n", TargetDevice)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } else { serialNumberAllocated = TRUE; serialNumberLength = strlen((const char*)serialNumber); } } } // // Allocate for the device. This is also used as DsmId. // allocationLength = sizeof(DSM_DEVICE_INFO); // // As DSM_DEVICE_INFO has storage for the descriptor, add only // the additional stuff that's at the end. // if (Descriptor) { status = RtlULongSub(Descriptor->Size, sizeof(STORAGE_DEVICE_DESCRIPTOR), &tempResult); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Arithmetic underflow - status %x.\n", TargetDevice, status)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } } status = RtlULongAdd(allocationLength, tempResult, &allocationLength); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Arithmetic overflow - status %x.\n", TargetDevice, status)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } deviceInfo = DsmpAllocatePool(NonPagedPoolNx, allocationLength, DSM_TAG_DEV_INFO); if (!deviceInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to allocate Device Info.\n", TargetDevice)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } deviceInfo->State = deviceInfo->PreviousState = deviceInfo->TempPreviousStateForLB = deviceInfo->ALUAState = deviceInfo->LastKnownGoodState = DSM_DEV_NOT_USED_STATE; deviceInfo->DesiredState = DSM_DEV_UNDETERMINED; // // Copy over the StorageDescriptor. // if (Descriptor) { RtlCopyMemory(&deviceInfo->Descriptor, Descriptor, Descriptor->Size); } // // Get the scsi address for this device. Note that on success, DsmGetScsiAddress() // will allocate memory which we are responsible for freeing. // status = DsmGetScsiAddress(TargetDevice, &deviceInfo->ScsiAddress); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Error %x while getting scsi address.\n", TargetDevice, status)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } // // Capture the serial number allocated flag. // deviceInfo->SerialNumberAllocated = serialNumberAllocated; // // Set the serial number. // if (!serialNumberAllocated) { PSTORAGE_DEVICE_DESCRIPTOR descriptor; // // serialNumber is not pointing to the buffer passed by MPIO. Update // it to point to the Device Descriptor allocated by the DSM. // descriptor = &(deviceInfo->Descriptor); NT_ASSERT(descriptor->SerialNumberOffset != 0 && descriptor->SerialNumberOffset != MAXULONG); serialNumber = (PCHAR)descriptor + descriptor->SerialNumberOffset; serialNumberLength = strlen((const char*)serialNumber); } if (alua == (DSM_DEVINFO_ALUA_IMPLICIT | DSM_DEVINFO_ALUA_EXPLICIT)) { BOOLEAN disableImplicit = FALSE; status = DsmpDisableImplicitStateTransition(TargetDevice, &disableImplicit); if (NT_SUCCESS(status)) { if (disableImplicit) { alua &= ~DSM_DEVINFO_ALUA_IMPLICIT; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Disabled implicit ALUA state transition.\n", TargetDevice)); // // Record that the storage actually supported implicit also, but we // turned it OFF. // deviceInfo->ImplicitDisabled = TRUE; } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Storage support both transitions but does NOT allow disabling Implicit.\n", TargetDevice)); } } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to disable implicit ALUA state transitions - status %x.\n", TargetDevice, status)); } } deviceInfo->SerialNumber = serialNumber; // // Save the Physical Device Object (PDO) of the device. // Used to verify that no two devices have the same PDO. // deviceInfo->PortPdo = TargetDevice; // // Save the FDO of the adapter. Used for handling reserve\release // deviceInfo->PortFdo = PortObject; // // Set the signature. // deviceInfo->DeviceSig = DSM_DEVICE_SIG; deviceInfo->DsmContext = DsmContext; deviceInfo->ALUASupport = alua; // // Build the name (using serialnumber) that will be used as registry key // to store Load Balance settings for this device. // deviceName = DsmpBuildDeviceName(deviceInfo, serialNumber, serialNumberLength); if (!deviceName) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to allocate device name for %p.\n", TargetDevice, deviceInfo)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } // // Send down ReportTargetPortGroups command and keep the info handy. // if (alua != DSM_DEVINFO_ALUA_NOT_SUPPORTED) { status = DsmpReportTargetPortGroups(TargetDevice, &targetPortGroupsInfo, &targetPortGroupsInfoLength); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to report target port groups for %p. Status %x.\n", TargetDevice, deviceInfo, status)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } // // We've just sent down an RTPG (relatively expensive operation), and it // succeeded, so sending down one more as part part of the initialization // in PathVerify() since it is going to be called almost immediately. // deviceInfo->IgnorePathVerify = TRUE; } // // Query the registry for max time to retry failed PR requests // DsmpGetMaxPRRetryTime(DsmContext, &maxPRRetryTimeDuringStateTransition); // // Query the registry to see if the user has overridden the default // Least Blocks settings. // status = DsmpQueryCacheInformationFromRegistry(DsmContext, &useCacheForLeastBlocks, &cacheSizeForLeastBlocks); if (!NT_SUCCESS(status)) { // // Couldn't get the settings from the registry so fall back on the // default for Least Blocks. // useCacheForLeastBlocks = TRUE; cacheSizeForLeastBlocks = DSM_LEAST_BLOCKS_DEFAULT_THRESHOLD; } // // Build LUN's hardware id. Needs to be called at PASSIVE_LEVEL, so // do it before grabbing the lock. The hardware id of the group is // later set under the protection of the lock. // hardwareId = DsmpBuildHardwareId(deviceInfo); irql = ExAcquireSpinLockExclusive(&(((PDSM_CONTEXT)DsmContext)->DsmContextLock)); spinlockHeld = TRUE; status = STATUS_SUCCESS; // // See if there is an existing Multi-path group to which this belongs. // (same serial number). // group = DsmpFindDevice(DsmContext, deviceInfo, FALSE); if (!group) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): First device %p in the group.\n", TargetDevice, deviceInfo)); newGroup = TRUE; // // This device doesn't belong to any group yet. So Build a multi-path // group entry. This'll represents all paths to a particular device. // group = DsmpBuildGroupEntry(DsmContext, deviceInfo); if (group) { // // Set the registry key name for the new group // group->RegistryKeyName = deviceName; deviceName = NULL; // // Cache the LUN's hardware id // if (!hardwareId) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to build a hardwareId for %p.\n", TargetDevice, deviceInfo)); } group->HardwareId = hardwareId; hardwareId = NULL; group->UseCacheForLeastBlocks = useCacheForLeastBlocks; group->CacheSizeForLeastBlocks = cacheSizeForLeastBlocks; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to allocate Group Entry for %p.\n", TargetDevice, deviceInfo)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Found group %p for device %p.\n", TargetDevice, group, deviceInfo)); newGroup = FALSE; if (!group->HardwareId) { // // If we weren't successful in previously building the hardware id for this LUN, // retry doing it again now. // hardwareId = DsmpBuildHardwareId(deviceInfo); if (!hardwareId) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to build a hardwareId for %p.\n", TargetDevice, deviceInfo)); } group->HardwareId = hardwareId; hardwareId = NULL; } // // Sanity check that we haven't been presented with device instances // with different ALUA support. So compare with the first device instance. // for (index = 0; index < DSM_MAX_PATHS; index++) { if (group->DeviceList[index]) { break; } } if (index < DSM_MAX_PATHS) { // // Only acceptable conditions are: // 1. both have same support, // 2. one has explicit, while other has both explicit-and-implicit (this // is a potential valid case because DsmpDisableImplicitStateTransition // may have failed). // if (!((deviceInfo->ALUASupport == group->DeviceList[index]->ALUASupport) || ((deviceInfo->ALUASupport == DSM_DEVINFO_ALUA_EXPLICIT && deviceInfo->ImplicitDisabled) && (group->DeviceList[index]->ALUASupport == (DSM_DEVINFO_ALUA_IMPLICIT | DSM_DEVINFO_ALUA_EXPLICIT))) || ((group->DeviceList[index]->ALUASupport == DSM_DEVINFO_ALUA_EXPLICIT && group->DeviceList[index]->ImplicitDisabled) && (deviceInfo->ALUASupport == (DSM_DEVINFO_ALUA_IMPLICIT | DSM_DEVINFO_ALUA_EXPLICIT))))) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Mismatch in device instances' ALUA support %d vs %d.\n", TargetDevice, deviceInfo->ALUASupport, group->DeviceList[index]->ALUASupport)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } } } if (NT_SUCCESS(status)) { NT_ASSERT(group); group->MaxPRRetryTimeDuringStateTransition = maxPRRetryTimeDuringStateTransition; if (alua == DSM_DEVINFO_ALUA_NOT_SUPPORTED) { // // Since the device doesn't support ALUA, it is automatically // symmetric LU access. // group->Symmetric = TRUE; if (newGroup) { // // This is the first in the group, so make it the active device. // The actual active/passive devices will be set-up when // LB policies are set by the user. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } else { // // Already something active, this will be the fail-over device // until the load-balance groups are set-up. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_STANDBY; } } else { if (DeviceIdList == NULL) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): No Device ID List.\n", TargetDevice)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } if (alua == DSM_DEVINFO_ALUA_IMPLICIT) { // // Assume that the LU access is symmetric. When parsing the TPG // info, if we find that not all TPGs are in the same LU access // state, then we know that this the access is asymmetric. // group->Symmetric = TRUE; } // // Build TPG and TP info // status = DsmpParseTargetPortGroupsInformation(DsmContext, group, targetPortGroupsInfo, targetPortGroupsInfoLength); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to build TPG information - status %x.\n", TargetDevice, status)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } for (index = 0; index < DSM_MAX_PATHS; index++) { PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup; targetPortGroup = group->TargetPortGroupList[index]; if (targetPortGroup) { DsmpUpdateTargetPortGroupDevicesStates(targetPortGroup, targetPortGroup->AsymmetricAccessState); } } // // Find the target port through which this devInfo was exposed. // relativeTargetPortId = (PULONG)DsmpParseDeviceID(DeviceIdList, DSM_DEVID_RELATIVE_TARGET_PORT, NULL, NULL, FALSE); NT_ASSERT(relativeTargetPortId); if (!relativeTargetPortId) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Couldn't retrieve relative TP id.\n", TargetDevice)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } // // Find the target port group // targetPortGroupId = (PUSHORT)DsmpParseDeviceID(DeviceIdList, DSM_DEVID_TARGET_PORT_GROUP, NULL, NULL, FALSE); NT_ASSERT(targetPortGroupId); if (targetPortGroupId) { // // Find the target port group entry // targetPortGroupEntry = DsmpFindTargetPortGroup(DsmContext, group, targetPortGroupId); NT_ASSERT(targetPortGroupEntry); if (targetPortGroupEntry) { // // Look through the target port group to find the target port // targetPortEntry = DsmpFindTargetPort(DsmContext, targetPortGroupEntry, relativeTargetPortId); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Couldn't find TPG Id %x's entry.\n", TargetDevice, *targetPortGroupId)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } NT_ASSERT(targetPortEntry); if (!targetPortEntry) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Couldn't find relative TP %x's entry.\n", TargetDevice, *relativeTargetPortId)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } // // Update the devInfo with the target port and target port group // info // deviceInfo->TargetPortGroup = targetPortGroupEntry; deviceInfo->TargetPort = targetPortEntry; deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = deviceInfo->ALUAState = deviceInfo->TargetPortGroup->AsymmetricAccessState; tp_device = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_TARGET_PORT_DEVICELIST_ENTRY), DSM_TAG_TP_DEVICE_LIST_ENTRY); if (!tp_device) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Insufficient resources allocating TP device list entry.\n", TargetDevice)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } // // Add the device to the list of devices that are exposed via this target port. // tp_device->DeviceInfo = deviceInfo; InterlockedIncrement((LONG volatile*)&targetPortEntry->Count); InsertTailList(&targetPortEntry->TP_DeviceList, &tp_device->ListEntry); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to retrieve TPG Id.\n", TargetDevice)); status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } } if (NT_SUCCESS(status)) { // // Add the deviceInfo to the list. DO NOT modify the status // variable if this function returns SUCCESS. // status = DsmpAddDeviceEntry(DsmContext, group, deviceInfo); if (NT_SUCCESS(status)) { *DsmIdentifier = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Added device %p to group %p.\n", TargetDevice, *DsmIdentifier, group)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to add device %p to group %p - status %x.\n", TargetDevice, deviceInfo, group, status)); // // We weren't able to add this deviceInfo to the list so we must // remove its entry on the target port list before the deviceInfo // is freed. // DsmpRemoveDeviceFromTargetPortList(deviceInfo); if (newGroup) { DsmpRemoveGroupEntry(DsmContext, group, FALSE); DsmpFreePool(group); group = NULL; } status = STATUS_NOT_SUPPORTED; goto __Exit_DsmInquire; } } } ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); spinlockHeld = FALSE; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Device %p added. State %d, Desired State %d\n", TargetDevice, deviceInfo, deviceInfo->State, deviceInfo->DesiredState)); // // Update the global list of controller objects // controllerObjects = DsmGetAssociatedDevice(dsmContext->MPIOContext, PortObject, 0x0C); if (controllerObjects) { // // This loop needs its own status variable so that it does not // inadvertently overwrite a STATUS_SUCCESS from the code above. // NTSTATUS matchStatus = STATUS_SUCCESS; PSCSI_ADDRESS controllerScsiAddress = NULL; // // Walk through the list and get VPD 0x83 data and associate the devInfo // with the controller object. // for (index = 0; index < controllerObjects->Count; index++) { STORAGE_IDENTIFIER_CODE_SET codeSet = StorageIdCodeSetReserved; // // Free the previously allocated SCSI address, if any. // if (controllerScsiAddress) { DsmpFreePool(controllerScsiAddress); controllerScsiAddress = NULL; } controllerDeviceObject = (PDEVICE_OBJECT)controllerObjects->IdList[index]; NT_ASSERT(controllerDeviceObject); if (!controllerDeviceObject) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Controller list %p's index %x is NULL.\n", TargetDevice, controllerObjects, index)); continue; } matchStatus = DsmpGetDeviceIdList(controllerDeviceObject, &controllerIdHeader); NT_ASSERT(NT_SUCCESS(matchStatus)); if (!NT_SUCCESS(matchStatus)) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to get DeviceId list for controller %p - status %x.\n", TargetDevice, controllerDeviceObject, matchStatus)); continue; } controllerSerialNumber = DsmpParseDeviceID((PSTORAGE_DEVICE_ID_DESCRIPTOR)controllerIdHeader, DSM_DEVID_SERIAL_NUMBER, NULL, &codeSet, FALSE); NT_ASSERT(controllerSerialNumber); DsmpFreePool(controllerIdHeader); if (!controllerSerialNumber) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to parse serial number for controller %p.\n", TargetDevice, controllerDeviceObject)); continue; } // // Note that on success, DsmGetScsiAddress() will allocate memory // which we are responsible for freeing. // matchStatus = DsmGetScsiAddress(controllerDeviceObject, &controllerScsiAddress); NT_ASSERT(NT_SUCCESS(matchStatus)); if (!NT_SUCCESS(matchStatus)) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to get controller %p's scsi address - status %x.\n", TargetDevice, controllerDeviceObject, matchStatus)); continue; } controllerEntry = DsmpFindControllerEntry(DsmContext, PortObject, controllerScsiAddress, controllerSerialNumber, strlen(controllerSerialNumber), codeSet, TRUE); if (!controllerEntry) { controllerEntry = DsmpBuildControllerEntry(DsmContext, controllerDeviceObject, PortObject, controllerScsiAddress, controllerSerialNumber, codeSet, TRUE); if (!controllerEntry) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to build an entry for controller %p.\n", TargetDevice, controllerDeviceObject)); continue; } InsertHeadList(&dsmContext->ControllerList, &controllerEntry->ListEntry); InterlockedIncrement((LONG volatile*)&dsmContext->NumberControllers); } controllerEntry->DeviceObject = controllerDeviceObject; // // Parse the DeviceIdList for all the 0x5 type identifiers // and for each, compare the target port groups and target ports to match // the device to its controller. // if (!match) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Failed to match devInfo %p with controller %p's Ids.\n", TargetDevice, deviceInfo, controllerDeviceObject)); match = DsmpIsDeviceBelongsToController(DsmContext, deviceInfo, controllerEntry); } if (match && !doneUpdating) { InterlockedIncrement((LONG volatile*)&(controllerEntry->RefCount)); deviceInfo->Controller = controllerEntry; doneUpdating = TRUE; } } // // Free the last SCSI address allocated in the loop, if any. // if (controllerScsiAddress) { DsmpFreePool(controllerScsiAddress); controllerScsiAddress = NULL; } } // // If there was no controller to associate this device with, use a fake one. // Note that we only really care about matching on the Port and Target // portions of the SCSI address. // if (!deviceInfo->Controller) { for (entry = dsmContext->ControllerList.Flink; entry != &dsmContext->ControllerList; entry = entry->Flink) { controllerEntry = CONTAINING_RECORD(entry, DSM_CONTROLLER_LIST_ENTRY, ListEntry); if ((controllerEntry->IsFakeController) && (controllerEntry->ScsiAddress->PortNumber == deviceInfo->ScsiAddress->PortNumber) && (controllerEntry->ScsiAddress->TargetId == deviceInfo->ScsiAddress->TargetId)) { fakeControllerEntryExists = TRUE; break; } } // // If no fake one exists as yet for this port FDO, create one now. // if (!fakeControllerEntryExists) { CHAR fakeControllerSerialNumber[] = "FakeController"; SCSI_ADDRESS fakeControllerScsiAddress = {0}; fakeControllerScsiAddress.PortNumber = deviceInfo->ScsiAddress->PortNumber; fakeControllerScsiAddress.TargetId = deviceInfo->ScsiAddress->TargetId; controllerEntry = DsmpBuildControllerEntry(DsmContext, NULL, PortObject, &fakeControllerScsiAddress, fakeControllerSerialNumber, StorageIdCodeSetBinary, TRUE); if (controllerEntry) { InsertHeadList(&dsmContext->ControllerList, &controllerEntry->ListEntry); InterlockedIncrement((LONG volatile*)&dsmContext->NumberControllers); controllerEntry->IsFakeController = TRUE; } } if (controllerEntry) { InterlockedIncrement((LONG volatile*)&(controllerEntry->RefCount)); } deviceInfo->Controller = controllerEntry; } __Exit_DsmInquire: if (spinlockHeld) { ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); } if (NT_SUCCESS(status)) { NT_ASSERT(*DsmIdentifier); } else { // // If there was any sort of ERROR, the deviceInfo will NOT be put on // MSDSM's internal list that is accessible to other threads. Thus, // we are safe to free the memory below and we do not require any // synchronization mechanism to do so. // // // Check to see whether the serial number buffer was allocated, or just // an offset into the Descriptor. // if (serialNumberAllocated) { // // Need to free this before returning. // DsmpFreePool(serialNumber); } if (deviceInfo) { if (deviceInfo->ScsiAddress) { DsmpFreePool(deviceInfo->ScsiAddress); } DsmpFreePool(deviceInfo); } } // // If deviceName is not NULL then it hasn't been assigned to any GROUP. // Free the allocated memory. // if (deviceName) { DsmpFreePool(deviceName); } // // If hardwareId is not NULL then it hasn't been assigned to any GROUP. // Free the allocated memory. // if (hardwareId) { DsmpFreePool(hardwareId); } if (targetPortGroupsInfo) { DsmpFreePool(targetPortGroupsInfo); } if (relativeTargetPortId) { DsmpFreePool(relativeTargetPortId); } if (targetPortGroupId) { DsmpFreePool(targetPortGroupId); } if (controllerObjects) { DsmpFreePool(controllerObjects); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmInquire (DevObj %p): Exiting function with status %x.\n", TargetDevice, status)); return status; } BOOLEAN DsmCompareDevices( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId1, _In_ IN PVOID DsmId2 ) /*++ Routine Description: This routine is called to determine if the device ids represent the same underlying physical device. Arguments: DsmContext - Context value given to the multipath driver during registration. DsmId1/2 - Identifers returned from DMS_INQUIRE_DRIVER. Return Value: TRUE if DsmIds correspond to the same underlying device. --*/ { PDSM_DEVICE_INFO deviceInfo0 = DsmId1; PDSM_DEVICE_INFO deviceInfo1 = DsmId2; PSTR serialNumber0; PSTR serialNumber1; SIZE_T length; BOOLEAN match = FALSE; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmCompareDevices (DevInfo %p): Entering function - comparing with %p.\n", deviceInfo0, deviceInfo1)); // // Get the two serial numbers. They were either embedded in // the STORAGE_DEVICE_DESCRIPTOR or built by directly issuing // the VPD request. // serialNumber0 = deviceInfo0->SerialNumber; serialNumber1 = deviceInfo1->SerialNumber; if (serialNumber0 && serialNumber1) { // // Get the length of the base-device Serial Number. // length = strlen((const char*)serialNumber0); // // If the lengths match, compare the contents. // if (length == strlen((const char*)serialNumber1)) { if (RtlEqualMemory(serialNumber0, serialNumber1, length)) { match = TRUE; } } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmCompareDevices (DevInfo %p): Serialnumber not assigned for %p and\\or %p.\n", DsmId1, deviceInfo0, deviceInfo1)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmCompareDevices (DevInfo %p): Exiting function with match = %!bool!.\n", DsmId1, match)); return match; } NTSTATUS DsmGetControllerInfo( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN ULONG Flags, _Inout_ IN OUT PCONTROLLER_INFO *ControllerInfo ) /*++ Routine Description: This routine is used to get information about the controller that the device corresponding to DsmId in on. Currently this DSM controls hardware that doesn't expose controllers directly. Therefore State is always NO_CNTRL. This information is used mainly by whatever WMI admin utilities want it. Arguments: DsmContext - Context value given to the multipath driver during registration. DsmId - Value returned from DMSInquireDriver. Flags - Bitfield of modifiers. If ALLOCATE is not set, ControllerInfo will have a valid buffer for the DSM to operate on. ControllerInfo - Pointer for the DSM to place the allocated controller info pertaining to DsmId Return Value: STATUS_INSUFFICIENT_RESOURCES if memory allocation fails. STATUS_SUCCESS on success --*/ { PDSM_DEVICE_INFO deviceInfo = DsmId; PDSM_CONTROLLER_LIST_ENTRY controllerEntry = deviceInfo->Controller; PCONTROLLER_INFO controllerInfo = NULL; LARGE_INTEGER time; ULONG controllerId = 0; NTSTATUS status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmGetControllerInfo (DevInfo %p): Entering function.\n", DsmId)); // // Check to see whether a controller id has already been made-up. // if (!controllerEntry) { // // Since this device is in an enclosure that doesn't have controllers, // e.g. JBOD, make one up. // KeQuerySystemTime(&time); // // Use only the lower 32-bits. // controllerId = time.LowPart; } // // Check the Flags // if (Flags & DSM_CNTRL_FLAGS_ALLOCATE) { // // This is the first call. Need to allocate the controller structure. // controllerInfo = DsmpAllocatePool(NonPagedPoolNx, sizeof(CONTROLLER_INFO), DSM_TAG_CTRL_INFO); if (!controllerInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmGetControllerInfo (DevInfo %p): Failed to allocate memory for Controller Info\n", DsmId)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmGetControllerInfo; } if (!controllerEntry) { // // Indicate that there are no specific controllers. // controllerInfo->State = DSM_CONTROLLER_NO_CNTRL; // // Set the identifier to the value generated earlier. // Indicate that it's Binary, not ASCII. // controllerInfo->Identifier.Type = StorageIdCodeSetBinary; controllerInfo->Identifier.Length = 8; RtlCopyMemory(controllerInfo->Identifier.SerialNumber, &controllerId, sizeof(controllerId)); } else { // // If either implicit or explicit ALUA state transition is supported, // every controller is active. Else, if the devInfo's is in Active // state, the controller is obviously in the active state. // if ((deviceInfo->ALUASupport != DSM_DEVINFO_ALUA_NOT_SUPPORTED) || (DsmpIsDeviceStateActive(deviceInfo->State))) { controllerInfo->State = DSM_CONTROLLER_ACTIVE; } else { controllerInfo->State = DSM_CONTROLLER_STANDBY; } controllerInfo->Identifier.Type = controllerEntry->IdCodeSet; controllerInfo->Identifier.Length = controllerEntry->IdLength; if (controllerInfo->Identifier.Length > 32) { controllerInfo->Identifier.Length = 32; } RtlCopyMemory(controllerInfo->Identifier.SerialNumber, controllerEntry->Identifier, controllerInfo->Identifier.Length); controllerInfo->DeviceObject = controllerEntry->DeviceObject; } *ControllerInfo = controllerInfo; } else if (Flags & DSM_CNTRL_FLAGS_CHECK_STATE) { // // Get the passed in struct. // controllerInfo = *ControllerInfo; // // If the enclosures supported by this DSM actually had controllers, // there would be a list of them and a search based on // ControllerIdentifier would be made. // controllerEntry = deviceInfo->Controller; if (!controllerEntry) { controllerInfo->State = DSM_CONTROLLER_NO_CNTRL; } else { // // If either implicit or explicit ALUA state transition is supported, // every controller is active. Else, if the devInfo's is in Active // state, the controller is obviously in the active state. // if ((deviceInfo->ALUASupport != DSM_DEVINFO_ALUA_NOT_SUPPORTED) || (DsmpIsDeviceStateActive(deviceInfo->State))) { controllerInfo->State = DSM_CONTROLLER_ACTIVE; } else { controllerInfo->State = DSM_CONTROLLER_STANDBY; } } } __Exit_DsmGetControllerInfo: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmGetControllerInfo (DevInfo %p): Exiting function with status %x.\n", DsmId, status)); return status; } NTSTATUS DsmSetDeviceInfo( _In_ IN PVOID DsmContext, _In_ IN PDEVICE_OBJECT TargetObject, _In_ IN PVOID DsmId, _Inout_ IN OUT PVOID *PathId ) /*++ Routine Description: This routine associates the DsmId to the controlling MPDisk PDO, the targetObject for DSM-initiated requests, and to a Path (given by PathId). This routine will update the PathId in a way that better explains the topology to MPIO. Additionally, if we are in failover LB policy, failback if this path is preferred path. Also, if PR is being used, send registration down this path. Arguments: DsmContext - Context value given to the multipath driver during registration. TargetObject - The D.O. to which DSM-initiated requests should be sent. DsmId - Value returned from DMSInquireDriver. PathId - Id that represents the path. The value passed in may be used as is, or the DSM optionally can update it if it requires additional state info to be kept. Return Value: INSUFFICENT_RESOURCES for no-mem conditions. STATUS_SUCCESS --*/ { PDSM_DEVICE_INFO deviceInfo = DsmId; PDSM_GROUP_ENTRY group = deviceInfo->Group; PDSM_FAILOVER_GROUP failGroup; PDSM_CONTEXT dsmContext; PSCSI_ADDRESS scsiAddress; ULONG primaryPath = 0; ULONG optimizedPath = 0; ULONG pathWeight = 0; ULONG pathId; NTSTATUS status = STATUS_SUCCESS; WCHAR registryKeyName[256] = {0}; BOOLEAN newFOGroup = FALSE; BOOLEAN registryKeyExists = FALSE; KIRQL irql; PVOID tempPathId = *PathId; DSM_LOAD_BALANCE_TYPE loadBalanceType; ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG); UCHAR explicitlySet = FALSE; BOOLEAN vidpidPolicySet = FALSE; BOOLEAN overallPolicySet = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): Entering function.\n", DsmId)); // // 1. Set default LB policy. // 2. Query LB policy from registry and update if necessary. // 3. Set default value for primaryPath and optimizedPath based on device's // access state // 4. Map deviceInfo to real LUN by saving off the target for I/O // 5. Build pathId from SCSI address // 6. Find FOG for device. If none found, build one. // Add deviceInfo to FOG. // 7. Query registry for pathWeight, primaryPath and optimizedPath // Update deviceInfo with results of query. // 8. Compare deviceInfo access state with persistent value (based on // primaryPath and optimizedPath) and update its DesiredState. // if (!TargetObject) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): No target object.\n", deviceInfo)); // // This deviceInfo will have no path or targetObject associated with it. // Mark it in a failed state so it won't be used to handle any requests. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_UNDETERMINED; goto __Exit_DsmSetDeviceInfo; } // // Default LB type is Round Robin. // loadBalanceType = DSM_LB_ROUND_ROBIN; // // Override the default with whatever is the overall policy that needs to be // applied for all LUNs controlled by MSDSM. // // Override that policy if one has been set for this device's VID/PID. // // Override that policy with whatever has been explicitly set for this particular // device. // // In order to perform the above, first query the policy for this particular device. // If it has not been explicity set, use MSDSM's overall policy or VID/PID policy. // status = DsmpQueryDeviceLBPolicyFromRegistry(deviceInfo, group->RegistryKeyName, &loadBalanceType, &preferredPath, &explicitlySet); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): Failed to query LB policy from registry. Status %x.\n", deviceInfo, status)); NT_ASSERT(NT_SUCCESS(status)); // // This deviceInfo will have no path or targetObject associated with it. // Mark it in a failed state so it won't be used to handle any requests. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_UNDETERMINED; goto __Exit_DsmSetDeviceInfo; } // // If this device's policy was not explicitly set, check to see if a policy // was set for this device's VID/PID and use that. // If VID/PID policy is not set, query the overall default policy // that needs to be applied to all devices controlled by this DSM. // If this setting hasn't been set, we'll fall back to using the default that was // determined based on the storage's ALUA capabilities. // if (!explicitlySet) { status = DsmpQueryTargetLBPolicyFromRegistry(deviceInfo, &loadBalanceType, &preferredPath); if (NT_SUCCESS(status)) { group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_VID_PID; vidpidPolicySet = TRUE; } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) { // // Since the policy hasn't been set for this VID/PID, check if // overall MSDSM-wide policy has been set. // status = DsmpQueryDsmLBPolicyFromRegistry(&loadBalanceType, &preferredPath); if (NT_SUCCESS(status)) { group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_DSM_WIDE; overallPolicySet = TRUE; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): Failed to query Dsm overall LB policy from registry. Status %x.\n", deviceInfo, status)); NT_ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND); status = STATUS_SUCCESS; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): Failed to query VID/PID LB policy from registry. Status %x.\n", deviceInfo, status)); NT_ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND); status = STATUS_SUCCESS; } } else { group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_LUN_EXPLICIT; } if (!explicitlySet && !vidpidPolicySet && !overallPolicySet) { group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY; } // // If ALUA is enabled and the load balance policy is set to Round Robin, // we need to set it to Round Robin with Subset instead. // if (!DsmpIsSymmetricAccess(deviceInfo) && loadBalanceType == DSM_LB_ROUND_ROBIN) { loadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET; } group->LoadBalanceType = loadBalanceType; group->PreferredPath = preferredPath; dsmContext = (PDSM_CONTEXT) DsmContext; irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock)); // // Save the registry key name under which Load balance policies // are stored. This will be used to query the LB policy later. // if (group->RegistryKeyName) { registryKeyExists = TRUE; if (!NT_SUCCESS(RtlStringCchCopyNW(registryKeyName, sizeof(registryKeyName) / sizeof(registryKeyName[0]), group->RegistryKeyName, ((sizeof(registryKeyName) / sizeof(registryKeyName[0])) - sizeof(WCHAR))))) { registryKeyName[(sizeof(registryKeyName) / sizeof(registryKeyName[0])) - 1] = L'\0'; } } // // TargetObject is the destination for any requests created by this driver. // Save this for future reference. // deviceInfo->TargetObject = TargetObject; // // Set the PathId - All devices on the same PathId will // failover together. Currently the pathId is constructed // from Port Number, Bus Number, and Target Id of the device. // scsiAddress = deviceInfo->ScsiAddress; NT_ASSERT(scsiAddress); pathId = 0x77; pathId <<= 8; pathId |= scsiAddress->PortNumber; pathId <<= 8; pathId |= scsiAddress->PathId; pathId <<= 8; pathId |= scsiAddress->TargetId; *PathId = ((PVOID)((ULONG_PTR)(pathId))); // // PathId indicates the path on which this device resides. Meaning // that when a Fail-Over occurs all device's on the same path fail // together. Search for a matching F.O. Group // failGroup = DsmpFindFOGroup(DsmContext, *PathId); // // If not found, create a new failover group // if (!failGroup) { failGroup = DsmpBuildFOGroup(DsmContext, deviceInfo, PathId); if (failGroup) { newFOGroup = TRUE; failGroup->MPIOPath = tempPathId; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): Failed to build FO Group.\n", DsmId)); status = STATUS_INSUFFICIENT_RESOURCES; } } if (NT_SUCCESS(status)) { // // If this path is in the midst of failover processing, mark it as "good" // again. // failGroup->State = DSM_FG_NORMAL; // // add this deviceInfo to the f.o. group. // status = DsmpUpdateFOGroup(DsmContext, failGroup, deviceInfo); NT_ASSERT(NT_SUCCESS(status)); } ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); if (NT_SUCCESS(status)) { if (registryKeyExists) { NTSTATUS queryStatus = STATUS_INVALID_PARAMETER; ULONGLONG pathId64; // // If the overall default policy or a target-level policy has been set and // this device's policy has not been explicitly set, there's no use querying // its individual path (desired) states. // if ((!overallPolicySet && !vidpidPolicySet) || (explicitlySet)) { // // Created a new failover group. Query the LB policy // for this device from registry. // pathId64 = (ULONGLONG)((ULONG_PTR)*PathId); queryStatus = DsmpQueryLBPolicyForDevice(registryKeyName, pathId64, loadBalanceType, &primaryPath, &optimizedPath, &pathWeight); } irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock)); if (NT_SUCCESS(queryStatus)) { deviceInfo->PathWeight = pathWeight; // // If device doesn't support ALUA, update the device state // based on the primary path info in the registry. // if (DsmpIsSymmetricAccess(deviceInfo)) { if (primaryPath) { deviceInfo->DesiredState = DSM_DEV_ACTIVE_OPTIMIZED; } else { deviceInfo->DesiredState = DSM_DEV_STANDBY; } } else { DSM_DEVICE_STATE devState; if (primaryPath) { devState = optimizedPath ? DSM_DEV_ACTIVE_OPTIMIZED : DSM_DEV_ACTIVE_UNOPTIMIZED; } else { devState = optimizedPath ? DSM_DEV_STANDBY : DSM_DEV_UNAVAILABLE; } // // For ALUA, desired state makes sense for FOO. // For RRWS, we assume desired state was explicitly selected // by Admin if the ALUA state is different from the path // state. Only under such cases would the path state have // been saved in registry. // In all other policies, state must just match the TPG state. // if (group->LoadBalanceType == DSM_LB_FAILOVER || group->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET) { deviceInfo->DesiredState = devState; } else { deviceInfo->DesiredState = DSM_DEV_UNDETERMINED; } } } else if (queryStatus == STATUS_OBJECT_NAME_NOT_FOUND) { deviceInfo->PathWeight = pathWeight; deviceInfo->DesiredState = DSM_DEV_UNDETERMINED; } else { deviceInfo->PathWeight = 0; deviceInfo->DesiredState = DSM_DEV_UNDETERMINED; } ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); } } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): PathWeight %x, DesiredState %x, State %x, PrevState %x.\n", deviceInfo, deviceInfo->PathWeight, deviceInfo->DesiredState, deviceInfo->State, deviceInfo->PreviousState)); if (NT_SUCCESS(status)) { deviceInfo->Initialized = TRUE; } else if (!NT_SUCCESS(status) && newFOGroup) { // // This deviceInfo will have no path associated with it. // Mark it in a failed state so it won't be used to handle any requests. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_UNDETERMINED; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): No path associated with instance. Changing state from %u to %u.\n", deviceInfo, deviceInfo->PreviousState, deviceInfo->State)); DsmpRemoveDeviceFailGroup(DsmContext, failGroup, deviceInfo, TRUE); if (failGroup->Count == 0) { // // Yank it from the list. // RemoveEntryList(&failGroup->ListEntry); InterlockedDecrement((LONG volatile*)&dsmContext->NumberFOGroups); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): Removing FOGroup %p with path %p. Count of FOGroups %d.\n", DsmId, failGroup, failGroup->PathId, dsmContext->NumberFOGroups)); // // Free the zombie group list and then the failover group. // DsmpFreeZombieGroupList(failGroup); DsmpFreePool(failGroup); } } __Exit_DsmSetDeviceInfo: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmSetDeviceInfo (DevInfo %p): Exiting function with status %x.\n", DsmId, status)); return status; } BOOLEAN DsmIsPathActive( _In_ IN PVOID DsmContext, _In_ IN PVOID PathId, _In_ IN PVOID DsmId ) /*++ Routine Description: This routine is used to determine whether the path to DsmId is usable (ie. able to handle requests without a failover). Also, after a failover, the path validity will be queried. If the path error was transitory and the DSM feels that the path is good, then this request will be re-issued to determine whether it is usable. Arguments: DsmContext - Context value given to the multipath driver during registration. PathId - Value set in SetPathId. DsmId - DSM Id returned during DsmInquire. Return Value: TRUE if the path is active. FALSE otherwise. --*/ { PDSM_FAILOVER_GROUP foGroup; PDSM_DEVICE_INFO deviceInfo = DsmId; PDSM_GROUP_ENTRY group = deviceInfo->Group; PDSM_CONTEXT dsmContext = (PDSM_CONTEXT) DsmContext; KIRQL irql; BOOLEAN retVal; ULONG SpecialHandlingFlag = 0; // // 1. If PR and reserved by this node, register the PR keys. // 2. Find the FOG for the passed in PathId // 3. Depending on the LB policy, set the appropriate devInfo states // If FailOver, and DesiredState is AO, change the active // devInfos to non-active state and make this one AO. // If ALUA supported, send down SetTPG to make this change, // else directly make the change. // If RR/LWP/LQD, make this DevInfo ActiveOptimized. // If RRS, and DesiredState is AO, change the active devInfos to // their desired states and then make this one AO. // If DesiredState is not AO, find a devInfo in AO state. If // one is found, make this devInfo's state its desired state, // else if one isn't found, make this one AO. // 3. If this is preferredPath, and LB policy is failover-only, change the // access state of deviceInfo to AO. // If there is another devInfo currently in AO, change its state too. // If ALUA supported, send down SetTPG to make these changes. // 4. Get the appropriate AO DeviceInfo and mark the group's PTBU to its // pathId. // TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): Entering function.\n", DsmId)); // // Initialize this instance to be usable so that during the possible processing // of PR register, this device can be a candidate for certain kind of requests. // deviceInfo->Usable = TRUE; // // New path arriving. If this Node owns the reservation register this path. // if (group->PRKeyValid) { NTSTATUS prRegStatus; ULONG i; PDSM_DEVICE_INFO devInfo; ULONG ordinal; prRegStatus = DsmpRegisterPersistentReservationKeys(deviceInfo, TRUE); deviceInfo->RegisterServiced = TRUE; if (NT_SUCCESS(prRegStatus)) { deviceInfo->PRKeyRegistered = TRUE; } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): Failed (status %x) to register PR key\n", deviceInfo, prRegStatus)); } for (i = 0; i < group->NumberDevices; i++) { devInfo = group->DeviceList[i]; if (devInfo && devInfo == deviceInfo) { ordinal = (1 << i); group->ReservationList |= ordinal; break; } } } irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock)); // // Get the F.O. Group information. // foGroup = DsmpFindFOGroup(DsmContext, PathId); // // If there are any devices on this path, and it's not in a failed state // it's capable of handling requests. So it's active. // if ((foGroup) && (foGroup->Count) && (foGroup->State == DSM_FG_NORMAL)) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): Path %p is usable.\n", DsmId, PathId)); retVal = TRUE; // // Update the next path to be used for the group if it not set already. // deviceInfo = (PDSM_DEVICE_INFO)DsmId; group = deviceInfo->Group; DSM_ASSERT(group != NULL); DSM_ASSERT(group->GroupSig == DSM_GROUP_SIG); // // If an invalidated path came back online before PnP removes came in, // then MPIO's path recovery thread would have sent down a PathVerify // just moments before by which we changed the state of the FOG to // normal. Now it is time to change the deviceInfo's state to a "good" // state. // if (deviceInfo->State >= DSM_DEV_FAILED) { DSM_ASSERT(deviceInfo->State == DSM_DEV_INVALIDATED); if (DsmpIsSymmetricAccess(deviceInfo)) { // // Mark it as AO. The SetLBForPathArrival will update the state // appropriately. // deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; } else { // // Set it to the state that was reported during the last RTPG // call that was made. // deviceInfo->State = deviceInfo->ALUAState; } } if (DsmpIsSymmetricAccess(deviceInfo)) { DsmpSetLBForPathArrival(DsmContext, deviceInfo, SpecialHandlingFlag); } else { ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); DsmpSetLBForPathArrivalALUA(DsmContext, deviceInfo, SpecialHandlingFlag); irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock)); } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): State set to %d\n", deviceInfo, deviceInfo->State)); if (group->PathToBeUsed == NULL) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): Will set PathToBeUsed for %p\n", deviceInfo, group)); deviceInfo = DsmpGetActivePathToBeUsed(group, DsmpIsSymmetricAccess(deviceInfo), SpecialHandlingFlag); if (deviceInfo != NULL) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): FOG %p set for PathToBeUsed for %p\n", deviceInfo, deviceInfo->FailGroup, group)); InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): No active/alternative path available for group %p\n", DsmId, group)); InterlockedExchangePointer(&(group->PathToBeUsed), NULL); } } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): Path %p is NOT usable.\n", DsmId, PathId)); retVal = FALSE; } ((PDSM_DEVICE_INFO)DsmId)->Usable = retVal; ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmIsPathActive (DevInfo %p): Exiting function with retVal = %!bool!.\n", DsmId, retVal)); return retVal; } NTSTATUS DsmPathVerify( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN PVOID PathId ) /*++ Routine Description: This routine ensures that the path to the device indicated by DsmId is healthy. It's called periodically by the bus driver, and also after a fail-over condition has been dealt with to ensure that the path is able to handle requests. Arguments: DsmContext - Context value given to the multipath driver during registration. DsmId - Value returned from DMSInquire. PathId - Value set in SetPathId. Return Value: NTSTATUS --*/ { PDSM_CONTEXT dsmCtxt = (PDSM_CONTEXT) DsmContext; PDSM_DEVICE_INFO deviceInfo = DsmId; PDSM_FAILOVER_GROUP foGroup; NTSTATUS status = STATUS_UNSUCCESSFUL; BOOLEAN found = FALSE; KIRQL irql; PLIST_ENTRY entry; PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry = NULL; PDSM_GROUP_ENTRY group = deviceInfo->Group; ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmPathVerify (DevInfo %p): Entering function.\n", DsmId)); if (DsmpIsDeviceInitialized(deviceInfo)) { irql = ExAcquireSpinLockExclusive(&(dsmCtxt->DsmContextLock)); // // Get the failover group // foGroup = DsmpFindFOGroup(DsmContext, PathId); if (foGroup) { // // Find the device. // for (entry = foGroup->FOG_DeviceList.Flink; entry != &foGroup->FOG_DeviceList; entry = entry->Flink) { fogDeviceListEntry = CONTAINING_RECORD(entry, DSM_FOG_DEVICELIST_ENTRY, ListEntry); if (fogDeviceListEntry && fogDeviceListEntry->DeviceInfo == deviceInfo) { status = STATUS_SUCCESS; found = TRUE; break; } } } else { // // This is not a good thing. It indicates that either we // returned a bogus path to the bus-driver on a fail-over, // or that the path evaporated between polls and PnP hasn't // torn stuff down. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmPathVerify (DevInfo %p): Failed to find failover group for path %p.\n", DsmId, PathId)); status = STATUS_DEVICE_NOT_CONNECTED; } ExReleaseSpinLockExclusive(&(dsmCtxt->DsmContextLock), irql); if (NT_SUCCESS(status)) { if (found) { // // Send down TUR if ALUA is not supported. // Else, send down ReportTargetPortGroups (sending TUR down non-A/O path will // always result in a check condition). // if (deviceInfo->ALUASupport == DSM_DEVINFO_ALUA_NOT_SUPPORTED) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmPathVerify (DevInfo %p): Sending TUR using %p to verify path %p.\n", DsmId, deviceInfo, deviceInfo->FailGroup->PathId)); status = DsmSendTUR(deviceInfo->TargetObject); } else { // // Check for whether we should ignore sending down an RTPG: // Flag set indicates that this PathVerify() is happening in response to device // arrival and can be skipped since Inquire() has just already sent down an RTPG. // All that needs to be done is to clear the flag so that subsequent PathVerify() // sent in response to InitiateFO will send RTPG as a ping. // This is an optimization with the idea of helping speed up boot time, which is // is adversely impacted, especially if there are many LUNs, each with many paths. // if (deviceInfo->IgnorePathVerify) { deviceInfo->IgnorePathVerify = FALSE; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmPathVerify (DevInfo %p): Returning success immediately since RTPG was already just sent.\n", DsmId)); status = STATUS_SUCCESS; } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmPathVerify (DevInfo %p): Sending RTPG using %p to verify path %p.\n", DsmId, deviceInfo, deviceInfo->FailGroup->PathId)); status = DsmpGetDeviceALUAState(dsmCtxt, deviceInfo, NULL); // // Since this RTPG may have resulted in us losing a UA, adjust // the states if needed. // if (NT_SUCCESS(status)) { DsmpAdjustDeviceStatesALUA(group, NULL, SpecialHandlingFlag); } } } } if (NT_SUCCESS(status)) { if (deviceInfo->State >= DSM_DEV_FAILED) { foGroup->State = DSM_FG_NORMAL; deviceInfo->State = deviceInfo->LastKnownGoodState; } } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmPathVerify (DevInfo %p): Exiting function with status %x.\n", DsmId, status)); return status; } NTSTATUS DsmInvalidatePath( _In_ IN PVOID DsmContext, _In_ IN ULONG ErrorMask, _In_ IN PVOID PathId, _Inout_ IN OUT PVOID *NewPathId ) /*++ Routine Description: This routine will mark up devices as failed on PathId, and find an appropriate path to return to MPIO. Arguments: DsmContext - Context value given to the multipath driver during registration. ErrorMask - Value returned from InterpretError. PathId - The failing path. NewPathId - Pointer to the new path. Return Value: NTSTATUS of the operation. --*/ { PDSM_CONTEXT context = DsmContext; PDSM_FAILOVER_GROUP failGroup; PDSM_FAILOVER_GROUP newPath = NULL; PDSM_FAILOVER_GROUP pathId; PDSM_DEVICE_INFO deviceInfo; LIST_ENTRY reservedDeviceList; NTSTATUS status = STATUS_SUCCESS; KIRQL irql; PLIST_ENTRY entry; PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry = NULL; BOOLEAN lockHeld = FALSE; UNREFERENCED_PARAMETER(ErrorMask); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmInvalidatePath (PathId %p): Entering function.\n", PathId)); DSM_ASSERT(ErrorMask & DSM_FATAL_ERROR); *NewPathId = NULL; InitializeListHead(&reservedDeviceList); irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock)); lockHeld = TRUE; // // Get the fail-over group corresponding to the PathId. // failGroup = DsmpFindFOGroup(DsmContext, PathId); if (!failGroup || failGroup->State == DSM_FG_FAILED) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInvalidatePath (PathId %p): Failed to find FailOver group.\n", PathId)); status = STATUS_NO_SUCH_DEVICE; goto __Exit_DsmInvalidatePath; } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmInvalidatePath (PathId %p): Context %p, FOG %p failing.\n", PathId, DsmContext, failGroup)); // // Mark the path as failed. // failGroup->State = DSM_FG_FAILED; // // Check to see whether the port driver and PnP removed the devices // BEFORE the fail-over indication actually occurred. Work-around // of several Fibre miniports. // if (failGroup->Count == 0) { // // There are no longer any devices in this fail-over group, which means // in order to get a back-pointer to the groups using this fail-over // group, we need to go through the "zombie" group list. This should // allow us to find a new path ID to return. //Then go through failGroup->ZombieGroupList to do failover for each group. // PDSM_ZOMBIEGROUP_ENTRY group; PDSM_GROUP_ENTRY groupEntry; // // Initialize all the entries to indicate that they haven't been processed. // for (entry = failGroup->ZombieGroupList.Flink; entry != &(failGroup->ZombieGroupList); entry = entry->Flink) { group = CONTAINING_RECORD(entry, DSM_ZOMBIEGROUP_ENTRY, ListEntry); group->Processed = FALSE; } // // Since we need to drop the spin lock while processing an entry, it is possible // that a removal in parallel frees up this entry during that time, thus making it // impossible for us to move to the next entry in the list. // In order to safely access each of the entries, we mark an entry as being processed // just before dropping the spinlock, and always start processing from the beginning // of the list, skipping over the already processed ones. // entry = failGroup->ZombieGroupList.Flink; while (entry != &(failGroup->ZombieGroupList)) { group = CONTAINING_RECORD(entry, DSM_ZOMBIEGROUP_ENTRY, ListEntry); entry = entry->Flink; if (!group || !group->Group || group->Processed) { continue; } group->Processed = TRUE; groupEntry = group->Group; ExReleaseSpinLockExclusive(&context->DsmContextLock, irql); lockHeld = FALSE; pathId = DsmpSetNewPathUsingGroup((PDSM_CONTEXT)DsmContext, groupEntry); if (!newPath) { newPath = pathId; // Save off first good alternative path that we find } if (!lockHeld) { irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock)); lockHeld = TRUE; entry = failGroup->ZombieGroupList.Flink; } } if (!newPath) { // // This indicates that all of the devices have already been removed. // If there were reservations outstanding, the RemoveDevice code // should have updated them. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInvalidatePath (PathId %p): Failed to find new path using zombie group list.\n", PathId)); } } else { // // Process each device in the fail-over group // for (entry = failGroup->FOG_DeviceList.Flink; entry != &failGroup->FOG_DeviceList; entry = entry->Flink) { fogDeviceListEntry = CONTAINING_RECORD(entry, DSM_FOG_DEVICELIST_ENTRY, ListEntry); if (!fogDeviceListEntry) { continue; } // // Get the deviceInfo. // deviceInfo = fogDeviceListEntry->DeviceInfo; if (!(DsmpIsDeviceFailedState(deviceInfo->State))) { deviceInfo->LastKnownGoodState = deviceInfo->State; } // // Set the state of the Failing Device // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_INVALIDATED; InterlockedIncrement(&deviceInfo->BlockRemove); ExReleaseSpinLockExclusive(&(context->DsmContextLock), irql); lockHeld = FALSE; pathId = DsmpSetNewPath(DsmContext, deviceInfo); if (!newPath) { newPath = pathId; // Save off first good alternative path that we find } if (!lockHeld) { irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock)); lockHeld = TRUE; } InterlockedDecrement(&deviceInfo->BlockRemove); } } if (!newPath) { // // This indicates that no acceptable paths // were found. Return the error to mpctl. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInvalidatePath (PathId %p): No valid path found.\n", PathId)); status = STATUS_NO_SUCH_DEVICE; } else { // // return the new path. // *NewPathId = newPath->PathId; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmInvalidatePath (PathId %p): Returning %p as newPath.\n", PathId, newPath->PathId)); } __Exit_DsmInvalidatePath: if (lockHeld) { ExReleaseSpinLockExclusive(&(context->DsmContextLock), irql); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmInvalidatePath (PathId %p): Exiting function with status %x.\n", PathId, status)); return status; } NTSTATUS DsmMoveDevice( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PVOID MPIOPath, _In_ IN PVOID SuggestedPath, _In_ IN ULONG Flags ) /*++ Routine Description: This routine is invoked in response to an administrative request. The device that's associated with SuggestedPath will be made active, and the current active device, moved to stand-by. Arguments: DsmContext - Context value given to the multipath driver during registration. DsmIds - The collection of DSM IDs that pertain to the MPDisk. MPIOPath - The original path value passed to SetDeviceInfo. SuggestedPath - The path which should become the active path. Flags - Bitmask indicating the intent of the move. Return Value: NTSTATUS - STATUS_SUCCESS, unless SuggestedPath is somehow invalid. STATUS_INVALID_PARAMETER is ADMIN is set and the path is invalid. --*/ { PDSM_CONTEXT context = DsmContext; PDSM_DEVICE_INFO deviceInfo; PDSM_FAILOVER_GROUP failGroup; ULONG i; NTSTATUS status; KIRQL irql; BOOLEAN adminRequest = FALSE; PDSM_GROUP_ENTRY group = NULL; ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmMoveDevice (DsmIds %p): Entering function - DsmContext %p MPIOPath (%p) SuggestedPath %p.\n", DsmIds, DsmContext, MPIOPath, SuggestedPath)); // // Capture the value of the ADMIN flag bit. // Currently, permanent assignment of the device to "preferred path" isn't supported. // This driver doesn't care about the pending remove flag (currently). // adminRequest = (BOOLEAN)(Flags & DSM_MOVE_ADMIN_REQUEST); irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock)); group = ((PDSM_DEVICE_INFO)(DsmIds->IdList[0]))->Group; // // Find the first active device. // deviceInfo = DsmpGetActivePathToBeUsed(group, DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmIds->IdList[0]), SpecialHandlingFlag); if (!deviceInfo) { // // Didn't find an active device. Should LOG. // Use the first one to piggy-back the request. // deviceInfo = DsmIds->IdList[0]; } // // Get the fail-over group associated with the Path. // failGroup = DsmpFindFOGroup(DsmContext, SuggestedPath); if (!failGroup) { // // The caller has made a terrible mistake. // If it's an ADMIN request, blow it off. // if (adminRequest) { status = STATUS_INVALID_PARAMETER; } else { // // Try to set another path. // // Note that failGroup will be NULL going into // SetNewPath. This is OK. // status = STATUS_SUCCESS; } } else { status = STATUS_SUCCESS; } if (status == STATUS_SUCCESS) { // // Set the new path, using SuggestedPath. // InterlockedIncrement(&deviceInfo->BlockRemove); ExReleaseSpinLockExclusive(&context->DsmContextLock, irql); failGroup = DsmpSetNewPath(context, deviceInfo); irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock)); InterlockedDecrement(&deviceInfo->BlockRemove); // // If we were able to make the suggested path active, that should be used. // for (i = 0, status = STATUS_UNSUCCESSFUL; i < DsmIds->Count && !NT_SUCCESS(status); i++) { deviceInfo = DsmIds->IdList[i]; if (deviceInfo->FailGroup == failGroup) { if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) { InterlockedExchangePointer(&(group->PathToBeUsed), (PVOID)failGroup); status = STATUS_SUCCESS; } } } } ExReleaseSpinLockExclusive(&(context->DsmContextLock), irql); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmMoveDevice (DsmIds %p): Exiting function with status %x.\n", DsmIds, status)); return status; } NTSTATUS DsmRemovePending( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId ) /*++ Routine Description: This routine indicates that the device represented by DsmId will be removed, so the deviceInfo is marked up to indicate the pending removal, so that it won't be used. Arguments: DsmContext - Context value given to the multipath driver during registration. DsmId - Value referring to the failed device. Return Value: STATUS_SUCCESS --*/ { PDSM_CONTEXT dsmContext = DsmContext; PDSM_DEVICE_INFO deviceInfo = DsmId; KIRQL irql; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmRemovePending (DevInfo %p): Entering function.\n", DsmId)); // // DsmpSetNewPath then finds the next available device. This is basically a // fail-over for just this device. // InterlockedIncrement(&deviceInfo->BlockRemove); DsmpSetNewPath(DsmContext, deviceInfo); irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock)); InterlockedDecrement(&deviceInfo->BlockRemove); if (!(DsmpIsDeviceFailedState(deviceInfo->State))) { deviceInfo->LastKnownGoodState = deviceInfo->State; } // // Mark the device as being unavailable since remove will be sent shortly. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_REMOVE_PENDING; ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmRemovePending (DevInfo %p): Exiting function.\n", DsmId)); return STATUS_SUCCESS; } NTSTATUS DsmRemoveDevice( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN PVOID PathId ) /*++ Routine Description: The device is gone and the port pdo has been removed. This routine will update the internal structures and free any allocations. Arguments: DsmContext - Context value given to the multipath driver during registration. DsmId - Value referring to the failed device. PathId - The path on which the Device lives. Return Value: STATUS_SUCCESS --*/ { PDSM_CONTEXT dsmContext = DsmContext; PDSM_DEVICE_INFO deviceInfo = DsmId; KIRQL irql; PDSM_FAILOVER_GROUP failGroup = deviceInfo->FailGroup; PDSM_GROUP_ENTRY group = deviceInfo->Group; LONG block; UNREFERENCED_PARAMETER(PathId); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmRemoveDevice (DevInfo %p): Entering function.\n", DsmId)); do { irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock)); block = deviceInfo->BlockRemove; NT_ASSERT(block >= 0); if (block) { ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); KeStallExecutionProcessor(10000); } } while (block); if (!(DsmpIsDeviceFailedState(deviceInfo->State))) { deviceInfo->LastKnownGoodState = deviceInfo->State; } deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = DSM_DEV_REMOVED; // // Decrement the reference count for this device's controller entry and // delete the entry if its reference count is now zero. // if (deviceInfo->Controller) { if (InterlockedDecrement((LONG volatile*)&(deviceInfo->Controller->RefCount)) == 0) { RemoveEntryList(&(deviceInfo->Controller->ListEntry)); DsmpFreeControllerEntry(dsmContext, deviceInfo->Controller); deviceInfo->Controller = NULL; InterlockedDecrement((LONG volatile*)&(dsmContext->NumberControllers)); } } // // Ensure that the device has been fully initialized before trying to // remove it from the FOG. If SetDeviceInfo has yet to be invoked, there // will yet to be an association set. // if (failGroup) { // // Remove its entry from the Fail-Over Group. // DsmpRemoveDeviceFailGroup(DsmContext, failGroup, deviceInfo, FALSE); } ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); // // Remove it from it's multi-path group. This has the side-effect // of cleaning up the Group if the number of devices goes to zero. // DsmpRemoveDeviceEntry(DsmContext, group, deviceInfo); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmRemoveDevice (DevInfo %p): Exiting function.\n", DsmId)); return STATUS_SUCCESS; } NTSTATUS DsmRemovePath( _In_ IN PVOID _DsmContext, _In_ IN PVOID PathId ) /*++ Routine Description: This routine indicates that the path is no longer valid, and that it should be removed. Internal counts will be updated and any allocations associated with this path freed. Arguments: DsmContext - Context value given to the multipath driver during registration. PathId - The path to remove. Return Value: NTSTATUS of the operation. --*/ { PDSM_FAILOVER_GROUP failGroup; KIRQL irql; PDSM_CONTEXT DsmContext = (PDSM_CONTEXT)_DsmContext; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmRemovePath (PathId %p): Entering function.\n", PathId)); irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); failGroup = DsmpFindFOGroup(DsmContext, PathId); if (failGroup) { // // The claim is that a path won't be removed, until all // the devices on it are. // if (failGroup->Count == 0) { // // Yank it from the list. // RemoveEntryList(&failGroup->ListEntry); InterlockedDecrement((LONG volatile*)&DsmContext->NumberFOGroups); // // Move this over to the stale FOG list if there are inflight requests. // Otherwise free the allocation. // if (InterlockedCompareExchange(&failGroup->NumberOfRequestsInFlight, 0, 0) > 0) { failGroup->State = DSM_FG_PENDING_REMOVE; InsertTailList(&DsmContext->StaleFailGroupList, &failGroup->ListEntry); InterlockedIncrement((LONG volatile*)&DsmContext->NumberStaleFOGroups); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmRemovePath (PathId %p): Outstanding requests %d. Moving FOGroup %p with path %p to stale path list.\n", PathId, failGroup->NumberOfRequestsInFlight, failGroup, failGroup->PathId)); } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmRemovePath (PathId %p): Removing FOGroup %p with path %p. Count of FOGroups %d.\n", PathId, failGroup, failGroup->PathId, DsmContext->NumberFOGroups)); // // Free the zombie group list and then the failover group. // DsmpFreeZombieGroupList(failGroup); DsmpFreePool(failGroup); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmRemovePath (PathId %p): Count %d. Not removing FOGroup %p.\n", PathId, failGroup->Count, failGroup)); // // Should never be here. // NT_ASSERT(failGroup->Count == 0); } } else { // // It's already been removed. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmRemovePath (PathId %p): Did not find the FO group.\n", PathId)); NT_ASSERT(failGroup); } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmRemovePath (PathId %p): Exiting function.\n", PathId)); return STATUS_SUCCESS; } PVOID DsmLBGetPath( _In_ IN PVOID DsmContext, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PDSM_IDS DsmList, _In_ IN PVOID CurrentPath, _Out_ OUT NTSTATUS *Status ) /*++ Routine Description: This routine is used by mpio to handle load-balancing. Arguments: DsmContext - Context value given to the multipath driver during registration. Srb - The current read/write Srb. DsmList - List of our DSM IDs. CurrentPath - The last path that was returned for this multi-path group. Status - Storage to place NTSTATUS of the call. Return Value: The path ID to which the request should be sent. --*/ { PDSM_CONTEXT dsmContext = DsmContext; PDSM_DEVICE_INFO deviceInfo; PDSM_GROUP_ENTRY group; PDSM_FAILOVER_GROUP failGroup = NULL; PVOID newPath = NULL; PDSM_FAILOVER_GROUP oldFailGroup = NULL; PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failPathDevInfoEntry = NULL; PCDB cdb = NULL; UCHAR opCode = 0xFF; BOOLEAN lockInExclusiveMode = FALSE; ULONG SpecialHandlingFlag = 0; if (Srb) { cdb = SrbGetCdb(Srb); if (cdb) { opCode = cdb->AsByte[0]; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmLBGetPath (DsmIds %p): Entering function.\n", DsmList)); // // Up-front checking to minimally validate the list of // DsmId's being passed in. // NT_ASSERT(DsmList->Count && DsmList->IdList[0]); if (!(DsmList->Count && DsmList->IdList[0])) { *Status = STATUS_NO_SUCH_DEVICE; goto __Exit_DsmLBGetPath; } deviceInfo = DsmList->IdList[0]; group = deviceInfo->Group; failGroup = DsmpGetPath(dsmContext, DsmList, Srb, SpecialHandlingFlag); // // If there wasn't a single active/optimized path found, check to see if // there is an STPG in progress that may be making a path A/O. // if (!failGroup) { // // Take the last path used. // oldFailGroup = DsmpFindFOGroup(dsmContext, CurrentPath); // // Find the devInfo corresponding to this path. // deviceInfo = DsmpFindDevInfoFromGroupAndFOGroup(dsmContext, group, oldFailGroup); if (deviceInfo) { // // Check if there is an alternate devInfo to be used temporarily // for this deviceInfo // failPathDevInfoEntry = DsmpFindFailPathDevInfoEntry(dsmContext, group, deviceInfo); if (failPathDevInfoEntry) { // // Use the alternate devInfo for now temporarily while the STPG // that was previously sent (asynchronously) works on making the // appropriate path active/optimized. // failGroup = (failPathDevInfoEntry->TempDeviceInfo)->FailGroup; } TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmLBGetPath (DsmIds %p): Couldn't find FOG but FO in progress, so returning devInfo %p (FOG %p path %p).\n", DsmList, deviceInfo, deviceInfo->FailGroup, deviceInfo->FailGroup->PathId)); } else { // // Check if there is an RTPG in progress, if yes, return some path // for the IO to be sent down. // if (InterlockedCompareExchange((LONG volatile*)&group->InFlightRTPG, 0, 0)) { BOOLEAN sendTPG = FALSE; deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag); if (deviceInfo) { failGroup = deviceInfo->FailGroup; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmLBGetPath (DsmIds %p): Couldn't find FOG but RTPG inflight, so returning devInfo %p (FOG %p path %p).\n", DsmList, deviceInfo, deviceInfo->FailGroup, deviceInfo->FailGroup->PathId)); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmLBGetPath (DsmIds %p): Couldn't find FOG but RTPG inflight, even then couldn't find alternative devInfo.\n", DsmList)); } } } } if (failGroup) { newPath = failGroup->PathId; *Status = STATUS_SUCCESS; // // If this is a retried request, our SetCompletion would have been bypassed, // and our completion routine won't yet get called, so update the old and // the new paths' stats. // if (Srb && DsmIsReadWrite(opCode)) { PDSM_FAILOVER_GROUP oldPath; PIRP irp = (PIRP)SrbGetOriginalRequest(Srb); PIO_STACK_LOCATION irpStack; // // This indicates that the request is being retried. So we need to: // 1. Update old path's and new path's request count // 2. If the old path was supposed to be removed, check if there is // no more outstanding request, and if so, remove the path // irpStack = IoGetCurrentIrpStackLocation(irp); oldPath = irpStack->Parameters.Others.Argument3; if (oldPath) { NT_ASSERT(oldPath->FailOverSig == DSM_FOG_SIG); if (DsmpDecrementCounters(oldPath, Srb)) { // // If there are no requests on a path that is supposed to be removed, // remove it now. // if (oldPath->State == DSM_FG_PENDING_REMOVE) { KIRQL irql; NT_ASSERT(oldPath->Count == 0); // // We need to acquire the DsmContextLock in Exclusive mode since // we are removing a path from the Failover Group list. // irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock)); lockInExclusiveMode = TRUE; RemoveEntryList(&oldPath->ListEntry); InterlockedDecrement((LONG volatile*)&dsmContext->NumberStaleFOGroups); ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmLBGetPath (DsmIds %p): Removing FOGroup %p with path %p.\n", DsmList, oldPath, oldPath->PathId)); DsmpFreePool(oldPath); } } irpStack->Parameters.Others.Argument3 = failGroup; DsmpIncrementCounters(failGroup, Srb); } } } else { *Status = STATUS_NO_SUCH_DEVICE; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmLBGetPath (DsmIds %p): Failed to get FO group in LBGetPath.\n", DsmList)); } __Exit_DsmLBGetPath: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmLBGetPath (DsmIds %p): Exiting function returning path %p for request %p.\n", DsmList, newPath, Srb)); return newPath; } _Success_(return == DSM_PATH_SET) ULONG DsmCategorizeRequest( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PVOID CurrentPath, _Outptr_result_maybenull_ OUT PVOID *PathId, _Out_ OUT NTSTATUS *Status ) /*++ Routine Description: This routine is called when a request is received other than a read/write. It will determine the best path to which the request is to be sent. In order to support clusters, reserve and release need to be handled via SrbControl. Arguments: DsmContext - Context value given to the multipath driver during registration. DsmIds - List of our DSM IDs. Irp - The Irp containing Srb. Srb - The current non-read/write Srb. CurrentPath - The last path that was returned for this multi-path group. PathId - Placeholder for the PathID Status - Storage to place NTSTATUS of the call. Return Value: DSM_PATH_SET - Indicates PathID is valid. DSM_ERROR - Couldn't get a path. --*/ { ULONG dsmStatus; NTSTATUS status = STATUS_UNSUCCESSFUL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmCategorizeRequest (DsmIds %p): Entering function.\n", DsmIds)); // // Determine whether this is a special-case request. // if (DsmpReservationCommand(Irp, Srb)) { dsmStatus = DSM_WILL_HANDLE; goto __Exit_DsmCategorizeRequest; } // // If this is a mpio pass through or a mpio pass through direct request, // pick the path that corresponds to the pathId specified. // if (DsmpMpioPassThroughPathCommand(Irp)) { *PathId = DsmpGetPathIdFromPassThroughPath(DsmContext, DsmIds, Irp, &status); } else { // // For requests other than reservation-handling and pass through, punt // it back to the bus-driver. Need to get a path for the request first, // so call the Load-Balance function. // *PathId = DsmLBGetPath(DsmContext, Srb, DsmIds, CurrentPath, &status); } if (NT_SUCCESS(status)) { if (!*PathId) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmCategorizeRequest (DsmIds %p): DSM_PATH_SET didn't return a path.\n", DsmIds)); } // // Indicate that the path is updated, and mpctl should handle the request. // dsmStatus = DSM_PATH_SET; } else { // // Indicate the error back to mpctl. // dsmStatus = DSM_ERROR; // // Mark-up the Srb to show that a failure has occurred. // This value is really only for this DSM to know what to do // in the InterpretError routine - Fatal Error. // It could be something more meaningful. // if (Srb) { Srb->SrbStatus = SRB_STATUS_NO_DEVICE; } *PathId = NULL; } // // Pass back status info to mpctl. // *Status = status; __Exit_DsmCategorizeRequest: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmCategorizeRequest (DsmIds %p): Exiting function with categorization %x.\n", DsmIds, dsmStatus)); return dsmStatus; } NTSTATUS DsmBroadcastRequest( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PKEVENT Event ) /*++ Routine Description: This routine is called when the DSM has indicated that Srb should be sent to the device down all paths. The DSM will update IoStatus information and status, but not complete the request. Currently MSDSM doesn't have a need for this. Arguments: DsmIds - The collection of DSM IDs that pertain to the MPDisk. Irp - Irp containing SRB. Srb - Scsi request block Event - DSM sets this once all sub-requests have completed and the original request's IoStatus has been setup. Return Value: NTSTATUS of the operation. --*/ { NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; UNREFERENCED_PARAMETER(DsmContext); UNREFERENCED_PARAMETER(Srb); UNREFERENCED_PARAMETER(Irp); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmBroadcastRequest (DsmIds %p): Entering function.\n", DsmIds)); // // Currently nothing is handled via Broadcast. Just set the event to // free up the request handling in the bus-driver. // NT_ASSERT(NT_SUCCESS(status)); KeSetEvent(Event, 0, FALSE); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmBroadcastReqeust (DsmIds %p): Exiting function with status %x.\n", DsmIds, status)); return status; } NTSTATUS DsmSrbDeviceControl( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PKEVENT Event ) /*++ Routine Description: This routine is called when the DSM has indicated that it wants to handle it internally (via returning DSM_WILL_HANDLE in CategorizeRequest). It should set IoStatus (Status and Information) and the Event, but not complete the request. Arguments: DsmContext - The DSM's context DsmIds - The collection of DSM IDs that pertain to the MPDISK. Irp - Irp containing SRB. Srb - Scsi request block Event - Event to be set when the DSM is finished if DsmHandled is TRUE Return Value: NTSTATUS of the request. --*/ { PDSM_CONTEXT dsmContext = DsmContext; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status; UCHAR opCode = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmSrbDeviceControl (DsmIds %p): Entering function.\n", DsmIds)); if (!DsmIds || !DsmIds->Count) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DsmSrbDeviceControl (DsmIds %p): No DsmIds passed in.\n", DsmIds)); status = STATUS_NO_SUCH_DEVICE; goto __Exit_DsmSrbDeviceControl; } if (irpStack->MajorFunction == IRP_MJ_SCSI) { // // Determine the operation. // PCDB cdb = SrbGetCdb(Srb); if (cdb) { opCode = cdb->AsByte[0]; } if (opCode == SCSIOP_PERSISTENT_RESERVE_OUT) { status = DsmpPersistentReserveOut(dsmContext, DsmIds, Irp, Srb, Event); } else if (opCode == SCSIOP_PERSISTENT_RESERVE_IN) { status = DsmpPersistentReserveIn(dsmContext, DsmIds, Irp, Srb, Event); } else { // // Should never be here. // DSM_ASSERT(FALSE); status = STATUS_INVALID_DEVICE_REQUEST; } } else { // // Should never be here. // DSM_ASSERT(irpStack->MajorFunction == IRP_MJ_SCSI); status = STATUS_INVALID_DEVICE_REQUEST; } __Exit_DsmSrbDeviceControl: if (status != STATUS_PENDING) { // // Set-up the Irp status for mpio's completion of the request. // If it was IRP_MJ_SCSI, one of the helper routines set Srb->SrbStatus // already. // if ((irpStack->MajorFunction == IRP_MJ_SCSI) && (Srb != NULL) && (Srb->SrbStatus == SRB_STATUS_PENDING)) { Srb->SrbStatus = SRB_STATUS_ERROR; } Irp->IoStatus.Status = status; // // Set the event to free up the request handling in the bus-driver. // KeSetEvent(Event, 0, FALSE); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmSrbDeviceControl (DsmIds %p): Exiting function with status %x.\n", DsmIds, status)); return status; } VOID DsmSetCompletion( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _Inout_ IN OUT PDSM_COMPLETION_INFO DsmCompletion ) /*++ Routine Description: This routine is called before the actual submission of a request, but after the categorisation of the I/O. This will be called only for those requests not handled by the DSM directly: Read/Write Other requests not handled by SrbControl or Broadcast Arguments: DsmContext - The DSM's context. DsmId - Identifer that was indicated when the request was categorized (or be LBGetPath) Irp - Irp containing Srb. Srb - The request DsmCompletion - Completion info structure to be filled out by DSM. Return Value: None --*/ { PDSM_CONTEXT dsmContext = DsmContext; PDSM_DEVICE_INFO deviceInfo = DsmId; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PDSM_FAILOVER_GROUP failGroup = deviceInfo->FailGroup; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmSetCompletion (DevInfo %p): Entering function.\n", DsmId)); // // Save off the path that was selected to service this request in Argument3. // irpStack->Parameters.Others.Argument3 = failGroup; DsmpIncrementCounters(failGroup, Srb); if (!dsmContext->DisableStatsGathering) { // // Indicate one more request on this device down this path. // InterlockedIncrement(&deviceInfo->NumberOfRequestsInProgress); } // // Update the passed-in struct with our routine and context values. // DsmCompletion->DsmCompletionRoutine = DsmpRequestComplete; DsmCompletion->DsmContext = DsmContext; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmSetCompletion (DevInfo %p): Exiting function.\n", DsmId)); return; } ULONG DsmInterpretError( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN PSCSI_REQUEST_BLOCK Srb, _Inout_ IN OUT NTSTATUS *Status, _Out_ OUT PBOOLEAN Retry, _Out_ OUT PLONG RetryInterval, ... ) /*++ Routine Description: This routine is invoked by MPIO if Status is other than SUCCESS. A few NTSTATUS and SRB_STATUS values indicate a fatal error. Also checked are unit attentions, for which a retry is requested. Arguments: DsmContext - The DSM's context. DsmId - Identifers returned from DMS_INQUIRE_DRIVER. Srb - The Srb with an error. Status - NTSTATUS of the operation. Can be updated. Retry - Allows the DSM to indicate whether to retry the IO. RetryInterval - Lets DSM specify (in seconds) when this specific I/O should be retried. Use MAXLONG to use the default retry interval. Use zero to retry immediately. Return Value: DSM_FATAL_ERROR indicates a fatal error. --*/ { // // The requests that will be encountered can be divided into four categories: // 1. The request that has failed. // 2. Subsequent requests that were sent down the failing path that will // complete with failure. // 3. Requests that were already submitted to LBGetPath() just before InterpretError() // was called for the failed request (but have yet to have the LB policy // algo run). // 4. Requests that come into the Dispatch() routine after the failed request // has been processed by InterpretError(). // // For the failed request: // ======================= // 1. Find a standby path to make active/optimized. // 2. Send STPG asynchronously as a scsi pass through via IRP_MJ_SCSI (this // way it can be sent at DISPATCH_IRQL) after setting a completion routine. // 3. Save the devInfo corresponding to the standby path for the failing devInfo. // 4. Return FATAL to MPIO so that new IO are queued. // 5. In the completion routine, update the new states for the devInfos. Then // clear the saved (previously) standby devInfo for the failing devInfo. // // For the subsequent request that will fail (since it was sent on the failing path): // ================================================================================== // 1. If a standby devInfo has been saved off, it indicates that an STPG was // already sent, so no need to send another one. // 2. Return FATAL to MPIO so that this request gets queued. // // For the requests that were already submitted to LBGetPath() during this time: // ============================================================================= // 1. If there is no active path, check if a standby devInfo has been saved // away. If it has, return this path. Such requests will fail with check // condition saying path used is in standby. // 2. In InterpretError() retry (since the error indicates that request // completed before STPG completed) without decrementing the remaining // retries count. // // For new requests that come into Dispatch() after above processing: // ================================================================== // We don't need to worry about such requests, since MPIO will queue them // automatically. // PDSM_DEVICE_INFO deviceInfo = DsmId; ULONG errorMask = 0; PVOID senseData = SrbGetSenseInfoBuffer(Srb); UCHAR senseDataLength = SrbGetSenseInfoBufferLength(Srb); BOOLEAN failover = FALSE; BOOLEAN retry = FALSE; BOOLEAN handled = FALSE; BOOLEAN sendTPG = FALSE; BOOLEAN tpgException = FALSE; BOOLEAN devInfoException = FALSE; PCDB cdb = SrbGetCdb(Srb); UCHAR opCode = 0; UCHAR scsiStatus = SrbGetScsiStatus(Srb); BOOLEAN validSense = FALSE; UCHAR senseKey = 0; UCHAR addSenseCode = 0; UCHAR addSenseCodeQualifier = 0; if (cdb) { opCode = cdb->AsByte[0]; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Entering function.\n", DsmId)); *RetryInterval = MAXLONG; if ((scsiStatus == SCSISTAT_RESERVATION_CONFLICT) || (*Status == STATUS_DEVICE_BUSY)) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Srb %p. Either busy or res. conflict (%x %x).\n", DsmId, Srb, scsiStatus, *Status)); } // // Go ahead and get the sense data if it's valid. // if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) { NT_ASSERT(senseData != NULL); validSense = ScsiGetSenseKeyAndCodes(senseData, senseDataLength, SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, &senseKey, &addSenseCode, &addSenseCodeQualifier); } // // Sense data relating to logical block provisioning should be failed // immediately back to the class layer for handling. // if (validSense) { if (senseKey == SCSI_SENSE_NOT_READY && addSenseCode == SCSI_ADSENSE_LUN_NOT_READY && addSenseCodeQualifier == SCSI_SENSEQ_SPACE_ALLOC_IN_PROGRESS) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Temporary resource exhaustion. Fail Srb %p.\n", DsmId, Srb)); handled = TRUE; } else if (senseKey == SCSI_SENSE_DATA_PROTECT && addSenseCode == SCSI_ADSENSE_WRITE_PROTECT && addSenseCodeQualifier == SCSI_SENSEQ_SPACE_ALLOC_FAILED_WRITE_PROTECT) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Permanent resource exhaustion. Fail Srb %p.\n", DsmId, Srb)); handled = TRUE; } else if (senseKey == SCSI_SENSE_UNIT_ATTENTION && addSenseCode == SCSI_ADSENSE_LB_PROVISIONING && addSenseCodeQualifier == SCSI_SENSEQ_SOFT_THRESHOLD_REACHED) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Soft threshold reached. Fail Srb %p.\n", DsmId, Srb)); handled = TRUE; } else if (senseKey == SCSI_SENSE_UNIT_ATTENTION && addSenseCode == SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED && addSenseCodeQualifier == SCSI_SENSEQ_INQUIRY_DATA_CHANGED) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Inquiry data changed. Fail Srb %p.\n", DsmId, Srb)); handled = TRUE; } else if (senseKey == SCSI_SENSE_UNIT_ATTENTION && addSenseCode == SCSI_ADSENSE_PARAMETERS_CHANGED && addSenseCodeQualifier == SCSI_SENSEQ_CAPACITY_DATA_CHANGED) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Capacity data changed. Fail Srb %p.\n", DsmId, Srb)); handled = TRUE; } } if (handled) { return errorMask; } // // Check the NT Status first. // Several are clearly failover conditions. // switch (*Status) { case STATUS_DEVICE_NOT_CONNECTED: case STATUS_DEVICE_DOES_NOT_EXIST: case STATUS_NO_SUCH_DEVICE: case STATUS_DELETE_PENDING: { // // The port pdo has either been removed or is // very broken. A fail-over is necessary. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Will initiate fail over. Status %x. Opcode %x.\n", DsmId, *Status, opCode)); handled = TRUE; failover = TRUE; break; } case STATUS_IO_DEVICE_ERROR: { if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) { if (validSense) { // // See if it's a unit attention. // if (senseKey == SCSI_SENSE_UNIT_ATTENTION) { switch (addSenseCode) { case SCSI_ADSENSE_PARAMETERS_CHANGED: { switch (addSenseCodeQualifier) { case SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_CHANGED: case SPC3_SCSI_SENSEQ_IMPLICIT_ASYMMETRIC_ACCESS_STATE_TRANSITION_FAILED: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): TPG states have changed. Requesting retry on Srb %p. Will send asyn RTPG.\n", DsmId, Srb)); // // Retry but after sending RTPG, which will update the path states. // sendTPG = TRUE; retry = TRUE; handled = TRUE; errorMask = DSM_RETRY_DONT_DECREMENT; if (addSenseCodeQualifier == SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_CHANGED) { // // Worth retrying on the same path. // devInfoException = TRUE; NT_ASSERT(!tpgException); } break; } case SPC3_SCSI_SENSEQ_RESERVATIONS_RELEASED: { // // This request needs to be immediately retried down the same path. // retry = TRUE; *RetryInterval = 0; handled = TRUE; InterlockedExchangePointer(&(deviceInfo->Group->PathToBeUsed), deviceInfo->FailGroup); break; } case SPC3_SCSI_SENSEQ_MODE_PARAMETERS_CHANGED: case SPC3_SCSI_SENSEQ_RESERVATIONS_PREEMPTED: case SPC3_SCSI_SENSEQ_REGISTRATIONS_PREEMPTED: case SPC3_SCSI_SENSEQ_CAPACITY_DATA_HAS_CHANGED: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Failing request. STATUS_IO_DEVICE_ERROR (params changed). SrbStatus (%x) Scsi (%x) AddQual (%u).\n", DsmId, Srb->SrbStatus, scsiStatus, addSenseCodeQualifier)); // // Just fail these back. // handled = TRUE; break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): UNIT_ATTENTION for params changed. ASCQ %x. Asking for retry on Srb %p.\n", DsmId, addSenseCodeQualifier, Srb)); // // Indicate that a retry is necessary. // retry = TRUE; handled = TRUE; break; } } break; } case SPC3_SCSI_ADSENSE_COMMANDS_CLEARED_BY_ANOTHER_INITIATOR: { if (addSenseCodeQualifier == 0x00) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): UNIT_ATTENTION (commands cleared by another initiator). Fail back to upper level. Srb %p.\n", DsmId, Srb)); // // Commands cleared by another Initiator // handled = TRUE; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): UNIT_ATTENTION (commands cleared by another initiator). ASCQ %x. Asking for retry on Srb %p.\n", DsmId, addSenseCodeQualifier, Srb)); // // Indicate that a retry is necessary. // retry = TRUE; handled = TRUE; } break; } case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: { if (addSenseCodeQualifier == SCSI_SENSEQ_VOLUME_SET_MODIFIED || addSenseCodeQualifier == SCSI_SENSEQ_REPORTED_LUNS_DATA_CHANGED) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): VolumeSet/LunsData changed. Fail Srb %p.\n", DsmId, Srb)); // // Fail back to upper layers. // handled = TRUE; break; } else { // // Fall through to default case (ie. retry the request) // } } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): UNIT_ATTENTION. ASC %x, ASCQ %x. Asking for retry on Srb %p.\n", DsmId, addSenseCode, addSenseCodeQualifier, Srb)); // // Indicate that a retry is necessary. // retry = TRUE; handled = TRUE; break; } } } else if (senseKey == SCSI_SENSE_NOT_READY) { if (addSenseCode == SCSI_ADSENSE_LUN_NOT_READY) { if (scsiStatus == SCSISTAT_CHECK_CONDITION) { switch (addSenseCodeQualifier) { // // See if failure is due to device's current TPG state. // // If the failure is PORT_IN_STANDBY_STATE, we leave DSM_RETRY_DONT_DECREMENT unset if no active path exists, // because otherwise MPIO will not be able to find a better path, and it will get into an infinite loop // of trying and failing the command on a Standby path. See WCxeTfs:89150 // case SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION: case SPC3_SCSI_SENSEQ_TARGET_PORT_IN_UNAVAILABLE_STATE: errorMask = DSM_RETRY_DONT_DECREMENT; case SPC3_SCSI_SENSEQ_TARGET_PORT_IN_STANDBY_STATE: TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): TPG-transition/TPG-SB/TPG-UA. ASCQ %x. Will send down async RTPG. Asking for retry on Srb %p.\n", DsmId, addSenseCodeQualifier, Srb)); // // Indicate that a retry is necessary but without decrementing the remaining // retries count. However, we may need to send down an STPG/RTPG also. // And we must set PTBU to a path that is in a different TPG. // sendTPG = TRUE; tpgException = TRUE; NT_ASSERT(!devInfoException); retry = TRUE; handled = TRUE; if ((addSenseCodeQualifier == SPC3_SCSI_SENSEQ_TARGET_PORT_IN_STANDBY_STATE) && DsmIsReadWrite(opCode)) { PDSM_CONTEXT context = (PDSM_CONTEXT) deviceInfo->DsmContext; KIRQL oldIrql = ExAcquireSpinLockExclusive(&(context->DsmContextLock)); BOOLEAN activePathExists = ( NULL != DsmpGetAnyActivePath(deviceInfo->Group, FALSE, NULL, 0) ); ExReleaseSpinLockExclusive(&(context->DsmContextLock), oldIrql); if (activePathExists) { errorMask = DSM_RETRY_DONT_DECREMENT; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Not decrementing error counter, as an active path exists in group %p and opcode %x is r/w\n", DsmId, deviceInfo->Group, opCode)); } } break; case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Manual intervention required. Asking for retry on Srb %p.\n", DsmId, Srb)); // // This may be caused by NDU of controller firmware. It does not // necessarily indicate that the device won't be ready via other path(s). // Worth retrying instead of immediately failing back. // retry = TRUE; handled = TRUE; break; } } } } } } else if (Srb->SrbStatus == SRB_STATUS_BUS_RESET) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): BUS_RESET. Failing back Srb %p.\n", DsmId, Srb)); // // Upper layers will retry in this case. If we retry here it will // have a multiplicative effect which may result in a very long // IO completion time if the device persistently times out. // retry = FALSE; handled = TRUE; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Failing request. STATUS_IO_DEVICE_ERROR. SrbStatus (%x) ScsiStatus (%x).\n", DsmId, Srb->SrbStatus, scsiStatus)); } break; } case STATUS_BUFFER_OVERFLOW: { if (DsmIsReadWrite(opCode)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): BUFFER_OVERFLOW: Retry.\n", DsmId)); // // Retry these, as this condition might indicate a torn write. // retry = TRUE; handled = TRUE; } break; } case STATUS_DEVICE_BUSY: { // // See if it's a check condition for TPG states in transition. // if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID && scsiStatus == SCSISTAT_CHECK_CONDITION) { if (validSense) { if (senseKey == SCSI_SENSE_NOT_READY && addSenseCode == SCSI_ADSENSE_LUN_NOT_READY && addSenseCodeQualifier == SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): TPG transition. Will send down async RTPG. Asking for retry on Srb %p.\n", DsmId, Srb)); // // Indicate that a retry is necessary but without decrementing the remaining // retries count. However, we may need to send down an STPG/RTPG also. // And we must set PTBU to a path that is in a different TPG. // sendTPG = TRUE; tpgException = TRUE; NT_ASSERT(!devInfoException); retry = TRUE; handled = TRUE; errorMask = DSM_RETRY_DONT_DECREMENT; } } } break; } case STATUS_DEVICE_NOT_READY: { if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID && scsiStatus == SCSISTAT_CHECK_CONDITION) { if (validSense) { if (senseKey == SCSI_SENSE_NOT_READY && addSenseCode == SCSI_ADSENSE_LUN_NOT_READY) { switch (addSenseCodeQualifier) { case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Manual intervention required. Asking for retry on Srb %p.\n", DsmId, Srb)); // // This may be caused by NDU of controller firmware. It does not // necessarily indicate that the device won't be ready via other path(s). // Worth retrying instead of immediately failing back. // retry = TRUE; handled = TRUE; break; } case SCSI_SENSEQ_SPACE_ALLOC_IN_PROGRESS: { // // This indicates a logical block provisioning temporary resource exhaustion // condition and therefore we must allow the class layer to handle it. // retry = FALSE; handled = TRUE; break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Unhandled AddQual %x.\n", DsmId, addSenseCodeQualifier)); break; } } } } } } default: { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Unhandled status code %x.\n", DsmId, *Status)); break; } } if (!handled) { // // The NTSTATUS didn't indicate a fail-over condition, but // check various srb status for failover-class error. // switch (Srb->SrbStatus) { case SRB_STATUS_SELECTION_TIMEOUT: case SRB_STATUS_INVALID_LUN: case SRB_STATUS_INVALID_TARGET_ID: case SRB_STATUS_NO_DEVICE: case SRB_STATUS_NO_HBA: case SRB_STATUS_INVALID_PATH_ID: { // // All of these are fatal. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): SrbStatus 0x%x. Will initiate fail over.\n", DsmId, Srb->SrbStatus)); failover = TRUE; break; } default: { if ((scsiStatus == SCSISTAT_CHECK_CONDITION) && (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) { if (validSense) { switch (senseKey) { case SCSI_SENSE_NO_SENSE: { if (addSenseCode == SCSI_ADSENSE_NO_SENSE && addSenseCodeQualifier == SCSI_SENSEQ_CAUSE_NOT_REPORTABLE) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): CheckCondition with no sense info. Will initiate fail over.\n", DsmId)); // // This could be a transient error generated // in response to potentially a hardware fault. // Worth trying another path. // failover = TRUE; handled = TRUE; } break; } case SCSI_SENSE_ILLEGAL_REQUEST: { if (addSenseCode == SCSI_ADSENSE_INVALID_LUN) { if (addSenseCodeQualifier == 0x00) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Invalid LUN. Will initiate fail over.\n", DsmId)); // // LUN may still exist on other path(s). // Worth a failover. // failover = TRUE; handled = TRUE; } } break; } case SCSI_SENSE_HARDWARE_ERROR: { if (addSenseCode == SPC3_SCSI_ADSENSE_LOGICAL_UNIT_COMMAND_FAILED) { if (addSenseCodeQualifier == SPC3_SCSI_SENSEQ_SET_TARGET_PORT_GROUPS_FAILED) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): STPG failed. Will initiate fail over.\n", DsmId)); // // If an STPG failed, treat as FATAL and get another // path set to A/O via another STPG. // failover = TRUE; handled = TRUE; } } else if ((addSenseCode == SCSI_ADSENSE_LOGICAL_UNIT_ERROR && addSenseCodeQualifier == SCSI_SENSEQ_TIMEOUT_ON_LOGICAL_UNIT) || (addSenseCode == SCSI_ADSENSE_DATA_TRANSFER_ERROR && addSenseCodeQualifier == SCSI_SENSEQ_INITIATOR_RESPONSE_TIMEOUT)) { // // Could potentially indicate a dropped FC packet. Retry (along another // path, based on the LB policy). // retry = TRUE; handled = TRUE; } break; } default: { break; } } } } if (!handled) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Unhandled SRB Status 0x%x. Sense data %x|%x|%x.\n", DsmId, Srb->SrbStatus, validSense ? senseKey : 0xFF, validSense ? addSenseCode : 0xFF, validSense ? addSenseCodeQualifier : 0xFF)); } break; } } } if (failover) { ULONG SpecialHandlingFlag = 0; // // If ALUA is supported, then it is possible that we may need to send // down an STPG so build an IRP and fill in the SRB for STPG and send it down. // if (!DsmpIsSymmetricAccess(deviceInfo)) { DsmpSetLBForPathFailingALUA(DsmContext, deviceInfo, TRUE, SpecialHandlingFlag); } else { // // If device doesn't support ALUA, we just need to update // states without sending down any commands (STPG) // DsmpSetLBForPathFailing(DsmContext, deviceInfo, TRUE, SpecialHandlingFlag); } errorMask = DSM_FATAL_ERROR; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmInterpretError(DevInfo %p): Device changed to state %d\n", deviceInfo, deviceInfo->State)); #if DBG { ULONG inx; PDSM_GROUP_ENTRY group = deviceInfo->Group; PDSM_DEVICE_INFO tempDevInfo; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Device %p in group %p being marked as failed. NTStatus 0x%x.\n", DsmId, deviceInfo, group, *Status)); for (inx = 0; inx < group->NumberDevices; inx++) { tempDevInfo = group->DeviceList[inx]; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Device %p at %d. State %d.\n", DsmId, tempDevInfo, inx, tempDevInfo->State)); } } #endif // DBG } if (retry) { if (sendTPG) { // // If ALUA is supported, send down STPG/RTPG as appropriate. // if (!DsmpIsSymmetricAccess(deviceInfo)) { DsmpSetPathForIoRetryALUA(DsmContext, deviceInfo, tpgException, devInfoException); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "DsmInterpretError(DevInfo %p): SRB request %p will be retried. PTBU set to %p.\n", deviceInfo, Srb, deviceInfo->Group->PathToBeUsed)); } } } *Retry = retry; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmInterpretError (DevInfo %p): Exiting function returning errorMask %x.\n", DsmId, errorMask)); return errorMask; } BOOLEAN DsmIsAddressTypeSupported( _In_ IN PVOID DsmContext, _In_ IN ULONG AddressType ) /*++ Routine Description: This routine is called when MPIO wants to know if the DSM supports a particular storage address type. This routine must be provided for DSMs of DsmType6 or higher. Arguments: DsmContext - Context value passed to DsmInitialize() AddressType - The storage address type being queried. Return Value: TRUE - If the DSM supports the given storage address type. FALSE - If the DSM does not support the given storage address type. --*/ { UNREFERENCED_PARAMETER(DsmContext); if (AddressType == STORAGE_ADDRESS_TYPE_BTL8) { return TRUE; } return FALSE; } NTSTATUS DsmDeviceNotUsed( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId ) /*++ Routine Description: This routine indicates that the device represented by DsmId will not be initialized completely by MPIO. The DSM_ID list passed to other functions will no longer contain DsmId, so internal structures should be updated accordingly. This routine must be provided for DSMs of DsmType6 or higher. Arguments: DsmContext - Context value given to the multipath driver during registration. DsmId - Value referring to the uninitialized device. Return Value: NTSTATUS of the operation. --*/ { PDSM_DEVICE_INFO deviceInfo = (PDSM_DEVICE_INFO)DsmId; DSM_ASSERT(deviceInfo->Group != NULL); DSM_ASSERT(deviceInfo->Group->GroupSig == DSM_GROUP_SIG); // // Undo anything we did to build up the device in DsmInquire(). // DsmRemoveDevice((PDSM_CONTEXT)DsmContext, DsmId, deviceInfo->FailGroup); return STATUS_SUCCESS; } NTSTATUS DsmUnload( _In_ IN PVOID DsmContext ) /*++ Routine Description: This routine is called when the main module requires the DSM to be unloaded (ie. prior to the main module unload). Arguments: DsmContext - Context value passed to DsmInitialize() Return Value: STATUS_SUCCESS; --*/ { PVOID tempAddress = DsmContext; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DsmUnload (DsmCtxt %p): Entering function.\n", DsmContext)); DsmpFreeDSMResources((PDSM_CONTEXT) DsmContext); if (gMPIOControlObjectRefd) { ObDereferenceObject(gMPIOControlObject); gMPIOControlObjectRefd = FALSE; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DsmUnload (DsmCtxt %p): Exiting function.\n", tempAddress)); // // Stop the tracing subsystem. // WPP_CLEANUP(gDsmDriverObject); return STATUS_SUCCESS; } ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/msdsm.h ================================================ /*++ Copyright (C) 2004-2010 Microsoft Corporation Module Name: msdsm.h Abstract: Header for the Microsoft Device Specific Module (DSM). Environment: kernel mode only Notes: --*/ #ifndef _MSDSM_H_ #define _MSDSM_H_ // // Maximum number of paths per device supported by the DSM. // This is a limit currently set by MPIO itself and needs to be updated if MPIO // supports more paths-per-device in the future. // #define DSM_MAX_PATHS 32 // // MPIO control object's well known symbolic name // #define DSM_MPIO_CONTROL_OBJECT_SYMLINK L"\\DosDevices\\MPIOControl" // // Location of System class node in the registry // #define DSM_SYSTEM_CLASS_GUID_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E97D-E325-11CE-BFC1-08002BE10318}" // // Values used for matching and figuring out the DriverVersion // #define DSM_INF_PATH L"InfPath" #define DSM_MSDSM_INF_PATH L"msdsm.inf" #define DSM_DRIVER_VERSION L"DriverVersion" #define DSM_DRIVER_VERSION_FIELD_DELIMITER L'.' #define DSM_BUFFER_MAXCOUNT 64 // // MSDSM's display name. // #define DSM_FRIENDLY_NAME L"Microsoft DSM" // // Name of the value for the supported devices in the registry, found in the // DSM's Services' Parameters key // #define DSM_SUPPORTED_DEVICELIST_VALUE_NAME L"DsmSupportedDeviceList" // // Value used to determine if per-IO statistics gathering needs to be turned OFF // #define DSM_DISABLE_STATISTICS L"DsmDisableStatistics" // // Names of the values in the registry for whether to use the same path for // sequential IOs when employing Least Blocks load balance policy, as well // as its size. // #define DSM_USE_CACHE_FOR_LEAST_BLOCKS L"DsmUseCacheForLeastBlocks" #define DSM_CACHE_SIZE_FOR_LEAST_BLOCKS L"DsmCacheSizeForLeastBlocks" // // Name of the value in the registry for the maximum request retry time during ALUA // state transitions. This value is found in the DSM's Services' Parameters key, and // applies only to Persistent Reservation commands. // #define DSM_MAX_STATE_TRANSITION_TIME_VALUE_NAME L"DsmMaximumStateTransitionTime" // // Default max amount of time (in seconds) that a PR failing with retry-able UA will be retried // #define DSM_MAX_PR_UNIT_ATTENTION_RETRY_TIME 3 // // Macro to translate seconds to ticks. Each system tick is 10^(-7) seconds. // #define DSM_SECONDS_TO_TICKS(_Seconds) ((_Seconds) * 10000000) // // Size of the buffer allocated to retrieve device serial number. // This is as defined by SPC-3 spec. The identifier with the biggest size is // SCSI name type (0x8). // #define DSM_SERIAL_NUMBER_BUFFER_SIZE 255 // // Number of LB Policies that are supported by this driver. // #define DSM_NUMBER_OF_LB_POLICIES 6 // // Size of the buffer passed to read in Persistent Reserve keys. // #define DSM_READ_PERSISTENT_KEYS_BUFFER_SIZE 4096 // // The default threshold for sequential IO for the Least Blocks load balance // policy is 1MB. // #define DSM_LEAST_BLOCKS_DEFAULT_THRESHOLD 0x00100000 // // Initialization data structure that needs to be filled in for MPIO // extern DSM_INIT_DATA gDsmInitData; // // Macro used to round of a number to the nearest 8 byte aligned one. // #ifdef AlignOn8Bytes #undef AlignOn8Bytes #endif #define AlignOn8Bytes(x) (((x) + 7) & ~7) // // Macro for determining minimum of two numbers // #ifdef MIN #undef MIN #endif #define MIN(a, b) ((ULONGLONG)(a) < (ULONGLONG)(b) ? (a) : (b)) // // Macro used to convert a 4 byte array to a ULONG (where byte 0 MSB, byte 3 LSB) // #define GetUlongFrom4ByteArray(UCharArray, ULongValue) \ ((UNALIGNED UCHAR *)&(ULongValue))[3] = ((UNALIGNED UCHAR *)(UCharArray))[0]; \ ((UNALIGNED UCHAR *)&(ULongValue))[2] = ((UNALIGNED UCHAR *)(UCharArray))[1]; \ ((UNALIGNED UCHAR *)&(ULongValue))[1] = ((UNALIGNED UCHAR *)(UCharArray))[2]; \ ((UNALIGNED UCHAR *)&(ULongValue))[0] = ((UNALIGNED UCHAR *)(UCharArray))[3]; // // Macro used to convert a ULONG into a 4 byte array (as big-endian) // #define Get4ByteArrayFromUlong(ULongValue, UCharArray) \ ((UNALIGNED UCHAR *)(UCharArray))[3] = ((UNALIGNED UCHAR *)&(ULongValue))[0]; \ ((UNALIGNED UCHAR *)(UCharArray))[2] = ((UNALIGNED UCHAR *)&(ULongValue))[1]; \ ((UNALIGNED UCHAR *)(UCharArray))[1] = ((UNALIGNED UCHAR *)&(ULongValue))[2]; \ ((UNALIGNED UCHAR *)(UCharArray))[0] = ((UNALIGNED UCHAR *)&(ULongValue))[3]; // // Macro to check if passed in opcode is a read, write // #define DsmIsReadRequest(_Opcode) (_Opcode == SCSIOP_READ || _Opcode == SCSIOP_READ16) #define DsmIsWriteRequest(_Opcode) (_Opcode == SCSIOP_WRITE || _Opcode == SCSIOP_WRITE16) #define DsmIsReadWrite(_Opcode) (_Opcode == SCSIOP_READ || _Opcode == SCSIOP_READ16 || \ _Opcode == SCSIOP_WRITE || _Opcode == SCSIOP_WRITE16) #define DsmIsReadCapacity( _Opcode ) (_Opcode == SCSIOP_READ_CAPACITY || _Opcode == SCSIOP_READ_CAPACITY16) // // Macro to find the number of bytes consumed by the array // #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) // // Signature used to identify various structures. // Used solely for debugging purposes. // #define DSM_DEVICE_SIG 0xAAAAAAAA #define DSM_GROUP_SIG 0x55555555 #define DSM_FOG_SIG 0x88888888 #define DSM_TARGET_PORT_GROUP_SIG 0x33333333 #define DSM_TARGET_PORT_SIG 0xCCCCCCCC #define DSM_CONTROLLER_SIG 0xEEEEEEEE #define WNULL (L'\0') #define WNULL_SIZE (sizeof(WNULL)) #if DBG // // NT_ASSERT wrapper. // #define DSM_ASSERT(exp) if (DoAssert) { \ NT_ASSERT(exp); \ } #else // DBG #define DSM_ASSERT(exp) #endif // DBG #define DSM_PARAMETER_PATH_W L"MSDSM\\Parameters" // // Pool Tags used in memory allocation // #define DSM_TAG_GENERIC '00ZZ' #define DSM_TAG_PASS_THRU '10ZZ' #define DSM_TAG_GROUP_ENTRY '20ZZ' #define DSM_TAG_FO_GROUP '30ZZ' #define DSM_TAG_DSM_CONTEXT '40ZZ' #define DSM_TAG_DEV_INFO '50ZZ' #define DSM_TAG_SERIAL_NUM '60ZZ' #define DSM_TAG_CTRL_INFO '70ZZ' #define DSM_TAG_SUPPORTED_DEV '80ZZ' #define DSM_TAG_REG_PATH '90ZZ' #define DSM_TAG_FOG_DEV_ENTRY 'A0ZZ' #define DSM_TAG_DEV_ID 'B0ZZ' #define DSM_TAG_DEV_NAME 'C0ZZ' #define DSM_TAG_LB_POLICY 'D0ZZ' #define DSM_TAG_PR_KEYS 'E0ZZ' #define DSM_TAG_RESERVED_DEVICE 'F0ZZ' #define DSM_TAG_BIN_TO_ASCII '01ZZ' #define DSM_TAG_TARGET_PORT_LIST_ENTRY '11ZZ' #define DSM_TAG_TARGET_PORT_GROUP_ENTRY '21ZZ' #define DSM_TAG_RELATIVE_TARGET_PORT_ID '31ZZ' #define DSM_TAG_TARGET_PORT_GROUPS '41ZZ' #define DSM_TAG_CONTROLLER_LIST_ENTRY '51ZZ' #define DSM_TAG_CONTROLLER_INFO '61ZZ' #define DSM_TAG_IO_STATUS_BLOCK '71ZZ' #define DSM_TAG_DEVICE_ID_LIST '81ZZ' #define DSM_TAG_TP_DEVICE_LIST_ENTRY '91ZZ' #define DSM_TAG_RETRY_RESERVE 'A1ZZ' #define DSM_TAG_WORKITEM 'B1ZZ' #define DSM_TAG_SCSI_ADDRESS 'C1ZZ' #define DSM_TAG_FAIL_DEVINFO_LIST_ENTRY 'D1ZZ' #define DSM_TAG_TPG_COMPLETION_CONTEXT 'E1ZZ' #define DSM_TAG_SCSI_REQUEST_BLOCK 'F1ZZ' #define DSM_TAG_SCSI_SENSE_INFO '02ZZ' #define DSM_TAG_SPT_DATA_BUFFER '12ZZ' #define DSM_TAG_REG_KEY_RELATED '22ZZ' #define DSM_TAG_DEV_HARDWARE_ID '32ZZ' #define DSM_TAG_REG_VALUE_RELATED '42ZZ' #define DSM_TAG_ZOMBIEGROUP_ENTRY '52ZZ' #define DSM_TAG_PERSISTENT_RESERVATION '62ZZ' // // Parameters subkey name under HKLM\System\CCS\Services\MSDSM // #define DSM_SERVICE_PARAMETERS L"Parameters" // // Load Balance settings are persisted in the registry under this key // #define DSM_LOAD_BALANCE_SETTINGS L"DsmLoadBalanceSettings" // // Load Balance settings on a VID/PID basis are persistented in the registry // under this key // #define DSM_TARGETS_LOAD_BALANCE_SETTING L"DsmTargetsLoadBalanceSetting" // // Values persisted per device: // 1. Load Balance Policy // 2. Preferred Path // 3. Whether LB policy has been explicitly set // #define DSM_LOAD_BALANCE_POLICY L"DsmLoadBalancePolicy" #define DSM_PREFERRED_PATH L"DsmPreferredPath" #define DSM_POLICY_EXPLICITLY_SET L"DsmLoadBalancePolicyExplicitlySet" // // Prefix for subkey created for each path // #define DSM_PATH L"DSMPath" // // Values persisted per path: // 1. Whether primary // 2. Whether optimized // 3. Path weight. // // Primary Optimized State //==================================== // True True Active-Optimized // True False Active-Unoptimized // False True StandBy // False False Unavailable // #define DSM_PRIMARY_PATH L"DsmPrimaryPath" #define DSM_OPTIMIZED_PATH L"DsmOptimizedPath" #define DSM_PATH_WEIGHT L"DsmPathWeight" // // Indicates that device doesn't support ALUA. // #define DSM_DEVINFO_ALUA_NOT_SUPPORTED 0 // // Implies that device supports implicit ALUA transistions. // #define DSM_DEVINFO_ALUA_IMPLICIT 1 // // Implies that device supports explicit ALUA state transitions. // #define DSM_DEVINFO_ALUA_EXPLICIT 2 // // Type of device identifier (VPD 0x83) // typedef enum _DSM_DEVID_TYPE { DSM_DEVID_SERIAL_NUMBER = 1, DSM_DEVID_RELATIVE_TARGET_PORT, DSM_DEVID_TARGET_PORT_GROUP } DSM_DEVID_TYPE, *PDSM_DEVID_TYPE; #define _DSM_TERNARY_BOOLEAN UCHAR typedef _DSM_TERNARY_BOOLEAN DSM_TERNARY_BOOLEAN, *PDSM_TERNARY_BOOLEAN; #define DSM_TERNARY_UNKNOWN 0 #define DSM_TERNARY_TRUE 1 #define DSM_TERNARY_FALSE 2 // // Macro to determine if _Id2 is more preferred than _Id1 to build a device's // serial number. // #define DsmpIsPreferredDeviceId(_Id1, _Id2) (((_Id2) == StorageIdTypeScsiNameString) || \ ((_Id2) == StorageIdTypeFCPHName && (_Id1) != StorageIdTypeScsiNameString) || \ ((_Id2) == StorageIdTypeEUI64 && (_Id1) != StorageIdTypeScsiNameString && (_Id1) != StorageIdTypeFCPHName) || \ ((_Id2) == StorageIdTypeVendorId && (_Id1) != StorageIdTypeScsiNameString && (_Id1) != StorageIdTypeFCPHName && (_Id1) != StorageIdTypeEUI64) || \ ((_Id2) == StorageIdTypeVendorSpecific && (_Id1) != StorageIdTypeScsiNameString && (_Id1) != StorageIdTypeFCPHName && (_Id1) != StorageIdTypeEUI64 && (_Id1) != StorageIdTypeVendorId)) // // Device State // typedef enum _DSM_DEVICE_STATE { // // If ALUA is not supported, this state indicates that the device is active // and a request can be sent to the device. // If ALUA is supported, then this state indicates optimizied device-path // pair for the device. // DSM_DEV_ACTIVE_OPTIMIZED = 0, // // If ALUA is not supported, this state is not used. // If ALUA is supported, then this state indicates active but unoptimized // device-path pairing for the device. Can be used in in case no // active/optimized path is available to service the IO. // DSM_DEV_ACTIVE_UNOPTIMIZED, // // If ALUA is not supported, this state indicates that the device is in // standby state. A request can be sent to the device in this state. // If ALUA is supported, then this state indicates standby device-path // pairing and only certain requests can be handled in this state. // DSM_DEV_STANDBY, // // If ALUA is not supported, this state is not used. // If ALUA is supported, then this state indicates that the device-path pairing // is not active and incapable of handling any requests. // DSM_DEV_UNAVAILABLE, // // If ALUA is not supported, this state is not used. // If ALUA is supported, then this state indicates that the device-path pairing // (actually its TPG) is in a transitioning state. // DSM_DEV_TRANSITIONING = 15, // // Initial state when devInfo is created. // DSM_DEV_NOT_USED_STATE = 16, // // Indicates that the state was undetermined (this is applicable only for // a deviceInfo's DesiredState or if the device instance's path was not // determined). // DSM_DEV_UNDETERMINED, // // Indicates that a request sent down previously failed with a fatal error // DSM_DEV_FAILED, // // Indicates that InvalidatePath has been called // DSM_DEV_INVALIDATED, // // This indicates the device is about to be removed. No new request // should be sent to the device. // DSM_DEV_REMOVE_PENDING, // // This indicates the device has been removed. // DSM_DEV_REMOVED } DSM_DEVICE_STATE, *PDSM_DEVICE_STATE; // // Device states supported // #define DSM_STATE_ACTIVE_OPTIMIZED_SUPPORTED 0 #define DSM_STATE_STANDBY_SUPPORTED 1 #define DSM_STATE_ACTIVE_UNOPTIMIZED_SUPPORTED 2 #define DSM_STATE_UNAVAILABLE_SUPPORTED 4 // // Macro to determine if devInfo is in a failure state. // #define DsmpIsDeviceFailedState(_State) ((_State) > DSM_DEV_NOT_USED_STATE) // // Macro to determine if devInfo was initialized. // #define DsmpIsDeviceInitialized(_DeviceInfo) ((_DeviceInfo)->Initialized) // // Macro to determine if device is "usable" (ie. IsPathActive was successfully called). // #define DsmpIsDeviceUsable(_DeviceInfo) ((_DeviceInfo)->Usable) // // Macro to determine if devInfo was used to send down registration. // It the devInfo's group is not reserved, then the devInfo doesn't need to have // had a register go down it. // It the group is reserved, then the devInfo MUST have had a register go down it // for it to be used. // #define DsmpIsDeviceUsablePR(_DeviceInfo) (!(_DeviceInfo)->Group->PRKeyValid || (_DeviceInfo)->PRKeyRegistered) // // Macro to determine if _State2 is a more preferred state than _State1. // #define DsmpIsBetterDeviceState(_State1, _State2) (((_State1) == DSM_DEV_STANDBY && (_State2) == DSM_DEV_ACTIVE_UNOPTIMIZED) || \ ((_State1) == DSM_DEV_UNAVAILABLE && \ ((_State2) == DSM_DEV_ACTIVE_UNOPTIMIZED || (_State2) == DSM_DEV_STANDBY)) || \ ((_State1) == DSM_DEV_TRANSITIONING && \ ((_State2) == DSM_DEV_ACTIVE_UNOPTIMIZED || (_State2) == DSM_DEV_STANDBY) || (_State2) == DSM_DEV_UNAVAILABLE)) // // Macro to determine if passed in _State is active. // #define DsmpIsDeviceStateActive(_State) ((_State) == DSM_DEV_ACTIVE_OPTIMIZED || (_State) == DSM_DEV_ACTIVE_UNOPTIMIZED) // // Macro to determine if symmetric access to the storage // #define DsmpIsSymmetricAccess(_DeviceInfo) ((_DeviceInfo)->ALUASupport == DSM_DEVINFO_ALUA_NOT_SUPPORTED || \ ((_DeviceInfo)->ALUASupport == DSM_DEVINFO_ALUA_IMPLICIT && \ (_DeviceInfo)->Group->Symmetric)) // // Multi-path Group State // typedef enum _DSM_GROUP_STATE { // // This indicates that the device is in working state. // DSM_GP_NORMAL = 1, // // This indicates that there is a pending reservation failover // DSM_GP_PENDING, // // This indicates that the device has lost all its paths // DSM_GP_FAILED } DSM_GROUP_STATE, *PDSM_GROUP_STATE; // // Fail-Over Group State // typedef enum _DSM_FAILOVER_GROUP_STATE { // // This indicates that the path is in working state. // DSM_FG_NORMAL = 1, // // This indicates the path which had failed earlier // is back to working state now. // DSM_FG_FAILBACK, // // This indicates the path is about to be removed // DSM_FG_PENDING_REMOVE, // // This indicates the path has failed. // DSM_FG_FAILED } DSM_FAILOVER_GROUP_STATE, *PDSM_FAILOVER_GROUP_STATE; #define DsmpIsPathFailedState(_State) ((_State) >= DSM_FG_PENDING_REMOVE) // // DSM Context is the global driver context that gets passed to each of the DSM // entry points. // // The DSM Context will maintain a list of all DeviceInfos (device-path pairing). // It will maintain a list of Group entries. Each entry in the Group list will // represent a LUN's different instances down different paths (i.e. DeviceInfos). // Each entry in the Group will maintain a list of target port groups. // Each entry in the target port group list will maintain a list of target // ports that make up the target port group. Every deviceInfo that isn't // in a failure state will be in the same state as the Asymmetric Access // State of the target port group. // There will be a list of Fail Over Group entries, where each entry represents // the list of devices that fail over as a group (i.e. devices on the same path). // There will also be a list of controller entries, representing the controllers // on all storages connected to the system. // typedef struct _DSM_CONTEXT { // // Used to synchronize access to the SupportedDevices list. // KSPIN_LOCK SupportedDevicesListLock; // // List of supported devices - added into the INF. // UNICODE_STRING SupportedDevices; // // Used to synchronize access to the elements in this structure. // EX_SPIN_LOCK DsmContextLock; // // Flag cached that indicates if statistics don't need to be gathered // BOOLEAN DisableStatsGathering; UCHAR Reserved[3]; // // Number of devices currently found. // ULONG NumberDevices; // // List of devices. // LIST_ENTRY DeviceList; // // Number of multi-path groups. // ULONG NumberGroups; // // List of multi-path groups. // LIST_ENTRY GroupList; // // Number of fail-over groups. // ULONG NumberFOGroups; // // List of fail-over groups. // LIST_ENTRY FailGroupList; // // Number of controllers. // ULONG NumberControllers; // // List of controllers // LIST_ENTRY ControllerList; // // Number of stale fail-over groups // ULONG NumberStaleFOGroups; // // List of stale fail-over groups maintained for paths for which all devices // have gotten removed but for which there is still outstanding IO-statistics // LIST_ENTRY StaleFailGroupList; // // Context value passed to the DSM from MPIO. // PVOID MPIOContext; // // Look-aside list of completion routine context structures. // NPAGED_LOOKASIDE_LIST CompletionContextList; } DSM_CONTEXT, *PDSM_CONTEXT; // // Statistics structure. Used by the device and path routines. // typedef struct _DSM_STATS { ULONG NumberReads; ULONG NumberWrites; ULONGLONG BytesRead; ULONGLONG BytesWritten; } DSM_STATS, *PDSM_STATS; // // Information about each device that is supported by the DSM. // typedef struct _DSM_DEVICE_INFO { // // To link to the next device info structure in the list // LIST_ENTRY ListEntry; // // The device SIG. Used for debug. // ULONG DeviceSig; // // Back-pointer to the DSM_CONTEXT. // PVOID DsmContext; // // The underlying port driver PDO. // PDEVICE_OBJECT PortPdo; // // The port FDO to which PortPdo is attached. // PDEVICE_OBJECT PortFdo; // // The DeviceObject to which I/Os generated by the DSM should // be sent. This is given to us by MPIO. // PDEVICE_OBJECT TargetObject; // // The multi-path group to which this device belongs. // struct _DSM_GROUP_ENTRY *Group; // // The fail-over group to which this device belongs. // struct _DSM_FAILOVER_GROUP *FailGroup; // // The controller through which this device showed up. // struct _DSM_CONTROLLER_LIST_ENTRY *Controller; // // The Target Port Group that this device belongs to. // struct _DSM_TARGET_PORT_GROUP_ENTRY *TargetPortGroup; // // The Target Port that this device was exposed via. // struct _DSM_TARGET_PORT_LIST_ENTRY *TargetPort; // // The current state of this device: ACTIVE_O, ACTIVE_U, STANDBY, UNAVAILABLE, etc. // DSM_DEVICE_STATE State; // // Previous state of this device. Updated whenever this deviceInfo makes a // state transition. // DSM_DEVICE_STATE PreviousState; // // The desired state of this device: based on PrimaryPath and OptimizedPath // specified in the registry. // DSM_DEVICE_STATE DesiredState; // // The ALUA state of the TPG immediately after a ReportTPG is issued. // DSM_DEVICE_STATE ALUAState; // // Holds state information temporarily while applying LB policy. Used in case // changes need to be reverted in case of failure to apply the policy. // DSM_DEVICE_STATE TempPreviousStateForLB; // // This is to save off the last known non-failed state. // In case of an error down this deviceInfo, it is marked to be in Failed state. // However, if no remove comes down for this device and a PathVerify down this // deviceInfo succeeds, we need to put the deviceInfo back into a usable state. // DSM_DEVICE_STATE LastKnownGoodState; // // This counter indicates that this deviceInfo is being used and a remove // must thus wait until the counter falls to 0. // LONG BlockRemove; // // This indicates whether this device has handled a register/register_ignore_existing request, // irrespective of the actual status of the operation. // BOOLEAN RegisterServiced; // // This flag is set when a register/register_ignore_existing succeeds down this device-path pair. // BOOLEAN PRKeyRegistered; // // Indicates whether the serial number was embedded in the device // descriptor, or it was allocated. // BOOLEAN SerialNumberAllocated; // // Flag to indicate that SetDeviceInfo has been called (and succeeded) on this device // BOOLEAN Initialized; // // Flag to indicate that IsPathActive has been called (and succeeded) on this device. // BOOLEAN Usable; // // Flag to indicate if IALUAE was disabled (via mode select) // BOOLEAN ImplicitDisabled; // // Flag to indicate that RTPG has already been sent down in Inquire, so // PathVerify can ignore sending down one more if it is called during // device initialization. // BOOLEAN IgnorePathVerify; // // Bit map indicating whether (and what kind) of ALUA support. // UCHAR ALUASupport; // // Weight assigned to this path by management application. This is used // when doing Load Balancing based on weighted paths. // ULONG PathWeight; // // Number of requests outstanding on this device. // LONG NumberOfRequestsInProgress; // // I/O, Fail-Over statistics. // DSM_STATS DeviceStats; // // The device's serial number. // PSTR SerialNumber; // // The scsi address of the port pdo. // PSCSI_ADDRESS ScsiAddress; // // Kernel structure that describes this device. Passed in to Inquire. // // NOTE: Descriptor should be the LAST field in this structure // STORAGE_DEVICE_DESCRIPTOR Descriptor; } DSM_DEVICE_INFO, *PDSM_DEVICE_INFO; typedef enum _DSM_DEFAULT_LB_POLICY_TYPE { DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY = 0, // DSM assigned based on LUN access capability DSM_DEFAULT_LB_POLICY_DSM_WIDE, // Admin has set a DSM-wide default policy DSM_DEFAULT_LB_POLICY_VID_PID, // Admin has set a default policy for LUN's VID/PID DSM_DEFAULT_LB_POLICY_LUN_EXPLICIT // Admin has explicitly set the policy on the LUN } DSM_DEFAULT_LB_POLICY_TYPE, *PDSM_DEFAULT_LB_POLICY_TYPE; typedef ULONG DSM_LOAD_BALANCE_TYPE, *PDSM_LOAD_BALANCE_TYPE; // // Information about multi-path groups: The same device found via multiple paths // are put under one group. Each group will have it's own Load Balance policy // settings. In other words, Load Balance policy settings are on per-device basis. // typedef struct _DSM_GROUP_ENTRY { // // To link to the next entry in the multi-path group. // LIST_ENTRY ListEntry; // // Group signature. Used for debug. // ULONG GroupSig; // // Ordinal of creation. Never decremented. // ULONG GroupNumber; // // State of the group. // DSM_GROUP_STATE State; // // Number of devices in the multi-path group. // ULONG NumberDevices; // // Array of devices belonging to this group. // PDSM_DEVICE_INFO DeviceList[DSM_MAX_PATHS]; // // Max time to retry failed PR requests // ULONG MaxPRRetryTimeDuringStateTransition; // // Number of target port groups that this device is accessible via. // ULONG NumberTargetPortGroups; // // Array of the target port groups that this LUN belongs in. // struct _DSM_TARGET_PORT_GROUP_ENTRY *TargetPortGroupList[DSM_MAX_PATHS]; // // Key used in Persistent Reserve\Release. This key is provided to the DSM // by Cluster service. If cluster service has provided the key PRKeyValid // is set to TRUE. PRKeyValid is set to FALSE otherwise. // PRServiceAction, PRType and PRScope are the service action, type and // scope associated with the PR registration. // UCHAR PersistentReservationRegisteredKey[8]; UCHAR PRServiceAction; UCHAR PRType; UCHAR PRScope; UCHAR PRKeyValid; // // Flag used to denote that LU access is symmetric down all paths // BOOLEAN Symmetric; // // Flag to indicate whether or not to use same path for sequential IO // when employing Least Blocks load balance policy. // BOOLEAN UseCacheForLeastBlocks; // // Flag used to indicate if a throttle request succeeded. // ULONG Throttled; // // Counter to track the number of RTPG in flight. // ULONG InFlightRTPG; // // A bitmask of which devices are currently reserved. // ULONG ReservationList; // // Which type of Load Balancing is being performed. // DSM_LOAD_BALANCE_TYPE LoadBalanceType; // // Indicates how the Load Balancing policy was selected. // DSM_DEFAULT_LB_POLICY_TYPE LBPolicySelection; // // The path to use when possible - if in F.O. Only, if failover had taken // place and this path comes back online, failback to this path will take // place. // ULONGLONG PreferredPath; // // The path to choose when Round Robin Load Balance policy is in use // PVOID PathToBeUsed; // // Size of cache set by Admin. Used in case of handling sequential // IO in Least Blocks policy. // ULONGLONG CacheSizeForLeastBlocks; // // The HardwareId (VID/PID) of the LUN // PWSTR HardwareId; // // The registry key under which Load Balance Policy settings // are stored in the registry for this Device Group. // PWSTR RegistryKeyName; // // Number of failing deviceInfos // ULONG NumberFailingDevInfos; // // To link the list of failed A/O devInfos and the corresponding non-A/O // devInfos that are temporarily being used to service IO until STPG can // properly update the device states. This is applicable only for ALUA // devices. // LIST_ENTRY FailingDevInfoList; // // General Purpose Event. // KEVENT Event; } DSM_GROUP_ENTRY, *PDSM_GROUP_ENTRY; // // The collection of devices on one path. These fail-over as a unit. // A path is considered an I_T nexus, i.e. Initiator port to Target (controller) port. // typedef struct _DSM_FAILOVER_GROUP { // // To link to the next entry in the failover group // LIST_ENTRY ListEntry; // // Signature. Used for debug. // ULONG FailOverSig; // // State of the Path. // DSM_FAILOVER_GROUP_STATE State; // // The pathId corresponding to this FOG. It may or may not be // the same as what MPIO gave us as the default value. // PVOID PathId; // // The default pathId (port FDO). // PDEVICE_OBJECT MPIOPath; // // Last LBA // ULONGLONG LastLba; // // Cumulative outstanding IO (in terms of size) // ULONGLONG OutstandingBytesOfIO; // // Count of inflight IOs. This will be used in LQD load balance policy. // volatile LONG NumberOfRequestsInFlight; // // Number of devices in this FOG. // ULONG Count; // // List of devices that will over together. // LIST_ENTRY FOG_DeviceList; // // List of zombie groups (in case a device is removed before the failover // processing begins). // LIST_ENTRY ZombieGroupList; } DSM_FAILOVER_GROUP, *PDSM_FAILOVER_GROUP; // // Information about a target port group entry for a given LUN. // Note: This is not a global list of all TPGs that are built. It is local to a Group entry. // typedef struct _DSM_TARGET_PORT_GROUP_ENTRY { // // Signature. Used for debug. // ULONG TargetPortGroupSig; // // The asymmetric access state for this target port group: // ACTIVE_O, ACTIVE_U, STANDBY or UNAVAILABLE // DSM_DEVICE_STATE AsymmetricAccessState; // // Flag to indicate if this is the preferred target port group. // BOOLEAN Preferred; // // Supported access states // BOOLEAN ActiveOptimizedSupported; BOOLEAN ActiveUnoptimizedSupported; BOOLEAN StandBySupported; BOOLEAN UnavailableSupported; // // Indicates if the device reports asymmetric state as being under transition. // BOOLEAN TransitioningSupported; // // Flag to indicate if this has been returned in any subsequent RTPG after // it is initially built. (If this flag is not set after parsing the RTPG // information, it indicates that this TPG entry is stale and should be // deleted). // BOOLEAN Traversed; UCHAR Reserved; // // The target group identifier // USHORT Identifier; // // Status code // UCHAR StatusCode; // // Vendor unique // UCHAR VendorUnique; // // Backpointer to owning group // PDSM_GROUP_ENTRY Group; // // Number of target ports that make up this group // ULONG NumberTargetPorts; // // Linked list of target ports that make up this target port group. // LIST_ENTRY TargetPortList; } DSM_TARGET_PORT_GROUP_ENTRY, *PDSM_TARGET_PORT_GROUP_ENTRY; // // Information about each target port list entry for a given target port group. // Note: this is not a global list of all TPs. It is local to a given TPG entry. // typedef struct _DSM_TARGET_PORT_LIST_ENTRY { // // Link // LIST_ENTRY ListEntry; // // Signature. Used for debug. // ULONG TargetPortSig; // // Relative target port identifier // ULONG Identifier; // // Backpointer to owning target port group // PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup; // // Number of device instances exposed via this target port // ULONG Count; // // List of device instances exposed via this target port // LIST_ENTRY TP_DeviceList; } DSM_TARGET_PORT_LIST_ENTRY, *PDSM_TARGET_PORT_LIST_ENTRY; // // Information about each controller entry // typedef struct _DSM_CONTROLLER_LIST_ENTRY { // // To link to the next contoller entry. // LIST_ENTRY ListEntry; // // It's signature. Used for debug. // ULONG ControllerSig; // // Device object (this controller's PDO). // PDEVICE_OBJECT DeviceObject; // // Port FDO through which this controller object was exposed. // PDEVICE_OBJECT PortObject; // // Identifier. // _Field_size_(IdLength) PUCHAR Identifier; // // Identifier length. // ULONG IdLength; // // Identifier code set. // STORAGE_IDENTIFIER_CODE_SET IdCodeSet; // // Controller's SCSI address. // PSCSI_ADDRESS ScsiAddress; // // Number of references to this entry. // UCHAR RefCount; // // Flag to indicate whether this is a fake entry built for storage that do // NOT have controllers // BOOLEAN IsFakeController; UCHAR Reserved[2]; } DSM_CONTROLLER_LIST_ENTRY, *PDSM_CONTROLLER_LIST_ENTRY; // // Generic linked list of devices // typedef struct _DSM_DEVICELIST_ENTRY { // // To link to the next device info structure in the list // LIST_ENTRY ListEntry; // // Representation of device-path pair // PDSM_DEVICE_INFO DeviceInfo; } DSM_DEVICELIST_ENTRY, *PDSM_DEVICELIST_ENTRY; // // Zombie Group List Entry // typedef struct _DSM_ZOMBIEGROUP_ENTRY { // // To link to the next zombie group structure in the list // LIST_ENTRY ListEntry; // // Pointer to actual group entry // PDSM_GROUP_ENTRY Group; // // Flag to indicate that the failover thread has processed this entry. // BOOLEAN Processed; } DSM_ZOMBIEGROUP_ENTRY, *PDSM_ZOMBIEGROUP_ENTRY; // // Linked list of devices that will failover as a group // typedef DSM_DEVICELIST_ENTRY DSM_FOG_DEVICELIST_ENTRY, *PDSM_FOG_DEVICELIST_ENTRY; // // Linked list of the same device being exposed off of a particular target port // (possibly because the controller is connected to multiple HBAs). // typedef DSM_DEVICELIST_ENTRY DSM_TARGET_PORT_DEVICELIST_ENTRY, *PDSM_TARGET_PORT_DEVICELIST_ENTRY; // // Information about each failing devInfo and its corresponding devInfo // being used temporarily to service requests until STPG can update new // device states. // typedef struct _DSM_FAIL_PATH_PROCESSING_LIST_ENTRY { // // To link to the next device info structure in the list // LIST_ENTRY ListEntry; // // Representation of the failing device-path pair // PDSM_DEVICE_INFO FailingDeviceInfo; // // Representation of the new candidate device-path pair that will take over // processing of requests // PDSM_DEVICE_INFO TempDeviceInfo; } DSM_FAIL_PATH_PROCESSING_LIST_ENTRY, *PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY; // // Completion context structure. // typedef struct _DSM_COMPLETION_CONTEXT { // // The device that handled the request. // PDSM_DEVICE_INFO DeviceInfo; // // The global context. // PDSM_CONTEXT DsmContext; // // These are used to store control code, pointer to KEVENT, etc. // PVOID RequestUnique1; ULONG_PTR RequestUnique2; #if DBG // // Request time-stamp. // LARGE_INTEGER TickCount; #endif } DSM_COMPLETION_CONTEXT, *PDSM_COMPLETION_CONTEXT; // // Completion context structure for report/set target port groups. // typedef struct _DSM_TPG_COMPLETION_CONTEXT { PDSM_COMPLETION_CONTEXT CompletionContext; PSCSI_REQUEST_BLOCK Srb; PVOID SenseInfoBuffer; ULONG NumberRetries; UCHAR SenseInfoBufferLength; } DSM_TPG_COMPLETION_CONTEXT, *PDSM_TPG_COMPLETION_CONTEXT; // // Version number used to determine whice version of MPIO_DSM_Path to use. // #define DSM_WMI_VERSION_1 1 #define DSM_WMI_VERSION_2 2 // // Version of MPIO_DSM_Path that is currently supported by this DSM. // #define DSM_WMI_VERSION DSM_WMI_VERSION_2 // // This struct is used to save Load Balance Policy Settings in the registry // typedef struct _DSM_LOAD_BALANCE_POLICY_SETTINGS { WCHAR RegistryKeyName[256]; ULONG LoadBalancePolicy; ULONG PathCount; MPIO_DSM_Path_V2 DsmPath[1]; } DSM_LOAD_BALANCE_POLICY_SETTINGS, *PDSM_LOAD_BALANCE_POLICY_SETTINGS; // // This structure is used to pass in information used by the workitem // to failover reservations down another path. // typedef struct _DSM_RETRY_RESERVE { PDSM_COMPLETION_CONTEXT CompletionContext; PIRP Irp; PKEVENT Event; } DSM_RETRY_RESERVE, *PDSM_RETRY_RESERVE; // // This structure defines the workitem that will be used to handle reservation // failover. // typedef struct _DSM_WORKITEM { // // Work item that should be freed by the worker routine // PIO_WORKITEM WorkItem; // // Context to be passed to worker routine // PVOID Context; } DSM_WORKITEM, *PDSM_WORKITEM; #endif // _MSDSM_H ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/msdsm.mof ================================================ // // Copyright (C) 2004 Microsoft Corporation // // // Microsoft DSM's internal classes // // // Perf class. // [WMI, guid("{a34d03ec-6b0b-46a1-9178-82525f41133f}")] class MSDSM_DEVICEPATH_PERF { [WmiDataId(1), Description("Path Identifier.") : amended ] uint64 PathId; [WmiDataId(2), Description("Number of Read Requests.") : amended ] uint32 NumberReads; [WmiDataId(3), Description("Number of Write Requests.") : amended ] uint32 NumberWrites; [WmiDataId(4), Description("Total Bytes Read.") : amended ] uint64 BytesRead; [WmiDataId(5), Description("Total Bytes Written.") : amended ] uint64 BytesWritten; }; [WMI, Dynamic, Provider("WmiProv"), Description("Retrieve MSDSM Performance Information.") : amended, Locale("MS\\0x409"), guid("{875b8871-4889-4114-93f6-cd064c001cea}")] class MSDSM_DEVICE_PERF { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, Description("Number of paths.") : amended ] uint32 NumberPaths; [WmiDataId(2), read, Description("Array of Performance Information per path for the device.") : amended, WmiSizeIs("NumberPaths") ] MSDSM_DEVICEPATH_PERF PerfInfo[]; }; // // Methods // Clear perf counters. // [Dynamic, Provider("WMIProv"), WMI, Description("MSDSM WMI Methods") : amended, guid("{04517f7e-92bb-4ebe-aed0-54339fa5f544}"), locale("MS\\0x409") ] class MSDSM_WMI_METHODS { [key, read] string InstanceName; [read] boolean Active; [WmiMethodId(1), Implemented, Description("Clear path performance counters for the device.") : amended ] void MSDsmClearCounters(); }; ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/msdsm.rc ================================================ //+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 2004 // // File: msdsm.rc // //-------------------------------------------------------------------------- #include #include #define VER_FILETYPE VFT_DRV #define VER_FILESUBTYPE VFT2_DRV_SYSTEM #define VER_FILEDESCRIPTION_STR "Microsoft Device Specific Module" #define VER_INTERNALNAME_STR "msdsm.sys" #define VER_ORIGINALFILENAME_STR "msdsm.sys" #include "common.ver" MofResourceName MOFDATA msdsm.bmf DsmMofResourceName MOFDATA msdsmdsm.bmf ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/msdsmdsm.mof ================================================ // // Copyright (C) 2004 Microsoft Corporation // // Microsoft DSM's DSM-specific classes // // // Class used for retrieving and setting MSDSM-wide default load balance policy. // [WMI, Dynamic, Provider("WmiProv"), Description("MSDSM-wide default load balance policies.") : amended, Locale("MS\\0x409"), guid("{c81b5681-f3ca-4c98-9325-707d0d62ffc4}")] class MSDSM_DEFAULT_LOAD_BALANCE_POLICY { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("Load Balance Policy to be applied to devices controlled by MSDSM.") : amended ] uint32 LoadBalancePolicy; [WmiDataId(2), read, Description("Reserved.") : amended ] uint32 Reserved; // // Preferred path. // [WmiDataId(3), read, write, Description("Preferred Path.") : amended ] uint64 PreferredPath; }; // // Embedded class that describes a target and the default load balance policy // of its LUNs. // [WMI, guid("{ddb00a72-0fab-418b-a89e-97370ae293a4}")] class MSDSM_TARGET_DEFAULT_POLICY_INFO { // // VID-PID string as an 8 + 16 character concatenated string. // Spaces should be used to make the VID 8 chars and the PID 16 chars. // [WmiDataId(1), MaxLen(31), Description("Concatenated VendorID (8 characters) and ProductID (16 characters).") : amended ] string HardwareId; // // The default load balance policy to be applied to LUNs from the target // whose hardware id matches the VID/PID above. // NOTE: Setting this to 0 will act as removal of default setting for this // target. // [WmiDataId(2)] uint32 LoadBalancePolicy; // // Used for alignment reasons. // [WmiDataId(3)] uint32 Reserved; // // Preferred path. // [WmiDataId(4)] uint64 PreferredPath; }; // // Class used for retrieving and setting target-level default load balance policy. // [WMI, Dynamic, Provider("WmiProv"), Description("Target-level default load balance policies.") : amended, Locale("MS\\0x409"), guid("{5ccbcd91-1b56-4327-a2f3-0960335f8846}")] class MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("Number of targets specified.") : amended ] uint32 NumberDevices; [WmiDataId(2), read, Description("Reserved.") : amended ] uint32 Reserved; [WmiDataId(3), read, write, MaxLen(31), Description("Array of target hardware identifiers with policy and preferred path information.") : amended, WmiSizeIs("NumberDevices") ] MSDSM_TARGET_DEFAULT_POLICY_INFO TargetDefaultPolicyInfo[]; }; // // Supported devices list class. // [WMI, Dynamic, Provider("WmiProv"), Description("Retrieve MSDSM's supported devices list.") : amended, Locale("MS\\0x409"), guid("{c362d67c-371e-44d8-8bba-044619e4f245}")] class MSDSM_SUPPORTED_DEVICES_LIST { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, Description("Number of supported devices.") : amended ] uint32 NumberDevices; [WmiDataId(2), read, Description("Reserved.") : amended ] uint32 Reserved; [WmiDataId(3), read, MaxLen(31), Description("Array of device hardware identifiers.") : amended, WmiSizeIs("NumberDevices") ] string DeviceId[]; }; ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/precomp.h ================================================ /*++ Copyright (c) 2004 Microsoft Corporation Module Name: precomp.h Abstract: Precompiled header file for Microsoft Device Specific Module (DSM). Revision History: --*/ #pragma once #define DEBUG_MAIN_SOURCE 1 #include #include #include "dsm.h" #include "mpiodisk.h" #include "msdsm.h" #include "prototypes.h" #include "trace.h" #include "srbhelper.h" #include #include ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/precompsrc.c ================================================ #include "precomp.h" ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/prototypes.h ================================================ /*++ Copyright (C) 2004 Microsoft Corporation Module Name: prototypes.h Abstract: Contains function prototypes for all the functions defined by Microsoft Device Specific Module (DSM). Environment: kernel mode only Notes: --*/ #pragma warning (disable:4214) // bit field usage #pragma warning (disable:4200) // zero-sized array #ifndef _PROTOTYPES_H_ #define _PROTOTYPES_H_ #define DSM_VENDOR_ID_LEN 8 #define DSM_PRODUCT_ID_LEN 16 #define DSM_VENDPROD_ID_LEN 24 // // In accordance with SPC-3 specs // #define SPC3_TARGET_PORT_GROUPS_HEADER_SIZE 4 typedef struct _SPC3_CDB_REPORT_TARGET_PORT_GROUPS { UCHAR OperationCode; UCHAR ServiceAction : 5; UCHAR Reserved1 : 3; UCHAR Reserved2[4]; UCHAR AllocationLength[4]; UCHAR Reserved3; UCHAR Control; } SPC3_CDB_REPORT_TARGET_PORT_GROUPS, *PSPC3_CDB_REPORT_TARGET_PORT_GROUPS; typedef struct _SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR { UCHAR AsymmetricAccessState : 4; UCHAR Reserved : 3; UCHAR Preferred : 1; UCHAR ActiveOptimizedSupported : 1; UCHAR ActiveUnoptimizedSupported : 1; UCHAR StandbySupported : 1; UCHAR UnavailableSupported : 1; UCHAR Reserved2 : 3; UCHAR TransitioningSupported : 1; USHORT TPG_Identifier; UCHAR Reserved3; UCHAR StatusCode; UCHAR VendorUnique; UCHAR NumberTargetPorts; ULONG TargetPortIds[0]; } SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR, *PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR; typedef struct _SPC3_CDB_SET_TARGET_PORT_GROUPS { UCHAR OperationCode; UCHAR ServiceAction : 5; UCHAR Reserved1 : 3; UCHAR Reserved2[4]; UCHAR ParameterListLength[4]; UCHAR Reserved3; UCHAR Control; } SPC3_CDB_SET_TARGET_PORT_GROUPS, *PSPC3_CDB_SET_TARGET_PORT_GROUPS; typedef struct _SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR { UCHAR AsymmetricAccessState : 4; UCHAR Reserved1 : 4; UCHAR Reserved2; USHORT TPG_Identifier; } SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR, *PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR; typedef struct _SPC3_CONTROL_EXTENSION_MODE_PAGE { UCHAR PageCode : 6; UCHAR SubpageFormat : 1; UCHAR ParametersSavable : 1; UCHAR SubpageCode; UCHAR PageLength[2]; UCHAR ImplicitALUAEnable : 1; UCHAR ScsiPrecendence : 1; UCHAR TimestampChangeable : 1; UCHAR Reserved1 : 5; UCHAR InitialPriority : 4; UCHAR Reserved2 : 4; UCHAR Reserved3[26]; } SPC3_CONTROL_EXTENSION_MODE_PAGE, *PSPC3_CONTROL_EXTENSION_MODE_PAGE; #define SPC3_SCSIOP_REPORT_TARGET_PORT_GROUPS 0xA3 #define SPC3_SCSIOP_SET_TARGET_PORT_GROUPS 0xA4 #define SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS 0xA #define SPC3_RESERVATION_ACTION_REPORT_CAPABILITIES 0x2 #define SPC3_SCSI_ADSENSE_COMMANDS_CLEARED_BY_ANOTHER_INITIATOR 0x2F #define SPC3_SCSI_ADSENSE_LOGICAL_UNIT_COMMAND_FAILED 0x67 #define SPC3_SCSI_SENSEQ_MODE_PARAMETERS_CHANGED 0x1 #define SPC3_SCSI_SENSEQ_RESERVATIONS_PREEMPTED 0x3 #define SPC3_SCSI_SENSEQ_RESERVATIONS_RELEASED 0x4 #define SPC3_SCSI_SENSEQ_REGISTRATIONS_PREEMPTED 0x5 #define SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_CHANGED 0x6 #define SPC3_SCSI_SENSEQ_IMPLICIT_ASYMMETRIC_ACCESS_STATE_TRANSITION_FAILED 0x7 #define SPC3_SCSI_SENSEQ_CAPACITY_DATA_HAS_CHANGED 0x9 #define SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION 0xA #define SPC3_SCSI_SENSEQ_TARGET_PORT_IN_STANDBY_STATE 0xB #define SPC3_SCSI_SENSEQ_TARGET_PORT_IN_UNAVAILABLE_STATE 0xC #define SPC3_SCSI_SENSEQ_SET_TARGET_PORT_GROUPS_FAILED 0xA #define SPC3_SET_TARGET_PORT_GROUPS_TIMEOUT 10 #define SPC3_REPORT_TARGET_PORT_GROUPS_TIMEOUT 10 // // Function prototypes for functions intrface.c // DRIVER_INITIALIZE DriverEntry; DRIVER_UNLOAD DsmDriverUnload; NTSTATUS DsmInquire ( _In_ IN PVOID DsmContext, _In_ IN PDEVICE_OBJECT TargetDevice, _In_ IN PDEVICE_OBJECT PortObject, _In_ IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor, _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceIdList, _Out_ OUT PVOID *DsmIdentifier ); BOOLEAN DsmCompareDevices( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId1, _In_ IN PVOID DsmId2 ); NTSTATUS DsmGetControllerInfo( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN ULONG Flags, _Inout_ IN OUT PCONTROLLER_INFO *ControllerInfo ); NTSTATUS DsmSetDeviceInfo( _In_ IN PVOID DsmContext, _In_ IN PDEVICE_OBJECT TargetObject, _In_ IN PVOID DsmId, _Inout_ IN OUT PVOID *PathId ); BOOLEAN DsmIsPathActive( _In_ IN PVOID DsmContext, _In_ IN PVOID PathId, _In_ IN PVOID DsmId ); NTSTATUS DsmPathVerify( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN PVOID PathId ); NTSTATUS DsmInvalidatePath( _In_ IN PVOID DsmContext, _In_ IN ULONG ErrorMask, _In_ IN PVOID PathId, _Inout_ IN OUT PVOID *NewPathId ); NTSTATUS DsmMoveDevice( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PVOID MPIOPath, _In_ IN PVOID SuggestedPath, _In_ IN ULONG Flags ); NTSTATUS DsmRemovePending( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId ); NTSTATUS DsmRemoveDevice( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN PVOID PathId ); NTSTATUS DsmRemovePath( _In_ IN PVOID DsmContext, _In_ IN PVOID PathId ); NTSTATUS DsmSrbDeviceControl( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PKEVENT Event ); PVOID DsmLBGetPath( _In_ IN PVOID DsmContext, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PDSM_IDS DsmList, _In_ IN PVOID CurrentPath, _Out_ OUT NTSTATUS *Status ); ULONG DsmInterpretError( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN PSCSI_REQUEST_BLOCK Srb, _Inout_ IN OUT NTSTATUS *Status, _Out_ OUT PBOOLEAN Retry, _Out_ OUT PLONG RetryInterval, ... ); NTSTATUS DsmUnload( _In_ IN PVOID DsmContext ); VOID DsmSetCompletion( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _Inout_ IN OUT PDSM_COMPLETION_INFO DsmCompletion ); _Success_(return == DSM_PATH_SET) ULONG DsmCategorizeRequest( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PVOID CurrentPath, _Outptr_result_maybenull_ OUT PVOID *PathId, _Out_ OUT NTSTATUS *Status ); NTSTATUS DsmBroadcastRequest( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PKEVENT Event ); BOOLEAN DsmIsAddressTypeSupported( _In_ IN PVOID DsmContext, _In_ IN ULONG AddressType ); NTSTATUS DsmDeviceNotUsed( _In_ IN PVOID DsmContext, _In_ IN PVOID DsmId ); // // Function prototypes for functions in dsmmain.c // VOID DsmpFreeDSMResources( _In_ IN PDSM_CONTEXT DsmContext ); PDSM_GROUP_ENTRY DsmpFindDevice( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN BOOLEAN AcquireDSMLockExclusive ); PDSM_GROUP_ENTRY DsmpBuildGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo ); NTSTATUS DsmpParseTargetPortGroupsInformation( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_reads_bytes_(TargetPortGroupsInfoLength) IN PUCHAR TargetPortGroupsInfo, _In_ IN ULONG TargetPortGroupsInfoLength ); PDSM_TARGET_PORT_GROUP_ENTRY DsmpFindTargetPortGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor, _In_ IN ULONG TPGs_BufferLength ); _Success_(return!=0) PDSM_TARGET_PORT_GROUP_ENTRY DsmpUpdateTargetPortGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor, _In_ IN ULONG TPGs_BufferLength, _Out_ OUT PULONG DescriptorSize ); PDSM_TARGET_PORT_GROUP_ENTRY DsmpBuildTargetPortGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor, _In_ IN ULONG TPGs_BufferLength, _Out_ OUT PULONG DescriptorSize ); PDSM_TARGET_PORT_LIST_ENTRY DsmpFindTargetPortListEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_ IN ULONG RelativeTargetPortId ); PDSM_TARGET_PORT_LIST_ENTRY DsmpBuildTargetPortListEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_ IN ULONG RelativeTargetPortId ); PDSM_TARGET_PORT_GROUP_ENTRY DsmpFindTargetPortGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PUSHORT TargetPortGroupId ); PDSM_TARGET_PORT_LIST_ENTRY DsmpFindTargetPort( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_ IN PULONG TargetPortGroupId ); NTSTATUS DsmpAddDeviceEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO DeviceInfo ); PDSM_CONTROLLER_LIST_ENTRY DsmpFindControllerEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDEVICE_OBJECT PortObject, _In_ IN PSCSI_ADDRESS ScsiAddress, _In_reads_(ControllerSerialNumberLength) IN PSTR ControllerSerialNumber, _In_ IN SIZE_T ControllerSerialNumberLength, _In_ IN STORAGE_IDENTIFIER_CODE_SET CodeSet, _In_ IN BOOLEAN AcquireLock ); _Ret_maybenull_ _Must_inspect_result_ _When_(return != NULL, __drv_allocatesMem(Mem)) PDSM_CONTROLLER_LIST_ENTRY DsmpBuildControllerEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_opt_ IN PDEVICE_OBJECT DeviceObject, _In_ IN PDEVICE_OBJECT PortObject, _In_ IN PSCSI_ADDRESS ScsiAddress, _In_ IN PSTR ControllerSerialNumber, _In_ IN STORAGE_IDENTIFIER_CODE_SET CodeSet, _In_ IN BOOLEAN AcquireLock ); VOID DsmpFreeControllerEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ __drv_freesMem(Mem) IN PDSM_CONTROLLER_LIST_ENTRY ControllerEntry ); BOOLEAN DsmpIsDeviceBelongsToController( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN PDSM_CONTROLLER_LIST_ENTRY ControllerEntry ); PDSM_DEVICE_INFO DsmpFindDevInfoFromGroupAndFOGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_FAILOVER_GROUP FOGroup ); PDSM_FAILOVER_GROUP DsmpFindFOGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PVOID PathId ); PDSM_FAILOVER_GROUP DsmpBuildFOGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN PVOID *PathId ); NTSTATUS DsmpUpdateFOGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_FAILOVER_GROUP FailGroup, _In_ IN PDSM_DEVICE_INFO DeviceInfo ); VOID DsmpRemoveDeviceFailGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_FAILOVER_GROUP FailGroup, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN BOOLEAN AcquireDSMLockExclusive ); ULONG DsmpRemoveDeviceEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO DeviceInfo ); VOID DsmpRemoveDeviceFromTargetPortList( _In_ IN PDSM_DEVICE_INFO DeviceInfo ); PDSM_FAILOVER_GROUP DsmpSetNewPath( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO FailingDevice ); PDSM_FAILOVER_GROUP DsmpSetNewPathUsingGroup( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY Group ); VOID DsmpRemoveZombieGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY ZombieGroup ); NTSTATUS DsmpUpdateTargetPortGroupDevicesStates( _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup, _In_ IN DSM_DEVICE_STATE NewState ); VOID DsmpIncrementCounters( _In_ PDSM_FAILOVER_GROUP FailGroup, _In_ PSCSI_REQUEST_BLOCK Srb ); BOOLEAN DsmpDecrementCounters( _In_ PDSM_FAILOVER_GROUP FailGroup, _In_ PSCSI_REQUEST_BLOCK Srb ); PDSM_FAILOVER_GROUP DsmpGetPath( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmList, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN ULONG SpecialHandlingFlag ); PVOID DsmpGetPathIdFromPassThroughPath( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmList, _In_ IN PIRP Irp, _Inout_ IN OUT NTSTATUS *Status ); VOID DsmpRemoveGroupEntry( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_GROUP_ENTRY GroupEntry, _In_ IN BOOLEAN AcquireDSMLockExclusive ); BOOLEAN DsmpMpioPassThroughPathCommand( _In_ IN PIRP Irp ); BOOLEAN DsmpReservationCommand( _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb ); VOID DsmpRequestComplete( _In_ IN PVOID DsmId, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PVOID DsmContext ); NTSTATUS DsmpRegisterPersistentReservationKeys( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN BOOLEAN Register ); BOOLEAN DsmpShouldRetryPassThroughRequest( _In_ IN PVOID SenseData, _In_ IN UCHAR SenseDataSize ); BOOLEAN DsmpShouldRetryPersistentReserveCommand( _In_ IN PVOID SenseData, _In_ IN UCHAR SenseDataSize ); BOOLEAN DsmpShouldRetryTPGRequest( _In_ IN PVOID SenseData, _In_ IN UCHAR SenseDataSize ); BOOLEAN DsmpIsDeviceRemoved( _In_ IN PVOID SenseData, _In_ IN UCHAR SenseDataSize ); PDSM_DEVICE_INFO DsmpGetActivePathToBeUsed( _In_ PDSM_GROUP_ENTRY Group, _In_ BOOLEAN Symmetric, _In_ IN ULONG SpecialHandlingFlag ); PDSM_DEVICE_INFO DsmpGetAnyActivePath( _In_ PDSM_GROUP_ENTRY Group, _In_ BOOLEAN Exception, _In_opt_ PDSM_DEVICE_INFO DeviceInfo, _In_ IN ULONG SpecialHandlingFlag ); PDSM_DEVICE_INFO DsmpFindStandbyPathToActivate( _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN ULONG SpecialHandlingFlag ); PDSM_DEVICE_INFO DsmpFindStandbyPathToActivateALUA( _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PBOOLEAN SendTPG, _In_ IN ULONG SpecialHandlingFlag ); PDSM_DEVICE_INFO DsmpFindStandbyPathInAlternateTpgALUA( _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN ULONG SpecialHandlingFlag ); NTSTATUS DsmpSetLBForDsmPolicyAdjustment( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONGLONG PreferredPath ); NTSTATUS DsmpSetLBForVidPidPolicyAdjustment( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PWSTR TargetHardwareId, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONGLONG PreferredPath ); NTSTATUS DsmpSetNewDefaultLBPolicy( _In_ IN PDSM_CONTEXT DsmContext, _In_opt_ IN PDSM_DEVICE_INFO NewDeviceInfo, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONG SpecialHandlingFlag ); NTSTATUS DsmpSetLBForPathArrival( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO NewDeviceInfo, _In_ IN ULONG SpecialHandlingFlag ); NTSTATUS DsmpSetLBForPathArrivalALUA( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO NewDeviceInfo, _In_ IN ULONG SpecialHandlingFlag ); NTSTATUS DsmpSetLBForPathRemoval( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO RemovedDeviceInfo, _In_opt_ IN OPTIONAL PDSM_GROUP_ENTRY Group, _In_ IN ULONG SpecialHandlingFlag ); NTSTATUS DsmpSetLBForPathRemovalALUA( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO RemovedDeviceInfo, _In_opt_ IN OPTIONAL PDSM_GROUP_ENTRY Group, _In_ IN ULONG SpecialHandlingFlag ); NTSTATUS DsmpSetLBForPathFailing( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo, _In_ IN BOOLEAN MarkDevInfoFailed, _In_ IN ULONG SpecialHandlingFlag ); NTSTATUS DsmpSetLBForPathFailingALUA( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo, _In_ IN BOOLEAN MarkDevInfoFailed, _In_ IN ULONG SpecialHandlingFlag ); NTSTATUS DsmpSetPathForIoRetryALUA( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo, _In_ IN BOOLEAN TPGException, _In_ IN BOOLEAN DeviceInfoException ); PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY DsmpFindFailPathDevInfoEntry( _In_ IN PDSM_CONTEXT Context, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO FailingDevInfo ); PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY DsmpBuildFailPathDevInfoEntry( _In_ IN PDSM_CONTEXT Context, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_DEVICE_INFO FailingDevInfo, _In_ IN PDSM_DEVICE_INFO AlternateDevInfo ); IO_COMPLETION_ROUTINE DsmpPhase1ProcessPathFailingALUA; NTSTATUS DsmpRemoveFailPathDevInfoEntry( _In_ IN PDSM_CONTEXT Context, _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY FailPathDevInfoEntry ); IO_COMPLETION_ROUTINE DsmpPhase2ProcessPathFailingALUA; NTSTATUS DsmpPersistentReserveOut( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PKEVENT Event ); __inline BOOLEAN DsmpIsPersistentReservationKeyZeroKey( _In_ ULONG KeyLength, _In_reads_bytes_(KeyLength) PUCHAR Key ) { BOOLEAN zeroKey = FALSE; NT_ASSERT(KeyLength == 8); if ((KeyLength) == 8 && (Key[0] == 0 && Key[1] == 0 && Key[2] == 0 && Key[3] == 0 && Key[4] == 0 && Key[5] == 0 && Key[6] == 0 && Key[7] == 0)) { zeroKey = TRUE; } return zeroKey; } NTSTATUS DsmpPersistentReserveIn( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN PSCSI_REQUEST_BLOCK Srb, _In_ IN PKEVENT Event ); IO_COMPLETION_ROUTINE DsmpPersistentReserveCompletion; // // Function prototypes for functions in utils.c // _Success_(return != NULL) __drv_allocatesMem(Mem) _When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL)) _When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL)) _When_(((PoolType&0x2))!=0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) _When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))==0, _Post_maybenull_ _Must_inspect_result_) _When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))!=0, _Post_notnull_) _When_((PoolType&NonPagedPoolMustSucceed)!=0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) _Post_writable_byte_size_(NumberOfBytes) PVOID DsmpAllocatePool( _In_ _Strict_type_match_ IN POOL_TYPE PoolType, _In_ IN SIZE_T NumberOfBytes, _In_ IN ULONG Tag ); _Success_(return != NULL) _Post_maybenull_ _Must_inspect_result_ __drv_allocatesMem(Mem) _Post_writable_byte_size_(*BytesAllocated) _When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL)) _When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL)) _When_((PoolType&NonPagedPoolMustSucceed)!=0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) PVOID DsmpAllocateAlignedPool( _In_ IN POOL_TYPE PoolType, _In_ IN SIZE_T NumberOfBytes, _In_ IN ULONG AlignmentMask, _In_ IN ULONG Tag, _Out_ OUT SIZE_T *BytesAllocated ); _IRQL_requires_max_(DISPATCH_LEVEL) VOID DsmpFreePool( _In_opt_ __drv_freesMem(Mem) IN PVOID Block ); NTSTATUS DsmpGetStatsGatheringChoice( _In_ IN PDSM_CONTEXT Context, _Out_ OUT PULONG StatsGatherChoice ); NTSTATUS DsmpSetStatsGatheringChoice( _In_ IN PDSM_CONTEXT Context, _In_ IN ULONG StatsGatherChoice ); NTSTATUS DsmpGetDeviceList( _In_ IN PDSM_CONTEXT Context ); _Success_(return==0) NTSTATUS DsmpGetStandardInquiryData( _In_ IN PDEVICE_OBJECT DeviceObject, _Out_ OUT PINQUIRYDATA InquiryData ); BOOLEAN DsmpCheckScsiCompliance( _In_ IN PDEVICE_OBJECT DeviceObject, _In_ IN PINQUIRYDATA InquiryData, _In_ IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor, _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceIdList ); BOOLEAN DsmpDeviceSupported( _In_ IN PDSM_CONTEXT Context, _In_ IN PCSTR VendorId, _In_ IN PCSTR ProductId ); BOOLEAN DsmpFindSupportedDevice( _In_ IN PUNICODE_STRING DeviceName, _In_ IN PUNICODE_STRING SupportedDevices ); _Success_(return!=0) PVOID DsmpParseDeviceID ( _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceID, _In_ IN DSM_DEVID_TYPE DeviceIdType, _In_opt_ IN PULONG IdNumber, _Out_opt_ PSTORAGE_IDENTIFIER_CODE_SET CodeSet, _In_ IN BOOLEAN Legacy ); PUCHAR DsmpBinaryToAscii( _In_reads_(Length) IN PUCHAR HexBuffer, _In_ IN ULONG Length, _Inout_ IN OUT PULONG UpdateLength, _In_ IN BOOLEAN Legacy ); PSTR DsmpGetSerialNumber( _In_ IN PDEVICE_OBJECT DeviceObject ); NTSTATUS DsmpDisableImplicitStateTransition( _In_ IN PDEVICE_OBJECT DeviceObject, _Out_ OUT PBOOLEAN DisableImplicit ); PWSTR DsmpBuildHardwareId( _In_ IN PDSM_DEVICE_INFO DeviceInfo ); PWSTR DsmpBuildDeviceNameLegacyPage0x80( _In_ IN PDSM_DEVICE_INFO DeviceInfo ); PWSTR DsmpBuildDeviceName( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_reads_(SerialNumberLength) IN PSTR SerialNumber, _In_ IN SIZE_T SerialNumberLength ); NTSTATUS DsmpApplyDeviceNameCorrection( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_reads_(DeviceNameLegacyLen) PWSTR DeviceNameLegacy, _In_ IN SIZE_T DeviceNameLegacyLen, _In_reads_(DeviceNameLen) PWSTR DeviceName, _In_ IN SIZE_T DeviceNameLen ); NTSTATUS DsmpQueryDeviceLBPolicyFromRegistry( _In_ PDSM_DEVICE_INFO DeviceInfo, _In_ PWSTR RegistryKeyName, _Inout_ PDSM_LOAD_BALANCE_TYPE LoadBalanceType, _Inout_ PULONGLONG PreferredPath, _Inout_ PUCHAR ExplicitlySet ); NTSTATUS DsmpQueryTargetLBPolicyFromRegistry( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _Out_ OUT PDSM_LOAD_BALANCE_TYPE LoadBalanceType, _Out_ OUT PULONGLONG PreferredPath ); NTSTATUS DsmpQueryDsmLBPolicyFromRegistry( _Out_ OUT PDSM_LOAD_BALANCE_TYPE LoadBalanceType, _Out_ OUT PULONGLONG PreferredPath ); NTSTATUS DsmpSetDsmLBPolicyInRegistry( _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONGLONG PreferredPath ); NTSTATUS DsmpSetVidPidLBPolicyInRegistry( _In_ IN PWSTR TargetHardwareId, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONGLONG PreferredPath ); NTSTATUS DsmpOpenLoadBalanceSettingsKey( _In_ IN ACCESS_MASK AccessMask, _Out_ OUT PHANDLE LoadBalanceSettingsKey ); NTSTATUS DsmpOpenTargetsLoadBalanceSettingKey( _In_ IN ACCESS_MASK AccessMask, _Out_ OUT PHANDLE TargetsLoadBalanceSettingKey ); NTSTATUS DsmpOpenDsmServicesParametersKey( _In_ IN ACCESS_MASK AccessMask, _Out_ OUT PHANDLE ParametersSettingsKey ); IO_COMPLETION_ROUTINE DsmpReportTargetPortGroupsSyncCompletion; _Success_(return==0) NTSTATUS DsmpReportTargetPortGroups( _In_ PDEVICE_OBJECT DeviceObject, _Outptr_result_buffer_maybenull_(*TargetPortGroupsInfoLength) PUCHAR *TargetPortGroupsInfo, _Out_ PULONG TargetPortGroupsInfoLength ); NTSTATUS DsmpReportTargetPortGroupsAsync( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN PIO_COMPLETION_ROUTINE CompletionRoutine, _Inout_ __drv_aliasesMem IN PDSM_TPG_COMPLETION_CONTEXT CompletionContext, _In_ IN ULONG TargetPortGroupsInfoLength, _Inout_ __drv_aliasesMem IN OUT PUCHAR TargetPortGroupsInfo ); NTSTATUS DsmpQueryLBPolicyForDevice( _In_ IN PWSTR RegistryKeyName, _In_ IN ULONGLONG PathId, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _Out_ OUT PULONG PrimaryPath, _Out_ OUT PULONG OptimizedPath, _Out_ OUT PULONG PathWeight ); VOID DsmpGetDSMPathKeyName( _In_ ULONGLONG DSMPathId, _Out_writes_(DsmPathKeyNameSize) PWCHAR DsmPathKeyName, _In_ ULONG DsmPathKeyNameSize ); UCHAR DsmpGetAsciiForBinary( _In_ UCHAR BinaryChar ); NTSTATUS DsmpGetDeviceIdList ( _In_ IN PDEVICE_OBJECT DeviceObject, _Out_ OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor ); NTSTATUS DsmpSetTargetPortGroups( _In_ IN PDEVICE_OBJECT DeviceObject, _In_reads_bytes_(TargetPortGroupsInfoLength) IN PUCHAR TargetPortGroupsInfo, _In_ IN ULONG TargetPortGroupsInfoLength ); NTSTATUS DsmpSetTargetPortGroupsAsync( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN PIO_COMPLETION_ROUTINE CompletionRoutine, _In_ __drv_aliasesMem IN PDSM_TPG_COMPLETION_CONTEXT CompletionContext, _In_ IN ULONG TargetPortGroupsInfoLength, _In_ __drv_aliasesMem IN PUCHAR TargetPortGroupsInfo ); PDSM_LOAD_BALANCE_POLICY_SETTINGS DsmpCopyLoadBalancePolicies( _In_ IN PDSM_GROUP_ENTRY GroupEntry, _In_ IN ULONG DsmWmiVersion, _In_ IN PVOID SupportedLBPolicies ); NTSTATUS DsmpPersistLBSettings( _In_ IN PDSM_LOAD_BALANCE_POLICY_SETTINGS LoadBalanceSettings ); NTSTATUS DsmpSetDeviceALUAState( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN DSM_DEVICE_STATE DevState ); NTSTATUS DsmpGetDeviceALUAState( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_opt_ IN PDSM_DEVICE_STATE DevState ); NTSTATUS DsmpAdjustDeviceStatesALUA( _In_ IN PDSM_GROUP_ENTRY Group, _In_opt_ IN PDSM_DEVICE_INFO PreferredActiveDeviceInfo, _In_ IN ULONG SpecialHandlingFlag ); PDSM_WORKITEM DsmpAllocateWorkItem( _In_ IN PDEVICE_OBJECT DeviceObject, _In_ IN PVOID Context ); VOID DsmpFreeWorkItem( _In_ IN PDSM_WORKITEM DsmWorkItem ); VOID DsmpFreeZombieGroupList( _In_ IN PDSM_FAILOVER_GROUP FailGroup ); NTSTATUS DsmpRegCopyTree( _In_ IN HANDLE SourceKey, _In_ IN HANDLE DestKey ); NTSTATUS DsmpRegDeleteTree( _In_ IN HANDLE KeyRoot ); #if defined (_WIN64) VOID DsmpPassThroughPathTranslate32To64( _In_ IN PMPIO_PASS_THROUGH_PATH32 MpioPassThroughPath32, _Inout_ IN OUT PMPIO_PASS_THROUGH_PATH MpioPassThroughPath64 ); VOID DsmpPassThroughPathTranslate64To32( _In_ IN PMPIO_PASS_THROUGH_PATH MpioPassThroughPath64, _Inout_ IN OUT PMPIO_PASS_THROUGH_PATH32 MpioPassThroughPath32 ); #endif NTSTATUS DsmpGetMaxPRRetryTime( _In_ IN PDSM_CONTEXT Context, _Out_ OUT PULONG RetryTime ); NTSTATUS DsmpQueryCacheInformationFromRegistry( _In_ IN PDSM_CONTEXT DsmContext, _Out_ OUT PBOOLEAN UseCacheForLeastBlocks, _Out_ OUT PULONGLONG CacheSizeForLeastBlocks ); BOOLEAN DsmpConvertSharedSpinLockToExclusive( _Inout_ _Requires_lock_held_(*_Curr_) PEX_SPIN_LOCK SpinLock ); // // Function prototypes for functions in wmi.c // VOID DsmpDsmWmiInitialize( _In_ IN PDSM_WMILIB_CONTEXT WmiGlobalInfo, _In_ IN PUNICODE_STRING RegistryPath ); NTSTATUS DsmGlobalQueryData( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN ULONG GuidIndex, _In_ IN ULONG InstanceIndex, _In_ IN ULONG InstanceCount, _Inout_ IN OUT PULONG InstanceLengthArray, _In_ IN ULONG BufferAvail, _Out_writes_to_(BufferAvail, *DataLength) OUT PUCHAR Buffer, _Out_ OUT PULONG DataLength, ... ); NTSTATUS DsmGlobalSetData( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN ULONG GuidIndex, _In_ IN ULONG InstanceIndex, _In_ IN ULONG BufferAvail, _In_reads_bytes_(BufferAvail) IN PUCHAR Buffer, ... ); VOID DsmpWmiInitialize( _In_ IN PDSM_WMILIB_CONTEXT WmiInfo, _In_ IN PUNICODE_STRING RegistryPath ); NTSTATUS DsmQueryData( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN ULONG GuidIndex, _In_ IN ULONG InstanceIndex, _In_ IN ULONG InstanceCount, _Inout_ IN OUT PULONG InstanceLengthArray, _In_ IN ULONG BufferAvail, _When_(GuidIndex == 0 || GuidIndex == 7, _Pre_notnull_ _Const_) _When_(!(GuidIndex == 0 || GuidIndex == 7), _Out_writes_to_(BufferAvail, *DataLength)) OUT PUCHAR Buffer, _Out_ OUT PULONG DataLength, ... ); NTSTATUS DsmpQueryLoadBalancePolicy( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN ULONG DsmWmiVersion, _In_ IN ULONG InBufferSize, _In_ IN PULONG OutBufferSize, _Out_writes_bytes_(*OutBufferSize) OUT PVOID Buffer ); NTSTATUS DsmpQuerySupportedLBPolicies( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN ULONG BufferAvail, _In_ IN ULONG DsmWmiVersion, _Out_ OUT PULONG OutBufferSize, _Out_writes_to_(BufferAvail, *OutBufferSize) OUT PUCHAR Buffer ); NTSTATUS DsmExecuteMethod( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN ULONG GuidIndex, _In_ IN ULONG InstanceIndex, _In_ IN ULONG MethodId, _In_ IN ULONG InBufferSize, _In_ IN PULONG OutBufferSize, _Inout_ IN OUT PUCHAR Buffer, ... ); NTSTATUS DsmpClearLoadBalancePolicy( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds ); NTSTATUS DsmpSetLoadBalancePolicy( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN ULONG DsmWmiVersion, _In_ IN ULONG InBufferSize, _In_ IN PULONG OutBufferSize, _In_ IN PVOID Buffer ); NTSTATUS DsmpValidateSetLBPolicyInput( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN ULONG DsmWmiVersion, _In_ IN PVOID SetLoadBalancePolicyIN, _In_ IN ULONG InBufferSize ); VOID DsmpSaveDeviceState( _In_ IN PVOID SupportedLBPolicies, _In_ IN ULONG DsmWmiVersion ); VOID DsmpRestorePreviousDeviceState( _In_ IN PVOID SupportedLBPolicies, _In_ IN ULONG DsmWmiVersion ); VOID DsmpUpdateDesiredStateAndWeight( _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN ULONG DsmWmiVersion, _In_ IN PVOID SupportedLBPolicies ); NTSTATUS DsmpQueryDevicePerf( _In_ PDSM_CONTEXT DsmContext, _In_ PDSM_IDS DsmIds, _In_ ULONG InBufferSize, _Inout_ PULONG OutBufferSize, _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer ); NTSTATUS DsmpClearPerfCounters( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds ); NTSTATUS DsmpQuerySupportedDevicesList( _In_ PDSM_CONTEXT DsmContext, _In_ ULONG InBufferSize, _Inout_ PULONG OutBufferSize, _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer ); NTSTATUS DsmpQueryTargetsDefaultPolicy( _In_ PDSM_CONTEXT DsmContext, _In_ ULONG InBufferSize, _Inout_ PULONG OutBufferSize, _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer ); NTSTATUS DsmpQueryDsmDefaultPolicy( _In_ PDSM_CONTEXT DsmContext, _In_ ULONG InBufferSize, _Inout_ PULONG OutBufferSize, _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer ); // // Function prototypes for functions in debug.c // VOID DsmpDebugPrint( _In_ ULONG DebugPrintLevel, _In_ PCCHAR DebugMessage, ... ); // // SRB Helpers not found in srbhelper.h // _Success_(return != 0) __drv_allocatesMem(mem) _When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL)) _When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL)) _When_(((PoolType&0x2))!=0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) _When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))==0, _Post_maybenull_ _Must_inspect_result_) _When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))!=0, _Post_notnull_ ) __inline PSTORAGE_REQUEST_BLOCK_HEADER SrbAllocateCopy( _Inout_ PVOID Srb, _In_ _Strict_type_match_ POOL_TYPE PoolType, _In_ ULONG Tag ) /* Description: This function returns an allocated copy of the given SRB. The memory is allocated using DsmpAllocatePool(). ***It is up to the caller to free the memory returned by this function.*** Arguments: Srb - A pointer to either a STORAGE_REQUEST_BLOCK or a SCSI_REQUEST_BLOCK. PoolType - The pool type to use. See documentation for ExAllocatePoolWithTag(). Tag - The allocation tag to use. See documentation for ExAllocatePoolWithTag(). Returns: NULL, if the copy could not be allocated; or A pointer to either a STORAGE_REQUEST_BLOCK or a SCSI_REQUEST_BLOCK that is direct copy of the given SRB. */ { PSTORAGE_REQUEST_BLOCK srb = (PSTORAGE_REQUEST_BLOCK)Srb; PSTORAGE_REQUEST_BLOCK_HEADER srbCopy = NULL; ULONG allocationSize = 0; if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { allocationSize = srb->SrbLength; NT_ASSERT(allocationSize >= (sizeof(STORAGE_REQUEST_BLOCK) + sizeof(STOR_ADDR_BTL8))); } else { allocationSize = SCSI_REQUEST_BLOCK_SIZE; NT_ASSERT(allocationSize >= sizeof(SCSI_REQUEST_BLOCK)); } #pragma warning(suppress: 28160 28118) // False-positive; PoolType is simply passed through srbCopy = (PSTORAGE_REQUEST_BLOCK_HEADER)DsmpAllocatePool(PoolType, allocationSize, Tag); if (srbCopy != NULL) { RtlCopyMemory(srbCopy, Srb, allocationSize); } return srbCopy; } __inline BOOLEAN DsmpIsMPIOPassThroughEx( ULONG ControlCode ) // // Returns TRUE if the given passthrough IOCTL's control code indicates it is // an "extended" passthrough. Returns FALSE otherwise. // { if (ControlCode == IOCTL_MPIO_PASS_THROUGH_PATH_EX || ControlCode == IOCTL_MPIO_PASS_THROUGH_PATH_DIRECT_EX) { return TRUE; } else { return FALSE; } } __inline UCHAR DsmpNtStatusToSrbStatus( _In_ NTSTATUS Status ) /*++ Routine Description: Translate an NT status value into a SCSI Srb status code. Arguments: Status - Supplies the NT status code to translate. Return Value: SRB status code. --*/ { switch (Status) { case STATUS_DEVICE_BUSY: return SRB_STATUS_BUSY; case STATUS_INVALID_DEVICE_REQUEST: return SRB_STATUS_BAD_FUNCTION; case STATUS_INSUFFICIENT_RESOURCES: return SRB_STATUS_INTERNAL_ERROR; case STATUS_INVALID_PARAMETER: return SRB_STATUS_INVALID_REQUEST; default: if (NT_SUCCESS (Status)) { return SRB_STATUS_SUCCESS; } else { return SRB_STATUS_ERROR; } } } #endif // _PROTOTYPES_H_ ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/trace.h ================================================ /*++ Copyright (C) 2004 Microsoft Corporation Module Name: trace.h Abstract: Header file included by the Microsoft Device Specific Module (DSM). This file contains Windows tracing related defines. Environment: kernel mode only Notes: --*/ // // Set component ID for DbgPrintEx calls // #define DEBUG_COMP_ID DPFLTR_MSDSM_ID // // Include header file and setup GUID for tracing // #include #define WPP_GUID_MSDSM (DEDADFF5, F99F, 4600, B8C9, 2D4D9B806B5B) #define WPP_CONTROL_GUIDS WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_MSDSM) ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/utils.c ================================================ /*++ Copyright (C) 2004-2010 Microsoft Corporation Module Name: utils.c Abstract: This driver is the Microsoft Device Specific Module (DSM). It exports behaviours that mpio.sys will use to determine how to multipath SPC-3 compliant devices. This file contains utility routines. Environment: kernel mode only Notes: --*/ #include "precomp.h" #ifdef DEBUG_USE_WPP #include "utils.tmh" #endif #pragma warning (disable:4305) extern BOOLEAN DoAssert; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, DsmpBuildDeviceNameLegacyPage0x80) #pragma alloc_text(PAGE, DsmpBuildDeviceName) #pragma alloc_text(PAGE, DsmpApplyDeviceNameCorrection) #pragma alloc_text(PAGE, DsmpOpenLoadBalanceSettingsKey) #pragma alloc_text(PAGE, DsmpQueryLBPolicyForDevice) #pragma alloc_text(PAGE, DsmpOpenTargetsLoadBalanceSettingKey) #pragma alloc_text(PAGE, DsmpOpenDsmServicesParametersKey) #endif _Success_(return != NULL) __drv_allocatesMem(Mem) _When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL)) _When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL)) _When_(((PoolType&0x2))!=0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) _When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))==0, _Post_maybenull_ _Must_inspect_result_) _When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))!=0, _Post_notnull_ ) _When_((PoolType&NonPagedPoolMustSucceed)!=0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) _Post_writable_byte_size_(NumberOfBytes) PVOID DsmpAllocatePool( _In_ _Strict_type_match_ IN POOL_TYPE PoolType, _In_ IN SIZE_T NumberOfBytes, _In_ IN ULONG Tag ) /*+++ Routine Description : Allocates memory from the specified pool using the given tag. If the allocation is successful, the entire buffer will be zeroed. Arguements: PoolType - Pool to allocate from (NonPaged, Paged, etc) NumberOfBytes - Size of the buffer to allocate Tag - Tag (DSM_TAG_XXX) to be used for this allocation. These tags are defined in msdsm.h Return Value: Pointer to the buffer if allocation is successful NULL otherwise --*/ { PVOID Block = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpAllocatePool (Tag %u): Entering function.\n", Tag)); #pragma warning(suppress: 28118) // False-positive; PoolType is simply passed through Block = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag); if (Block) { RtlZeroMemory(Block, NumberOfBytes); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpAllocatePool (Tag %u): Exiting function with allocated block %p.\n", Tag, Block)); return Block; } _Success_(return != NULL) _Post_maybenull_ _Must_inspect_result_ __drv_allocatesMem(Mem) _Post_writable_byte_size_(*BytesAllocated) _When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL)) _When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL)) _When_((PoolType&NonPagedPoolMustSucceed)!=0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) PVOID #pragma warning(suppress:28195) // Allocation is not guaranteed, caller needs to check return value DsmpAllocateAlignedPool( _In_ IN POOL_TYPE PoolType, _In_ IN SIZE_T NumberOfBytes, _In_ IN ULONG AlignmentMask, _In_ IN ULONG Tag, _Out_ OUT SIZE_T *BytesAllocated ) /*+++ Routine Description : Allocates memory from the specified pool using the given tag and alignment requirement. If the allocation is successful, the entire buffer will be zeroed. Arguements: PoolType - Pool to allocate from (NonPaged, Paged, etc) NumberOfBytes - Size of the buffer to allocate AlignmentMask - Alignment requirement specified by the device Tag - Tag (DSM_TAG_XXX) to be used for this allocation. These tags are defined in msdsm.h BytesAllocated - Returns the number of bytes allocated, if the routine was successful Return Value: Pointer to the buffer if allocation is successful NULL otherwise --*/ { PVOID Block = NULL; UINT_PTR align64 = (UINT_PTR)AlignmentMask; ULONG totalSize = (ULONG)NumberOfBytes; NTSTATUS status = STATUS_SUCCESS; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpAllocateAlignedPool (Tag %u): Entering function.\n", Tag)); if (BytesAllocated == NULL) { status = STATUS_INVALID_PARAMETER; goto __Exit; } *BytesAllocated = 0; if (AlignmentMask) { status = RtlULongAdd((ULONG)NumberOfBytes, AlignmentMask, &totalSize); } if (NT_SUCCESS(status)) { #pragma warning(suppress: 6014 28118) // Block isn't leaked, this function is marked as an allocator; PoolType is simply passed through Block = ExAllocatePoolWithTag(PoolType, totalSize, Tag); if (Block != NULL) { if (AlignmentMask) { Block = (PVOID)(((UINT_PTR)Block + align64) & ~align64); } } else { status = STATUS_INSUFFICIENT_RESOURCES; } } __Exit: if (NT_SUCCESS(status)) { RtlZeroMemory(Block, totalSize); *BytesAllocated = totalSize; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpAllocateAlignedPool (Tag %u): Exiting function with allocated block %p.\n", Tag, Block)); return Block; } _IRQL_requires_max_(DISPATCH_LEVEL) VOID DsmpFreePool( _In_opt_ __drv_freesMem(Mem) IN PVOID Block ) /*+++ Routine Description : Frees the block passed in. Arguements: Block - pointer to the memory to free. Return Value: Nothing --*/ { PVOID tempAddress = Block; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFreePool (Block %p): Entering function.\n", Block)); if (Block) { ExFreePool(Block); Block = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFreePool (Block %p): Exiting function.\n", tempAddress)); return; } NTSTATUS DsmpGetStatsGatheringChoice( _In_ IN PDSM_CONTEXT Context, _Out_ OUT PULONG StatsGatherChoice ) /*++ Routine Description: This routine is used to determine if the Admin wants statitics to be collected on every IO. It queries the the services key for the value under "msdsm\Parameters\DsmDisableStatistics" Arguments: Context - The DSM Context value. StatsGatherChoice - Returns the choice of whether or not to gather statistics Return Value: Status of the RtlQueryRegistryValues call. --*/ { RTL_QUERY_REGISTRY_TABLE queryTable[2]; WCHAR registryKeyName[56] = {0}; NTSTATUS status = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetStatsGatherChoice (DsmCtxt %p): Entering function.\n", Context)); if (!StatsGatherChoice) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DsmpGetStatsGatherChoice (DsmCtxt %p): Invalid parameter - StatsGatherChoice is NULL.\n", Context)); goto __Exit_DsmpGetStatsGatherChoice; } RtlZeroMemory(queryTable, sizeof(queryTable)); // // Build the key value name that we want as the base of the query. // RtlStringCbPrintfW(registryKeyName, sizeof(registryKeyName), DSM_PARAMETER_PATH_W); // // The query table has two entries. One for the supporteddeviceList and // the second which is the 'NULL' terminator. // queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_DISABLE_STATISTICS; queryTable[0].EntryContext = StatsGatherChoice; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, registryKeyName, queryTable, registryKeyName, NULL); __Exit_DsmpGetStatsGatherChoice: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetStatsGatherChoice (DsmCtxt %p): Exiting function with status %x.\n", Context, status)); return status; } NTSTATUS DsmpSetStatsGatheringChoice( _In_ IN PDSM_CONTEXT Context, _In_ IN ULONG StatsGatherChoice ) /*++ Routine Description: This routine is used to set the value that indicates whether statistics will be gathered on every IO. It updates the services key for the value under "msdsm\Parameters\DsmDisableStatistics" Arguments: Context - The DSM Context value. StatsGatherChoice - Value indicating whether to gather statistics (TRUE) or not (FALSE) Return Value: Status of the RtlWriteRegistryValue call. --*/ { WCHAR registryKeyName[56] = {0}; NTSTATUS status = STATUS_SUCCESS; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetStatsGatherChoice (DsmCtxt %p): Entering function.\n", Context)); // // Build the key value name that we want as the base of the query. // RtlStringCbPrintfW(registryKeyName, sizeof(registryKeyName), DSM_PARAMETER_PATH_W); status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES, registryKeyName, DSM_DISABLE_STATISTICS, REG_DWORD, &StatsGatherChoice, sizeof(ULONG)); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetStatsGatherChoice (DsmCtxt %p): Exiting function with status %x.\n", Context, status)); return status; } NTSTATUS DsmpGetDeviceList( _In_ IN PDSM_CONTEXT Context ) /*++ Routine Description: This routine is used to build the supported device list by querying the services key for the values under "msdsm\Parameters\DsmSupportedDeviceList" Arguments: Context - The DSM Context value. It contains storage for the multi_sz string that may be built. Return Value: Status of the RtlQueryRegistryValues call. --*/ { RTL_QUERY_REGISTRY_TABLE queryTable[2]; WCHAR registryKeyName[56] = {0}; UNICODE_STRING inquiryStrings; WCHAR defaultIDs[] = { L"\0" }; NTSTATUS status; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetDeviceList (DsmCtxt %p): Entering function.\n", Context)); RtlZeroMemory(queryTable, sizeof(queryTable)); RtlInitUnicodeString(&inquiryStrings, NULL); // // Build the key value name that we want as the base of the query. // RtlStringCbPrintfW(registryKeyName, sizeof(registryKeyName), DSM_PARAMETER_PATH_W); // // The query table has two entries. One for the supporteddeviceList and // the second which is the 'NULL' terminator. // // Indicate that there is NO call-back routine, and to give back the MULTI_SZ as // one blob, as opposed to individual unicode strings. // queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_TYPECHECK; // // The value to query. // queryTable[0].Name = DSM_SUPPORTED_DEVICELIST_VALUE_NAME; // // Where to put the strings. Note that we need to use an empty unicode_string // for the query or else RtlQueryRegistryValues will only fill in enough // entries as specified by the size of the unicode string's buffer, which // is why we can't use Context->SupportedDevices directly in the call. // queryTable[0].EntryContext = &inquiryStrings; queryTable[0].DefaultType = (REG_MULTI_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_MULTI_SZ; queryTable[0].DefaultData = defaultIDs; queryTable[0].DefaultLength = sizeof(defaultIDs); status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, registryKeyName, queryTable, registryKeyName, NULL); // // If we successfully queried for the supported device list, we need to delete // our cached list and update it with this new one. // if (NT_SUCCESS(status)) { KIRQL oldIrql; PWCHAR tempBuffer = NULL; tempBuffer = DsmpAllocatePool(NonPagedPoolNx, inquiryStrings.MaximumLength, DSM_TAG_REG_VALUE_RELATED); // // This is a "best effort" operation. If we are unable to allocate a // buffer for the strings, we just continue using our old cached list. // We do NOT fall back to using inquiryStrings's buffer as we want to // be able to work with the supported devices list at raised IRQL. // if (tempBuffer) { RtlCopyMemory(tempBuffer, inquiryStrings.Buffer, inquiryStrings.Length); KeAcquireSpinLock(&Context->SupportedDevicesListLock, &oldIrql); DsmpFreePool(Context->SupportedDevices.Buffer); Context->SupportedDevices.Buffer = tempBuffer; Context->SupportedDevices.Length = inquiryStrings.Length; Context->SupportedDevices.MaximumLength = inquiryStrings.MaximumLength; KeReleaseSpinLock(&Context->SupportedDevicesListLock, oldIrql); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetDeviceList (DsmCtxt %p): Failed to allocate supported device list's buffer.\n", Context)); status = STATUS_INSUFFICIENT_RESOURCES; } ExFreePool(inquiryStrings.Buffer); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetDeviceList (DsmCtxt %p): Exiting function with status %x.\n", Context, status)); return status; } _Success_(return==0) NTSTATUS DsmpGetStandardInquiryData( _In_ IN PDEVICE_OBJECT DeviceObject, _Out_ OUT PINQUIRYDATA InquiryData ) /*++ Routine Description: Helper routine to send an inquiry with EVPD cleared to get the standard inquiry data. Arguments: DeviceObject - The port PDO to which the command should be sent. InquiryData - Pointer to inquiry data that will be returned to caller. Return Value: STATUS_SUCCESS or failure NTSTATUS code. --*/ { PSCSI_PASS_THROUGH_WITH_BUFFERS passThrough = NULL; PCDB cdb; IO_STATUS_BLOCK ioStatus; ULONG length; NTSTATUS status = STATUS_SUCCESS; PINQUIRYDATA inquiryData; PSENSE_DATA senseData; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetStandardInquiryData (DevObj %p): Entering function.\n", DeviceObject)); if (InquiryData == NULL) { status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpGetStandardInquiryData; } // // Build a standard inquiry command. // length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS); passThrough = DsmpAllocatePool(NonPagedPoolNx, length, DSM_TAG_PASS_THRU); if (!passThrough) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetStandardInquiryData (DevObj %p): Failed to allocate mem for passthrough.\n", DeviceObject)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpGetStandardInquiryData; } __Retry_Request: // // Build the cdb for SCSI-3 standard inquiry. // cdb = (PCDB)passThrough->ScsiPassThrough.Cdb; cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY; cdb->CDB6INQUIRY3.EnableVitalProductData = 0; cdb->CDB6INQUIRY3.AllocationLength = sizeof(INQUIRYDATA); passThrough->ScsiPassThrough.Length = sizeof(SCSI_PASS_THROUGH); passThrough->ScsiPassThrough.CdbLength = 6; passThrough->ScsiPassThrough.SenseInfoLength = SPTWB_SENSE_LENGTH; passThrough->ScsiPassThrough.DataIn = 1; passThrough->ScsiPassThrough.DataTransferLength = sizeof(INQUIRYDATA); passThrough->ScsiPassThrough.TimeOutValue = 20; passThrough->ScsiPassThrough.SenseInfoOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseInfoBuffer); passThrough->ScsiPassThrough.DataBufferOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuffer); DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH, DeviceObject, passThrough, passThrough, length, length, FALSE, &ioStatus); status = ioStatus.Status; senseData = (PSENSE_DATA)(passThrough->SenseInfoBuffer); if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(status))) { // // Get the returned data. // inquiryData = (PINQUIRYDATA)(passThrough->DataBuffer); RtlCopyMemory(InquiryData, inquiryData, sizeof(INQUIRYDATA)); } else if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_CHECK_CONDITION) && (NT_SUCCESS(ioStatus.Status)) && (DsmpShouldRetryPassThroughRequest(senseData, passThrough->ScsiPassThrough.SenseInfoLength))) { length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS); // // Retry the request // RtlZeroMemory(passThrough, length); goto __Retry_Request; } else { // Failed to get inquiry data // Here it is possible that status is success, but scsi status is not. // If so, set status to unsuccessful. if (NT_SUCCESS(status)){ status = STATUS_UNSUCCESSFUL; } TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetStandardInquiryData (DevObj %p): NTStatus 0x%x, ScsiStatus 0x%x.\n", DeviceObject, status, passThrough->ScsiPassThrough.ScsiStatus)); } __Exit_DsmpGetStandardInquiryData: // // Free the passthrough + data buffer. // if (passThrough) { DsmpFreePool(passThrough); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetStandardInquiryData (DevObj %p): Exiting function with status %x.\n", DeviceObject, status)); return status; } BOOLEAN DsmpCheckScsiCompliance( _In_ IN PDEVICE_OBJECT TargetObject, _In_ IN PINQUIRYDATA InquiryData, _In_ IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor, _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceIdList ) /*++ Routine Description: Helper routine to determine if the device is SPC-3 compliant. Arguments: DeviceObject - The port PDO that we're determining compliance for. InquiryData - Pointer to its inquiry data. Descriptor - Pointer to its VPD page 0x80 data DeviceIdList - Pointer to its VPD page 0x83 data Return Value: TRUE if compliant, else FALSE. --*/ { BOOLEAN supported = FALSE /* TRUE */; UCHAR deviceType; UCHAR qualifier; UNREFERENCED_PARAMETER(DeviceIdList); UNREFERENCED_PARAMETER(Descriptor); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpCheckScsiCompliance (DevObj %p): Entering function.\n", TargetObject)); deviceType = InquiryData->DeviceType & 0x1F; qualifier = (InquiryData->DeviceTypeQualifier >> 0x5) & 0x7; if ((deviceType | qualifier) == 0x7F) { supported = FALSE; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpCheckScsiCompliance (DevObj %p): Exiting function with Supported = %u.\n", TargetObject, supported)); return supported; } BOOLEAN DsmpDeviceSupported( _In_ IN PDSM_CONTEXT Context, _In_ IN PCSTR VendorId, _In_ IN PCSTR ProductId ) /*++ Routine Description: This routine determines whether the device is supported by traversing the SupportedDevice list and comparing to the VendorId/ProductId values passed in. Arguments: Context - Context value given to the multipath driver during registration. VendorId - Pointer to the inquiry data VendorId. ProductId - Pointer to the inquiry data ProductId. Return Value: TRUE - If VendorId/ProductId is found. --*/ { UNICODE_STRING deviceName; UNICODE_STRING productName; ANSI_STRING ansiVendor; ANSI_STRING ansiProduct; NTSTATUS status; BOOLEAN supported = FALSE; KIRQL oldIrql; UNICODE_STRING tempStrings; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpDeviceSupported (DsmCtxt %p): Entering function.\n", Context)); KeAcquireSpinLock(&Context->SupportedDevicesListLock, &oldIrql); RtlInitUnicodeString(&tempStrings, NULL); tempStrings.Buffer = DsmpAllocatePool(NonPagedPoolNx, Context->SupportedDevices.MaximumLength, DSM_TAG_REG_VALUE_RELATED); if (tempStrings.Buffer) { RtlCopyMemory(tempStrings.Buffer, Context->SupportedDevices.Buffer, Context->SupportedDevices.Length); tempStrings.Length = Context->SupportedDevices.Length; tempStrings.MaximumLength = Context->SupportedDevices.MaximumLength; } else { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpDeviceSupported (DsmCtxt %p): Failed to allocate temporary list (error %x).\n", Context, status)); KeReleaseSpinLock(&Context->SupportedDevicesListLock, oldIrql); goto __Exit_DsmpDeviceSupported; } KeReleaseSpinLock(&Context->SupportedDevicesListLock, oldIrql); // // The SupportedDevice list was built in DriverEntry from the services key. // if (tempStrings.MaximumLength == 0) { // // List is empty. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpDeviceSupported (DsmCtxt %p): No supported Device in the list.\n", Context)); goto __Exit_DsmpDeviceSupported; } RtlInitUnicodeString(&productName, NULL); // // Convert the inquiry fields into ansi strings. // RtlInitAnsiString(&ansiVendor, VendorId); RtlInitAnsiString(&ansiProduct, ProductId); // // Allocate the deviceName buffer. Needs to be 8+16 plus NULL. // (productId length + vendorId length + NULL). // deviceName.MaximumLength = 25 * sizeof(WCHAR); deviceName.Buffer = DsmpAllocatePool(PagedPool, deviceName.MaximumLength, DSM_TAG_SUPPORTED_DEV); if (deviceName.Buffer) { // // Convert the vendorId to unicode. // status = RtlAnsiStringToUnicodeString(&deviceName, &ansiVendor, FALSE); if (NT_SUCCESS(status)) { // // Convert the productId to unicode. // status = RtlAnsiStringToUnicodeString(&productName, &ansiProduct, TRUE); if (NT_SUCCESS(status)) { // // 'cat' them. // status = RtlAppendUnicodeStringToString(&deviceName, &productName); if (NT_SUCCESS(status)) { // // Run the list of supported devices that was captured from the registry // and see if this one is in the list. // supported = DsmpFindSupportedDevice(&deviceName, &tempStrings); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpDeviceSupported (DsmCtxt %p): Failed to append product name. Status %x.\n", Context, status)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpDeviceSupported (DsmCtxt %p): Failed to convert ansi vendor string to unicode. Status %x\n", Context, status)); } DsmpFreePool(deviceName.Buffer); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpDeviceSupported (DsmCtxt %p): Failed to allocate device name buffer.\n", Context)); } __Exit_DsmpDeviceSupported: if (tempStrings.Buffer) { DsmpFreePool(tempStrings.Buffer); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpDeviceSupported (DsmCtxt %p): Exiting function with supported = %u.\n", Context, supported)); return supported; } BOOLEAN DsmpFindSupportedDevice( _In_ IN PUNICODE_STRING DeviceName, _In_ IN PUNICODE_STRING SupportedDevices ) /*++ Routine Description: This routine compares the two unicode strings for a match. Arguments: DeviceName - String built from the current device's inquiry data. SupportedDevices - MULTI_SZ of devices that are supported. Return Value: TRUE - If VendorId/ProductId is found. --*/ { PWSTR devices = SupportedDevices->Buffer; ULONG bufferLengthLeft = SupportedDevices->MaximumLength / sizeof(WCHAR); UNICODE_STRING unicodeString; USHORT originalLength = DeviceName->Length; LONG compare; BOOLEAN supported = FALSE; WCHAR tempString[32]; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpFindSupportedDevice (DevName %ws): Entering function.\n", DeviceName->Buffer)); // // 'devices' is the current buffer in the MULTI_SZ built from // the registry. // while (devices[0]) { RtlZeroMemory(tempString, sizeof(tempString)); if (!NT_SUCCESS(RtlStringCchCopyNW(tempString, sizeof(tempString) / sizeof(tempString[0]), devices, bufferLengthLeft))) { tempString[(sizeof(tempString) / sizeof(tempString)) - 1] = L'\0'; } // // Make the current entry into a unicode string. // RtlInitUnicodeString(&unicodeString, tempString); // // Compare this one with the current device. // However, for storages that make up the product id on-the-fly, MPIO // allows for matching based just on substring (product-id-prefix so to // speak). // if (unicodeString.Length < DeviceName->Length) { DeviceName->Length = unicodeString.Length; } compare = RtlCompareUnicodeStrings(unicodeString.Buffer, unicodeString.Length / sizeof(WCHAR), DeviceName->Buffer, DeviceName->Length / sizeof(WCHAR), TRUE); DeviceName->Length = originalLength; if (compare == 0) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpFindSupportedDevice (DevName %ws): Device support found in the registry.\n", DeviceName->Buffer)); supported = TRUE; break; } // // Advance to next entry in the MULTI_SZ. // devices += (unicodeString.MaximumLength / sizeof(WCHAR)); bufferLengthLeft -= (unicodeString.MaximumLength / sizeof(WCHAR)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpFindSupportedDevice (DevName %ws): Exiting function with Supported = %u.\n", DeviceName->Buffer, supported)); return supported; } _Success_(return!=0) PVOID DsmpParseDeviceID( _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceID, _In_ IN DSM_DEVID_TYPE DeviceIdType, _In_opt_ IN PULONG IdNumber, _Out_opt_ OUT PSTORAGE_IDENTIFIER_CODE_SET CodeSet, _In_ IN BOOLEAN Legacy ) /*++ Routine Description: This routine builds a serial number string based on the information in the VPD page 0x83 data if serial number is requested, else it returns the appropriate identifier requested. Caller must free the buffer. Arguments: DeviceIdList - VPD Page 0x83 information. DeviceIdType - Type of identifier that the DeviceID is being parsed for IdNumber - If there are multiple identifiers of type DeviceIdType, this parameter determines which among them to actually return. IMPORTANT: This number is one-based (not zero-based). CodeSet - Of relevance only if the DeviceIdType is DSM_DEVID_SERIAL_NUMBER. This returns the code set that was used when building the serial number. Legacy - Of relevance only if the DeviceIdType is DSM_DEVID_SERIAL_NUMBER. If the code set of the identifier is StorageIdCodeSetBinary, this determines whether to use the legacy method of binary to ascii conversion. Return Value: Requested Device identifier. --*/ { PSTORAGE_IDENTIFIER identifier; STORAGE_IDENTIFIER_CODE_SET codeSet = StorageIdCodeSetReserved; // Preload with a bogus value. STORAGE_IDENTIFIER_TYPE type = 0xF; STORAGE_ASSOCIATION_TYPE association = 0xF; ULONG numberIds; ULONG i; ULONG identifierSize = 0; PUCHAR bytes = NULL; PVOID buffer = NULL; BOOLEAN done = FALSE; ULONG idNumber = MAXULONG; ULONG matches = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpParseDeviceID (DevIdDesc %p): Entering function - IdType %x.\n", DeviceID, DeviceIdType)); if (IdNumber) { idNumber = *IdNumber; } // // Get the number of encapsulated identifiers. // numberIds = DeviceID->NumberOfIdentifiers; if (idNumber != MAXULONG && idNumber > numberIds) { goto __Exit_DsmpParseDeviceID; } // // Get a pointer to the first one. // identifier = (PSTORAGE_IDENTIFIER)(DeviceID->Identifiers); for (i = 0; i < numberIds && !done; i++) { switch (DeviceIdType) { case DSM_DEVID_SERIAL_NUMBER: { // // The way this works is that we will go through all the identifiers // Order of preference will be LUN-associated over Target-associated. // Further, upon same association, preference will be based on type as // follows: 0x8, 0x3, 0x2, 0x1, 0x0. // So an existing identifier will be discarded if a better one is found. // If two identifiers have the same type, we will prefer the one will // the larger length. // // // 1. Ensure that the association is for either the LUN or target. (If neither, ignore id). // 2. If association is with target, don't it consider if current candidate has assocation with LUN. // 3. If considering this identifier, order of preference is 8 > 3 > 2 > 1 > 0. // 4. If this id type is same as current candidate, consider it only if it is of greater length. // if (((identifier->Association == StorageIdAssocDevice) || (identifier->Association == 0x2 && association != StorageIdAssocDevice)) && ((type == identifier->Type && identifierSize < identifier->IdentifierSize) || (type != identifier->Type && DsmpIsPreferredDeviceId(type, identifier->Type)))) { // // Get a pointer to the id itself. // bytes = identifier->Identifier; // // The id's size. // identifierSize = identifier->IdentifierSize; // // Get the type, code set, and association. // type = identifier->Type; codeSet = identifier->CodeSet; association = identifier->Association; matches++; } break; } case DSM_DEVID_RELATIVE_TARGET_PORT: { // // Ensure that the association is for the target port. // if (identifier->Association != StorageIdAssocPort) { if ((i + 1) < numberIds) { identifier = (PSTORAGE_IDENTIFIER)((PUCHAR)identifier + identifier->NextOffset); } continue; } if (identifier->Type == StorageIdTypePortRelative) { // // Get a pointer to the id itself. // bytes = identifier->Identifier; // // The id's size. // identifierSize = identifier->IdentifierSize; type = identifier->Type; codeSet = identifier->CodeSet; association = identifier->Association; matches++; } break; } case DSM_DEVID_TARGET_PORT_GROUP: { // // Ensure that the association is for the target port. // if (identifier->Association != StorageIdAssocPort) { if ((i + 1) < numberIds) { identifier = (PSTORAGE_IDENTIFIER)((PUCHAR)identifier + identifier->NextOffset); } continue; } if (identifier->Type == 0x5) { // // Get a pointer to the id itself. // bytes = identifier->Identifier; // // Move this by two bytes because first two bytes are reservered // bytes += sizeof(USHORT); // // The id's size. Reduce the size by 2 bytes (to account // for the reservered bytes) // identifierSize = identifier->IdentifierSize - sizeof(USHORT); type = identifier->Type; codeSet = identifier->CodeSet; association = identifier->Association; matches++; } break; } default: break; } if (idNumber != MAXULONG && idNumber == matches) { done = TRUE; } // // Advance to the next identifier in the buffer. // if ((i + 1) < numberIds) { identifier = (PSTORAGE_IDENTIFIER)((PUCHAR)identifier + identifier->NextOffset); } } if (idNumber != MAXULONG && idNumber > matches) { goto __Exit_DsmpParseDeviceID; } if (DeviceIdType == DSM_DEVID_SERIAL_NUMBER) { if (type != StorageIdTypeScsiNameString && type != StorageIdTypeFCPHName && type != StorageIdTypeEUI64 && type != StorageIdTypeVendorId && type != StorageIdTypeVendorSpecific) { DSM_ASSERT(FALSE); bytes = NULL; identifierSize = 0; type = association = 0xF; codeSet = StorageIdCodeSetReserved; } TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpParseDeviceID (DevIdDesc %p): IdentifierSize = %u, Type = %u, Association = %u, CodeSet = %u.\n", DeviceID, identifierSize, type, association, codeSet)); if (!bytes) { goto __Exit_DsmpParseDeviceID; } if (codeSet == StorageIdCodeSetBinary) { // // Need to convert to ascii. // buffer = DsmpBinaryToAscii(bytes, identifierSize, &identifierSize, Legacy); } else { if (identifierSize) { // // Allocate a buffer that is the size of the data, plus one for NULL. // buffer = DsmpAllocatePool(NonPagedPoolNx, identifierSize + 1, DSM_TAG_DEV_ID); DSM_ASSERT(buffer); if (buffer) { // // Copy over the id. // RtlCopyMemory(buffer, bytes, identifierSize); } } } if (CodeSet) { *CodeSet = codeSet; } } else { if (identifierSize) { DSM_ASSERT((DeviceIdType == DSM_DEVID_RELATIVE_TARGET_PORT && identifierSize == sizeof(ULONG)) || (DeviceIdType == DSM_DEVID_TARGET_PORT_GROUP && identifierSize == sizeof(USHORT))); _Analysis_assume_((DeviceIdType == DSM_DEVID_RELATIVE_TARGET_PORT && identifierSize == sizeof(ULONG)) || (DeviceIdType == DSM_DEVID_TARGET_PORT_GROUP && identifierSize == sizeof(USHORT))); buffer = DsmpAllocatePool(NonPagedPoolNx, identifierSize, DSM_TAG_DEV_ID); if (buffer) { if (DeviceIdType == DSM_DEVID_RELATIVE_TARGET_PORT) { GetUlongFrom4ByteArray(bytes, *((PULONG)buffer)); } else if (DeviceIdType == DSM_DEVID_TARGET_PORT_GROUP) { *((PUSHORT)buffer) = (bytes[0] << 8) | (bytes[1]); } } } } __Exit_DsmpParseDeviceID: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpParseDeviceID (DevIdDesc %p): Exiting function with buffer %p.\n", DeviceID, buffer)); return buffer; } PUCHAR DsmpBinaryToAscii( _In_reads_(Length) IN PUCHAR HexBuffer, _In_ IN ULONG Length, _Inout_ IN OUT PULONG UpdateLength, _In_ IN BOOLEAN Legacy ) /*++ Routine Description: This routine will convert HexBuffer into an ascii NULL-terminated string. Note: This routine will allocate memory for storing the ascii string. It is the responsibility of the caller to free this buffer. Arguments: HexBuffer - Pointer to the binary data. Length - Length, in bytes, of HexBuffer. UpdateLength - Storage to place the actual length of the returned string. Legacy - Use the legacy method for the conversion. Return Value: Serial Number string, or NULL if an error occurred. --*/ { static UCHAR IntegerTable[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; ULONG i; ULONG j; ULONG actualLength; PUCHAR buffer = NULL; UCHAR highWord; UCHAR lowWord; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBinaryToAscii (HexBuff %p): Entering function.\n", HexBuffer)); if (Length == 0) { *UpdateLength = 0; goto __Exit_DsmpBinaryToAscii; } if (Legacy) { // // Do a pre-test on the buffer to determine the length actually needed. // for (i = 0, actualLength = 0; i < Length; i++) { if (HexBuffer[i] < 0x10) { actualLength++; } else { actualLength += 2; } } // // Add room for a terminating NULL. // actualLength++; } else { // // We need one character for each nibble, plus one for the terminating NULL. // actualLength = (Length * 2) + 1; } // // Allocate the buffer. // buffer = DsmpAllocatePool(NonPagedPoolNx, actualLength, DSM_TAG_BIN_TO_ASCII); if (!buffer) { *UpdateLength = 0; goto __Exit_DsmpBinaryToAscii; } for (i = 0, j = 0; i < Length && j < actualLength; i++) { if (Legacy && (HexBuffer[i] < 0x10)) { // // If legacy is mentioned and it's 0x0F or less, // just convert the entire byte. // buffer[j++] = IntegerTable[HexBuffer[i]]; } else { // // Split out each nibble from the binary byte. // highWord = HexBuffer[i] >> 4; lowWord = HexBuffer[i] & 0x0F; // // Using the lookup table, convert and stuff into // the ascii buffer. // buffer[j++] = IntegerTable[highWord]; buffer[j++] = IntegerTable[lowWord]; } } // // Update the caller's length field. // *UpdateLength = actualLength; __Exit_DsmpBinaryToAscii: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBinaryToAscii (HexBuff %p): Exiting function with buffer %s.\n", HexBuffer, (const char*) buffer)); return buffer; } PSTR DsmpGetSerialNumber( _In_ IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: Helper routine to send an inquiry with EVPD set to get the serial number page. Used if the serial number is not embedded in the device descriptor (this device probably doesn't support VPD page 0x00). Note: This routine will allocate memory for storing the serial number. It is the responsibility of the caller to free this buffer. Arguments: DeviceObject - The port PDO to which the command should be sent. Return Value: The serial number (null-terminated string) or NULL if the call fails. --*/ { PSCSI_PASS_THROUGH_WITH_BUFFERS passThrough = NULL; PVPD_SERIAL_NUMBER_PAGE serialPage; PCDB cdb; PSTR serialNumber = NULL; IO_STATUS_BLOCK ioStatus; ULONG length; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetSerialNumber (DevObj %p): Entering function.\n", DeviceObject)); // // Build an inquiry command with EVPD and pagecode of 0x80 (serial number). // length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS); passThrough = DsmpAllocatePool(NonPagedPoolNx, length, DSM_TAG_PASS_THRU); if (!passThrough) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetSerialNumber (DevObj %p): Failed to allocate mem for passthrough.\n", DeviceObject)); goto __Exit_DsmpGetSerialNumber; } // // Build the cdb. // cdb = (PCDB)passThrough->ScsiPassThrough.Cdb; cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY; cdb->CDB6INQUIRY.Reserved1 = 1; cdb->CDB6INQUIRY.PageCode = VPD_SERIAL_NUMBER; cdb->CDB6INQUIRY.AllocationLength = DSM_SERIAL_NUMBER_BUFFER_SIZE; passThrough->ScsiPassThrough.Length = sizeof(SCSI_PASS_THROUGH); passThrough->ScsiPassThrough.CdbLength = 6; passThrough->ScsiPassThrough.SenseInfoLength = SPTWB_SENSE_LENGTH; passThrough->ScsiPassThrough.DataIn = 1; passThrough->ScsiPassThrough.DataTransferLength = DSM_SERIAL_NUMBER_BUFFER_SIZE; passThrough->ScsiPassThrough.TimeOutValue = 20; passThrough->ScsiPassThrough.SenseInfoOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseInfoBuffer); passThrough->ScsiPassThrough.DataBufferOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuffer); DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH, DeviceObject, passThrough, passThrough, length, length, FALSE, &ioStatus); if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(ioStatus.Status))) { ULONG inx; // // Get the returned data. // serialPage = (PVPD_SERIAL_NUMBER_PAGE)(passThrough->DataBuffer); // // Allocate a buffer to hold just the serial number plus a null terminator // serialNumber = DsmpAllocatePool(NonPagedPoolNx, serialPage->PageLength + 1, DSM_TAG_SERIAL_NUM); if (serialNumber) { // // Copy it over. // RtlCopyMemory(serialNumber, serialPage->SerialNumber, serialPage->PageLength); // // Some devices return binary data for the serial number. // Convert to a more ascii-ish format so that other routines don't have a problem. // for (inx = 0; inx < serialPage->PageLength; inx++) { if (serialNumber[inx] == '\0') { serialNumber[inx] = ' '; } } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetSerialNumber (DevObj %p): Failed to allocate mem for serialnumber.\n", DeviceObject)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetSerialNumber (DevObj %p): NTStatus 0%x, ScsiStatus 0x%x.\n", DeviceObject, ioStatus.Status, passThrough->ScsiPassThrough.ScsiStatus)); } __Exit_DsmpGetSerialNumber: // // Free the passthrough + data buffer. // if (passThrough) { DsmpFreePool(passThrough); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetSerialNumber (DevObj %p): Exiting function with serial number %s.\n", DeviceObject, (const char*)serialNumber)); // // Return the sn. // return serialNumber; } NTSTATUS DsmpDisableImplicitStateTransition( _In_ IN PDEVICE_OBJECT TargetDevice, _Out_ OUT PBOOLEAN DisableImplicit ) /*++ Routine Description: Send down request to disable implicit ALUA state transition. The function first sends down a mode sense to get the control extension mode sense data. It then clears the IALUAE bit and sends down a mode select. Arguements: TargetDevice - Device object that will be target of this command. DisableImplicit - Flag returned to the caller to indicate whether or not implicit transitions are disabled. Return Value : STATUS_SUCCESS if the command succeeds. Appropriate NTSTATUS code on failure --*/ { NTSTATUS status = STATUS_SUCCESS; PSCSI_PASS_THROUGH_WITH_BUFFERS passThrough = NULL; PCDB cdb; IO_STATUS_BLOCK ioStatus; ULONG length; PSPC3_CONTROL_EXTENSION_MODE_PAGE controlExtensionPage = NULL; PSENSE_DATA senseData = NULL; BOOLEAN implicitDisabled = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpDisableImplicitStateTransition (DevObj %p): Entering function.\n", TargetDevice)); // // First build the mode sense command to get the control extension parameters. // length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS); passThrough = DsmpAllocatePool(NonPagedPoolNx, length, DSM_TAG_PASS_THRU); if (!passThrough) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpDisableImplicitStateTransition (DevObj %p): Failed to allocate mem for passthrough.\n", TargetDevice)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpDisableImplicitStateTransition; } __Retry_ModeSense: passThrough->ScsiPassThrough.Length = sizeof(SCSI_PASS_THROUGH); passThrough->ScsiPassThrough.CdbLength = 6; passThrough->ScsiPassThrough.SenseInfoLength = SPTWB_SENSE_LENGTH; passThrough->ScsiPassThrough.DataIn = 1; passThrough->ScsiPassThrough.DataTransferLength = sizeof(SPC3_CONTROL_EXTENSION_MODE_PAGE); passThrough->ScsiPassThrough.TimeOutValue = 20; passThrough->ScsiPassThrough.SenseInfoOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseInfoBuffer); passThrough->ScsiPassThrough.DataBufferOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuffer); // // Build the cdb for mode sense. // cdb = (PCDB)passThrough->ScsiPassThrough.Cdb; cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; cdb->MODE_SENSE.Dbd = 1; cdb->MODE_SENSE.PageCode = 0xA; cdb->MODE_SENSE.SubPageCode = 0x01; cdb->MODE_SENSE.AllocationLength = sizeof(SPC3_CONTROL_EXTENSION_MODE_PAGE); DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH, TargetDevice, passThrough, passThrough, length, length, FALSE, &ioStatus); status = ioStatus.Status; senseData = (PSENSE_DATA)(passThrough->SenseInfoBuffer); if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(status))) { controlExtensionPage = (PSPC3_CONTROL_EXTENSION_MODE_PAGE)(passThrough->DataBuffer); if (controlExtensionPage->ImplicitALUAEnable) { controlExtensionPage->ImplicitALUAEnable = 0; __Retry_ModeSelect: RtlZeroMemory(passThrough->SenseInfoBuffer, passThrough->ScsiPassThrough.SenseInfoLength); passThrough->ScsiPassThrough.DataIn = 0; // // Build the cdb for mode select. // RtlZeroMemory(cdb, 6); cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; cdb->MODE_SELECT.SPBit = 0; cdb->MODE_SELECT.PFBit = 1; cdb->MODE_SELECT.ParameterListLength = sizeof(SPC3_CONTROL_EXTENSION_MODE_PAGE); length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS); DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH, TargetDevice, passThrough, passThrough, length, length, FALSE, &ioStatus); status = ioStatus.Status; senseData = (PSENSE_DATA)(passThrough->SenseInfoBuffer); if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(status))) { implicitDisabled = TRUE; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpDisableImplicitStateTransition (DevObj %p): Implicit transitions turned off successfully.\n", TargetDevice)); } else if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_CHECK_CONDITION) && (NT_SUCCESS(status)) && (DsmpShouldRetryPassThroughRequest(senseData, passThrough->ScsiPassThrough.SenseInfoLength))) { // // Retry the request // goto __Retry_ModeSelect; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpDisableImplicitStateTransition (DevObj %p): ModeSelect failed - NTStatus 0x%x, ScsiStatus 0x%x.\n", TargetDevice, status, passThrough->ScsiPassThrough.ScsiStatus)); } } else { implicitDisabled = TRUE; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpDisableImplicitStateTransition (DevObj %p): Implicit transitions already turned OFF.\n", TargetDevice)); } } else if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_CHECK_CONDITION) && (NT_SUCCESS(status)) && (DsmpShouldRetryPassThroughRequest(senseData, passThrough->ScsiPassThrough.SenseInfoLength))) { length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS); // // Retry the request // RtlZeroMemory(passThrough, length); goto __Retry_ModeSense; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpDisableImplicitStateTransition (DevObj %p): ModeSense failed - NTStatus 0x%x, ScsiStatus 0x%x.\n", TargetDevice, status, passThrough->ScsiPassThrough.ScsiStatus)); } __Exit_DsmpDisableImplicitStateTransition: // // Free the passthrough + data buffer. // if (passThrough) { DsmpFreePool(passThrough); } // // Return whether IALUAE is set to 0. // if (DisableImplicit) { *DisableImplicit = implicitDisabled; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpDisableImplicitStateTransition (DevObj %p): Exiting function with status %x.\n", TargetDevice, status)); return status; } PWSTR DsmpBuildHardwareId( _In_ IN PDSM_DEVICE_INFO DeviceInfo ) /*++ Routine Description: Construct a string concatinating VendorId with ProductId. Arguements: DeviceInfo - Device Extension Return Value : NULL terminated hardware id if it was built successfully. NULL in case of failure. --*/ { PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor; PWSTR hardwareId = NULL; SIZE_T vendorIDLength = 0; SIZE_T productIDLength = 0; PCSZ vendorIdOffset; PCSZ productIdOffset; SIZE_T sizeNeeded; NTSTATUS status = STATUS_SUCCESS; ANSI_STRING ansiString; UNICODE_STRING unicodeString; ULONG offset; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildHardwareId (DevInfo %p): Entering function.\n", DeviceInfo)); deviceDescriptor = &(DeviceInfo->Descriptor); // // Save the vendorid and productid offset in Device Descriptor // offset = deviceDescriptor->ProductIdOffset; if ((offset != 0) && (offset != MAXULONG)) { productIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE; } offset = deviceDescriptor->VendorIdOffset; if ((offset != 0) && (offset != MAXULONG)) { vendorIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE; } if (!vendorIDLength || !productIDLength) { status = STATUS_UNSUCCESSFUL; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "DsmpBuildHardwareId (DevInfo %p): Invalid vendor and/or product id.\n", DeviceInfo)); goto __Exit_DsmpBuildHardwareId; } sizeNeeded = vendorIDLength + productIDLength; hardwareId = DsmpAllocatePool(NonPagedPoolNx, sizeNeeded, DSM_TAG_DEV_HARDWARE_ID); if (!hardwareId) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildHardwareId (DevInfo %p): Failed to allocate memory for device name.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpBuildHardwareId; } // // Build the NULL terminated hardwareId whose format is : // // VendorIdProductId // vendorIdOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->VendorIdOffset); RtlInitAnsiString(&ansiString, vendorIdOffset); unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT)vendorIDLength; unicodeString.Buffer = hardwareId; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildHardwareId (DevInfo %p): Failed to convert vendor id to unicode string.\n", DeviceInfo)); goto __Exit_DsmpBuildHardwareId; } productIdOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->ProductIdOffset); RtlInitAnsiString(&ansiString, productIdOffset); unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT)productIDLength; unicodeString.Buffer = hardwareId + strlen(((PCHAR)deviceDescriptor) + offset); status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildHardwareId (DevInfo %p): Failed to convert product id to unicode string.\n", DeviceInfo)); goto __Exit_DsmpBuildHardwareId; } TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildHardwareId (DevInfo %p): HardwareId is %ws.\n", DeviceInfo, hardwareId)); __Exit_DsmpBuildHardwareId: if (hardwareId && !NT_SUCCESS(status)) { DsmpFreePool(hardwareId); hardwareId = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildHardwareId (DevInfo %p): Exiting function with deviceName %ws.\n", DeviceInfo, hardwareId)); return hardwareId; } PWSTR DsmpBuildDeviceNameLegacyPage0x80( _In_ IN PDSM_DEVICE_INFO DeviceInfo ) /*++ Routine Description: Construct a string from VendorId, ProductId, and SerialNumber (page 0x80 info) of the device. Arguements: DeviceInfo - Device Extension Return Value : STATUS_SUCCESS if the device name was built successfully. Appropriate NTSTATUS code on failure --*/ { PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor; PWCHAR deviceName = NULL; PWCHAR tmpPtr; PWCHAR vendorID = NULL; PWCHAR productID = NULL; PWCHAR serialID = NULL; ANSI_STRING ansiString; UNICODE_STRING unicodeString; UNICODE_STRING unicodeDeviceName; SIZE_T vendorIDLength = 0; SIZE_T productIDLength = 0; SIZE_T serialIDLength = 0; ULONG offset; SIZE_T sizeNeeded; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Entering function.\n", DeviceInfo)); deviceDescriptor = &(DeviceInfo->Descriptor); // // Save the vendorid, productid, and serialnumber offset // in Device Descriptor // offset = deviceDescriptor->VendorIdOffset; if ((offset != 0) && (offset != MAXULONG)) { vendorIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE; } offset = deviceDescriptor->ProductIdOffset; if ((offset != 0) && (offset != MAXULONG)) { productIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE; } offset = deviceDescriptor->SerialNumberOffset; if ((offset != 0) && (offset != MAXULONG)) { serialIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE; } // // Allocate buffers to use to convert the IDs from ANSI to Unicode and // eventually build the device name. // if (vendorIDLength > 0) { vendorID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, vendorIDLength, DSM_TAG_DEV_NAME); if (!vendorID) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to allocate memory for vendor ID.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } if (productIDLength > 0) { productID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, productIDLength, DSM_TAG_DEV_NAME); if (!productID) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to allocate memory for product ID.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } if (serialIDLength > 0) { serialID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, serialIDLength, DSM_TAG_DEV_NAME); if (!serialID) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to allocate memory for serial ID.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } sizeNeeded = vendorIDLength + productIDLength + serialIDLength; if (sizeNeeded > 0) { // // Account for the terminating NULL if serial id is empty. // sizeNeeded += (serialIDLength ? 0 : WNULL_SIZE); deviceName = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, sizeNeeded, DSM_TAG_DEV_NAME); if (!deviceName) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to allocate memory for device name.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } else { status = STATUS_UNSUCCESSFUL; } if (!NT_SUCCESS(status)) { goto __Exit_DsmpBuildDeviceNameLegacyPage0x80; } // // Build the NULL terminated device name whose format is : // // VendorId_ProductId_SerialNumber // unicodeDeviceName.Length = 0; unicodeDeviceName.MaximumLength = (USHORT)sizeNeeded; unicodeDeviceName.Buffer = deviceName; if (vendorIDLength) { PCSZ vendorIdOffset; vendorIdOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->VendorIdOffset); RtlInitAnsiString(&ansiString, vendorIdOffset); unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT) vendorIDLength; unicodeString.Buffer = vendorID; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to convert vendor id to unicode string.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceNameLegacyPage0x80; } // // If there are spaces in the id, set NULL at the first space. // tmpPtr = wcschr(vendorID, L' '); if (tmpPtr != NULL) { *tmpPtr = WNULL; } status = RtlUnicodeStringCatString(&unicodeDeviceName, vendorID); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to concatenate vendor ID to device name.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceNameLegacyPage0x80; } RtlUnicodeStringCatString(&unicodeDeviceName, L"_"); } if (productIDLength) { PCSZ productIdOffset; productIdOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->ProductIdOffset); RtlInitAnsiString(&ansiString, productIdOffset); unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT) productIDLength; unicodeString.Buffer = productID; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to convert product id to unicode string.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceNameLegacyPage0x80; } // // If there are spaces in the id, set NULL at the first space. // tmpPtr = wcschr(productID, L' '); if (tmpPtr != NULL) { *tmpPtr = WNULL; } status = RtlUnicodeStringCatString(&unicodeDeviceName, productID); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to concatenate product ID to device name.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceNameLegacyPage0x80; } RtlUnicodeStringCatString(&unicodeDeviceName, L"_"); } // // Serial number // if (serialIDLength) { PCSZ serialNumberOffset; serialNumberOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->SerialNumberOffset); RtlInitAnsiString(&ansiString, serialNumberOffset); unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT) serialIDLength; unicodeString.Buffer = serialID; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to convert serial number to unicode string.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceNameLegacyPage0x80; } // // If there are spaces in the id, set NULL at the first space. // tmpPtr = wcschr(serialID, L' '); if (tmpPtr != NULL) { *tmpPtr = WNULL; } status = RtlUnicodeStringCatString(&unicodeDeviceName, serialID); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to concatenate serial number to device name.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceNameLegacyPage0x80; } } TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Device Name is %ws.\n", DeviceInfo, deviceName)); __Exit_DsmpBuildDeviceNameLegacyPage0x80: if (vendorID) { DsmpFreePool(vendorID); } if (productID) { DsmpFreePool(productID); } if (serialID) { DsmpFreePool(serialID); } if (deviceName && !NT_SUCCESS(status)) { DsmpFreePool(deviceName); deviceName = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Exiting function with deviceName %ws.\n", DeviceInfo, deviceName)); return deviceName; } PWSTR DsmpBuildDeviceName( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_reads_(SerialNumberLength) IN PSTR SerialNumber, _In_ IN SIZE_T SerialNumberLength ) /*++ Routine Description: Construct a string from VendorId, ProductId, and SerialNumber (page 0x83 identifiers) of the device. Arguements: DeviceInfo - Device Extension SerialNumber - Device serial number built from appropriate page 0x83 identifier SerialNumberLength - Length (in chars) of the passed in serial number buffer Return Value : Device name if it was built successfully. NULL in case of failure. --*/ { PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor; PWCHAR deviceName = NULL; PWCHAR tmpPtr; PWCHAR vendorID = NULL; PWCHAR productID = NULL; PWCHAR serialID = NULL; ANSI_STRING ansiString; UNICODE_STRING unicodeString; UNICODE_STRING unicodeDeviceName; SIZE_T vendorIDLength = 0; SIZE_T productIDLength = 0; SIZE_T serialIDLength = 0; ULONG offset; SIZE_T sizeNeeded; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Entering function.\n", DeviceInfo)); deviceDescriptor = &(DeviceInfo->Descriptor); // // Save the vendorid, productid, and serialnumber offset // in Device Descriptor // offset = deviceDescriptor->VendorIdOffset; if ((offset != 0) && (offset != MAXULONG)) { vendorIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE; } offset = deviceDescriptor->ProductIdOffset; if ((offset != 0) && (offset != -1)) { productIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE; } if (SerialNumber) { serialIDLength = (SerialNumberLength * sizeof(WCHAR)) + WNULL_SIZE; } // // Allocate buffers to use to convert the IDs from ANSI to Unicode and // eventually build the device name. // if (vendorIDLength > 0) { vendorID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, vendorIDLength, DSM_TAG_DEV_NAME); if (!vendorID) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to allocate memory for vendor ID.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } if (productIDLength > 0) { productID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, productIDLength, DSM_TAG_DEV_NAME); if (!productID) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to allocate memory for product ID.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } if (serialIDLength > 0) { serialID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, serialIDLength, DSM_TAG_DEV_NAME); if (!serialID) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to allocate memory for serial ID.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } sizeNeeded = vendorIDLength + productIDLength + serialIDLength; if (sizeNeeded > 0) { // // Account for the terminating NULL if serial id is empty. // sizeNeeded += (serialIDLength ? 0 : WNULL_SIZE); deviceName = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, sizeNeeded, DSM_TAG_DEV_NAME); if (!deviceName) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to allocate memory for device name.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } } else { status = STATUS_UNSUCCESSFUL; } if (!NT_SUCCESS(status)) { goto __Exit_DsmpBuildDeviceName; } // // Build the NULL terminated device name whose format is : // // VendorId_ProductId_SerialNumber // unicodeDeviceName.Length = 0; unicodeDeviceName.MaximumLength = (USHORT)sizeNeeded; unicodeDeviceName.Buffer = deviceName; if (vendorIDLength) { PCSZ vendorIdOffset; vendorIdOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->VendorIdOffset); RtlInitAnsiString(&ansiString, vendorIdOffset); unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT) vendorIDLength; unicodeString.Buffer = vendorID; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to convert vendor id to unicode string.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceName; } // // If there are spaces in the id, set NULL at the first space. // tmpPtr = wcschr(vendorID, L' '); if (tmpPtr != NULL) { *tmpPtr = WNULL; } status = RtlUnicodeStringCatString(&unicodeDeviceName, vendorID); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to concatenate vendor ID to device name.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceName; } RtlUnicodeStringCatString(&unicodeDeviceName, L"_"); } if (productIDLength) { PCSZ productIdOffset; productIdOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->ProductIdOffset); RtlInitAnsiString(&ansiString, productIdOffset); unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT) productIDLength; unicodeString.Buffer = productID; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to convert product id to unicode string.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceName; } // // If there are spaces in the id, set NULL at the first space. // tmpPtr = wcschr(productID, L' '); if (tmpPtr != NULL) { *tmpPtr = WNULL; } status = RtlUnicodeStringCatString(&unicodeDeviceName, productID); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to concatenate product ID to device name.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceName; } RtlUnicodeStringCatString(&unicodeDeviceName, L"_"); } // // Serial number // if (serialIDLength) { PSTR serialNumberOffset; serialNumberOffset = SerialNumber; RtlInitAnsiString(&ansiString, serialNumberOffset); unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT) serialIDLength; unicodeString.Buffer = serialID; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to convert serial number to unicode string.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceName; } // // If there are spaces in the id, set NULL at the first space. // tmpPtr = wcschr(serialID, L' '); if (tmpPtr != NULL) { *tmpPtr = WNULL; } status = RtlUnicodeStringCatString(&unicodeDeviceName, serialID); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Failed to concatenate serial number to device name.\n", DeviceInfo)); goto __Exit_DsmpBuildDeviceName; } } TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Device Name is %ws.\n", DeviceInfo, deviceName)); __Exit_DsmpBuildDeviceName: if (vendorID) { DsmpFreePool(vendorID); } if (productID) { DsmpFreePool(productID); } if (serialID) { DsmpFreePool(serialID); } if (deviceName && !NT_SUCCESS(status)) { DsmpFreePool(deviceName); deviceName = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpBuildDeviceName (DevInfo %p): Exiting function with deviceName %ws.\n", DeviceInfo, deviceName)); return deviceName; } NTSTATUS DsmpApplyDeviceNameCorrection( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_reads_(DeviceNameLegacyLen) PWSTR DeviceNameLegacy, _In_ IN SIZE_T DeviceNameLegacyLen, _In_reads_(DeviceNameLen) PWSTR DeviceName, _In_ IN SIZE_T DeviceNameLen ) /*++ Routine Description: If the registry has a key name built with a legacy device name, this function updates the key name with the current device name. Arguements: DeviceInfo - Device instance DeviceNameLegacy - Device name built using legacy methods. DeviceNameLegacyLen - Number of chars (including NULL) of the DeviceNameLegacy buffer. DeviceName - Device name built using current methods. DeviceNameLen - Number of chars (including NULL) of the DeviceName buffer. Return Value : STATUS_SUCCESS if the device's key was updated successfully. Appropriate NTSTATUS code on failure --*/ { HANDLE lbSettingsKey = NULL; HANDLE deviceKeyLegacy = NULL; HANDLE deviceKey = NULL; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status; UNICODE_STRING deviceNameLegacy; UNICODE_STRING deviceName; PAGED_CODE(); UNREFERENCED_PARAMETER(DeviceNameLen); UNREFERENCED_PARAMETER(DeviceNameLegacyLen); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Entering function.\n", DeviceInfo)); // // First open LoadBalanceSettings key under the service key. // status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to open LB Settings key. Status %x.\n", DeviceInfo, status)); goto __Exit_DsmpApplyDeviceNameCorrection; } RtlInitUnicodeString(&deviceNameLegacy, DeviceNameLegacy); InitializeObjectAttributes(&objectAttributes, &deviceNameLegacy, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), lbSettingsKey, (PSECURITY_DESCRIPTOR) NULL); // // Open the old device key under DsmLoadBalanceSettings key. // The name of this key is the one built using legacy methods - either a // serial number from VPD page 0x80 or an aliased serial number from VPD // page 0x83. // status = ZwOpenKey(&deviceKeyLegacy, KEY_ALL_ACCESS, &objectAttributes); if (NT_SUCCESS(status)) { ULONG disposition; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Key with old device name exists.\n", DeviceInfo)); RtlInitUnicodeString(&deviceName, DeviceName); InitializeObjectAttributes(&objectAttributes, &deviceName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), lbSettingsKey, (PSECURITY_DESCRIPTOR) NULL); // // Since the old name key exists, create one with the new name. // status = ZwCreateKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &disposition); if (NT_SUCCESS(status)) { // // The new key shouldn't exist if the old one does. // If it does, it indicates a error occured the previous time // this was tried, so just copy over the old subtree anyways now. // DSM_ASSERT(disposition == REG_CREATED_NEW_KEY); // // Copy over the entire subtree of the old key over to the new key. // status = DsmpRegCopyTree(deviceKeyLegacy, deviceKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to copy over the old device key's subtree. Status %x.\n", DeviceInfo, status)); goto __Exit_DsmpApplyDeviceNameCorrection; } // // Delete the old key name. // status = DsmpRegDeleteTree(deviceKeyLegacy); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to delete the old device key's subtree. Status %x.\n", DeviceInfo, status)); goto __Exit_DsmpApplyDeviceNameCorrection; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to create the new device key. Status %x.\n", DeviceInfo, status)); goto __Exit_DsmpApplyDeviceNameCorrection; } } else if (status == STATUS_INVALID_HANDLE || status == STATUS_OBJECT_NAME_NOT_FOUND) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Key with old device name does not exist.\n", DeviceInfo)); status = STATUS_SUCCESS; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to query key with old device name. Status %x\n", DeviceInfo, status)); } __Exit_DsmpApplyDeviceNameCorrection: if (deviceKey) { ZwClose(deviceKey); } if (deviceKeyLegacy) { ZwClose(deviceKeyLegacy); } if (lbSettingsKey) { ZwClose(lbSettingsKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpApplyDeviceNameCorrection (DevInfo %p): Exiting function with status %x\n", DeviceInfo, status)); return status; } NTSTATUS DsmpQueryDeviceLBPolicyFromRegistry( _In_ PDSM_DEVICE_INFO DeviceInfo, _In_ PWSTR RegistryKeyName, _Inout_ PDSM_LOAD_BALANCE_TYPE LoadBalanceType, _Inout_ PULONGLONG PreferredPath, _Inout_ PUCHAR ExplicitlySet ) /*++ Routine Description: Query the saved load balance policy and preferred path for this device from the registry. Also returns whether this setting was explicitly set via WMI call to SetLBPolicy, (as opposed to the settings being made based on defaults determined through the storage's ALUA capabilities). Arguements: DeviceInfo - The instance of the LUN through a paricular path RegistryKeyName - DeviceName representing this LUN LoadBalanceType - Type of LB policy. PreferredPath - The preferred path for the device. ExplicitlySet - Flag reflecting if LB policy was explicitly set. Return Value : STATUS_SUCCESS if we were able to successfully query the registry for the info. Appropriate NTSTATUS code on failure --*/ { HANDLE lbSettingsKey = NULL; HANDLE deviceKey = NULL; UNICODE_STRING subKeyName; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status; UNICODE_STRING keyValueName; ULONG length; struct _explicitSet { KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; UCHAR Data; } explicitSet; struct _preferredPath { KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; ULONGLONG Data; } preferredPath; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Entering function.\n", DeviceInfo)); // // Query the Load Balance settings for the given device from the registry. // First open LoadBalanceSettings key under the service key. // status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to open LB Settings key. Status %x.\n", DeviceInfo, status)); goto __Exit_DsmpQueryDeviceLBPolicyFromRegistry; } RtlInitUnicodeString(&subKeyName, RegistryKeyName); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), lbSettingsKey, (PSECURITY_DESCRIPTOR) NULL); // // Create or Open the device key under DsmLoadBalanceSettings key. // The name of this key is the one built in DsmpBuildDeviceName // status = ZwCreateKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (NT_SUCCESS(status)) { RTL_QUERY_REGISTRY_TABLE queryTable[2]; RtlZeroMemory(queryTable, sizeof(queryTable)); queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_LOAD_BALANCE_POLICY; queryTable[0].EntryContext = LoadBalanceType; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, deviceKey, queryTable, deviceKey, NULL); if (NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): LB Policy is %d.\n", DeviceInfo, *LoadBalanceType)); } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) { // // The device key must have been newly created. // Set the default load balance policy for this device // status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, deviceKey, DSM_LOAD_BALANCE_POLICY, REG_DWORD, LoadBalanceType, sizeof(ULONG)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to write LB policy. Status %x.\n", DeviceInfo, status)); goto __Exit_DsmpQueryDeviceLBPolicyFromRegistry; } } if (NT_SUCCESS(status)) { RtlInitUnicodeString(&keyValueName, DSM_POLICY_EXPLICITLY_SET); status = ZwQueryValueKey(deviceKey, &keyValueName, KeyValuePartialInformation, &explicitSet, sizeof(explicitSet), &length); if (NT_SUCCESS(status)) { NT_ASSERT(explicitSet.KeyValueInfo.DataLength == sizeof(UCHAR)); *ExplicitlySet = *((UCHAR UNALIGNED *)&(explicitSet.KeyValueInfo.Data)); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): ExplicitlySet is %!bool!.\n", DeviceInfo, *ExplicitlySet)); } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) { *ExplicitlySet = FALSE; // // The device key must have been newly created. // Set ExplicitlySet to 0 to indicate that the default was used. // status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, deviceKey, DSM_POLICY_EXPLICITLY_SET, REG_BINARY, ExplicitlySet, sizeof(UCHAR)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to write ExplicitlySet. Status %x.\n", DeviceInfo, status)); } } if (NT_SUCCESS(status)) { RtlInitUnicodeString(&keyValueName, DSM_PREFERRED_PATH); status = ZwQueryValueKey(deviceKey, &keyValueName, KeyValuePartialInformation, &preferredPath, sizeof(preferredPath), &length); if (NT_SUCCESS(status)) { NT_ASSERT(preferredPath.KeyValueInfo.DataLength == sizeof(ULONGLONG)); *PreferredPath = *((ULONGLONG UNALIGNED *)&(preferredPath.KeyValueInfo.Data)); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): PreferredPath is %I64x.\n", DeviceInfo, *PreferredPath)); } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) { *PreferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG); // // The device key must have been newly created. // Set a bogus preferred path as default. // status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, deviceKey, DSM_PREFERRED_PATH, REG_BINARY, PreferredPath, sizeof(ULONGLONG)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to write PreferredPath. Status %x.\n", DeviceInfo, status)); } } } } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to create LB policy registry key. Status %x.\n", DeviceInfo, status)); deviceKey = NULL; } __Exit_DsmpQueryDeviceLBPolicyFromRegistry: if (deviceKey) { ZwClose(deviceKey); } if (lbSettingsKey) { ZwClose(lbSettingsKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Exiting function with status %x.\n", DeviceInfo, status)); return status; } NTSTATUS DsmpQueryTargetLBPolicyFromRegistry( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _Out_ OUT PDSM_LOAD_BALANCE_TYPE LoadBalanceType, _Out_ OUT PULONGLONG PreferredPath ) /*++ Routine Description: Query the load balance policy for the VID/PID of the passed in device from the registry if it has been set. Arguements: DeviceInfo - Device's whose VID/PID we need to compare against. LoadBalanceType - Type of LB policy. PreferredPath - The preferred path for the device. Return Value : STATUS_SUCCESS if we were able to successfully query the registry for the info. Appropriate NTSTATUS code on failure --*/ { HANDLE targetsLBSettingKey = NULL; HANDLE targetKey = NULL; UNICODE_STRING subKeyName; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status = STATUS_INVALID_PARAMETER; UNICODE_STRING keyValueName; ULONG length; struct _preferredPath { KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; ULONGLONG Data; } preferredPath; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Entering function.\n", DeviceInfo)); if (!LoadBalanceType || !PreferredPath) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Invalid parameter.\n", DeviceInfo)); goto __Exit_DsmpQueryTargetLBPolicyFromRegistry; } if (!DeviceInfo->Group->HardwareId) { status = STATUS_UNSUCCESSFUL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Couldn't build hardware id for passed in device.\n", DeviceInfo)); goto __Exit_DsmpQueryTargetLBPolicyFromRegistry; } // // Query the Load Balance settings for the given target from the registry. // First open TargetsLoadBalanceSetting key under the service key. // status = DsmpOpenTargetsLoadBalanceSettingKey(KEY_ALL_ACCESS, &targetsLBSettingKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Failed to open Targets LB Setting key. Status %x.\n", DeviceInfo, status)); goto __Exit_DsmpQueryTargetLBPolicyFromRegistry; } RtlInitUnicodeString(&subKeyName, DeviceInfo->Group->HardwareId); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), targetsLBSettingKey, (PSECURITY_DESCRIPTOR) NULL); // // Open the VID/PID key under DsmTargetsLoadBalanceSetting key. // status = ZwOpenKey(&targetKey, KEY_ALL_ACCESS, &objectAttributes); if (NT_SUCCESS(status)) { RTL_QUERY_REGISTRY_TABLE queryTable[2]; RtlZeroMemory(queryTable, sizeof(queryTable)); queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_LOAD_BALANCE_POLICY; queryTable[0].EntryContext = LoadBalanceType; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, targetKey, queryTable, targetKey, NULL); if (NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): LB Policy is %d.\n", DeviceInfo, *LoadBalanceType)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Failed to query LB Policy - error %x.\n", DeviceInfo, status)); } if (NT_SUCCESS(status)) { RtlInitUnicodeString(&keyValueName, DSM_PREFERRED_PATH); status = ZwQueryValueKey(targetKey, &keyValueName, KeyValuePartialInformation, &preferredPath, sizeof(preferredPath), &length); if (NT_SUCCESS(status)) { NT_ASSERT(preferredPath.KeyValueInfo.DataLength == sizeof(ULONGLONG)); *PreferredPath = *((ULONGLONG UNALIGNED *)&(preferredPath.KeyValueInfo.Data)); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): PreferredPath is %I64x.\n", DeviceInfo, *PreferredPath)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Failed to query PreferredPath. Status %x.\n", DeviceInfo, status)); } } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Failed to open LB policy registry key. Status %x.\n", DeviceInfo, status)); targetKey = NULL; } __Exit_DsmpQueryTargetLBPolicyFromRegistry: if (targetKey) { ZwClose(targetKey); } if (targetsLBSettingKey) { ZwClose(targetsLBSettingKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Exiting function with status %x.\n", DeviceInfo, status)); return status; } NTSTATUS DsmpQueryDsmLBPolicyFromRegistry( _Out_ OUT PDSM_LOAD_BALANCE_TYPE LoadBalanceType, _Out_ OUT PULONGLONG PreferredPath ) /*++ Routine Description: Query the overall load balance policy for MSDSM controlled devices from the registry if it has been set. Arguements: LoadBalanceType - Type of LB policy. PreferredPath - The preferred path for the device. Return Value : STATUS_SUCCESS if we were able to successfully query the registry for the info. Appropriate NTSTATUS code on failure --*/ { HANDLE parametersKey = NULL; NTSTATUS status = STATUS_INVALID_PARAMETER; UNICODE_STRING keyValueName; RTL_QUERY_REGISTRY_TABLE queryTable[2]; ULONG length; struct _preferredPath { KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; ULONGLONG Data; } preferredPath; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryDsmLBPolicyFromRegistry: Entering function.\n")); if (!LoadBalanceType || !PreferredPath) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDsmLBPolicyFromRegistry: Invalid parameter.\n")); goto __Exit_DsmpQueryDsmLBPolicyFromRegistry; } // // Query the overall default Load Balance settings for MSDSM from the registry. // First open the Parameters key under the service key. // status = DsmpOpenDsmServicesParametersKey(KEY_ALL_ACCESS, ¶metersKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDsmLBPolicyFromRegistry: Failed to open Parameters key. Status %x.\n", status)); goto __Exit_DsmpQueryDsmLBPolicyFromRegistry; } RtlZeroMemory(queryTable, sizeof(queryTable)); queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_LOAD_BALANCE_POLICY; queryTable[0].EntryContext = LoadBalanceType; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, parametersKey, queryTable, parametersKey, NULL); if (NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDsmLBPolicyFromRegistry: LB Policy is %d.\n", *LoadBalanceType)); } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpQueryDsmLBPolicyFromRegistry: Failed to query LB policy. Status %x.\n", status)); goto __Exit_DsmpQueryDsmLBPolicyFromRegistry; } if (NT_SUCCESS(status)) { RtlInitUnicodeString(&keyValueName, DSM_PREFERRED_PATH); status = ZwQueryValueKey(parametersKey, &keyValueName, KeyValuePartialInformation, &preferredPath, sizeof(preferredPath), &length); if (NT_SUCCESS(status)) { NT_ASSERT(preferredPath.KeyValueInfo.DataLength == sizeof(ULONGLONG)); *PreferredPath = *((ULONGLONG UNALIGNED *)&(preferredPath.KeyValueInfo.Data)); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryDsmLBPolicyFromRegistry: PreferredPath is %I64x.\n", *PreferredPath)); } else { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpQueryDsmLBPolicyFromRegistry: Failed to query PreferredPath. Status %x.\n", status)); } } __Exit_DsmpQueryDsmLBPolicyFromRegistry: if (parametersKey) { ZwClose(parametersKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryDsmLBPolicyFromRegistry: Exiting function with status %x.\n", status)); return status; } NTSTATUS DsmpSetDsmLBPolicyInRegistry( _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONGLONG PreferredPath ) /*++ Routine Description: Set the overall load balance policy for MSDSM controlled devices in the registry. Note: If the policy specified is 0, remove the currently set values for policy and preferred path. Arguements: LoadBalanceType - Type of LB policy. PreferredPath - The preferred path for devices controlled by DSM. Return Value : STATUS_SUCCESS if we were able to successfully set the info in the registry. Appropriate NTSTATUS code on failure --*/ { HANDLE parametersKey = NULL; NTSTATUS status; UNICODE_STRING lbPolicyValueName; UNICODE_STRING preferredPathValueName; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetDsmLBPolicyInRegistry: Entering function.\n")); // // First open the Parameters key under the service key. // status = DsmpOpenDsmServicesParametersKey(KEY_ALL_ACCESS, ¶metersKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetDsmLBPolicyInRegistry: Failed to open Parameters key. Status %x.\n", status)); goto __Exit_DsmpSetDsmLBPolicyInRegistry; } RtlInitUnicodeString(&lbPolicyValueName, DSM_LOAD_BALANCE_POLICY); RtlInitUnicodeString(&preferredPathValueName, DSM_PREFERRED_PATH); // // If the LB policy is specified as 0, we need to delete the values. // if (LoadBalanceType < DSM_LB_FAILOVER) { status = ZwDeleteValueKey(parametersKey, &preferredPathValueName); if (NT_SUCCESS(status) || status == STATUS_OBJECT_NAME_NOT_FOUND) { status = ZwDeleteValueKey(parametersKey, &lbPolicyValueName); } if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetDsmLBPolicyInRegistry: Failed to delete either preferredPath or lbPolicy. Status %x.\n", status)); } } else { status = ZwSetValueKey(parametersKey, &lbPolicyValueName, 0, REG_DWORD, &LoadBalanceType, sizeof(ULONG)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetDsmLBPolicyInRegistry: Failed to set LB policy in registry. Status %x.\n", status)); goto __Exit_DsmpSetDsmLBPolicyInRegistry; } status = ZwSetValueKey(parametersKey, &preferredPathValueName, 0, REG_BINARY, &PreferredPath, sizeof(ULONGLONG)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetDsmLBPolicyInRegistry: Failed to set preferred path in registry. Status %x.\n", status)); } } __Exit_DsmpSetDsmLBPolicyInRegistry: if (parametersKey) { ZwClose(parametersKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetDsmLBPolicyInRegistry: Exiting function with status %x.\n", status)); return status; } NTSTATUS DsmpSetVidPidLBPolicyInRegistry( _In_ IN PWSTR TargetHardwareId, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _In_ IN ULONGLONG PreferredPath ) /*++ Routine Description: Set the default load balance policy for MSDSM controlled devices for a particular target VID/PID in the registry. Note: If the policy specified is 0, remove the subkey that matches the passed in TargetHardwareId. Arguements: TargetHardwareId - The VID/PID for which a default LB policy is being set. LoadBalanceType - Type of LB policy. PreferredPath - The preferred path for devices controlled by DSM. Return Value : STATUS_SUCCESS if we were able to successfully set the info in the registry. Appropriate NTSTATUS code on failure --*/ { HANDLE targetsLBSettingKey = NULL; HANDLE targetSubKey = NULL; NTSTATUS status; UNICODE_STRING vidPidKeyName; UNICODE_STRING lbPolicyValueName; UNICODE_STRING preferredPathValueName; OBJECT_ATTRIBUTES objectAttributes; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetVidPidLBPolicyInRegistry (%ws): Entering function.\n", TargetHardwareId)); // // First open the DsmTargetsLoadBalanceSetting key under the service's parameters key. // status = DsmpOpenTargetsLoadBalanceSettingKey(KEY_ALL_ACCESS, &targetsLBSettingKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to open Targets Policy settings key. Status %x.\n", TargetHardwareId, status)); goto __Exit_DsmpSetVidPidLBPolicyInRegistry; } RtlInitUnicodeString(&vidPidKeyName, TargetHardwareId); InitializeObjectAttributes(&objectAttributes, &vidPidKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), targetsLBSettingKey, (PSECURITY_DESCRIPTOR) NULL); // // If the LB policy is specified as 0, we need to delete the values. // if (LoadBalanceType < DSM_LB_FAILOVER) { // // Open the VID/PID key under DsmTargetsLoadBalanceSetting key. // status = ZwOpenKey(&targetSubKey, KEY_ALL_ACCESS, &objectAttributes); if (NT_SUCCESS(status)) { status = ZwDeleteKey(targetSubKey); } if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to either open or delete. Status %x.\n", TargetHardwareId, status)); } } else { RtlInitUnicodeString(&lbPolicyValueName, DSM_LOAD_BALANCE_POLICY); RtlInitUnicodeString(&preferredPathValueName, DSM_PREFERRED_PATH); status = ZwCreateKey(&targetSubKey, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to open/create key in registry. Status %x.\n", TargetHardwareId, status)); goto __Exit_DsmpSetVidPidLBPolicyInRegistry; } status = ZwSetValueKey(targetSubKey, &lbPolicyValueName, 0, REG_DWORD, &LoadBalanceType, sizeof(ULONG)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to set LB policy in registry. Status %x.\n", TargetHardwareId, status)); goto __Exit_DsmpSetVidPidLBPolicyInRegistry; } status = ZwSetValueKey(targetSubKey, &preferredPathValueName, 0, REG_BINARY, &PreferredPath, sizeof(ULONGLONG)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to set preferred path in registry. Status %x.\n", TargetHardwareId, status)); } } __Exit_DsmpSetVidPidLBPolicyInRegistry: if (targetSubKey) { ZwClose(targetSubKey); } if (targetsLBSettingKey) { ZwClose(targetsLBSettingKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpSetVidPidLBPolicyInRegistry (%ws): Exiting function with status %x.\n", TargetHardwareId, status)); return status; } NTSTATUS DsmpOpenLoadBalanceSettingsKey( _In_ IN ACCESS_MASK AccessMask, _Out_ OUT PHANDLE LoadBalanceSettingsKey ) /*++ Routine Description: Open the device key in the registry. NOTE: It is the responsibility of the caller to close the returned handle. Arguements: AccessMask - Requested access with which to open key LoadBalanceSettingsKey - handle of the key that is returned to the caller Return Value : STATUS_SUCCESS if we were able to successfully open the registry key. Appropriate NTSTATUS code on failure --*/ { HANDLE serviceKey = NULL; HANDLE parametersKey = NULL; PUNICODE_STRING registryPath = &(gDsmInitData.DsmWmiInfo.RegistryPath); OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING parametersKeyName; UNICODE_STRING subKeyName; NTSTATUS status = STATUS_UNSUCCESSFUL; PAGED_CODE(); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpOpenLoadBalanceSettingsKey (RegPath %p): Entering function.\n", registryPath)); *LoadBalanceSettingsKey = NULL; // // First check if registry path is available for msdsm. // if (!registryPath->Buffer) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenLoadBalanceSettingsKey (RegPath %p): Registry Path not set.\n", registryPath)); goto __Exit_DsmpOpenLoadBalanceSettingsKey; } // // Open the service key first // InitializeObjectAttributes(&objectAttributes, registryPath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); status = ZwOpenKey(&serviceKey, AccessMask, &objectAttributes); if (NT_SUCCESS(status)) { // // Open Parameters key under the Service key // RtlInitUnicodeString(¶metersKeyName, DSM_SERVICE_PARAMETERS); RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes(&objectAttributes, ¶metersKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), serviceKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey(¶metersKey, AccessMask, &objectAttributes); if (NT_SUCCESS(status)) { // // Open LoadBalanceSettings key under the Parameters key // RtlInitUnicodeString(&subKeyName, DSM_LOAD_BALANCE_SETTINGS); RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), parametersKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwCreateKey(LoadBalanceSettingsKey, AccessMask, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenLoadBalanceSettingsKey (RegPath %p): Failed to open/create LBSettings key. Status %x.\n", registryPath, status)); *LoadBalanceSettingsKey = NULL; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenLoadBalanceSettingsKey (RegPath %p): Failed to open parameters key. Status %x.\n", registryPath, status)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenLoadBalanceSettingsKey (RegPath %p): Failed to open service key %ws. Status %x.\n", registryPath, registryPath->Buffer, status)); } __Exit_DsmpOpenLoadBalanceSettingsKey: if (parametersKey) { ZwClose(parametersKey); } if (serviceKey) { ZwClose(serviceKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpOpenLoadBalanceSettingsKey (RegPath %p): Exiting function with status %x.\n", registryPath, status)); return status; } NTSTATUS DsmpOpenTargetsLoadBalanceSettingKey( _In_ IN ACCESS_MASK AccessMask, _Out_ OUT PHANDLE TargetsLoadBalanceSettingKey ) /*++ Routine Description: Open the target key in the registry. NOTE: It is the responsibility of the caller to close the returned handle. Arguements: AccessMask - Requested access with which to open key LoadBalanceSettingsKey - handle of the key that is returned to the caller Return Value : STATUS_SUCCESS if we were able to successfully open the registry key. Appropriate NTSTATUS code on failure --*/ { HANDLE serviceKey = NULL; HANDLE parametersKey = NULL; PUNICODE_STRING registryPath = &(gDsmInitData.DsmWmiInfo.RegistryPath); OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING parametersKeyName; UNICODE_STRING subKeyName; NTSTATUS status = STATUS_UNSUCCESSFUL; PAGED_CODE(); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Entering function.\n", registryPath)); if (!TargetsLoadBalanceSettingKey) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Invalid parameter.\n", registryPath)); status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpOpenTargetsLoadBalanceSettingKey; } *TargetsLoadBalanceSettingKey = NULL; // // First check if registry path is available for msdsm. // if (!registryPath->Buffer) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Registry Path not set.\n", registryPath)); goto __Exit_DsmpOpenTargetsLoadBalanceSettingKey; } // // Open the service key first // InitializeObjectAttributes(&objectAttributes, registryPath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); status = ZwOpenKey(&serviceKey, AccessMask, &objectAttributes); if (NT_SUCCESS(status)) { // // Open Parameters key under the Service key // RtlInitUnicodeString(¶metersKeyName, DSM_SERVICE_PARAMETERS); RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes(&objectAttributes, ¶metersKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), serviceKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey(¶metersKey, AccessMask, &objectAttributes); if (NT_SUCCESS(status)) { // // Open LoadBalanceSettings key under the Parameters key // RtlInitUnicodeString(&subKeyName, DSM_TARGETS_LOAD_BALANCE_SETTING); RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), parametersKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwCreateKey(TargetsLoadBalanceSettingKey, AccessMask, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Failed to open/create TargetsLBSetting key. Status %x.\n", registryPath, status)); *TargetsLoadBalanceSettingKey = NULL; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Failed to open parameters key. Status %x.\n", registryPath, status)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Failed to open service key %ws. Status %x.\n", registryPath, registryPath->Buffer, status)); } __Exit_DsmpOpenTargetsLoadBalanceSettingKey: if (parametersKey) { ZwClose(parametersKey); } if (serviceKey) { ZwClose(serviceKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Exiting function with status %x.\n", registryPath, status)); return status; } NTSTATUS DsmpOpenDsmServicesParametersKey( _In_ IN ACCESS_MASK AccessMask, _Out_ OUT PHANDLE ParametersKey ) /*++ Routine Description: Open the DSM's Parameters key in the registry. NOTE: It is the responsibility of the caller to close the returned handle. Arguements: AccessMask - Requested access with which to open key ParametersKey - handle of the key that is returned to the caller Return Value : STATUS_SUCCESS if we were able to successfully open the registry key. Appropriate NTSTATUS code on failure --*/ { HANDLE serviceKey = NULL; PUNICODE_STRING registryPath = &(gDsmInitData.DsmWmiInfo.RegistryPath); OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING parametersKeyName; NTSTATUS status = STATUS_UNSUCCESSFUL; PAGED_CODE(); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpOpenDsmServicesParametersKey (RegPath %p): Entering function.\n", registryPath)); if (!ParametersKey) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenDsmServicesParametersKey (RegPath %p): Invalid parameter.\n", registryPath)); status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpOpenDsmServicesParametersKey; } *ParametersKey = NULL; // // First check if registry path is available for msdsm. // if (!registryPath->Buffer) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenDsmServicesParametersKey (RegPath %p): Registry Path not set.\n", registryPath)); goto __Exit_DsmpOpenDsmServicesParametersKey; } // // Open the service key first // InitializeObjectAttributes(&objectAttributes, registryPath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); status = ZwOpenKey(&serviceKey, AccessMask, &objectAttributes); if (NT_SUCCESS(status)) { // // Open Parameters key under the Service key // RtlInitUnicodeString(¶metersKeyName, DSM_SERVICE_PARAMETERS); RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes(&objectAttributes, ¶metersKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), serviceKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey(ParametersKey, AccessMask, &objectAttributes); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenDsmServicesParametersKey (RegPath %p): Failed to open parameters key. Status %x.\n", registryPath, status)); *ParametersKey = NULL; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpOpenDsmServicesParametersKey (RegPath %p): Failed to open service key %ws. Status %x.\n", registryPath, registryPath->Buffer, status)); } __Exit_DsmpOpenDsmServicesParametersKey: if (serviceKey) { ZwClose(serviceKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpOpenDsmServicesParametersKey (RegPath %p): Exiting function with status %x.\n", registryPath, status)); return status; } NTSTATUS DsmpReportTargetPortGroupsSyncCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { UNREFERENCED_PARAMETER(DeviceObject); UNREFERENCED_PARAMETER(Context); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroupsSyncCompletion: IRP %p, Context %p\n", Irp, Context)); KeSetEvent(Irp->UserEvent, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } _Success_(return==0) NTSTATUS DsmpReportTargetPortGroups( _In_ PDEVICE_OBJECT DeviceObject, _Outptr_result_buffer_maybenull_(*TargetPortGroupsInfoLength) PUCHAR *TargetPortGroupsInfo, _Out_ PULONG TargetPortGroupsInfoLength ) /*++ Routine Description: Helper routine to send down ReportTargetPortGroups request synchronously. Used if device supports ALUA. Note: This routine will allocate memory for the TPG info. It is the responsibility of the caller to free this buffer, but only if the function returns STATUS_SUCCESS. Arguments: DeviceObject - The port PDO to which the command should be sent. TargetPortGroupsInfo - buffer containing the returned data. TargetPortGroupsInfoLength - size of the returned buffer. Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { PSPC3_CDB_REPORT_TARGET_PORT_GROUPS cdb; NTSTATUS status = STATUS_SUCCESS; PIRP irp = NULL; PMDL mdl = NULL; PSCSI_REQUEST_BLOCK srb = NULL; PSENSE_DATA_EX senseInfoBuffer = NULL; UCHAR senseInfoBufferLength = 0; KEVENT completionEvent; ULONG targetPortGroupsInfoLength = 0; PUCHAR targetPortGroupsInfo = NULL; PIO_STACK_LOCATION irpStack = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Entering function.\n", DeviceObject)); if (TargetPortGroupsInfoLength == NULL || TargetPortGroupsInfo == NULL) { status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpReportTargetPortGroups; } *TargetPortGroupsInfoLength = 0; *TargetPortGroupsInfo = NULL; senseInfoBuffer = (PSENSE_DATA_EX)DsmpAllocatePool(NonPagedPoolNx, SENSE_BUFFER_SIZE_EX, DSM_TAG_SCSI_SENSE_INFO); if (senseInfoBuffer != NULL) { senseInfoBufferLength = SENSE_BUFFER_SIZE_EX; srb = (PSCSI_REQUEST_BLOCK)DsmpAllocatePool(NonPagedPoolNx, sizeof(SCSI_REQUEST_BLOCK), DSM_TAG_SCSI_REQUEST_BLOCK); if (srb != NULL) { SrbSetSenseInfoBufferLength(srb, senseInfoBufferLength); SrbSetSenseInfoBuffer(srb, senseInfoBuffer); // // Take care of worst case scenario, which is: // 1. 4-byte header (for allocation length) // 2. 32 8-byte descriptors (for TPGs) // 3. Each descriptor containing 32 4-byte identifiers (for TPs in each TPG) // targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + (DSM_MAX_PATHS * (sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) + DSM_MAX_PATHS * sizeof(ULONG))); targetPortGroupsInfo = (PUCHAR)DsmpAllocatePool(NonPagedPoolNx, targetPortGroupsInfoLength, DSM_TAG_TARGET_PORT_GROUPS); if (targetPortGroupsInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Failed to allocate TPG info.\n", DeviceObject)); goto __Exit_DsmpReportTargetPortGroups; } } else { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Failed to allocate SRB.\n", DeviceObject)); goto __Exit_DsmpReportTargetPortGroups; } } else { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Failed to allocate Sense Info Buffer.\n", DeviceObject)); goto __Exit_DsmpReportTargetPortGroups; } irp = IoAllocateIrp(DeviceObject->StackSize + 1, FALSE); if (irp == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Failed to allocate IRP.\n", DeviceObject)); goto __Exit_DsmpReportTargetPortGroups; } mdl = IoAllocateMdl(targetPortGroupsInfo, targetPortGroupsInfoLength, FALSE, FALSE, irp); if (mdl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Failed to allocate MDL.\n", DeviceObject)); goto __Exit_DsmpReportTargetPortGroups; } MmBuildMdlForNonPagedPool(mdl); __Retry_DsmpReportTargetPortGroups: irp->MdlAddress = mdl; // // Set up SRB for execute scsi request. Save SRB address in next stack // for the port driver. // irpStack = IoGetNextIrpStackLocation(irp); irpStack->MajorFunction = IRP_MJ_SCSI; irpStack->MinorFunction = IRP_MN_SCSI_CLASS; irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srb; irpStack->DeviceObject = DeviceObject; // // Set the completion event and the completion routine. // KeInitializeEvent(&completionEvent, NotificationEvent, FALSE); irp->UserEvent = &completionEvent; IoSetCompletionRoutine(irp, DsmpReportTargetPortGroupsSyncCompletion, srb, TRUE, TRUE, TRUE); srb->Function = SRB_FUNCTION_EXECUTE_SCSI; srb->Length = sizeof(SCSI_REQUEST_BLOCK); SrbSetCdbLength(srb, sizeof(SPC3_CDB_REPORT_TARGET_PORT_GROUPS)); cdb = (PSPC3_CDB_REPORT_TARGET_PORT_GROUPS)SrbGetCdb(srb); cdb->OperationCode = SPC3_SCSIOP_REPORT_TARGET_PORT_GROUPS; cdb->ServiceAction = SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS; REVERSE_BYTES(&(cdb->AllocationLength), &targetPortGroupsInfoLength); SrbSetTimeOutValue(srb, SPC3_REPORT_TARGET_PORT_GROUPS_TIMEOUT); SrbSetDataTransferLength(srb, targetPortGroupsInfoLength); SrbSetDataBuffer(srb, targetPortGroupsInfo); srb->SrbStatus = 0; SrbSetScsiStatus(srb, 0); SrbSetNextSrb(srb, NULL); SrbSetSrbFlags(srb, SRB_FLAGS_DONT_START_NEXT_PACKET | SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE); SrbSetQueueAction(srb, SRB_HEAD_OF_QUEUE_TAG_REQUEST); SrbSetOriginalRequest(srb, irp); ObReferenceObject(DeviceObject); // // Finally, send the IRP down and wait for its completion. // status = IoCallDriver(DeviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&completionEvent, Executive, KernelMode, FALSE, NULL); status = irp->IoStatus.Status; } ObDereferenceObject(DeviceObject); if ((status == STATUS_BUFFER_OVERFLOW) || (NT_SUCCESS(status) && (SrbGetScsiStatus(srb) == SCSISTAT_GOOD))) { // // The first 4 bytes of the returned data are the Returned Data Length // field of the RTPG header. // ULONG returnedDataLength = 0; REVERSE_BYTES(&returnedDataLength, targetPortGroupsInfo); status = STATUS_SUCCESS; if (returnedDataLength > SrbGetDataTransferLength(srb)) { status = STATUS_BUFFER_OVERFLOW; } } if (NT_SUCCESS(status) && SrbGetScsiStatus(srb) == SCSISTAT_GOOD) { // // RTPG was successful so return the TPG info to the caller. // // // The first 4 bytes of the returned data are the Returned Data Length // field of the RTPG header. We need to return this value plus the header size. // ULONG returnedDataLength = 0; REVERSE_BYTES(&returnedDataLength, targetPortGroupsInfo); *TargetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + returnedDataLength; *TargetPortGroupsInfo = targetPortGroupsInfo; } else if (SrbGetScsiStatus(srb) == SCSISTAT_CHECK_CONDITION) { if (DsmpShouldRetryTPGRequest(senseInfoBuffer, senseInfoBufferLength)) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Retrying request.\n", DeviceObject)); IoReuseIrp(irp, STATUS_SUCCESS); RtlZeroMemory(senseInfoBuffer, senseInfoBufferLength); goto __Retry_DsmpReportTargetPortGroups; } if (DsmpIsDeviceRemoved(senseInfoBuffer, senseInfoBufferLength)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Device not available.\n", DeviceObject)); // // Sense key was illegal request. SPC 6.25 says response to TPG should follow Test Unit Ready responses // status = STATUS_NO_SUCH_DEVICE; } // RTPG was unsuccessful // Here it is possible that status is success, but scsi status is not. // and there was no RTPG retry. If so, set status to unsuccessful. if (NT_SUCCESS(status)) { status = STATUS_UNSUCCESSFUL; } // // TPG resulted HW to respond with Check Condition but Sense Key indicates it is not for retry or illegal request // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): TPG returned Check Condition, NTStatus 0x%x, ScsiStatus 0x%x.\n", DeviceObject, status, SrbGetScsiStatus(srb))); } else { // RTPG was unsuccessful // Here it is possible that status is success, but scsi status is not. // If so, set status to unsuccessful. if (NT_SUCCESS(status)) { status = STATUS_UNSUCCESSFUL; } TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): NTStatus 0x%x, ScsiStatus 0x%x.\n", DeviceObject, status, SrbGetScsiStatus(srb))); } __Exit_DsmpReportTargetPortGroups: // // The port driver may have allocated its own sense buffer so we need to // make sure we free that here. // if (srb != NULL && SrbGetSrbFlags(srb) & SRB_FLAGS_PORT_DRIVER_ALLOCSENSE && SrbGetSrbFlags(srb) & SRB_FLAGS_FREE_SENSE_BUFFER && SrbGetSenseInfoBuffer(srb) != NULL) { DsmpFreePool(SrbGetSenseInfoBuffer(srb)); } if (senseInfoBuffer) { DsmpFreePool(senseInfoBuffer); } if (srb) { DsmpFreePool(srb); } if (irp) { if (irp->MdlAddress) { IoFreeMdl(irp->MdlAddress); } IoFreeIrp(irp); } if (!NT_SUCCESS(status) && targetPortGroupsInfo) { DsmpFreePool(targetPortGroupsInfo); *TargetPortGroupsInfoLength = 0; *TargetPortGroupsInfo = NULL; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpReportTargetPortGroups (DevObj %p): Exiting function with status %x.\n", DeviceObject, status)); return status; } NTSTATUS DsmpReportTargetPortGroupsAsync( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN PIO_COMPLETION_ROUTINE CompletionRoutine, _Inout_ __drv_aliasesMem IN PDSM_TPG_COMPLETION_CONTEXT CompletionContext, _In_ IN ULONG TargetPortGroupsInfoLength, _Inout_ __drv_aliasesMem IN OUT PUCHAR TargetPortGroupsInfo ) /*++ Routine Description: Helper routine to send down ReportTargetPortGroups request asynchronously. Used if device supports ALUA. NOTE: Caller needs to free Irp, system buffer, and passThrough buffer. Arguments: DeviceInfo - The deviceInfo whose corresponding port PDO the command should be sent to. CompletionRoutine - completion routine passed in by the caller. CompletionContext - context to be passed to be completion routine. TargetPortGroupsInfoLength - size of the returned buffer. TargetPortGroupsInfo - preallocated (by caller) buffer that'll contain the returned data. Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { PDSM_TPG_COMPLETION_CONTEXT tpgCompletionContext = CompletionContext; PSCSI_REQUEST_BLOCK srb = NULL; PSPC3_CDB_REPORT_TARGET_PORT_GROUPS cdb; NTSTATUS status; PIRP irp = NULL; PIO_STACK_LOCATION irpStack; PMDL mdl = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpReportTargetPortGroupsAsync (DevInfo %p): Entering function.\n", DeviceInfo)); srb = tpgCompletionContext->Srb; SrbZeroSrb(srb); // // Allocate an irp. // irp = IoAllocateIrp(DeviceInfo->TargetObject->StackSize + 1, FALSE); if (!irp) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpReportTargetPortGroupsAsync (DevInfo %p): Failed to allocate IRP.\n", DeviceInfo)); goto __Exit_DsmpReportTargetPortGroupsAsync; } mdl = IoAllocateMdl(TargetPortGroupsInfo, TargetPortGroupsInfoLength, FALSE, FALSE, irp); if (!mdl) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpReportTargetPortGroupsAsync (DevInfo %p): Failed to allocate MDL.\n", DeviceInfo)); goto __Exit_DsmpReportTargetPortGroupsAsync; } MmBuildMdlForNonPagedPool(irp->MdlAddress); // // It is possible that if an implicit access state transition took place, // each I_T nexus will return UA for asymmetric access state changed. So // set the number of retries to be one more than the total number of paths. // Worst case scenario is the it is sent down each path once (assuming every // is a different I_T nexus) and then one more for a retry one one of the // paths. // tpgCompletionContext->NumberRetries = DeviceInfo->Group->NumberDevices + 1; // // Set-up the completion routine. // IoSetCompletionRoutine(irp, CompletionRoutine, (PVOID)CompletionContext, TRUE, TRUE, TRUE); // // Get the recipient's irpstack location. // irpStack = IoGetNextIrpStackLocation(irp); irpStack->Parameters.Scsi.Srb = srb; irpStack->DeviceObject = DeviceInfo->TargetObject; // // Set the major function code to IRP_MJ_SCSI. // irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; // // Set the minor function, or many requests will get kicked by by port. // irpStack->MinorFunction = IRP_MN_SCSI_CLASS; srb->Function = SRB_FUNCTION_EXECUTE_SCSI; srb->Length = sizeof(SCSI_REQUEST_BLOCK); SrbSetCdbLength(srb, sizeof(SPC3_CDB_REPORT_TARGET_PORT_GROUPS)); cdb = (PSPC3_CDB_REPORT_TARGET_PORT_GROUPS)SrbGetCdb(srb); cdb->OperationCode = SPC3_SCSIOP_REPORT_TARGET_PORT_GROUPS; cdb->ServiceAction = SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS; Get4ByteArrayFromUlong(TargetPortGroupsInfoLength, cdb->AllocationLength); SrbSetTimeOutValue(srb, SPC3_REPORT_TARGET_PORT_GROUPS_TIMEOUT); SrbSetSenseInfoBuffer(srb, tpgCompletionContext->SenseInfoBuffer); SrbSetSenseInfoBufferLength(srb, tpgCompletionContext->SenseInfoBufferLength); SrbSetDataTransferLength(srb, TargetPortGroupsInfoLength); SrbSetDataBuffer(srb, TargetPortGroupsInfo); srb->SrbStatus = 0; SrbSetScsiStatus(srb, 0); SrbSetNextSrb(srb, NULL); SrbSetSrbFlags(srb, SRB_FLAGS_DONT_START_NEXT_PACKET | SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE); SrbSetQueueAction(srb, SRB_HEAD_OF_QUEUE_TAG_REQUEST); SrbSetOriginalRequest(srb, irp); irp->UserBuffer = TargetPortGroupsInfo; irp->Tail.Overlay.Thread = PsGetCurrentThread(); // // Send the IRP asynchronously // DsmSendRequestEx(((PDSM_CONTEXT)(DeviceInfo->DsmContext))->MPIOContext, DeviceInfo->TargetObject, irp, (PVOID)DeviceInfo, DSM_CALL_COMPLETION_ON_MPIO_ERROR); // // We know that the completion routine will always be called. // status = STATUS_PENDING; __Exit_DsmpReportTargetPortGroupsAsync: if (status != STATUS_PENDING) { // // This indicates Irp was never sent down to stack (completion routine was never called). // We need to clean up. // if (irp) { if (irp->MdlAddress) { IoFreeMdl(irp->MdlAddress); } IoFreeIrp(irp); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpReportTargetPortGroupsAsync (DevInfo %p): Exiting function with status %x\n.", DeviceInfo, status)); return status; } NTSTATUS DsmpQueryLBPolicyForDevice( _In_ IN PWSTR RegistryKeyName, _In_ IN ULONGLONG PathId, _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType, _Out_ OUT PULONG PrimaryPath, _Out_ OUT PULONG OptimizedPath, _Out_ OUT PULONG PathWeight ) /*++ Routine Description: This routine opens the device's registry subkey, builds the path subkey from the passed in PathId, then queries that subkey for the value of PrimaryPath, OptimizedPath and PathWeight. Arguments: RegistryKeyName - The device's registry subkey name. PathId - The pathId for this instance of the device. LoadBalanceType - The current load balance policy. PrimaryPath - Output of the queried PrimaryPath value. OptimizedPath - Output of the queried OptimizedPath value. PathWeight - Output of the queried PathWeight value. Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { HANDLE lbSettingsKey = NULL; HANDLE deviceKey = NULL; HANDLE dsmPathKey = NULL; UNICODE_STRING subKeyName; WCHAR dsmPathName[128] = {0}; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status; NTSTATUS pathWeightQueryStatus = STATUS_SUCCESS; PAGED_CODE(); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Entering function.\n", RegistryKeyName)); // // Query PrimaryPath and PathWeight for the given path. // These values are stored under DsmPath#Suffix key for // this path. If this key doesn't exist create it and // create PrimaryPath and PathWeight values - use the // values passed in PrimaryPath and PathWeight in this case. // status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Failed to open LB Settings key. Status %x.\n", RegistryKeyName, status)); goto __Exit_DsmpQueryLBPolicyForDevice; } RtlInitUnicodeString(&subKeyName, RegistryKeyName); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), lbSettingsKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes); if (NT_SUCCESS(status)) { // // Create or open DsmPath#Suffix key for this path // DsmpGetDSMPathKeyName(PathId, dsmPathName, 128); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Will query %ws for PrimaryPath, OptimizedPath and PathWeight.\n", RegistryKeyName, dsmPathName)); RtlInitUnicodeString(&subKeyName, dsmPathName); RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), deviceKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwCreateKey(&dsmPathKey, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (NT_SUCCESS(status)) { RTL_QUERY_REGISTRY_TABLE queryTable[2]; // // Query the Path Weight value. // RtlZeroMemory(queryTable, sizeof(queryTable)); queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_PATH_WEIGHT; queryTable[0].EntryContext = PathWeight; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; pathWeightQueryStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, dsmPathKey, queryTable, dsmPathKey, NULL); if (!NT_SUCCESS(pathWeightQueryStatus)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Failed to query PathWeight. Status %x.\n", RegistryKeyName, pathWeightQueryStatus)); } // // Query the Primary Path value. // RtlZeroMemory(queryTable, sizeof(queryTable)); queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_PRIMARY_PATH; queryTable[0].EntryContext = PrimaryPath; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, dsmPathKey, queryTable, dsmPathKey, NULL); if (NT_SUCCESS(status)) { // // Query the Optimized Path value. // RtlZeroMemory(queryTable, sizeof(queryTable)); queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_OPTIMIZED_PATH; queryTable[0].EntryContext = OptimizedPath; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, dsmPathKey, queryTable, dsmPathKey, NULL); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Failed to query OptimizedPath. Status %x.\n", RegistryKeyName, status)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Failed to query PrimaryPath. Status %x.\n", RegistryKeyName, status)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Failed to create DSM Path key %ws. Status %x.\n", RegistryKeyName, dsmPathName, status)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Failed to open key. Status %x.\n", RegistryKeyName, status)); } if (NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): PrimaryPath %d, OptmizedPath %d, PathWeight %d.\n", RegistryKeyName, *PrimaryPath, *OptimizedPath, *PathWeight)); } __Exit_DsmpQueryLBPolicyForDevice: if (dsmPathKey) { ZwClose(dsmPathKey); } if (deviceKey) { ZwClose(deviceKey); } if (lbSettingsKey) { ZwClose(lbSettingsKey); } // // If the load balance policy is Weighted Paths and we failed to read in // the path weight value, we need to return the failure status from the // path weight value query. // if (LoadBalanceType == DSM_LB_WEIGHTED_PATHS && !NT_SUCCESS(pathWeightQueryStatus)) { status = pathWeightQueryStatus; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryLBPolicyForDevice (DevName %ws): Exiting function with status %x.\n", RegistryKeyName, status)); return status; } VOID DsmpGetDSMPathKeyName( _In_ ULONGLONG DSMPathId, _Out_writes_(DsmPathKeyNameSize) PWCHAR DsmPathKeyName, _In_ ULONG DsmPathKeyNameSize ) /*++ Routine Description: This routine builds the string that corresponds to the device's Path subkey name in the registry. Arguments: DSMPathId - The pathId of this instance of the device. DsmPathKeyName - Output buffer in which the subkey name for path is returned. DsmPathKeyNameSize - size of the output buffer in WCHARs. Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { PWCHAR pathPtr; SIZE_T wcharsLeft; SIZE_T size; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetDSMPathKeyName (PathId %I64x): Entering function.\n", DSMPathId)); // // This routine will build a name for a given DSM Path. // The name is of the format DsmPath#Suffix, where Suffix // is derived from the PathId // pathPtr = DsmPathKeyName; wcharsLeft = DsmPathKeyNameSize; size = wcslen(DSM_PATH); if (size < wcharsLeft) { // // First copy the string DsmPath# // if (NT_SUCCESS(RtlStringCchCopyNW(pathPtr, wcharsLeft, DSM_PATH, wcslen(DSM_PATH)))) { wcharsLeft -= size; pathPtr += size; if (wcharsLeft > 2) { RtlStringCchCatW(pathPtr, wcharsLeft, L"#"); wcharsLeft--; pathPtr++; // // Each nibble in the path id would need 1 WCHAR // upon conversion to WCHAR string. So we'll need // 2 WCHARs for each byte. Include the NULL char also // size = (sizeof(PVOID) + 1) * 2; if (size <= wcharsLeft) { PVOID pathId; PUCHAR pathIdPtr; ULONG inx; UCHAR tmpChar; // // Convert the ULONGLONG path id to a string and // append that to DsmPath# // pathId = (PVOID) DSMPathId; pathIdPtr = (PUCHAR) &pathId; for (inx = 0; inx < sizeof(PVOID); inx++) { tmpChar = (*pathIdPtr & 0xF0) >> 4; *pathPtr++ = DsmpGetAsciiForBinary(tmpChar); tmpChar = (*pathIdPtr & 0x0F); *pathPtr++ = DsmpGetAsciiForBinary(tmpChar); pathIdPtr++; } *pathPtr = WNULL; } } } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetDSMPathKeyName (PathId %I64x): Exiting function.\n", DSMPathId)); return; } UCHAR DsmpGetAsciiForBinary( _In_ UCHAR BinaryChar ) /*++ Routine Description: This routine converts the passed in binary value into ASCII equivalent. Arguments: BinaryChar - The binary value that needs to be converted. Return Value: Corresponding ASCII value. --*/ { UCHAR outChar = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpGetAsciiForBinary (BinaryChar %d): Entering function.\n", BinaryChar)); // // Convert a binary nibble into an ASCII character. // if ((BinaryChar >= 0) && (BinaryChar <= 9)) { outChar = BinaryChar + '0'; } else { outChar = BinaryChar + 'A' - 10; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpGetAsciiForBinary (BinaryChar %d): Exiting function with outChar %c.\n", BinaryChar, outChar)); return outChar; } NTSTATUS DsmpGetDeviceIdList( _In_ IN PDEVICE_OBJECT DeviceObject, _Out_ OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor ) /*++ Routine Description: This routine will perform a query for the StorageDeviceIdProperty and will allocate a non-paged buffer to store the data in. IMPORTANT: It is the responsibility of the caller to ensure that this buffer is freed. Arguments: DeviceObject - the device to query Descriptor - a location to store a pointer to the buffer we allocate Return Value: status. --*/ { STORAGE_PROPERTY_QUERY query; PIO_STATUS_BLOCK ioStatus = NULL; PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL; ULONG length; NTSTATUS status = STATUS_UNSUCCESSFUL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetDeviceIdList (DevObj %p): Entering function.\n", DeviceObject)); if (!DeviceObject) { status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpGetDeviceIdList; } // // Poison the passed in descriptor. // *Descriptor = NULL; // // Setup the query buffer. // query.PropertyId = StorageDeviceIdProperty; query.QueryType = PropertyStandardQuery; query.AdditionalParameters[0] = 0; ioStatus = DsmpAllocatePool(NonPagedPoolNx, sizeof(IO_STATUS_BLOCK), DSM_TAG_IO_STATUS_BLOCK); if (!ioStatus) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetDeviceIdList (DevObj %p): Failed to allocate an IO_STATUS_BLOCK.\n", DeviceObject)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpGetDeviceIdList; } ioStatus->Status = 0; ioStatus->Information = 0; // // On the first call, just need to get the length of the descriptor. // descriptor = (PVOID)&query; DsmSendDeviceIoControlSynchronous(IOCTL_STORAGE_QUERY_PROPERTY, DeviceObject, &query, &query, sizeof(STORAGE_PROPERTY_QUERY), sizeof(STORAGE_DESCRIPTOR_HEADER), FALSE, ioStatus); status = ioStatus->Status; if(!NT_SUCCESS(status)) { descriptor = NULL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetDeviceIdList (DevObj %p): Query failed (%x) on attempt 1.\n", DeviceObject, ioStatus->Status)); goto __Exit_DsmpGetDeviceIdList; } NT_ASSERT(descriptor->Size); if (descriptor->Size == 0) { status = STATUS_UNSUCCESSFUL; goto __Exit_DsmpGetDeviceIdList; } // // This time we know how much data there is so we can // allocate a buffer of the correct size // length = descriptor->Size; descriptor = DsmpAllocatePool(NonPagedPoolNx, length, DSM_TAG_DEVICE_ID_LIST); if(!descriptor) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetDeviceIdList (DevObj %p): Couldn't allocate descriptor of %ld.\n", DeviceObject, length)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpGetDeviceIdList; } // // setup the query again. // query.PropertyId = StorageDeviceIdProperty; query.QueryType = PropertyStandardQuery; query.AdditionalParameters[0] = 0; // // copy the input to the new outputbuffer // RtlCopyMemory(descriptor, &query, sizeof(STORAGE_PROPERTY_QUERY)); DsmSendDeviceIoControlSynchronous(IOCTL_STORAGE_QUERY_PROPERTY, DeviceObject, descriptor, descriptor, sizeof(STORAGE_PROPERTY_QUERY), length, 0, ioStatus); status = ioStatus->Status; if(!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpGetDeviceIdList (DevObj %p): Query Failed (%x) on attempt 2.\n", DeviceObject, ioStatus->Status)); goto __Exit_DsmpGetDeviceIdList; } __Exit_DsmpGetDeviceIdList: if (ioStatus) { DsmpFreePool(ioStatus); } if (!NT_SUCCESS(status)) { if (descriptor) { DsmpFreePool(descriptor); } } else { *Descriptor = descriptor; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetDeviceIdList (DevObj %p): Exiting function with status %x.\n", DeviceObject, status)); return status; } NTSTATUS DsmpSetTargetPortGroups( _In_ IN PDEVICE_OBJECT DeviceObject, _In_reads_bytes_(TargetPortGroupsInfoLength) IN PUCHAR TargetPortGroupsInfo, _In_ IN ULONG TargetPortGroupsInfoLength ) /*++ Routine Description: Helper routine to send down SetTargetPortGroups request. Arguments: DeviceObject - The port PDO to which the command should be sent. TargetPortGroupsInfo - buffer containing the TPG data. TargetPortGroupsInfoLength - size of the TPG buffer. Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { NTSTATUS status = STATUS_SUCCESS; SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER passThrough; PSPC3_CDB_SET_TARGET_PORT_GROUPS cdb; IO_STATUS_BLOCK ioStatus; ULONG alignmentMask = DeviceObject->AlignmentRequirement; PUCHAR dataBuffer = NULL; SIZE_T allocatedLength = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpSetTargetPortGroups (DevObj %p): Entering function.\n", DeviceObject)); NT_ASSERT(TargetPortGroupsInfoLength && TargetPortGroupsInfo); // // Build request. // RtlZeroMemory(&passThrough, sizeof(passThrough)); dataBuffer = DsmpAllocateAlignedPool(NonPagedPoolNx, TargetPortGroupsInfoLength, alignmentMask, DSM_TAG_PASS_THRU, &allocatedLength); if (!dataBuffer) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpSetTargetPortGroups (DevObj %p): Failed to allocate mem for passthrough's databuffer.\n", DeviceObject)); goto __Exit_DsmpSetTargetPortGroups; } __Retry_Request: // // Build the cdb. // cdb = (PSPC3_CDB_SET_TARGET_PORT_GROUPS)passThrough.ScsiPassThroughDirect.Cdb; cdb->OperationCode = SPC3_SCSIOP_SET_TARGET_PORT_GROUPS; cdb->ServiceAction = SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS; Get4ByteArrayFromUlong(TargetPortGroupsInfoLength, cdb->ParameterListLength); passThrough.ScsiPassThroughDirect.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); passThrough.ScsiPassThroughDirect.CdbLength = 12; passThrough.ScsiPassThroughDirect.SenseInfoLength = SPTWB_SENSE_LENGTH; passThrough.ScsiPassThroughDirect.DataIn = 0; passThrough.ScsiPassThroughDirect.DataTransferLength = TargetPortGroupsInfoLength; passThrough.ScsiPassThroughDirect.TimeOutValue = 20; passThrough.ScsiPassThroughDirect.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseInfoBuffer); passThrough.ScsiPassThroughDirect.DataBuffer = dataBuffer; RtlCopyMemory(dataBuffer, TargetPortGroupsInfo, TargetPortGroupsInfoLength); DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH_DIRECT, DeviceObject, &passThrough, &passThrough, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), FALSE, &ioStatus); if ((passThrough.ScsiPassThroughDirect.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(ioStatus.Status))) { status = STATUS_SUCCESS; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpSetTargetPortGroups (DevObj %p): STPG succeeded.\n", DeviceObject)); } else if (NT_SUCCESS(ioStatus.Status) && passThrough.ScsiPassThroughDirect.ScsiStatus == SCSISTAT_CHECK_CONDITION && DsmpShouldRetryTPGRequest((PSENSE_DATA)&passThrough.SenseInfoBuffer, passThrough.ScsiPassThroughDirect.SenseInfoLength)) { // // Retry the request // RtlZeroMemory(dataBuffer, TargetPortGroupsInfoLength); goto __Retry_Request; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpSetTargetPortGroups (DevObj %p): NTStatus 0%x, ScsiStatus 0x%x.\n", DeviceObject, ioStatus.Status, passThrough.ScsiPassThroughDirect.ScsiStatus)); status = ioStatus.Status; } __Exit_DsmpSetTargetPortGroups: // // Free the passthrough + data buffer. // if (dataBuffer) { DsmpFreePool(dataBuffer); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpSetTargetPortGroups (DevObj %p): Exiting function with status %x.\n", DeviceObject, status)); return status; } NTSTATUS DsmpSetTargetPortGroupsAsync( _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN PIO_COMPLETION_ROUTINE CompletionRoutine, _In_ __drv_aliasesMem IN PDSM_TPG_COMPLETION_CONTEXT CompletionContext, _In_ IN ULONG TargetPortGroupsInfoLength, _In_ __drv_aliasesMem IN PUCHAR TargetPortGroupsInfo ) /*++ Routine Description: Helper routine to send down SetTargetPortGroups request asynchronously. IMPORTANT: Caller needs to free the IRP and allocated system buffer. Arguments: DeviceInfo - The deviceInfo whose corresponding port PDO the command should be sent to. CompletionRoutine - completion routine provided by the caller. CompletionContext - context passed into the completion routine. TargetPortGroupsInfoLength - size of the TPG buffer. TargetPortGroupsInfo - buffer containing the TPG data. Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { PDSM_TPG_COMPLETION_CONTEXT tpgCompletionContext = CompletionContext; PSCSI_REQUEST_BLOCK srb; PSPC3_CDB_SET_TARGET_PORT_GROUPS cdb; NTSTATUS status; PIRP irp = NULL; PIO_STACK_LOCATION irpStack; PMDL mdl = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpSetTargetPortGroupsAsync (DevInfo %p): Entering function.\n", DeviceInfo)); srb = tpgCompletionContext->Srb; SrbZeroSrb(srb); // // Allocate an irp. // irp = IoAllocateIrp(DeviceInfo->TargetObject->StackSize + 1, FALSE); if (!irp) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetTargetPortGroupsAsync (DevInfo %p): Failed to allocate IRP.\n", DeviceInfo)); goto __Exit_DsmpSetTargetPortGroupsAsync; } mdl = IoAllocateMdl(TargetPortGroupsInfo, TargetPortGroupsInfoLength, FALSE, FALSE, irp); if (!mdl) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "DsmpSetTargetPortGroupsAsync (DevInfo %p): Failed to allocate MDL.\n", DeviceInfo)); goto __Exit_DsmpSetTargetPortGroupsAsync; } MmBuildMdlForNonPagedPool(irp->MdlAddress); // // It is possible that an implicit state transition may have occurred which // will cause every I_T nexus to return an UA (for asymmetric access state // changed). So set the number of retries to number of paths (worst case of // every path being a separate I_T nexus) plus one for a retry down one of // paths. // tpgCompletionContext->NumberRetries = DeviceInfo->Group->NumberDevices + 1; // // Set-up the completion routine. // IoSetCompletionRoutine(irp, CompletionRoutine, (PVOID)CompletionContext, TRUE, TRUE, TRUE); // // Get the recipient's irpstack location. // irpStack = IoGetNextIrpStackLocation(irp); irpStack->Parameters.Scsi.Srb = srb; irpStack->DeviceObject = DeviceInfo->TargetObject; // // Set the major function code to IRP_MJ_SCSI. // irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; // // Set the minor function, or many requests will get kicked by by port. // irpStack->MinorFunction = IRP_MN_SCSI_CLASS; srb->Function = SRB_FUNCTION_EXECUTE_SCSI; srb->Length = sizeof(SCSI_REQUEST_BLOCK); SrbSetCdbLength(srb, sizeof(SPC3_CDB_SET_TARGET_PORT_GROUPS)); cdb = (PSPC3_CDB_SET_TARGET_PORT_GROUPS)SrbGetCdb(srb); cdb->OperationCode = SPC3_SCSIOP_SET_TARGET_PORT_GROUPS; cdb->ServiceAction = SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS; Get4ByteArrayFromUlong(TargetPortGroupsInfoLength, cdb->ParameterListLength); SrbSetTimeOutValue(srb, SPC3_SET_TARGET_PORT_GROUPS_TIMEOUT); SrbSetSenseInfoBuffer(srb, tpgCompletionContext->SenseInfoBuffer); SrbSetSenseInfoBufferLength(srb, tpgCompletionContext->SenseInfoBufferLength); SrbSetDataTransferLength(srb, TargetPortGroupsInfoLength); SrbSetDataBuffer(srb, TargetPortGroupsInfo); srb->SrbStatus = 0; SrbSetScsiStatus(srb, 0); SrbSetNextSrb(srb, NULL); SrbSetSrbFlags(srb, SRB_FLAGS_DONT_START_NEXT_PACKET | SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE); SrbSetQueueAction(srb, SRB_HEAD_OF_QUEUE_TAG_REQUEST); SrbSetOriginalRequest(srb, irp); irp->UserBuffer = TargetPortGroupsInfo; irp->Tail.Overlay.Thread = PsGetCurrentThread(); // // Send the IRP asynchronously // DsmSendRequestEx(((PDSM_CONTEXT)(DeviceInfo->DsmContext))->MPIOContext, DeviceInfo->TargetObject, irp, DeviceInfo, DSM_CALL_COMPLETION_ON_MPIO_ERROR); // // We know that the completion routine will always be called. // status = STATUS_PENDING; __Exit_DsmpSetTargetPortGroupsAsync: if (status != STATUS_PENDING) { // // This indicates Irp was never sent down to stack (completion routine was never called). // We need to clean up. // if (irp) { if (irp->MdlAddress) { IoFreeMdl(irp->MdlAddress); } IoFreeIrp(irp); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_RW, "DsmpSetTargetPortGroupsAsync (DevInfo %p): Exiting function with status %x.\n", DeviceInfo, status)); return status; } PDSM_LOAD_BALANCE_POLICY_SETTINGS DsmpCopyLoadBalancePolicies( _In_ IN PDSM_GROUP_ENTRY GroupEntry, _In_ IN ULONG DsmWmiVersion, _In_ IN PVOID SupportedLBPolicies ) /*+++ Routine Description: This routine copies the LB Policies that needs to be persisted in registry. This is done because registry routines can be called at PASSIVE IRQL only. So a spinlock cannot be held while accessing registry. So hold a spinlock, save the values in a temp buffer, release spinlock, and save data to registry from the temp buffer. NOTE: This routine MUST be called with DSM_CONTEXT lock held. Arguements: GroupEntry - Group entry DsmWmiVersion - version of the MPIO_DSM_Path class to use SupportedLBPolicies - LB policy for the group Return Value: Pointer to LOAD_BALANCE_POLICY_SETTINGS if successful. Else, NULL --*/ { PDSM_LOAD_BALANCE_POLICY_SETTINGS lbSettings = NULL; ULONG sizeNeeded; ULONG inx; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpCopyLoadBalancePolicies (Group %p): Entering function.\n", GroupEntry)); if (((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount == 0) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpCopyLoadBalancePolicies (Group %p): No paths specified in Set LB policies.\n", GroupEntry)); goto __Exit_DsmpCopyLoadBalancePolicies; } sizeNeeded = sizeof(DSM_LOAD_BALANCE_POLICY_SETTINGS) + ((((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount - 1) * sizeof(MPIO_DSM_Path_V2));; lbSettings = DsmpAllocatePool(NonPagedPoolNx, sizeNeeded, DSM_TAG_LB_POLICY); if (!lbSettings) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpCopyLoadBalancePolicies (Group %p): Failed to allocate memory for LBSettings.\n", GroupEntry)); goto __Exit_DsmpCopyLoadBalancePolicies; } // // Copy the registry key name used to store the LB policies. // RtlStringCchCopyNW(lbSettings->RegistryKeyName, sizeof(lbSettings->RegistryKeyName) / sizeof(lbSettings->RegistryKeyName[0]), GroupEntry->RegistryKeyName, ((sizeof(lbSettings->RegistryKeyName) - sizeof(WCHAR))/sizeof(WCHAR))); // // Copy the Load Balance settings for this group // lbSettings->LoadBalancePolicy = ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->LoadBalancePolicy; lbSettings->PathCount = ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount; for (inx = 0; inx < ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount; inx++) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { RtlCopyMemory(&(lbSettings->DsmPath[inx]), &(((PDSM_Load_Balance_Policy)SupportedLBPolicies)->DSM_Paths[inx]), sizeof(MPIO_DSM_Path)); // // DSM_WMI_VERSION_1 supports only active and standby states // (lbSettings->DsmPath[inx]).OptimizedPath = TRUE; } else { RtlCopyMemory(&(lbSettings->DsmPath[inx]), &(((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSM_Paths[inx]), sizeof(MPIO_DSM_Path_V2)); } } __Exit_DsmpCopyLoadBalancePolicies: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpCopyLoadBalancePolicies (Group %p): Exiting function with lbSettings %p.\n", GroupEntry, lbSettings)); return lbSettings; } NTSTATUS DsmpPersistLBSettings( _In_ IN PDSM_LOAD_BALANCE_POLICY_SETTINGS LoadBalanceSettings ) /*+++ Routine Description: This routine will save the Load Balance settings from LoadBalanceSettings to registry. NOTE: This routine MUST be called at PASSIVE IRQL The format of the registry tree is : Services\MSDSM\LoadBalanceSettings -> DeviceName -> LoadBalancePolicy REG_DWORD DsmPath#Suffix -> PrimaryPath REG_DWORD OptimizedPath REG_DWORD PathWeight REG_DWORD The device name is the one built in DsmpBuildDeviceName The Suffix in DsmPath#Suffix is built from the PathId. It is built in the routine DsmpGetDSMPathKeyName. Arguements: LoadBalanceSettings - Load Balance settings to be persisted in registry Return Value: STATUS_SUCCESS if the data could be successfully stored in the registry Appropriate NT Status code on failure. --*/ { PMPIO_DSM_Path_V2 dsmPath; HANDLE lbSettingsKey = NULL; HANDLE deviceKey = NULL; HANDLE dsmPathKey = NULL; UNICODE_STRING subKeyName; WCHAR dsmPathName[128]; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status; ULONG inx; PMPIO_DSM_Path_V2 preferredPath = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Entering function.\n", LoadBalanceSettings->RegistryKeyName)); // // First open LoadBalanceSettings key under the Service key // status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Failed to open LB Settings key. Status %x.\n", LoadBalanceSettings->RegistryKeyName, status)); goto __Exit_DsmpPersistLBSettings; } // // Now open the key under which the LB settings for the given device is stored // RtlInitUnicodeString(&subKeyName, LoadBalanceSettings->RegistryKeyName); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), lbSettingsKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes); if (NT_SUCCESS(status)) { // // Remove all LB policy information as we are going to rewrite it. // We do this in case there is stale information about a path that // no longer exists // status = DsmpRegDeleteTree(deviceKey); if (NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Deleted key along with its subkeys.\n", LoadBalanceSettings->RegistryKeyName)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Failed to delete key. Status %x\n", LoadBalanceSettings->RegistryKeyName, status)); } ZwClose(deviceKey); deviceKey = NULL; } status = ZwCreateKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (NT_SUCCESS(status)) { PDSM_DEVICE_INFO devInfo; for (inx = 0; inx < LoadBalanceSettings->PathCount; inx++) { dsmPath = &(LoadBalanceSettings->DsmPath[inx]); if (dsmPath->DsmPathId == 0) { continue; } RtlZeroMemory(dsmPathName, sizeof(dsmPathName)); // // Get the sub key name under which the LB settings for // the given path is stored. // DsmpGetDSMPathKeyName(dsmPath->DsmPathId, dsmPathName, 128); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Will open subkey %ws.\n", LoadBalanceSettings->RegistryKeyName, dsmPathName)); RtlInitUnicodeString(&subKeyName, dsmPathName); RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), deviceKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwCreateKey(&dsmPathKey, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (NT_SUCCESS(status)) { if (dsmPath->PreferredPath) { preferredPath = dsmPath; } devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved; // // Save PrimaryPath, PathWeight and OptimizedPath values for this path // if (devInfo->DesiredState != DSM_DEV_UNDETERMINED) { status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, dsmPathKey, DSM_PRIMARY_PATH, REG_DWORD, &(dsmPath->PrimaryPath), sizeof(ULONG)); if (NT_SUCCESS(status)) { status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, dsmPathKey, DSM_OPTIMIZED_PATH, REG_DWORD, &(dsmPath->OptimizedPath), sizeof(ULONG)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Failed to save OptimizedPath. Status %x.\n", LoadBalanceSettings->RegistryKeyName, status)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Failed to save Primary Path. Status %x.\n", LoadBalanceSettings->RegistryKeyName, status)); } } if (NT_SUCCESS(status)) { if (LoadBalanceSettings->LoadBalancePolicy == DSM_LB_WEIGHTED_PATHS) { status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, dsmPathKey, DSM_PATH_WEIGHT, REG_DWORD, &(dsmPath->PathWeight), sizeof(ULONG)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Failed to save PathWeight. Status %x.\n", LoadBalanceSettings->RegistryKeyName, status)); } } } ZwClose(dsmPathKey); dsmPathKey = NULL; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Failed to open DSM Path key. Status %x.\n", LoadBalanceSettings->RegistryKeyName, status)); } if (!NT_SUCCESS(status)) { break; } } if (NT_SUCCESS(status)) { // // Save the new Load Balance Policy value, // status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, deviceKey, DSM_LOAD_BALANCE_POLICY, REG_DWORD, &(LoadBalanceSettings->LoadBalancePolicy), sizeof(ULONG)); if (NT_SUCCESS(status)) { UCHAR explicitlySet = TRUE; // // Write out that the policy has been explicitly set // status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, deviceKey, DSM_POLICY_EXPLICITLY_SET, REG_BINARY, &explicitlySet, sizeof(UCHAR)); if (NT_SUCCESS(status)) { // // If FailOver-Only policy, set the PreferredPath, if specified // if (preferredPath) { status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, deviceKey, DSM_PREFERRED_PATH, REG_BINARY, &(preferredPath->DsmPathId), sizeof(ULONGLONG)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Failed to save LB Settings (ES).\n", LoadBalanceSettings->RegistryKeyName)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Failed to save LB Settings (LBP).\n", LoadBalanceSettings->RegistryKeyName)); } } } __Exit_DsmpPersistLBSettings: if (dsmPathKey) { ZwClose(dsmPathKey); } if (deviceKey) { ZwClose(deviceKey); } if (lbSettingsKey) { ZwClose(lbSettingsKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpPersistLBSettings (DevName %ws): Exiting function with status %x.\n", LoadBalanceSettings->RegistryKeyName, status)); return status; } NTSTATUS DsmpSetDeviceALUAState( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_ IN DSM_DEVICE_STATE DevState ) /*++ Routine Description: Helper routine to build the STPG info and send it down to modify the passed in devInfo's state. Arguments: DsmContext - DSM context. DeviceInfo - DevInfo whose state needs to be changed. DevState - New state to be set. Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { PUCHAR targetPortGroupsInfo = NULL; ULONG targetPortGroupsInfoLength; PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR tpgDescriptor = NULL; NTSTATUS status; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpSetDeviceALUAState (DevInfo %p): Entering function.\n", DeviceInfo)); // // Send down SetTPG to set the appropriate access state // (The TPG block will contain the header and a SetTPG descriptor). // targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR); targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx, targetPortGroupsInfoLength, DSM_TAG_TARGET_PORT_GROUPS); if (targetPortGroupsInfo) { tpgDescriptor = (PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)(targetPortGroupsInfo + SPC3_TARGET_PORT_GROUPS_HEADER_SIZE); tpgDescriptor->AsymmetricAccessState = DevState; REVERSE_BYTES_SHORT(&tpgDescriptor->TPG_Identifier, &DeviceInfo->TargetPortGroup->Identifier); status = DsmpSetTargetPortGroups(DeviceInfo->TargetObject, targetPortGroupsInfo, targetPortGroupsInfoLength); if (NT_SUCCESS(status)) { // // An explicit transition may cause changes to some other TPGs. // So we need to query for the states of all the TPGs and update // our internal list and its elements. // status = DsmpGetDeviceALUAState(DsmContext, DeviceInfo, NULL); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpSetDeviceALUAState (DevInfo %p): Failed to SetTPG with %x.\n", DeviceInfo, status)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpSetDeviceALUAState (DevInfo %p): Failed to allocate TPG.\n", DeviceInfo)); status = STATUS_INSUFFICIENT_RESOURCES; } if (targetPortGroupsInfo) { DsmpFreePool(targetPortGroupsInfo); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpSetDeviceALUAState (DevInfo %p): Exiting function with status %x\n", DeviceInfo, status)); return status; } NTSTATUS DsmpAdjustDeviceStatesALUA( _In_ IN PDSM_GROUP_ENTRY Group, _In_opt_ IN PDSM_DEVICE_INFO PreferredActiveDeviceInfo, _In_ IN ULONG SpecialHandlingFlag ) /*++ Routine Description: Helper routine to build the adjust every device state in the group taking the following into consideration: 1. PreferredActiveDeviceInfo 2. DeviceInfo's TPG state 3. Preferred Path 4. LB Policy Arguments: Group - Pseudo-LUN whose path states need to be adjusted. PreferredActiveDeviceInfo - DevInfo whose state needs to preferrably made A/O, if possible. This parameter is optional. SpecialHandlingFlag - Flags to indicate any special handling requirement Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { ULONG index; PDSM_DEVICE_INFO deviceInfo; PDSM_DEVICE_INFO activeDevice = NULL; DSM_DEVICE_STATE devState; NTSTATUS status = STATUS_SUCCESS; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): Entering function with preferred active devInfo %p.\n", Group, PreferredActiveDeviceInfo)); // // Ensure that: // 1. All devices match their ALUA state. // 2. For RRWS, if a device's desired state is non-A/O, but ALUA state is A/O, mask it. // 3. For FOO there must be only one A/O device. Preferably the preferred path. // for (index = 0; index < DSM_MAX_PATHS; index++) { deviceInfo = Group->DeviceList[index]; if (deviceInfo) { devState = deviceInfo->State; if (!DsmpIsDeviceFailedState(deviceInfo->State) && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo)) { deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = deviceInfo->ALUAState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (its ALUA state).\n", Group, deviceInfo, deviceInfo->PreviousState, deviceInfo->State)); if (deviceInfo->ALUAState == DSM_DEV_ACTIVE_OPTIMIZED) { // // In FOO and RRWS, we need to mask states. // switch (Group->LoadBalanceType) { case DSM_LB_FAILOVER: { // // Cache the first available devInfo that is in A/O // if (!activeDevice) { activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p choosen as the active device.\n", Group, activeDevice)); break; } // // Check if this deviceInfo is the preferred path. If yes, // mask the active device's state and make this the new // active device. // if (Group->PreferredPath == (ULONGLONG)((ULONG_PTR)deviceInfo->FailGroup->PathId)) { activeDevice->PreviousState = activeDevice->State; activeDevice->State = (activeDevice->DesiredState == DSM_DEV_UNDETERMINED || activeDevice->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : activeDevice->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): Previous active devInfo %p transitioning from %u to %u.\n", Group, activeDevice, activeDevice->PreviousState, activeDevice->State)); activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is now the new active device (preferred path).\n", Group, activeDevice)); break; } // // If active device's desired state is not A/O but this // deviceInfo's is, then mask the active device's state // and make this one the new active device. // if (activeDevice->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED && activeDevice->DesiredState != DSM_DEV_UNDETERMINED) { // // The exception though is if the current active device // is the preferred path // if (Group->PreferredPath == (ULONGLONG)((ULONG_PTR)activeDevice->FailGroup->PathId)) { deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = (deviceInfo->DesiredState == DSM_DEV_UNDETERMINED || deviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : deviceInfo->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (active DI is PrefPath).\n", Group, deviceInfo, deviceInfo->PreviousState, deviceInfo->State)); } else { // // If this is the devInfo that is preferred to be A/O, make it such // if (PreferredActiveDeviceInfo && PreferredActiveDeviceInfo == deviceInfo) { activeDevice->PreviousState = activeDevice->State; activeDevice->State = activeDevice->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (found a preferred active DI).\n", Group, activeDevice, activeDevice->PreviousState, activeDevice->State)); activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is now the new active DI (preferred).\n", Group, activeDevice)); } else { // // Check if this devInfo desires to be in A/O, since the currently // active one doesn't want to be. // if (deviceInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED && deviceInfo->DesiredState != DSM_DEV_UNDETERMINED) { // // This deviceInfo's desire is also not to be in A/O, // so just leave the current one active. // if (devState == DSM_DEV_ACTIVE_OPTIMIZED) { // // Exception is if we're processing the device whose state before // RTPG was sent was already A/O, it is best to leave this device // in A/O state. // activeDevice->PreviousState = activeDevice->State; activeDevice->State = (activeDevice->DesiredState == DSM_DEV_UNDETERMINED || activeDevice->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : activeDevice->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u. Found a DI that was previously active.\n", Group, activeDevice, activeDevice->PreviousState, activeDevice->State)); activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p now the new active device (previously A/O).\n", Group, activeDevice)); } else { // // This device wasn't in A/O state before, so just leave // the currently selected active device as is. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = deviceInfo->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (active device already exists).\n", Group, deviceInfo, deviceInfo->PreviousState, deviceInfo->State)); } } else { // // Current devInfo wants (or doesn't) mind being in // A/O, whereas the current active device doesn't, so // mask the active device and make this devInfo the // active device. // activeDevice->PreviousState = activeDevice->State; activeDevice->State = activeDevice->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u. Current DI prefers being A/O.\n", Group, activeDevice, activeDevice->PreviousState, activeDevice->State)); activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is now the new active device (desired state).\n", Group, activeDevice)); } } } } else { // // The single overriding factor is always the preferred path. // Everything else is secondary, so first check if the currently // active device can even be overridden by another one. // if (Group->PreferredPath != (ULONGLONG)((ULONG_PTR)activeDevice->FailGroup->PathId)) { // // It can't be overridden, so we're done. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = (deviceInfo->DesiredState == DSM_DEV_UNDETERMINED || deviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : deviceInfo->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (current active DI is PrefPath).\n", Group, deviceInfo, deviceInfo->PreviousState, deviceInfo->State)); } else { // // Active device's desired state is A/O but it isn't the preferred // path. Check if this devInfo is preferred as A/O. // if (PreferredActiveDeviceInfo && PreferredActiveDeviceInfo == deviceInfo) { activeDevice->PreviousState = activeDevice->State; activeDevice->State = (activeDevice->DesiredState == DSM_DEV_UNDETERMINED || activeDevice->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : activeDevice->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u. New DI is preferred active.\n", Group, activeDevice, activeDevice->PreviousState, activeDevice->State)); activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is now the new active device (this DI is preferred active).\n", Group, activeDevice)); } else { // // Active device's desired state is A/O but it isn't the // preferred path. Check if this devInfo's desired state // is also A/O. If yes, we'll need to make certain decisions. // if (deviceInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED && deviceInfo->DesiredState != DSM_DEV_UNDETERMINED) { // // Since this device doesn't desire to be in // A/O and we already have an active device, just // mask its state. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = deviceInfo->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (prefers being in non-A/O).\n", Group, deviceInfo, deviceInfo->PreviousState, deviceInfo->State)); } else { // // Active device is in A/O and this device desires to be in // A/O too. Make this the new active device only if its state // before the RTPG was already A/O. // if (devState == DSM_DEV_ACTIVE_OPTIMIZED) { activeDevice->PreviousState = activeDevice->State; activeDevice->State = (activeDevice->DesiredState == DSM_DEV_UNDETERMINED || activeDevice->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : activeDevice->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (new DI was already in A/O previously).\n", Group, activeDevice, activeDevice->PreviousState, activeDevice->State)); activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is new active device (since it was in A/O previously too).\n", Group, activeDevice)); } else { // // Just leave the currently active one alone. // deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = (deviceInfo->DesiredState == DSM_DEV_UNDETERMINED || deviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : deviceInfo->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (leave current active DI alone).\n", Group, deviceInfo, deviceInfo->PreviousState, deviceInfo->State)); } } } } } break; } case DSM_LB_ROUND_ROBIN_WITH_SUBSET: { // // At least one path needs to be in A/O state, so // cache the first available devInfo that is in A/O // if (!activeDevice) { activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): We have atleast one A/O DevInfo %p.\n", Group, activeDevice)); break; } // // Check if this device is preferred to be in A/O // if (PreferredActiveDeviceInfo && PreferredActiveDeviceInfo == deviceInfo) { // // If the currently active device, doesn't desire to be in // A/O state, mask its state. // if (activeDevice->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED && activeDevice->DesiredState != DSM_DEV_UNDETERMINED) { activeDevice->PreviousState = activeDevice->State; activeDevice->State = activeDevice->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (desired state non-A/O).\n", Group, activeDevice, activeDevice->PreviousState, activeDevice->State)); } activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p now the new active device (preferred active DI).\n", Group, activeDevice)); } else { // // If this device's desired state is specified and not A/O, // mask its path state. // if (deviceInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED && deviceInfo->DesiredState != DSM_DEV_UNDETERMINED) { deviceInfo->PreviousState = deviceInfo->State; deviceInfo->State = deviceInfo->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (desires to be in non-A/O).\n", Group, deviceInfo, deviceInfo->PreviousState, deviceInfo->State)); } else { // // Since this devInfo desires to be in A/O, we are assured // of at least one path in A/O. So check to see if the // currently active device doesn't desire to be in A/O. // if (activeDevice->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED && activeDevice->DesiredState != DSM_DEV_UNDETERMINED) { activeDevice->PreviousState = activeDevice->State; activeDevice->State = activeDevice->DesiredState; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (new DI desires to be in A/O).\n", Group, activeDevice, activeDevice->PreviousState, activeDevice->State)); activeDevice = deviceInfo; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p now the new active DI (desires to be in A/O).\n", Group, activeDevice)); } } } break; } default: { // // For RR, LQD and WP, paths must be in the same // state as their corresponding TPG. Preferably // all should be A/O. // if (deviceInfo->State != DSM_DEV_ACTIVE_OPTIMIZED) { DSM_ASSERT(deviceInfo->State == deviceInfo->ALUAState); } break; } } } } } } // // There may have been a change to the device states. // DsmpGetPath() will pick these changes for RR, RRWS and LQD. // However, it won't for FOO and WP, so update PTBU if needed. // if (Group->LoadBalanceType == DSM_LB_FAILOVER || Group->LoadBalanceType == DSM_LB_WEIGHTED_PATHS) { deviceInfo = DsmpGetActivePathToBeUsed(Group, FALSE, SpecialHandlingFlag); if (deviceInfo) { InterlockedExchangePointer(&(Group->PathToBeUsed), deviceInfo->FailGroup); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpAdjustDeviceStatesALUA (Group %p): Exiting function with status %x\n", Group, status)); return status; } PDSM_WORKITEM DsmpAllocateWorkItem( _In_ IN PDEVICE_OBJECT DeviceObject, _In_ IN PVOID Context ) /*++ Routine Description: Allocates a work item to handle reservation failover. Arguments: DeviceObject - Target device. Context - Workitem context Return Value: Allocated workitem or NULL (if low memory). --*/ { PDSM_WORKITEM dsmWorkItem = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpAllocateWorkItem (DevObj %p): Entering function.\n", DeviceObject)); dsmWorkItem = DsmpAllocatePool(NonPagedPoolNx, sizeof(DSM_WORKITEM), DSM_TAG_WORKITEM); if (dsmWorkItem != NULL) { dsmWorkItem->WorkItem = IoAllocateWorkItem(DeviceObject); if (dsmWorkItem->WorkItem != NULL) { dsmWorkItem->Context = Context; } else { DsmpFreePool(dsmWorkItem); dsmWorkItem = NULL; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpAllocateWorkItem (DevObj %p): Exiting function. dsmWorkItem %p.\n", DeviceObject, dsmWorkItem)); return dsmWorkItem; } VOID DsmpFreeWorkItem( _In_ IN PDSM_WORKITEM DsmWorkItem ) { PVOID temp = DsmWorkItem; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpFreeWorkItem (WorkItem %p): Entering function.\n", DsmWorkItem)); if (DsmWorkItem != NULL) { if (DsmWorkItem->WorkItem != NULL) { IoFreeWorkItem(DsmWorkItem->WorkItem); } DsmpFreePool(DsmWorkItem); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DsmpFreeWorkItem (WorkItem %p): Exiting function.\n", temp)); return; } VOID DsmpFreeZombieGroupList( _In_ IN PDSM_FAILOVER_GROUP FailGroup ) { PLIST_ENTRY zombieEntry = NULL; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFreeZombieGroupList (FailGroup %p): Entering function.\n", FailGroup)); while (!IsListEmpty(&FailGroup->ZombieGroupList)) { zombieEntry = RemoveHeadList(&FailGroup->ZombieGroupList); if (zombieEntry) { DsmpFreePool(zombieEntry); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpFreeZombieGroupList (FailGroup %p): Exiting function.\n", FailGroup)); } NTSTATUS DsmpGetDeviceALUAState( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_DEVICE_INFO DeviceInfo, _In_opt_ IN PDSM_DEVICE_STATE DevState ) /*++ Routine Description: Helper routine to build the RTPG info and send it down to retrieve the devInfo's current state. Arguments: DsmContext - DSM context. DeviceInfo - DevInfo whose state needs to be changed. DevState - Current state of passed in DeviceInfo. Return Value: STATUS_SUCCESS or appropriate failure code. --*/ { PUCHAR targetPortGroupsInfo = NULL; ULONG targetPortGroupsInfoLength = 0; PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = NULL; KIRQL irql; NTSTATUS status; ULONG index; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpGetDeviceALUAState (DevInfo %p): Entering function.\n", DeviceInfo)); status = DsmpReportTargetPortGroups(DeviceInfo->TargetObject, &targetPortGroupsInfo, &targetPortGroupsInfoLength); if (NT_SUCCESS(status) && targetPortGroupsInfo != NULL) { irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); status = DsmpParseTargetPortGroupsInformation(DsmContext, DeviceInfo->Group, targetPortGroupsInfo, targetPortGroupsInfoLength); for (index = 0; index < DSM_MAX_PATHS; index++) { targetPortGroup = DeviceInfo->Group->TargetPortGroupList[index]; if (targetPortGroup) { DsmpUpdateTargetPortGroupDevicesStates(targetPortGroup, targetPortGroup->AsymmetricAccessState); } } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); if (DevState) { *DevState = DeviceInfo->State; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DsmpGetDeviceALUAState (DevInfo %p): ReportTPG failed with %x.\n", DeviceInfo, status)); } if (targetPortGroupsInfo) { DsmpFreePool(targetPortGroupsInfo); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DsmpGetDeviceALUAState (DevInfo %p): Exiting function with status %x\n", DeviceInfo, status)); return status; } NTSTATUS DsmpRegCopyTree( _In_ IN HANDLE SourceKey, _In_ IN HANDLE DestKey ) /*++ Routine Description: Copies a reg subtree from source key to destination key. This routine will first copy over all the key's values, and then copy the subkeys, each time recursively handling the subkey's values and its subtree. Arguments: SourceKey - Handle to the root of the subtree to copy over. DestKey - Handle to the root of the new tree. Return Value: STATUS_SUCCESS upon successfully coping over the tree. Appropriate NT error code in case of failure. --*/ { ULONG numValues = 0; ULONG numSubKeys = 0; ULONG lengthOfValueName = 0; ULONG lengthOfValueData = 0; ULONG lengthOfKeyName = 0; LPWSTR valueBuf = NULL; BYTE *valueDataBuf = NULL; ULONG valueDataType; ULONG titleIndex; HANDLE srcSubKey = NULL; HANDLE destSubKey = NULL; LPWSTR subKey = NULL; NTSTATUS status; PKEY_FULL_INFORMATION keyFullInfo = NULL; ULONG length = sizeof(KEY_FULL_INFORMATION); ULONG index = 0; PKEY_VALUE_FULL_INFORMATION keyValueFullInfo = NULL; PKEY_BASIC_INFORMATION keyBasicInfo = NULL; OBJECT_ATTRIBUTES objectAttributes; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Entering function.\n", SourceKey)); if (!SourceKey || !DestKey) { status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpRegCopyTree; } // // Query the source key for information about number of subkeys, number of values, etc. // do { if (keyFullInfo) { DsmpFreePool(keyFullInfo); } keyFullInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED); if (!keyFullInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for key full info.\n", SourceKey)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegCopyTree; } status = ZwQueryKey(SourceKey, KeyFullInformation, keyFullInfo, length, &length); } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to query key. Status %x.\n", SourceKey, status)); goto __Exit_DsmpRegCopyTree; } numSubKeys = keyFullInfo->SubKeys; numValues = keyFullInfo->Values; lengthOfKeyName = keyFullInfo->MaxNameLen + sizeof(WCHAR); lengthOfValueName = keyFullInfo->MaxValueNameLen + sizeof(WCHAR); lengthOfValueData = keyFullInfo->MaxValueDataLen + sizeof(WCHAR); // // Allocate a buffer for the name of the value // valueBuf = DsmpAllocatePool(NonPagedPoolNxCacheAligned, lengthOfValueName, DSM_TAG_REG_KEY_RELATED); if (!valueBuf) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for value name.\n", SourceKey)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegCopyTree; } // // Allocate a buffer for the value data // valueDataBuf = DsmpAllocatePool(NonPagedPoolNxCacheAligned, lengthOfValueData, DSM_TAG_REG_KEY_RELATED); if (!valueDataBuf) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for value's data.\n", SourceKey)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegCopyTree; } // // First enumerate all of the values // status = STATUS_SUCCESS; for (index = 0; index < numValues && NT_SUCCESS(status); index++) { UNICODE_STRING valueName; length = sizeof(KEY_VALUE_FULL_INFORMATION); do { if (keyValueFullInfo) { DsmpFreePool(keyValueFullInfo); } keyValueFullInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED); if (!keyValueFullInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for value full info.\n", SourceKey)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegCopyTree; } // // Get the information of the index'th value // status = ZwEnumerateValueKey(SourceKey, index, KeyValueFullInformation, keyValueFullInfo, length, &length); } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to enumerate key's value information. Status %x.\n", SourceKey, status)); goto __Exit_DsmpRegCopyTree; } // // Capture the data type, data value, and value name. // titleIndex = keyValueFullInfo->TitleIndex; valueDataType = keyValueFullInfo->Type; RtlZeroMemory(valueDataBuf, lengthOfValueData); RtlCopyMemory(valueDataBuf, (PUCHAR)keyValueFullInfo + keyValueFullInfo->DataOffset, keyValueFullInfo->DataLength); RtlZeroMemory(valueBuf, lengthOfValueName); RtlStringCbCopyNW(valueBuf, lengthOfValueName, keyValueFullInfo->Name, keyValueFullInfo->NameLength); RtlInitUnicodeString(&valueName, valueBuf); // // Copy the value over to the new key // status = ZwSetValueKey(DestKey, &valueName, titleIndex, valueDataType, valueDataBuf, keyValueFullInfo->DataLength); } if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to allocate set new key's value information. Status %x.\n", SourceKey, status)); goto __Exit_DsmpRegCopyTree; } // // Allocate buffer for subkey name // subKey = DsmpAllocatePool(NonPagedPoolNxCacheAligned, lengthOfKeyName, DSM_TAG_REG_KEY_RELATED); if(!subKey) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for sub key name.\n", SourceKey)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegCopyTree; } // // Now Enumerate all of the subkeys // length = sizeof(KEY_BASIC_INFORMATION); for(index = 0; index < numSubKeys && NT_SUCCESS(status); index++) { UNICODE_STRING subKeyName; do { if (keyBasicInfo) { DsmpFreePool(keyBasicInfo); } keyBasicInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED); if (!keyBasicInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for key basic info.\n", SourceKey)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegCopyTree; } // // Enumerate the index'th subkey // status = ZwEnumerateKey(SourceKey, index, KeyBasicInformation, keyBasicInfo, length, &length); } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to enumerate sub key's info. Status %x.\n", SourceKey, status)); goto __Exit_DsmpRegCopyTree; } RtlZeroMemory(subKey, lengthOfKeyName); RtlStringCbCopyNW(subKey, lengthOfKeyName, keyBasicInfo->Name, keyBasicInfo->NameLength); RtlInitUnicodeString(&subKeyName, subKey); // // Open a handle to the the subkey on the old device. // InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), SourceKey, (PSECURITY_DESCRIPTOR) NULL); if (srcSubKey) { ZwClose(srcSubKey); srcSubKey = NULL; } status = ZwOpenKey(&srcSubKey, KEY_ALL_ACCESS, &objectAttributes); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to open reg key %ws. Status %x.\n", SourceKey, subKey, status)); goto __Exit_DsmpRegCopyTree; } InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), DestKey, (PSECURITY_DESCRIPTOR) NULL); if (destSubKey) { ZwClose(destSubKey); destSubKey = NULL; } // // Create the subkey on the new device. // status = ZwCreateKey(&destSubKey, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Failed to create reg key %ws. Status %x.\n", SourceKey, subKey, status)); goto __Exit_DsmpRegCopyTree; } // // That's it. We've got everything we need (ie. handles to the two new // subtrees' roots. Call recursively. // status = DsmpRegCopyTree(srcSubKey, destSubKey); } __Exit_DsmpRegCopyTree: if (keyFullInfo) { DsmpFreePool(keyFullInfo); } if (valueBuf) { DsmpFreePool(valueBuf); } if (valueDataBuf) { DsmpFreePool(valueDataBuf); } if (keyValueFullInfo) { DsmpFreePool(keyValueFullInfo); } if (subKey) { DsmpFreePool(subKey); } if (keyBasicInfo) { DsmpFreePool(keyBasicInfo); } if (srcSubKey) { ZwClose(srcSubKey); } if (destSubKey) { ZwClose(destSubKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRegCopyTree (SrcKey %p): Exiting function with status %x.\n", SourceKey, status)); return status; } NTSTATUS DsmpRegDeleteTree( _In_ IN HANDLE KeyRoot ) /*++ Routine Description: This routine is a recursive worker that enumerates the subkeys of a given key, applies itself to each one, then deletes itself. Arguments: KeyRoot - Supplies a handle to the root of subtree to be deleted. Return Value: STATUS_SUCCESS - upon successful deletion of subtree. Appropriate NT error code upon failure. --*/ { NTSTATUS status; PKEY_FULL_INFORMATION keyFullInfo = NULL; ULONG length = sizeof(KEY_FULL_INFORMATION); ULONG numSubKeys; ULONG lengthOfKeyName; LPWSTR subKey = NULL; PKEY_BASIC_INFORMATION keyBasicInfo = NULL; ULONG index = 0; HANDLE srcSubKey = NULL; OBJECT_ATTRIBUTES objectAttributes; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRegDeleteTree (SrcKey %p): Entering function.\n", KeyRoot)); if (!KeyRoot) { status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpRegDeleteTree; } // // Query the source key for information about number of subkeys and max // length needed for subkey name. // do { if (keyFullInfo) { DsmpFreePool(keyFullInfo); } keyFullInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED); if (!keyFullInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegDeleteTree (SrcKey %p): Failed to allocate resources for key full info.\n", KeyRoot)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegDeleteTree; } status = ZwQueryKey(KeyRoot, KeyFullInformation, keyFullInfo, length, &length); } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegDeleteTree (SrcKey %p): Failed to query key. Status %x.\n", KeyRoot, status)); goto __Exit_DsmpRegDeleteTree; } numSubKeys = keyFullInfo->SubKeys; lengthOfKeyName = keyFullInfo->MaxNameLen + sizeof(WCHAR); if (numSubKeys) { // // Allocate buffer for subkey name // subKey = DsmpAllocatePool(NonPagedPoolNxCacheAligned, lengthOfKeyName, DSM_TAG_REG_KEY_RELATED); if(!subKey) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegDeleteTree (SrcKey %p): Failed to allocate resources for sub key.\n", KeyRoot)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegDeleteTree; } // // Now Enumerate all of the subkeys // index = numSubKeys - 1; length = sizeof(KEY_BASIC_INFORMATION); do { UNICODE_STRING subKeyName; do { if (keyBasicInfo) { DsmpFreePool(keyBasicInfo); } keyBasicInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED); if (!keyBasicInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegDeleteTree (SrcKey %p): Failed to allocate resources for key basic info.\n", KeyRoot)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpRegDeleteTree; } // // Enumerate the index'th subkey // status = ZwEnumerateKey(KeyRoot, index, KeyBasicInformation, keyBasicInfo, length, &length); } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); if (NT_SUCCESS(status)) { RtlZeroMemory(subKey, lengthOfKeyName); RtlStringCbCopyNW(subKey, lengthOfKeyName, keyBasicInfo->Name, keyBasicInfo->NameLength); RtlInitUnicodeString(&subKeyName, subKey); // // Open a handle to the the current root's subkey. // InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), KeyRoot, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey(&srcSubKey, KEY_ALL_ACCESS, &objectAttributes); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpRegDeleteTree (SrcKey %p): Failed to open key %ws. Status %x.\n", KeyRoot, subKey, status)); goto __Exit_DsmpRegDeleteTree; } // // Delete this key's subtree (recursively). // status = DsmpRegDeleteTree(srcSubKey); ZwClose(srcSubKey); srcSubKey = NULL; } index--; } while (status != STATUS_NO_MORE_ENTRIES && (LONG)index >= 0); if (status == STATUS_NO_MORE_ENTRIES) { status = STATUS_SUCCESS; } } ZwDeleteKey(KeyRoot); __Exit_DsmpRegDeleteTree: if (srcSubKey) { ZwClose(srcSubKey); } if (keyFullInfo) { DsmpFreePool(keyFullInfo); } if (subKey) { DsmpFreePool(subKey); } if (keyBasicInfo) { DsmpFreePool(keyBasicInfo); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpRegDeleteTree (SrcKey %p): Exiting function with status %x.\n", KeyRoot, status)); return status; } #if defined (_WIN64) VOID DsmpPassThroughPathTranslate32To64( _In_ IN PMPIO_PASS_THROUGH_PATH32 MpioPassThroughPath32, _Inout_ IN OUT PMPIO_PASS_THROUGH_PATH MpioPassThroughPath64 ) /*++ Routine Description: On WIN64, the SCSI_PASS_THROUGH field of the MPIO_PASS_THROUGH_PATH structure sent down by a 32-bit application must be marshaled into a 64-bit version of the structure. This function performs that marshaling. Arguments: MpioPassThroughPath32 - Supplies a pointer to a 32-bit MPIO_PASS_THROUGH_PATH struct. MpioPassThroughPath64 - Supplies a pointer to a 64-bit MPIO_PASS_THROUGH_PATH structure, into which we'll copy the marshaled 32-bit data. Return Value: None. --*/ { // // Copy the first set of fields out of the 32-bit structure. These // fields all line up between the 32 & 64 bit versions. // // Note that we do NOT adjust the length in the SrbControl. This is to // allow the calling routine to compare the length of the actual // control area against the offsets embedded within. If we adjusted the // length then requests with the sense area backed against the control // area would be rejected because the 64-bit control area is 4 bytes // longer. // RtlCopyMemory(MpioPassThroughPath64, MpioPassThroughPath32, FIELD_OFFSET(SCSI_PASS_THROUGH, DataBufferOffset)); // // Copy over the CDB. // RtlCopyMemory(MpioPassThroughPath64->PassThrough.Cdb, MpioPassThroughPath32->PassThrough.Cdb, 16 * sizeof(UCHAR) ); // // Copy over the rest of the fields of the structure. // MpioPassThroughPath64->Version = MpioPassThroughPath32->Version; MpioPassThroughPath64->Length = MpioPassThroughPath32->Length; MpioPassThroughPath64->Flags = MpioPassThroughPath32->Flags; MpioPassThroughPath64->PortNumber = MpioPassThroughPath32->PortNumber; MpioPassThroughPath64->MpioPathId = MpioPassThroughPath32->MpioPathId; // // Copy the fields that follow the ULONG_PTR. // MpioPassThroughPath64->PassThrough.DataBufferOffset = (ULONG_PTR)MpioPassThroughPath32->PassThrough.DataBufferOffset; MpioPassThroughPath64->PassThrough.SenseInfoOffset = MpioPassThroughPath32->PassThrough.SenseInfoOffset; return; } VOID DsmpPassThroughPathTranslate64To32( _In_ IN PMPIO_PASS_THROUGH_PATH MpioPassThroughPath64, _Inout_ IN OUT PMPIO_PASS_THROUGH_PATH32 MpioPassThroughPath32 ) /*++ Routine Description: On WIN64, the SCSI_PASS_THROUGH field of MPIO_PASS_THROUGH_PATH structure sent down by a 32-bit application must be marshaled into a 64-bit version of the structure. This function marshals a 64-bit version of the structure back into a 32-bit version. Arguments: MpioPassThroughPath64 - Supplies a pointer to a 64-bit MPIO_PASS_THROUGH_PATH struct. MpioPassThroughPath32 - Supplies the address of a pointer to a 32-bit MPIO_PASS_THROUGH_PATH structure, into which we'll copy the marshaled 64-bit data. Return Value: None. --*/ { // // Copy back the fields through the data offsets. // RtlCopyMemory(MpioPassThroughPath32, MpioPassThroughPath64, FIELD_OFFSET(SCSI_PASS_THROUGH, DataBufferOffset)); // // Copy over the CDB. // RtlCopyMemory(MpioPassThroughPath32->PassThrough.Cdb, MpioPassThroughPath64->PassThrough.Cdb, 16 * sizeof(UCHAR) ); // // Copy over the rest of the fields of the structure. // MpioPassThroughPath32->Version = MpioPassThroughPath64->Version; MpioPassThroughPath32->Length = MpioPassThroughPath64->Length; MpioPassThroughPath32->Flags = MpioPassThroughPath64->Flags; MpioPassThroughPath32->PortNumber = MpioPassThroughPath64->PortNumber; MpioPassThroughPath32->MpioPathId = MpioPassThroughPath64->MpioPathId; return; } #endif NTSTATUS DsmpGetMaxPRRetryTime( _In_ IN PDSM_CONTEXT Context, _Out_ OUT PULONG RetryTime ) /*++ Routine Description: This routine is used to get the max time period for which a PR request failing with a retry-able unit attention should be retried before failing back to MSCS. The value is determined by querying the value found at "msdsm\Parameters\DsmMaximumStateTransitionTime" Arguments: Context - The DSM Context value. RetryTime - The output parameter that will receive the value to be used. Return Value: Status of the RtlQueryRegistryValues call. --*/ { RTL_QUERY_REGISTRY_TABLE queryTable[2]; WCHAR registryKeyName[56] = {0}; NTSTATUS status; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetMaxPRRetryTime (DsmCtxt %p): Entering function.\n", Context)); NT_ASSERT(RetryTime); *RetryTime = DSM_MAX_PR_UNIT_ATTENTION_RETRY_TIME; RtlZeroMemory(queryTable, sizeof(queryTable)); // // Build the key value name that we want as the base of the query. // RtlStringCbPrintfW(registryKeyName, sizeof(registryKeyName), DSM_PARAMETER_PATH_W); // // The query table has two entries. One for the state transition time and // the second which is the 'NULL' terminator. // queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_MAX_STATE_TRANSITION_TIME_VALUE_NAME; queryTable[0].EntryContext = RetryTime; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, registryKeyName, queryTable, registryKeyName, NULL); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpGetMaxPRRetryTime (DsmCtxt %p): Exiting function with status %x.\n", Context, status)); return status; } NTSTATUS DsmpQueryCacheInformationFromRegistry( _In_ IN PDSM_CONTEXT DsmContext, _Out_ OUT PBOOLEAN UseCacheForLeastBlocks, _Out_ OUT PULONGLONG CacheSizeForLeastBlocks ) /*++ Routine Description: This routine is used to get the information about whether sequential IO should use the same path when employing Least Blocks policy. It also queries the size of cache set by the administrator. The value is determined by querying the value found at "msdsm\Parameters\DsmUseCacheForLeastBlocks" and "msdsm\Parameters\DsmCacheSizeForLeastBlocks" Arguments: Context - The DSM Context value. UseCacheForLeastBlocks - Returns the flag that indicates whether or not to use same path for sequential IO when LB policy is Least Blocks. CacheSizeForLeastBlocks - Returns the size of the cache (in bytes) set by the Admin to indicate the amount of sequential data that should be use the same path when LB policy is Least Blocks. Return Value: Status of the RtlQueryRegistryValues call. --*/ { RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0}; WCHAR registryKeyName[56] = {0}; HANDLE parametersKey = NULL; UNICODE_STRING keyValueName; NTSTATUS status; struct _cacheSizeForLeastBlocks { KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; ULONGLONG Data; } cacheSizeForLeastBlocks; ULONG length = 0; BOOLEAN useCacheForLeastBlocksDefault = FALSE; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryCacheInformationFromRegistry (DsmCtxt %p): Entering function.\n", DsmContext)); NT_ASSERT(UseCacheForLeastBlocks); NT_ASSERT(CacheSizeForLeastBlocks); RtlZeroMemory(queryTable, sizeof(queryTable)); // // Build the key value name that we want as the base of the query. // RtlStringCbPrintfW(registryKeyName, sizeof(registryKeyName), DSM_PARAMETER_PATH_W); // // The query table has two entries. One for whether to use cache, and // and the second which is the 'NULL' terminator. // queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_USE_CACHE_FOR_LEAST_BLOCKS; queryTable[0].EntryContext = UseCacheForLeastBlocks; queryTable[0].DefaultType = (REG_BINARY << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_BINARY; queryTable[0].DefaultLength = sizeof(BOOLEAN); queryTable[0].DefaultData = &useCacheForLeastBlocksDefault; status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, registryKeyName, queryTable, registryKeyName, NULL); if (NT_SUCCESS(status)) { status = DsmpOpenDsmServicesParametersKey(KEY_QUERY_VALUE, ¶metersKey); if (NT_SUCCESS(status)) { RtlInitUnicodeString(&keyValueName, DSM_CACHE_SIZE_FOR_LEAST_BLOCKS); status = ZwQueryValueKey(parametersKey, &keyValueName, KeyValuePartialInformation, &cacheSizeForLeastBlocks, sizeof(cacheSizeForLeastBlocks), &length); if (NT_SUCCESS(status)) { NT_ASSERT(cacheSizeForLeastBlocks.KeyValueInfo.DataLength == sizeof(ULONGLONG)); *CacheSizeForLeastBlocks = *((ULONGLONG UNALIGNED *)&(cacheSizeForLeastBlocks.KeyValueInfo.Data)); } } if (parametersKey) { ZwClose(parametersKey); } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_PNP, "DsmpQueryCacheInformationFromRegistry (DsmCtxt %p): Exiting function with status %x.\n", DsmContext, status)); return status; } BOOLEAN DsmpConvertSharedSpinLockToExclusive( _Inout_ _Requires_lock_held_(*_Curr_) PEX_SPIN_LOCK SpinLock ) /*++ Routine Description: This routine is a wrapper around ExTryConvertSharedSpinLockExclusive() that guarantees the given EX_SPIN_LOCK will be acquired in Exclusive mode once this function returns. It's possible the lock may be released and re-acquired within this function so the caller should be very careful about the use of this function. N.B. The caller MUST have acquired the given lock in Shared mode before calling this function. Arguments: SpinLock - The EX_SPIN_LOCK to convert from Shared to Exclusive mode. Return Value: Status of the ExTryConvertSharedSpinLockExclusive() call. This function will always return with the lock acquired in Exclusive mode. The FALSE is returned, then the lock had to be released and re-acquired. --*/ { BOOLEAN converted = FALSE; converted = (BOOLEAN)ExTryConvertSharedSpinLockExclusive(SpinLock); // // If the conversion attempt failed, then we should release the lock from // Shared mode and try to pick it back up in Exclusive mode to guarantee // this function will always return with the lock in Exclusive mode. // if (converted == FALSE) { ExReleaseSpinLockSharedFromDpcLevel(SpinLock); ExAcquireSpinLockExclusiveAtDpcLevel(SpinLock); } return converted; } ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/wmi.c ================================================ /*++ Copyright (C) 2004-2010 Microsoft Corporation Module Name: wmi.c Abstract: This driver is the Microsoft Device Specific Module (DSM). It exports behaviours that mpio.sys will use to determine how to multipath SPC-3 compliant devices. This file contains WMI related functions. Environment: kernel mode only Notes: --*/ #include "precomp.h" #include "msdsmwmi.h" #include "msdsmdsm.h" #ifdef DEBUG_USE_WPP #include "wmi.tmh" #endif #pragma warning (disable:4305) extern BOOLEAN DoAssert; #define USE_BINARY_MOF_RESOURCE #define DSM_INVALID_LOAD_BALANCE_POLICY STATUS_INVALID_PARAMETER #define DSM_UNSUPPORTED_VERSION STATUS_NOT_SUPPORTED // // Max length for each of the DeviceId strings (supported device list) // NOTE: This must be kept in sync with msdsmdsm.mof // #define MSDSM_MAX_DEVICE_ID_LENGTH 31 #define MSDSM_MAX_DEVICE_ID_SIZE (MSDSM_MAX_DEVICE_ID_LENGTH * sizeof(WCHAR)) // // List of supported DSM-centric guids // GUID MSDSM_SUPPORTED_DEVICES_LISTGUID = MSDSM_SUPPORTED_DEVICES_LISTGuid; GUID MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID = MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGuid; GUID MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID = MSDSM_DEFAULT_LOAD_BALANCE_POLICYGuid; // // Symbolic names for the DSM-centric guid indexes // #define MSDSM_SUPPORTED_DEVICES_LISTGUID_Index 0 #define MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID_Index 1 #define MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID_Index 2 WMIGUIDREGINFO MSDsmGuidList[] = { { &MSDSM_SUPPORTED_DEVICES_LISTGUID, 1, 0 }, { &MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID, 1, 0 }, { &MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID, 1, 0 } }; #define MSDsmGuidCount (sizeof(MSDsmGuidList) / sizeof(WMIGUIDREGINFO)) // // List of supported Device-centric guids // GUID DSM_LBOperationsGUID = DSM_LB_OperationsGuid; GUID DSM_QueryLBPolicyGUID = DSM_QueryLBPolicyGuid; GUID DSM_QuerySupportedLBPoliciesGUID = DSM_QuerySupportedLBPoliciesGuid; GUID DSM_QueryDsmUniqueIdGUID = DSM_QueryUniqueIdGuid; GUID DSM_QueryLBPolicyV2GUID = DSM_QueryLBPolicy_V2Guid; GUID DSM_QuerySupportedLBPoliciesV2GUID = DSM_QuerySupportedLBPolicies_V2Guid; GUID MSDSM_DEVICE_PERFGUID = MSDSM_DEVICE_PERFGuid; GUID MSDSM_WMI_METHODSGUID = MSDSM_WMI_METHODSGuid; // // Symbolic names for the Device-centric guid indexes // #define DSM_LBOperationsGUID_Index 0 #define DSM_QueryLBPolicyGUID_Index 1 #define DSM_QuerySupportedLBPoliciesGUID_Index 2 #define DSM_QueryDsmUniqueIdGUID_Index 3 #define DSM_QueryLBPolicyV2GUID_Index 4 #define DSM_QuerySupportedLBPoliciesV2GUID_Index 5 #define MSDSM_DEVICE_PERFGuidIndex 6 #define MSDSM_WMI_METHODSGuidIndex 7 WMIGUIDREGINFO DsmGuidList[] = { { &DSM_LBOperationsGUID, 1, 0 }, { &DSM_QueryLBPolicyGUID, 1, 0 }, { &DSM_QuerySupportedLBPoliciesGUID, 1, 0 }, { &DSM_QueryDsmUniqueIdGUID, 1, 0 }, { &DSM_QueryLBPolicyV2GUID, 1, 0 }, { &DSM_QuerySupportedLBPoliciesV2GUID, 1, 0 }, { &MSDSM_DEVICE_PERFGUID, 1, 0 }, { &MSDSM_WMI_METHODSGUID, 1, 0 } }; #define DsmGuidCount (sizeof(DsmGuidList) / sizeof(WMIGUIDREGINFO)) VOID DsmpDsmWmiInitialize( _In_ IN PDSM_WMILIB_CONTEXT WmiGlobalInfo, _In_ IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine intializes the DSM-specific WmiGlobalInfo structure that is passed back to MPIO during DriverEntry. Arguments: WmiGlobalInfo - WMI information structure to initialize. RegistryPath - Registry path to the service key for this driver. Return Value: None --*/ { TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DsmpDsmWmiInitialize (RegPath %ws): Entering function.\n", RegistryPath->Buffer)); RtlZeroMemory(WmiGlobalInfo, sizeof(DSM_WMILIB_CONTEXT)); // // Build the mof resource name. This tells wmi via the busdriver, // where to find the mof data. This is found in the .rc. // RtlInitUnicodeString(&WmiGlobalInfo->MofResourceName, L"DsmMofResourceName"); // // This will jam in the entry points and guids for supported WMI // operations. SetDataBlock, SetDataItem, ExecuteMethod and FunctionControl are // currently not needed, so leave them set to zero. // WmiGlobalInfo->GuidCount = MSDsmGuidCount; WmiGlobalInfo->GuidList = MSDsmGuidList; WmiGlobalInfo->QueryWmiDataBlockEx = DsmGlobalQueryData; WmiGlobalInfo->SetWmiDataBlockEx = DsmGlobalSetData; // // Allocate a buffer for the reg. path. // WmiGlobalInfo->RegistryPath.Buffer = DsmpAllocatePool(NonPagedPoolNx, RegistryPath->MaximumLength, DSM_TAG_REG_PATH); if (WmiGlobalInfo->RegistryPath.Buffer) { // // Set maximum length of the new string and copy it. // WmiGlobalInfo->RegistryPath.MaximumLength = RegistryPath->MaximumLength; RtlCopyUnicodeString(&WmiGlobalInfo->RegistryPath, RegistryPath); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DsmpDsmWmiInitialize (RegPath %ws): Failed to allocate memory for Registry path in WmiGlobalInfo.\n", RegistryPath->Buffer)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DsmpDsmWmiInitialize (RegPath %ws): Exiting function.\n", RegistryPath->Buffer)); return; } NTSTATUS DsmGlobalQueryData( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN ULONG GuidIndex, _In_ IN ULONG InstanceIndex, _In_ IN ULONG InstanceCount, _Inout_ IN OUT PULONG InstanceLengthArray, _In_ IN ULONG BufferAvail, _Out_writes_to_(BufferAvail, *DataLength) OUT PUCHAR Buffer, _Out_ OUT PULONG DataLength, ... ) /*++ Routine Description: This is the WMI query entry point for DSM-specific GUIDs. The index into the GUID array is found and assuming the buffer is large enough, the data will be copied over. Arguments: DsmContext - Global DSM Context DsmIds - Dsm Ids Irp - The WMI Irp GuidIndex - Index into the WMIGUIDINFO array InstanceIndex - Index of the data instance InstanceCount - Number of instances InstanceLengthArray - Array of ULONGs that indicate per-instance data lengths. BufferAvail - Size of the buffer in which data is returned. Buffer - Buffer in which the data is returned. DataLength - Storage for the actual data length written. Return Value: STATUS_BUFFER_TOO_SMALL - If output buffer is not big enough to to return all the available data. STATUS_WMI_GUID_NOT_FOUND - If GuidIndex doesn't correspond to an actual entry in the reginfo array. STATUS_SUCCESS - On success. --*/ { NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND; UNREFERENCED_PARAMETER(DsmContext); UNREFERENCED_PARAMETER(InstanceLengthArray); UNREFERENCED_PARAMETER(InstanceCount); UNREFERENCED_PARAMETER(InstanceIndex); UNREFERENCED_PARAMETER(Irp); UNREFERENCED_PARAMETER(DsmIds); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmGlobalQueryData (DsmContext %p): Entering function - GuidIndex %u.\n", DsmContext, GuidIndex)); // // Check the GuidIndex - the index into the DsmGuildList array - to see // whether this is a supported GUID or not. // switch(GuidIndex) { case MSDSM_SUPPORTED_DEVICES_LISTGUID_Index: { *DataLength = BufferAvail; status = DsmpQuerySupportedDevicesList(DsmContext, BufferAvail, DataLength, Buffer); break; } case MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID_Index: { *DataLength = BufferAvail; status = DsmpQueryTargetsDefaultPolicy(DsmContext, BufferAvail, DataLength, Buffer); break; } case MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID_Index: { *DataLength = BufferAvail; status = DsmpQueryDsmDefaultPolicy(DsmContext, BufferAvail, DataLength, Buffer); break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmGlobalQueryData (DsmContext %p): Unknown GuidIndex %d.\n", DsmContext, GuidIndex)); *DataLength = 0; break; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmGlobalQueryData (DsmContext %p): Exiting function with status 0x%x.\n", DsmContext, status)); return status; } NTSTATUS DsmGlobalSetData( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN ULONG GuidIndex, _In_ IN ULONG InstanceIndex, _In_ IN ULONG BufferAvail, _In_reads_bytes_(BufferAvail) IN PUCHAR Buffer, ... ) /*++ Routine Description: This is the WMI set entry point for DSM-specific GUIDs. The index into the GUID array is found and the contents of the buffer are set to the passed in instance index. Arguments: DsmContext - Global DSM Context DsmIds - Dsm Ids Irp - The WMI Irp GuidIndex - Index into the WMIGUIDINFO array InstanceIndex - Index of the data instance BufferAvail - Size of the buffer in which data is returned. Buffer - Buffer in which the data is returned. Return Value: STATUS_BUFFER_TOO_SMALL - If output buffer is not big enough to to return all the available data. STATUS_WMI_GUID_NOT_FOUND - If GuidIndex doesn't correspond to an actual entry in the reginfo array. STATUS_SUCCESS - On success. --*/ { NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND; ULONG dataLength; PDSM_CONTEXT dsmContext = (PDSM_CONTEXT)DsmContext; UNREFERENCED_PARAMETER(DsmIds); UNREFERENCED_PARAMETER(Irp); UNREFERENCED_PARAMETER(InstanceIndex); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): Entering function - GuidIndex %u.\n", DsmContext, GuidIndex)); switch (GuidIndex) { case MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID_Index: { PMSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY targetsPolicyInfo = (PMSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY)Buffer; PMSDSM_TARGET_DEFAULT_POLICY_INFO targetPolicyInfo; PWSTR vidpidIndex; DSM_LOAD_BALANCE_TYPE loadBalancePolicy; ULONGLONG preferredPath; DWORD index; NTSTATUS errorStatus = STATUS_SUCCESS; // // Determine the correct buffer size. // dataLength = AlignOn8Bytes(FIELD_OFFSET(MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY, TargetDefaultPolicyInfo)); if (BufferAvail < dataLength) { status = STATUS_BUFFER_TOO_SMALL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): GuidIndex %u. Incorrect buffer size. Status %x\n", DsmContext, GuidIndex, status)); break; } dataLength += targetsPolicyInfo->NumberDevices * sizeof(MSDSM_TARGET_DEFAULT_POLICY_INFO); if (BufferAvail < dataLength) { status = STATUS_BUFFER_TOO_SMALL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): GuidIndex %u. Incorrect buffer size for %u targets. Status %x\n", DsmContext, GuidIndex, targetsPolicyInfo->NumberDevices, status)); break; } targetPolicyInfo = targetsPolicyInfo->TargetDefaultPolicyInfo; for (index = 0; index < targetsPolicyInfo->NumberDevices; index++, targetPolicyInfo++) { size_t stringLength = 0; // // First ensure that these values make sense. The VID/PID should be // a string of 8+16 chars and the LB policy must be one that MSDSM // supports. // // The WMI string is like a unicode string with the first USHORT // containing the size. // vidpidIndex = targetPolicyInfo->HardwareId; vidpidIndex++; if (!NT_SUCCESS(RtlStringCchLengthW(vidpidIndex, DSM_VENDPROD_ID_LEN + 1, &stringLength)) || (stringLength != DSM_VENDPROD_ID_LEN)) { errorStatus = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): GuidIndex %u. Ignoring incorrect VID/PID %ws. Status %x\n", DsmContext, GuidIndex, vidpidIndex, errorStatus)); continue; } if (targetPolicyInfo->LoadBalancePolicy >= DSM_LB_VENDOR_SPECIFIC) { errorStatus = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): GuidIndex %u. Ignoring policy %u for %ws. Status %x\n", DsmContext, GuidIndex, targetPolicyInfo->LoadBalancePolicy, vidpidIndex, errorStatus)); continue; } loadBalancePolicy = targetPolicyInfo->LoadBalancePolicy; preferredPath = (ULONGLONG)((ULONG_PTR)targetPolicyInfo->PreferredPath); // // Now update/create the key in the registry with the LB policy info. // If the LB policy is specified as 0, delete the key. // status = DsmpSetVidPidLBPolicyInRegistry(vidpidIndex, loadBalancePolicy, preferredPath); // // If above was successful, find the group that corresponds to this // targetId and update its LB policy as well as the states of the paths // if (NT_SUCCESS(status)) { DsmpSetLBForVidPidPolicyAdjustment(dsmContext, vidpidIndex, loadBalancePolicy, preferredPath); } else { errorStatus = status; } } // // If any error occurred, return the last error. // if (!NT_SUCCESS(errorStatus)) { status = errorStatus; } break; } case MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID_Index: { PMSDSM_DEFAULT_LOAD_BALANCE_POLICY dsmPolicyInfo = (PMSDSM_DEFAULT_LOAD_BALANCE_POLICY)Buffer; DSM_LOAD_BALANCE_TYPE loadBalancePolicy; ULONGLONG preferredPath; // // Determine the correct buffer size. // dataLength = sizeof(MSDSM_DEFAULT_LOAD_BALANCE_POLICY); if (BufferAvail < dataLength) { status = STATUS_BUFFER_TOO_SMALL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): GuidIndex %u. Incorrect buffer size. Status %x\n", DsmContext, GuidIndex, status)); break; } loadBalancePolicy = dsmPolicyInfo->LoadBalancePolicy; preferredPath = (ULONGLONG)((ULONG_PTR)dsmPolicyInfo->PreferredPath); // // First ensure that the values make sense. // if (loadBalancePolicy >= DSM_LB_VENDOR_SPECIFIC) { status = STATUS_INVALID_PARAMETER; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): GuidIndex %u. Invalid policy %u specified. Status %x\n", DsmContext, GuidIndex, loadBalancePolicy, status)); } else { // // Update/create the values in the registry with the LB policy info. // If the LB policy is specified as 0, delete the values. // status = DsmpSetDsmLBPolicyInRegistry(loadBalancePolicy, preferredPath); // // If above is successful, find the groups that haven't had their LB policy // explicitly set or haven't had their policy set in accordance with target // hardware id. For each of these, adjust the states of the paths as well. // if (NT_SUCCESS(status)) { DsmpSetLBForDsmPolicyAdjustment(dsmContext, loadBalancePolicy, preferredPath); } } break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): Unknown GuidIndex %d.\n", DsmContext, GuidIndex)); break; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmGlobalSetData (DsmContext %p): Exiting function with status 0x%x.\n", DsmContext, status)); return status; } VOID DsmpWmiInitialize( _In_ IN PDSM_WMILIB_CONTEXT WmiInfo, _In_ IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine intializes the Device-specific WmiInfo structure that is passed back to MPIO during DriverEntry. Arguments: WmiInfo - WMI information structure to initialize. RegistryPath - Registry path to the service key for this driver. Return Value: None --*/ { TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DsmpWmiInitialize (RegPath %ws): Entering function.\n", RegistryPath->Buffer)); RtlZeroMemory(WmiInfo, sizeof(DSM_WMILIB_CONTEXT)); // // Build the mof resource name. This tells wmi via the busdriver, // where to find the mof data. This is found in the .rc. // RtlInitUnicodeString(&WmiInfo->MofResourceName, L"MofResourceName"); // // This will jam in the entry points and guids for supported WMI // operations. SetDataBlock, SetDataItem, and FunctionControl are // currently not needed, so leave them set to zero. // WmiInfo->GuidCount = DsmGuidCount; WmiInfo->GuidList = DsmGuidList; WmiInfo->QueryWmiDataBlockEx = DsmQueryData; WmiInfo->ExecuteWmiMethodEx = DsmExecuteMethod; // // Allocate a buffer for the reg. path. // WmiInfo->RegistryPath.Buffer = DsmpAllocatePool(NonPagedPoolNx, RegistryPath->MaximumLength, DSM_TAG_REG_PATH); if (WmiInfo->RegistryPath.Buffer) { // // Set maximum length of the new string and copy it. // WmiInfo->RegistryPath.MaximumLength = RegistryPath->MaximumLength; RtlCopyUnicodeString(&WmiInfo->RegistryPath, RegistryPath); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DsmpWmiInitialize (RegPath %ws): Failed to allocate memory for Registry path in WMIInfo.\n", RegistryPath->Buffer)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, "DsmpWmiInitialize (RegPath %ws): Exiting function.\n", RegistryPath->Buffer)); return; } NTSTATUS DsmQueryData( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN ULONG GuidIndex, _In_ IN ULONG InstanceIndex, _In_ IN ULONG InstanceCount, _Inout_ IN OUT PULONG InstanceLengthArray, _In_ IN ULONG BufferAvail, _When_(GuidIndex == DSM_LBOperationsGUID_Index || GuidIndex == MSDSM_WMI_METHODSGuidIndex, _Pre_notnull_ _Const_) _When_(!(GuidIndex == DSM_LBOperationsGUID_Index || GuidIndex == MSDSM_WMI_METHODSGuidIndex), _Out_writes_to_(BufferAvail, *DataLength)) OUT PUCHAR Buffer, _Out_ OUT PULONG DataLength, ... ) /*++ Routine Description: This is the main WMI query entry point. The index into the GUID array is found and assuming the buffer is large enough, the data will be copied over. Arguments: DsmContext - Global DSM Context DsmIds - Dsm Ids Irp - The WMI Irp GuidIndex - Index into the WMIGUIDINFO array InstanceIndex - Index of the data instance InstanceCount - Number of instances InstanceLengthArray - Array of ULONGs that indicate per-instance data lengths. BufferAvail - Size of the buffer in which data is returned. Buffer - Buffer in which the data is returned. DataLength - Storage for the actual data length written. Return Value: STATUS_BUFFER_TOO_SMALL - If output buffer is not big enough to to return all the available data. STATUS_WMI_GUID_NOT_FOUND - If GuidIndex doesn't correspond to an actual entry in the reginfo array. STATUS_SUCCESS - On success. --*/ { ULONG sizeNeeded; NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND; UNREFERENCED_PARAMETER(DsmContext); UNREFERENCED_PARAMETER(InstanceCount); UNREFERENCED_PARAMETER(InstanceIndex); UNREFERENCED_PARAMETER(Irp); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmQueryData (DsmIds %p): Entering function - GuidIndex %u.\n", DsmIds, GuidIndex)); // // Check the GuidIndex - the index into the DsmGuildList array - to see // whether this is a supported GUID or not. // switch(GuidIndex) { case DSM_LBOperationsGUID_Index: { // // Even though this class only has methods, we need to respond // to any queries for it since WMI expects that there is an actual // instance of the class on which to execute the method // sizeNeeded = sizeof(ULONG); *DataLength = sizeNeeded; if (BufferAvail >= sizeNeeded) { *InstanceLengthArray = sizeNeeded; status = STATUS_SUCCESS; } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DsmQueryData (DsmIds %p): Buffer too small in query data. Needed %d, Given %d.\n", DsmIds, sizeNeeded, BufferAvail)); status = STATUS_BUFFER_TOO_SMALL; } break; } case DSM_QueryLBPolicyGUID_Index: case DSM_QueryLBPolicyV2GUID_Index: { *DataLength = BufferAvail; status = DsmpQueryLoadBalancePolicy(DsmContext, DsmIds, ((GuidIndex == DSM_QueryLBPolicyGUID_Index) ? DSM_WMI_VERSION_1 : DSM_WMI_VERSION_2), BufferAvail, DataLength, Buffer); break; } case DSM_QuerySupportedLBPoliciesGUID_Index: case DSM_QuerySupportedLBPoliciesV2GUID_Index: { *DataLength = BufferAvail; status = DsmpQuerySupportedLBPolicies(DsmContext, DsmIds, BufferAvail, ((GuidIndex == DSM_QuerySupportedLBPoliciesGUID_Index) ? DSM_WMI_VERSION_1 : DSM_WMI_VERSION_2), DataLength, Buffer); break; } case DSM_QueryDsmUniqueIdGUID_Index: { PDSM_QueryUniqueId dsmQueryUniqueId; *DataLength = sizeof(DSM_QueryUniqueId); if (BufferAvail >= sizeof(DSM_QueryUniqueId)) { dsmQueryUniqueId = (PDSM_QueryUniqueId) Buffer; dsmQueryUniqueId->DsmUniqueId = (ULONGLONG)((ULONG_PTR)DsmContext); status = STATUS_SUCCESS; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmQueryData (DsmIds %p): Buffersize %d too small for Query Unique Id.\n", DsmIds, BufferAvail)); status = STATUS_BUFFER_TOO_SMALL; } break; } case MSDSM_DEVICE_PERFGuidIndex: { *DataLength = BufferAvail; status = DsmpQueryDevicePerf(DsmContext, DsmIds, BufferAvail, DataLength, Buffer); break; } case MSDSM_WMI_METHODSGuidIndex: { // // Even though this class only has methods, we need to respond // to any queries for it since WMI expects that there is an actual // instance of the class on which to execute the method // sizeNeeded = sizeof(ULONG); *DataLength = sizeNeeded; if (BufferAvail >= sizeNeeded) { *InstanceLengthArray = sizeNeeded; status = STATUS_SUCCESS; } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DsmQueryData (DsmIds %p): Buffer too small in query data. Needed %d, Given %d.\n", DsmIds, sizeNeeded, BufferAvail)); status = STATUS_BUFFER_TOO_SMALL; } break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmQueryData (DsmIds %p): Unknown GuidIndex %d in DsmQueryData.\n", DsmIds, GuidIndex)); *DataLength = 0; break; } } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmQueryData (DsmIds %p): Exiting function with status 0x%x.\n", DsmIds, status)); return status; } NTSTATUS DsmpQueryLoadBalancePolicy( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN ULONG DsmWmiVersion, _In_ IN ULONG InBufferSize, _In_ IN PULONG OutBufferSize, _Out_writes_bytes_(*OutBufferSize) OUT PVOID Buffer ) /*+++ Routine Description: This routine returns the current Load Balance policy settings for the given device. Arguements: DsmContext - Global DSM context DsmIds - DSM Ids for the given device DsmWmiVersion - version of the MPIO_DSM_Path class to use InBufferSize - Size of the input buffer OutBufferSize - Size of the output buffer Buffer - Buffer in which the current Load Balance policy settings is returned, if the buffer is big enough Return Value: STATUS_SUCCESS on success Appropriate error code on error. --*/ { PDSM_GROUP_ENTRY groupEntry; PDSM_DEVICE_INFO devInfo; PDSM_DEVICE_INFO rtpgDeviceInfo = NULL; ULONG inx; ULONG sizeNeeded; NTSTATUS status = STATUS_SUCCESS; KIRQL irql; PDSM_Load_Balance_Policy_V2 supportedLBPolicies; PMPIO_DSM_Path_V2 dsmPath; PDSM_FAILOVER_GROUP foGroup; ULONG SpecialHandlingFlag = 0; UNREFERENCED_PARAMETER(InBufferSize); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQueryLoadBalancePolicy (DsmIds %p): Entering function.\n", DsmIds)); // // At least one device should be given // if (DsmIds->Count == 0) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryLoadBalancePolicy (DsmIds %p): No DSM Ids given in DsmpQueryLoadBalancePolicy.\n", DsmIds)); *OutBufferSize = 0; status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpQueryLoadBalancePolicy; } // // Compute the size needed for returning LoadBalance policy information // if (DsmWmiVersion == DSM_WMI_VERSION_1) { sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths)); sizeNeeded += (DsmIds->Count) * sizeof(MPIO_DSM_Path); } else { sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths)); sizeNeeded += (DsmIds->Count * sizeof(MPIO_DSM_Path_V2)); } if (*OutBufferSize < sizeNeeded) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryLoadBalancePolicy (DsmIds %p): Output buffer too small for QueryLBPolicy.\n", DsmIds)); *OutBufferSize = sizeNeeded; status = STATUS_BUFFER_TOO_SMALL; goto __Exit_DsmpQueryLoadBalancePolicy; } // // Set the size of the data returned to user // *OutBufferSize = sizeNeeded; // // Zero out the output buffer first // RtlZeroMemory(Buffer, sizeNeeded); devInfo = DsmIds->IdList[0]; DSM_ASSERT(devInfo && devInfo->DeviceSig == DSM_DEVICE_SIG); groupEntry = devInfo->Group; // // Send down an RTPG to get the current state info if implicit transitions // are supported, since the states may have changed from under us. // Storages that support both implicit and explicit transitions that haven't // allowed us to turn OFF their implicit transitions, may have also changed // TPG states from under us. So do this for such storages also. // if (!DsmpIsSymmetricAccess(devInfo) && devInfo->ALUASupport != DSM_DEVINFO_ALUA_EXPLICIT) { rtpgDeviceInfo = DsmpGetActivePathToBeUsed(groupEntry, FALSE, SpecialHandlingFlag); if (!rtpgDeviceInfo) { BOOLEAN sendTPG = FALSE; rtpgDeviceInfo = DsmpFindStandbyPathToActivateALUA(groupEntry, &sendTPG, SpecialHandlingFlag); } if (rtpgDeviceInfo) { status = DsmpGetDeviceALUAState(DsmContext, rtpgDeviceInfo, NULL); } } irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); // // If an RTPG was sent down, update all the devInfo states. // if (NT_SUCCESS(status) && rtpgDeviceInfo) { DsmpAdjustDeviceStatesALUA(groupEntry, NULL, SpecialHandlingFlag); } supportedLBPolicies = &(((PDSM_QueryLBPolicy_V2)Buffer)->LoadBalancePolicy); supportedLBPolicies->Version = DSM_WMI_VERSION; supportedLBPolicies->LoadBalancePolicy = groupEntry->LoadBalanceType; supportedLBPolicies->DSMPathCount = DsmIds->Count; dsmPath = supportedLBPolicies->DSM_Paths; // // Indicate which path is active and which path(s) are standby paths // inx = 0; while (inx < DsmIds->Count) { devInfo = (PDSM_DEVICE_INFO)DsmIds->IdList[inx]; dsmPath->PathWeight = devInfo->PathWeight; dsmPath->Reserved = DSM_STATE_ACTIVE_OPTIMIZED_SUPPORTED; if (devInfo->ALUASupport == DSM_DEVINFO_ALUA_NOT_SUPPORTED) { if (DsmWmiVersion > DSM_WMI_VERSION_1) { dsmPath->TargetPortGroup_State = DSM_DEV_NOT_USED_STATE; } dsmPath->Reserved |= DSM_STATE_STANDBY_SUPPORTED; } else { if (DsmWmiVersion > DSM_WMI_VERSION_1) { dsmPath->TargetPortGroup_State = devInfo->TargetPortGroup->AsymmetricAccessState; dsmPath->TargetPortGroup_Preferred = devInfo->TargetPortGroup->Preferred; dsmPath->TargetPortGroup_Identifier = devInfo->TargetPortGroup->Identifier; if (devInfo->TargetPort) { dsmPath->TargetPort_Identifier = devInfo->TargetPort->Identifier; } if (groupEntry->Symmetric) { // // For certain policies like FOO and RRWS, we need to be able to put // path in standby. // dsmPath->Reserved |= DSM_STATE_STANDBY_SUPPORTED; } } dsmPath->Reserved |= devInfo->TargetPortGroup->ActiveUnoptimizedSupported ? DSM_STATE_ACTIVE_UNOPTIMIZED_SUPPORTED : 0; dsmPath->Reserved |= devInfo->TargetPortGroup->StandBySupported ? DSM_STATE_STANDBY_SUPPORTED : 0; dsmPath->Reserved |= devInfo->TargetPortGroup->UnavailableSupported ? DSM_STATE_UNAVAILABLE_SUPPORTED : 0; } groupEntry = devInfo->Group; if (DsmWmiVersion > DSM_WMI_VERSION_1) { dsmPath->SymmetricLUA = groupEntry->Symmetric; dsmPath->ALUASupport = devInfo->ALUASupport; } if (DsmpIsDeviceFailedState(devInfo->State) || !DsmpIsDeviceInitialized(devInfo)) { dsmPath->PrimaryPath = FALSE; dsmPath->DsmPathId = 0; if (DsmWmiVersion > DSM_WMI_VERSION_1) { dsmPath->OptimizedPath = dsmPath->PreferredPath = FALSE; dsmPath->FailedPath = TRUE; } } else { foGroup = devInfo->FailGroup; dsmPath->DsmPathId = (ULONGLONG)((ULONG_PTR)foGroup->PathId); if (DsmpIsDeviceStateActive(devInfo->State)) { dsmPath->PrimaryPath = TRUE; } if (DsmWmiVersion > DSM_WMI_VERSION_1) { if (devInfo->State == DSM_DEV_ACTIVE_OPTIMIZED || devInfo->State == DSM_DEV_STANDBY) { dsmPath->OptimizedPath = TRUE; } if (((ULONGLONG)((ULONG_PTR)(foGroup->PathId))) == (devInfo->Group->PreferredPath)) { dsmPath->PreferredPath = TRUE; } } } #if DBG if (!dsmPath->PrimaryPath && !dsmPath->FailedPath) { NT_ASSERT(groupEntry->LoadBalanceType != DSM_LB_ROUND_ROBIN && groupEntry->LoadBalanceType != DSM_LB_WEIGHTED_PATHS && groupEntry->LoadBalanceType != DSM_LB_DYN_LEAST_QUEUE_DEPTH && groupEntry->LoadBalanceType != DSM_LB_LEAST_BLOCKS); } #endif dsmPath = DsmWmiVersion == DSM_WMI_VERSION_1 ? (PVOID)((PUCHAR)dsmPath + sizeof(MPIO_DSM_Path)) : (PVOID)((PUCHAR)dsmPath + sizeof(MPIO_DSM_Path_V2)); inx++; } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); __Exit_DsmpQueryLoadBalancePolicy: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQueryLoadBalancePolicy (DsmIds %p): Exiting with status %x.\n", DsmIds, status)); return status; } NTSTATUS DsmpQuerySupportedLBPolicies( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN ULONG BufferAvail, _In_ IN ULONG DsmWmiVersion, _Out_ OUT PULONG OutBufferSize, _Out_writes_to_(BufferAvail, *OutBufferSize) OUT PUCHAR Buffer ) /*+++ Routine Description: This routine returns the load balance policies supported by this DSM for the given LUN (specified by the DsmIds). Arguements: DsmContext - Global DSM context DsmIds - DSM Ids for the given device BufferAvail - Size of buffer available. DsmWmiVersion - Indicates which version of MPIO_DSMPath to use. OutBufferSize - Size of the output buffer. Buffer - Buffer in which the supported Load Balance policies are returned, if the buffer is big enough. Return Value: STATUS_SUCCESS on success Appropriate error code on error. --*/ { PDSM_QuerySupportedLBPolicies_V2 supportedLBPolicies; PDSM_Load_Balance_Policy_V2 dsmLBPolicy; ULONG sizeNeeded; ULONG policyCount; ULONG inx; NTSTATUS status = STATUS_SUCCESS; BOOLEAN skipRR = FALSE; PDSM_DEVICE_INFO devInfo = NULL; PUCHAR endOfBuffer; UNREFERENCED_PARAMETER(DsmContext); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI,"DsmpQuerySupportedLBPolicies (DsmIds %p): Entering function.\n", DsmIds)); // // At least one device should be given // if (DsmIds->Count == 0) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQuerySupportedLBPolicies (DsmIds %p): No DSM Ids given in DsmpQuerySupportedLBPolicies.\n", DsmIds)); *OutBufferSize = 0; status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpQuerySupportedLBPolicies; } devInfo = DsmIds->IdList[0]; DSM_ASSERT(devInfo && devInfo->DeviceSig == DSM_DEVICE_SIG); policyCount = DSM_NUMBER_OF_LB_POLICIES; // // Round Robin policy is not supported for arrays that are AAA. // if (!DsmpIsSymmetricAccess(devInfo)) { skipRR = TRUE; policyCount--; } if (DsmWmiVersion == DSM_WMI_VERSION_1) { sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(DSM_QuerySupportedLBPolicies, Supported_LB_Policies)); sizeNeeded += policyCount * AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths)); } else { sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(DSM_QuerySupportedLBPolicies_V2, Supported_LB_Policies)); sizeNeeded += policyCount * AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths)); } // // Set the size of the data returned to user or needed but not provided. // *OutBufferSize = sizeNeeded; if (sizeNeeded > BufferAvail) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQuerySupportedLBPolicies (Buffer %p): Output buffer too small. Size needed = %u.\n", Buffer, sizeNeeded)); status = STATUS_BUFFER_TOO_SMALL; goto __Exit_DsmpQuerySupportedLBPolicies; } endOfBuffer = Buffer + sizeNeeded - 1; // // Zero out the output buffer first // supportedLBPolicies = (PDSM_QuerySupportedLBPolicies_V2)Buffer; RtlZeroMemory(Buffer, sizeNeeded); supportedLBPolicies->SupportedLBPoliciesCount = policyCount; if (DsmWmiVersion > DSM_WMI_VERSION_1) { dsmLBPolicy = &(supportedLBPolicies->Supported_LB_Policies[0]); } else { dsmLBPolicy = (PVOID)&(((PDSM_QuerySupportedLBPolicies)supportedLBPolicies)->Supported_LB_Policies[0]); } // // All Load Balance policies are supported in Windows Server 2003 // and above. // for (inx = 0; inx < DSM_NUMBER_OF_LB_POLICIES; inx++) { // // Skip reporting Round Robin for AAA arrays. // if (((inx + 1) == DSM_LB_ROUND_ROBIN) && skipRR) { continue; } if (DsmWmiVersion > DSM_WMI_VERSION_1) { if ((PUCHAR)dsmLBPolicy + AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths)) - 1 > endOfBuffer) { status = STATUS_BUFFER_TOO_SMALL; break; } } else { if ((PUCHAR)dsmLBPolicy + AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths)) - 1 > endOfBuffer) { status = STATUS_BUFFER_TOO_SMALL; break; } } dsmLBPolicy->Version = DSM_WMI_VERSION; // // The value set for LoadBalancePolicy is based on // the #define for LB policies in LBPolicy.h // dsmLBPolicy->LoadBalancePolicy = inx + 1; // // Point to the next DSM_Load_Balance_Policy area // if (DsmWmiVersion > DSM_WMI_VERSION_1) { dsmLBPolicy = (PDSM_Load_Balance_Policy_V2)((PUCHAR)dsmLBPolicy + AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths))); } else { dsmLBPolicy = (PVOID)((PUCHAR)dsmLBPolicy + AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths))); } } __Exit_DsmpQuerySupportedLBPolicies: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQuerySupportedLBPolicies (DsmIds %p): Exiting function with status %x.\n", DsmIds, status)); return status; } NTSTATUS DsmExecuteMethod( _In_ IN PVOID DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN PIRP Irp, _In_ IN ULONG GuidIndex, _In_ IN ULONG InstanceIndex, _In_ IN ULONG MethodId, _In_ IN ULONG InBufferSize, _In_ IN PULONG OutBufferSize, _Inout_ IN OUT PUCHAR Buffer, ... ) /*++ Routine Description: This routine handles the invocation of WMI methods defined in the DSM mof. Arguments: DsmContext - Global DSM context DsmIds - DSM Ids Irp - The WMI Irp GuidIndex - Index into the WMIGUIDINFO array InstanceIndex - Index value indicating for which instance data should be returned. MethodId - Specifies which method to invoke. InBufferSize - Buffer size, in bytes, of input parameter data. OutBufferSize - Buffer size, in bytes, of output data. Buffer - Buffer to which the data is read/written. Return Value: Status of the method, or STATUS_WMI_ITEMID_NOT_FOUND --*/ { NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND; UNREFERENCED_PARAMETER(DsmContext); UNREFERENCED_PARAMETER(InstanceIndex); UNREFERENCED_PARAMETER(Irp); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmExecuteMethod (DsmIds %p): Entering function.\n", DsmIds)); // // This should be the index for ExecMethod Index // if (GuidIndex == DSM_LBOperationsGUID_Index) { switch (MethodId) { case DsmSetLoadBalancePolicy: case DsmSetLoadBalancePolicyALUA: { status = DsmpSetLoadBalancePolicy(DsmContext, DsmIds, (MethodId == DsmSetLoadBalancePolicy) ? DSM_WMI_VERSION_1 : DSM_WMI_VERSION_2, InBufferSize, OutBufferSize, Buffer); break; } default: { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmExecuteMethod (DsmIds %p): Unknown MethodId %d in DsmExecuteMethod.\n", DsmIds, MethodId)); status = STATUS_WMI_ITEMID_NOT_FOUND; break; } } } else if (GuidIndex == MSDSM_WMI_METHODSGuidIndex) { if (MethodId == MSDsmClearCounters) { status = DsmpClearPerfCounters(DsmContext, DsmIds); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmExecuteMethod (DsmIds %p): Unknown MethodId %d for GuidIndex %d in DsmExecuteMethod.\n", DsmIds, MethodId, GuidIndex)); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmExecuteMethod (DsmIds %p): Unknown GuidIndex %d in DsmExecuteMethod.\n", DsmIds, GuidIndex)); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmExecuteMethod (DsmIds %p): Exiting function with status 0x%x.\n", DsmIds, status)); return status; } NTSTATUS DsmpClearLoadBalancePolicy( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds ) /*++ Routine Description: This routine is called to clear the LUN-specific load balance policy for the given device. First, the routine will try to clear the "explicitly set" registry key for the device. If this fails, the whole routine is aborted. If the registry key is successfully cleared, the following happens: 1. Check to see if there is a target-wide load balance policy set for this device's VID/PID. If yes, we set the device's load balance policy accordingly and return. 2. Check to see if there is an MSDSM-wide load balance policy set. If yes, we set the device's load balance policy accordingly and return. 3. If steps 1 and 2 fall through, we set the device's load balance policy to RR, or RRWS if ALUA is enabled. Arguements: DsmContext - Global DSM context DsmIds - DSM Ids for the given device Return Value: Appropriate status indicating the error if the input is malformed or if the function was unable to clear the load balance policy. STATUS_SUCCESS on success --*/ { NTSTATUS status = STATUS_SUCCESS; PDSM_DEVICE_INFO deviceInfo = NULL; PDSM_GROUP_ENTRY group = NULL; HANDLE lbSettingsKey = NULL; HANDLE deviceKey = NULL; UNICODE_STRING subKeyName; OBJECT_ATTRIBUTES objectAttributes; DSM_LOAD_BALANCE_TYPE loadBalanceType; ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG); ULONG devInfoIndex; ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpClearLoadBalancePolicy (DsmIds %p): Entering function.\n", DsmIds)); // // There should be at least one device // if (DsmIds->Count == 0) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DsmpClearLoadBalancePolicy (DsmIds %p): No DSM Ids given.\n", DsmIds)); status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpClearLoadBalancePolicy; } deviceInfo = (PDSM_DEVICE_INFO)DsmIds->IdList[0]; group = deviceInfo->Group; // // First open LoadBalanceSettings key under the Services key // status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpClearLoadBalancePolicy (DevName %ws): Failed to open LB Settings key. Status %x.\n", group->RegistryKeyName, status)); goto __Exit_DsmpClearLoadBalancePolicy; } // // Now open the key under which the LB settings for the given device is stored // and clear the DsmLoadBalancePolicyExplicitlySet key. // RtlInitUnicodeString(&subKeyName, group->RegistryKeyName); InitializeObjectAttributes(&objectAttributes, &subKeyName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), lbSettingsKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes); if (NT_SUCCESS(status)) { UCHAR explicitlySet = FALSE; status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, deviceKey, DSM_POLICY_EXPLICITLY_SET, REG_BINARY, &explicitlySet, sizeof(UCHAR)); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpClearLoadBalancePolicy (DevName %ws): Failed to clear DsmLoadBalancePolicyExplicitlySet key.\n", group->RegistryKeyName)); goto __Exit_DsmpClearLoadBalancePolicy; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpClearLoadBalancePolicy (DevName %ws): Failed to open device subkey.\n", group->RegistryKeyName)); goto __Exit_DsmpClearLoadBalancePolicy; } // // Set the defaults. These will be used if no target-wide or MSDSM-wide // load balance policies are set. // group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY; loadBalanceType = DSM_LB_ROUND_ROBIN; preferredPath = 0; // // Check to see if target-wide (VID/PID) LB policy is set for this device. // status = DsmpQueryTargetLBPolicyFromRegistry(deviceInfo, &loadBalanceType, &preferredPath); if (NT_SUCCESS(status)) { group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_VID_PID; } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) { // // Since the policy hasn't been set for this VID/PID, check if // overall MSDSM-wide policy has been set. // status = DsmpQueryDsmLBPolicyFromRegistry(&loadBalanceType, &preferredPath); if (NT_SUCCESS(status)) { group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_DSM_WIDE; } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpClearLoadBalancePolicy (DevInfo %p): Failed to query Dsm overall LB policy from registry. Status %x.\n", deviceInfo, status)); NT_ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND); status = STATUS_SUCCESS; } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DsmpClearLoadBalancePolicy (DevInfo %p): Failed to query VID/PID LB policy from registry. Status %x.\n", deviceInfo, status)); NT_ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND); status = STATUS_SUCCESS; } // // If the storage is ALUA enabled and we specified Round Robin, change // it to Round Robin with Subset instead. // if (!DsmpIsSymmetricAccess(deviceInfo) && loadBalanceType == DSM_LB_ROUND_ROBIN) { loadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET; } // // Finally set the load balance policy and the preferred path. // group->LoadBalanceType = loadBalanceType; group->PreferredPath = preferredPath; // // Update the path states in accordance with the new policy. // for (devInfoIndex = 0; devInfoIndex < DSM_MAX_PATHS; devInfoIndex++) { DsmpSetNewDefaultLBPolicy(DsmContext, group->DeviceList[devInfoIndex], group->LoadBalanceType, SpecialHandlingFlag); } __Exit_DsmpClearLoadBalancePolicy: if (deviceKey) { ZwClose(deviceKey); } if (lbSettingsKey) { ZwClose(lbSettingsKey); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpClearLoadBalancePolicy (DsmIds %p): Exiting function with status 0x%x.\n", DsmIds, status)); return status; } NTSTATUS DsmpSetLoadBalancePolicy( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN ULONG DsmWmiVersion, _In_ IN ULONG InBufferSize, _In_ IN PULONG OutBufferSize, _In_ IN PVOID Buffer ) /*++ Routine Description: This routine is called to set the load balance policy for the given device. If zero is passed in as the load balance policy, the LUN-specific load balance policy will attempt to be cleared. See DsmpClearLoadBalancePolicy for more details. Arguements: DsmContext - Global DSM context DsmIds - DSM Ids for the given device DsmWmiVersion - version of the MPIO_DSM_Path class to use InBufferSize - Size of the input buffer OutBufferSize - Size of the output buffer Buffer - Buffer for input\output data Return Value: STATUS_BUFFER_TOO_SMALL - If the input buffer is too small Appropriate status indicating the error if the input is malformed. STATUS_SUCCESS on success --*/ { PDsmSetLoadBalancePolicyALUA_IN setLoadBalancePolicyIN = (PDsmSetLoadBalancePolicyALUA_IN) Buffer; PDsmSetLoadBalancePolicyALUA_OUT setLoadBalancePolicyOUT = (PDsmSetLoadBalancePolicyALUA_OUT) Buffer; PVOID supportedLBPolicies; PMPIO_DSM_Path_V2 dsmPath; ULONG inx = 0; ULONG jnx; NTSTATUS status = STATUS_SUCCESS; BOOLEAN lengthOkay = TRUE; PDSM_DEVICE_INFO devInfo = NULL; PDSM_DEVICE_INFO tempDevInfo = NULL; PDSM_GROUP_ENTRY groupEntry; PDSM_LOAD_BALANCE_POLICY_SETTINGS savedLBSettings = NULL; KIRQL irql; BOOLEAN optimized = TRUE; BOOLEAN preferred = FALSE; ULONG activePaths = 0; ULONG activeTPGs = 0; ULONG numberDevInfoChanged = 0; ULONG numberPreferredPaths = 0; DSM_LOAD_BALANCE_TYPE loadBalancePolicy; BOOLEAN sendSTPG = FALSE; ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG); ULONG SpecialHandlingFlag = 0; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Entering function.\n", DsmIds)); // // There should be at least one device // if (DsmIds->Count == 0) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): No DSM Ids given.\n", DsmIds)); status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpSetLoadBalancePolicy; } groupEntry = ((PDSM_DEVICE_INFO)DsmIds->IdList[0])->Group; if (DsmWmiVersion == DSM_WMI_VERSION_1) { if (*OutBufferSize < sizeof(DsmSetLoadBalancePolicy_OUT)) { *OutBufferSize = sizeof(DsmSetLoadBalancePolicy_OUT); lengthOkay = FALSE; } } else { if (*OutBufferSize < sizeof(DsmSetLoadBalancePolicyALUA_OUT)) { *OutBufferSize = sizeof(DsmSetLoadBalancePolicyALUA_OUT); lengthOkay = FALSE; } } if (!lengthOkay) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Buffer too small for SetLBPolicy.\n", DsmIds)); status = STATUS_BUFFER_TOO_SMALL; goto __Exit_DsmpSetLoadBalancePolicy; } *OutBufferSize = (DsmWmiVersion == DSM_WMI_VERSION_1) ? sizeof(DsmSetLoadBalancePolicy_OUT) : sizeof(DsmSetLoadBalancePolicyALUA_OUT); // // If the user specified zero as the load balance policy, we need to clear the // LUN-specific load balance policy. // if (setLoadBalancePolicyIN->LoadBalancePolicy.LoadBalancePolicy == 0) { status = DsmpClearLoadBalancePolicy(DsmContext, DsmIds); goto __Exit_DsmpSetLoadBalancePolicy; } status = DsmpValidateSetLBPolicyInput(DsmContext, DsmIds, DsmWmiVersion, Buffer, InBufferSize); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Failed to validate input. Status %x.\n", DsmIds, status)); goto __Exit_DsmpSetLoadBalancePolicy; } // // At this point the Reserved field in each MPIO_DSM_Path should // contain the respective Device Info // supportedLBPolicies = &(setLoadBalancePolicyIN->LoadBalancePolicy); loadBalancePolicy = ((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->LoadBalancePolicy; irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); // // Cache each DeviceInfo's current state. // This will be used to rollback in case of errors. // DsmpSaveDeviceState(supportedLBPolicies, DsmWmiVersion); while (inx < ((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSMPathCount) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[inx]); optimized = TRUE; preferred = FALSE; } else { dsmPath = &(((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSM_Paths[inx]); optimized = dsmPath->OptimizedPath ? TRUE : FALSE; preferred = dsmPath->PreferredPath ? TRUE : FALSE; if (preferred && loadBalancePolicy == DSM_LB_FAILOVER) { preferredPath = dsmPath->DsmPathId; if (preferredPath != 0) { numberPreferredPaths++; } if (numberPreferredPaths > 1) { DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); status = STATUS_INVALID_PARAMETER; break; } } } // // Reserved field in MPIO_DSM_Path is set to DeviceInfo in // DsmpValidateSetLBPolicyInput routine. // devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved; if (!devInfo) { inx++; continue; } else { if (!tempDevInfo) { tempDevInfo = devInfo; if (loadBalancePolicy == DSM_LB_ROUND_ROBIN || loadBalancePolicy == DSM_LB_ROUND_ROBIN_WITH_SUBSET) { InterlockedExchangePointer(&(groupEntry->PathToBeUsed), NULL); } } } if (!DsmpIsDeviceFailedState(devInfo->State)) { if (devInfo->ALUAState == DSM_DEV_ACTIVE_OPTIMIZED) { activeTPGs++; } if (dsmPath->PrimaryPath) { // // Optimized flag decides between AO and AU // if (optimized) { // // For implicit-only ALUA, state cannot be explicitly changed to A/O // if (!DsmpIsSymmetricAccess(devInfo) && devInfo->ALUASupport == DSM_DEVINFO_ALUA_IMPLICIT) { // // While we can mask off acutal A/O to be A/U, there is no // way to explicitly make non-A/O state A/O // if (devInfo->ALUAState != DSM_DEV_ACTIVE_OPTIMIZED) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Can't make non-AO path A/O for Implicit-only transitions.\n", DsmIds)); DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); status = STATUS_INVALID_PARAMETER; break; } } numberDevInfoChanged++; devInfo->State = DSM_DEV_ACTIVE_OPTIMIZED; activePaths++; // // Check to see if the actual making of this path state A/O // will require an STPG to be sent down. // if (devInfo->TargetPortGroup && devInfo->ALUAState != DSM_DEV_ACTIVE_OPTIMIZED) { sendSTPG = TRUE; } if (loadBalancePolicy == DSM_LB_FAILOVER) { // // Only ONE path can be specified as AO for FailOverOnly policy. // if (activePaths > 1) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): More than one AO node given for FO Only.\n", DsmIds)); DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); status = STATUS_INVALID_PARAMETER; break; } } if (loadBalancePolicy == DSM_LB_ROUND_ROBIN || loadBalancePolicy == DSM_LB_ROUND_ROBIN_WITH_SUBSET) { if (!groupEntry->PathToBeUsed) { InterlockedExchangePointer(&(groupEntry->PathToBeUsed), (PVOID)devInfo->FailGroup); } } } else { // // This is an ActiveUnoptimized path // devInfo->State = DSM_DEV_ACTIVE_UNOPTIMIZED; // // For LB policy RR, WP, LB and LQD, all paths must be in A/O // state. However, this is not possible for ALUA storages. // For these storages, A/U is allowable only if that is the // access state that the TPG is in. // if (loadBalancePolicy == DSM_LB_ROUND_ROBIN || loadBalancePolicy == DSM_LB_WEIGHTED_PATHS || loadBalancePolicy == DSM_LB_DYN_LEAST_QUEUE_DEPTH || loadBalancePolicy == DSM_LB_LEAST_BLOCKS) { if (devInfo->TargetPortGroup && devInfo->ALUAState != DSM_DEV_ACTIVE_UNOPTIMIZED) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Path (%u) specified in A/U state when TPG is in %u state (for LB %u).\n", DsmIds, inx, devInfo->ALUAState, loadBalancePolicy)); DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); status = STATUS_INVALID_PARAMETER; break; } } } } else { if (optimized) { // // This is a standby path // devInfo->State = DSM_DEV_STANDBY; } else { // // This is unavailable path // devInfo->State = DSM_DEV_UNAVAILABLE; } // // For RR, LQD, LB and WP, all paths must be in A/O state for non-ALUA // storage. For ALUA storage, the only time path states can be in // S/B or U/A is if the TPG itself is in that state. // if (loadBalancePolicy == DSM_LB_ROUND_ROBIN || loadBalancePolicy == DSM_LB_WEIGHTED_PATHS || loadBalancePolicy == DSM_LB_DYN_LEAST_QUEUE_DEPTH || loadBalancePolicy == DSM_LB_LEAST_BLOCKS) { if ((!devInfo->TargetPortGroup) || (devInfo->TargetPortGroup && devInfo->State != devInfo->ALUAState)) { // // No paths can be in SB or UA unless its TPG is in that state. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Path (%u) specified in non-active state for LB %u.\n", DsmIds, inx, loadBalancePolicy)); DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); status = STATUS_INVALID_PARAMETER; break; } } else if (loadBalancePolicy == DSM_LB_ROUND_ROBIN_WITH_SUBSET) { // // It is okay to set a path to be in S/B or U/A state in RRWS // if either the storage is non-ALUA, or if the storage is // ALUA but the TPG is in A/O (where it can be masked) or the // TPG is in the state that the path is being set to. // if ((devInfo->TargetPortGroup) && (devInfo->ALUAState != DSM_DEV_ACTIVE_OPTIMIZED && devInfo->State != devInfo->ALUAState)) { // // No paths can be in SB or UA unless its TPG is in that state. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Path (%u) (in TPG state %u) can't be specified in non-active state for LB %u.\n", DsmIds, inx, devInfo->ALUAState, loadBalancePolicy)); DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); status = STATUS_INVALID_PARAMETER; break; } } } } inx++; } if (NT_SUCCESS(status)) { // // If we arrive here, that means DsmpValidateSetLBPolicyInput already returned success. // The device info is found. // _Analysis_assume_(tempDevInfo != NULL); // // There must be at least one AO path. Unless there are no A/O TPGs. // eg. During a controller failover, it is possible that the TPG through // the TPG through other controller is still in non-A/O state and the // storage supports implicit transitions and is still in the midst of // making the transition of the non-A/O TPG to A/O. During such windows // the states for all paths will be non-A/O and there's nothing that can // be done about it. This is not an error condition. // if (!activePaths) { if ((tempDevInfo->ALUASupport == DSM_DEVINFO_ALUA_NOT_SUPPORTED) || (tempDevInfo->ALUASupport != DSM_DEVINFO_ALUA_NOT_SUPPORTED && activeTPGs)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): No active node given for LB %u.\n", DsmIds, loadBalancePolicy)); // // Roll back to DeviceState to the state it was before // processing this SetLB policy request // DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); status = STATUS_INVALID_PARAMETER; } } } if (NT_SUCCESS(status)) { // // If we arrive here, that means DsmpValidateSetLBPolicyInput already returned success. // The device info is found. // _Analysis_assume_(tempDevInfo != NULL); // // If device supports explicit transitions, we need to send down an // STPG to enforce A/O path selection if we need to make a path in a // non-A/O TPG active/optimized. // if (tempDevInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT && sendSTPG) { PUCHAR targetPortGroupsInfo = NULL; ULONG targetPortGroupsInfoLength = 0; PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR tpgDescriptor = NULL; // // Build the target port groups info to set the new states. // Send down an STPG for TPG descriptors for those devInfos' TPGs // that need to be in AO state. If this causes side-effects in // state transitions (these can't be considered implicit according // to the spec), fake the devInfo states to what was selected. // targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + activePaths * sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR); targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx, targetPortGroupsInfoLength, DSM_TAG_TARGET_PORT_GROUPS); if (targetPortGroupsInfo) { PDSM_DEVICE_INFO devInfoToUse = NULL; // // Set the new asymmetric access states for the the devices' target port groups // tpgDescriptor = (PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)(targetPortGroupsInfo + SPC3_TARGET_PORT_GROUPS_HEADER_SIZE); for (inx = 0, jnx = 0; inx < ((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSMPathCount; inx++) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[inx]); } else { dsmPath = &(((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSM_Paths[inx]); } devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved; if (!devInfo) { continue; } if (devInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) { tpgDescriptor->AsymmetricAccessState = devInfo->State; REVERSE_BYTES_SHORT(&tpgDescriptor->TPG_Identifier, &devInfo->TargetPortGroup->Identifier); tpgDescriptor = (PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)((PUCHAR)tpgDescriptor + sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)); jnx++; } if (devInfo->TempPreviousStateForLB == DSM_DEV_ACTIVE_OPTIMIZED) { devInfoToUse = devInfo; } } NT_ASSERT(jnx == numberDevInfoChanged); NT_ASSERT(devInfoToUse); if (devInfoToUse) { ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); status = DsmpSetTargetPortGroups(devInfoToUse->TargetObject, targetPortGroupsInfo, targetPortGroupsInfoLength); if (NT_SUCCESS(status)) { DsmpFreePool(targetPortGroupsInfo); targetPortGroupsInfo = NULL; targetPortGroupsInfoLength = 0; status = DsmpReportTargetPortGroups(devInfoToUse->TargetObject, &targetPortGroupsInfo, &targetPortGroupsInfoLength); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): STPG failed with status %x.\n", DsmIds, status)); DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); } irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); } if (NT_SUCCESS(status)) { ULONG index; PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup; status = DsmpParseTargetPortGroupsInformation(DsmContext, groupEntry, targetPortGroupsInfo, targetPortGroupsInfoLength); NT_ASSERT(NT_SUCCESS(status)); for (index = 0; index < DSM_MAX_PATHS; index++) { targetPortGroup = groupEntry->TargetPortGroupList[index]; if (targetPortGroup) { DsmpUpdateTargetPortGroupDevicesStates(targetPortGroup, targetPortGroup->AsymmetricAccessState); } } // // Update TPGs with new state // for (inx = 0; inx < ((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSMPathCount; inx++) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[inx]); } else { dsmPath = &(((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSM_Paths[inx]); } devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved; if (devInfo) { // // An explicit state transition can cause TPGs that were not specified // in the parameter list to also change (this is not considered to be // an implicit transition. It is SPC3 behavior and we must take // this into consideration and update the devInfo states. // This is an unfortunate side-effect in that the Admin may not get // the paths to be in the exact states that he has set. // if (devInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) { if (devInfo->ALUAState == DSM_DEV_ACTIVE_UNOPTIMIZED || devInfo->ALUAState == DSM_DEV_STANDBY || devInfo->ALUAState == DSM_DEV_UNAVAILABLE) { // // An A/O TPG's devInfos can be masked as A/U. // However, the reverse the is not true (ie. we can't // mark a non-A/O TPG's devInfo(s) to be in A/O state. // devInfo->State = devInfo->ALUAState; } } // // The devInfo->State has already been set. Update its previous state. // devInfo->PreviousState = devInfo->TempPreviousStateForLB; } } NT_ASSERT(jnx == numberDevInfoChanged); } } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Failed to allocate targetPortGroupsInfo.\n", DsmIds)); status = STATUS_INSUFFICIENT_RESOURCES; } } if (NT_SUCCESS(status)) { groupEntry->LoadBalanceType = loadBalancePolicy; if (loadBalancePolicy == DSM_LB_FAILOVER) { groupEntry->PreferredPath = preferredPath; } savedLBSettings = DsmpCopyLoadBalancePolicies(groupEntry, DsmWmiVersion, supportedLBPolicies); } else { // // Roll back to DeviceState to the state it was before // processing this SetLB policy request // DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion); } } if (NT_SUCCESS(status)) { // // LUN's LB policy has been explicitly set by Admin // groupEntry->LBPolicySelection = DSM_DEFAULT_LB_POLICY_LUN_EXPLICIT; // // Update the states and if appropriate, the path weight // DsmpUpdateDesiredStateAndWeight(groupEntry, DsmWmiVersion, supportedLBPolicies); // // Update the next path to be used for the group // devInfo = DsmpGetActivePathToBeUsed(groupEntry, DsmpIsSymmetricAccess(tempDevInfo), SpecialHandlingFlag); if (devInfo != NULL) { InterlockedExchangePointer(&(groupEntry->PathToBeUsed), (PVOID)devInfo->FailGroup); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): After setting LB policy No FOG available for group %p\n", DsmIds, groupEntry)); InterlockedExchangePointer(&(groupEntry->PathToBeUsed), NULL); } } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); if (NT_SUCCESS(status) && savedLBSettings) { DsmpPersistLBSettings(savedLBSettings); DsmpFreePool(savedLBSettings); } __Exit_DsmpSetLoadBalancePolicy: if (DsmWmiVersion == DSM_WMI_VERSION_1) { ((PDsmSetLoadBalancePolicy_OUT)setLoadBalancePolicyOUT)->Status = status; } else { setLoadBalancePolicyOUT->Status = status; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSetLoadBalancePolicy (DsmIds %p): Exiting function with status 0x%x.\n", DsmIds, status)); return status; } NTSTATUS DsmpValidateSetLBPolicyInput( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds, _In_ IN ULONG DsmWmiVersion, _In_ IN PVOID SetLoadBalancePolicyIN, _In_ IN ULONG InBufferSize ) /*++ Routine Description: This routine validates the input buffer given for setting Load Balance policy Arguements: DsmContext - DSM Global Context DsmIds - DSM Ids for the given device DsmWmiVersion - version of the MPIO_DSM_Path class to use SetLoadBalancePolicyIN - Describes the load balance policy to be set InBufferSize - Number of bytes in SetLoadBalancePolicyIN Return Value: STATUS_SUCCESS - if the input buffer is well formed Appropriate error status if the input buffer is malformed. --*/ { PDSM_Load_Balance_Policy_V2 supportedLBPolicies; PMPIO_DSM_Path_V2 dsmPath0; PMPIO_DSM_Path_V2 dsmPath1; NTSTATUS status = STATUS_SUCCESS; ULONG inx; ULONG jnx; ULONG sizeNeeded; KIRQL irql; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Entering function.\n", DsmIds)); // // Validate the input buffer for setting Load Balance policy // if (DsmWmiVersion > DSM_WMI_VERSION_1) { sizeNeeded = FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths); } else { sizeNeeded = FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths); } if (InBufferSize < sizeNeeded) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Insufficient buffer in SetLB. Expected %d, Given %d.\n", DsmIds, sizeNeeded, InBufferSize)); status = STATUS_BUFFER_TOO_SMALL; goto __Exit_DsmpValidateSetLBPolicyInput; } if (DsmWmiVersion == DSM_WMI_VERSION_1) { supportedLBPolicies = (PVOID)&(((PDsmSetLoadBalancePolicy_IN)SetLoadBalancePolicyIN)->LoadBalancePolicy); sizeNeeded += supportedLBPolicies->DSMPathCount * sizeof(MPIO_DSM_Path); } else { supportedLBPolicies = &(((PDsmSetLoadBalancePolicyALUA_IN)SetLoadBalancePolicyIN)->LoadBalancePolicy); sizeNeeded += supportedLBPolicies->DSMPathCount * sizeof(MPIO_DSM_Path_V2); } if (InBufferSize < sizeNeeded) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Insufficient buffer in SetLB. Expected %d, Given %d.\n", DsmIds, sizeNeeded, InBufferSize)); status = STATUS_BUFFER_TOO_SMALL; goto __Exit_DsmpValidateSetLBPolicyInput; } if (supportedLBPolicies->Version > DSM_WMI_VERSION) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): WMI Version mismatch. Expected %d, Given %d.\n", DsmIds, DSM_WMI_VERSION, supportedLBPolicies->Version)); status = DSM_UNSUPPORTED_VERSION; goto __Exit_DsmpValidateSetLBPolicyInput; } else if (supportedLBPolicies->Version < DSM_WMI_VERSION) { ULONG dsmWmiVersion = DSM_WMI_VERSION; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Use of older management app (WMI-Version %x) with newer DSM (WMI-Version %x).\n", DsmIds, supportedLBPolicies->Version, dsmWmiVersion)); NT_ASSERT(supportedLBPolicies->Version == DSM_WMI_VERSION); } if ((supportedLBPolicies->LoadBalancePolicy < DSM_LB_FAILOVER) || (supportedLBPolicies->LoadBalancePolicy > DSM_LB_LEAST_BLOCKS)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Invalid LB Policy %d.\n", DsmIds, supportedLBPolicies->LoadBalancePolicy)); status = DSM_INVALID_LOAD_BALANCE_POLICY; goto __Exit_DsmpValidateSetLBPolicyInput; } // // It is expected that the user provide LB policy settings // for all the paths and not just a subset of the paths. // if (supportedLBPolicies->DSMPathCount != DsmIds->Count) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Path Count %d not equal to DSM IDs count %d.\n", DsmIds, supportedLBPolicies->DSMPathCount, DsmIds->Count)); status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpValidateSetLBPolicyInput; } // // Make sure user did not provide duplicate path ids // for (inx = 0; inx < supportedLBPolicies->DSMPathCount && NT_SUCCESS(status); inx++) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath0 = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[inx]); } else { dsmPath0 = &(supportedLBPolicies->DSM_Paths[inx]); } dsmPath0->Reserved = 0; for (jnx = 0; jnx < supportedLBPolicies->DSMPathCount; jnx++) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath1 = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[jnx]); } else { dsmPath1 = &(supportedLBPolicies->DSM_Paths[jnx]); } if ((inx != jnx) && ((dsmPath0->DsmPathId == dsmPath1->DsmPathId) && (dsmPath1->DsmPathId != 0))) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Duplicate path id %I64x at %d and %d.\n", DsmIds, dsmPath0->DsmPathId, inx, jnx)); status = STATUS_INVALID_PARAMETER; break; } } } if (NT_SUCCESS(status)) { PDSM_DEVICE_INFO devInfo; PDSM_FAILOVER_GROUP foGroup; PVOID pathId; BOOLEAN foundPath; irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); // // Make sure the user has provided path id corresponding // to all the DSM IDs given to us. // for (inx = 0; inx < DsmIds->Count; inx++) { devInfo = DsmIds->IdList[inx]; if (!DsmpIsDeviceInitialized(devInfo)) { continue; } foGroup = devInfo->FailGroup; if (!foGroup) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): FO Group NULL for %p at index %d.\n", DsmIds, devInfo, inx)); status = STATUS_INVALID_PARAMETER; break; } foundPath = FALSE; for (jnx = 0; jnx < supportedLBPolicies->DSMPathCount; jnx++) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath0 = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[jnx]); } else { dsmPath0 = &(supportedLBPolicies->DSM_Paths[jnx]); } pathId = (PVOID) dsmPath0->DsmPathId; if (foGroup->PathId == pathId) { // // Found the device info corresponding to the given path. // Use the reserved field in MPIO_DSM_Path to store // the pointer to the device info. Device Info is used // later on to set the load balance policy for the device. // foundPath = TRUE; dsmPath0->Reserved = (ULONG_PTR) devInfo; // // If ALUA, RoundRobin is not an allowed LB policy since not all paths can // be in A/O state. RRWS must be used instead. // if (supportedLBPolicies->LoadBalancePolicy == DSM_LB_ROUND_ROBIN && !DsmpIsSymmetricAccess(devInfo)) { status = DSM_INVALID_LOAD_BALANCE_POLICY; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Invalid LB policy for ALUA. Status %x.\n", DsmIds, status)); } break; } } if (!foundPath) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Failed to find path %p for %p at index %d.\n", DsmIds, foGroup->PathId, devInfo, inx)); status = STATUS_INVALID_PARAMETER; break; } } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); } __Exit_DsmpValidateSetLBPolicyInput: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpValidateSetLBPolicyInput (DsmIds %p): Exiting function with status %x.\n", DsmIds, status)); return status; } VOID DsmpSaveDeviceState( _In_ IN PVOID SupportedLBPolicies, _In_ IN ULONG DsmWmiVersion ) /*+++ Routine Description: This routine saves the current Load Balance policy settings. If there is any error while setting the new policy given by the user, the saved values will be used to restore the old state. Note: This routine MUST be called with DsmContextLock held in Exclusive mode. Arguements: SupportedLBPolicies - New Load Balance policy values DsmWmiVersion - version of the MPIO_DSM_Path class to use Return Value: None --*/ { PDSM_DEVICE_INFO devInfo; PMPIO_DSM_Path_V2 dsmPath; ULONG inx; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSaveDeviceState (LBP %p): Entering function.\n", SupportedLBPolicies)); inx = 0; while (inx < ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)SupportedLBPolicies)->DSM_Paths[inx]); } else { dsmPath = &(((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSM_Paths[inx]); } devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved; if (devInfo) { devInfo->TempPreviousStateForLB = devInfo->State; } inx++; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpSaveDeviceState (LBP %p): Exiting function.\n", SupportedLBPolicies)); return; } VOID DsmpRestorePreviousDeviceState( _In_ IN PVOID SupportedLBPolicies, _In_ IN ULONG DsmWmiVersion ) /*++ Routine Description: This routine restores the old Load Balance policy settings. If there is any error while setting the new policy given by the user, the old state is restored from the saved state. Note: This routine MUST be called with DsmContextLock held in Exclusive mode. Arguements: SupportedLBPolicies - New Load Balance policy values DsmWmiVersion - version of the MPIO_DSM_Path class to use Return Value: None --*/ { PDSM_DEVICE_INFO devInfo; PMPIO_DSM_Path_V2 dsmPath; ULONG inx; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpRestorePreviousDeviceState (LBP %p): Entering function.\n", SupportedLBPolicies)); inx = 0; while (inx < ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)SupportedLBPolicies)->DSM_Paths[inx]); } else { dsmPath = &(((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSM_Paths[inx]); } devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved; if (devInfo) { devInfo->State = devInfo->TempPreviousStateForLB; } inx++; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpRestorePreviousDeviceState (LBP %p): Exiting function.\n", SupportedLBPolicies)); return; } VOID DsmpUpdateDesiredStateAndWeight( _In_ IN PDSM_GROUP_ENTRY Group, _In_ IN ULONG DsmWmiVersion, _In_ IN PVOID SupportedLBPolicies ) /*++ Routine Description: This routine updates the desired state and path weights based on admin's LB selection. Note: This routine MUST be called with DsmContextLock held in Exclusive mode. Arguements: Group - The group entry correponding to the pseudo-LUN. SupportedLBPolicies - New Load Balance policy values DsmWmiVersion - version of the MPIO_DSM_Path class to use Return Value: None --*/ { PMPIO_DSM_Path_V2 dsmPath; PDSM_DEVICE_INFO devInfo; ULONG inx; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpUpdatedDesiredState (Group %p): Entering function.\n", Group)); inx = 0; while (inx < ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount) { if (DsmWmiVersion == DSM_WMI_VERSION_1) { dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)SupportedLBPolicies)->DSM_Paths[inx]); } else { dsmPath = &(((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSM_Paths[inx]); } devInfo = (PDSM_DEVICE_INFO) dsmPath->Reserved; if (!devInfo) { inx++; continue; } DSM_ASSERT(devInfo->DeviceSig == DSM_DEVICE_SIG); NT_ASSERT(devInfo->Group == Group); // // We'll honor the chosen path for FOO for ALUA storage // since we know for a fact that the Admin has chosen the path. // We'll also honor path state in RRWS if it is different from TPG state // as that too is an indication that it was explicitly selected. // if ((DsmpIsSymmetricAccess(devInfo)) || (Group->LoadBalanceType == DSM_LB_FAILOVER) || (!DsmpIsSymmetricAccess(devInfo) && Group->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET && devInfo->State != devInfo->ALUAState)) { // // Check if this is the primary path or a standby path // if (dsmPath->PrimaryPath) { devInfo->DesiredState = DSM_DEV_ACTIVE_OPTIMIZED; if (DsmWmiVersion > DSM_WMI_VERSION_1) { if (!dsmPath->OptimizedPath) { devInfo->DesiredState = DSM_DEV_ACTIVE_UNOPTIMIZED; } } } else { devInfo->DesiredState = DSM_DEV_STANDBY; if (DsmWmiVersion > DSM_WMI_VERSION_1) { if (!dsmPath->OptimizedPath) { devInfo->DesiredState = DSM_DEV_UNAVAILABLE; } } } } else { devInfo->DesiredState = DSM_DEV_UNDETERMINED; } if (Group->LoadBalanceType == DSM_LB_WEIGHTED_PATHS) { devInfo->PathWeight = dsmPath->PathWeight; } inx++; } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpUpdatedDesiredState (Group %p): Exiting function.\n", Group)); return; } NTSTATUS DsmpQueryDevicePerf( _In_ PDSM_CONTEXT DsmContext, _In_ PDSM_IDS DsmIds, _In_ ULONG InBufferSize, _Inout_ PULONG OutBufferSize, _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer ) /*++ Routine Description: This routine returns the perf counters for each path for the device that corresponds to the passed in DsmIds. Arguements: DsmContext - Global DSM context DsmIds - DSM Ids for the given device InBufferSize - Size of the input buffer OutBufferSize - Size of the output buffer Buffer - Buffer in which the current Load Balance policy settings is returned, if the buffer is big enough Return Value: STATUS_SUCCESS on success Appropriate error code on error. --*/ { NTSTATUS status = STATUS_SUCCESS; PDSM_DEVICE_INFO devInfo; ULONG sizeNeeded; PMSDSM_DEVICE_PERF devicePerf; ULONG i; PMSDSM_DEVICEPATH_PERF pathPerf; KIRQL irql; UNREFERENCED_PARAMETER(InBufferSize); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQueryDevicePerf (DsmIds %p): Entering function.\n", DsmIds)); // // At least one device should be given // if (DsmIds->Count == 0) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryDevicePerf (DsmIds %p): No DSM Ids given.\n", DsmIds)); *OutBufferSize = 0; status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpQueryDevicePerf; } sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(MSDSM_DEVICE_PERF, PerfInfo)); sizeNeeded += (DsmIds->Count * sizeof(MSDSM_DEVICEPATH_PERF)); if (*OutBufferSize < sizeNeeded) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryDevicePerf (DsmIds %p): Output buffer too small for QueryLBPolicy.\n", DsmIds)); *OutBufferSize = sizeNeeded; status = STATUS_BUFFER_TOO_SMALL; goto __Exit_DsmpQueryDevicePerf; } // // Zero out the output buffer first // RtlZeroMemory(Buffer, sizeNeeded); #if DBG devInfo = DsmIds->IdList[0]; DSM_ASSERT(devInfo); DSM_ASSERT(devInfo->DeviceSig == DSM_DEVICE_SIG); #endif irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); devicePerf = (PMSDSM_DEVICE_PERF)Buffer; devicePerf->NumberPaths = DsmIds->Count; // // For each path, get the stats info // for (i = 0; i < DsmIds->Count; i++) { pathPerf = &devicePerf->PerfInfo[i]; devInfo = DsmIds->IdList[i]; if (DsmpIsDeviceInitialized(devInfo)) { pathPerf->PathId = (ULONGLONG)((ULONG_PTR)((devInfo->FailGroup)->PathId)); pathPerf->NumberReads = (devInfo->DeviceStats).NumberReads; pathPerf->NumberWrites = (devInfo->DeviceStats).NumberWrites; pathPerf->BytesRead = (devInfo->DeviceStats).BytesRead; pathPerf->BytesWritten = (devInfo->DeviceStats).BytesWritten; } } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); *OutBufferSize = sizeNeeded; __Exit_DsmpQueryDevicePerf: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQueryDevicePerf (DsmIds %p): Exiting function with status %x.\n", DsmIds, status)); return status; } NTSTATUS DsmpClearPerfCounters( _In_ IN PDSM_CONTEXT DsmContext, _In_ IN PDSM_IDS DsmIds ) /*++ Routine Description: This routine clears the perf counters for each path for the device that corresponds to the passed in DsmIds. Arguements: DsmContext - Global DSM context DsmIds - DSM Ids for the given device Return Value: STATUS_SUCCESS on success Appropriate error code on error. --*/ { NTSTATUS status = STATUS_SUCCESS; PDSM_DEVICE_INFO devInfo; KIRQL irql; ULONG i; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpClearPerfCounters (DsmIds %p): Entering function.\n", DsmIds)); // // At least one device should be given // if (DsmIds->Count == 0) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpClearPerfCounters (DsmIds %p): No DSM Ids given.\n", DsmIds)); status = STATUS_INVALID_PARAMETER; goto __Exit_DsmpClearPerfCounters; } irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock)); for (i = 0; i < DsmIds->Count; i++) { devInfo = DsmIds->IdList[i]; DSM_ASSERT(devInfo); DSM_ASSERT(devInfo->DeviceSig == DSM_DEVICE_SIG); if (devInfo) { (devInfo->DeviceStats).BytesRead = 0; (devInfo->DeviceStats).BytesWritten = 0; (devInfo->DeviceStats).NumberReads = 0; (devInfo->DeviceStats).NumberWrites = 0; } } ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql); __Exit_DsmpClearPerfCounters: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpClearPerfCounters (DsmIds %p): Exiting function with status %x.\n", DsmIds, status)); return status; } NTSTATUS DsmpQuerySupportedDevicesList( _In_ PDSM_CONTEXT DsmContext, _In_ ULONG InBufferSize, _Inout_ PULONG OutBufferSize, _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer ) /*++ Routine Description: This routine returns the list of devices that are supported by MSDSM. Arguements: DsmContext - Global DSM context InBufferSize - Size of the input buffer OutBufferSize - Size of the output buffer Buffer - Buffer in which the current Load Balance policy settings is returned, if the buffer is big enough Return Value: STATUS_SUCCESS on success Appropriate error code on error. --*/ { NTSTATUS status; ULONG sizeNeeded; PMSDSM_SUPPORTED_DEVICES_LIST supportedDeviceIds; PWSTR szIndex; PWSTR deviceIdIndex; ULONG numberDeviceIds = 0; ULONG index = 0; KIRQL oldIrql; PWSTR tempBuffer = NULL; UNREFERENCED_PARAMETER(InBufferSize); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQuerySupportedDevicesList (DsmContext %p): Entering function.\n", DsmContext)); // // It is possible that manually changes to the registry weren't yet picked up, // so query for the list in its current state. Failure to get this list is not // fatal, so ignore errors. // #if DBG status = DsmpGetDeviceList(DsmContext); NT_ASSERT(NT_SUCCESS(status)); #else DsmpGetDeviceList(DsmContext); #endif // // Since it is possible that this list may change if a new device arrival // gets processed at the same time as this query being processed, we need // to protect it. // KeAcquireSpinLock(&DsmContext->SupportedDevicesListLock, &oldIrql); tempBuffer = DsmpAllocatePool(NonPagedPoolNx, DsmContext->SupportedDevices.MaximumLength, DSM_TAG_REG_VALUE_RELATED); if (tempBuffer) { RtlCopyMemory(tempBuffer, DsmContext->SupportedDevices.Buffer, DsmContext->SupportedDevices.Length); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQuerySupportedDevicesList (DsmContext %p): Failed to allocate temporary list.\n", DsmContext)); status = STATUS_INSUFFICIENT_RESOURCES; KeReleaseSpinLock(&DsmContext->SupportedDevicesListLock, oldIrql); goto __Exit_DsmpQuerySupportedDevicesList; } KeReleaseSpinLock(&DsmContext->SupportedDevicesListLock, oldIrql); status = STATUS_SUCCESS; szIndex = tempBuffer; sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(MSDSM_SUPPORTED_DEVICES_LIST, DeviceId)); if (szIndex) { while (*szIndex) { szIndex += wcslen(szIndex) + 1; numberDeviceIds++; } sizeNeeded += numberDeviceIds * (MSDSM_MAX_DEVICE_ID_SIZE + sizeof(WNULL)); } if (*OutBufferSize < sizeNeeded) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQuerySupportedDevicesList (DsmContext %p): Output buffer too small for QuerySupportedDevicesList.\n", DsmContext)); *OutBufferSize = sizeNeeded; status = STATUS_BUFFER_TOO_SMALL; goto __Exit_DsmpQuerySupportedDevicesList; } // // Zero out the output buffer first // RtlZeroMemory(Buffer, sizeNeeded); *OutBufferSize = sizeNeeded; supportedDeviceIds = (PMSDSM_SUPPORTED_DEVICES_LIST)Buffer; supportedDeviceIds->NumberDevices = numberDeviceIds; for (index = 0, szIndex = tempBuffer, deviceIdIndex = supportedDeviceIds->DeviceId; index < numberDeviceIds; index++, szIndex += wcslen(szIndex) + 1, deviceIdIndex += MSDSM_MAX_DEVICE_ID_LENGTH) { *((PUSHORT)deviceIdIndex) = MSDSM_MAX_DEVICE_ID_SIZE; deviceIdIndex++; RtlStringCchCopyW(deviceIdIndex, MSDSM_MAX_DEVICE_ID_LENGTH - 1, szIndex); } __Exit_DsmpQuerySupportedDevicesList: if (tempBuffer) { DsmpFreePool(tempBuffer); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQuerySupportedDevicesList (DsmContext %p): Exiting function with status %x.\n", DsmContext, status)); return status; } NTSTATUS DsmpQueryTargetsDefaultPolicy( _In_ PDSM_CONTEXT DsmContext, _In_ ULONG InBufferSize, _Inout_ PULONG OutBufferSize, _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer ) /*++ Routine Description: This routine is used to build the target list (for which the override default LB policy was explicitly set), by querying the services key for the subkeys under "msdsm\Parameters\DsmTargetsLoadBalanceSetting" Arguements: Context - The DSM Context value. It contains storage for the target hardware ids and their default policy info. InBufferSize - Size of the input buffer OutBufferSize - Size of the output buffer Buffer - Buffer in which the current targets whose default policy settings is returned, if the buffer is big enough Return Value: STATUS_SUCCESS on success Appropriate error code on error. --*/ { ULONG sizeNeeded; PMSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY targetsPolicyInfo = (PMSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY)Buffer; PMSDSM_TARGET_DEFAULT_POLICY_INFO targetPolicyInfo; HANDLE targetsLBSettingKey = NULL; NTSTATUS status; PKEY_FULL_INFORMATION keyFullInfo = NULL; ULONG length = sizeof(KEY_FULL_INFORMATION); ULONG numSubKeys = 0; WCHAR vidPid[25] = {0}; PKEY_BASIC_INFORMATION keyBasicInfo = NULL; OBJECT_ATTRIBUTES objectAttributes; HANDLE targetKey = NULL; ULONG index = 0; RTL_QUERY_REGISTRY_TABLE queryTable[2]; DSM_LOAD_BALANCE_TYPE loadBalanceType; ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG); PWCHAR policyInfoIndex; UNICODE_STRING keyValueName; PKEY_VALUE_PARTIAL_INFORMATION keyValueInfo = NULL; UNREFERENCED_PARAMETER(InBufferSize); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Entering function.\n", DsmContext)); status = DsmpOpenTargetsLoadBalanceSettingKey(KEY_ALL_ACCESS, &targetsLBSettingKey); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to open Targets LB Setting key. Status %x.\n", DsmContext, status)); goto __Exit_DsmpQueryTargetsDefaultPolicy; } // // Query for number of subkeys // do { if (keyFullInfo) { DsmpFreePool(keyFullInfo); } keyFullInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED); if (!keyFullInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to allocate resources for key full info.\n", DsmContext)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpQueryTargetsDefaultPolicy; } status = ZwQueryKey(targetsLBSettingKey, KeyFullInformation, keyFullInfo, length, &length); } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to query key. Status %x.\n", DsmContext, status)); goto __Exit_DsmpQueryTargetsDefaultPolicy; } // // Calculate total buffer size required // numSubKeys = keyFullInfo->SubKeys; sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY, TargetDefaultPolicyInfo)); sizeNeeded += numSubKeys * sizeof(MSDSM_TARGET_DEFAULT_POLICY_INFO); if (*OutBufferSize < sizeNeeded) { *OutBufferSize = sizeNeeded; status = STATUS_BUFFER_TOO_SMALL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Buffer insufficient. Status %x.\n", DsmContext, status)); goto __Exit_DsmpQueryTargetsDefaultPolicy; } *OutBufferSize = sizeNeeded; RtlZeroMemory(Buffer, *OutBufferSize); targetsPolicyInfo->NumberDevices = numSubKeys; targetPolicyInfo = targetsPolicyInfo->TargetDefaultPolicyInfo; // // Now Enumerate all of the subkeys // for(index = 0; index < numSubKeys && NT_SUCCESS(status); index++) { UNICODE_STRING targetName; if (targetKey) { ZwClose(targetKey); targetKey = NULL; } length = sizeof(KEY_BASIC_INFORMATION); do { if (keyBasicInfo) { DsmpFreePool(keyBasicInfo); } keyBasicInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED); if (!keyBasicInfo) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to allocate resources for key basic info.\n", DsmContext)); status = STATUS_INSUFFICIENT_RESOURCES; goto __Exit_DsmpQueryTargetsDefaultPolicy; } // // Enumerate the index'th subkey // status = ZwEnumerateKey(targetsLBSettingKey, index, KeyBasicInformation, keyBasicInfo, length, &length); } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); // // Ignore errors - this is a best case effort. // if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to enumerate sub key's info. Status %x.\n", DsmContext, status)); status = STATUS_SUCCESS; continue; } RtlZeroMemory(vidPid, sizeof(vidPid)); RtlStringCbCopyNW(vidPid, sizeof(vidPid), keyBasicInfo->Name, keyBasicInfo->NameLength); RtlInitUnicodeString(&targetName, vidPid); // // Open a handle to the the target subkey. // InitializeObjectAttributes(&objectAttributes, &targetName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), targetsLBSettingKey, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey(&targetKey, KEY_ALL_ACCESS, &objectAttributes); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to open reg key %ws. Status %x.\n", DsmContext, vidPid, status)); goto __Exit_DsmpQueryTargetsDefaultPolicy; } RtlZeroMemory(queryTable, sizeof(queryTable)); queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = DSM_LOAD_BALANCE_POLICY; queryTable[0].EntryContext = &loadBalanceType; queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, targetKey, queryTable, targetKey, NULL); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to query LB Policy for %ws - error %x.\n", DsmContext, vidPid, status)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): LB Policy for %ws is %d.\n", DsmContext, vidPid, loadBalanceType)); RtlInitUnicodeString(&keyValueName, DSM_PREFERRED_PATH); length = sizeof(KEY_VALUE_PARTIAL_INFORMATION); do { DsmpFreePool(keyValueInfo); keyValueInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED); if (!keyValueInfo) { status = STATUS_INSUFFICIENT_RESOURCES; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to allocate resources for keyValueInfo (PP). Status %x.\n", DsmContext, status)); goto __Exit_DsmpQueryTargetsDefaultPolicy; } status = ZwQueryValueKey(targetKey, &keyValueName, KeyValuePartialInformation, keyValueInfo, length, &length); } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); if (NT_SUCCESS(status)) { NT_ASSERT(keyValueInfo->DataLength == sizeof(ULONGLONG)); preferredPath = *((ULONGLONG UNALIGNED *)keyValueInfo->Data); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): PreferredPath for %ws is %I64x.\n", DsmContext, vidPid, preferredPath)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Failed to query PreferredPath for %ws. Status %x.\n", DsmContext, vidPid, status)); } // // Copy over this target's policy info. // policyInfoIndex = targetPolicyInfo->HardwareId; *((PUSHORT)policyInfoIndex) = MSDSM_MAX_DEVICE_ID_SIZE; policyInfoIndex++; RtlStringCchCopyW((PWSTR)policyInfoIndex, MSDSM_MAX_DEVICE_ID_LENGTH - 1, vidPid); targetPolicyInfo->LoadBalancePolicy = loadBalanceType; targetPolicyInfo->PreferredPath = preferredPath; targetPolicyInfo++; } } __Exit_DsmpQueryTargetsDefaultPolicy: if (targetKey) { ZwClose(targetKey); } if (targetsLBSettingKey) { ZwClose(targetsLBSettingKey); } if (keyBasicInfo) { DsmpFreePool(keyBasicInfo); } if (keyValueInfo) { DsmpFreePool(keyValueInfo); } if (keyFullInfo) { DsmpFreePool(keyFullInfo); } TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQueryTargetsDefaultPolicy (Context %p): Exiting function with status %x.\n", DsmContext, status)); return status; } NTSTATUS DsmpQueryDsmDefaultPolicy( _In_ PDSM_CONTEXT DsmContext, _In_ ULONG InBufferSize, _Inout_ PULONG OutBufferSize, _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer ) /*++ Routine Description: This routine is used to return the override MSDSM-wide default LB policy if it was explicitly set, by querying the services key at "msdsm\Parameters" Arguements: Context - The DSM Context value. It contains storage for the target hardware ids and their default policy info. InBufferSize - Size of the input buffer OutBufferSize - Size of the output buffer Buffer - Buffer in which the current MSDSM-wide default policy is returned, if the buffer is big enough Return Value: STATUS_SUCCESS on success Appropriate error code on error. --*/ { PMSDSM_DEFAULT_LOAD_BALANCE_POLICY dsmPolicyInfo = (PMSDSM_DEFAULT_LOAD_BALANCE_POLICY)Buffer; NTSTATUS status; DSM_LOAD_BALANCE_TYPE loadBalanceType; ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG); UNREFERENCED_PARAMETER(InBufferSize); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQueryDsmDefaultPolicy (Context %p): Entering function.\n", DsmContext)); if (*OutBufferSize < sizeof(MSDSM_DEFAULT_LOAD_BALANCE_POLICY)) { *OutBufferSize = sizeof(MSDSM_DEFAULT_LOAD_BALANCE_POLICY); status = STATUS_BUFFER_TOO_SMALL; TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryDsmDefaultPolicy (Context %p): Buffer insufficient. Status %x.\n", DsmContext, status)); goto __Exit_DsmpQueryDsmDefaultPolicy; } *OutBufferSize = sizeof(MSDSM_DEFAULT_LOAD_BALANCE_POLICY); RtlZeroMemory(Buffer, *OutBufferSize); status = DsmpQueryDsmLBPolicyFromRegistry(&loadBalanceType, &preferredPath); if (NT_SUCCESS(status)) { dsmPolicyInfo->LoadBalancePolicy = loadBalanceType; dsmPolicyInfo->PreferredPath = (ULONGLONG)((ULONG_PTR)preferredPath); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryDsmDefaultPolicy (Context %p): LB policy = %u, Preferred path = %I64x.\n", DsmContext, dsmPolicyInfo->LoadBalancePolicy, dsmPolicyInfo->PreferredPath)); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DsmpQueryDsmDefaultPolicy (Context %p): Query for MSDSM-wide policy, status %x.\n", DsmContext, status)); } __Exit_DsmpQueryDsmDefaultPolicy: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "DsmpQueryDsmDefaultPolicy (Context %p): Exiting function with status %x.\n", DsmContext, status)); return status; } ================================================ FILE: tests/projects/windows/driver/wdm/msdsm/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("sampledsm") add_rules("wdk.env.wdm", "wdk.driver") add_values("wdk.tracewpp.flags", "-func:TracePrint((LEVEL,FLAGS,MSG,...))") add_files("*.c", {rules = "wdk.tracewpp"}) add_files("*.rc", "*.inf") add_files("*.mof|msdsm.mof") -- add file msdsm.mof and modify default wdk.mof.header for this file add_files("msdsm.mof", {values = {wdk_mof_header = "msdsmwmi.h"}}) set_pcheader("precomp.h") add_links("mpio") ================================================ FILE: tests/projects/windows/driver/wdm/perfcounters/kcs.c ================================================ /*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: kcs.c Abstract: This module contains sample code to demonstrate how to provide counter data from a kernel driver. Environment: Kernel mode only. --*/ #include #include "kcs.h" #include "kcsCounters.h" #include #include #pragma code_seg("PAGE") DRIVER_INITIALIZE DriverEntry; DRIVER_UNLOAD KcsUnload; NTSTATUS KcsAddGeometricInstance ( _In_ PPCW_BUFFER Buffer, _In_ PCWSTR Name, _In_ ULONG MinimalValue, _In_ ULONG Amplitude ) /*++ Routine Description: This utility function adds instance to the callback buffer. Arguments: Buffer - Data will be returned in this buffer. Name - Name of instances to be added. MinimalValue - Minimum value of the wave. Amplitude - Amplitude of the wave. Return Value: NTSTATUS indicating if the function succeeded. --*/ { ULONG Index; LARGE_INTEGER Timestamp; UNICODE_STRING UnicodeName; GEOMETRIC_WAVE_VALUES Values; PAGED_CODE(); KeQuerySystemTime(&Timestamp); Index = (Timestamp.QuadPart / 10000000) % 10; Values.Triangle = MinimalValue + Amplitude * abs(5 - Index) / 5; Values.Square = MinimalValue + Amplitude * (Index < 5); RtlInitUnicodeString(&UnicodeName, Name); return KcsAddGeometricWave(Buffer, &UnicodeName, 0, &Values); } NTSTATUS NTAPI KcsGeometricWaveCallback ( _In_ PCW_CALLBACK_TYPE Type, _In_ PPCW_CALLBACK_INFORMATION Info, _In_opt_ PVOID Context ) /*++ Routine Description: This function returns the list of counter instances and counter data. Arguments: Type - Request type. Info - Buffer for returned data. Context - Not used. Return Value: NTSTATUS indicating if the function succeeded. --*/ { NTSTATUS Status; UNICODE_STRING UnicodeName; UNREFERENCED_PARAMETER(Context); PAGED_CODE(); switch (Type) { case PcwCallbackEnumerateInstances: // // Instances are being enumerated, so we add them without values. // RtlInitUnicodeString(&UnicodeName, L"Small Wave"); Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer, &UnicodeName, 0, NULL); if (!NT_SUCCESS(Status)) { return Status; } RtlInitUnicodeString(&UnicodeName, L"Medium Wave"); Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer, &UnicodeName, 0, NULL); if (!NT_SUCCESS(Status)) { return Status; } RtlInitUnicodeString(&UnicodeName, L"Large Wave"); Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer, &UnicodeName, 0, NULL); if (!NT_SUCCESS(Status)) { return Status; } break; case PcwCallbackCollectData: // // Add values for 3 instances of Geometric Wave Counter Set. // Status = KcsAddGeometricInstance(Info->CollectData.Buffer, L"Small Wave", 40, 20); if (!NT_SUCCESS(Status)) { return Status; } Status = KcsAddGeometricInstance(Info->CollectData.Buffer, L"Medium Wave", 30, 40); if (!NT_SUCCESS(Status)) { return Status; } Status = KcsAddGeometricInstance(Info->CollectData.Buffer, L"Large Wave", 20, 60); if (!NT_SUCCESS(Status)) { return Status; } break; } return STATUS_SUCCESS; } NTSTATUS KcsAddTrignometricInstance ( _In_ PPCW_BUFFER Buffer, _In_ PCWSTR Name, _In_ ULONG MinimalValue, _In_ ULONG Amplitude ) /*++ Routine Description: This utility function adds instance to the callback buffer. Arguments: Buffer - Data will be returned in this buffer. Name - Name of instances to be added. MinimalValue - Minimum value of the wave. Amplitude - Amplitude of the wave. Return Value: NTSTATUS indicating if the function succeeded. --*/ { double Angle; KFLOATING_SAVE FloatSave; NTSTATUS Status; LARGE_INTEGER Timestamp; UNICODE_STRING UnicodeName; TRIGNOMETRIC_WAVE_VALUES Values; PAGED_CODE(); Status = KeSaveFloatingPointState(&FloatSave); if (!NT_SUCCESS(Status)) { return Status; } KeQuerySystemTime(&Timestamp); Angle = (double)(Timestamp.QuadPart / 400000) * (22/7) / 180; Values.Constant = MinimalValue; Values.Cosine = (ULONG)(MinimalValue + Amplitude * cos(Angle)); Values.Sine = (ULONG)(MinimalValue + Amplitude * sin(Angle)); KeRestoreFloatingPointState(&FloatSave); // // Add instance name & values to the caller's buffer. // RtlInitUnicodeString(&UnicodeName, Name); return KcsAddTrignometricWave(Buffer, &UnicodeName, 0, &Values); } NTSTATUS NTAPI KcsTrignometricWaveCallback ( _In_ PCW_CALLBACK_TYPE Type, _In_ PPCW_CALLBACK_INFORMATION Info, _In_opt_ PVOID Context ) /*++ Routine Description: This function returns the list of counter instances and counter data. Arguments: Type - Request type. Info - Buffer for returned data. Context - Not used. Return Value: NTSTATUS indicating if the function succeeded. --*/ { NTSTATUS Status; UNICODE_STRING UnicodeName; UNREFERENCED_PARAMETER(Context); PAGED_CODE(); switch (Type) { case PcwCallbackEnumerateInstances: RtlInitUnicodeString(&UnicodeName, L"default"); Status = KcsAddTrignometricWave(Info->EnumerateInstances.Buffer, &UnicodeName, 0, NULL); if (!NT_SUCCESS(Status)) { return Status; } break; case PcwCallbackCollectData: // // Add values for Single Instance of Trignometirc Wave Counter Set. // return KcsAddTrignometricInstance(Info->CollectData.Buffer, L"default", 50, 30); } return STATUS_SUCCESS; } VOID KcsUnload ( _In_ PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This function unregisters countersets Arguments: DriverObject - Not used. Return Value: None. --*/ { UNREFERENCED_PARAMETER(DriverObject); PAGED_CODE(); // // Unregister Countersets. // KcsUnregisterGeometricWave(); KcsUnregisterTrignometricWave(); } NTSTATUS DriverEntry ( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ Routine Description: This function registers countersets on initial loading of the driver. Arguments: DriverObject - Supplies the driver object of the driver being loaded. RegistryPath - Not used. Return Value: NTSTATUS indicating if driver was properly loaded. --*/ { NTSTATUS Status; UNREFERENCED_PARAMETER(RegistryPath); PAGED_CODE(); // // Register Countersets. // Status = KcsRegisterGeometricWave(KcsGeometricWaveCallback, NULL); if (!NT_SUCCESS(Status)) { return Status; } Status = KcsRegisterTrignometricWave(KcsTrignometricWaveCallback, NULL); if (!NT_SUCCESS(Status)) { KcsUnregisterTrignometricWave(); return Status; } // // Success path - set up unload routine and return success. // DriverObject->DriverUnload = KcsUnload; return STATUS_SUCCESS; } ================================================ FILE: tests/projects/windows/driver/wdm/perfcounters/kcs.h ================================================ /*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: kcs.h Abstract: This module contains sample code to demonstrate how to provide counter data from a kernel driver. Environment: Kernel mode only. --*/ typedef struct _GEOMETRIC_WAVE_VALUES { ULONG Square; ULONG Triangle; } GEOMETRIC_WAVE_VALUES, *PGEOMETRIC_WAVE_VALUES; typedef struct _TRIGNOMETRIC_WAVE_VALUES { ULONG Constant; ULONG Cosine; ULONG Sine; } TRIGNOMETRIC_WAVE_VALUES, *PTRIGNOMETRIC_WAVE_VALUES; ================================================ FILE: tests/projects/windows/driver/wdm/perfcounters/kcs.man ================================================ ================================================ FILE: tests/projects/windows/driver/wdm/perfcounters/kcs.rc ================================================ #include "kcsCounters.rc" ================================================ FILE: tests/projects/windows/driver/wdm/perfcounters/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("kcs") add_rules("wdk.env.wdm", "wdk.driver") add_values("wdk.man.prefix", "Kcs") add_values("wdk.man.resource", "kcsCounters.rc") add_values("wdk.man.header", "kcsCounters.h") add_values("wdk.man.counter_header", "kcsCounters_counters.h") add_files("*.c", "*.rc", "*.man") ================================================ FILE: tests/projects/windows/idl/test_norpc/src/lockowner.idl ================================================ /* * PROJECT: SupernovaX SDK * LICENSE: MIT (https://spdx.org/licenses/MIT) * PURPOSE: Lock owner COM interfaces * COPYRIGHT: Copyright 2023 Christian Rendina */ import "oaidl.idl"; import "ocidl.idl"; [ object, local, uuid(9b7e4a00-342c-4106-a19f-4f2704f689f0) ] interface ILockOwner : IUnknown { void LOEnter( void ); void LOLeave( void ); BOOL LOTryEnter( void ); }; ================================================ FILE: tests/projects/windows/idl/test_norpc/src/test_iid.c ================================================ #include #include int main(int argc, char** argv) { IID g = IID_ILockOwner; printf("GUID: %x-%x-%x-%llx", g.Data1, g.Data2, g.Data3, *(unsigned long long*)g.Data4); return 0; } ================================================ FILE: tests/projects/windows/idl/test_norpc/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("idltest_norpc") set_kind("binary") add_files("src/*.idl", { proxy = false }) add_files("src/*.c") add_syslinks("Rpcrt4") ================================================ FILE: tests/projects/windows/idl/test_norpc_proxy/src/lockowner.idl ================================================ /* * PROJECT: SupernovaX SDK * LICENSE: MIT (https://spdx.org/licenses/MIT) * PURPOSE: Lock owner COM interfaces * COPYRIGHT: Copyright 2023 Christian Rendina */ import "oaidl.idl"; import "ocidl.idl"; [ object, local, uuid(9b7e4a00-342c-4106-a19f-4f2704f689f0) ] interface ILockOwner : IUnknown { void LOEnter( void ); void LOLeave( void ); BOOL LOTryEnter( void ); }; ================================================ FILE: tests/projects/windows/idl/test_norpc_proxy/src/test_iid.c ================================================ #include #include int main(int argc, char** argv) { IID g = IID_ILockOwner; printf("GUID: %x-%x-%x-%llx", g.Data1, g.Data2, g.Data3, *(unsigned long long*)g.Data4); return 0; } ================================================ FILE: tests/projects/windows/idl/test_norpc_proxy/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("idltest_norpc") set_kind("binary") add_files("src/*.idl") add_files("src/*.c") add_syslinks("Rpcrt4") ================================================ FILE: tests/projects/windows/idl/test_rpc/src/example.idl ================================================ [ uuid(ba209999-0c6c-11d2-97cf-00c04f8eea45), version(1.0) ] interface MyInterface { const unsigned short INT_ARRAY_LEN = 100; void MyRemoteProc( [in] int param1, [out] int outArray[INT_ARRAY_LEN] ); } ================================================ FILE: tests/projects/windows/idl/test_rpc/src/test_iid.c ================================================ #include #include #include int main(int argc, char** argv) { MyInterface_v1_0_c_ifspec = (void*)1; MyInterface_v1_0_s_ifspec = (void*)1; printf("set ok\n"); return 0; } void __RPC_FAR * __RPC_API midl_user_allocate(size_t cBytes) { return(malloc(cBytes)); } void __RPC_API midl_user_free(void __RPC_FAR * p) { free(p); } ================================================ FILE: tests/projects/windows/idl/test_rpc/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("idltest_rpc") set_kind("binary") add_files("src/*.idl", {client = true, server = true}) add_files("src/*.c") add_syslinks("Rpcrt4") ================================================ FILE: tests/projects/windows/idl/test_rpc_noserver/src/example.idl ================================================ [ uuid(ba209999-0c6c-11d2-97cf-00c04f8eea45), version(1.0) ] interface MyInterface { const unsigned short INT_ARRAY_LEN = 100; void MyRemoteProc( [in] int param1, [out] int outArray[INT_ARRAY_LEN] ); } ================================================ FILE: tests/projects/windows/idl/test_rpc_noserver/src/test_iid.c ================================================ #include #include #include int main(int argc, char** argv) { MyInterface_v1_0_c_ifspec = (void*)1; printf("call ok\n"); return 0; } void __RPC_FAR * __RPC_API midl_user_allocate(size_t cBytes) { return(malloc(cBytes)); } void __RPC_API midl_user_free(void __RPC_FAR * p) { free(p); } ================================================ FILE: tests/projects/windows/idl/test_rpc_noserver/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("idltest_rpc_noserver") set_kind("binary") add_files("src/*.idl", {client = true, server = false}) add_files("src/*.c") add_syslinks("Rpcrt4") ================================================ FILE: tests/projects/windows/windows_links/src/foo.c ================================================ #include #ifdef _WIN32 __declspec(dllexport) #endif void foo() { printf("foo called\n"); } ================================================ FILE: tests/projects/windows/windows_links/src/main.c ================================================ #include #include #include __declspec(dllimport) void foo(); int main() { PROCESS_MEMORY_COUNTERS pmc; printf("Calling GetProcessMemoryInfo...\n"); if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { printf("PageFaultCount: %lu\n", pmc.PageFaultCount); printf("WorkingSetSize: %lu\n", pmc.WorkingSetSize); } else { printf("GetProcessMemoryInfo failed (%lu)\n", GetLastError()); } printf("Calling foo...\n"); foo(); printf("Done.\n"); return 0; } ================================================ FILE: tests/projects/windows/windows_links/xmake.lua ================================================ add_rules("mode.debug", "mode.release") set_policy("run.windows_error_dialog", true) target("foo") set_kind("shared") add_files("src/foo.c") target("test_foo_dll_presence") set_kind("binary") add_files("src/main.c") add_deps("foo") add_syslinks("psapi") after_build(function (target) local foo = target:dep("foo") if foo then os.tryrm(foo:targetfile()) end end) ================================================ FILE: tests/projects/windows/winsdk/usbview/app.config ================================================  ================================================ FILE: tests/projects/windows/winsdk/usbview/codeanalysis.h ================================================ /*++ Copyright (c) 1997-2011 Microsoft Corporation Module Name: CODEANALYSIS.H Abstract: This header file is used for supressing fxcop errors which are not applicable Environment: user mode Revision History: 08-11-11 : created --*/ #pragma once #if CODE_ANALYSIS /***************************************************************************** C O D E A N A L Y S I S S U P P R E S S I O N S *****************************************************************************/ using namespace System::Diagnostics::CodeAnalysis; namespace Microsoft { namespace Kits { namespace Samples { namespace Usb { // Justification : C++ Compiler cannot enforce ClsCompliant [module: SuppressMessage("Microsoft.Design", "CA1014:MarkAssembliesWithClsCompliant")] // Justification : The naming of the following types are based on native USB types [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="type", Target="Microsoft.Kits.Samples.Usb.UsbBosDescriptorType", MessageId="Bos")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.Hub30DescriptorType.#HubHdrDecLat", MessageId="Hdr")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.MachineInfoType.#UvcMajorSpecVersion", MessageId="Uvc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.MachineInfoType.#UvcMinorSpecVersion", MessageId="Uvc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.MachineInfoType.#UvcMinorVersion", MessageId="Uvc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.MachineInfoType.#UvcMajorVersion", MessageId="Uvc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceClassDetailsType.#UvcVersion", MessageId="Uvc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#BNumDeviceCaps", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UsbDispContIdCapExtDescriptor", MessageId="Disp")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.ExternalHubType.#BosDescriptor", MessageId="Bos")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.NodeConnectionInfoExType.#IProductStringDescEn", MessageId="Desc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#OtgDescriptor", MessageId="Otg")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#OtgError", MessageId="Otg")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#IadError", MessageId="Iad")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#IadDescriptor", MessageId="Iad")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceIADDescriptorType.#StringDesc", MessageId="Desc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceInterfaceDescriptorType.#BNumEndpoints", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceInterfaceDescriptorType.#StringDesc", MessageId="Desc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceInterfaceDescriptorType.#WNumClasses", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.NodeConnectionInfoExStructType.#NumOfOpenPipes", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.NodeConnectionInfoExStructType.#SpeedStr", MessageId="Str")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#ConfStringDesc", MessageId="Desc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#AttributesStr", MessageId="Str")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#ConfigDescError", MessageId="Desc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#BNumInterfaces", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="type", Target="Microsoft.Kits.Samples.Usb.UvcViewAll", MessageId="Uvc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UvcViewAll.#UvcView", MessageId="Uvc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="type", Target="Microsoft.Kits.Samples.Usb.UsbDispContIdCapExtDescriptorType", MessageId="Disp")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDispContIdCapExtDescriptorType.#ContainerIdStr", MessageId="Str")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbConnectionStatusType.#DeviceCausedOvercurrent", MessageId="Overcurrent")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceQualifierDescriptorType.#NumConfigurations", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceQualifierDescriptorType.#DeviceNumConfigError", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceDescriptorType.#NumConfigurations", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceType.#BosDescriptor", MessageId="Bos")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="type", Target="Microsoft.Kits.Samples.Usb.UvcViewType", MessageId="Uvc")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceHidDescriptorType.#BNumDescriptors", MessageId="Num")]; [module: SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Scope="member", Target="Microsoft.Kits.Samples.Usb.ExternalHubType.#HubInformationEx")]; [module: SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Scope="member", Target="Microsoft.Kits.Samples.Usb.RootHubType.#HubInformationEx")]; [module: SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#PreReleaseError", MessageId="PreRelease")]; [module: SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbHCPowerStateType.#CanWakeUp", MessageId="WakeUp")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbSuperSpeedExtensionDescriptorType.#BmAttributes", MessageId="Bm")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbUsb20ExtensionDescriptorType.#BmAttributes", MessageId="Bm")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.HubNodeType.#UsbMiParent", MessageId="Mi")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.ExternalHubType.#HwId", MessageId="Hw")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.HostControllerType.#HwId", MessageId="Hw")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="type", Target="Microsoft.Kits.Samples.Usb.UsbDeviceOTGDescriptorType", MessageId="OTG")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceOTGDescriptorType.#BmAttributes", MessageId="Bm")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.HubNodeInformationType.#MiParentNumberOfInterfaces", MessageId="Mi")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.NodeConnectionInfoExType.#IProductStringDescEn", MessageId="En")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="type", Target="Microsoft.Kits.Samples.Usb.UsbDeviceIADDescriptorType", MessageId="IAD")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#BmAttributes", MessageId="Bm")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.RootHubType.#HwId", MessageId="Hw")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceQualifierDescriptorType.#BcdUSB", MessageId="USB")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceDescriptorType.#CdDevice", MessageId="Cd")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceDescriptorType.#CdUSB", MessageId="USB")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceDescriptorType.#CdUSB", MessageId="Cd")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceType.#HwId", MessageId="Hw")]; [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceHidDescriptorType.#BcdHID", MessageId="HID")]; [module: SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Scope="member", Target="Microsoft.Kits.Samples.Usb.ExternalHubType.#HubCapabilityEx")] [module: SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Scope="member", Target="Microsoft.Kits.Samples.Usb.RootHubType.#HubCapabilityEx")] [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.HubCapabilitiesExType.#HubIsMultiTt", MessageId="Multi")] [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope="member", Target="Microsoft.Kits.Samples.Usb.HubCapabilitiesExType.#HubIsMultiTtCapable", MessageId="Multi")] [module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId="usbview")]; [module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId="usbview")]; // Justification: The version of XSD which is used to generate the objects does not support Collections. [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UsbSuperSpeedExtensionDescriptor")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UsbUsb20ExtensionDescriptor")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UnknownDescriptor")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UsbDispContIdCapExtDescriptor")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.ExternalHubType.#UsbDevice")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.ExternalHubType.#DeviceConfiguration")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.ExternalHubType.#NoDevice")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.ExternalHubType.#ExternalHub")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.NodeConnectionInfoExStructType.#Pipe")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbHCPowerStateMappingType.#PowerMap")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.RootHubType.#NoDevice")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.RootHubType.#ExternalHub")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.RootHubType.#UsbDevice")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceType.#DeviceConfiguration")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.UvcViewType.#UsbTree")]; [module: SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Scope="member", Target="Microsoft.Kits.Samples.Usb.UsbDeviceHidDescriptorType.#OptionalDescriptor")]; }; }; }; }; #endif ================================================ FILE: tests/projects/windows/winsdk/usbview/debug.c ================================================ /*++ Copyright (c) 1997-2008 Microsoft Corporation Module Name: DEBUG.C Abstract: This source file contains debug routines. Environment: user mode Revision History: 07-08-97 : created --*/ /***************************************************************************** I N C L U D E S *****************************************************************************/ #include "uvcview.h" #if DBG /***************************************************************************** T Y P E D E F S *****************************************************************************/ typedef struct _ALLOCHEADER { LIST_ENTRY ListEntry; PCHAR File; ULONG Line; } ALLOCHEADER, *PALLOCHEADER; /***************************************************************************** G L O B A L S *****************************************************************************/ LIST_ENTRY AllocListHead = { &AllocListHead, &AllocListHead }; /***************************************************************************** MyAlloc() *****************************************************************************/ _Success_(return != NULL) _Post_writable_byte_size_(dwBytes) HGLOBAL MyAlloc ( _In_ PCHAR File, ULONG Line, DWORD dwBytes ) { PALLOCHEADER header; DWORD dwRequest = dwBytes; if (0 == dwBytes) { return NULL; } dwBytes += sizeof(ALLOCHEADER); // check for integer overflow if (dwBytes > dwRequest) { header = (PALLOCHEADER)GlobalAlloc(GPTR, dwBytes); if (header != NULL) { InsertTailList(&AllocListHead, &header->ListEntry); header->File = File; header->Line = Line; return (HGLOBAL)(header + 1); } } return NULL; } /***************************************************************************** MyReAlloc() *****************************************************************************/ _Success_(return != NULL) _Post_writable_byte_size_(dwBytes) HGLOBAL MyReAlloc ( HGLOBAL hMem, DWORD dwBytes ) { PALLOCHEADER header; PALLOCHEADER headerNew; if ((NULL == hMem) || (0 == dwBytes)) { return NULL; } header = (PALLOCHEADER)hMem; header--; // Remove the old address from the allocation list // RemoveEntryList(&header->ListEntry); if (dwBytes < (dwBytes + (DWORD) sizeof(ALLOCHEADER))) { dwBytes += sizeof(ALLOCHEADER); headerNew = GlobalReAlloc((HGLOBAL)header, dwBytes, GMEM_MOVEABLE|GMEM_ZEROINIT); if (NULL == headerNew) { // If GlobalReAlloc fails, the original memory is not freed, // and the original handle and pointer are still valid. // Add the old address back to the allocation list. // #pragma prefast(suppress:__WARNING_USING_UNINIT_VAR, "SAL noise") InsertTailList(&AllocListHead, &header->ListEntry); } else { // Add the new address to the allocation list // InsertTailList(&AllocListHead, &headerNew->ListEntry); return (HGLOBAL)(headerNew + 1); } } return NULL; } /***************************************************************************** MyFree() *****************************************************************************/ HGLOBAL MyFree ( HGLOBAL hMem ) { PALLOCHEADER header; if (hMem) { header = (PALLOCHEADER)hMem; header--; RemoveEntryList(&header->ListEntry); return GlobalFree((HGLOBAL)header); } return GlobalFree(hMem); } /***************************************************************************** MyCheckForLeaks() *****************************************************************************/ VOID MyCheckForLeaks ( VOID ) { PALLOCHEADER header; CHAR buf[128]; memset(buf, 0, sizeof(buf)); while (!IsListEmpty(&AllocListHead)) { header = (PALLOCHEADER)RemoveHeadList(&AllocListHead); StringCbPrintf(buf, sizeof(buf), "File: %s, Line: %d\r\n", header->File, header->Line); OutputDebugString(buf); } } #endif ================================================ FILE: tests/projects/windows/winsdk/usbview/devnode.c ================================================ /*++ Copyright (c) 1998-2011 Microsoft Corporation Module Name: DEVNODE.C --*/ /***************************************************************************** I N C L U D E S *****************************************************************************/ #include "uvcview.h" /***************************************************************************** DriverNameToDeviceInst() Finds the Device instance of the DevNode with the matching DriverName. Returns FALSE if the matching DevNode is not found and TRUE if found *****************************************************************************/ BOOL DriverNameToDeviceInst( _In_reads_bytes_(cbDriverName) PCHAR DriverName, _In_ size_t cbDriverName, _Out_ HDEVINFO *pDevInfo, _Out_writes_bytes_(sizeof(SP_DEVINFO_DATA)) PSP_DEVINFO_DATA pDevInfoData ) { HDEVINFO deviceInfo = INVALID_HANDLE_VALUE; BOOL status = TRUE; ULONG deviceIndex; SP_DEVINFO_DATA deviceInfoData; BOOL bResult = FALSE; PCHAR pDriverName = NULL; PSTR buf = NULL; BOOL done = FALSE; if (pDevInfo == NULL) { return FALSE; } if (pDevInfoData == NULL) { return FALSE; } memset(pDevInfoData, 0, sizeof(SP_DEVINFO_DATA)); *pDevInfo = INVALID_HANDLE_VALUE; // Use local string to guarantee zero termination pDriverName = (PCHAR) ALLOC((DWORD) cbDriverName + 1); if (NULL == pDriverName) { status = FALSE; goto Done; } StringCbCopyN(pDriverName, cbDriverName + 1, DriverName, cbDriverName); // // We cannot walk the device tree with CM_Get_Sibling etc. unless we assume // the device tree will stabilize. Any devnode removal (even outside of USB) // would force us to retry. Instead we use Setup API to snapshot all // devices. // // Examine all present devices to see if any match the given DriverName // deviceInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); if (deviceInfo == INVALID_HANDLE_VALUE) { status = FALSE; goto Done; } deviceIndex = 0; deviceInfoData.cbSize = sizeof(deviceInfoData); while (done == FALSE) { // // Get devinst of the next device // status = SetupDiEnumDeviceInfo(deviceInfo, deviceIndex, &deviceInfoData); deviceIndex++; if (!status) { // // This could be an error, or indication that all devices have been // processed. Either way the desired device was not found. // done = TRUE; break; } // // Get the DriverName value // bResult = GetDeviceProperty(deviceInfo, &deviceInfoData, SPDRP_DRIVER, &buf); // If the DriverName value matches, return the DeviceInstance // if (bResult == TRUE && buf != NULL && _stricmp(pDriverName, buf) == 0) { done = TRUE; *pDevInfo = deviceInfo; CopyMemory(pDevInfoData, &deviceInfoData, sizeof(deviceInfoData)); FREE(buf); break; } if(buf != NULL) { FREE(buf); buf = NULL; } } Done: if (bResult == FALSE) { if (deviceInfo != INVALID_HANDLE_VALUE) { SetupDiDestroyDeviceInfoList(deviceInfo); } } if (pDriverName != NULL) { FREE(pDriverName); } return status; } /***************************************************************************** DriverNameToDeviceProperties() Returns the Device properties of the DevNode with the matching DriverName. Returns NULL if the matching DevNode is not found. The caller should free the returned structure using FREE() macro *****************************************************************************/ PUSB_DEVICE_PNP_STRINGS DriverNameToDeviceProperties( _In_reads_bytes_(cbDriverName) PCHAR DriverName, _In_ size_t cbDriverName ) { HDEVINFO deviceInfo = INVALID_HANDLE_VALUE; SP_DEVINFO_DATA deviceInfoData = {0}; ULONG len; BOOL status; PUSB_DEVICE_PNP_STRINGS DevProps = NULL; DWORD lastError; // Allocate device propeties structure DevProps = (PUSB_DEVICE_PNP_STRINGS) ALLOC(sizeof(USB_DEVICE_PNP_STRINGS)); if(NULL == DevProps) { status = FALSE; goto Done; } // Get device instance status = DriverNameToDeviceInst(DriverName, cbDriverName, &deviceInfo, &deviceInfoData); if (status == FALSE) { goto Done; } len = 0; status = SetupDiGetDeviceInstanceId(deviceInfo, &deviceInfoData, NULL, 0, &len); lastError = GetLastError(); if (status != FALSE && lastError != ERROR_INSUFFICIENT_BUFFER) { status = FALSE; goto Done; } // // An extra byte is required for the terminating character // len++; DevProps->DeviceId = ALLOC(len); if (DevProps->DeviceId == NULL) { status = FALSE; goto Done; } status = SetupDiGetDeviceInstanceId(deviceInfo, &deviceInfoData, DevProps->DeviceId, len, &len); if (status == FALSE) { goto Done; } status = GetDeviceProperty(deviceInfo, &deviceInfoData, SPDRP_DEVICEDESC, &DevProps->DeviceDesc); if (status == FALSE) { goto Done; } // // We don't fail if the following registry query fails as these fields are additional information only // GetDeviceProperty(deviceInfo, &deviceInfoData, SPDRP_HARDWAREID, &DevProps->HwId); GetDeviceProperty(deviceInfo, &deviceInfoData, SPDRP_SERVICE, &DevProps->Service); GetDeviceProperty(deviceInfo, &deviceInfoData, SPDRP_CLASS, &DevProps->DeviceClass); Done: if (deviceInfo != INVALID_HANDLE_VALUE) { SetupDiDestroyDeviceInfoList(deviceInfo); } if (status == FALSE) { if (DevProps != NULL) { FreeDeviceProperties(&DevProps); } } return DevProps; } /***************************************************************************** FreeDeviceProperties() Free the device properties structure *****************************************************************************/ VOID FreeDeviceProperties(_In_ PUSB_DEVICE_PNP_STRINGS *ppDevProps) { if(ppDevProps == NULL) { return; } if(*ppDevProps == NULL) { return; } if ((*ppDevProps)->DeviceId != NULL) { FREE((*ppDevProps)->DeviceId); } if ((*ppDevProps)->DeviceDesc != NULL) { FREE((*ppDevProps)->DeviceDesc); } // // The following are not necessary, but left in case // in the future there is a later failure where these // pointer fields would be allocated. // if ((*ppDevProps)->HwId != NULL) { FREE((*ppDevProps)->HwId); } if ((*ppDevProps)->Service != NULL) { FREE((*ppDevProps)->Service); } if ((*ppDevProps)->DeviceClass != NULL) { FREE((*ppDevProps)->DeviceClass); } if ((*ppDevProps)->PowerState != NULL) { FREE((*ppDevProps)->PowerState); } FREE(*ppDevProps); *ppDevProps = NULL; } ================================================ FILE: tests/projects/windows/winsdk/usbview/dispaud.c ================================================ /*++ Copyright (c) 1997-2008 Microsoft Corporation Module Name: DISPAUD.C Abstract: This source file contains routines which update the edit control to display information about USB Audio descriptors. Environment: user mode Revision History: 03-07-1998 : created --*/ /***************************************************************************** I N C L U D E S *****************************************************************************/ #include "uvcview.h" /***************************************************************************** G L O B A L S P R I V A T E T O T H I S F I L E *****************************************************************************/ // // USB Device Class Definition for Terminal Types 0.9 Draft Revision // STRINGLIST slAudioTerminalTypes [] = { // // 2.1 USB Terminal Types // {0x0100, "USB Undefined", ""}, {0x0101, "USB streaming", ""}, {0x01FF, "USB vendor specific", ""}, // // 2.2 Input Terminal Types // {0x0200, "Input Undefined", ""}, {0x0201, "Microphone", ""}, {0x0202, "Desktop microphone", ""}, {0x0203, "Personal microphone", ""}, {0x0204, "Omni-directional microphone", ""}, {0x0205, "Microphone array", ""}, {0x0206, "Processing microphone array", ""}, // // 2.3 Output Terminal Types // {0x0300, "Output Undefined", ""}, {0x0301, "Speaker", ""}, {0x0302, "Headphones", ""}, {0x0303, "Head Mounted Display Audio", ""}, {0x0304, "Desktop speaker", ""}, {0x0305, "Room speaker", ""}, {0x0306, "Communication speaker", ""}, {0x0307, "Low frequency effects speaker", ""}, // // 2.4 Bi-directional Terminal Types // {0x0400, "Bi-directional Undefined", ""}, {0x0401, "Handset", ""}, {0x0402, "Headset", ""}, {0x0403, "Speakerphone, no echo reduction", ""}, {0x0404, "Echo-suppressing speakerphone", ""}, {0x0405, "Echo-canceling speakerphone", ""}, // // 2.5 Telephony Terminal Types // {0x0500, "Telephony Undefined", ""}, {0x0501, "Phone line", ""}, {0x0502, "Telephone", ""}, {0x0503, "Down Line Phone", ""}, // // 2.6 External Terminal Types // {0x0600, "External Undefined", ""}, {0x0601, "Analog connector", ""}, {0x0602, "Digital audio interface", ""}, {0x0603, "Line connector", ""}, {0x0604, "Legacy audio connector", ""}, {0x0605, "S/PDIF interface", ""}, {0x0606, "1394 DA stream", ""}, {0x0607, "1394 DV stream soundtrack", ""}, // // Embedded Function Terminal Types // {0x0700, "Embedded Undefined", ""}, {0x0701, "Level Calibration Noise Source", ""}, {0x0702, "Equalization Noise", ""}, {0x0703, "CD player", ""}, {0x0704, "DAT", ""}, {0x0705, "DCC", ""}, {0x0706, "MiniDisk", ""}, {0x0707, "Analog Tape", ""}, {0x0708, "Phonograph", ""}, {0x0709, "VCR Audio", ""}, {0x070A, "Video Disc Audio", ""}, {0x070B, "DVD Audio", ""}, {0x070C, "TV Tuner Audio", ""}, {0x070D, "Satellite Receiver Audio", ""}, {0x070E, "Cable Tuner Audio", ""}, {0x070F, "DSS Audio", ""}, {0x0710, "Radio Receiver", ""}, {0x0711, "Radio Transmitter", ""}, {0x0712, "Multi-track Recorder", ""}, {0x0713, "Synthesizer", ""}, }; STRINGLIST slAudioFormatTypes [] = { // // A.1.1 Audio Data Format Type I Codes // {0x0000, "TYPE_I_UNDEFINED", ""}, {0x0001, "PCM", ""}, {0x0002, "PCM8", ""}, {0x0003, "IEEE_FLOAT", ""}, {0x0004, "ALAW", ""}, {0x0005, "MULAW", ""}, // // A.1.2 Audio Data Format Type II Codes // {0x1000, "TYPE_II_UNDEFINED", ""}, {0x1001, "MPEG", ""}, {0x1002, "AC-3", ""}, // // A.1.3 Audio Data Format Type III Codes // {0x2000, "TYPE_III_UNDEFINED", ""}, {0x2001, "IEC1937_AC-3", ""}, {0x2002, "IEC1937_MPEG-1_Layer1", ""}, {0x2003, "IEC1937_MPEG-1_Layer2/3 or IEC1937_MPEG-2_NOEXT", ""}, {0x2004, "IEC1937_MPEG-2_EXT", ""}, {0x2005, "IEC1937_MPEG-2_Layer1_LS", ""}, {0x2006, "IEC1937_MPEG-2_Layer2/3_LS", ""}, }; /***************************************************************************** L O C A L F U N C T I O N P R O T O T Y P E S *****************************************************************************/ BOOL DisplayACHeader ( PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR HeaderDesc ); BOOL DisplayACInputTerminal ( PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR ITDesc ); BOOL DisplayACOutputTerminal ( PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR OTDesc ); BOOL DisplayACMixerUnit ( PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR MixerDesc ); BOOL DisplayACSelectorUnit ( PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR SelectorDesc ); BOOL DisplayACFeatureUnit ( PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR FeatureDesc ); BOOL DisplayACProcessingUnit ( PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR ProcessingDesc ); BOOL DisplayACExtensionUnit ( PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR ExtensionDesc ); BOOL DisplayASGeneral ( PUSB_AUDIO_GENERAL_DESCRIPTOR GeneralDesc ); BOOL DisplayCSEndpoint ( PUSB_AUDIO_ENDPOINT_DESCRIPTOR EndpointDesc ); BOOL DisplayASFormatType ( PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR FormatDesc ); BOOL DisplayASFormatSpecific ( PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc ); VOID DisplayBytes ( PUCHAR Data, USHORT Len ); /***************************************************************************** L O C A L F U N C T I O N S *****************************************************************************/ /***************************************************************************** DisplayAudioDescriptor() CommonDesc - An Audio Class Descriptor bInterfaceSubClass - The SubClass of the Interface containing the descriptor *****************************************************************************/ BOOL DisplayAudioDescriptor ( PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc, UCHAR bInterfaceSubClass ) { switch (CommonDesc->bDescriptorType) { case USB_AUDIO_CS_INTERFACE: switch (bInterfaceSubClass) { case USB_AUDIO_SUBCLASS_AUDIOCONTROL: switch (CommonDesc->bDescriptorSubtype) { case USB_AUDIO_AC_HEADER: return DisplayACHeader((PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR)CommonDesc); case USB_AUDIO_AC_INPUT_TERMINAL: return DisplayACInputTerminal((PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR)CommonDesc); case USB_AUDIO_AC_OUTPUT_TERMINAL: return DisplayACOutputTerminal((PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR)CommonDesc); case USB_AUDIO_AC_MIXER_UNIT: return DisplayACMixerUnit((PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR)CommonDesc); case USB_AUDIO_AC_SELECTOR_UNIT: return DisplayACSelectorUnit((PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR)CommonDesc); case USB_AUDIO_AC_FEATURE_UNIT: return DisplayACFeatureUnit((PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR)CommonDesc); case USB_AUDIO_AC_PROCESSING_UNIT: return DisplayACProcessingUnit((PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR)CommonDesc); case USB_AUDIO_AC_EXTENSION_UNIT: return DisplayACExtensionUnit((PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR)CommonDesc); default: break; } break; case USB_AUDIO_SUBCLASS_AUDIOSTREAMING: switch (CommonDesc->bDescriptorSubtype) { case USB_AUDIO_AS_GENERAL: return DisplayASGeneral((PUSB_AUDIO_GENERAL_DESCRIPTOR)CommonDesc); case USB_AUDIO_AS_FORMAT_TYPE: return DisplayASFormatType((PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR)CommonDesc); break; case USB_AUDIO_AS_FORMAT_SPECIFIC: return DisplayASFormatSpecific(CommonDesc); default: break; } break; default: break; } break; case USB_AUDIO_CS_ENDPOINT: return DisplayCSEndpoint((PUSB_AUDIO_ENDPOINT_DESCRIPTOR)CommonDesc); default: break; } return FALSE; } /***************************************************************************** DisplayACHeader() *****************************************************************************/ BOOL DisplayACHeader ( PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR HeaderDesc ) { UINT i = 0; if (HeaderDesc->bLength < sizeof(USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR)) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Control Interface Header Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", HeaderDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", HeaderDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", HeaderDesc->bDescriptorSubtype); AppendTextBuffer("bcdADC: 0x%04X\r\n", HeaderDesc->bcdADC); AppendTextBuffer("wTotalLength: 0x%04X\r\n", HeaderDesc->wTotalLength); AppendTextBuffer("bInCollection: 0x%02X\r\n", HeaderDesc->bInCollection); for (i=0; ibInCollection; i++) { AppendTextBuffer("baInterfaceNr[%d]: 0x%02X\r\n", i+1, HeaderDesc->baInterfaceNr[i]); } return TRUE; } /***************************************************************************** DisplayACInputTerminal() *****************************************************************************/ BOOL DisplayACInputTerminal ( PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR ITDesc ) { PCHAR pStr = NULL; if (ITDesc->bLength != sizeof(USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR)) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Control Input Terminal Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", ITDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", ITDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", ITDesc->bDescriptorSubtype); AppendTextBuffer("bTerminalID: 0x%02X\r\n", ITDesc->bTerminalID); AppendTextBuffer("wTerminalType: 0x%04X", ITDesc->wTerminalType); pStr = GetStringFromList(slAudioTerminalTypes, sizeof(slAudioTerminalTypes) / sizeof(STRINGLIST), ITDesc->wTerminalType, "Invalid AC Input Terminal Type"); AppendTextBuffer(" (%s)\r\n", pStr); AppendTextBuffer("bAssocTerminal: 0x%02X\r\n", ITDesc->bAssocTerminal); AppendTextBuffer("bNrChannels: 0x%02X\r\n", ITDesc->bNrChannels); AppendTextBuffer("wChannelConfig: 0x%04X\r\n", ITDesc->wChannelConfig); AppendTextBuffer("iChannelNames: 0x%02X\r\n", ITDesc->iChannelNames); AppendTextBuffer("iTerminal: 0x%02X\r\n", ITDesc->iTerminal); return TRUE; } /***************************************************************************** DisplayACOutputTerminal() *****************************************************************************/ BOOL DisplayACOutputTerminal ( PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR OTDesc ) { PCHAR pStr = NULL; if (OTDesc->bLength != sizeof(USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR)) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Control Output Terminal Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", OTDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", OTDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", OTDesc->bDescriptorSubtype); AppendTextBuffer("bTerminalID: 0x%02X\r\n", OTDesc->bTerminalID); AppendTextBuffer("wTerminalType: 0x%04X", OTDesc->wTerminalType); pStr = GetStringFromList(slAudioTerminalTypes, sizeof(slAudioTerminalTypes) / sizeof(STRINGLIST), OTDesc->wTerminalType, "Invalid AC Output Terminal Type"); AppendTextBuffer(" (%s)\r\n", pStr); AppendTextBuffer("bAssocTerminal: 0x%02X\r\n", OTDesc->bAssocTerminal); AppendTextBuffer("bSourceID: 0x%02X\r\n", OTDesc->bSourceID); AppendTextBuffer("iTerminal: 0x%02X\r\n", OTDesc->iTerminal); return TRUE; } /***************************************************************************** DisplayACMixerUnit() *****************************************************************************/ BOOL DisplayACMixerUnit ( PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR MixerDesc ) { UCHAR i = 0; PUCHAR data = NULL; if (MixerDesc->bLength < 10) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Control Mixer Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", MixerDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", MixerDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", MixerDesc->bDescriptorSubtype); AppendTextBuffer("bUnitID: 0x%02X\r\n", MixerDesc->bUnitID); AppendTextBuffer("bNrInPins: 0x%02X\r\n", MixerDesc->bNrInPins); for (i=0; ibNrInPins; i++) { AppendTextBuffer("baSourceID[%d]: 0x%02X\r\n", i+1, MixerDesc->baSourceID[i]); } data = &MixerDesc->baSourceID[MixerDesc->bNrInPins]; AppendTextBuffer("bNrChannels: 0x%02X\r\n", *data++); AppendTextBuffer("wChannelConfig: 0x%04X\r\n", *(PUSHORT)data); data = (PUCHAR) ((PUSHORT) data + 1); AppendTextBuffer("iChannelNames: 0x%02X\r\n", *data++); AppendTextBuffer("bmControls:\r\n"); i = MixerDesc->bLength - 10 - MixerDesc->bNrInPins; DisplayBytes(data, i); data += i; AppendTextBuffer("iMixer: 0x%02X\r\n", *data); return TRUE; } /***************************************************************************** DisplayACSelectorUnit() *****************************************************************************/ BOOL DisplayACSelectorUnit ( PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR SelectorDesc ) { UCHAR i = 0; PUCHAR data = NULL; if (SelectorDesc->bLength < 6) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Control Selector Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", SelectorDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", SelectorDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", SelectorDesc->bDescriptorSubtype); AppendTextBuffer("bUnitID: 0x%02X\r\n", SelectorDesc->bUnitID); AppendTextBuffer("bNrInPins: 0x%02X\r\n", SelectorDesc->bNrInPins); for (i=0; ibNrInPins; i++) { AppendTextBuffer("baSourceID[%d]: 0x%02X\r\n", i+1, SelectorDesc->baSourceID[i]); } data = &SelectorDesc->baSourceID[SelectorDesc->bNrInPins]; AppendTextBuffer("iSelector: 0x%02X\r\n", *data); return TRUE; } /***************************************************************************** DisplayACFeatureUnit() *****************************************************************************/ BOOL DisplayACFeatureUnit ( PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR FeatureDesc ) { UCHAR i = 0; UCHAR n = 0; UCHAR ch = 0; PUCHAR data = NULL; AppendTextBuffer("\r\n ===>Audio Control Feature Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", FeatureDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", FeatureDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", FeatureDesc->bDescriptorSubtype); AppendTextBuffer("bUnitID: 0x%02X\r\n", FeatureDesc->bUnitID); AppendTextBuffer("bSourceID: 0x%02X\r\n", FeatureDesc->bSourceID); AppendTextBuffer("bControlSize: 0x%02X\r\n", FeatureDesc->bControlSize); if (FeatureDesc->bLength < 7) { AppendTextBuffer("*!*WARNING: bLength is invalid (< 7)\r\n"); OOPS(); return FALSE; } else if(FeatureDesc->bLength == 7) { AppendTextBuffer("Audio controls are not available (bLength = 7)\r\n"); return TRUE; } n = FeatureDesc->bControlSize; if(n == 0) { AppendTextBuffer("Audio controls are not available (bControlSize = 0)\r\n"); return TRUE; } ch = ((FeatureDesc->bLength - 7) / n) - 1; // Check if there are extra bytes in descriptor based on formula in Spec if (FeatureDesc->bLength != (7 + (ch + 1) * n)) { // The descriptor length is greater than number of bmaControls AppendTextBuffer("*!*WARNING: bLength is greater than number of bmaControls (bLength > ( 7 + (ch + 1) * n)\r\n"); } data = &FeatureDesc->bmaControls[0]; if (ch == (UCHAR) -1) { // This should not happen, but this check is put in place so we don't loop for a long time below AppendTextBuffer("*!*WARNING: Either bLength or bControlSize are invalid. The calculated logical channel count is -1. ((bLength - 7)/ n) - 1\r\n"); OOPS(); return FALSE; } for (i=0; i<=ch; i++) { AppendTextBuffer("bmaControls[%d]: ", i); DisplayBytes(data, n); data += n; } AppendTextBuffer("iFeature: 0x%02X\r\n", *data); return TRUE; } /***************************************************************************** DisplayACProcessingUnit() *****************************************************************************/ BOOL DisplayACProcessingUnit ( PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR ProcessingDesc ) { UCHAR i = 0; PUCHAR data = NULL; if (ProcessingDesc->bLength < sizeof(USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR)) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Control Processing Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", ProcessingDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", ProcessingDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", ProcessingDesc->bDescriptorSubtype); AppendTextBuffer("bUnitID: 0x%02X\r\n", ProcessingDesc->bUnitID); AppendTextBuffer("wProcessType: 0x%04X", ProcessingDesc->wProcessType); switch (ProcessingDesc->wProcessType) { case USB_AUDIO_PROCESS_UNDEFINED: AppendTextBuffer("(Undefined Process)\r\n"); break; case USB_AUDIO_PROCESS_UPDOWNMIX: AppendTextBuffer("(Up / Down Mix Process)\r\n"); break; case USB_AUDIO_PROCESS_DOLBYPROLOGIC: AppendTextBuffer("(Dolby Prologic Process)\r\n"); break; case USB_AUDIO_PROCESS_3DSTEREOEXTENDER: AppendTextBuffer("(3D-Stereo Extender Process)\r\n"); break; case USB_AUDIO_PROCESS_REVERBERATION: AppendTextBuffer("(Reverberation Process)\r\n"); break; case USB_AUDIO_PROCESS_CHORUS: AppendTextBuffer("(Chorus Process)\r\n"); break; case USB_AUDIO_PROCESS_DYNRANGECOMP: AppendTextBuffer("(Dynamic Range Compressor Process)\r\n"); break; default: AppendTextBuffer("\r\n"); break; } AppendTextBuffer("bNrInPins: 0x%02X\r\n", ProcessingDesc->bNrInPins); for (i=0; ibNrInPins; i++) { AppendTextBuffer("baSourceID[%d]: 0x%02X\r\n", i+1, ProcessingDesc->baSourceID[i]); } data = &ProcessingDesc->baSourceID[ProcessingDesc->bNrInPins]; AppendTextBuffer("bNrChannels: 0x%02X\r\n", *data++); AppendTextBuffer("wChannelConfig: 0x%04X\r\n", *(PUSHORT)data); data = (PUCHAR) ((PUSHORT) data + 1); AppendTextBuffer("iChannelNames: 0x%02X\r\n", *data++); i = *data++; AppendTextBuffer("bControlSize: 0x%02X\r\n", i); AppendTextBuffer("bmControls:\r\n"); DisplayBytes(data, i); data += i; AppendTextBuffer("iProcessing: 0x%02X\r\n", *data++); i = ProcessingDesc->bLength - 13 - ProcessingDesc->bNrInPins - i; if (i) { AppendTextBuffer("Process Specific:\r\n"); DisplayBytes(data, i); } return TRUE; } /***************************************************************************** DisplayACExtensionUnit() *****************************************************************************/ BOOL DisplayACExtensionUnit ( PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR ExtensionDesc ) { UCHAR i = 0; PUCHAR data = NULL; if (ExtensionDesc->bLength < 13) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Control Extension Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", ExtensionDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", ExtensionDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", ExtensionDesc->bDescriptorSubtype); AppendTextBuffer("bUnitID: 0x%02X\r\n", ExtensionDesc->bUnitID); AppendTextBuffer("wExtensionCode: 0x%04X\r\n", ExtensionDesc->wExtensionCode); AppendTextBuffer("bNrInPins: 0x%02X\r\n", ExtensionDesc->bNrInPins); for (i=0; ibNrInPins; i++) { AppendTextBuffer("baSourceID[%d]: 0x%02X\r\n", i+1, ExtensionDesc->baSourceID[i]); } data = &ExtensionDesc->baSourceID[ExtensionDesc->bNrInPins]; AppendTextBuffer("bNrChannels: 0x%02X\r\n", *data++); AppendTextBuffer("wChannelConfig: 0x%04X\r\n", *(PUSHORT)data); data = (PUCHAR) ((PUSHORT) data + 1); AppendTextBuffer("iChannelNames: 0x%02X\r\n", *data++); i = *data++; AppendTextBuffer("bControlSize: 0x%02X\r\n", i); AppendTextBuffer("bmControls:\r\n"); DisplayBytes(data, i); data += i; AppendTextBuffer("iExtension: 0x%02X\r\n", *data); return TRUE; } /***************************************************************************** DisplayASGeneral() *****************************************************************************/ BOOL DisplayASGeneral ( PUSB_AUDIO_GENERAL_DESCRIPTOR GeneralDesc ) { PCHAR pStr = NULL; if (GeneralDesc->bLength != sizeof(USB_AUDIO_GENERAL_DESCRIPTOR)) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Streaming Class Specific Interface Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", GeneralDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", GeneralDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", GeneralDesc->bDescriptorSubtype); AppendTextBuffer("bTerminalLink: 0x%02X\r\n", GeneralDesc->bTerminalLink); AppendTextBuffer("bDelay: 0x%02X\r\n", GeneralDesc->bDelay); AppendTextBuffer("wFormatTag: 0x%04X", GeneralDesc->wFormatTag); pStr = GetStringFromList(slAudioFormatTypes, sizeof(slAudioFormatTypes) / sizeof(STRINGLIST), GeneralDesc->wFormatTag, "Invalid AC Format Type"); AppendTextBuffer(" (%s)\r\n", pStr); return TRUE; } /***************************************************************************** DisplayCSEndpoint() *****************************************************************************/ BOOL DisplayCSEndpoint ( PUSB_AUDIO_ENDPOINT_DESCRIPTOR EndpointDesc ) { if (EndpointDesc->bLength != sizeof(USB_AUDIO_ENDPOINT_DESCRIPTOR)) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Streaming Class Specific Audio Data Endpoint Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", EndpointDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", EndpointDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", EndpointDesc->bDescriptorSubtype); AppendTextBuffer("bmAttributes: 0x%02X\r\n", EndpointDesc->bmAttributes); AppendTextBuffer("bLockDelayUnits: 0x%02X\r\n", EndpointDesc->bLockDelayUnits); AppendTextBuffer("wLockDelay: 0x%04X\r\n", EndpointDesc->wLockDelay); return TRUE; } /***************************************************************************** DisplayASFormatType() *****************************************************************************/ BOOL DisplayASFormatType ( PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR FormatDesc ) { UCHAR i = 0; UCHAR n = 0; ULONG freq = 0; PUCHAR data = NULL; if (FormatDesc->bLength < sizeof(USB_AUDIO_COMMON_FORMAT_DESCRIPTOR)) { OOPS(); return FALSE; } AppendTextBuffer("\r\n ===>Audio Streaming Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", FormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", FormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", FormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatType: 0x%02X\r\n", FormatDesc->bFormatType); if (FormatDesc->bFormatType == 0x01 || FormatDesc->bFormatType == 0x03) { PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR FormatI_IIIDesc; FormatI_IIIDesc = (PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR)FormatDesc; AppendTextBuffer("bNrChannels: 0x%02X\r\n", FormatI_IIIDesc->bNrChannels); AppendTextBuffer("bSubframeSize: 0x%02X\r\n", FormatI_IIIDesc->bSubframeSize); AppendTextBuffer("bBitResolution: 0x%02X\r\n", FormatI_IIIDesc->bBitResolution); AppendTextBuffer("bSamFreqType: 0x%02X\r\n", FormatI_IIIDesc->bSamFreqType); data = (PUCHAR)(FormatI_IIIDesc + 1); n = FormatI_IIIDesc->bSamFreqType; } else if (FormatDesc->bFormatType == 0x02) { PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR FormatIIDesc; FormatIIDesc = (PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR)FormatDesc; AppendTextBuffer("wMaxBitRate: 0x%04X\r\n", FormatIIDesc->wMaxBitRate); AppendTextBuffer("wSamplesPerFrame: 0x%04X\r\n", FormatIIDesc->wSamplesPerFrame); AppendTextBuffer("bSamFreqType: 0x%02X\r\n", FormatIIDesc->bSamFreqType); data = (PUCHAR)(FormatIIDesc + 1); n = FormatIIDesc->bSamFreqType; } else { data = NULL; } if (data != NULL) { if (n == 0) { freq = (data[0]) + (data[1] << 8) + (data[2] << 16); data += 3; AppendTextBuffer("tLowerSamFreq: 0x%06X (%d Hz)\r\n", freq, freq); freq = (data[0]) + (data[1] << 8) + (data[2] << 16); data += 3; AppendTextBuffer("tUpperSamFreq: 0x%06X (%d Hz)\r\n", freq, freq); } else { for (i=0; iAudio Streaming Format Specific Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", CommonDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", CommonDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", CommonDesc->bDescriptorSubtype); DisplayBytes((PUCHAR)(CommonDesc + 1), CommonDesc->bLength); return TRUE; } /***************************************************************************** DisplayBytes() *****************************************************************************/ VOID DisplayBytes ( PUCHAR Data, USHORT Len ) { USHORT i; for (i = 0; i < Len; i++) { AppendTextBuffer("%02X ", Data[i]); if (i % 16 == 15) { AppendTextBuffer("\r\n"); } } if (i % 16 != 0) { AppendTextBuffer("\r\n"); } } ================================================ FILE: tests/projects/windows/winsdk/usbview/display.c ================================================ /*++ Copyright (c) 1997-2011 Microsoft Corporation Module Name: DISPLAY.C Abstract: This source file contains the routines which update the edit control to display information about the selected USB device. Environment: user mode Revision History: 04-25-97 : created 03-28-03 : extensive changes to support new USBVCD 03-28-08 : extensive changes to support new USB Video Class 1.1 --*/ /***************************************************************************** I N C L U D E S *****************************************************************************/ #include "uvcview.h" #include "h264.h" #include #include "vndrlist.h" #include "langidlist.h" /***************************************************************************** D E F I N E S *****************************************************************************/ #define BUFFERALLOCINCREMENT 0x10000 #define BUFFERMINFREESPACE 0x1000 /***************************************************************************** T Y P E D E F S *****************************************************************************/ // // Hardcoded information about specific EHCI controllers // typedef struct _EHCI_CONTROLLER_DATA { USHORT VendorID; USHORT DeviceID; UCHAR DebugPortNumber; } EHCI_CONTROLLER_DATA, *PEHCI_CONTROLLER_DATA; /***************************************************************************** G L O B A L S P R I V A T E T O T H I S F I L E *****************************************************************************/ // Workspace for text info which is used to update the edit control // CHAR *TextBuffer = NULL; UINT TextBufferLen = 0; UINT TextBufferPos = 0; STRINGLIST slPowerState [] = { {WdmUsbPowerNotMapped, "S? (unmapped) ", ""}, {WdmUsbPowerSystemUnspecified, "S? (unspecified)", ""}, {WdmUsbPowerSystemWorking, "S0 (working) ", ""}, {WdmUsbPowerSystemSleeping1, "S1 (sleep) ", ""}, {WdmUsbPowerSystemSleeping2, "S2 (sleep) ", ""}, {WdmUsbPowerSystemSleeping3, "S3 (sleep) ", ""}, {WdmUsbPowerSystemHibernate, "S4 (Hibernate) ", ""}, {WdmUsbPowerSystemShutdown, "S5 (shutdown) ", ""}, {WdmUsbPowerDeviceUnspecified, "D? (unspecified)", ""}, {WdmUsbPowerDeviceD0, "D0 ", ""}, {WdmUsbPowerDeviceD1, "D1 ", ""}, {WdmUsbPowerDeviceD2, "D2 ", ""}, {WdmUsbPowerDeviceD3, "D3 ", ""}, }; STRINGLIST slControllerFlavor[] = { { USB_HcGeneric, "USB_HcGeneric", "" }, { OHCI_Generic, "OHCI_Generic", "" }, { OHCI_Hydra, "OHCI_Hydra", "" }, { OHCI_NEC, "OHCI_NEC", "" }, { UHCI_Generic, "UHCI_Generic", "" }, { UHCI_Piix4, "UHCI_Piix4", "" }, { UHCI_Piix3, "UHCI_Piix3", "" }, { UHCI_Ich2, "UHCI_Ich2", "" }, { UHCI_Reserved204, "UHCI_Reserved204", "" }, { UHCI_Ich1, "UHCI_Ich1", "" }, { UHCI_Ich3m, "UHCI_Ich3m", "" }, { UHCI_Ich4, "UHCI_Ich4", "" }, { UHCI_Ich5, "UHCI_Ich5", "" }, { UHCI_Ich6, "UHCI_Ich6", "" }, { UHCI_Intel, "UHCI_Intel", "" }, { UHCI_VIA, "UHCI_VIA", "" }, { UHCI_VIA_x01, "UHCI_VIA_x01", "" }, { UHCI_VIA_x02, "UHCI_VIA_x02", "" }, { UHCI_VIA_x03, "UHCI_VIA_x03", "" }, { UHCI_VIA_x04, "UHCI_VIA_x04", "" }, { UHCI_VIA_x0E_FIFO, "UHCI_VIA_x0E_FIFO", "" }, { EHCI_Generic, "EHCI_Generic", "" }, { EHCI_NEC, "EHCI_NEC", "" }, { EHCI_Lucent, "EHCI_Lucent", "" }, { EHCI_NVIDIA_Tegra2, "EHCI_NVIDIA_Tegra2", "" }, { EHCI_NVIDIA_Tegra3, "EHCI_NVIDIA_Tegra3", "" }, { EHCI_Intel_Medfield, "EHCI_Intel_Medfield", "" } }; // // For supporting pre Win8 versions of Windows, a hardcoded list is maintained for determining // debug port numbers. As usbport.inf is augmented with new host controllers, this list should // be updated. // // The following entries do not have a debug port: // PCI\VEN_8086&DEV_0806 - "Intel(R) SM35 Express Chipset USB2 Enhanced Host Controller MPH - 0806" // PCI\VEN_8086&DEV_0811 - "Intel(R) SM35 Express Chipset USB2 Enhanced Host Controller SPM - 0811" // EHCI_CONTROLLER_DATA EhciControllerData[] = { {0x8086, 0x24CD, 1}, // ICH4 - Intel(R) 82801DB/DBM USB 2.0 Enhanced Host Controller - 24CD {0x8086, 0x24DD, 1}, // ICH5 - Intel(R) 82801EB USB2 Enhanced Host Controller - 24DD {0x8086, 0x25AD, 1}, // ICH5 - Intel(R) 6300ESB USB2 Enhanced Host Controller - 25AD {0x8086, 0x265C, 1}, // ICH6 - Intel(R) 82801FB/FBM USB2 Enhanced Host Controller - 265C {0x8086, 0x268C, 1}, // Intel(R) 631xESB/6321ESB/3100 Chipset USB2 Enhanced Host Controller - 268C {0x8086, 0x27CC, 1}, // ICH7 - Intel(R) 82801G (ICH7 Family) USB2 Enhanced Host Controller - 27CC {0x8086, 0x2836, 1}, // ICH8 - Intel(R) ICH8 Family USB2 Enhanced Host Controller - 2836 {0x8086, 0x283A, 1}, // ICH8 - Intel(R) ICH8 Family USB2 Enhanced Host Controller - 283A {0x8086, 0x293A, 1}, // ICH9 - Intel(R) ICH9 Family USB2 Enhanced Host Controller - 293A {0x8086, 0x293C, 1}, // ICH9 - Intel(R) ICH9 Family USB2 Enhanced Host Controller - 293C {0x8086, 0x3A3A, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A3A {0x8086, 0x3A3C, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A3C {0x8086, 0x3A6A, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A6A {0x8086, 0x3A6C, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A6C {0x8086, 0x3B34, 2}, // 5 series - Intel(R) 5 Series/3400 Series Chipset Family USB Enhanced Host Controller - 3B34 {0x8086, 0x3B36, 2}, // 5 series - Intel(R) 5 Series/3400 Series Chipset Family USB Universal Host Controller - 3B36 {0x8086, 0x1C26, 2}, // 6 series - Intel(R) 6 Series/C200 Series Chipset Family USB Enhanced Host Controller - 1C26 {0x8086, 0x1C2D, 2}, // 6 series - Intel(R) 6 Series/C200 Series Chipset Family USB Enhanced Host Controller - 1C2D {0x8086, 0x1D26, 2}, // Intel(R) C600/X79 series chipset USB2 Enhanced Host Controller #1 - 1D26 {0x8086, 0x1D2D, 2}, // Intel(R) C600/X79 series chipset USB2 Enhanced Host Controller #2 - 1D2D {0x8086, 0x268C, 1}, // Intel(R) 631xESB/6321ESB/3100 Chipset USB2 Enhanced Host Controller - 268C {0x10DE, 0x00D8, 1}, {0,0,0}, }; /***************************************************************************** L O C A L F U N C T I O N P R O T O T Y P E S *****************************************************************************/ VOID DisplayPortConnectorProperties ( _In_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 ); void DisplayDevicePowerState ( _In_ PDEVICE_INFO_NODE DeviceInfoNode ); VOID DisplayHubInfo ( PUSB_HUB_INFORMATION HubInfo, BOOL DisplayDescriptor ); VOID DisplayHubInfoEx ( PUSB_HUB_INFORMATION_EX HubInfoEx ); VOID DisplayHubCapabilityEx ( PUSB_HUB_CAPABILITIES_EX HubCapabilityEx ); VOID DisplayPowerState( PUSB_POWER_INFO pUPI ); VOID DisplayConnectionInfo ( _In_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo, _In_ PUSBDEVICEINFO info, _In_ PSTRING_DESCRIPTOR_NODE StringDescs, _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 ); VOID DisplayPipeInfo ( ULONG NumPipes, USB_PIPE_INFO *PipeInfo ); VOID DisplayConfigDesc ( PUSBDEVICEINFO info, PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, PSTRING_DESCRIPTOR_NODE StringDescs ); VOID DisplayBosDescriptor ( PUSBDEVICEINFO info, PUSB_BOS_DESCRIPTOR BosDesc, PSTRING_DESCRIPTOR_NODE StringDescs ); VOID DisplayBillboardCapabilityDescriptor ( PUSBDEVICEINFO info, PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR billboardCapDesc, PSTRING_DESCRIPTOR_NODE StringDescs ); VOID DisplayDeviceQualifierDescriptor ( PUSB_DEVICE_QUALIFIER_DESCRIPTOR DevQualDesc ); VOID DisplayConfigurationDescriptor ( PUSBDEVICEINFO info, PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, PSTRING_DESCRIPTOR_NODE StringDescs ); VOID DisplayInterfaceDescriptor ( PUSB_INTERFACE_DESCRIPTOR InterfaceDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); VOID DisplayEndpointDescriptor ( _In_ PUSB_ENDPOINT_DESCRIPTOR EndpointDesc, _In_opt_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc, _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochCompDesc, _In_ UCHAR InterfaceClass, _In_ BOOLEAN EpCompDescAvail ); VOID DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor( _In_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc ); VOID DisplayEndointCompanionDescriptor ( _In_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc, _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc, _In_ UCHAR DescType ); VOID DisplayHidDescriptor ( PUSB_HID_DESCRIPTOR HidDesc ); VOID DisplayOTGDescriptor ( PUSB_OTG_DESCRIPTOR OTGDesc ); void InitializePerDeviceSettings ( PUSBDEVICEINFO info ); UINT IsUVCDevice ( PUSBDEVICEINFO info ); VOID DisplayIADDescriptor ( PUSB_IAD_DESCRIPTOR IADDesc, PSTRING_DESCRIPTOR_NODE StringDescs, int nInterfaces, DEVICE_POWER_STATE LatestDevicePowerState ); VOID DisplayUSEnglishStringDescriptor ( UCHAR Index, PSTRING_DESCRIPTOR_NODE USStringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); VOID DisplayUnknownDescriptor ( PUSB_COMMON_DESCRIPTOR CommonDesc ); VOID DisplayRemainingUnknownDescriptor( PUCHAR DescriptorData, ULONG Start, ULONG Stop ); PCHAR GetVendorString ( USHORT idVendor ); PCHAR GetLangIDString ( USHORT idLang ); UINT GetConfigurationSize ( PUSBDEVICEINFO info ); UINT GetInterfaceCount ( PUSBDEVICEINFO info ); /***************************************************************************** L O C A L F U N C T I O N S *****************************************************************************/ /***************************************************************************** NextDescriptor() *****************************************************************************/ //__forceinline PUSB_COMMON_DESCRIPTOR NextDescriptor( _In_ PUSB_COMMON_DESCRIPTOR Descriptor ) { if (Descriptor->bLength == 0) { return NULL; } return (PUSB_COMMON_DESCRIPTOR)((PUCHAR)Descriptor + Descriptor->bLength); } /***************************************************************************** GetNextDescriptor() *****************************************************************************/ PUSB_COMMON_DESCRIPTOR GetNextDescriptor( _In_reads_bytes_(TotalLength) PUSB_COMMON_DESCRIPTOR FirstDescriptor, _In_ ULONG TotalLength, _In_ PUSB_COMMON_DESCRIPTOR StartDescriptor, _In_ long DescriptorType ) { PUSB_COMMON_DESCRIPTOR currentDescriptor = NULL; PUSB_COMMON_DESCRIPTOR endDescriptor = NULL; endDescriptor = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)FirstDescriptor + TotalLength); if (StartDescriptor >= endDescriptor || NextDescriptor(StartDescriptor)>= endDescriptor) { return NULL; } if (DescriptorType == -1) // -1 means any type { return NextDescriptor(StartDescriptor); } currentDescriptor = StartDescriptor; while (((currentDescriptor = NextDescriptor(currentDescriptor)) < endDescriptor) && currentDescriptor != NULL) { if (currentDescriptor->bDescriptorType == (UCHAR)DescriptorType) { return currentDescriptor; } } return NULL; } /***************************************************************************** CreateTextBuffer() *****************************************************************************/ BOOL CreateTextBuffer ( ) { // Allocate the buffer // TextBuffer = ALLOC(BUFFERALLOCINCREMENT); if (TextBuffer == NULL) { OOPS(); return FALSE; } TextBufferLen = BUFFERALLOCINCREMENT; // Reset the buffer position and terminate the buffer // memset(TextBuffer, 0, BUFFERALLOCINCREMENT); TextBufferPos = 0; return TRUE; } /***************************************************************************** DestroyTextBuffer() *****************************************************************************/ VOID DestroyTextBuffer ( ) { if (TextBuffer != NULL) { FREE(TextBuffer); TextBuffer = NULL; } } /***************************************************************************** ResetTextBuffer() *****************************************************************************/ BOOL ResetTextBuffer ( ) { // Fail if the text buffer has not been allocated // if (TextBuffer == NULL) { OOPS(); return FALSE; } // Reset the buffer position and terminate the buffer // *TextBuffer = 0; TextBufferPos = 0; return TRUE; } /***************************************************************************** GetTextBufferPos() *****************************************************************************/ UINT GetTextBufferPos ( ) { return TextBufferPos; } /***************************************************************************** AppendTextBuffer() *****************************************************************************/ VOID __cdecl AppendTextBuffer ( LPCTSTR lpFormat, ... ) { va_list arglist; HRESULT hr = S_OK; int nPos = TextBufferPos; char LocalTextBuffer[512]; va_start(arglist, lpFormat); // Make sure we have a healthy amount of space free in the buffer, // reallocating the buffer if necessary. // if (TextBufferLen - TextBufferPos < BUFFERMINFREESPACE) { CHAR *TextBufferTmp; UINT uNewTextBufferLen = 0; hr = UIntAdd(TextBufferLen, BUFFERALLOCINCREMENT, &uNewTextBufferLen); if (hr != S_OK) { // we've exceeded DWORD length of (2^32)-1 for buffer OOPS(); return; } TextBufferTmp = REALLOC(TextBuffer, uNewTextBufferLen); if (TextBufferTmp != NULL) { TextBuffer = TextBufferTmp; TextBufferLen += BUFFERALLOCINCREMENT; // update TextBufferLen to reflect the new, bigger size of the text buffer } else { // If GlobalReAlloc fails, the original memory is not freed, // and the original handle and pointer are still valid. // OOPS(); return; } } // Add the text to the end of the buffer // hr = StringCchVPrintf(LocalTextBuffer, sizeof(LocalTextBuffer), lpFormat, arglist); if (SUCCEEDED(hr)) { size_t cbMax = 512; size_t pcb = 0; // Ensure TextBuffer is zero terminated // The text buffer size is specified by TextBufferLen. // the text buffer size will be bigger than BUFFERALLOCINCREMENT if the buffer has been reallocated more than // once (which would happen if it had to be made bigger to hold more text) hr = StringCbLength((LPCTSTR) TextBuffer, TextBufferLen, // the maximum number of bytes allowed in TextBuffer. &pcb); if (FAILED(hr)) // buffer is not null-terminated, go ahead and do that { TextBuffer[TextBufferLen-1] = 0; } hr = StringCbLength((LPCTSTR) LocalTextBuffer, cbMax, &pcb); if (SUCCEEDED(hr)) { StringCbCatN(TextBuffer, TextBufferLen, LocalTextBuffer, pcb); // Increment the text position by the number of charcters we just added to it. TextBufferPos += (UINT) pcb; } // If DebugLog flag set, send output to the debugger // if (gLogDebug) { OutputDebugString(TextBuffer + nPos); // print the string just added to the text buffer } } } //***************************************************************************** // // GetTextBuffer // // Returns the display text buffer // //***************************************************************************** PCHAR GetTextBuffer(void) { return (TextBuffer); } //***************************************************************************** // // GetEhciDebugPort // // Returns debug port value if present for EHCI controller. 0 if its not present // //***************************************************************************** ULONG GetEhciDebugPort(ULONG vendorId, ULONG deviceId) { int i = 0; ULONG debugPort = 0; for (i = 0; EhciControllerData[i].VendorID != 0; i++) { if (vendorId == EhciControllerData[i].VendorID && deviceId == EhciControllerData[i].DeviceID) { debugPort = EhciControllerData[i].DebugPortNumber; break; } } return debugPort; } //***************************************************************************** // // UpdateTreeItemDeviceInfo // // hTreeItem - Handle of selected TreeView item for which information should // be added to the TextBuffer global // // The functions returns error status if AppendTextBuffer() used in Display*() functions // fails. The display text would be missing or truncated in such cases. //***************************************************************************** HRESULT UpdateTreeItemDeviceInfo( HWND hTreeWnd, HTREEITEM hTreeItem ) { TV_ITEM tvi; PVOID info; ULONG i; HRESULT hr = S_OK; PCHAR tviName = NULL; SetLastError(0); #ifndef H264_SUPPORT UNREFERENCED_PARAMETER(bShowVersion) #endif #ifdef H264_SUPPORT ResetErrorCounts(); #endif tviName = ALLOC(256); if(NULL == tviName) { OOPS(); hr = E_OUTOFMEMORY; return hr; } // // Get the name of the TreeView item, along with the a pointer to the // info we stored about the item in the item's lParam. // tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM; tvi.hItem = hTreeItem; tvi.pszText = (LPSTR) tviName; tvi.cchTextMax = 256; TreeView_GetItem(hTreeWnd, &tvi); info = (PVOID)tvi.lParam; AppendTextBuffer(tviName); AppendTextBuffer("\r\n"); // // If we didn't store any info for the item, just display the item's // name, else display the info we stored for the item. // if (NULL != info) { PUSB_NODE_INFORMATION HubInfo = NULL; PCHAR HubName = NULL; PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo = NULL; PUSB_DESCRIPTOR_REQUEST ConfigDesc = NULL; PSTRING_DESCRIPTOR_NODE StringDescs = NULL; PUSB_HUB_INFORMATION_EX HubInfoEx = NULL; PUSB_HUB_CAPABILITIES_EX HubCapabilityEx = NULL; PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps = NULL; PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 = NULL; PUSB_DESCRIPTOR_REQUEST BosDesc = NULL; PDEVICE_INFO_NODE DeviceInfoNode = NULL; // The TextBuffer has the TreeView name; add 2 lines for display AppendTextBuffer("\r\n\r\n"); switch (*(PUSBDEVICEINFOTYPE)info) { case HostControllerInfo: { HTREEITEM rootHubItem = NULL; BOOL dbgPortFound = FALSE; AppendTextBuffer("DriverKey: %s\r\n", ((PUSBHOSTCONTROLLERINFO)info)->DriverKey); AppendTextBuffer("VendorID: %04X\r\n", ((PUSBHOSTCONTROLLERINFO)info)->VendorID); AppendTextBuffer("DeviceID: %04X\r\n", ((PUSBHOSTCONTROLLERINFO)info)->DeviceID); AppendTextBuffer("SubSysID: %08X\r\n", ((PUSBHOSTCONTROLLERINFO)info)->SubSysID); AppendTextBuffer("Revision: %02X\r\n", ((PUSBHOSTCONTROLLERINFO)info)->Revision); // // Search for the debug port number. If running on Win8 or later, // the USB_PORT_CONNECTOR_PROPERTIES structure will contain the // port number. If that fails, the list of known host controllers // with debug ports will be searched. // AppendTextBuffer("\r\nDebug Port Number: "); rootHubItem = TreeView_GetChild(hTreeWnd, hTreeItem); if (rootHubItem != NULL) { HTREEITEM portItem = NULL; PVOID portInfo; portItem = TreeView_GetChild(hTreeWnd, rootHubItem); while (portItem != NULL) { tvi.mask = TVIF_PARAM; tvi.hItem = portItem; tvi.pszText = NULL; tvi.cchTextMax = 0; TreeView_GetItem(hTreeWnd, &tvi); portInfo = (PVOID)tvi.lParam; // // Note that an empty port is a port without a device attached // is still a DeviceInfo instance. // if ((*(PUSBDEVICEINFOTYPE)portInfo) == DeviceInfo) { ConnectionInfo = ((PUSBDEVICEINFO)portInfo)->ConnectionInfo; PortConnectorProps = ((PUSBDEVICEINFO)portInfo)->PortConnectorProps; } else if ((*(PUSBDEVICEINFOTYPE)portInfo) == ExternalHubInfo) { ConnectionInfo = ((PUSBEXTERNALHUBINFO)portInfo)->ConnectionInfo; PortConnectorProps = ((PUSBEXTERNALHUBINFO)portInfo)->PortConnectorProps; } if (ConnectionInfo != NULL && PortConnectorProps != NULL && PortConnectorProps->UsbPortProperties.PortIsDebugCapable) { dbgPortFound = TRUE; AppendTextBuffer("%d\r\n", ((PUSBDEVICEINFO)portInfo)->ConnectionInfo->ConnectionIndex); break; } portItem = TreeView_GetNextSibling(hTreeWnd, portItem); } // // Resetting ConnectionInfo and PortConnectorProps to NULL so that they won't be erroneously // be displayed below. // ConnectionInfo = NULL; PortConnectorProps = NULL; } if (dbgPortFound == FALSE) { for (i = 0; EhciControllerData[i].VendorID; i++) { if (((PUSBHOSTCONTROLLERINFO)info)->VendorID == EhciControllerData[i].VendorID && ((PUSBHOSTCONTROLLERINFO)info)->DeviceID == EhciControllerData[i].DeviceID) { dbgPortFound = TRUE; AppendTextBuffer("%d\r\n", EhciControllerData[i].DebugPortNumber); break; } } } if (dbgPortFound == FALSE) { AppendTextBuffer("None\r\n"); } // // Display bus/device/function to help with setting debug // settings. // if (((PUSBHOSTCONTROLLERINFO)info)->BusDeviceFunctionValid) { AppendTextBuffer("Bus.Device.Function (in decimal): %d.%d.%d\r\n", ((PUSBHOSTCONTROLLERINFO)info)->BusNumber, ((PUSBHOSTCONTROLLERINFO)info)->BusDevice, ((PUSBHOSTCONTROLLERINFO)info)->BusFunction); } // Display the USB Host Controller Power State Info { PUSB_POWER_INFO pUPI = (PUSB_POWER_INFO) &((PUSBHOSTCONTROLLERINFO)info)->USBPowerInfo[0]; int nIndex = 0; int nPowerState = WdmUsbPowerSystemWorking; AppendTextBuffer("\r\nHost Controller Power State Mappings\r\n"); AppendTextBuffer("System State\t\tHost Controller\t\tRoot Hub\tUSB wakeup\tPowered\r\n"); for ( ; nPowerState < WdmUsbPowerSystemShutdown; nIndex++, nPowerState++, pUPI++) { DisplayPowerState(pUPI); } AppendTextBuffer("%s\t%s\r\n", "Last Sleep State", GetPowerStateString(pUPI->LastSystemSleepState) ); } break; } case RootHubInfo: HubInfo = ((PUSBROOTHUBINFO)info)->HubInfo; HubName = ((PUSBROOTHUBINFO)info)->HubName; HubCapabilityEx = ((PUSBROOTHUBINFO)info)->HubCapabilityEx; AppendTextBuffer("Root Hub: %s\r\n", HubName); break; case ExternalHubInfo: HubInfo = ((PUSBEXTERNALHUBINFO)info)->HubInfo; HubName = ((PUSBEXTERNALHUBINFO)info)->HubName; HubInfoEx = ((PUSBEXTERNALHUBINFO)info)->HubInfoEx; HubCapabilityEx = ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx; ConnectionInfo = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo; ConnectionInfoV2 = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2; PortConnectorProps = ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps; ConfigDesc = ((PUSBEXTERNALHUBINFO)info)->ConfigDesc; StringDescs = ((PUSBEXTERNALHUBINFO)info)->StringDescs; BosDesc = ((PUSBEXTERNALHUBINFO)info)->BosDesc; DeviceInfoNode = ((PUSBEXTERNALHUBINFO)info)->DeviceInfoNode; AppendTextBuffer("External Hub: %s\r\n", HubName); break; case DeviceInfo: ConnectionInfo = ((PUSBDEVICEINFO)info)->ConnectionInfo; ConnectionInfoV2 = ((PUSBDEVICEINFO)info)->ConnectionInfoV2; PortConnectorProps = ((PUSBDEVICEINFO)info)->PortConnectorProps; ConfigDesc = ((PUSBDEVICEINFO)info)->ConfigDesc; StringDescs = ((PUSBDEVICEINFO)info)->StringDescs; BosDesc = ((PUSBDEVICEINFO)info)->BosDesc; DeviceInfoNode = ((PUSBDEVICEINFO)info)->DeviceInfoNode; break; } if (PortConnectorProps) { DisplayPortConnectorProperties(PortConnectorProps, ConnectionInfoV2); } if (DeviceInfoNode) { DisplayDevicePowerState(DeviceInfoNode); } if (HubInfo) { DisplayHubInfo(&HubInfo->u.HubInformation, (HubInfoEx == NULL)); } if (HubInfoEx) { DisplayHubInfoEx(HubInfoEx); } if(HubCapabilityEx) { DisplayHubCapabilityEx(HubCapabilityEx); } if (ConnectionInfo) { DisplayConnectionInfo(ConnectionInfo, (PUSBDEVICEINFO)info, StringDescs, ConnectionInfoV2); } if (ConfigDesc) { DisplayConfigDesc((PUSBDEVICEINFO)info, (PUSB_CONFIGURATION_DESCRIPTOR)(ConfigDesc + 1), StringDescs); } if (BosDesc) { DisplayBosDescriptor((PUSBDEVICEINFO) info, (PUSB_BOS_DESCRIPTOR) (BosDesc + 1), StringDescs); } } if(tviName != NULL) { FREE(tviName); } // AppendTextBuffer() which is used in Display*() functions uses GlobalRealloc() which can fail if realloc fails. // Obtain last error code from GetLastError() and propagate the error to caller. hr = HRESULT_FROM_WIN32(GetLastError()); return hr; } //***************************************************************************** // // UpdateEditControl() // // hTreeItem - Handle of selected TreeView item for which information should // be displayed in the edit control. // //***************************************************************************** VOID UpdateEditControl ( HWND hEditWnd, HWND hTreeWnd, HTREEITEM hTreeItem ) { HRESULT hr = S_OK; // Start with an empty text buffer. // if (!ResetTextBuffer()) { return; } // Get the item information in global TextBuffer hr = UpdateTreeItemDeviceInfo(hTreeWnd, hTreeItem); if(FAILED(hr)) { OOPS(); } // All done formatting text buffer with info, now update the edit // control with the contents of the text buffer // SetWindowText(hEditWnd, TextBuffer); } /***************************************************************************** DisplayPortConnectorProperties() PortConnectorProps - Info about the port connector properties. *****************************************************************************/ void DisplayPortConnectorProperties ( _In_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 ) { AppendTextBuffer("Is Port User Connectable: %s\r\n", PortConnectorProps->UsbPortProperties.PortIsUserConnectable ? "yes" : "no"); AppendTextBuffer("Is Port Debug Capable: %s\r\n", PortConnectorProps->UsbPortProperties.PortIsDebugCapable ? "yes" : "no"); AppendTextBuffer("Companion Port Number: %d\r\n", PortConnectorProps->CompanionPortNumber); AppendTextBuffer("Companion Hub Symbolic Link Name: %ws\r\n", PortConnectorProps->CompanionHubSymbolicLinkName); if (ConnectionInfoV2 != NULL) { AppendTextBuffer("Protocols Supported:\r\n"); AppendTextBuffer(" USB 1.1: %s\r\n", ConnectionInfoV2->SupportedUsbProtocols.Usb110 ? "yes" : "no"); AppendTextBuffer(" USB 2.0: %s\r\n", ConnectionInfoV2->SupportedUsbProtocols.Usb200 ? "yes" : "no"); AppendTextBuffer(" USB 3.0: %s\r\n", ConnectionInfoV2->SupportedUsbProtocols.Usb300 ? "yes" : "no"); } AppendTextBuffer("\r\n"); } /***************************************************************************** DisplayDevicePowerState() DeviceInfoNode - Structure containing info used to acquire device state *****************************************************************************/ void DisplayDevicePowerState ( _In_ PDEVICE_INFO_NODE DeviceInfoNode ) { DEVICE_POWER_STATE powerState; powerState = AcquireDevicePowerState(DeviceInfoNode); AppendTextBuffer("Device Power State: "); if (powerState >= PowerDeviceD0 && powerState <= PowerDeviceD3) { AppendTextBuffer("PowerDeviceD%d\r\n", powerState-1); } else { AppendTextBuffer("Invalid Device Power State Value %d\r\n", powerState); } AppendTextBuffer("\r\n"); } /***************************************************************************** DisplayHubDescriptorBase() HubDescriptor - hub descriptor, could also be PUSB_30_HUB_DESCRIPTOR which has these field in common at the beginning of the data structure: - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bNumberOfPorts; - USHORT wHubCharacteristics; - UCHAR bPowerOnToPowerGood; - UCHAR bHubControlCurrent; *****************************************************************************/ VOID DisplayHubDescriptorBase( PUSB_HUB_DESCRIPTOR HubDescriptor ) { USHORT wHubChar = 0; AppendTextBuffer("Number of Ports: %d\r\n", HubDescriptor->bNumberOfPorts); wHubChar = HubDescriptor->wHubCharacteristics; switch (wHubChar & 0x0003) { case 0x0000: AppendTextBuffer("Power switching: Ganged\r\n"); break; case 0x0001: AppendTextBuffer("Power switching: Individual\r\n"); break; case 0x0002: case 0x0003: AppendTextBuffer("Power switching: None\r\n"); break; } switch (wHubChar & 0x0004) { case 0x0000: AppendTextBuffer("Compound device: No\r\n"); break; case 0x0004: AppendTextBuffer("Compound device: Yes\r\n"); break; } switch (wHubChar & 0x0018) { case 0x0000: AppendTextBuffer("Over-current Protection: Global\r\n"); break; case 0x0008: AppendTextBuffer("Over-current Protection: Individual\r\n"); break; case 0x0010: case 0x0018: AppendTextBuffer("No Over-current Protection (Bus Power Only)\r\n"); break; } } /***************************************************************************** DisplayHubInfo() HubInfo - Info about the hub. *****************************************************************************/ VOID DisplayHubInfo ( PUSB_HUB_INFORMATION HubInfo, BOOL DisplayDescriptor ) { AppendTextBuffer("Hub Power: %s\r\n", HubInfo->HubIsBusPowered ? "Bus Power" : "Self Power"); if (DisplayDescriptor == TRUE) { DisplayHubDescriptorBase(&HubInfo->HubDescriptor); } } /***************************************************************************** DisplayHubInfoEx() HubInfo - Extended info about the hub. *****************************************************************************/ VOID DisplayHubInfoEx ( PUSB_HUB_INFORMATION_EX HubInfoEx ) { AppendTextBuffer("Hub type: "); switch (HubInfoEx->HubType) { case UsbRootHub: AppendTextBuffer("USB Root Hub\r\n"); break; case Usb20Hub: AppendTextBuffer("USB 2.0 Hub\r\n"); DisplayHubDescriptorBase((PUSB_HUB_DESCRIPTOR)&HubInfoEx->u.UsbHubDescriptor); break; case Usb30Hub: AppendTextBuffer("USB 3.0 Hub\r\n"); // // Note that the DisplayHubDescriptorBase will display the fields of either // the legacy hub descriptor and the USB 3.0 descriptor which have the same // offset // DisplayHubDescriptorBase((PUSB_HUB_DESCRIPTOR)&HubInfoEx->u.UsbHubDescriptor); AppendTextBuffer("Packet Header Decode Latency: 0x%x\r\n", HubInfoEx->u.Usb30HubDescriptor.bHubHdrDecLat); AppendTextBuffer("Delay: 0x%x ns\r\n", HubInfoEx->u.Usb30HubDescriptor.wHubDelay); break; default: AppendTextBuffer("ERROR: Unknown hub type %d\r\n", HubInfoEx->HubType); break; } AppendTextBuffer("\r\n"); } /***************************************************************************** DisplayHubCapabilityEx() HubCapabilityInfo - Hub capability information *****************************************************************************/ VOID DisplayHubCapabilityEx ( PUSB_HUB_CAPABILITIES_EX HubCapabilityEx ) { if(HubCapabilityEx != NULL) { AppendTextBuffer("High speed capable: %s\r\n", HubCapabilityEx->CapabilityFlags.HubIsHighSpeedCapable ? "Yes" : "No"); AppendTextBuffer("High speed: %s\r\n", HubCapabilityEx->CapabilityFlags.HubIsHighSpeed ? "Yes" : "No"); AppendTextBuffer("Multiple transaction translations capable: %s\r\n", HubCapabilityEx->CapabilityFlags.HubIsMultiTtCapable ? "Yes" : "No"); AppendTextBuffer("Performs multiple transaction translations simultaneously: %s\r\n", HubCapabilityEx->CapabilityFlags.HubIsMultiTt ? "Yes" : "No"); AppendTextBuffer("Hub wakes when device is connected: %s\r\n", HubCapabilityEx->CapabilityFlags.HubIsArmedWakeOnConnect ? "Yes" : "No"); AppendTextBuffer("Hub is bus powered: %s\r\n", HubCapabilityEx->CapabilityFlags.HubIsBusPowered ? "Yes" : "No"); AppendTextBuffer("Hub is root: %s\r\n", HubCapabilityEx->CapabilityFlags.HubIsRoot ? "Yes" : "No"); } } /***************************************************************************** DisplayConnectionInfo() ConnectInfo - Info about the connection. PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo, PSTRING_DESCRIPTOR_NODE StringDescs DisplayConnectionInfo(info->ConnectionInfo, info->StringDescs); DisplayConnectionInfo ( PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo, PSTRING_DESCRIPTOR_NODE StringDescs ) *****************************************************************************/ VOID DisplayConnectionInfo ( _In_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo, _In_ PUSBDEVICEINFO info, _In_ PSTRING_DESCRIPTOR_NODE StringDescs, _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 ) { //@@DisplayConnectionInfo - Device Information PCHAR VendorString = NULL; UINT tog = 1; UINT uIADcount = 0; // No device connected if (ConnectInfo->ConnectionStatus == NoDeviceConnected) { AppendTextBuffer("ConnectionStatus: NoDeviceConnected\r\n"); return; } // This is the entry point to the device display functions. // First, save this device's PUSBDEVICEINFO address // In a future version of this test, we will keep track of the the // descriptor that we're parsing (# of bytes from beginning of info->configuration descriptor) // Then we can linked descriptors by reading forward through the remaining descriptors // while still keeping our place in this main DisplayConnectionInfo() and called // functions. // // We also initialize some global flags in uvcview.h that are used to // verify items in MJPEG, Uncompressed and Vendor Frame descriptors // InitializePerDeviceSettings(info); if(gDoAnnotation) { AppendTextBuffer(" ---===>Device Information<===---\r\n"); if (ConnectInfo->DeviceDescriptor.iProduct) { DisplayUSEnglishStringDescriptor(ConnectInfo->DeviceDescriptor.iProduct, StringDescs, info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); } AppendTextBuffer("\r\nConnectionStatus: %s\r\n", ConnectionStatuses[ConnectInfo->ConnectionStatus]); AppendTextBuffer("Current Config Value: 0x%02X", ConnectInfo->CurrentConfigurationValue); } switch (ConnectInfo->Speed){ case UsbLowSpeed: if(gDoAnnotation) { AppendTextBuffer(" -> Device Bus Speed: Low\r\n"); } else { AppendTextBuffer("\r\n"); } gDeviceSpeed = UsbLowSpeed; break; case UsbFullSpeed: if(gDoAnnotation) { AppendTextBuffer(" -> Device Bus Speed: Full"); if (ConnectionInfoV2 != NULL) { if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedPlusCapableOrHigher) { AppendTextBuffer(" (is SuperSpeedPlus or higher capable)\r\n"); } else if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedCapableOrHigher) { AppendTextBuffer(" (is SuperSpeed or higher capable)\r\n"); } else { AppendTextBuffer(" (is not SuperSpeed or higher capable)\r\n"); } } else { AppendTextBuffer("\r\n"); } } else { AppendTextBuffer("\r\n"); } gDeviceSpeed = UsbFullSpeed; break; case UsbHighSpeed: if(gDoAnnotation) { AppendTextBuffer(" -> Device Bus Speed: High"); if (ConnectionInfoV2 != NULL) { if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedPlusCapableOrHigher) { AppendTextBuffer(" (is SuperSpeedPlus or higher capable)\r\n"); } else if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedCapableOrHigher) { AppendTextBuffer(" (is SuperSpeed or higher capable)\r\n"); } else { AppendTextBuffer(" (is not SuperSpeed or higher capable)\r\n"); } } else { AppendTextBuffer("\r\n"); } } else { AppendTextBuffer("\r\n"); } gDeviceSpeed = UsbHighSpeed; break; case UsbSuperSpeed: if(gDoAnnotation) { if (ConnectionInfoV2 != NULL) { AppendTextBuffer(" -> Device Bus Speed: Super%s\r\n", ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher ? "SpeedPlus" : "Speed"); } else { AppendTextBuffer(" -> Device Bus Speed: Super Speed\r\n"); } } else { AppendTextBuffer("\r\n"); } gDeviceSpeed = UsbSuperSpeed; break; default: if(gDoAnnotation){AppendTextBuffer(" -> Device Bus Speed: Unknown\r\n");} else {AppendTextBuffer("\r\n");} } if(gDoAnnotation){ AppendTextBuffer("Device Address: 0x%02X\r\n", ConnectInfo->DeviceAddress); AppendTextBuffer("Open Pipes: %2d\r\n", ConnectInfo->NumberOfOpenPipes); } // No open pipes means the USB stack has not loaded the device if (ConnectInfo->NumberOfOpenPipes == 0) { AppendTextBuffer("*!*ERROR: No open pipes!\r\n"); } AppendTextBuffer("\r\n ===>Device Descriptor<===\r\n"); //@@DisplayConnectionInfo - Device Descriptor if (ConnectInfo->DeviceDescriptor.bLength != 18) { //@@TestCase A1.1 //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the //@@ required length in the USB Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", ConnectInfo->DeviceDescriptor.bLength, 18); OOPS(); } AppendTextBuffer("bLength: 0x%02X\r\n", ConnectInfo->DeviceDescriptor.bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", ConnectInfo->DeviceDescriptor.bDescriptorType); //@@TestCase A1.2 //@@Not implemented - Priority 1 //@@Descriptor Field - bcdUSB //@@Need to check that any UVC device is set to 0x0200 or later. AppendTextBuffer("bcdUSB: 0x%04X\r\n", ConnectInfo->DeviceDescriptor.bcdUSB); AppendTextBuffer("bDeviceClass: 0x%02X", ConnectInfo->DeviceDescriptor.bDeviceClass); // Quit on these device failures if ((ConnectInfo->ConnectionStatus == DeviceFailedEnumeration) || (ConnectInfo->ConnectionStatus == DeviceGeneralFailure)) { AppendTextBuffer("\r\n*!*ERROR: Device enumeration failure\r\n"); return; } // Is this an IAD device? uIADcount = IsIADDevice((PUSBDEVICEINFO) info); if (uIADcount) { // this device configuration has 1 or more IAD descriptors if (ConnectInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE) { tog = 0; if (gDoAnnotation) { AppendTextBuffer(" -> This is a Multi-interface Function Code Device\r\n"); } else { AppendTextBuffer("\r\n"); } } else { AppendTextBuffer("\r\n*!*ERROR: device class should be Multi-interface Function 0x%02X\r\n"\ " When IAD descriptor is used\r\n", USB_MISCELLANEOUS_DEVICE); } // Is this a UVC device? g_chUVCversion = IsUVCDevice((PUSBDEVICEINFO) info); } else { // this is not an IAD device switch (ConnectInfo->DeviceDescriptor.bDeviceClass) { case USB_INTERFACE_CLASS_DEVICE: if(gDoAnnotation) {AppendTextBuffer(" -> This is an Interface Class Defined Device\r\n");} else {AppendTextBuffer("\r\n");} break; case USB_COMMUNICATION_DEVICE: tog = 0; if(gDoAnnotation) {AppendTextBuffer(" -> This is a Communication Device\r\n");} else {AppendTextBuffer("\r\n");} break; case USB_HUB_DEVICE: tog = 0; if(gDoAnnotation) {AppendTextBuffer(" -> This is a HUB Device\r\n");} else {AppendTextBuffer("\r\n");} break; case USB_DIAGNOSTIC_DEVICE: tog = 0; if(gDoAnnotation) {AppendTextBuffer(" -> This is a Diagnostic Device\r\n");} else {AppendTextBuffer("\r\n");} break; case USB_WIRELESS_CONTROLLER_DEVICE: tog = 0; if(gDoAnnotation) {AppendTextBuffer(" -> This is a Wireless Controller(Bluetooth) Device\r\n");} else {AppendTextBuffer("\r\n");} break; case USB_VENDOR_SPECIFIC_DEVICE: tog = 0; if(gDoAnnotation) {AppendTextBuffer(" -> This is a Vendor Specific Device\r\n");} else {AppendTextBuffer("\r\n");} break; case USB_DEVICE_CLASS_BILLBOARD: tog = 0; if (gDoAnnotation) { AppendTextBuffer(" -> This is a billboard class device\r\n"); } else { AppendTextBuffer("\r\n"); } break; case USB_MISCELLANEOUS_DEVICE: tog = 0; //@@TestCase A1.3 //@@ERROR //@@Descriptor Field - bDeviceClass //@@Multi-interface Function code used for non-IAD device AppendTextBuffer("\r\n*!*ERROR: Multi-interface Function code %d used for "\ "device with no IAD descriptors\r\n", ConnectInfo->DeviceDescriptor.bDeviceClass); break; default: //@@TestCase A1.4 //@@ERROR //@@Descriptor Field - bDeviceClass //@@An unknown device class has been defined AppendTextBuffer("\r\n*!*ERROR: unknown bDeviceClass %d\r\n", ConnectInfo->DeviceDescriptor.bDeviceClass); OOPS(); break; } } AppendTextBuffer("bDeviceSubClass: 0x%02X", ConnectInfo->DeviceDescriptor.bDeviceSubClass); // check the subclass if (uIADcount) { // this device configuration has 1 or more IAD descriptors if (ConnectInfo->DeviceDescriptor.bDeviceSubClass == USB_COMMON_SUB_CLASS) { if (gDoAnnotation) { AppendTextBuffer(" -> This is the Common Class Sub Class\r\n"); } else { AppendTextBuffer("\r\n"); } } else { //@@TestCase A1.5 //@@ERROR //@@Descriptor Field - bDeviceSubClass //@@An invalid device sub class used for Multi-interface Function (IAD) device AppendTextBuffer("\r\n*!*ERROR: device SubClass should be USB Common Sub Class %d\r\n"\ " When IAD descriptor is used\r\n", USB_COMMON_SUB_CLASS); OOPS(); } } else { // Not an IAD device, so all subclass values are invalid if(ConnectInfo->DeviceDescriptor.bDeviceSubClass > 0x00 && ConnectInfo->DeviceDescriptor.bDeviceSubClass < 0xFF) { //@@TestCase A1.6 //@@ERROR //@@Descriptor Field - bDeviceSubClass //@@An invalid device sub class has been defined AppendTextBuffer("\r\n*!*ERROR: bDeviceSubClass of %d is invalid\r\n", ConnectInfo->DeviceDescriptor.bDeviceSubClass); OOPS(); } else { AppendTextBuffer("\r\n"); } } AppendTextBuffer("bDeviceProtocol: 0x%02X", ConnectInfo->DeviceDescriptor.bDeviceProtocol); // check the protocol if (uIADcount) { // this device configuration has 1 or more IAD descriptors if (ConnectInfo->DeviceDescriptor.bDeviceProtocol == USB_IAD_PROTOCOL) { if (gDoAnnotation) { AppendTextBuffer(" -> This is the Interface Association Descriptor protocol\r\n"); } else { AppendTextBuffer("\r\n"); } } else { //@@TestCase A1.7 //@@ERROR //@@Descriptor Field - bDeviceSubClass //@@An invalid device sub class used for Multi-interface Function (IAD) device AppendTextBuffer("\r\n*!*ERROR: device Protocol should be USB IAD Protocol %d\r\n"\ " When IAD descriptor is used\r\n", USB_IAD_PROTOCOL); OOPS(); } } else { // Not an IAD device, so all subclass values are invalid if(ConnectInfo->DeviceDescriptor.bDeviceProtocol > 0x00 && ConnectInfo->DeviceDescriptor.bDeviceProtocol < 0xFF && tog==1) { //@@TestCase A1.8 //@@ERROR //@@Descriptor Field - bDeviceProtocol //@@An invalid device protocol has been defined AppendTextBuffer("\r\n*!*ERROR: bDeviceProtocol of %d is invalid\r\n", ConnectInfo->DeviceDescriptor.bDeviceProtocol); OOPS(); } else { AppendTextBuffer("\r\n"); } } AppendTextBuffer("bMaxPacketSize0: 0x%02X", ConnectInfo->DeviceDescriptor.bMaxPacketSize0); if(gDoAnnotation) { AppendTextBuffer(" = (%d) Bytes\r\n", ConnectInfo->DeviceDescriptor.bMaxPacketSize0); } else { AppendTextBuffer("\r\n"); } switch (gDeviceSpeed){ case UsbLowSpeed: if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 8) { //@@TestCase A1.9 //@@ERROR //@@Descriptor Field - bMaxPacketSize0 //@@An invalid bMaxPacketSize0 has been defined for a low speed device AppendTextBuffer("*!*ERROR: Low Speed Devices require bMaxPacketSize0 = 8\r\n"); OOPS(); } break; case UsbFullSpeed: if(!(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 8 || ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 16 || ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 32 || ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 64)) { //@@TestCase A1.10 //@@ERROR //@@Descriptor Field - bMaxPacketSize0 //@@An invalid bMaxPacketSize0 has been defined for a full speed device AppendTextBuffer("*!*ERROR: Full Speed Devices require bMaxPacketSize0 = 8, 16, 32, or 64\r\n"); OOPS(); } break; case UsbHighSpeed: if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 64) { //@@TestCase A1.11 //@@ERROR //@@Descriptor Field - bMaxPacketSize0 //@@An invalid bMaxPacketSize0 has been defined for a high speed device AppendTextBuffer("*!*ERROR: High Speed Devices require bMaxPacketSize0 = 64\r\n"); OOPS(); } break; case UsbSuperSpeed: if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 9) { AppendTextBuffer("*!*ERROR: SuperSpeed Devices require bMaxPacketSize0 = 9 (512)\r\n"); OOPS(); } break; } AppendTextBuffer("idVendor: 0x%04X", ConnectInfo->DeviceDescriptor.idVendor); if (gDoAnnotation) { VendorString = GetVendorString(ConnectInfo->DeviceDescriptor.idVendor); if (VendorString != NULL) { AppendTextBuffer(" = %s\r\n", VendorString); } } else {AppendTextBuffer("\r\n");} AppendTextBuffer("idProduct: 0x%04X\r\n", ConnectInfo->DeviceDescriptor.idProduct); AppendTextBuffer("bcdDevice: 0x%04X\r\n", ConnectInfo->DeviceDescriptor.bcdDevice); AppendTextBuffer("iManufacturer: 0x%02X\r\n", ConnectInfo->DeviceDescriptor.iManufacturer); if (ConnectInfo->DeviceDescriptor.iManufacturer && gDoAnnotation) { DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iManufacturer, StringDescs, info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); } AppendTextBuffer("iProduct: 0x%02X\r\n", ConnectInfo->DeviceDescriptor.iProduct); if (ConnectInfo->DeviceDescriptor.iProduct && gDoAnnotation) { DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iProduct, StringDescs, info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); } AppendTextBuffer("iSerialNumber: 0x%02X\r\n", ConnectInfo->DeviceDescriptor.iSerialNumber); if (ConnectInfo->DeviceDescriptor.iSerialNumber && gDoAnnotation) { DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iSerialNumber, StringDescs, info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); } AppendTextBuffer("bNumConfigurations: 0x%02X\r\n", ConnectInfo->DeviceDescriptor.bNumConfigurations); if(ConnectInfo->DeviceDescriptor.bNumConfigurations != 1) { //@@TestCase A1.12 //@@CAUTION //@@Descriptor Field - bNumConfigurations //@@Most host controllers do not handle more than one configuration AppendTextBuffer("*!*CAUTION: Most host controllers will only work with "\ "one configuration per speed\r\n"); OOPS(); } if (ConnectInfo->NumberOfOpenPipes) { AppendTextBuffer("\r\n ---===>Open Pipes<===---\r\n"); DisplayPipeInfo(ConnectInfo->NumberOfOpenPipes, ConnectInfo->PipeList); } return; } /***************************************************************************** DisplayPipeInfo() NumPipes - Number of pipe for we info should be displayed. PipeInfo - Info about the pipes. *****************************************************************************/ VOID DisplayPipeInfo ( ULONG NumPipes, USB_PIPE_INFO *PipeInfo ) { ULONG i = 0; for (i = 0; i < NumPipes; i++) { DisplayEndpointDescriptor(&PipeInfo[i].EndpointDescriptor, NULL, NULL, 0, FALSE); } } /***************************************************************************** GetControllerFlavorString() Returns the text for given controller flavor *****************************************************************************/ PCHAR GetControllerFlavorString(USB_CONTROLLER_FLAVOR flavor) { return(GetStringFromList(slControllerFlavor, sizeof(slControllerFlavor) / sizeof(STRINGLIST), flavor, STR_UNKNOWN_CONTROLLER_FLAVOR)); } /***************************************************************************** GetPowerStateString() Returns the descriptive string for given power state *****************************************************************************/ PCHAR GetPowerStateString(WDMUSB_POWER_STATE powerState) { return(GetStringFromList(slPowerState, sizeof(slPowerState) / sizeof(STRINGLIST), powerState, STR_INVALID_POWER_STATE)); } /***************************************************************************** DisplayPowerState() PUSB_POWER_INFO pUPI - USBUSER.H USB_Power_Info data *****************************************************************************/ VOID DisplayPowerState( PUSB_POWER_INFO pUPI ) { AppendTextBuffer("%s\t%s\t%s%s\t\t%s\r\n", GetPowerStateString(pUPI->SystemState), GetPowerStateString(pUPI->HcDevicePowerState), GetPowerStateString(pUPI->RhDevicePowerState), pUPI->CanWakeup ? "Yes" : "", pUPI->IsPowered ? "Yes" : "" ); return; } /***************************************************************************** ValidateDescAddress() Given a descriptor address and the Configuration Descriptor length (saved in DisplayConfigDesc(), and initialized for each new device) return TRUE if the descriptor is within the Configuration length else FALSE *****************************************************************************/ BOOL ValidateDescAddress ( PUSB_COMMON_DESCRIPTOR commonDesc ) { if ((PUCHAR) commonDesc + commonDesc->bLength <= g_descEnd) { return TRUE; } return FALSE; } /***************************************************************************** DisplayConfigDesc() ConfigDesc - The Configuration Descriptor, and associated Interface and Endpoint Descriptors *****************************************************************************/ VOID DisplayConfigDesc ( PUSBDEVICEINFO info, PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, PSTRING_DESCRIPTOR_NODE StringDescs ) { PUSB_COMMON_DESCRIPTOR commonDesc = NULL; UCHAR bInterfaceClass = 0; UCHAR bInterfaceSubClass = 0; UCHAR bInterfaceProtocol = 0; BOOL displayUnknown = FALSE; BOOL isSS; isSS = info->ConnectionInfoV2 && info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher ? TRUE : FALSE; commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; // initialize global Configuration start/end address and string desc address g_pConfigDesc = ConfigDesc; g_pStringDescs = StringDescs; g_descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; AppendTextBuffer("\r\n ---===>Full Configuration Descriptor<===---\r\n"); do { displayUnknown = FALSE; switch (commonDesc->bDescriptorType) { case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE: //@@DisplayConfigDesc - Device Qualifier Descriptor if (commonDesc->bLength != sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)) { //@@TestCase A2.1 //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the //@@ required length in the USB Device Specification AppendTextBuffer("*!*ERROR: bLength of %d for Device Qualifier incorrect, "\ "should be %d\r\n", commonDesc->bLength, sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)); OOPS(); displayUnknown = TRUE; break; } DisplayDeviceQualifierDescriptor((PUSB_DEVICE_QUALIFIER_DESCRIPTOR)commonDesc); break; case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE: //@@DisplayConfigDesc - Other Speed Configuration Descriptor if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) { //@@TestCase A2.2 //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the //@@ required length in the USB Device Specification AppendTextBuffer("*!*ERROR: bLength of %d for Other Speed Configuration "\ "incorrect, should be %d\r\n", commonDesc->bLength, sizeof(USB_CONFIGURATION_DESCRIPTOR)); OOPS(); displayUnknown = TRUE; } DisplayConfigurationDescriptor( (PUSBDEVICEINFO) info, (PUSB_CONFIGURATION_DESCRIPTOR)commonDesc, StringDescs); break; case USB_CONFIGURATION_DESCRIPTOR_TYPE: //@@DisplayConfigDesc - Configuration Descriptor if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) { //@@TestCase A2.3 //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the //@@required length in the USB Device Specification AppendTextBuffer("*!*ERROR: bLength of %d for Configuration incorrect, "\ "should be %d\r\n", commonDesc->bLength, sizeof(USB_CONFIGURATION_DESCRIPTOR)); OOPS(); displayUnknown = TRUE; break; } DisplayConfigurationDescriptor((PUSBDEVICEINFO)info, (PUSB_CONFIGURATION_DESCRIPTOR)commonDesc, StringDescs); break; case USB_INTERFACE_DESCRIPTOR_TYPE: //@@DisplayConfigDesc - Interface Descriptor if ((commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR)) && (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))) { //@@TestCase A2.4 //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the //@@required length in the USB Device Specification AppendTextBuffer("*!*ERROR: bLength of %d for Interface incorrect, "\ "should be %d or %d\r\n", commonDesc->bLength, sizeof(USB_INTERFACE_DESCRIPTOR), sizeof(USB_INTERFACE_DESCRIPTOR2)); OOPS(); displayUnknown = TRUE; break; } bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass; bInterfaceSubClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceSubClass; bInterfaceProtocol = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceProtocol; DisplayInterfaceDescriptor( (PUSB_INTERFACE_DESCRIPTOR)commonDesc, StringDescs, info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); break; case USB_ENDPOINT_DESCRIPTOR_TYPE: { PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR epCompDesc = NULL; PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR sspIsochCompDesc = NULL; //@@DisplayConfigDesc - Endpoint Descriptor if ((commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR)) && (commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR2))) { //@@TestCase A2.5 //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to //@@ the required length in the USB Device Specification AppendTextBuffer("*!*ERROR: bLength of %d for Endpoint incorrect, "\ "should be %d or %d\r\n", commonDesc->bLength, sizeof(USB_ENDPOINT_DESCRIPTOR), sizeof(USB_ENDPOINT_DESCRIPTOR2)); OOPS(); displayUnknown = TRUE; break; } if (isSS) { epCompDesc = (PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR) GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc, ConfigDesc->wTotalLength, commonDesc, -1); } if (epCompDesc != NULL && epCompDesc->bmAttributes.Isochronous.SspCompanion == 1) { sspIsochCompDesc = (PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR) GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc, ConfigDesc->wTotalLength, (PUSB_COMMON_DESCRIPTOR)epCompDesc, -1); } DisplayEndpointDescriptor((PUSB_ENDPOINT_DESCRIPTOR)commonDesc, epCompDesc, sspIsochCompDesc, bInterfaceClass, TRUE); if (sspIsochCompDesc != NULL) { commonDesc = (PUSB_COMMON_DESCRIPTOR)sspIsochCompDesc; } else if (epCompDesc != NULL) { commonDesc = (PUSB_COMMON_DESCRIPTOR)epCompDesc; } } break; case USB_HID_DESCRIPTOR_TYPE: if (commonDesc->bLength < sizeof(USB_HID_DESCRIPTOR)) { OOPS(); displayUnknown = TRUE; break; } DisplayHidDescriptor((PUSB_HID_DESCRIPTOR)commonDesc); break; case USB_OTG_DESCRIPTOR_TYPE: if (commonDesc->bLength < sizeof(USB_OTG_DESCRIPTOR)) { OOPS(); displayUnknown = TRUE; break; } DisplayOTGDescriptor((PUSB_OTG_DESCRIPTOR)commonDesc); break; case USB_IAD_DESCRIPTOR_TYPE: if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR)) { OOPS(); displayUnknown = TRUE; break; } DisplayIADDescriptor((PUSB_IAD_DESCRIPTOR)commonDesc, StringDescs, ConfigDesc->bNumInterfaces, info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); break; default: //@@DisplayConfigDesc - Interface Class Device // TODO: BUG: bInterfaceClass is initialized before this code switch (bInterfaceClass) { case USB_DEVICE_CLASS_AUDIO: displayUnknown = ! DisplayAudioDescriptor( (PUSB_AUDIO_COMMON_DESCRIPTOR)commonDesc, bInterfaceSubClass); break; case USB_DEVICE_CLASS_VIDEO: displayUnknown = ! DisplayVideoDescriptor( (PVIDEO_SPECIFIC)commonDesc, bInterfaceSubClass, StringDescs, info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); break; case USB_DEVICE_CLASS_RESERVED: //@@TestCase A2.6 //@@ERROR //@@Descriptor Field - bInterfaceClass //@@An unknown interface class has been defined AppendTextBuffer("*!*ERROR: %d is a Reserved USB Device Interface Class\r\n", USB_DEVICE_CLASS_RESERVED); displayUnknown = TRUE; break; case USB_DEVICE_CLASS_COMMUNICATIONS: AppendTextBuffer(" -> This is a Communications (CDC Control) USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_DEVICE_CLASS_HUMAN_INTERFACE: AppendTextBuffer(" -> This is a HID USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_DEVICE_CLASS_MONITOR: AppendTextBuffer(" -> This is a Monitor USB Device Interface Class (This may be obsolete)\r\n"); displayUnknown = TRUE; break; case USB_DEVICE_CLASS_PHYSICAL_INTERFACE: AppendTextBuffer(" -> This is a Physical Interface USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_DEVICE_CLASS_POWER: if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1) { AppendTextBuffer(" -> This is an Image USB Device Interface Class\r\n"); } else { AppendTextBuffer(" -> This is a Power USB Device Interface Class (This may be obsolete)\r\n"); } displayUnknown = TRUE; break; case USB_DEVICE_CLASS_PRINTER: AppendTextBuffer(" -> This is a Printer USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_DEVICE_CLASS_STORAGE: AppendTextBuffer(" -> This is a Mass Storage USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_DEVICE_CLASS_HUB: AppendTextBuffer(" -> This is a HUB USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_CDC_DATA_INTERFACE: AppendTextBuffer(" -> This is a CDC Data USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_CHIP_SMART_CARD_INTERFACE: AppendTextBuffer(" -> This is a Chip/Smart Card USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_CONTENT_SECURITY_INTERFACE: AppendTextBuffer(" -> This is a Content Security USB Device Interface Class\r\n"); displayUnknown = TRUE; break; case USB_DIAGNOSTIC_DEVICE_INTERFACE: if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1) { AppendTextBuffer(" -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\r\n"); } else { //@@TestCase A2.7 //@@CAUTION //@@Descriptor Field - bInterfaceClass //@@An unknown diagnostic interface class device has been defined AppendTextBuffer("*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } displayUnknown = TRUE; break; case USB_WIRELESS_CONTROLLER_INTERFACE: if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1) { AppendTextBuffer(" -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\r\n"); } else { //@@TestCase A2.8 //@@CAUTION //@@Descriptor Field - bInterfaceClass //@@An unknown wireless controller interface class device has been defined AppendTextBuffer("*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } displayUnknown = TRUE; break; case USB_APPLICATION_SPECIFIC_INTERFACE: AppendTextBuffer(" -> This is an Application Specific USB Device Interface Class\r\n"); switch(bInterfaceSubClass) { case 1: AppendTextBuffer(" -> This is a Device Firmware Application Specific USB Device Interface Class\r\n"); break; case 2: AppendTextBuffer(" -> This is an IrDA Bridge Application Specific USB Device Interface Class\r\n"); break; case 3: AppendTextBuffer(" -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\r\n"); break; default: //@@TestCase A2.9 //@@CAUTION //@@Descriptor Field - bInterfaceClass //@@A possibly invalid interface class has been defined AppendTextBuffer("*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } displayUnknown = TRUE; break; default: if (bInterfaceClass == USB_DEVICE_CLASS_VENDOR_SPECIFIC) { AppendTextBuffer(" -> This is a Vendor Specific USB Device Interface Class\r\n"); } else { //@@TestCase A2.10 //@@CAUTION //@@Descriptor Field - bInterfaceClass //@@An unknown interface class has been defined AppendTextBuffer("*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } displayUnknown = TRUE; break; } break; } if (displayUnknown) { DisplayUnknownDescriptor(commonDesc); } } while ((commonDesc = GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc, ConfigDesc->wTotalLength, commonDesc, -1)) != NULL); #ifdef H264_SUPPORT DoAdditionalErrorChecks(); #endif } /***************************************************************************** DisplayDeviceQualifierDescriptor() *****************************************************************************/ VOID DisplayDeviceQualifierDescriptor ( PUSB_DEVICE_QUALIFIER_DESCRIPTOR DevQualDesc ) { //@@DisplayDeviceQualifierDescriptor - Device Qualifier Descriptor AppendTextBuffer("\r\n ===>Device Qualifier Descriptor<===\r\n"); //length checked in DisplayConfigDesc() AppendTextBuffer("bLength: 0x%02X\r\n", DevQualDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", DevQualDesc->bDescriptorType); AppendTextBuffer("bcdUSB: 0x%04X\r\n", DevQualDesc->bcdUSB); AppendTextBuffer("bDeviceClass: 0x%02X", DevQualDesc->bDeviceClass); switch (DevQualDesc->bDeviceClass) { case USB_INTERFACE_CLASS_DEVICE: if(gDoAnnotation) { AppendTextBuffer(" -> This is an Interface Class Defined Device\r\n"); } break; case USB_COMMUNICATION_DEVICE: if(gDoAnnotation) { AppendTextBuffer(" -> This is a Communication Device\r\n"); } break; case USB_HUB_DEVICE: if(gDoAnnotation) { AppendTextBuffer(" -> This is a HUB Device\r\n"); } break; case USB_DIAGNOSTIC_DEVICE: if(gDoAnnotation) { AppendTextBuffer(" -> This is a Diagnostic Device\r\n"); } break; case USB_WIRELESS_CONTROLLER_DEVICE: if(gDoAnnotation) { AppendTextBuffer(" -> This is a Wireless Controller(Bluetooth) Device\r\n"); } break; case USB_VENDOR_SPECIFIC_DEVICE: if(gDoAnnotation) { AppendTextBuffer(" -> This is a Vendor Specific Device\r\n"); } break; case USB_DEVICE_CLASS_BILLBOARD: if (gDoAnnotation) { AppendTextBuffer(" -> This is a billboard class device\r\n"); } break; default: //@@TestCase A3.1 //@@ERROR //@@Descriptor Field - bDeviceClass //@@An unknown device class has been defined AppendTextBuffer("*!*ERROR: bDeviceClass of %d is invalid\r\n", DevQualDesc->bDeviceClass); OOPS(); break; } AppendTextBuffer("bDeviceSubClass: 0x%02X\r\n", DevQualDesc->bDeviceSubClass); if(DevQualDesc->bDeviceSubClass > 0x00 && DevQualDesc->bDeviceSubClass < 0xFF) { //@@TestCase A3.2 //@@ERROR //@@Descriptor Field - bDeviceSubClass //@@An unknown device sub class has been defined AppendTextBuffer("*!*ERROR: bDeviceSubClass of %d is invalid\r\n", DevQualDesc->bDeviceSubClass); OOPS(); } AppendTextBuffer("bDeviceProtocol: 0x%02X\r\n", DevQualDesc->bDeviceProtocol); if(DevQualDesc->bDeviceProtocol > 0x00 && DevQualDesc->bDeviceProtocol < 0xFF) { //@@TestCase A3.4 //@@ERROR //@@Descriptor Field - bDeviceProtocol //@@An invalid device protocol has been defined AppendTextBuffer("*!*ERROR: bDeviceProtocol of %d is invalid", DevQualDesc->bDeviceProtocol); OOPS(); } //@@TestCase A3.5 //@@Priority 1 //@@Descriptor Field - bcdDevice //@@We should test to verify a valid bMaxPacketSize0 based on speed AppendTextBuffer("bMaxPacketSize0: 0x%02X", DevQualDesc->bMaxPacketSize0); if(gDoAnnotation) { AppendTextBuffer(" = (%d) Bytes\r\n", DevQualDesc->bMaxPacketSize0); } else {AppendTextBuffer("\r\n");} AppendTextBuffer("bNumConfigurations: 0x%02X\r\n", DevQualDesc->bNumConfigurations); if(DevQualDesc->bNumConfigurations != 1) { //@@TestCase A3.6 //@@CAUTION //@@Descriptor Field - bNumConfigurations //@@Most host controllers do not handle more than one configuration AppendTextBuffer("*!*CAUTION: Most host controllers will only work with one configuration per speed\r\n"); OOPS(); } AppendTextBuffer("bReserved: 0x%02X\r\n", DevQualDesc->bReserved); if(DevQualDesc->bReserved != 0) { AppendTextBuffer("*!*WARNING: bReserved needs to be set to 0 to be valid\r\n"); OOPS(); } } VOID DisplayUsb20ExtensionCapabilityDescriptor ( PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR extCapDesc ) { AppendTextBuffer("\r\n ===>USB 2.0 Extension Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", extCapDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", extCapDesc->bDescriptorType); AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", extCapDesc->bDevCapabilityType); AppendTextBuffer("bmAttributes: 0x%08X", extCapDesc->bmAttributes); if (extCapDesc->bmAttributes.AsUlong & USB_DEVICE_CAPABILITY_USB20_EXTENSION_BMATTRIBUTES_RESERVED_MASK) { if(gDoAnnotation) { AppendTextBuffer("\r\n*!*ERROR: bits 31..2 and bit 0 are reserved and must be 0\r\n"); } } if (extCapDesc->bmAttributes.LPMCapable == 1) { if(gDoAnnotation) { AppendTextBuffer(" -> Supports Link Power Management protocol\r\n"); } } if (extCapDesc->bmAttributes.AsUlong == 0) { AppendTextBuffer("\r\n"); } } VOID DisplaySuperSpeedCapabilityDescriptor ( PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR ssCapDesc ) { AppendTextBuffer("\r\n ===>SuperSpeed USB Device Capability Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", ssCapDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", ssCapDesc->bDescriptorType); AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", ssCapDesc->bDevCapabilityType); AppendTextBuffer("bmAttributes: 0x%02X\r\n", ssCapDesc->bmAttributes); if (ssCapDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_RESERVED_MASK) { if(gDoAnnotation) { AppendTextBuffer("\r\n*!*ERROR: bits 7:2 and bit 0 are reserved\r\n"); } } if (ssCapDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_LTM_CAPABLE) { if(gDoAnnotation) { AppendTextBuffer(" -> capable of generating Latency Tolerance Messages\r\n"); } } AppendTextBuffer("wSpeedsSupported: 0x%02X\r\n", ssCapDesc->wSpeedsSupported); if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_LOW) { if(gDoAnnotation) { AppendTextBuffer(" -> Supports low-speed operation\r\n"); } } if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_FULL) { if(gDoAnnotation) { AppendTextBuffer(" -> Supports full-speed operation\r\n"); } } if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_HIGH) { if(gDoAnnotation) { AppendTextBuffer(" -> Supports high-speed operation\r\n"); } } if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_SUPER) { if(gDoAnnotation) { AppendTextBuffer(" -> Supports SuperSpeed operation\r\n"); } } if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_RESERVED_MASK) { if(gDoAnnotation) { AppendTextBuffer("\r\n*!*ERROR: bits 15:4 are reserved\r\n"); } } if (!gDoAnnotation) { AppendTextBuffer("\r\n"); } AppendTextBuffer("bFunctionalitySupport: 0x%02X", ssCapDesc->bFunctionalitySupport); if(gDoAnnotation) { switch (ssCapDesc->bFunctionalitySupport) { case UsbLowSpeed: AppendTextBuffer(" -> lowest speed = low-speed\r\n"); break; case UsbFullSpeed: AppendTextBuffer(" -> lowest speed = full-speed\r\n"); break; case UsbHighSpeed: AppendTextBuffer(" -> lowest speed = high-speed\r\n"); break; case UsbSuperSpeed: AppendTextBuffer(" -> lowest speed = SuperSpeed\r\n"); break; default: AppendTextBuffer("\r\n*!*ERROR: Invalid value\r\n"); break; } } else { AppendTextBuffer("\r\n"); } AppendTextBuffer("bU1DevExitLat: 0x%02X", ssCapDesc->bU1DevExitLat); if(gDoAnnotation) { if (ssCapDesc->bU1DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U1_DEVICE_EXIT_MAX_VALUE) { AppendTextBuffer(" -> less than %d micro-seconds\r\n", ssCapDesc->bU1DevExitLat); } else { AppendTextBuffer("\r\n*!*ERROR: Invalid value\r\n"); } } else { AppendTextBuffer("\r\n"); } AppendTextBuffer("wU2DevExitLat: 0x%04X", ssCapDesc->wU2DevExitLat); if(gDoAnnotation) { if (ssCapDesc->wU2DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U2_DEVICE_EXIT_MAX_VALUE) { AppendTextBuffer(" -> less than %d micro-seconds\r\n", ssCapDesc->wU2DevExitLat); } else { AppendTextBuffer("\r\n*!*ERROR: Invalid value\r\n"); } } else { AppendTextBuffer("\r\n"); } } VOID DisplaySuperSpeedPlusCapabilityDescriptor ( PUSB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR sspCapDesc ) { UCHAR i; AppendTextBuffer("\r\n ===>SuperSpeed USB Device Capability Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", sspCapDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", sspCapDesc->bDescriptorType); AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", sspCapDesc->bDevCapabilityType); AppendTextBuffer("bReserved: 0x%02X\r\n", sspCapDesc->bReserved); if (sspCapDesc->bReserved != 0) { if(gDoAnnotation) { AppendTextBuffer("*!*ERROR: field is reserved\r\n"); } } AppendTextBuffer("bmAttributes: 0x%08X\r\n", sspCapDesc->bmAttributes.AsUlong); AppendTextBuffer(" SublinkSpeedAttrCount: 0x%02X\r\n", sspCapDesc->bmAttributes.SublinkSpeedAttrCount); AppendTextBuffer(" SublinkSpeedIDCount: 0x%02X\r\n", sspCapDesc->bmAttributes.SublinkSpeedIDCount); AppendTextBuffer("wFunctionalitySupport: 0x%04X\r\n", sspCapDesc->wFunctionalitySupport.AsUshort); AppendTextBuffer(" SublinkSpeedAttrID: 0x%02X\r\n", sspCapDesc->wFunctionalitySupport.SublinkSpeedAttrID); AppendTextBuffer(" Reserved: 0x%02X\r\n", sspCapDesc->wFunctionalitySupport.Reserved); if (sspCapDesc->wFunctionalitySupport.Reserved != 0) { if(gDoAnnotation) { AppendTextBuffer("*!*ERROR: field is reserved\r\n"); } } AppendTextBuffer(" MinRxLaneCount: 0x%02X\r\n", sspCapDesc->wFunctionalitySupport.MinRxLaneCount); AppendTextBuffer(" MinTxLaneCount: 0x%02X\r\n", sspCapDesc->wFunctionalitySupport.MinTxLaneCount); AppendTextBuffer("wReserved: 0x%04X\r\n", sspCapDesc->wReserved); if (sspCapDesc->wReserved != 0) { if(gDoAnnotation) { AppendTextBuffer("*!*ERROR: field is reserved\r\n"); } } // The array size = SublinkSpeedAttrCount + 1 for (i = 0; i <= sspCapDesc->bmAttributes.SublinkSpeedAttrCount; i++) { PUSB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED speed = &sspCapDesc->bmSublinkSpeedAttr[i]; AppendTextBuffer("bmSublinkSpeedAttr #: 0x%02X\r\n", i); AppendTextBuffer(" SublinkSpeedAttrID: 0x%02X\r\n", speed->SublinkSpeedAttrID); AppendTextBuffer(" LaneSpeedExponent: 0x%02X", speed->LaneSpeedExponent); if(gDoAnnotation) { switch (speed->LaneSpeedExponent) { case 0: AppendTextBuffer(" -> Bits per second\r\n"); break; case 1: AppendTextBuffer(" -> Kb/s\r\n"); break; case 2: AppendTextBuffer(" -> Mb/s\r\n"); break; case 3: AppendTextBuffer(" -> Gb/s\r\n"); break; } } else { AppendTextBuffer("\r\n"); } AppendTextBuffer(" SublinkTypeMode: 0x%02X", speed->SublinkTypeMode); if(gDoAnnotation) { switch (speed->SublinkTypeMode) { case 0: AppendTextBuffer(" -> Symmetric\r\n"); break; case 1: AppendTextBuffer(" -> Asymmetric\r\n"); break; } } else { AppendTextBuffer("\r\n"); } AppendTextBuffer(" SublinkTypeDir: 0x%02X", speed->SublinkTypeDir); if(gDoAnnotation) { switch (speed->SublinkTypeDir) { case 0: AppendTextBuffer(" -> Receive mode\r\n"); break; case 1: AppendTextBuffer(" -> Transmit mode\r\n"); break; } } else { AppendTextBuffer("\r\n"); } AppendTextBuffer(" Reserved: 0x%02X\r\n", speed->Reserved); AppendTextBuffer(" LinkProtocol: 0x%02X", speed->LinkProtocol); if(gDoAnnotation) { switch (speed->LinkProtocol) { case 0: AppendTextBuffer(" -> SuperSpeed\r\n"); break; case 1: AppendTextBuffer(" -> SuperSpeedPlus\r\n"); break; default: AppendTextBuffer(" -> Reserved\r\n"); break; } } else { AppendTextBuffer("\r\n"); } AppendTextBuffer(" LaneSpeedMantissa: 0x%04X\r\n", speed->LaneSpeedMantissa); } } VOID DisplayPlatformCapabilityDescriptor ( PUSB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR platformCapDesc ) { LPGUID pGuid; AppendTextBuffer("\r\n ===>Platform Capability Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", platformCapDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", platformCapDesc->bDescriptorType); AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", platformCapDesc->bDevCapabilityType); AppendTextBuffer("bReserved: 0x%02X\r\n", platformCapDesc->bReserved); if (platformCapDesc->bReserved != 0) { if(gDoAnnotation) { AppendTextBuffer("*!*ERROR: field is reserved\r\n"); } } pGuid = (LPGUID)&platformCapDesc->PlatformCapabilityUuid; AppendTextBuffer("Platform Capability UUID: "); AppendTextBuffer("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\r\n", pGuid->Data1, pGuid->Data2, pGuid->Data3, pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]); DisplayRemainingUnknownDescriptor((PUCHAR)platformCapDesc, (ULONG)offsetof(USB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR, CapabililityData), platformCapDesc->bLength); } VOID DisplayContainerIdCapabilityDescriptor ( PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR containerIdCapDesc ) { LPGUID pGuid; AppendTextBuffer("\r\n ===>Container ID Capability Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", containerIdCapDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", containerIdCapDesc->bDescriptorType); AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", containerIdCapDesc->bDevCapabilityType); AppendTextBuffer("bReserved: 0x%02X\r\n", containerIdCapDesc->bReserved); if (containerIdCapDesc->bReserved != 0) { if(gDoAnnotation) { AppendTextBuffer("*!*ERROR: field is reserved\r\n"); } } pGuid = (LPGUID)containerIdCapDesc->ContainerID; AppendTextBuffer("Container ID: "); AppendTextBuffer("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\r\n", pGuid->Data1, pGuid->Data2, pGuid->Data3, pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]); } VOID DisplayBillboardCapabilityDescriptor ( PUSBDEVICEINFO info, PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR billboardCapDesc, PSTRING_DESCRIPTOR_NODE StringDescs ) { UCHAR i = 0; UCHAR bNumAlternateModes = 0; UCHAR alternateModeConfiguration = 0; UCHAR adjustedBLength = 0; AppendTextBuffer("\r\n ===>Billboard Capability Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X", billboardCapDesc->bLength); adjustedBLength = sizeof(USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) + sizeof(billboardCapDesc->AlternateMode[0]) * (billboardCapDesc->bNumberOfAlternateModes - 1); AppendTextBuffer(" -> Actual Length: 0x%02X\r\n", adjustedBLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", billboardCapDesc->bDescriptorType); AppendTextBuffer("bDevCapabilityType: 0x%02X -> Billboard capability\r\n", billboardCapDesc->bDevCapabilityType); AppendTextBuffer("iAdditionalInfoURL: 0x%02X ->", billboardCapDesc->iAddtionalInfoURL); if (billboardCapDesc->iAddtionalInfoURL && gDoAnnotation) { DisplayStringDescriptor(billboardCapDesc->iAddtionalInfoURL, StringDescs, info->DeviceInfoNode != NULL ? info->DeviceInfoNode->LatestDevicePowerState : PowerDeviceUnspecified); } AppendTextBuffer("bNumberOfAlternateModes: 0x%02X\r\n", billboardCapDesc->bNumberOfAlternateModes); if (billboardCapDesc->bNumberOfAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE) { AppendTextBuffer("*!*ERROR: Invalid bNumberofAlternateModes\r\n"); } AppendTextBuffer("bPreferredAlternateMode: 0x%02X\r\n", billboardCapDesc->bPreferredAlternateMode); AppendTextBuffer("VCONN Power: 0x%04X", billboardCapDesc->VconnPower); if (billboardCapDesc->VconnPower.NoVconnPowerRequired) { AppendTextBuffer(" -> The adapter does not require Vconn Power. Bits 2..0 ignored\r\n"); } else { switch (billboardCapDesc->VconnPower.VConnPowerNeededForFullFunctionality) { case 0: AppendTextBuffer(" -> 1W needed by adapter for full functionality\r\n"); break; case 1: AppendTextBuffer(" -> 1.5W needed by adapter for full functionality\r\n"); break; case 7: AppendTextBuffer(" -> *!*ERROR: VConnPowerNeededForFullFunctionality - Reserved value being used\r\n"); break; default: AppendTextBuffer(" -> %2XW needed by adapter for full functionality\r\n", billboardCapDesc->VconnPower.VConnPowerNeededForFullFunctionality); } } if (billboardCapDesc->VconnPower.Reserved) { AppendTextBuffer("*!*ERROR: Reserved bits in VCONN Power being used\r\n"); } if (billboardCapDesc->bReserved) { AppendTextBuffer("*!*ERROR: bReserved being used\r\n"); } bNumAlternateModes = billboardCapDesc->bNumberOfAlternateModes; if (bNumAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE) { bNumAlternateModes = BILLBOARD_MAX_NUM_ALT_MODE; } if (bNumAlternateModes > 0) { AppendTextBuffer("\r\nAlternate Modes Identified:\r\n"); } for (i = 0; i < bNumAlternateModes; i++) { alternateModeConfiguration = ((billboardCapDesc->bmConfigured[i / 4]) >> ((i % 4) * 2)) & 0x3; AppendTextBuffer("wSVID - 0x%04X bAlternateMode - 0x%02X ->", billboardCapDesc->AlternateMode[i].wSVID, billboardCapDesc->AlternateMode[i].bAlternateMode, billboardCapDesc->AlternateMode[i].iAlternateModeSetting); switch (alternateModeConfiguration) { case 0: AppendTextBuffer("Unspecified Error\r\n"); break; case 1: AppendTextBuffer("Alternate Mode configuration not attempted\r\n"); break; case 2: AppendTextBuffer("Alternate Mode configuration attempted but unsuccessful\r\n"); break; case 3: AppendTextBuffer("Alternate Mode configuration successful\r\n"); break; } AppendTextBuffer("iAlternateModeString - 0x%02X ", billboardCapDesc->AlternateMode[i].iAlternateModeSetting); if (billboardCapDesc->AlternateMode[i].iAlternateModeSetting && gDoAnnotation) { DisplayStringDescriptor(billboardCapDesc->AlternateMode[i].iAlternateModeSetting, StringDescs, info->DeviceInfoNode != NULL ? info->DeviceInfoNode->LatestDevicePowerState : PowerDeviceUnspecified); } else { AppendTextBuffer("\r\n"); } AppendTextBuffer("\r\n"); } } #ifdef USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY VOID DisplayConfigurationSummaryCapabilityDescriptor ( PUSB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR configSummaryCapDesc ) { UCHAR i; AppendTextBuffer("\r\n ===>Configuration Summary Capability Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", configSummaryCapDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", configSummaryCapDesc->bDescriptorType); AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", configSummaryCapDesc->bDevCapabilityType); AppendTextBuffer("bcdVersion: 0x%04X\r\n", configSummaryCapDesc->bcdVersion); AppendTextBuffer("bConfigurationValue: 0x%02X\r\n", configSummaryCapDesc->bConfigurationValue); AppendTextBuffer("bMaxPower: 0x%02X\r\n", configSummaryCapDesc->bMaxPower); AppendTextBuffer("bNumFunctions: 0x%02X\r\n", configSummaryCapDesc->bNumFunctions); for (i = 0; i < configSummaryCapDesc->bNumFunctions; i++) { AppendTextBuffer("Function #: 0x%02X\r\n", i); AppendTextBuffer(" bClass: 0x%02X\r\n", configSummaryCapDesc->Function[i].bClass); AppendTextBuffer(" bSubClass: 0x%02X\r\n", configSummaryCapDesc->Function[i].bSubClass); AppendTextBuffer(" bProtocol: 0x%02X\r\n", configSummaryCapDesc->Function[i].bProtocol); } } #endif /***************************************************************************** DisplayBosDescriptor() BosDesc - The Binary Object Store (BOS) Descriptor, and associated Descriptors *****************************************************************************/ VOID DisplayBosDescriptor ( PUSBDEVICEINFO info, PUSB_BOS_DESCRIPTOR BosDesc, PSTRING_DESCRIPTOR_NODE StringDescs ) { PUSB_COMMON_DESCRIPTOR commonDesc = NULL; PUSB_DEVICE_CAPABILITY_DESCRIPTOR capDesc = NULL; AppendTextBuffer("\r\n ===>BOS Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", BosDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", BosDesc->bDescriptorType); AppendTextBuffer("wTotalLength: 0x%04X\r\n", BosDesc->wTotalLength); AppendTextBuffer("bNumDeviceCaps: 0x%02X\r\n", BosDesc->bNumDeviceCaps); commonDesc = (PUSB_COMMON_DESCRIPTOR)BosDesc; while ((commonDesc = GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)BosDesc, BosDesc->wTotalLength, commonDesc, -1)) != NULL) { switch (commonDesc->bDescriptorType) { case USB_DEVICE_CAPABILITY_DESCRIPTOR_TYPE: capDesc = (PUSB_DEVICE_CAPABILITY_DESCRIPTOR)commonDesc; switch (capDesc->bDevCapabilityType) { case USB_DEVICE_CAPABILITY_USB20_EXTENSION: DisplayUsb20ExtensionCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR)capDesc); break; case USB_DEVICE_CAPABILITY_SUPERSPEED_USB: DisplaySuperSpeedCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR)capDesc); break; case USB_DEVICE_CAPABILITY_CONTAINER_ID: DisplayContainerIdCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR)capDesc); break; case USB_DEVICE_CAPABILITY_PLATFORM: DisplayPlatformCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR)capDesc); break; case USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB: DisplaySuperSpeedPlusCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR)capDesc); break; case USB_DEVICE_CAPABILITY_BILLBOARD: DisplayBillboardCapabilityDescriptor((PUSBDEVICEINFO) info, (PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) capDesc, StringDescs); break; #ifdef USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY case USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY: DisplayConfigurationSummaryCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR)capDesc); break; #endif default: AppendTextBuffer("\r\n ===>Unknown Capability Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", capDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", capDesc->bDescriptorType); AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", capDesc->bDevCapabilityType); DisplayRemainingUnknownDescriptor((PUCHAR)commonDesc, (ULONG)sizeof(USB_DEVICE_CAPABILITY_DESCRIPTOR), commonDesc->bLength); break; } break; default: DisplayUnknownDescriptor(commonDesc); break; } } } /***************************************************************************** DisplayConfigurationDescriptor() *****************************************************************************/ VOID DisplayConfigurationDescriptor ( PUSBDEVICEINFO info, PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, PSTRING_DESCRIPTOR_NODE StringDescs ) { UINT uCount = 0; BOOL isSS; isSS = info->ConnectionInfoV2 && (info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher || info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher) ? TRUE : FALSE; AppendTextBuffer("\r\n ===>Configuration Descriptor<===\r\n"); //@@DisplayConfigurationDescriptor - Configuration Descriptor //length checked in DisplayConfigDesc() AppendTextBuffer("bLength: 0x%02X\r\n", ConfigDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", ConfigDesc->bDescriptorType); //@@TestCase A4.1 //@@Priority 1 //@@Descriptor Field - wTotalLength //@@Verify Configuration length is valid AppendTextBuffer("wTotalLength: 0x%04X", ConfigDesc->wTotalLength); uCount = GetConfigurationSize(info); if (uCount != ConfigDesc->wTotalLength) { AppendTextBuffer("\r\n*!*ERROR: Invalid total configuration size 0x%02X, should be 0x%02X\r\n", ConfigDesc->wTotalLength, uCount); } else { AppendTextBuffer(" -> Validated\r\n"); } //@@TestCase A4.2 //@@Priority 1 //@@Descriptor Field - bNumInterfaces //@@Verify the number of interfaces is valid AppendTextBuffer("bNumInterfaces: 0x%02X\r\n", ConfigDesc->bNumInterfaces); /* Need to check spec vs composite devices uCount = GetInterfaceCount(info); if (uCount != ConfigDesc->bNumInterfaces) { AppendTextBuffer("\r\n*!*ERROR: Invalid total Interfaces %d, should be %d\r\n", ConfigDesc->bNumInterfaces, uCount); } else { AppendTextBuffer(" -> Validated\r\n"); } */ AppendTextBuffer("bConfigurationValue: 0x%02X\r\n", ConfigDesc->bConfigurationValue); if(ConfigDesc->bConfigurationValue != 1) { //@@TestCase A4.3 //@@CAUTION //@@Descriptor Field - bConfigurationValue //@@Most host controllers do not handle more than one configuration AppendTextBuffer("*!*CAUTION: Most host controllers will only work with one configuration per speed\r\n"); OOPS(); } AppendTextBuffer("iConfiguration: 0x%02X\r\n", ConfigDesc->iConfiguration); if (ConfigDesc->iConfiguration && gDoAnnotation) { DisplayStringDescriptor(ConfigDesc->iConfiguration, StringDescs, info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); } AppendTextBuffer("bmAttributes: 0x%02X", ConfigDesc->bmAttributes); if (info->ConnectionInfo->DeviceDescriptor.bcdUSB == 0x0100) { if (ConfigDesc->bmAttributes & USB_CONFIG_SELF_POWERED) { if(gDoAnnotation) { AppendTextBuffer(" -> Self Powered\r\n"); } } if (ConfigDesc->bmAttributes & USB_CONFIG_BUS_POWERED) { if(gDoAnnotation) { AppendTextBuffer(" -> Bus Powered\r\n"); } } } else { if (ConfigDesc->bmAttributes & USB_CONFIG_SELF_POWERED) { if(gDoAnnotation) { AppendTextBuffer(" -> Self Powered\r\n"); } } else { if(gDoAnnotation) { AppendTextBuffer(" -> Bus Powered\r\n"); } } if ((ConfigDesc->bmAttributes & USB_CONFIG_BUS_POWERED) == 0) { AppendTextBuffer("\r\n*!*ERROR: Bit 7 is reserved and must be set\r\n"); OOPS(); } } if (ConfigDesc->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) { if(gDoAnnotation) { AppendTextBuffer(" -> Remote Wakeup\r\n"); } } if (ConfigDesc->bmAttributes & USB_CONFIG_RESERVED) { //@@TestCase A4.4 //@@WARNING //@@Descriptor Field - bmAttributes //@@A bit has been set in reserved space AppendTextBuffer("\r\n*!*ERROR: Bits 4...0 are reserved\r\n"); OOPS(); } AppendTextBuffer("MaxPower: 0x%02X", ConfigDesc->MaxPower); if(gDoAnnotation) { AppendTextBuffer(" = %3d mA\r\n", isSS ? ConfigDesc->MaxPower * 8 : ConfigDesc->MaxPower * 2); } else {AppendTextBuffer("\r\n");} } /***************************************************************************** DisplayInterfaceDescriptor() *****************************************************************************/ VOID DisplayInterfaceDescriptor ( PUSB_INTERFACE_DESCRIPTOR InterfaceDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { //@@DisplayInterfaceDescriptor - Interface Descriptor AppendTextBuffer("\r\n ===>Interface Descriptor<===\r\n"); //length checked in DisplayConfigDesc() AppendTextBuffer("bLength: 0x%02X\r\n", InterfaceDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", InterfaceDesc->bDescriptorType); //@@TestCase A5.1 //@@Priority 1 //@@Descriptor Field - bInterfaceNumber //@@Question - Should we test to verify bInterfaceNumber is valid? AppendTextBuffer("bInterfaceNumber: 0x%02X\r\n", InterfaceDesc->bInterfaceNumber); //@@TestCase A5.2 //@@Priority 1 //@@Descriptor Field - bAlternateSetting //@@Question - Should we test to verify bAlternateSetting is valid? AppendTextBuffer("bAlternateSetting: 0x%02X\r\n", InterfaceDesc->bAlternateSetting); //@@TestCase A5.3 //@@Priority 1 //@@Descriptor Field - bNumEndpoints //@@Question - Should we test to verify bNumEndpoints is valid? AppendTextBuffer("bNumEndpoints: 0x%02X\r\n", InterfaceDesc->bNumEndpoints); AppendTextBuffer("bInterfaceClass: 0x%02X", InterfaceDesc->bInterfaceClass); switch (InterfaceDesc->bInterfaceClass) { case USB_DEVICE_CLASS_AUDIO: if(gDoAnnotation) { AppendTextBuffer(" -> Audio Interface Class\r\n"); } AppendTextBuffer("bInterfaceSubClass: 0x%02X", InterfaceDesc->bInterfaceSubClass); if(gDoAnnotation) { switch (InterfaceDesc->bInterfaceSubClass) { case USB_AUDIO_SUBCLASS_AUDIOCONTROL: AppendTextBuffer(" -> Audio Control Interface SubClass\r\n"); break; case USB_AUDIO_SUBCLASS_AUDIOSTREAMING: AppendTextBuffer(" -> Audio Streaming Interface SubClass\r\n"); break; case USB_AUDIO_SUBCLASS_MIDISTREAMING: AppendTextBuffer(" -> MIDI Streaming Interface SubClass\r\n"); break; default: //@@TestCase A5.4 //@@CAUTION //@@Descriptor Field - bInterfaceSubClass //@@Invalid bInterfaceSubClass AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid bInterfaceSubClass\r\n"); OOPS(); break; } } break; case USB_DEVICE_CLASS_VIDEO: if(gDoAnnotation) AppendTextBuffer(" -> Video Interface Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X", InterfaceDesc->bInterfaceSubClass); switch(InterfaceDesc->bInterfaceSubClass) { case VIDEO_SUBCLASS_CONTROL: if(gDoAnnotation) { AppendTextBuffer(" -> Video Control Interface SubClass\r\n"); } break; case VIDEO_SUBCLASS_STREAMING: if(gDoAnnotation) { AppendTextBuffer(" -> Video Streaming Interface SubClass\r\n"); } break; default: //@@TestCase A5.5 //@@CAUTION //@@Descriptor Field - bInterfaceSubClass //@@Invalid bInterfaceSubClass AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid bInterfaceSubClass\r\n"); OOPS(); break; } break; case USB_DEVICE_CLASS_HUMAN_INTERFACE: if(gDoAnnotation) { AppendTextBuffer(" -> HID Interface Class\r\n"); } AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_HUB: if(gDoAnnotation) { AppendTextBuffer(" -> HUB Interface Class\r\n"); } AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_RESERVED: //@@TestCase A5.6 //@@CAUTION //@@Descriptor Field - bInterfaceClass //@@A reserved USB Device Interface Class has been defined AppendTextBuffer("\r\n*!*CAUTION: %d is a Reserved USB Device Interface Class\r\n", USB_DEVICE_CLASS_RESERVED); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_COMMUNICATIONS: AppendTextBuffer(" -> This is Communications (CDC Control) USB Device Interface Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_MONITOR: AppendTextBuffer(" -> This is a Monitor USB Device Interface Class*** (This may be obsolete)\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_PHYSICAL_INTERFACE: AppendTextBuffer(" -> This is a Physical Interface USB Device Interface Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_POWER: if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1) { AppendTextBuffer(" -> This is an Image USB Device Interface Class\r\n"); } else { AppendTextBuffer(" -> This is a Power USB Device Interface Class (This may be obsolete)\r\n"); } AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_PRINTER: AppendTextBuffer(" -> This is a Printer USB Device Interface Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_STORAGE: AppendTextBuffer(" -> This is a Mass Storage USB Device Interface Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_CDC_DATA_INTERFACE: AppendTextBuffer(" -> This is a CDC Data USB Device Interface Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_CHIP_SMART_CARD_INTERFACE: AppendTextBuffer(" -> This is a Chip/Smart Card USB Device Interface Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_CONTENT_SECURITY_INTERFACE: AppendTextBuffer(" -> This is a Content Security USB Device Interface Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DIAGNOSTIC_DEVICE_INTERFACE: if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1) { AppendTextBuffer(" -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\r\n"); } else { //@@TestCase A5.7 //@@CAUTION //@@Descriptor Field - bInterfaceClass //@@Invalid Interface Class AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_WIRELESS_CONTROLLER_INTERFACE: if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1) { AppendTextBuffer(" -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\r\n"); } else { //@@TestCase A5.8 //@@CAUTION //@@Descriptor Field - bInterfaceClass //@@Invalid Interface Class AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_APPLICATION_SPECIFIC_INTERFACE: AppendTextBuffer(" -> This is an Application Specific USB Device Interface Class\r\n"); switch(InterfaceDesc->bInterfaceSubClass) { case 1: AppendTextBuffer(" -> This is a Device Firmware Application Specific USB Device Interface Class\r\n"); break; case 2: AppendTextBuffer(" -> This is an IrDA Bridge Application Specific USB Device Interface Class\r\n"); break; case 3: AppendTextBuffer(" -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\r\n"); break; default: //@@TestCase A5.9 //@@CAUTION //@@Descriptor Field - bInterfaceClass //@@Invalid Interface Class AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; case USB_DEVICE_CLASS_BILLBOARD: AppendTextBuffer(" -> Billboard Class\r\n"); AppendTextBuffer("bInterfaceSubClass: 0x%02X", InterfaceDesc->bInterfaceSubClass); switch (InterfaceDesc->bInterfaceSubClass) { case 0: AppendTextBuffer(" -> Billboard Subclass\r\n"); break; default: AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid bInterfaceSubClass\r\n"); break; } break; default: if(gDoAnnotation) { AppendTextBuffer(" -> Interface Class Unknown to USBView\r\n"); } AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; } AppendTextBuffer("bInterfaceProtocol: 0x%02X\r\n", InterfaceDesc->bInterfaceProtocol); //This is basically the check for PC_PROTOCOL_UNDEFINED if ((InterfaceDesc->bInterfaceClass == USB_DEVICE_CLASS_VIDEO) || (InterfaceDesc->bInterfaceClass == USB_DEVICE_CLASS_AUDIO)) { if(InterfaceDesc->bInterfaceProtocol != PC_PROTOCOL_UNDEFINED) { //@@TestCase A5.10 //@@WARNING //@@Descriptor Field - iInterface //@@bInterfaceProtocol must be set to PC_PROTOCOL_UNDEFINED AppendTextBuffer("*!*WARNING: must be set to PC_PROTOCOL_UNDEFINED %d for this class\r\n", PC_PROTOCOL_UNDEFINED); OOPS(); } } AppendTextBuffer("iInterface: 0x%02X\r\n", InterfaceDesc->iInterface); if(gDoAnnotation) { if (InterfaceDesc->iInterface) { DisplayStringDescriptor(InterfaceDesc->iInterface, StringDescs, LatestDevicePowerState); } } if (InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR2)) { PUSB_INTERFACE_DESCRIPTOR2 interfaceDesc2; interfaceDesc2 = (PUSB_INTERFACE_DESCRIPTOR2)InterfaceDesc; AppendTextBuffer("wNumClasses: 0x%04X\r\n", interfaceDesc2->wNumClasses); } } /***************************************************************************** DisplayEndpointDescriptor() *****************************************************************************/ VOID DisplayEndpointDescriptor ( _In_ PUSB_ENDPOINT_DESCRIPTOR EndpointDesc, _In_opt_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc, _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc, _In_ UCHAR InterfaceClass, _In_ BOOLEAN EpCompDescAvail ) { UCHAR epType = EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK; PUSB_HIGH_SPEED_MAXPACKET hsMaxPacket; AppendTextBuffer("\r\n ===>Endpoint Descriptor<===\r\n"); //@@DisplayEndpointDescriptor - Endpoint Descriptor //length checked in DisplayConfigDesc() AppendTextBuffer("bLength: 0x%02X\r\n", EndpointDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", EndpointDesc->bDescriptorType); AppendTextBuffer("bEndpointAddress: 0x%02X", EndpointDesc->bEndpointAddress); if(gDoAnnotation) { if(USB_ENDPOINT_DIRECTION_OUT(EndpointDesc->bEndpointAddress)) { AppendTextBuffer(" -> Direction: OUT - EndpointID: %d\r\n", (EndpointDesc->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK)); } else if(USB_ENDPOINT_DIRECTION_IN(EndpointDesc->bEndpointAddress)) { AppendTextBuffer(" -> Direction: IN - EndpointID: %d\r\n", (EndpointDesc->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK)); } else { //@@TestCase A6.1 //@@ERROR //@@Descriptor Field - bEndpointAddress //@@An invalid endpoint addressl has been defined AppendTextBuffer("\r\n*!*ERROR: This appears to be an invalid bEndpointAddress\r\n"); OOPS(); } } else {AppendTextBuffer("\r\n");} AppendTextBuffer("bmAttributes: 0x%02X", EndpointDesc->bmAttributes); if(gDoAnnotation) { AppendTextBuffer(" -> "); switch (epType) { case USB_ENDPOINT_TYPE_CONTROL: AppendTextBuffer("Control Transfer Type\r\n"); if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_CONTROL_RESERVED_MASK) { AppendTextBuffer("\r\n*!*ERROR: Bits 7..2 are reserved and must be set to 0\r\n"); OOPS(); } break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: AppendTextBuffer("Isochronous Transfer Type, Synchronization Type = "); switch (USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION(EndpointDesc->bmAttributes)) { case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_NO_SYNCHRONIZATION: AppendTextBuffer("No Synchronization"); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_ASYNCHRONOUS: AppendTextBuffer("Asynchronous"); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_ADAPTIVE: AppendTextBuffer("Adaptive"); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_SYNCHRONOUS: AppendTextBuffer("Synchronous"); break; } AppendTextBuffer(", Usage Type = "); switch (USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE(EndpointDesc->bmAttributes)) { case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_DATA_ENDOINT: AppendTextBuffer("Data Endpoint\r\n"); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_FEEDBACK_ENDPOINT: AppendTextBuffer("Feedback Endpoint\r\n"); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_IMPLICIT_FEEDBACK_DATA_ENDPOINT: AppendTextBuffer("Implicit Feedback Data Endpoint\r\n"); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_RESERVED: //@@TestCase A6.2 //@@ERROR //@@Descriptor Field - bmAttributes //@@A reserved bit has a value AppendTextBuffer("\r\n*!*ERROR: This value is Reserved\r\n"); OOPS(); break; } if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_ISOCHRONOUS_RESERVED_MASK) { AppendTextBuffer("\r\n*!*ERROR: Bits 7..6 are reserved and must be set to 0\r\n"); OOPS(); } break; case USB_ENDPOINT_TYPE_BULK: AppendTextBuffer("Bulk Transfer Type\r\n"); if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_BULK_RESERVED_MASK) { AppendTextBuffer("\r\n*!*ERROR: Bits 7..2 are reserved and must be set to 0\r\n"); OOPS(); } break; case USB_ENDPOINT_TYPE_INTERRUPT: if (gDeviceSpeed != UsbSuperSpeed) { AppendTextBuffer("Interrupt Transfer Type\r\n"); if (EndpointDesc->bmAttributes & USB_20_ENDPOINT_TYPE_INTERRUPT_RESERVED_MASK) { AppendTextBuffer("\r\n*!*ERROR: Bits 7..2 are reserved and must be set to 0\r\n"); OOPS(); } } else { AppendTextBuffer("Interrupt Transfer Type, Usage Type = "); switch (USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE(EndpointDesc->bmAttributes)) { case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_PERIODIC: AppendTextBuffer("Periodic\r\n"); break; case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_NOTIFICATION: AppendTextBuffer("Notification\r\n"); break; case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_RESERVED10: case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_RESERVED11: AppendTextBuffer("\r\n*!*ERROR: This value is Reserved\r\n"); OOPS(); break; } if (EndpointDesc->bmAttributes & USB_30_ENDPOINT_TYPE_INTERRUPT_RESERVED_MASK) { AppendTextBuffer("\r\n*!*ERROR: Bits 7..6 and 3..2 are reserved and must be set to 0\r\n"); OOPS(); } if (EpCompDescAvail) { if (EpCompDesc == NULL) { AppendTextBuffer("\r\n*!*ERROR: Endpoint Companion Descriptor missing\r\n"); OOPS(); } else if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 1 && SspIsochEpCompDesc == NULL) { AppendTextBuffer("\r\n*!*ERROR: SuperSpeedPlus Isoch Endpoint Companion Descriptor missing\r\n"); OOPS(); } } } break; } } else { AppendTextBuffer("\r\n"); } //@@TestCase A6.3 //@@Priority 1 //@@Descriptor Field - bInterfaceNumber //@@Question - Should we test to verify bInterfaceNumber is valid? AppendTextBuffer("wMaxPacketSize: 0x%04X", EndpointDesc->wMaxPacketSize); if(gDoAnnotation) { switch (gDeviceSpeed) { case UsbSuperSpeed: switch (epType) { case USB_ENDPOINT_TYPE_BULK: if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_BULK_MAX_PACKET_SIZE) { AppendTextBuffer("\r\n*!*ERROR: SuperSpeed Bulk endpoints must be %d bytes\r\n", USB_ENDPOINT_SUPERSPEED_BULK_MAX_PACKET_SIZE); } else { AppendTextBuffer("\r\n"); } break; case USB_ENDPOINT_TYPE_CONTROL: if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_CONTROL_MAX_PACKET_SIZE) { AppendTextBuffer("\r\n*!*ERROR: SuperSpeed Control endpoints must be %d bytes\r\n", USB_ENDPOINT_SUPERSPEED_CONTROL_MAX_PACKET_SIZE); } else { AppendTextBuffer("\r\n"); } break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: if (EpCompDesc != NULL) { if (EpCompDesc->bMaxBurst > 0) { if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE) { AppendTextBuffer("\r\n*!*ERROR: SuperSpeed isochronous endpoints must have wMaxPacketSize value of %d bytes\r\n", USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE); AppendTextBuffer(" when the SuperSpeed endpoint companion descriptor bMaxBurst value is greater than 0\r\n"); } else { AppendTextBuffer("\r\n"); } } else if (EndpointDesc->wMaxPacketSize > USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE) { AppendTextBuffer("\r\n*!*ERROR: Invalid SuperSpeed isochronous maximum packet size\r\n"); } else { AppendTextBuffer("\r\n"); } } else { AppendTextBuffer("\r\n"); } break; case USB_ENDPOINT_TYPE_INTERRUPT: if (EpCompDesc != NULL) { if (EpCompDesc->bMaxBurst > 0) { if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE) { AppendTextBuffer("\r\n*!*ERROR: SuperSpeed interrupt endpoints must have wMaxPacketSize value of %d bytes\r\n", USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE); AppendTextBuffer(" when the SuperSpeed endpoint companion descriptor bMaxBurst value is greater than 0\r\n"); } else { AppendTextBuffer("\r\n"); } } else if (EndpointDesc->wMaxPacketSize > USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE) { AppendTextBuffer("\r\n*!*ERROR: Invalid SuperSpeed interrupt maximum packet size\r\n"); } else { AppendTextBuffer("\r\n"); } } else { AppendTextBuffer("\r\n"); } break; } break; case UsbHighSpeed: hsMaxPacket = (PUSB_HIGH_SPEED_MAXPACKET)&EndpointDesc->wMaxPacketSize; switch (epType) { case USB_ENDPOINT_TYPE_ISOCHRONOUS: case USB_ENDPOINT_TYPE_INTERRUPT: switch (hsMaxPacket->HSmux) { case 0: if ((hsMaxPacket->MaxPacket < 1) || (hsMaxPacket->MaxPacket >1024)) { AppendTextBuffer("*!*ERROR: Invalid maximum packet size, should be between 1 and 1024\r\n"); } break; case 1: if ((hsMaxPacket->MaxPacket < 513) || (hsMaxPacket->MaxPacket >1024)) { AppendTextBuffer("*!*ERROR: Invalid maximum packet size, should be between 513 and 1024\r\n"); } break; case 2: if ((hsMaxPacket->MaxPacket < 683) || (hsMaxPacket->MaxPacket >1024)) { AppendTextBuffer("*!*ERROR: Invalid maximum packet size, should be between 683 and 1024\r\n"); } break; case 3: AppendTextBuffer("*!*ERROR: Bits 12-11 set to Reserved value in wMaxPacketSize\r\n"); break; } AppendTextBuffer(" = %d transactions per microframe, 0x%02X max bytes\r\n", hsMaxPacket->HSmux + 1, hsMaxPacket->MaxPacket); break; case USB_ENDPOINT_TYPE_BULK: case USB_ENDPOINT_TYPE_CONTROL: AppendTextBuffer(" = 0x%02X max bytes\r\n", hsMaxPacket->MaxPacket); break; } break; case UsbFullSpeed: // full speed AppendTextBuffer(" = 0x%02X bytes\r\n", EndpointDesc->wMaxPacketSize & 0x7FF); break; default: // low or invalid speed if (InterfaceClass == USB_DEVICE_CLASS_VIDEO) { AppendTextBuffer(" = Invalid bus speed for USB Video Class\r\n"); } else { AppendTextBuffer("\r\n"); } break; } } else { AppendTextBuffer("\r\n"); } if (EndpointDesc->wMaxPacketSize & 0xE000) { //@@TestCase A6.4 //@@Priority 1 //@@OTG Descriptor Field - wMaxPacketSize //@@Attribute bits D7-2 reserved (reset to 0) AppendTextBuffer("*!*ERROR: wMaxPacketSize bits 15-13 should be 0\r\n"); } if (EndpointDesc->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR)) { //@@TestCase A6.5 //@@Priority 1 //@@Descriptor Field - bInterfaceNumber //@@Question - Should we test to verify bInterfaceNumber is valid? AppendTextBuffer("bInterval: 0x%02X\r\n", EndpointDesc->bInterval); } else { PUSB_ENDPOINT_DESCRIPTOR2 endpointDesc2; endpointDesc2 = (PUSB_ENDPOINT_DESCRIPTOR2)EndpointDesc; AppendTextBuffer("wInterval: 0x%04X\r\n", endpointDesc2->wInterval); AppendTextBuffer("bSyncAddress: 0x%02X\r\n", endpointDesc2->bSyncAddress); } if (EpCompDesc != NULL) { DisplayEndointCompanionDescriptor(EpCompDesc, SspIsochEpCompDesc, epType); } if (SspIsochEpCompDesc != NULL) { DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor(SspIsochEpCompDesc); } } /***************************************************************************** DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor() *****************************************************************************/ VOID DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor( _In_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc ) { AppendTextBuffer("\r\n ===>SuperSpeedPlus Isochronous Endpoint Companion Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", SspIsochEpCompDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", SspIsochEpCompDesc->bDescriptorType); AppendTextBuffer("wReserved: 0x%02X\r\n", SspIsochEpCompDesc->wReserved); if (gDoAnnotation) { if (SspIsochEpCompDesc->wReserved != 0) { AppendTextBuffer("*!*ERROR: field is reserved\r\n"); } } AppendTextBuffer("dwBytesPerInterval: 0x%04X\r\n", SspIsochEpCompDesc->dwBytesPerInterval); } /***************************************************************************** DisplayEndointCompanionDescriptor() *****************************************************************************/ VOID DisplayEndointCompanionDescriptor ( _In_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc, _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc, _In_ UCHAR DescType ) { AppendTextBuffer("\r\n ===>SuperSpeed Endpoint Companion Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", EpCompDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", EpCompDesc->bDescriptorType); AppendTextBuffer("bMaxBurst: 0x%02X\r\n", EpCompDesc->bMaxBurst); AppendTextBuffer("bmAttributes: 0x%02X", EpCompDesc->bmAttributes.AsUchar); if(gDoAnnotation) { switch (DescType) { case USB_ENDPOINT_TYPE_CONTROL: case USB_ENDPOINT_TYPE_INTERRUPT: if (EpCompDesc->bmAttributes.AsUchar != 0) { AppendTextBuffer("*!*ERROR: Control/Interrupt SuperSpeed endpoints do not support streams\r\n"); } else { AppendTextBuffer("\r\n"); } break; case USB_ENDPOINT_TYPE_BULK: if(EpCompDesc->bmAttributes.Bulk.MaxStreams == 0) { AppendTextBuffer("The bulk endpoint does not define streams (MaxStreams == 0)\r\n"); } else { AppendTextBuffer(" = %d streams supported\r\n", 1 << EpCompDesc->bmAttributes.Bulk.MaxStreams); } if (EpCompDesc->bmAttributes.Bulk.Reserved1 != 0) { AppendTextBuffer("*!*ERROR: bmAttributes bits 7-5 should be 0\r\n"); } break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 0) { if (EpCompDesc->bMaxBurst == 0 && EpCompDesc->bmAttributes.Isochronous.Mult != 0) { AppendTextBuffer("*!*ERROR: SuperSpeed isochronous endpoint multiplier value should be zero if bMaxBurst is zero\r\n"); } else { AppendTextBuffer(" = %d maximum number of packets within a service interval\r\n", (EpCompDesc->bmAttributes.Isochronous.Mult + 1)*(EpCompDesc->bMaxBurst + 1)); if (EpCompDesc->bmAttributes.Isochronous.Mult > USB_SUPERSPEED_ISOCHRONOUS_MAX_MULTIPLIER) { AppendTextBuffer("*!*ERROR: Maximum SuperSpeed isochronous endpoint multiplier value exceeded\r\n"); } } } else { if (EpCompDesc->bMaxBurst != 0 && SspIsochEpCompDesc != NULL) { AppendTextBuffer(" = %d maximum number of packets within a service interval\r\n", (SspIsochEpCompDesc->dwBytesPerInterval*USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE) / EpCompDesc->bMaxBurst); } } if (EpCompDesc->bmAttributes.Isochronous.Reserved2 != 0) { AppendTextBuffer("*!*ERROR: bmAttributes bits 7-2 should be 0\r\n"); } else { AppendTextBuffer("\r\n"); } break; } } AppendTextBuffer("wBytesPerInterval: 0x%04X\r\n", EpCompDesc->wBytesPerInterval); if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 1 && EpCompDesc->wBytesPerInterval != 0x1) { AppendTextBuffer("*!*ERROR: SuperSpeed endpoint wBytesPerInterval value should be 1 if \ SuperSpeedPlus Isoch companion descriptor is present\r\n"); } } /***************************************************************************** DisplayHidDescriptor() *****************************************************************************/ VOID DisplayHidDescriptor ( PUSB_HID_DESCRIPTOR HidDesc ) { UCHAR i = 0; AppendTextBuffer("\r\n ===>HID Descriptor<===\r\n"); //length checked in DisplayConfigDesc() AppendTextBuffer("bLength: 0x%02X\r\n", HidDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", HidDesc->bDescriptorType); AppendTextBuffer("bcdHID: 0x%04X\r\n", HidDesc->bcdHID); AppendTextBuffer("bCountryCode: 0x%02X\r\n", HidDesc->bCountryCode); AppendTextBuffer("bNumDescriptors: 0x%02X\r\n", HidDesc->bNumDescriptors); for (i=0; ibNumDescriptors; i++) { if (HidDesc->OptionalDescriptors[i].bDescriptorType == 0x22) { AppendTextBuffer("bDescriptorType: 0x%02X (Report Descriptor)\r\n", HidDesc->OptionalDescriptors[i].bDescriptorType); } else { AppendTextBuffer("bDescriptorType: 0x%02X\r\n", HidDesc->OptionalDescriptors[i].bDescriptorType); } AppendTextBuffer("wDescriptorLength: 0x%04X\r\n", HidDesc->OptionalDescriptors[i].wDescriptorLength); } } /***************************************************************************** DisplayOTGDescriptor() *****************************************************************************/ VOID DisplayOTGDescriptor ( PUSB_OTG_DESCRIPTOR OTGDesc ) { AppendTextBuffer("\r\n ===>OTG Descriptor<===\r\n"); //length checked in DisplayConfigDesc() AppendTextBuffer("bLength: 0x%02X\r\n", OTGDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", OTGDesc->bDescriptorType); AppendTextBuffer("bmAttributes: 0x%02X", OTGDesc->bmAttributes); switch (OTGDesc->bmAttributes) { case 0: break; case 1: if(gDoAnnotation) { AppendTextBuffer(" -> SRP support\r\n"); } break; case 2: if(gDoAnnotation) { AppendTextBuffer(" -> HNP support\r\n"); } break; case 3: if(gDoAnnotation) { AppendTextBuffer(" -> SRP and HNP support\r\n"); } break; default: //@@TestCase A6.5 //@@Priority 1 //@@OTG Descriptor Field - bmAttributes //@@Attribute bits D7-2 reserved (reset to 0) AppendTextBuffer("*!*ERROR: bmAttributes bits 2-7 are reserved "\ "(should be 0)\r\n"); OOPS(); break; } } /***************************************************************************** InitializeGlobalFlags () Initialize the global device flags in UVCView.h *****************************************************************************/ void InitializePerDeviceSettings ( PUSBDEVICEINFO info ) { // Save base address for this current device's info (including Configuration descriptor) CurrentUSBDeviceInfo = info; // Initialize Configuration descriptor length dwConfigLength = 0; // Save # of bytes from start of Configuration descriptor // (Update this in the descriptor parsing routines) dwConfigIndex = 0; // Flags used in dispvid.c to display default Frame descriptor for MJPEG, // Uncompressed, Vendor and FrameBased Formats g_chMJPEGFrameDefault = 0; g_chUNCFrameDefault = 0; g_chVendorFrameDefault = 0; g_chFrameBasedFrameDefault = 0; // Spec version of UVC device g_chUVCversion = 0; // Start and end address of the configuration descriptor and start of the string descriptors g_pConfigDesc = NULL; g_pStringDescs = NULL; g_descEnd = NULL; // // The GetConfigDescriptor() function in enum.c does not always work // If that fails, the Configuration descriptor will be NULL // and we can only display the device descriptor // CurrentConfigDesc = NULL; if (NULL != info) { if (NULL != info->ConfigDesc) { CurrentConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); // Save the LENGTH of the Config descriptor // Note that IsIADDevice() saves the ADDRESS of the END of the Config desc // Be aware of the difference dwConfigLength = CurrentConfigDesc->wTotalLength; } } return; } /***************************************************************************** IsUVCDevice() Return Spec version of UVC device 0x0 = Not a UVC device 0x10 = UVC 1.0 0x11 = UVC 1.1 *****************************************************************************/ UINT IsUVCDevice ( PUSBDEVICEINFO info ) { PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc = NULL; PUSB_COMMON_DESCRIPTOR commonDesc = NULL; PUCHAR descEnd = NULL; UINT uUVCversion = 0; // // The GetConfigDescriptor() function in enum.c does not always work // If that fails, the Configuration descriptor will be NULL // and we can only display the device descriptor // if (NULL == info) { return 0; } if (NULL == info->ConfigDesc) { return 0; } ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); if (NULL == ConfigDesc) { return 0; } // We've got a good Configuration Descriptor commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; // walk through all the descriptors looking for the VIDEO_CONTROL_HEADER_UNIT while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { if ((commonDesc->bDescriptorType == CS_INTERFACE) && (commonDesc->bLength > sizeof(VIDEO_CONTROL_HEADER_UNIT))) { // Right type, size. Now check subtype PVIDEO_CONTROL_HEADER_UNIT pCSVC = NULL; pCSVC = (PVIDEO_CONTROL_HEADER_UNIT) commonDesc; if (VC_HEADER == pCSVC->bDescriptorSubtype) { // found the Class-specific VC Interface Header descriptor uUVCversion = pCSVC->bcdVideoSpec; // Save the version to global g_chUVCversion = uUVCversion; // We're done break; } } commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); } return (uUVCversion); } /***************************************************************************** IsIADDevice() *****************************************************************************/ UINT IsIADDevice ( PUSBDEVICEINFO info ) { PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc = NULL; PUSB_COMMON_DESCRIPTOR commonDesc = NULL; PUCHAR descEnd = NULL; UINT uIADcount = 0; // // The GetConfigDescriptor() function in enum.c does not always work // If that fails, the Configuration descriptor will be NULL // and we can only display the device descriptor // if (NULL == info) { return 0; } if (NULL == info->ConfigDesc) { return 0; } ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); if (NULL != ConfigDesc) { commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; } // return total number of IAD descriptors in this device configuration while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { if (commonDesc->bDescriptorType == USB_IAD_DESCRIPTOR_TYPE) { uIADcount++; } commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); } return (uIADcount); } /***************************************************************************** DisplayIADDescriptor() *****************************************************************************/ VOID DisplayIADDescriptor ( PUSB_IAD_DESCRIPTOR IADDesc, PSTRING_DESCRIPTOR_NODE StringDescs, int nInterfaces, DEVICE_POWER_STATE LatestDevicePowerState ) { AppendTextBuffer("\r\n ===>IAD Descriptor<===\r\n"); //length checked in DisplayConfigDesc() AppendTextBuffer("bLength: 0x%02X\r\n", IADDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", IADDesc->bDescriptorType); AppendTextBuffer("bFirstInterface: 0x%02X\r\n", IADDesc->bFirstInterface); AppendTextBuffer("bInterfaceCount: 0x%02X\r\n", IADDesc->bInterfaceCount); if (IADDesc->bInterfaceCount == 1) { //@@TestCase A7.1 //@@Priority 1 //@@Standard IAD Descriptor Field - bInterfaceCount //@@The number of interfaces must be greater than 1 AppendTextBuffer("*!*ERROR: bInterfaceCount must be greater than 1 \r\n"); OOPS(); } if (nInterfaces < IADDesc->bFirstInterface + IADDesc->bInterfaceCount) { //@@TestCase A7.2 //@@Priority 1 //@@Standard IAD Descriptor Field - bInterfaceCount //@@The total number of interfaces must be greater than or equal to //@@ the highest linked interface number (base interface number plus count) AppendTextBuffer("*!*ERROR: The total number of interfaces (%d) must be greater "\ "than or equal to\r\n", nInterfaces); AppendTextBuffer(" the highest linked interface number (base %d + "\ "count %d = %d)\r\n", IADDesc->bFirstInterface, IADDesc->bInterfaceCount, (IADDesc->bFirstInterface + IADDesc->bInterfaceCount)); OOPS(); } AppendTextBuffer("bFunctionClass: 0x%02X", IADDesc->bFunctionClass); if (IADDesc->bFunctionClass == 0) { //@@TestCase A7.3 //@@Priority 1 //@@Standard IAD Descriptor Field - bFunctionClass //@@"A value of zero is not allowed in this descriptor" AppendTextBuffer("\r\n*!*ERROR: bFunctionClass contains an illegal value 0 \r\n"); OOPS(); } switch (IADDesc->bFunctionClass) { case USB_DEVICE_CLASS_AUDIO: if(gDoAnnotation) { AppendTextBuffer(" -> Audio Interface Class\r\n"); } AppendTextBuffer("bFunctionSubClass: 0x%02X", IADDesc->bFunctionSubClass); if(gDoAnnotation) { switch (IADDesc->bFunctionSubClass) { case USB_AUDIO_SUBCLASS_AUDIOCONTROL: AppendTextBuffer(" -> Audio Control Interface SubClass\r\n"); break; case USB_AUDIO_SUBCLASS_AUDIOSTREAMING: AppendTextBuffer(" -> Audio Streaming Interface SubClass\r\n"); break; case USB_AUDIO_SUBCLASS_MIDISTREAMING: AppendTextBuffer(" -> MIDI Streaming Interface SubClass\r\n"); break; default: //@@TestCase A7.4 //@@CAUTION //@@Descriptor Field - bFunctionSubClass //@@Invalid bFunctionSubClass AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid bFunctionSubClass\r\n"); OOPS(); break; } } break; case USB_DEVICE_CLASS_VIDEO: if(gDoAnnotation) { AppendTextBuffer(" -> Video Interface Class\r\n"); } AppendTextBuffer("bFunctionSubClass: 0x%02X", IADDesc->bFunctionSubClass); switch(IADDesc->bFunctionSubClass) { case SC_VIDEO_INTERFACE_COLLECTION: if(gDoAnnotation) { AppendTextBuffer(" -> Video Interface Collection\r\n"); } break; default: //@@TestCase A7.5 //@@CAUTION //@@Descriptor Field - bFunctionSubClass //@@Invalid bFunctionSubClass AppendTextBuffer("\r\n*!*ERROR: This should be USB_VIDEO_SC_VIDEO_INTERFACE_COLLECTION %d\r\n", SC_VIDEO_INTERFACE_COLLECTION); OOPS(); break; } break; case USB_DEVICE_CLASS_HUMAN_INTERFACE: if(gDoAnnotation) { AppendTextBuffer(" -> HID Interface Class\r\n"); } AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DEVICE_CLASS_HUB: if(gDoAnnotation) { AppendTextBuffer(" -> HUB Interface Class\r\n"); } AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DEVICE_CLASS_RESERVED: //@@TestCase A7.6 //@@CAUTION //@@Descriptor Field - bFunctionClass //@@A reserved USB Device Interface Class has been defined AppendTextBuffer("\r\n*!*CAUTION: %d is a Reserved USB Device Interface Class\r\n", USB_DEVICE_CLASS_RESERVED); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DEVICE_CLASS_COMMUNICATIONS: AppendTextBuffer(" -> This is Communications (CDC Control) USB Device Interface Class\r\n"); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DEVICE_CLASS_MONITOR: AppendTextBuffer(" -> This is a Monitor USB Device Interface Class*** (This may be obsolete)\r\n"); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DEVICE_CLASS_PHYSICAL_INTERFACE: AppendTextBuffer(" -> This is a Physical Interface USB Device Interface Class\r\n"); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DEVICE_CLASS_POWER: if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1) { AppendTextBuffer(" -> This is an Image USB Device Interface Class\r\n"); } else { AppendTextBuffer(" -> This is a Power USB Device Interface Class (This may be obsolete)\r\n"); } AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DEVICE_CLASS_PRINTER: AppendTextBuffer(" -> This is a Printer USB Device Interface Class\r\n"); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DEVICE_CLASS_STORAGE: AppendTextBuffer(" -> This is a Mass Storage USB Device Interface Class\r\n"); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_CDC_DATA_INTERFACE: AppendTextBuffer(" -> This is a CDC Data USB Device Interface Class\r\n"); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_CHIP_SMART_CARD_INTERFACE: AppendTextBuffer(" -> This is a Chip/Smart Card USB Device Interface Class\r\n"); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_CONTENT_SECURITY_INTERFACE: AppendTextBuffer(" -> This is a Content Security USB Device Interface Class\r\n"); AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_DIAGNOSTIC_DEVICE_INTERFACE: if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1) { AppendTextBuffer(" -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\r\n"); } else { //@@TestCase A7.7 //@@CAUTION //@@Descriptor Field - bFunctionClass //@@Invalid Interface Class AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_WIRELESS_CONTROLLER_INTERFACE: if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1) { AppendTextBuffer(" -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\r\n"); } else { //@@TestCase A7.8 //@@CAUTION //@@Descriptor Field - bFunctionClass //@@Invalid Interface Class AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; case USB_APPLICATION_SPECIFIC_INTERFACE: AppendTextBuffer(" -> This is an Application Specific USB Device Interface Class\r\n"); switch(IADDesc->bFunctionSubClass) { case 1: AppendTextBuffer(" -> This is a Device Firmware Application Specific USB Device Interface Class\r\n"); break; case 2: AppendTextBuffer(" -> This is an IrDA Bridge Application Specific USB Device Interface Class\r\n"); break; case 3: AppendTextBuffer(" -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\r\n"); break; default: //@@TestCase A7.9 //@@CAUTION //@@Descriptor Field - bFunctionClass //@@Invalid Interface Class AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); OOPS(); } AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; default: if(gDoAnnotation) { AppendTextBuffer(" -> Interface Class Unknown to USBView\r\n"); } AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", IADDesc->bFunctionSubClass); break; } AppendTextBuffer("bFunctionProtocol: 0x%02X", IADDesc->bFunctionProtocol); // check protocol for our class if ((IADDesc->bFunctionClass == USB_DEVICE_CLASS_VIDEO)) { // USB Video Class if(IADDesc->bFunctionProtocol == PC_PROTOCOL_UNDEFINED) { // correct protocol for UVC if(gDoAnnotation) { AppendTextBuffer(" -> PC_PROTOCOL_UNDEFINED protocol\r\n"); } else { AppendTextBuffer("\r\n"); } } else { // incorrect protocol for UVC //@@TestCase A7.10 //@@WARNING //@@Descriptor Field - iInterface //@@bFunctionProtocol must be set to PC_PROTOCOL_UNDEFINED AppendTextBuffer("*!*WARNING: must be set to PC_PROTOCOL_UNDEFINED %d for this class\r\n", PC_PROTOCOL_UNDEFINED); OOPS(); } } else { AppendTextBuffer("\r\n"); } AppendTextBuffer("iFunction: 0x%02X\r\n", IADDesc->iFunction); if(gDoAnnotation) { if (IADDesc->iFunction) { DisplayStringDescriptor(IADDesc->iFunction, StringDescs, LatestDevicePowerState); } } } /***************************************************************************** GetConfigurationSize() *****************************************************************************/ UINT GetConfigurationSize ( PUSBDEVICEINFO info ) { PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); PUSB_COMMON_DESCRIPTOR commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; PUCHAR descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; UINT uCount = 0; // return this device configuration's total sum of descriptor lengths while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { uCount += commonDesc->bLength; commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); } return (uCount); } /***************************************************************************** GetInterfaceCount() *****************************************************************************/ UINT GetInterfaceCount ( PUSBDEVICEINFO info ) { // how do we handle composite devices? PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); PUSB_COMMON_DESCRIPTOR commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; PUCHAR descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; UINT uCount = 0; // return this device configuration's total number of interface descriptors while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { if (commonDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) { uCount++; } commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); } return (uCount); } /***************************************************************************** DisplayUSEnglishStringDescriptor() *****************************************************************************/ VOID DisplayUSEnglishStringDescriptor ( UCHAR Index, PSTRING_DESCRIPTOR_NODE USStringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { ULONG nBytes = 0; BOOLEAN FoundMatchingString = FALSE; CHAR pString[512]; //@@DisplayUSEnglishStringDescriptor - String Descriptor for (; USStringDescs; USStringDescs = USStringDescs->Next) { if (USStringDescs->DescriptorIndex == Index && USStringDescs->LanguageID == 0x0409) { FoundMatchingString = TRUE; AppendTextBuffer("English product name: \""); memset(pString, 0, 512); nBytes = WideCharToMultiByte( CP_ACP, // CodePage WC_NO_BEST_FIT_CHARS, USStringDescs->StringDescriptor->bString, (USStringDescs->StringDescriptor->bLength - 2) / 2, pString, 512, NULL, // lpDefaultChar NULL); // pUsedDefaultChar if (nBytes) AppendTextBuffer("%s\"\r\n", pString); else AppendTextBuffer("\"\r\n", pString); return; } } //@@TestCase A8.1 //@@WARNING //@@Descriptor Field - string index //@@No support for english if (!FoundMatchingString) { if (LatestDevicePowerState == PowerDeviceD0) { AppendTextBuffer("*!*ERROR: No String Descriptor for index %d!\r\n", Index); OOPS(); } else { AppendTextBuffer("String Descriptor for index %d not available while device is in low power state.\r\n", Index); } } else { AppendTextBuffer("*!*ERROR: The index selected does not support English(US)\r\n"); OOPS(); } return; } /***************************************************************************** DisplayStringDescriptor() *****************************************************************************/ VOID DisplayStringDescriptor ( UCHAR Index, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { ULONG nBytes = 0; BOOLEAN FoundMatchingString = FALSE; PCHAR pStr = NULL; CHAR pString[512]; //@@DisplayStringDescriptor - String Descriptor while (StringDescs) { if (StringDescs->DescriptorIndex == Index) { FoundMatchingString = TRUE; if(gDoAnnotation) { pStr= GetLangIDString(StringDescs->LanguageID); if(pStr) { AppendTextBuffer(" %s \"", pStr); } else { //@@TestCase A9.1 //@@WARNING //@@Descriptor Field - string index //@@The Language ID does not match any known languages supported by USB ORG AppendTextBuffer("*!*WARNING: %d is an invalid Language ID\r\n", Index); OOPS(); } } else { AppendTextBuffer(" 0x%04X: \"", StringDescs->LanguageID); } memset(pString, 0, 512); if (StringDescs->StringDescriptor->bLength > sizeof(USHORT)) { nBytes = WideCharToMultiByte( CP_ACP, // CodePage WC_NO_BEST_FIT_CHARS, StringDescs->StringDescriptor->bString, (StringDescs->StringDescriptor->bLength - 2) / 2, pString, 512, NULL, // lpDefaultChar NULL); // pUsedDefaultChar if (nBytes) { AppendTextBuffer("%s\"\r\n", pString); } else { AppendTextBuffer("\"\r\n"); } } else { // // This is NULL string which is invalid // AppendTextBuffer("\"\r\n"); } } StringDescs = StringDescs->Next; } if (!FoundMatchingString) { if (LatestDevicePowerState == PowerDeviceD0) { AppendTextBuffer("*!*ERROR: No String Descriptor for index %d!\r\n", Index); OOPS(); } else { AppendTextBuffer("String Descriptor for index %d not available while device is in low power state.\r\n", Index); } } } /***************************************************************************** DisplayUnknownDescriptor() *****************************************************************************/ VOID DisplayUnknownDescriptor ( PUSB_COMMON_DESCRIPTOR CommonDesc ) { AppendTextBuffer("\r\n ===>Descriptor Hex Dump<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", CommonDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", CommonDesc->bDescriptorType); DisplayRemainingUnknownDescriptor((PUCHAR)CommonDesc, 0, CommonDesc->bLength); } VOID DisplayRemainingUnknownDescriptor( PUCHAR DescriptorData, ULONG Start, ULONG Stop ) { ULONG i; for (i = Start; i < Stop; i++) { AppendTextBuffer("%02X ", DescriptorData[i]); if (i % 16 == 15) { AppendTextBuffer("\r\n"); } } if (i % 16 != 0) { AppendTextBuffer("\r\n"); } } /***************************************************************************** GetVendorString() idVendor - USB Vendor ID Return Value - Vendor name string associated with idVendor, or NULL if no vendor name string is found which is associated with idVendor. *****************************************************************************/ PCHAR GetVendorString ( USHORT idVendor ) { PVENDOR_ID vendorID = NULL; if (idVendor == 0x0000) { return NULL; } vendorID = USBVendorIDs; while (vendorID->usVendorID != 0x0000) { if (vendorID->usVendorID == idVendor) { break; } vendorID++; } return (vendorID->szVendor); } /***************************************************************************** GetLangIDString() idVendor - USB Vendor ID Return Value - Vendor name string associated with idVendor, or NULL if no vendor name string is found which is associated with idVendor. *****************************************************************************/ PCHAR GetLangIDString ( USHORT idLang ) { PUSBLANGID langID = NULL; if (idLang != 0x0000) { langID = USBLangIDs; while (langID->usLangID != 0x0000) { if (langID->usLangID == idLang) { return (langID->szLanguage); } langID++; } } return NULL; } /***************************************************************************** GetStringFromList() PSTRINGLIST slList, - pointer to STRINGLIST used ULONG ulNumElements, - number of elements in that STRINGLIST calc before call with sizeof(slList) / sizeof(STRINGLIST), ULONG or ULONGLONG (if H264_SUPPORT is defined)ulFlag - - flag to look for PCHAR szDefault - string to return if no match Return a string associated with a value from a stringtable. example: GetStringFromList(slPowerState, sizeof(slPowerState) / sizeof(STRINGLIST), pUPI->SystemState, "Invalid Power State") *****************************************************************************/ PCHAR GetStringFromList( PSTRINGLIST slList, ULONG ulNumElements, #ifdef H264_SUPPORT ULONGLONG ulFlag, #else ULONG ulFlag, #endif _In_ PCHAR szDefault ) { // ulIndex is zero based, but ulNumElements is 1 based // subtract 1 from ulNumElements so that are same base #ifdef H264_SUPPORT ULONGLONG ulIndex = 0; #else ULONG ulIndex = 0; #endif ulNumElements--; for ( ; ulIndex <= ulNumElements; ulIndex++) { if (ulFlag == slList[ulIndex].ulFlag) { return (slList[ulIndex].pszString); } } return szDefault; } ================================================ FILE: tests/projects/windows/winsdk/usbview/dispvid.c ================================================ /*++ Copyright (c) 2002-2008 Microsoft Corporation Module Name: DISPVID.C Abstract: This source file contains routines which update the edit control to display information about USB Video descriptors. Environment: user mode Revision History: 11-22-2002 : created 03-28-2003 : major revisions from latest specs. 03-28-2008 : include USB Video Class 1.1 --*/ //***************************************************************************** // I N C L U D E S //***************************************************************************** #include "uvcview.h" #include "h264.h" //***************************************************************************** // G L O B A L S P R I V A T E T O T H I S F I L E //***************************************************************************** int StillMethod = 0; // // USB Device Class Definition for Video Devices 0.8b version // // 3.6.2.3 Camera Terminal Descriptor // STRINGLIST slCameraControl1 [] = { {1, "Scanning Mode", ""}, {2, "Auto-Exposure Mode", ""}, {4, "Auto-Exposure Priority", ""}, {8, "Exposure Time (Absolute)", ""}, {0x10, "Exposure Time (Relative)", ""}, {0x20, "Focus (Absolute)", ""}, {0x40, "Focus (Relative)", ""}, {0x80, "Iris (Absolute)", ""}, }; STRINGLIST slCameraControl2 [] = { {1, "Iris (Relative)", ""}, {2, "Zoom (Absolute)", ""}, {4, "Zoom (Relative)", ""}, {8, "PanTilt (Absolute)", ""}, {0x10, "PanTilt (Relative)", ""}, {0x20, "Roll (Absolute)", ""}, {0x40, "Roll (Relative)", ""}, {0x80, "Reserved", ""}, }; STRINGLIST slCameraControl3 [] = { {1, "Reserved", ""}, {2, "Focus, Auto", ""}, {4, "Privacy", ""}, {8, "Focus, Simple", ""}, {0x10, "Window", ""}, {0x20, "Region of Interest", ""}, {0x40, "Reserved", ""}, {0x80, "Reserved", ""}, }; // 3.6.2.5 Processing Unit Descriptor // STRINGLIST slProcessorControls1 [] = { {1, "Brightness", ""}, {2, "Contrast", ""}, {4, "Hue", ""}, {8, "Saturation", ""}, {0x10, "Sharpness", ""}, {0x20, "Gamma", ""}, {0x40, "White Balance Temperature", ""}, {0x80, "White Balance Component", ""}, }; STRINGLIST slProcessorControls2 [] = { {1, "Backlight Compensation", ""}, {2, "Gain", ""}, {4, "Power Line Frequency", ""}, {8, "Hue, Auto", ""}, {0x10, "White Balance Temperature, Auto", ""}, {0x20, "White Balance Component, Auto", ""}, {0x40, "Digital Multiplier", ""}, {0x80, "Digital Multiplier Limit", ""}, }; STRINGLIST slProcessorControls3 [] = { {1, "Analog Video Standard", ""}, {2, "Analog Video Lock Status", ""}, {4, "Contrast, Auto", ""}, {8, "Reserved", ""}, {0x10, "Reserved", ""}, {0x20, "Reserved", ""}, {0x40, "Reserved", ""}, {0x80, "Reserved", ""}, }; STRINGLIST slProcessorVideoStandards [] = { {1, "None", ""}, {2, "NTSC - 525/60", ""}, {4, "PAL - 625/50", ""}, {8, "SECAM - 625/50", ""}, {0x10, "NTSC - 625/50", ""}, {0x20, "PAL - 525/60", ""}, {0x40, "Reserved", ""}, {0x80, "Reserved", ""}, }; // 3.8.2.1 Input Header Descriptor // STRINGLIST slInputHeaderControls[]= { {1, "Key Frame Rate" , ""}, {2, "P Frame Rate" , ""}, {4, "Compression Quality" , ""}, {8, "Compression Window Size", ""}, {0x10, "Generate Key Frame" , ""}, {0x20, "Update Frame Segment" , ""}, {0x40, "Reserved" , ""}, {0x80, "Reserved" , ""}, }; STRINGLIST slOutputHeaderControls[]= { {1, "Key Frame Rate" , ""}, {2, "P Frame Rate" , ""}, {4, "Compression Quality" , ""}, {8, "Compression Window Size", ""}, {0x10, "Reserved" , ""}, {0x20, "Reserved" , ""}, {0x40, "Reserved" , ""}, {0x80, "Reserved" , ""}, }; STRINGLIST slMediaTransportControls[]= { {1, "Transport Control" , ""}, {2, "Absolute Track Number Control", ""}, {4, "Media Information" , ""}, {8, "Time Code Information" , ""}, {0x10, "Reserved" , ""}, {0x20, "Reserved" , ""}, {0x40, "Reserved" , ""}, {0x80, "Reserved" , ""}, }; STRINGLIST slMediaTransportModes1[]= { {1, "Play Forward", ""}, {2, "Pause", ""}, {4, "Rewind", ""}, {8, "Fast Forward", ""}, {0x10, "High Speed Rewind", ""}, {0x20, "Stop", ""}, {0x40, "Eject", ""}, {0x80, "Play Next Frame", ""}, }; STRINGLIST slMediaTransportModes2[]= { {1, "Play Slowest Forward", ""}, {2, "Play Slow Forward 4", ""}, {4, "Play Slow Forward 3", ""}, {8, "Play Slow Forward 2", ""}, {0x10, "Play Slow Forward 1", ""}, {0x20, "Play X1", ""}, {0x40, "Play Fast Forward 1", ""}, {0x80, "Play Fast Forward 2", ""}, }; STRINGLIST slMediaTransportModes3[]= { {1, "Play Fast Forward 3", ""}, {2, "Play Fast Forward 4", ""}, {4, "Play Fastest Forward", ""}, {8, "Play Previous Frame", ""}, {0x10, "Play Slowest Reverse", ""}, {0x20, "Play Slow Reverse 4", ""}, {0x40, "Play Slow Reverse 3", ""}, {0x80, "Play Slow Reverse 2", ""}, }; STRINGLIST slMediaTransportModes4[]= { {1, "Play Slow Reverse 1", ""}, {2, "Play X1 Reverse", ""}, {4, "Play Fast Reverse 1", ""}, {8, "Play Fast Reverse 2", ""}, {0x10, "Play Fast Reverse 3", ""}, {0x20, "Play Fast Reverse 4", ""}, {0x40, "Play Fastest Reverse", ""}, {0x80, "Record StateStart", ""}, }; STRINGLIST slMediaTransportModes5[]= { {1, "Record Pause", ""}, {2, "Reserved", ""}, {4, "Reserved", ""}, {8, "Reserved", ""}, {0x10, "Reserved", ""}, {0x20, "Reserved", ""}, {0x40, "Reserved", ""}, {0x80, "Reserved", ""}, }; STRINGLIST slInputTermTypes[]= { {0x0100, "TT_VENDOR_SPECIFIC", "I//O"}, {0x0101, "TT_STREAMING", "I//O"}, {0x0400, "EXTERNAL_VENDOR_SPECIFIC", "I//O"}, {0x0401, "COMPOSITE_CONNECTOR", "I//O"}, {0x0402, "SVIDEO_CONNECTOR", "I//O"}, {0x0403, "COMPONENT_CONNECTOR", "I//O"}, {0x0200, "ITT_VENDOR_SPECIFIC", "I"}, {0x0201, "ITT_CAMERA", "I"}, {0x0202, "ITT_MEDIA_TRANSPORT_INPUT", "I"}, }; STRINGLIST slOutputTermTypes[]= { {0x0100, "TT_VENDOR_SPECIFIC", "I//O"}, {0x0101, "TT_STREAMING", "I//O"}, {0x0400, "EXTERNAL_VENDOR_SPECIFIC", "I//O"}, {0x0401, "COMPOSITE_CONNECTOR", "I//O"}, {0x0402, "SVIDEO_CONNECTOR", "I//O"}, {0x0403, "COMPONENT_CONNECTOR", "I//O"}, {0x0300, "OTT_VENDOR_SPECIFIC", "O"}, {0x0301, "OTT_DISPLAY", "O"}, {0x0302, "OTT_MEDIA_TRANSPORT_OUTPUT", "O"}, }; //***************************************************************************** // L O C A L F U N C T I O N P R O T O T Y P E S //***************************************************************************** BOOL DisplayVCHeader ( PVIDEO_CONTROL_HEADER_UNIT VCInterfaceDesc ); BOOL DisplayVCInputTerminal ( PVIDEO_INPUT_TERMINAL VidITDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); BOOL DisplayVCOutputTerminal ( PVIDEO_OUTPUT_TERMINAL VidOTDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); BOOL DisplayVCCameraTerminal ( PVIDEO_CAMERA_TERMINAL CameraDesc ); BOOL DisplayVCMediaTransInputTerminal ( PVIDEO_INPUT_MTT VCMedTransInDesc ); BOOL DisplayVCMediaTransOutputTerminal ( PVIDEO_OUTPUT_MTT VCMedTransOutDesc ); BOOL DisplayVCSelectorUnit ( PVIDEO_SELECTOR_UNIT VidSelectorDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); BOOL DisplayVCProcessingUnit ( PVIDEO_PROCESSING_UNIT VidProcessingDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); BOOL DisplayVCExtensionUnit ( PVIDEO_EXTENSION_UNIT VidExtensionDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); BOOL DisplayVidInHeader ( PVIDEO_STREAMING_INPUT_HEADER VidInHeaderDesc ); BOOL DisplayVidOutHeader ( PVIDEO_STREAMING_OUTPUT_HEADER VidOutHeaderDesc ); BOOL DisplayStillImageFrame ( PVIDEO_STILL_IMAGE_FRAME StillFrameDesc ); BOOL DisplayColorMatching ( PVIDEO_COLORFORMAT ColorMatchDesc ); BOOL DisplayUncompressedFormat ( PVIDEO_FORMAT_UNCOMPRESSED UnCompFormatDesc ); BOOL DisplayUncompressedFrameType ( PVIDEO_FRAME_UNCOMPRESSED UnCompFrameDesc ); BOOL DisplayUnComContinuousFrameType( PVIDEO_FRAME_UNCOMPRESSED UContinuousDesc ); BOOL DisplayUnComDiscreteFrameType( PVIDEO_FRAME_UNCOMPRESSED UDiscreteDesc ); BOOL DisplayMJPEGFormat ( PVIDEO_FORMAT_MJPEG MJPEGFormatDesc ); BOOL DisplayMJPEGFrameType ( PVIDEO_FRAME_MJPEG MJPEGFrameDesc ); BOOL DisplayMJPEGContinuousFrameType( PVIDEO_FRAME_MJPEG MContinuousDesc ); BOOL DisplayMJPEGDiscreteFrameType( PVIDEO_FRAME_MJPEG MDiscreteDesc ); BOOL DisplayMPEG1SSFormat ( PVIDEO_FORMAT_MPEG1SS MPEG1SSFormatDesc ); BOOL DisplayMPEG2PSFormat ( PVIDEO_FORMAT_MPEG2PS MPEG2PSFormatDesc ); BOOL DisplayMPEG2TSFormat ( PVIDEO_FORMAT_MPEG2TS MPEG2TSFormatDesc ); BOOL DisplayMPEG4SLFormat ( PVIDEO_FORMAT_MPEG4SL MPEG4SLFormatDesc ); BOOL DisplayDVFormat ( PVIDEO_FORMAT_DV DVFormatDesc ); BOOL DisplayVendorVidFormat ( PVIDEO_FORMAT_VENDOR VendorVidFormatDesc ); BOOL DisplayVendorVidFrameType ( PVIDEO_FRAME_VENDOR VendorVidFrameDesc ); BOOL DisplayVendorVidContinuousFrameType( PVIDEO_FRAME_VENDOR VContinuousDesc ); BOOL DisplayVendorVidDiscreteFrameType( PVIDEO_FRAME_VENDOR VDiscreteDesc ); BOOL DisplayFramePayloadFormat( PVIDEO_FORMAT_FRAME FramePayloadFormatDesc ); BOOL DisplayFramePayloadFrame( PVIDEO_FRAME_FRAME FramePayloadFrameDesc ); BOOL DisplayFramePayloadContinuousFrameType( PVIDEO_FRAME_FRAME FContinuousDesc ); BOOL DisplayFramePayloadDiscreteFrameType( PVIDEO_FRAME_FRAME FDiscreteDesc ); BOOL DisplayStreamPayload( PVIDEO_FORMAT_STREAM StreamPayloadDesc ); BOOL DisplayVSEndpoint ( PVIDEO_CS_INTERRUPT VidEndpointDesc ); VOID VDisplayBytes ( PUCHAR Data, USHORT Len ); PCHAR VidFormatGUIDCodeToName ( REFGUID VidFormatGUIDCode ); UINT GetVCInterfaceSize ( PVIDEO_CONTROL_HEADER_UNIT VCInterfaceDesc ); UINT CheckForColorMatchingDesc ( PVIDEO_SPECIFIC FormatDesc, UCHAR bNumFrameDescriptors, UCHAR bDescriptorSubtype ); UINT GetVSInterfaceSize ( PUSB_COMMON_DESCRIPTOR VidInHeaderDesc, USHORT wTotalLength ); BOOL ValidateTerminalID( UINT uTerminalID ); VOID VDisplayDescString ( UINT uControlSize, PUCHAR pControl , PSTRINGLIST pslControl ); //***************************************************************************** // L O C A L F U N C T I O N S //***************************************************************************** //***************************************************************************** // // DisplayVideoDescriptor() UPDATED // // VidCommonDesc - An Video Class Descriptor // // bInterfaceSubClass - The SubClass of the Interface containing the descriptor // //***************************************************************************** BOOL DisplayVideoDescriptor ( PVIDEO_SPECIFIC VidCommonDesc, UCHAR bInterfaceSubClass, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { //@@DisplayVideoDescriptor -Class-Specific Video Descriptor switch (VidCommonDesc->bDescriptorType) { case CS_INTERFACE: //@@DisplayVideoDescriptor -Class-Specific Video Interface Descriptor switch (bInterfaceSubClass) { case VIDEO_SUBCLASS_CONTROL: //@@DisplayVideoDescriptor -Class-Specific Video Control Interface Descriptor switch (VidCommonDesc->bDescriptorSubtype) { case VC_HEADER: return DisplayVCHeader( (PVIDEO_CONTROL_HEADER_UNIT)VidCommonDesc); case INPUT_TERMINAL: return DisplayVCInputTerminal( (PVIDEO_INPUT_TERMINAL)VidCommonDesc, StringDescs, LatestDevicePowerState); case OUTPUT_TERMINAL: return DisplayVCOutputTerminal( (PVIDEO_OUTPUT_TERMINAL)VidCommonDesc, StringDescs, LatestDevicePowerState); case SELECTOR_UNIT: return DisplayVCSelectorUnit( (PVIDEO_SELECTOR_UNIT)VidCommonDesc, StringDescs, LatestDevicePowerState); case PROCESSING_UNIT: return DisplayVCProcessingUnit( (PVIDEO_PROCESSING_UNIT)VidCommonDesc, StringDescs, LatestDevicePowerState); case EXTENSION_UNIT: return DisplayVCExtensionUnit( (PVIDEO_EXTENSION_UNIT)VidCommonDesc, StringDescs, LatestDevicePowerState); #ifdef H264_SUPPORT case H264_ENCODING_UNIT: return DisplayVCH264EncodingUnit( (PVIDEO_ENCODING_UNIT)VidCommonDesc ); #endif #ifdef H264_SUPPORT case MAX_TYPE_UNIT+1: // for H.264, the bDescriptorSubtype = 7, which is equal to MAX_TYPE_UNIT // so now MAX_TYPE_UNIT needs to be set to 8 //(TODO: need to change nt\sdpublic\internal\drivers\inc\uvcdesc.h's define // of MAX_TYPE_UNIT from7 to 8, and ad the type for H.264 = 8) #else case MAX_TYPE_UNIT: #endif //@@TestCase B1.1 //@@CAUTION //@@Descriptor Field - bDescriptorSubtype //@@An undefined descriptor subtype has been defined AppendTextBuffer("*!*CAUTION: This is an undefined class specific "\ "Video Control bDescriptorSubtype\r\n"); break; default: //@@TestCase B1.2 //@@ERROR //@@Descriptor Field - bDescriptorSubtype //@@An unknown descriptor subtype has been defined AppendTextBuffer("*!*ERROR: unknown bDescriptorSubtype\r\n"); OOPS(); break; } break; case VIDEO_SUBCLASS_STREAMING: //@@DisplayVideoDescriptor -Class-Specific Video Streaming Interface Descriptor switch (VidCommonDesc->bDescriptorSubtype) { case VS_INPUT_HEADER: return DisplayVidInHeader( (PVIDEO_STREAMING_INPUT_HEADER)VidCommonDesc); case VS_OUTPUT_HEADER: return DisplayVidOutHeader( (PVIDEO_STREAMING_OUTPUT_HEADER)VidCommonDesc); case VS_STILL_IMAGE_FRAME: return DisplayStillImageFrame( (PVIDEO_STILL_IMAGE_FRAME)VidCommonDesc); case VS_FORMAT_UNCOMPRESSED: #ifdef H264_SUPPORT { BOOL retCode = DisplayUncompressedFormat( (PVIDEO_FORMAT_UNCOMPRESSED)VidCommonDesc ); g_expectedNumberOfUncompressedFrameFrameDescriptors += ((PVIDEO_FORMAT_UNCOMPRESSED)VidCommonDesc)->bNumFrameDescriptors; return retCode; } #else return DisplayUncompressedFormat( (PVIDEO_FORMAT_UNCOMPRESSED)VidCommonDesc); #endif case VS_FRAME_UNCOMPRESSED: #ifdef H264_SUPPORT { BOOL retCode = DisplayUncompressedFrameType( (PVIDEO_FRAME_UNCOMPRESSED)VidCommonDesc ); g_numberOfUncompressedFrameFrameDescriptors++; return retCode; } #else return DisplayUncompressedFrameType( (PVIDEO_FRAME_UNCOMPRESSED)VidCommonDesc); #endif #ifdef H264_SUPPORT case VS_FORMAT_H264: { BOOL retCode = DisplayVCH264Format( (PVIDEO_FORMAT_H264)VidCommonDesc ); g_expectedNumberOfH264FrameDescriptors += ((PVIDEO_FORMAT_H264)VidCommonDesc)->bNumFrameDescriptors; return retCode; } case VS_FRAME_H264: { BOOL retCode = DisplayVCH264FrameType( (PVIDEO_FRAME_H264)VidCommonDesc ); g_numberOfH264FrameDescriptors++; return retCode; } #endif case VS_FORMAT_MJPEG: #ifdef H264_SUPPORT // additional checks { BOOL retCode = DisplayMJPEGFormat( (PVIDEO_FORMAT_MJPEG)VidCommonDesc ); g_expectedNumberOfMJPEGFrameDescriptors += ((PVIDEO_FORMAT_MJPEG)VidCommonDesc)->bNumFrameDescriptors; return retCode; } #else return DisplayMJPEGFormat( (PVIDEO_FORMAT_MJPEG)VidCommonDesc); #endif case VS_FRAME_MJPEG: #ifdef H264_SUPPORT { BOOL retCode = DisplayMJPEGFrameType( (PVIDEO_FRAME_MJPEG)VidCommonDesc ); g_numberOfMJPEGFrameDescriptors++; return retCode; } #else return DisplayMJPEGFrameType( (PVIDEO_FRAME_MJPEG)VidCommonDesc); #endif case VS_FORMAT_MPEG1: { if (UVC10 == g_chUVCversion) { return DisplayMPEG1SSFormat( (PVIDEO_FORMAT_MPEG1SS)VidCommonDesc); } else // this format is obsoleted in UVC version >= 1.1 { AppendTextBuffer("*!*ERROR: obsoleted bDescriptorSubtype\r\n"); OOPS(); break; } } case VS_FORMAT_MPEG2PS: { if (UVC10 == g_chUVCversion) { return DisplayMPEG2PSFormat( (PVIDEO_FORMAT_MPEG2PS)VidCommonDesc); } else // this format is obsoleted in UVC version >= 1.1 { AppendTextBuffer("*!*ERROR: obsoleted bDescriptorSubtype\r\n"); OOPS(); break; } } case VS_FORMAT_MPEG2TS: return DisplayMPEG2TSFormat( (PVIDEO_FORMAT_MPEG2TS)VidCommonDesc); case VS_FORMAT_MPEG4SL: { if (UVC10 == g_chUVCversion) { return DisplayMPEG4SLFormat( (PVIDEO_FORMAT_MPEG4SL)VidCommonDesc); } else // this format is obsoleted in UVC version >= 1.1 { AppendTextBuffer("*!*ERROR: obsoleted bDescriptorSubtype\r\n"); OOPS(); break; } } case VS_FORMAT_DV: return DisplayDVFormat( (PVIDEO_FORMAT_DV)VidCommonDesc); case VS_COLORFORMAT: return DisplayColorMatching( (PVIDEO_COLORFORMAT)VidCommonDesc); case VS_FORMAT_VENDOR: { if (UVC10 == g_chUVCversion) { return DisplayVendorVidFormat( (PVIDEO_FORMAT_VENDOR)VidCommonDesc); } else // this format is obsoleted in UVC version >= 1.1 { AppendTextBuffer("*!*ERROR: obsoleted bDescriptorSubtype\r\n"); OOPS(); break; } } case VS_FRAME_VENDOR: { if (UVC10 == g_chUVCversion) { return DisplayVendorVidFrameType( (PVIDEO_FRAME_VENDOR)VidCommonDesc); } else // this format is obsoleted in UVC version >= 1.1 { AppendTextBuffer("*!*ERROR: obsoleted bDescriptorSubtype\r\n"); OOPS(); break; } } case VS_FORMAT_FRAME_BASED: { if (UVC10 != g_chUVCversion) { return DisplayFramePayloadFormat( (PVIDEO_FORMAT_FRAME)VidCommonDesc); } else // this format did not exist in UVC 1.0 { AppendTextBuffer("*!*ERROR: bDescriptorSubtype did not exist in UVC 1.0\r\n"); OOPS(); break; } } case VS_FRAME_FRAME_BASED: { if (UVC10 != g_chUVCversion) { return DisplayFramePayloadFrame( (PVIDEO_FRAME_FRAME)VidCommonDesc); } else // this format did not exist in UVC 1.0 { AppendTextBuffer("*!*ERROR: bDescriptorSubtype did not exist in UVC 1.0\r\n"); OOPS(); break; } } case VS_FORMAT_STREAM_BASED: { if (UVC10 != g_chUVCversion) { return DisplayStreamPayload( (PVIDEO_FORMAT_STREAM)VidCommonDesc); } else // this format did not exist in UVC 1.0 { AppendTextBuffer("*!*ERROR: bDescriptorSubtype did not exist in UVC 1.0\r\n"); OOPS(); break; } } case VS_DESCRIPTOR_UNDEFINED: //@@TestCase B1.3 //@@CAUTION //@@Descriptor Field - bDescriptorSubtype //@@An undefined descriptor subtype has been defined AppendTextBuffer("*!*CAUTION: This is an undefined class specific Video "\ "Streaming bDescriptorSubtype\r\n"); break; default: //@@TestCase B1.4 //@@ERROR //@@Descriptor Field - bDescriptorSubtype //@@An unknown descriptor subtype has been defined AppendTextBuffer("*!*ERROR: unknown bDescriptorSubtype\r\n"); OOPS(); break; } break; default: //@@TestCase B1.6 //@@ERROR //@@Descriptor Field - bInterfaceSubClass //@@An unknown interface sub-class has been defined AppendTextBuffer("*!*ERROR: unknown bInterfaceSubClass\r\n"); OOPS(); break; } break; case CS_ENDPOINT: //@@DisplayVideoDescriptor -Class-Specific Video Endpoint Descriptor switch (VidCommonDesc->bDescriptorSubtype) { //@@TestCase B1.7 //@@CAUTION //@@Descriptor Field - bInterfaceSubtype //@@An undefined descriptor subtype has been defined case EP_UNDEFINED: AppendTextBuffer("*!*CAUTION: This is an undefined bDescriptorSubtype\r\n"); break; //@@TestCase B1.8 //@@Not yet implemented - Priority 3 //@@Descriptor Field - bDescriptorSubtype //@@Question: How valid are VIDEO_EP_GENERAL and VIDEO_EP_ENDPOINT? Should we test? case EP_GENERAL: break; case EP_ENDPOINT: break; case EP_INTERRUPT: return DisplayVSEndpoint( (PVIDEO_CS_INTERRUPT)VidCommonDesc); break; default: //@@TestCase B1.9 //@@ERROR //@@Descriptor Field - bDescriptorSubtype //@@An unknown descriptor subtype has been defined AppendTextBuffer("*!*CAUTION: Unknown bDescriptorSubtype"); break; } break; //@@DisplayVideoDescriptor -Class-Specific Video Device Descriptor //@@DisplayVideoDescriptor -Class-Specific Video Configuration Descriptor //@@DisplayVideoDescriptor -Class-Specific Video String Descriptor //@@DisplayVideoDescriptor -Class-Specific Video Undefined Descriptor //@@TestCase B1.10 //@@Not yet implemented - Priority 3 //@@Descriptor -Class-Specific Device, Configuration, String, Undefined //@@Descriptor Field - bDescriptorType //@@Question: How valid are these Descriptor Types? Should we test? /* case USB_VIDEO_CS_DEVICE: AppendTextBuffer("USB_VIDEO_CS_DEVICE bDescriptorType\r\n"); break; case USB_VIDEO_CS_CONFIGURATION: AppendTextBuffer("USB_VIDEO_CS_CONFIGURATION bDescriptorType\r\n"); break; case USB_VIDEO_CS_STRING: AppendTextBuffer("USB_VIDEO_CS_STRING bDescriptorType\r\n"); break; case USB_VIDEO_CS_UNDEFINED: AppendTextBuffer("USB_VIDEO_CS_UNDEFINED bDescriptorType\r\n"); break; */ default: //@@TestCase B1.11 //@@ERROR //@@Descriptor Field - bDescriptorType //@@An unknown descriptor type has been defined AppendTextBuffer("*!*CAUTION: Unknown bDescriptorSubtype"); OOPS(); break; } return FALSE; } //***************************************************************************** // // DisplayVCHeader() // //***************************************************************************** BOOL DisplayVCHeader ( PVIDEO_CONTROL_HEADER_UNIT VCInterfaceDesc ) { //@@DisplayVCHeader -Video Control Interface Header UINT i = 0; UINT uSize = 0; PUCHAR pData = NULL; AppendTextBuffer("\r\n ===>Class-Specific Video Control Interface Header "\ "Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VCInterfaceDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VCInterfaceDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VCInterfaceDesc->bDescriptorSubtype); if ( UVC10 == g_chUVCversion ) { AppendTextBuffer("bcdVDC: 0x%04X\r\n", VCInterfaceDesc->bcdVideoSpec); } else { AppendTextBuffer("bcdUVC: 0x%04X\r\n", VCInterfaceDesc->bcdVideoSpec); } AppendTextBuffer("wTotalLength: 0x%04X", VCInterfaceDesc->wTotalLength); // Verify the total interface size (size of this header and all descriptors // following until and not including the first endpoint) uSize = GetVCInterfaceSize(VCInterfaceDesc); if (uSize != VCInterfaceDesc->wTotalLength) { AppendTextBuffer("\r\n*!*ERROR: Invalid total interface size 0x%02X, should be 0x%02X\r\n", VCInterfaceDesc->wTotalLength, uSize); } else { AppendTextBuffer(" -> Validated\r\n"); } AppendTextBuffer("dwClockFreq: 0x%08X", VCInterfaceDesc->dwClockFreq); if (gDoAnnotation) { AppendTextBuffer(" = (%d) Hz", VCInterfaceDesc->dwClockFreq); } AppendTextBuffer("\r\nbInCollection: 0x%02X\r\n", VCInterfaceDesc->bInCollection); // baInterfaceNr is a variable length field // Size is in bInCollection for (i = 1, pData = (PUCHAR) &VCInterfaceDesc->bInCollection; i <= VCInterfaceDesc->bInCollection; i++, pData++) { AppendTextBuffer("baInterfaceNr[%d]: 0x%02X\r\n", i, *pData); } uSize = (sizeof(VIDEO_CONTROL_HEADER_UNIT) + VCInterfaceDesc->bInCollection); if (VCInterfaceDesc->bLength != uSize) { //@@TestCase B2.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is less than required length in //@@ the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", VCInterfaceDesc->bLength, uSize); OOPS(); } //@@TestCase B2.2 (also in Descript.c) //@@WARNING //@@Descriptor Field - bcdVDC //@@The bcdVDC version of the device is not the same as the version of used by USBView if(VCInterfaceDesc->bcdVideoSpec < BCDVDC) { AppendTextBuffer("*!*WARNING: This device is set to the old USB Video "\ "Class spec version 0x%04X\r\n", VCInterfaceDesc->bcdVideoSpec); OOPS(); } if (VCInterfaceDesc->dwClockFreq < 1) { //@@TestCase B2.3 (Descript.c Line 70) //@@WARNING //@@dwClockFrequency should be greater than 0 //@@Question should we check that any non-zero value is accurate AppendTextBuffer("*!*ERROR: dwClockFreq must be non-zero\r\n"); OOPS(); } //@@TestCase B2.4 //@@Not yet implemented - Priority 1 //@@Descriptor Field - baInterfaceNr //@@We should test to verify each interface number is valid? // for (i=0; ibInCollection; i++) // {AppendTextBuffer("baInterfaceNr[%d]: 0x%02X\r\n", i+1, // VCInterfaceDesc->baInterfaceNr[i]);} if (gDoAnnotation) { switch(g_chUVCversion) { case UVC10: AppendTextBuffer("USB Video Class device: spec version 1.0\r\n"); break; case UVC11: AppendTextBuffer("USB Video Class device: spec version 1.1\r\n"); break; #ifdef H264_SUPPORT case UVC15: AppendTextBuffer("USB Video Class device: spec version 1.5\r\n"); break; #endif default: break; } } return TRUE; } //***************************************************************************** // // DisplayVCInputTerminal() // //***************************************************************************** BOOL DisplayVCInputTerminal ( PVIDEO_INPUT_TERMINAL VidITDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { //@@DisplayVCInputTerminal -Video Control Input Terminal PCHAR pStr = NULL; AppendTextBuffer("\r\n ===>Video Control Input Terminal Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VidITDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VidITDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VidITDesc->bDescriptorSubtype); AppendTextBuffer("bTerminalID: 0x%02X\r\n", VidITDesc->bTerminalID); AppendTextBuffer("wTerminalType: 0x%04X", VidITDesc->wTerminalType); if(gDoAnnotation) { pStr = GetStringFromList(slInputTermTypes, sizeof(slInputTermTypes) / sizeof(STRINGLIST), VidITDesc->wTerminalType, "Invalid Input Terminal Type"); AppendTextBuffer(" = (%s)", pStr); } AppendTextBuffer("\r\n"); AppendTextBuffer("bAssocTerminal: 0x%02X\r\n", VidITDesc->bAssocTerminal); AppendTextBuffer("iTerminal: 0x%02X\r\n", VidITDesc->iTerminal); if (gDoAnnotation) { if (VidITDesc->iTerminal) { // if executing this code, the configuration descriptor has been // obtained. If a device is suspended, then its configuration // descriptor was not obtained and we do not want errors to be // displayed when string descriptors were not obtained. DisplayStringDescriptor(VidITDesc->iTerminal, StringDescs, LatestDevicePowerState); } } if (VidITDesc->bLength < sizeof(VIDEO_INPUT_TERMINAL)) { //@@TestCase B3.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is less than required length in //@@ the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d is too small\r\n", VidITDesc->bLength); OOPS(); } if (VidITDesc->bTerminalID < 1) { //@@TestCase B3.2 (descript.c line 133) //@@ERROR //@@Descriptor Field - bTerminalID //@@bTerminalID should be greater than 0 //@@Question: Should test to verify terminal number is valid AppendTextBuffer("*!*ERROR: bTerminalID of %d is too small\r\n", VidITDesc->bTerminalID); OOPS(); } if (!(pStr)) { //@@TestCase B3.3 //@@CAUTION //@@Descriptor Field - wTerminalType //@@No valid Terminal Type was found AppendTextBuffer("*!*CAUTION: 0x%04X is an unknown wTerminalType for an Input "\ "Terminal\r\n", VidITDesc->wTerminalType); OOPS(); } //@@TestCase B3.4 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bAssocTerminal //@@Should test to verify terminal number is valid? // AppendTextBuffer("bAssocTerminal: 0x%02X\r\n", VidITDesc->bAssocTerminal); switch (VidITDesc->wTerminalType) { case 0x0100: // TT_VENDOR_SPECIFIC Terminal Type break; case 0x0101: // TT_STREAMING Terminal Type break; case 0x0200: // ITT_VENDOR_SPECIFIC Terminal Type break; case 0x0201: // ITT_CAMERA Terminal Type return DisplayVCCameraTerminal( (PVIDEO_CAMERA_TERMINAL)VidITDesc); case 0x0202: // ITT_MEDIA_TRANSPORT_INPUT Terminal Type return DisplayVCMediaTransInputTerminal( (PVIDEO_INPUT_MTT)VidITDesc); case 0x0400: // EXTERNAL_VENDOR_SPECIFIC Terminal Type break; case 0x0401: // COMPOSITE_CONNECTOR Terminal Type break; case 0x0402: // SVIDEO_CONNECTOR Terminal Type break; case 0x0403: // COMPONENT_CONNECTOR Terminal Type break; default: break; } return TRUE; } //***************************************************************************** // // DisplayVCOutputTerminal() // //***************************************************************************** BOOL DisplayVCOutputTerminal ( PVIDEO_OUTPUT_TERMINAL VidOTDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { //@@DisplayVCOutputTerminal -Video Control Output Terminal PCHAR pStr = NULL; AppendTextBuffer("\r\n ===>Video Control Output Terminal Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VidOTDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VidOTDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VidOTDesc->bDescriptorSubtype); AppendTextBuffer("bTerminalID: 0x%02X\r\n", VidOTDesc->bTerminalID); AppendTextBuffer("wTerminalType: 0x%04X", VidOTDesc->wTerminalType); if(gDoAnnotation) { pStr = GetStringFromList(slOutputTermTypes, sizeof(slOutputTermTypes) / sizeof(STRINGLIST), VidOTDesc->wTerminalType, "Invalid Output Terminal Type"); AppendTextBuffer(" = (%s)", pStr); } AppendTextBuffer("\r\n"); AppendTextBuffer("bAssocTerminal: 0x%02X\r\n", VidOTDesc->bAssocTerminal); AppendTextBuffer("bSourceID: 0x%02X\r\n", VidOTDesc->bSourceID); AppendTextBuffer("iTerminal: 0x%02X\r\n", VidOTDesc->iTerminal); if (gDoAnnotation) { if (VidOTDesc->iTerminal) { // if executing this code, the configuration descriptor has been // obtained. If a device is suspended, then its configuration // descriptor was not obtained and we do not want errors to be // displayed when string descriptors were not obtained. DisplayStringDescriptor(VidOTDesc->iTerminal, StringDescs, LatestDevicePowerState); } } if (VidOTDesc->bLength < sizeof(PVIDEO_OUTPUT_TERMINAL)) { //@@TestCase B4.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is less than required length in //@@ the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d is too small\r\n", VidOTDesc->bLength); OOPS(); } if (VidOTDesc->bTerminalID < 1) { //@@TestCase B4.2 (see Descript.c line 328) //@@ERROR //@@Descriptor Field - bTerminalID //@@bTerminalID should be greater than 0 //@@Question: Should test to verify terminal number is valid AppendTextBuffer("*!*ERROR: bTerminalID of %d is too small\r\n", VidOTDesc->bTerminalID); OOPS(); } if (!(pStr)) { //@@TestCase B4.3 //@@ERROR //@@Descriptor Field - wTerminalType //@@No valid Terminal Type was found AppendTextBuffer("*!*ERROR: 0x%04X is an invalid wTerminalType for an Output Terminal\r\n", VidOTDesc->wTerminalType); OOPS(); } //@@TestCase B4.4 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bAssocTerminal //@@We should test to verify terminal number is valid // AppendTextBuffer("bAssocTerminal: 0x%02X\r\n", VidOTDesc->bAssocTerminal); if (VidOTDesc->bSourceID < 1) { //@@TestCase B4.5 (see Descript.c line 333) //@@ERROR //@@Descriptor Field - bSourceID //@@bSourceID should be greater than 0 //@@Question: Should test to verify source number is valid AppendTextBuffer("*!*ERROR: bSourceID of %d is too small\r\n", VidOTDesc->bSourceID); OOPS(); } switch (VidOTDesc->wTerminalType) { case 0x0100: // TT_VENDOR_SPECIFIC Terminal Type break; case 0x0101: // TT_STREAMING Terminal Type break; case 0x0300: // OTT_VENDOR_SPECIFIC Terminal Type break; case 0x0301: // OTT_DISPLAY Terminal Type break; case 0x0302: // OTT_MEDIA_TRANSPORT_OUTPUT Terminal Type return DisplayVCMediaTransOutputTerminal( (PVIDEO_OUTPUT_MTT)VidOTDesc); case 0x0400: // EXTERNAL_VENDOR_SPECIFIC Terminal Type break; case 0x0401: // COMPOSITE_CONNECTOR Terminal Type break; case 0x0402: // SVIDEO_CONNECTOR Terminal Type break; case 0x0403: // COMPONENT_CONNECTOR Terminal Type break; default: break; } return TRUE; } //***************************************************************************** // // DisplayVCMediaTransInputTerminal() // //***************************************************************************** BOOL DisplayVCMediaTransInputTerminal( PVIDEO_INPUT_MTT MediaTransportInDesc ) { //@@DisplayVCMediaTransInputTerminal -Video Control Media Transport Input Terminal UCHAR p = 0; PUCHAR pData = NULL; size_t bLength = 0; bLength = SizeOfVideoInputMTT(MediaTransportInDesc); AppendTextBuffer("===>Additional Media Transport Input Terminal Data\r\n"); AppendTextBuffer("bControlSize: 0x%02X\r\n", MediaTransportInDesc->bControlSize); // point to bControlSize pData = & MediaTransportInDesc->bControlSize; // Are there any controls? if (0 < * pData) { UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; AppendTextBuffer("bmControls : "); VDisplayBytes(pData + 1, *pData); // map the first control for ( ; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData + 1); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportControls, sizeof(slMediaTransportControls) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportCtrl bmControl value")); cMask = cMask << 1; } } // point to bTransportModeSize pData = pData + 2 ; // Are there any controls? if (0 < * pData) { UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; AppendTextBuffer("bmControls : "); VDisplayBytes(pData + 1, *pData); // map the first control for ( ; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData + 1); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes1, sizeof(slMediaTransportModes1) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } // Is there a second control? if (1 < * pData) { // map the second control for ( uBitIndex = 8, cMask = 1; uBitIndex < 16; uBitIndex++ ) { cCheckBit = cMask & *(pData + 2); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes2, sizeof(slMediaTransportModes2) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } } // Is there a third control? if (2 < * pData) { // map the third control for ( uBitIndex = 16, cMask = 1; uBitIndex < 24; uBitIndex++ ) { cCheckBit = cMask & *(pData + 3); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes3, sizeof(slMediaTransportModes3) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } } // Is there a fourth control? if (3 < * pData) { // map the fourth control for ( uBitIndex = 24, cMask = 1; uBitIndex < 32; uBitIndex++ ) { cCheckBit = cMask & *(pData + 4); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes4, sizeof(slMediaTransportModes4) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } } // Is there a fifth control? if (4 < * pData) { // map the fifth control for ( uBitIndex = 32, cMask = 1; uBitIndex < 40; uBitIndex++ ) { cCheckBit = cMask & *(pData + 5); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes5, sizeof(slMediaTransportModes5) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } } } // The size of a Media Transport Descriptor is // the size of the Descriptor plus // (bControlSize - 1) plus // IF bmControls & 1 THEN 1 (bTransportModeSize) plus // bTransportModeSize // // p = sizeof(VIDEO_INPUT_MTT) + // (MediaTransportInDesc->bControlSize - 1); // if (MediaTransportInDesc->bmControls[0] & 1) // p += 1 + (*pData); if (MediaTransportInDesc->bLength != bLength) { //@@TestCase B5.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@Invalid Descriptor length AppendTextBuffer("*!*ERROR: Invalid descriptor bLength 0x%02X. "\ "Should be 0x%02X\r\n", MediaTransportInDesc->bLength, p); OOPS(); } return TRUE; } //***************************************************************************** // // DisplayVCMediaTransOutputTerminal() // //***************************************************************************** BOOL DisplayVCMediaTransOutputTerminal( PVIDEO_OUTPUT_MTT MediaTransportOutDesc ) { //@@DisplayVCMediaTransOutputTerminal -Video Control Media Transport Output Terminal UCHAR p = 0; PUCHAR pData = NULL; AppendTextBuffer("===>Additional Media Transport Output Terminal Data\r\n"); AppendTextBuffer("bControlSize: 0x%02X\r\n", MediaTransportOutDesc->bControlSize); // point to bControlSize pData = & MediaTransportOutDesc->bControlSize; // Are there any controls? if (0 < * pData) { UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; AppendTextBuffer("bmControls : "); VDisplayBytes(pData + 1, *pData); // map the first control for ( ; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData + 1); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportControls, sizeof(slMediaTransportControls) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportCtrl bmControl value")); cMask = cMask << 1; } } // point to bTransportModeSize pData = pData + 2 ; // Are there any controls? if (0 < * pData) { UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; AppendTextBuffer("bmControls : "); VDisplayBytes(pData + 1, *pData); // map the first control for ( ; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData + 1); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes1, sizeof(slMediaTransportModes1) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } // Is there a second control? if (1 < * pData) { // map the second control for ( uBitIndex = 8, cMask = 1; uBitIndex < 16; uBitIndex++ ) { cCheckBit = cMask & *(pData + 2); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes2, sizeof(slMediaTransportModes2) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } } // Is there a third control? if (2 < * pData) { // map the third control for ( uBitIndex = 16, cMask = 1; uBitIndex < 24; uBitIndex++ ) { cCheckBit = cMask & *(pData + 3); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes3, sizeof(slMediaTransportModes3) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } } // Is there a fourth control? if (3 < * pData) { // map the fourth control for ( uBitIndex = 24, cMask = 1; uBitIndex < 32; uBitIndex++ ) { cCheckBit = cMask & *(pData + 4); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes4, sizeof(slMediaTransportModes4) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } } // Is there a fifth control? if (4 < * pData) { // map the fourth control for ( uBitIndex = 32, cMask = 1; uBitIndex < 40; uBitIndex++ ) { cCheckBit = cMask & *(pData + 5); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slMediaTransportModes5, sizeof(slMediaTransportModes5) / sizeof(STRINGLIST), cMask, "Invalid MediaTransportMode value")); cMask = cMask << 1; } } } // The size of a Media Transport Descriptor is // the size of the Descriptor plus // (bControlSize - 1) plus // IF bmControls & 1 THEN 1 (bTransportModeSize) plus // bTransportModeSize // p = sizeof(VIDEO_OUTPUT_MTT) + (MediaTransportOutDesc->bControlSize - 1); if (MediaTransportOutDesc->bmControls[0] & 1) p += 1 + (*pData); if (MediaTransportOutDesc->bLength != p) { //@@TestCase B5.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@Invalid Descriptor length AppendTextBuffer("*!*ERROR: Invalid descriptor bLength 0x%02X. "\ "Should be 0x%02X\r\n", MediaTransportOutDesc->bLength, p); OOPS(); } return TRUE; } //***************************************************************************** // // DisplayVCCameraTerminal() // //***************************************************************************** BOOL DisplayVCCameraTerminal( PVIDEO_CAMERA_TERMINAL CameraDesc ) { //@@DisplayVCCameraTerminal -Video Control Camera Terminal UCHAR p = 0; PUCHAR pData = NULL; AppendTextBuffer("===>Camera Input Terminal Data\r\n"); AppendTextBuffer("wObjectiveFocalLengthMin: 0x%04X\r\n", CameraDesc->wObjectiveFocalLengthMin); AppendTextBuffer("wObjectiveFocalLengthMax: 0x%04X\r\n", CameraDesc->wObjectiveFocalLengthMax); AppendTextBuffer("wOcularFocalLength: 0x%04X\r\n", CameraDesc->wOcularFocalLength); AppendTextBuffer("bControlSize: 0x%02X\r\n", CameraDesc->bControlSize); pData = &CameraDesc->bControlSize; // Are there any controls? if (0 < * pData) { UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; AppendTextBuffer("bmControls : "); VDisplayBytes(pData + 1, *pData); // map the first control for ( ; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData + 1); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slCameraControl1, sizeof(slCameraControl1) / sizeof(STRINGLIST), cMask, "Invalid CamCtrl bmControl value")); cMask = cMask << 1; } // Is there a second control? if (1 < * pData) { // map the second control for ( uBitIndex = 8, cMask = 1; uBitIndex < 16; uBitIndex++ ) { cCheckBit = cMask & *(pData + 2); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slCameraControl2, sizeof(slCameraControl2) / sizeof(STRINGLIST), cMask, "Invalid CamCtrl bmControl value")); cMask = cMask << 1; } } // Is there a third control? if (2 < * pData) { // map the third control for ( uBitIndex = 16, cMask = 1; uBitIndex < 24; uBitIndex++ ) { cCheckBit = cMask & *(pData + 3); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slCameraControl3, sizeof(slCameraControl3) / sizeof(STRINGLIST), cMask, "Invalid CamCtrl bmControl value")); cMask = cMask << 1; } } } p = (sizeof(VIDEO_CAMERA_TERMINAL) + CameraDesc->bControlSize); if (CameraDesc->bLength != p) { //@@TestCase B7.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The descriptor should be the size of the descriptor structure //@@ plus the number of controls AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", CameraDesc->bLength, p); OOPS(); } //@@TestCase B7.2 //@@Not yet implemented - Priority 3 //@@Descriptor Field - wObjectiveFocalLengthMin //@@Question - Should we do any checking here? What are the acceptable boundaries? //@@Question - Is zero an acceptable value? // AppendTextBuffer("wObjectiveFocalLengthMin: 0x%04X\r\n", CameraDesc->wObjectiveFocalLengthMin); //@@TestCase B7.3 //@@Not yet implemented - Priority 3 //@@Descriptor Field - wObjectiveFocalLengthMax //@@Question - Should we do any checking here? What are the acceptable boundaries //@@Question - Is zero an acceptable value? // AppendTextBuffer("wObjectiveFocalLengthMax: 0x%04X\r\n", CameraDesc->wObjectiveFocalLengthMax); //@@TestCase B7.4 //@@Not yet implemented - Priority 3 //@@Descriptor Field - wOcularFocalLength //@@Question - Should we do any checking here? What are the acceptable boundaries //@@Question - Is zero an acceptable value? // AppendTextBuffer("wOcularFocalLength: 0x%04X\r\n", CameraDesc->wOcularFocalLength); //@@TestCase B7.5 //@@ERROR //@@Descriptor Field - wObjectiveFocalLengthMin and wObjectiveFocalLengthMax //@@Verify that wObjectiveFocalLengthMax is greater than wObjectiveFocalLengthMin if(CameraDesc->wObjectiveFocalLengthMin > CameraDesc->wObjectiveFocalLengthMax) { AppendTextBuffer("*!*ERROR: wObjectiveFocalLengthMin is larger than wObjectiveFocalLengthMax\r\n"); OOPS(); } //@@TestCase B7.6 //@@ERROR //@@Descriptor Field - bControlSize //@@Verify that wObjectiveFocalLengthMax is 3 or less if(CameraDesc->bControlSize > 3) { AppendTextBuffer("*!*ERROR: bControlSize must be 3 or less\r\n"); OOPS(); } return TRUE; } //***************************************************************************** // // DisplayVCSelectorUnit() // //***************************************************************************** BOOL DisplayVCSelectorUnit ( PVIDEO_SELECTOR_UNIT VidSelectorDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { //@@DisplayVCSelectorUnit -Video Control Selector Unit UCHAR i = 0; UCHAR p = 0; PUCHAR pData = NULL; AppendTextBuffer("\r\n ===>Video Control Selector Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VidSelectorDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VidSelectorDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VidSelectorDesc->bDescriptorSubtype); AppendTextBuffer("bUnitID: 0x%02X\r\n", VidSelectorDesc->bUnitID); AppendTextBuffer("bNrInPins: 0x%02X\r\n", VidSelectorDesc->bNrInPins); if (gDoAnnotation) { AppendTextBuffer("===>List of Connected Unit and Terminal ID's\r\n"); } // baSourceID is a variable length field // Size is in bNrInPins, must be at least 1 (so index starts at 1) for (i = 1, pData = (PUCHAR) &VidSelectorDesc->baSourceID; i <= VidSelectorDesc->bNrInPins; i++, pData++) { AppendTextBuffer("baSourceID[%d]: 0x%02X\r\n", i, *pData); } // get address of iSelector, the last field in this descriptor pData = (PUCHAR) VidSelectorDesc + (VidSelectorDesc->bLength - 1); AppendTextBuffer("iSelector: 0x%02X\r\n", *pData); if (gDoAnnotation) { if (*pData) { // if executing this code, the configuration descriptor has been // obtained. If a device is suspended, then its configuration // descriptor was not obtained and we do not want errors to be // displayed when string descriptors were not obtained. DisplayStringDescriptor(*pData, StringDescs, LatestDevicePowerState); } } p = (sizeof(VIDEO_SELECTOR_UNIT) + VidSelectorDesc->bNrInPins + 1); if (VidSelectorDesc->bLength != p) { //@@TestCase B8.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The descriptor should be the size of the descriptor structure plus the number of pins AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", VidSelectorDesc->bLength, p); OOPS(); } if (VidSelectorDesc->bUnitID < 1) { //@@TestCase B8.2 (Descript.c Line 396) //@@ERROR //@@Descriptor Field - bUnitID //@@bUnitID must be greater than 0 //@@Question: Should we test to verify unit number is unique? AppendTextBuffer("*!*ERROR: bUnitID must be non-zero\r\n"); OOPS(); } if (VidSelectorDesc->bNrInPins < 1) { //@@TestCase B8.3 //@@ERROR //@@Descriptor Field - bNrInPins //@@bNrInPins should be greater than 0 //@@Question: Should test to verify total in pins is valid AppendTextBuffer("*!*ERROR: bNrInPins must be non-zero\r\n"); OOPS(); } // baSourceID is a variable length field // Size is in bNrInPins, must be at least 1 (so index starts at 1) for (i = 1, pData = (PUCHAR) &VidSelectorDesc->baSourceID; i <= VidSelectorDesc->bNrInPins; i++, pData++) { if (*pData < 1) { //@@TestCase B8.4 //@@ERROR //@@Descriptor Field - baSourceID[] //@@baSourceID should be greater than 0 AppendTextBuffer("*!*ERROR: baSourceID[%d] must be non-zero\r\n", i); OOPS(); } else { if (! ValidateTerminalID(*pData)) { //@@TestCase B8.5 //@@ERROR //@@Descriptor Field - baSourceID[] //@@baSourceID should be a valid terminal ID AppendTextBuffer("*!*ERROR: baSourceID[%d] must be non-zero\r\n", i); OOPS(); } } } return TRUE; } //***************************************************************************** // // DisplayVCProcessingUnit() // //***************************************************************************** BOOL DisplayVCProcessingUnit ( PVIDEO_PROCESSING_UNIT VidProcessingDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { //@@DisplayVCProcessingUnit -Video Control Processor Unit PUCHAR pData = NULL; UCHAR bLength = 0; AppendTextBuffer("\r\n ===>Video Control Processing Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VidProcessingDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VidProcessingDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VidProcessingDesc->bDescriptorSubtype); AppendTextBuffer("bUnitID: 0x%02X\r\n", VidProcessingDesc->bUnitID); AppendTextBuffer("bSourceID: 0x%02X\r\n", VidProcessingDesc->bSourceID); AppendTextBuffer("wMaxMultiplier: 0x%04X\r\n", VidProcessingDesc->wMaxMultiplier); AppendTextBuffer("bControlSize: 0x%02X\r\n", VidProcessingDesc->bControlSize); pData = &VidProcessingDesc->bControlSize; // Are there any controls? if (0 < * pData) { UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; AppendTextBuffer("bmControls : "); VDisplayBytes(pData + 1, *pData); // map the first control for ( ; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData + 1); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slProcessorControls1, sizeof(slProcessorControls1) / sizeof(STRINGLIST), cMask, "Invalid PU bmControl value")); cMask = cMask << 1; } // Is there a second control? if (1 < * pData) { // map the second control for ( uBitIndex = 8, cMask = 1; uBitIndex < 16; uBitIndex++ ) { cCheckBit = cMask & *(pData + 2); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slProcessorControls2, sizeof(slProcessorControls2) / sizeof(STRINGLIST), cMask, "Invalid PU bmControl value")); cMask = cMask << 1; } } // Is there a third control? if (2 < * pData) { // map the third control for ( uBitIndex = 16, cMask = 1; uBitIndex < 24; uBitIndex++ ) { cCheckBit = cMask & *(pData + 3); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slProcessorControls3, sizeof(slProcessorControls3) / sizeof(STRINGLIST), cMask, "Invalid PU bmControl value")); cMask = cMask << 1; } } } // get address of iProcessing if (UVC10 != g_chUVCversion) { // size of descriptor is struct size plus control size plus 2 if UVC11 bLength = sizeof(VIDEO_PROCESSING_UNIT) + 2 + VidProcessingDesc->bControlSize; pData = (PUCHAR) VidProcessingDesc + (VidProcessingDesc->bLength - 2); } else // UVC 1.0 { // size of descriptor is struct size plus control size plus 1 if UVC10 bLength = sizeof(VIDEO_PROCESSING_UNIT) + 1 + VidProcessingDesc->bControlSize; pData = (PUCHAR) VidProcessingDesc + (VidProcessingDesc->bLength - 1); } AppendTextBuffer("iProcessing : 0x%02X\r\n", *pData); if (gDoAnnotation) { if (*pData) { // if executing this code, the configuration descriptor has been // obtained. If a device is suspended, then its configuration // descriptor was not obtained and we do not want errors to be // displayed when string descriptors were not obtained. DisplayStringDescriptor(*pData, StringDescs, LatestDevicePowerState); } } // check for new UVC 1.1 bmVideoStandards fields if (UVC10 != g_chUVCversion) { UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; pData = (PUCHAR) VidProcessingDesc + (VidProcessingDesc->bLength - 1); AppendTextBuffer("bmVideoStandards : "); VDisplayBytes(pData, 1); // map the first control for ( ; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slProcessorVideoStandards, sizeof(slProcessorVideoStandards) / sizeof(STRINGLIST), cMask, "Invalid PU bmVideoStandards value")); cMask = cMask << 1; } } if (VidProcessingDesc->bLength != bLength) { //@@TestCase B9.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength AppendTextBuffer("*!*ERROR: bLength of 0x%02X incorrect, should be 0x%02X\r\n", VidProcessingDesc->bLength, bLength); OOPS(); } if (VidProcessingDesc->bUnitID < 1) { //@@TestCase B9.2 (Descript.c Line 466) //@@ERROR //@@Descriptor Field - bUnitID //@@bUnitID must be greater than 0 //@@Question: Should we test to verify unit number is unique? AppendTextBuffer("*!*ERROR: bUnitID must be non-zero\r\n"); OOPS(); } if (VidProcessingDesc->bSourceID < 1) { //@@TestCase B9.3 (Descript.c Line 471) //@@ERROR //@@Descriptor Field - bSourceID //@@bSourceID must be non-zero //@@Question: Should we test to verify the bSourceID is valid? AppendTextBuffer("*!*ERROR: bSourceID must be non-zero\r\n"); OOPS(); } //@@TestCase B9.4 //@@Not yet implemented - Priority 1 //@@Descriptor Field - wMaxMultiplier //@@We should test to verify multiplier is valid // AppendTextBuffer("wMaxMultiplier: 0x%04X\r\n", VidProcessingDesc->wMaxMultiplier); return TRUE; } //***************************************************************************** // // DisplayVCExtensionUnit() // //***************************************************************************** BOOL DisplayVCExtensionUnit ( PVIDEO_EXTENSION_UNIT VidExtensionDesc, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ) { //@@DisplayVCExtensionUnit -Video Control Extension Unit int i = 0; UCHAR p = 0; UCHAR bControlSize = 0; PUCHAR pData = NULL; OLECHAR szGUID[256]; size_t bLength = 0; bLength = SizeOfVideoExtensionUnit(VidExtensionDesc); memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256); i = StringFromGUID2((REFGUID) &VidExtensionDesc->guidExtensionCode, (LPOLESTR) szGUID, 255); i++; AppendTextBuffer("\r\n ===>Video Control Extension Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VidExtensionDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VidExtensionDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VidExtensionDesc->bDescriptorSubtype); AppendTextBuffer("bUnitID: 0x%02X\r\n", VidExtensionDesc->bUnitID); AppendTextBuffer("guidExtensionCode: %S\r\n", szGUID); AppendTextBuffer("bNumControls: 0x%02X\r\n", VidExtensionDesc->bNumControls); AppendTextBuffer("bNrInPins: 0x%02X\r\n", VidExtensionDesc->bNrInPins); if (gDoAnnotation) { AppendTextBuffer("===>List of Connected Units and Terminal ID's\r\n"); } // baSourceID is a variable length field // Size is in bNrInPins, must be at least 1 (so index starts at 1) for (i = 1, pData = (PUCHAR) &VidExtensionDesc->baSourceID; i <= VidExtensionDesc->bNrInPins; i++, pData++) { AppendTextBuffer("baSourceID[%d]: 0x%02X\r\n", i, *pData); } // point to bControlSize (address of bNrInPins plus number of fields in bNrInPins // plus 1 for next field) pData = &VidExtensionDesc->bNrInPins + VidExtensionDesc->bNrInPins +1; bControlSize = *pData; AppendTextBuffer("bControlSize: 0x%02X\r\n", bControlSize); // Are there any controls? if ( bControlSize > 0) { AppendTextBuffer("bmControls : "); VDisplayBytes(pData + 1, *pData); // Map one byte at a time of the bmControls field in the Video Control Extension Unit Descriptor for (i = 1; i <= bControlSize; i++) { UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; // map byte for ( ; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData + i); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex + 8 * (i-1), cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", "Vendor-Specific (Optional)"); cMask = cMask << 1; } } } // get address of iExtension pData = &VidExtensionDesc->bNrInPins + VidExtensionDesc->bNrInPins + bControlSize + 2; // pData = (PUCHAR) VidExtensionDesc + (VidExtensionDesc->bLength - 1); AppendTextBuffer("iExtension: 0x%02X\r\n", *pData); if (gDoAnnotation) { if (*pData) { DisplayStringDescriptor(*pData,StringDescs, LatestDevicePowerState); } } // size of descriptor struct size (23) + bNrInPins + bControlSize + iExtension size // // p = (sizeof(VIDEO_EXTENSION_UNIT) // + VidExtensionDesc->bNrInPins + bControlSize + 1); if (VidExtensionDesc->bLength != bLength) { //@@TestCase B10.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the //@@ required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of 0x%02X incorrect, should be 0x%02X\r\n", VidExtensionDesc->bLength, p); OOPS(); } if (VidExtensionDesc->bUnitID < 1) { //@@TestCase B10.2 (Descript.c Line 517) //@@ERROR //@@Descriptor Field - bUnitID //@@bUnitID must be non-zero //@@Question: Should we test to verify bUnitID is valid AppendTextBuffer("*!*ERROR: bUnitID must be non-zero\r\n"); OOPS(); } //bugbug do we need two if (VidExtensionDesc->bNrInPins < 1) { //@@TestCase B10.3 (Descript.c Line 522) //@@ERROR //@@Descriptor Field - bNrInPins //@@bNrInPins must be non-zero //@@Question: Should we test to verify bNrInPins is valid AppendTextBuffer("*!*ERROR: bNrInPins must be non-zero\r\n"); OOPS(); } for (i = 1, pData = (PUCHAR) &VidExtensionDesc->baSourceID; i <= VidExtensionDesc->bNrInPins; i++, pData++) { if (*pData == 0) { //@@TestCase B10.4 (Descript.c Line 527) //@@ERROR //@@Descriptor Field - baSourceID[] //@@baSourceID[] must be non-zero //@@Question: Should we test to verify baSourceID is valid AppendTextBuffer("*!*ERROR: baSourceID[%d] must be non-zero\r\n", *pData); OOPS(); } } return TRUE; } //***************************************************************************** // // DisplayVidInHeaderl() // //***************************************************************************** BOOL DisplayVidInHeader ( PVIDEO_STREAMING_INPUT_HEADER VidInHeaderDesc ) { //@@DisplayVidInHeader -Video Streaming Video Input Header UINT p = 0; UINT uCount = 0; PUCHAR pData = NULL; AppendTextBuffer("\r\n ===>Video Class-Specific VS Video Input Header Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VidInHeaderDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VidInHeaderDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VidInHeaderDesc->bDescriptorSubtype); AppendTextBuffer("bNumFormats: 0x%02X\r\n", VidInHeaderDesc->bNumFormats); AppendTextBuffer("wTotalLength: 0x%04X", VidInHeaderDesc->wTotalLength); uCount = GetVSInterfaceSize((PUSB_COMMON_DESCRIPTOR) VidInHeaderDesc, VidInHeaderDesc->wTotalLength); if (uCount != VidInHeaderDesc->wTotalLength) { AppendTextBuffer("\r\n*!*ERROR: invalid interface size 0x%02X, should be 0x%02X\r\n", VidInHeaderDesc->wTotalLength, uCount); } else { AppendTextBuffer(" -> Validated\r\n"); } AppendTextBuffer("bEndpointAddress: 0x%02X", VidInHeaderDesc->bEndpointAddress); if (USB_ENDPOINT_DIRECTION_IN(VidInHeaderDesc->bEndpointAddress)) { if (gDoAnnotation) { AppendTextBuffer(" -> Direction: IN - EndpointID: %d", (VidInHeaderDesc->bEndpointAddress & 0x0F)); } AppendTextBuffer("\r\n"); } AppendTextBuffer("bmInfo: 0x%02X", VidInHeaderDesc->bmInfo); if (gDoAnnotation) { AppendTextBuffer(" -> Dynamic Format Change %sSupported", ! (VidInHeaderDesc->bmInfo & 0x01) ? "not " : " "); } AppendTextBuffer("\r\nbTerminalLink: 0x%02X\r\n", VidInHeaderDesc->bTerminalLink); AppendTextBuffer("bStillCaptureMethod: 0x%02X", VidInHeaderDesc->bStillCaptureMethod); // globally save the StillMethod, then verify value StillMethod = VidInHeaderDesc->bStillCaptureMethod; if (StillMethod > 3) { //@@TestCase B11.1 (Descript.c Line 798) //@@ERROR //@@Descriptor Field - bStillCaptureMethod //@@bStillCaptureMethod is greater than 3 AppendTextBuffer("*!*ERROR: invalid bStillCaptureMethod 0x%02X\r\n", VidInHeaderDesc->bStillCaptureMethod); if (gDoAnnotation) { AppendTextBuffer(" -> Invalid Still Capture Method"); } } else { if (0 == StillMethod) { AppendTextBuffer(" -> No Still Capture"); } else { AppendTextBuffer(" -> Still Capture Method %d", VidInHeaderDesc->bStillCaptureMethod); } } AppendTextBuffer("\r\nbTriggerSupport: 0x%02X", VidInHeaderDesc->bTriggerSupport); if(gDoAnnotation) { AppendTextBuffer(" -> "); if (! VidInHeaderDesc->bTriggerSupport) AppendTextBuffer("No "); AppendTextBuffer("Hardware Triggering Support"); } AppendTextBuffer("\r\n"); AppendTextBuffer("bTriggerUsage: 0x%02X", VidInHeaderDesc->bTriggerUsage); if (gDoAnnotation) { if (VidInHeaderDesc->bTriggerSupport != 0) { if (VidInHeaderDesc->bTriggerUsage == 0) AppendTextBuffer(" -> Host will initiate still image capture"); if (VidInHeaderDesc->bTriggerUsage == 1) AppendTextBuffer(" -> Host will notify client application of button event"); } } AppendTextBuffer("\r\nbControlSize: 0x%02X\r\n", VidInHeaderDesc->bControlSize); // are there formats to display? if (VidInHeaderDesc->bNumFormats) { UINT uFormatIndex = 1; UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; // There are (bNumFormats) bmaControls fields, each with size (bControlSize) pData = (PUCHAR) &(VidInHeaderDesc->bControlSize); // VidInHeaderDesc->bNumFormats -> number of formats // VidInHeaderDesc->bControlSize -> size of EACH format control // ((PUCHAR) &VidInHeaderDesc->bControlSize) + 1 -> address of first format control for ( pData++ ; uFormatIndex <= VidInHeaderDesc->bNumFormats; uFormatIndex++ ) { AppendTextBuffer("Video Payload Format %d ", uFormatIndex); // Handle case of 0 control size if (! VidInHeaderDesc->bControlSize) { AppendTextBuffer("0x00\r\n"); } else { VDisplayBytes(pData, VidInHeaderDesc->bControlSize); // map the first control for (uBitIndex = 0, cMask = 1; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pData); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slInputHeaderControls, sizeof(slInputHeaderControls) / sizeof(STRINGLIST), cMask, "Invalid Control value")); cMask = cMask << 1; } } pData += VidInHeaderDesc->bControlSize; } } p = (sizeof(VIDEO_STREAMING_INPUT_HEADER) + (VidInHeaderDesc->bNumFormats * VidInHeaderDesc->bControlSize)); if (VidInHeaderDesc->bLength != p) { //@@TestCase B11.2 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The descriptor should be the size of the descriptor structure //@@ plus the number of formats times the size of each format AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", VidInHeaderDesc->bLength, p); OOPS(); } if (VidInHeaderDesc->bNumFormats < 1) { //@@TestCase B11.3 (Descript.c Line778) //@@ERROR //@@Descriptor Field - bNumFormats //@@bNumFormats must be non-zero //@@Question: Should we test to verify the non-zero value for bNumFormats is valid AppendTextBuffer("*!*ERROR: bNumFormats must be non-zero\r\n", VidInHeaderDesc->bNumFormats); OOPS(); } if (VidInHeaderDesc->bEndpointAddress < 1) { //@@TestCase B11.4 (Descript.c Line788) //@@ERROR //@@Descriptor Field - bEndpointAddress //@@bEndpointAddress should be greater than 0 //@@Question: Should we test to verify the non-zero value for bEndpointAddress is valid AppendTextBuffer("*!*ERROR: bEndpointAddress of %d is too small\r\n", VidInHeaderDesc->bEndpointAddress); OOPS(); } //@@TestCase B11.5 //@@ERROR //@@Descriptor Field - bEndPointAddress //@@The bEndPointAddress is set incorrectly according to the USB Video Device Specification if (!USB_ENDPOINT_DIRECTION_IN(VidInHeaderDesc->bEndpointAddress)){ AppendTextBuffer("\r\n*!*ERROR: bEndPointAddress needs to have the Direction IN for this header\r\n"); OOPS();} //@@TestCase B11.6 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bmInfo //@@We should validate that reserved bits are set to zero. // AppendTextBuffer("bmInfo: 0x%02X", VidInHeaderDesc->bmInfo); if (VidInHeaderDesc->bTerminalLink < 1) { //@@TestCase B11.7 (Descript.c Line 793) //@@ERROR //@@Descriptor Field - bTerminalLink //@@bTerminalLink should be greater than 0 //@@Question: Should we test to verify the non-zero value for bTerminalLink is valid AppendTextBuffer("*!*ERROR: bTerminalLink of %d is too small\r\n", VidInHeaderDesc->bTerminalLink); OOPS(); } //@@TestCase B11.8 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bTriggerSupport //@@We should validate that reserved bits are set to zero. // AppendTextBuffer("bTriggerSupport: 0x%02X", VidInHeaderDesc->bTriggerSupport); //@@TestCase B11.9 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bTriggerUsage //@@We should validate that reserved bits are set to zero. // AppendTextBuffer("bTriggerUsage: 0x%02X", VidInHeaderDesc->bTriggerUsage); return TRUE; } //***************************************************************************** // // DisplayVidOutHeader() // //***************************************************************************** BOOL DisplayVidOutHeader ( PVIDEO_STREAMING_OUTPUT_HEADER VidOutHeaderDesc ) { //@@DisplayVidOutHeader -Video Streaming Video Output Header UINT uCount = 0; UCHAR bLength = sizeof(VIDEO_STREAMING_OUTPUT_HEADER); AppendTextBuffer("\r\n ===>Video Class-Specific VS Video Output Header Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VidOutHeaderDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VidOutHeaderDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VidOutHeaderDesc->bDescriptorSubtype); AppendTextBuffer("bNumFormats: 0x%02X\r\n", VidOutHeaderDesc->bNumFormats); AppendTextBuffer("wTotalLength: 0x%04X", VidOutHeaderDesc->wTotalLength); uCount = GetVSInterfaceSize((PUSB_COMMON_DESCRIPTOR) VidOutHeaderDesc, VidOutHeaderDesc->wTotalLength); if (uCount != VidOutHeaderDesc->wTotalLength) { AppendTextBuffer("\r\n*!*ERROR: invalid interface size 0x%02X, should be 0x%02X\r\n", VidOutHeaderDesc->wTotalLength, uCount); } else { AppendTextBuffer(" -> Validated\r\n"); } AppendTextBuffer("bEndpointAddress: 0x%02X", VidOutHeaderDesc->bEndpointAddress); if(USB_ENDPOINT_DIRECTION_OUT(VidOutHeaderDesc->bEndpointAddress)) { if (gDoAnnotation) { AppendTextBuffer(" -> Direction: OUT - EndpointID: %d", (VidOutHeaderDesc->bEndpointAddress & 0x0F)); } AppendTextBuffer("\r\n"); } AppendTextBuffer("bTerminalLink: 0x%02X\r\n", VidOutHeaderDesc->bTerminalLink); // UVC11 Video Output Header has additional fields, larger size #ifdef H264_SUPPORT if (UVC10 != g_chUVCversion) #else if (UVC11 == g_chUVCversion) #endif { UCHAR bControlSize = 0; PUCHAR pControls = NULL; // bControlSize field is next after bTerminalLink pControls = &(VidOutHeaderDesc->bTerminalLink)+1; bControlSize = *(pControls); // point to first bmaControls pControls++; // Size of UVC 1.1 Video Output Header is 1.0 size // plus 1 (bControlSize field) plus (number of formats * bControlSize) bLength += 1 + (VidOutHeaderDesc->bNumFormats * bControlSize); // Need new uvcdesc.h to handle new fields AppendTextBuffer("bControlSize: 0x%02X\r\n", bControlSize); // are there formats to display? if (VidOutHeaderDesc->bNumFormats) { UINT uFormatIndex = 1; UINT uBitIndex = 0; BYTE cCheckBit = 0; BYTE cMask = 1; // There are (bNumFormats) bmaControls fields, each with size (bControlSize) for ( ; uFormatIndex <= VidOutHeaderDesc->bNumFormats; uFormatIndex++, pControls ++) { AppendTextBuffer("Video Payload Format %d ", uFormatIndex); // Handle case of 0 control size if (0 == bControlSize) { AppendTextBuffer("0x00\r\n"); } else { VDisplayBytes(pControls, bControlSize); // map the first control for (uBitIndex = 0, cMask = 1; uBitIndex < 8; uBitIndex++ ) { cCheckBit = cMask & *(pControls); AppendTextBuffer(" D%02d = %d %s %s\r\n", uBitIndex, cCheckBit ? 1 : 0, cCheckBit ? "yes - " : " no - ", GetStringFromList(slOutputHeaderControls, sizeof(slOutputHeaderControls) / sizeof(STRINGLIST), cMask, "Invalid control value")); cMask = cMask << 1; } } } // for ( pData++ ; uFormatIndex <= VidOutHeaderDesc->bNumFormats; uFormatIndex++ ) } // if (VidOutHeaderDesc->bNumFormats) } // if (UVC11 == g_chUVCversion) if (VidOutHeaderDesc->bLength != bLength) { //@@TestCase B12.1 (also in Descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the //@@ required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", VidOutHeaderDesc->bLength, sizeof(VIDEO_STREAMING_OUTPUT_HEADER)); OOPS(); } if (VidOutHeaderDesc->bNumFormats < 1) { //@@TestCase B12.2 (Descript.c Line 827) //@@ERROR //@@Descriptor Field - bNumFormats //@@bNumFormats should be greater than 0 //@@Question: Should we test to verify the non-zero value for bNumFormats is valid AppendTextBuffer("*!*ERROR: bNumFormats of %d is too small\r\n", VidOutHeaderDesc->bNumFormats); OOPS(); } if (VidOutHeaderDesc->wTotalLength < VidOutHeaderDesc->bLength) { //@@TestCase B12.3 (Descript.c Line 832) //@@ERROR //@@Descriptor Field - wTotalLength //@@wTotalLength should be greater than bLength //@@Question: Should we calculate wTotalLength to verify the value is valid AppendTextBuffer("*!*ERROR: wTotalLength of %d is small than the bLength of %d\r\n", VidOutHeaderDesc->wTotalLength, VidOutHeaderDesc->bLength); OOPS(); } if (VidOutHeaderDesc->bEndpointAddress < 1) { //@@TestCase B12.4 (Descript.c Line 837) //@@ERROR //@@Descriptor Field - bEndpointAddress //@@bEndpointAddress should be greater than 0 //@@Question: Should we test to verify the non-zero value for bEndpointAddress is valid AppendTextBuffer("*!*ERROR: bEndpointAddress of %d is too small\r\n", VidOutHeaderDesc->bEndpointAddress); OOPS(); } if(!(USB_ENDPOINT_DIRECTION_OUT(VidOutHeaderDesc->bEndpointAddress))) { //@@TestCase B12.5 //@@ERROR //@@Descriptor Field - bEndPointAddress //@@The bEndPointAddress is set for the wrong direction AppendTextBuffer("\r\n*!*ERROR: bEndPointAddress needs to have the Direction OUT for this header\r\n"); OOPS();} if (VidOutHeaderDesc->bTerminalLink < 1) { //@@TestCase B12.6 (Descript.c Line 842) //@@ERROR //@@Descriptor Field - bTerminalLink //@@bTerminalLink should be greater than 0 //@@Question: Should we test to verify the non-zero value for bTerminalLink is valid AppendTextBuffer("*!*ERROR: bTerminalLink of %d is too small\r\n", VidOutHeaderDesc->bTerminalLink); OOPS(); } return TRUE; } //***************************************************************************** // // DisplayStillImageFrame() // //***************************************************************************** BOOL DisplayStillImageFrame ( PVIDEO_STILL_IMAGE_FRAME StillFrameDesc ) { //@@DisplayStillImageFrame -Still Image Frame VIDEO_STILL_IMAGE_RECT * pXY; PUCHAR pbCurr = NULL; UINT i = 0; UINT uNumComp = 0; UINT uSize = 0; size_t bLength = 0; bLength = SizeOfVideoStillImageFrame(StillFrameDesc); AppendTextBuffer("\r\n ===>Still Image Frame Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", StillFrameDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", StillFrameDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", StillFrameDesc->bDescriptorSubtype); AppendTextBuffer("bEndpointAddress: 0x%02X\r\n", StillFrameDesc->bEndpointAddress); AppendTextBuffer("bNumImageSizePatterns: 0x%02X\r\n", StillFrameDesc->bNumImageSizePatterns); if (StillFrameDesc->bNumImageSizePatterns < 1) { //@@TestCase B13.1 (also Descript.c Line 886) //@@Not yet implemented - Priority 1 //@@Descriptor Field - bNumImageSizePatterns //@@The bNumImageSizePatterns should be greater than 0 //@@Question: Should we test to verify the non-zero value for bNumImageSizePatterns is valid AppendTextBuffer("*!*ERROR: bNumImageSizePatterns must be non-zero\r\n"); OOPS(); } // point to first StillFrameDesc->dwStillImage structure pXY = (VIDEO_STILL_IMAGE_RECT *) &StillFrameDesc->aStillRect[0]; for (i = 1; i <= StillFrameDesc->bNumImageSizePatterns; i++, pXY++) { AppendTextBuffer("wWidth[%d]: 0x%04X\r\n", i, pXY->wWidth); AppendTextBuffer("wHeight[%d]: 0x%04X\r\n", i, pXY->wHeight); } // point to bNumCompressionPattern field (after variable count field dwStillImage) pbCurr = (PUCHAR) pXY; // get number of compression patterns uNumComp = *pbCurr; AppendTextBuffer("bNumCompressionPattern: 0x%02X\r\n", *pbCurr++); for (i = 1; i <= uNumComp; i++) { AppendTextBuffer("bCompression[%d]: 0x%02X\r\n", i, *pbCurr++); } switch(StillMethod) { case 0: //@@TestCase B13.2 //@@ERROR //@@Descriptor Field - Still Image Frame Type Descriptor //@@An still method type has been defined that shouldn't use a Still Image Frame AppendTextBuffer("*!*ERROR: VS Video Input Header set to "\ "No Still Method support\r\n"); OOPS(); case 1: //@@TestCase B13.3 //@@ERROR //@@Descriptor Field - Still Image Frame Type Descriptor //@@An still method type has been defined that shouldn't use a Still Image Frame AppendTextBuffer("*!*ERROR: VS Video Input Header set to "\ "Still Method One support with a Still Image Frame descriptor\r\n"); OOPS(); default: break;} if (StillFrameDesc->bLength != bLength) { //@@TestCase B13.4 (Also in descript.c) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is incorrect AppendTextBuffer("*!*ERROR: bLength 0x%02X incorrect, should be 0x%02X\r\n", StillFrameDesc->bLength, uSize); OOPS(); } //@@TestCase B13.5 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bEndpointAddress //@@Should test to verify endpoint validity // AppendTextBuffer("bEndpointAddress: 0x%02X", StillFrameDesc->bEndpointAddress); if(USB_ENDPOINT_DIRECTION_IN(StillFrameDesc->bEndpointAddress) && StillMethod==3){ if((StillFrameDesc->bEndpointAddress) == 0){ //@@TestCase B13.6 //@@ERROR //@@Descriptor Field - bEndPointAddress //@@bEndPointAddress should be non-zero for 0 when using StillMethod 3 AppendTextBuffer("\r\n*!*ERROR: bEndpointAddress is reported as %d. "\ "This should be non-zero when using StillMethod 3.\r\n", (StillFrameDesc->bEndpointAddress)); OOPS(); } if (gDoAnnotation) { AppendTextBuffer(" -> Direction: IN - EndpointID: %d", (StillFrameDesc->bEndpointAddress & 0x0F)); } AppendTextBuffer("\r\n"); } else if(USB_ENDPOINT_DIRECTION_OUT(StillFrameDesc->bEndpointAddress) && StillMethod==2) { if((StillFrameDesc->bEndpointAddress & 0x0F) != 0) { //@@TestCase B13.7 //@@ERROR //@@Descriptor Field - bEndPointAddress //@@The EndpointID of bEndPointAddress should be set for 0 when using StillMethod 2 AppendTextBuffer("\r\n*!*ERROR: The EndpointID of the "\ "bEndpointAddress is reported as %d. This should be 0.\r\n", (StillFrameDesc->bEndpointAddress & 0x0F)); OOPS(); } else {AppendTextBuffer("\r\n");}} else if (StillFrameDesc->bEndpointAddress != 0) { //@@TestCase B13.8 //@@ERROR //@@Descriptor Field - bEndPointAddress //@@The bEndPointAddress should be set for 0 when not using StillMethod 2 or 3 AppendTextBuffer("\r\n*!*ERROR: bEndPointAddress should be 0.\r\n"); OOPS(); } else {AppendTextBuffer("\r\n");} return TRUE; } //***************************************************************************** // // DisplayColorMatching() // //***************************************************************************** BOOL DisplayColorMatching ( PVIDEO_COLORFORMAT ColorMatchDesc ) { //@@DisplayColorMatching -Color Matching AppendTextBuffer("\r\n ===>Color Matching Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", ColorMatchDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", ColorMatchDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", ColorMatchDesc->bDescriptorSubtype); AppendTextBuffer("bColorPrimaries: 0x%02X\r\n", ColorMatchDesc->bColorPrimaries); AppendTextBuffer("bTransferCharacteristics: 0x%02X\r\n", ColorMatchDesc->bTransferCharacteristics); AppendTextBuffer("bMatrixCoefficients: 0x%02X\r\n", ColorMatchDesc->bMatrixCoefficients); if (ColorMatchDesc->bLength != sizeof(VIDEO_COLORFORMAT)) { //@@TestCase B14.1 (Descript.c Line 1596) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", ColorMatchDesc->bLength, sizeof(VIDEO_COLORFORMAT)); OOPS(); } //@@TestCase B14.2 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bColorPrimaries //@@Question - Should we test to verify bColorPrimaries // AppendTextBuffer("bColorPrimaries: 0x%02X\r\n", ColorMatchDesc->bColorPrimaries); //@@TestCase B14.3 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bTransferCharacteristics //@@Question - Should we test to verify bTransferCharacteristics // AppendTextBuffer("bTransferCharacteristics: 0x%02X\r\n", ColorMatchDesc->bTransferCharacteristics); //@@TestCase B14.4 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bMatrixCoefficients //@@Question - Should we test to verify bMatrixCoefficients // AppendTextBuffer("bMatrixCoefficients: 0x%02X\r\n", ColorMatchDesc->bMatrixCoefficients); return TRUE; } //***************************************************************************** // // DisplayUncompressedFormat() // //***************************************************************************** BOOL DisplayUncompressedFormat ( PVIDEO_FORMAT_UNCOMPRESSED UnCompFormatDesc ) { //@@DisplayUncompressedFormat - Uncompressed Format int i = 0; PCHAR pStr = NULL; OLECHAR szGUID[256]; // Initialize the default Frame g_chUNCFrameDefault = UnCompFormatDesc->bDefaultFrameIndex; memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256); i = StringFromGUID2((REFGUID) &UnCompFormatDesc->guidFormat, (LPOLESTR) szGUID, 255); i++; AppendTextBuffer("\r\n ===>Video Streaming Uncompressed Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", UnCompFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", UnCompFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", UnCompFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", UnCompFormatDesc->bFormatIndex); AppendTextBuffer("bNumFrameDescriptors: 0x%02X\r\n", UnCompFormatDesc->bNumFrameDescriptors); AppendTextBuffer("guidFormat: %S", szGUID); pStr = VidFormatGUIDCodeToName((REFGUID) &UnCompFormatDesc->guidFormat); if ( pStr ) { if ( gDoAnnotation ) { AppendTextBuffer(" = %s Format", pStr); } } AppendTextBuffer("\r\n"); AppendTextBuffer("bBitsPerPixel: 0x%02X\r\n", UnCompFormatDesc->bBitsPerPixel); AppendTextBuffer("bDefaultFrameIndex: 0x%02X\r\n", UnCompFormatDesc->bDefaultFrameIndex); if (UnCompFormatDesc->bLength != sizeof(VIDEO_FORMAT_UNCOMPRESSED)) { //@@TestCase B15.1 (descript.c line 925) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required //@@length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", UnCompFormatDesc->bLength, sizeof(VIDEO_FORMAT_UNCOMPRESSED)); OOPS(); } if (UnCompFormatDesc->bFormatIndex == 0 ) { //@@TestCase B15.2 (descript.c line 930) //@@ERROR //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bFormatIndex = 0, this is a 1 based index\r\n"); OOPS(); } if (UnCompFormatDesc->bNumFrameDescriptors == 0 ) { //@@TestCase B15.3 (descript.c line 930) //@@ERROR //@@Descriptor Field - bNumFrameDescriptors //@@bNumFrameDescriptors is set to zero which is not in accordance with the //@@USB Video Device Specification AppendTextBuffer("*!*ERROR: bNumFrameDescriptors = 0, must have at least 1 Frame descriptor\r\n"); OOPS(); } if(!(pStr)) { //@@TestCase B15.4 //@@WARNING //@@Descriptor Field - guidFormat //@@guidFormat is set to unknown or undefined format AppendTextBuffer("\r\n*!*WARNING: guidFormat is an unknown format\r\n"); OOPS(); } if (UnCompFormatDesc->bBitsPerPixel == 0 ) { //@@TestCase B15.5 (descript.c line 940) //@@ERROR //@@Descriptor Field - bBitsPerPixel //@@bBitsPerPixel is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bBitsPerPixel = 0, this invalidates the descriptor\r\n"); OOPS(); } if (UnCompFormatDesc->bDefaultFrameIndex == 0 || UnCompFormatDesc->bDefaultFrameIndex > UnCompFormatDesc->bNumFrameDescriptors) { //@@TestCase B15.6 (desctipt.c line 945) //@@ERROR //@@Descriptor Field - bDefaultFrameIndex //@@The value for bDefaultFrameIndex is not greater than 0 or less than or equal to bNumFrameDescriptors AppendTextBuffer("*!*ERROR: The value %d for the bDefaultFrameIndex is out of range, this invalidates the descriptor\r\n*!*The proper range is 1 to %d)", UnCompFormatDesc->bDefaultFrameIndex, UnCompFormatDesc->bNumFrameDescriptors); OOPS(); } AppendTextBuffer("bAspectRatioX: 0x%02X\r\n", UnCompFormatDesc->bAspectRatioX); AppendTextBuffer("bAspectRatioY: 0x%02X", UnCompFormatDesc->bAspectRatioY); if (((UnCompFormatDesc->bmInterlaceFlags & 0x01) && (UnCompFormatDesc->bAspectRatioY != 0 && UnCompFormatDesc->bAspectRatioX != 0))) { if(gDoAnnotation) { AppendTextBuffer(" -> Aspect Ratio is set for a %d:%d display", (UnCompFormatDesc->bAspectRatioX),(UnCompFormatDesc->bAspectRatioY)); } else { if (UnCompFormatDesc->bAspectRatioY != 0 || UnCompFormatDesc->bAspectRatioX != 0) { //@@TestCase B15.7 //@@ERROR //@@Descriptor Field - bAspectRatioX, bAspectRatioY //@@Verify that that bAspectRatioX and bAspectRatioY are set to zero //@@ if stream is non-interlaced AppendTextBuffer("\r\n*!*ERROR: Both bAspectRatioX and bAspectRatioY "\ "must equal 0 if stream is non-interlaced"); OOPS(); } } } AppendTextBuffer("\r\nbmInterlaceFlags: 0x%02X\r\n", UnCompFormatDesc->bmInterlaceFlags); if (gDoAnnotation) { AppendTextBuffer(" D0 = 0x%02X Interlaced stream or variable: %s\r\n", (UnCompFormatDesc->bmInterlaceFlags & 1), (UnCompFormatDesc->bmInterlaceFlags & 1) ? "Yes" : "No"); AppendTextBuffer(" D1 = 0x%02X Fields per frame: %s\r\n", ((UnCompFormatDesc->bmInterlaceFlags >> 1) & 1), ((UnCompFormatDesc->bmInterlaceFlags >> 1) & 1) ? "1 field" : "2 fields"); AppendTextBuffer(" D2 = 0x%02X Field 1 first: %s\r\n", ((UnCompFormatDesc->bmInterlaceFlags >> 2) & 1), ((UnCompFormatDesc->bmInterlaceFlags >> 2) & 1) ? "Yes" : "No"); //@@TestCase B15.9 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bmInterlaceFlags //@@Validate that reserved bits (D3) are set to zero. AppendTextBuffer(" D3 = 0x%02X Reserved%s\r\n", ((UnCompFormatDesc->bmInterlaceFlags >> 3) & 1), ((UnCompFormatDesc->bmInterlaceFlags >> 3) & 1) ? "\r\n*!*ERROR: Reserved to 0" : "" ); AppendTextBuffer(" D4..5 = 0x%02X Field patterns ->", ((UnCompFormatDesc->bmInterlaceFlags >> 4) & 3)); switch(UnCompFormatDesc->bmInterlaceFlags & 0x30) { case 0x00: AppendTextBuffer(" Field 1 only"); break; case 0x10: AppendTextBuffer(" Field 2 only"); break; case 0x20: AppendTextBuffer(" Regular Pattern of fields 1 and 2"); break; case 0x30: AppendTextBuffer(" Random Pattern of fields 1 and 2"); break; } AppendTextBuffer("\r\n D6..7 = 0x%02X Display Mode ->", ((UnCompFormatDesc->bmInterlaceFlags >> 6) & 3)); switch(UnCompFormatDesc->bmInterlaceFlags & 0xC0) { case 0x00: AppendTextBuffer(" Bob only"); break; case 0x40: AppendTextBuffer(" Weave only"); break; case 0x80: AppendTextBuffer(" Bob or weave"); break; case 0xC0: //@@TestCase B15.10 //@@Not yet implemented - Priority 3 //@@Descriptor Field - bmInterlaceFlags //@@Question - Should we validate that reserved bits are set to zero? AppendTextBuffer(" Reserved"); break; } } //@@TestCase B15.11 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bCopyProtect //@@Question - Are their reserved bits and should we validate that //@@ reserved bits are set to zero? AppendTextBuffer("\r\nbCopyProtect: 0x%02X", UnCompFormatDesc->bCopyProtect); if (gDoAnnotation) { if (UnCompFormatDesc->bCopyProtect) AppendTextBuffer(" -> Duplication Restricted"); else AppendTextBuffer(" -> Duplication Unrestricted"); } AppendTextBuffer("\r\n"); //@@TestCase B15.12 //@@We should check to make sure that a Color Matching Descriptor is included in the device // Check that the correct number of Frame Descriptors and one Color Matching // descriptor follow CheckForColorMatchingDesc ((PVIDEO_SPECIFIC) UnCompFormatDesc, UnCompFormatDesc->bNumFrameDescriptors, VS_FRAME_UNCOMPRESSED); return TRUE; } //***************************************************************************** // // DisplayUncompressedFrameType() // //***************************************************************************** BOOL DisplayUncompressedFrameType ( PVIDEO_FRAME_UNCOMPRESSED UnCompFrameDesc ) { size_t bLength = 0; bLength = SizeOfVideoFrameUncompressed(UnCompFrameDesc); //@@DisplayUncompressedFrameType -Uncompressed Frame AppendTextBuffer("\r\n ===>Video Streaming Uncompressed Frame Type Descriptor<===\r\n"); if (gDoAnnotation) { if(UnCompFrameDesc->bFrameIndex == g_chUNCFrameDefault) { AppendTextBuffer(" --->This is the Default (optimum) Frame index\r\n"); } } AppendTextBuffer("bLength: 0x%02X\r\n", UnCompFrameDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", UnCompFrameDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", UnCompFrameDesc->bDescriptorSubtype); AppendTextBuffer("bFrameIndex: 0x%02X\r\n", UnCompFrameDesc->bFrameIndex); AppendTextBuffer("bmCapabilities: 0x%02X\r\n", UnCompFrameDesc->bmCapabilities); AppendTextBuffer("wWidth: 0x%04X = %d\r\n", UnCompFrameDesc->wWidth, UnCompFrameDesc->wWidth); AppendTextBuffer("wHeight: 0x%04X = %d\r\n", UnCompFrameDesc->wHeight, UnCompFrameDesc->wHeight); AppendTextBuffer("dwMinBitRate: 0x%08X\r\n", UnCompFrameDesc->dwMinBitRate); AppendTextBuffer("dwMaxBitRate: 0x%08X\r\n", UnCompFrameDesc->dwMaxBitRate); AppendTextBuffer("dwMaxVideoFrameBufferSize: 0x%08X\r\n", UnCompFrameDesc->dwMaxVideoFrameBufferSize); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwDefaultFrameInterval: 0x%08X = %lf mSec (%4.2f Hz)\r\n", UnCompFrameDesc->dwDefaultFrameInterval, ((double)UnCompFrameDesc->dwDefaultFrameInterval)/10000.0, (10000000.0/((double)UnCompFrameDesc->dwDefaultFrameInterval)) ); AppendTextBuffer("bFrameIntervalType: 0x%02X\r\n", UnCompFrameDesc->bFrameIntervalType); if (UnCompFrameDesc->bLength != bLength) { //@@TestCase B15.1 (descript.c line 925) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required //@@length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", UnCompFrameDesc->bLength, bLength); OOPS(); } if (UnCompFrameDesc->bFrameIndex == 0 ) { //@@TestCase B16.2 (descript.c line 991) //@@ERROR //@@Descriptor Field - bFrameIndex //@@bFrameIndex must be nonzero AppendTextBuffer("*!*ERROR: bFrameIndex = 0, this is a 1 based index\r\n"); OOPS(); } //@@TestCase B16.3 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bmCapabilities //@@Question: Should we try to verify that bmCapabilities is valid? // AppendTextBuffer("bmCapabilities: 0x%02X\r\n", UnCompFrameDesc->bmCapabilities); if (UnCompFrameDesc->wWidth == 0 ) { //@@TestCase B16.4 (descript.c line 996) //@@ERROR //@@Descriptor Field - wWidth //@@wWidth must be nonzero AppendTextBuffer("*!*ERROR: wWidth must be nonzero\r\n"); OOPS(); } if (UnCompFrameDesc->wHeight == 0 ) { //@@TestCase B16.5 (descript.c line 1001) //@@ERROR //@@Descriptor Field - wHeight //@@wHeight must be nonzero AppendTextBuffer("*!*ERROR: wHeight must be nonzero\r\n"); OOPS(); } if (UnCompFrameDesc->dwMinBitRate == 0 ) { //@@TestCase B16.6 (descript.c line 1006) //@@ERROR //@@Descriptor Field - dwMinBitRate //@@dwMinBitRate must be nonzero AppendTextBuffer("*!*ERROR: dwMinBitRate must be nonzero\r\n"); OOPS(); } if (UnCompFrameDesc->dwMaxBitRate == 0 ) { //@@TestCase B16.7 (descript.c line 1011) //@@ERROR //@@Descriptor Field - dwMaxBitRate //@@dwMaxBitRate must be nonzero AppendTextBuffer("*!*ERROR: dwMaxBitRate must be nonzero\r\n"); OOPS(); } if(UnCompFrameDesc->dwMinBitRate > UnCompFrameDesc->dwMaxBitRate) { //@@TestCase B16.8 //@@ERROR //@@Descriptor Field - dwMinBitRate and dwMaxBitRate //@@Verify that dwMaxBitRate is greater than dwMinBitRate AppendTextBuffer("*!*ERROR: dwMinBitRate should be less than dwMaxBitRate\r\n"); OOPS(); } else { if (UnCompFrameDesc->bFrameIntervalType == 1 && UnCompFrameDesc->dwMinBitRate != UnCompFrameDesc->dwMaxBitRate) { //@@TestCase B16.9 //@@WARNING //@@Descriptor Field - bFrameIntervalType, dwMinBitRate, and dwMaxBitRate //@@Verify that dwMaxBitRate is equal to dwMinBitRate if bFrameIntervalType is 1 AppendTextBuffer("*!*WARNING: if bFrameIntervalType is 1 then dwMinBitRate "\ "should equal dwMaxBitRate\r\n"); OOPS(); } } if (UnCompFrameDesc->dwMaxVideoFrameBufferSize == 0 ) { //@@TestCase B16.10 (descript.c line 1015) //@@WARNING //@@Descriptor Field - bFrameIndex //@@bFrameIndex must be nonzero AppendTextBuffer("*!*WARNING: dwMaxVideoFrameBufferSize must be nonzero\r\n"); OOPS(); } if (UnCompFrameDesc->dwDefaultFrameInterval == 0 ) { //@@TestCase B16.11 (descript.c line 1020) //@@WARNING //@@Descriptor Field - dwDefaultFrameInterval //@@dwDefaultFrameInterval must be nonzero AppendTextBuffer("*!*WARNING: dwDefaultFrameInterval must be nonzero\r\n"); OOPS(); } if (0 == UnCompFrameDesc->bFrameIntervalType) { DisplayUnComContinuousFrameType(UnCompFrameDesc); } else { DisplayUnComDiscreteFrameType(UnCompFrameDesc); } return TRUE; } //***************************************************************************** // // DisplayUnComContinuousFrameType() // //***************************************************************************** BOOL DisplayUnComContinuousFrameType( PVIDEO_FRAME_UNCOMPRESSED UContinuousDesc ) { //@@DisplayUnComContinuousFrameType -Uncompressed Continuous Frame ULONG dwMinFrameInterval = UContinuousDesc->adwFrameInterval[0]; ULONG dwMaxFrameInterval = UContinuousDesc->adwFrameInterval[1]; ULONG dwFrameIntervalStep = UContinuousDesc->adwFrameInterval[2]; AppendTextBuffer("===>Additional Continuous Frame Type Data\r\n"); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwMinFrameInterval: 0x%08X = %lf mSec (%d Hz)\r\n", dwMinFrameInterval, ((double)dwMinFrameInterval)/10000.0, (ULONG)(10000000.0/((double)dwMinFrameInterval) + 0.5)); AppendTextBuffer("dwMaxFrameInterval: 0x%08X = %lf mSec (%d Hz)\r\n", dwMaxFrameInterval, ((double)dwMaxFrameInterval)/10000.0, (ULONG)(10000000.0/((double)dwMaxFrameInterval) + 0.5)); AppendTextBuffer("dwFrameIntervalStep: 0x%08X\r\n", dwFrameIntervalStep); if (dwMinFrameInterval == 0 ) { //@@TestCase B17.2 (descript.c line 1025) //@@ERROR //@@Descriptor Field - dwMinFrameInterval //@@dwMinFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMinFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if (dwMaxFrameInterval == 0 ) { //@@TestCase B17.3 (descript.c line 1025) //@@ERROR //@@Descriptor Field - dwMaxFrameInterval //@@dwMaxFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMaxFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if(dwMinFrameInterval > dwMaxFrameInterval) { //@@TestCase B17.4 (descript.c 1043) //@@ERROR //@@Descriptor Field - dwMinFrameInterval and dwMaxFrameInterval //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval AppendTextBuffer("*!*ERROR: dwMinFrameInterval is larger that dwMaxFrameInterval, this invalidates the descriptor\r\n"); OOPS(); } else if ((dwMinFrameInterval + dwFrameIntervalStep) > dwMaxFrameInterval) { //@@TestCase B17.5 //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval combined with dwFrameIntervalStep AppendTextBuffer("*!*WARNING: dwMinFrameInterval + dwFrameIntervalStep is greater than dwMaxFrameInterval, this could cause problems\r\n"); OOPS(); } else if ((dwMaxFrameInterval - dwMinFrameInterval) == 0 ) { //@@TestCase B17.6 //@@CAUTION //@@Descriptor Field - dwFrameIntervalStep //@@Suggestion to use descrite frames if dwFrameIntervalStep is zero AppendTextBuffer("*!*CAUTION: dwFrameIntervalStep equals zero, consider using discrete frames\r\n"); OOPS(); } else if ((dwMaxFrameInterval - dwMinFrameInterval) % dwFrameIntervalStep ) { //@@TestCase B17.7 (descript.c 1052) //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that the difference between dwMaxFrameInterval and dwMinFrameInterval is evenly divisible by dwFrameIntervalStep AppendTextBuffer("*!*WARNING: dwMaxFrameInterval minus dwMinFrameInterval is not evenly divisible by dwFrameIntervalStep, this could cause problems\r\n"); OOPS(); } if (dwFrameIntervalStep == 0 && (dwMaxFrameInterval - dwMinFrameInterval)) { //@@TestCase B17.8 (descript.c line 1032) //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that the dwFrameIntervalStep is not zero if there is a difference between dwMaxFrameInterval and dwMinFrameInterval AppendTextBuffer("*!*WARNING: dwFrameIntervalStep = 0, this invalidates the descriptor when there is a difference between dwMinFrameInterval and dwMaxFrameInterval\r\n"); OOPS(); } return TRUE; } //***************************************************************************** // // DisplayUnComDiscreteFrameType() // //***************************************************************************** BOOL DisplayUnComDiscreteFrameType( PVIDEO_FRAME_UNCOMPRESSED UDiscreteDesc ) { //@@DisplayUnComDiscreteFrameType -Uncompressed Discrete Frame UINT iNdex = 1; UINT iCurFrame = 0; ULONG * ulFrameInterval = NULL; AppendTextBuffer("===>Additional Discrete Frame Type Data\r\n"); // There are (UDiscreteDesc->bFrameIntervalType) dwFrameIntervals (1 based index) for (; iNdex <= UDiscreteDesc->bFrameIntervalType; iNdex++, iCurFrame++) { ulFrameInterval = &UDiscreteDesc->adwFrameInterval[iCurFrame]; // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwFrameInterval[%d]: 0x%08X = %lf mSec (%4.2f Hz)\r\n", iNdex, *ulFrameInterval, ((double)*ulFrameInterval)/10000.0, (10000000.0/((double)*ulFrameInterval)) ); if (0 == *ulFrameInterval) { //@@TestCase B18.1 (descript.c line 1061) //@@ERROR //@@Descriptor Field - dwFrameInterval[x] //@@dwFrameInterval[x] must be non-zero AppendTextBuffer("*!*ERROR: dwFrameInterval[%d] must be non-zero\r\n", iNdex); OOPS(); } if ((iNdex > 1)&&(*ulFrameInterval <= UDiscreteDesc->adwFrameInterval[iCurFrame - 1])) { //@@TestCase B18.2 (descript.c line 1067) //@@ERROR //@@Descriptor Field - dwFrameInterval[x] //@@dwFrameInterval[n] must be greater than dwFrameInterval[n - 1] AppendTextBuffer("*!*ERROR: dwFrameInterval[0x%02X] must be "\ "greater than preceding dwFrameInterval[0x%02X]\r\n", iNdex, iNdex - 1); OOPS(); } } return TRUE; } //***************************************************************************** // // DisplayMJPEGFormat() // //***************************************************************************** BOOL DisplayMJPEGFormat ( PVIDEO_FORMAT_MJPEG MJPEGFormatDesc ) { //@@DisplayMJPEGFormat - MJPEG Format // Initialize the default Frame g_chMJPEGFrameDefault = MJPEGFormatDesc->bDefaultFrameIndex; AppendTextBuffer("\r\n ===>Video Streaming MJPEG Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", MJPEGFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", MJPEGFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", MJPEGFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", MJPEGFormatDesc->bFormatIndex); AppendTextBuffer("bNumFrameDescriptors: 0x%02X\r\n", MJPEGFormatDesc->bNumFrameDescriptors); if (MJPEGFormatDesc->bLength != sizeof(VIDEO_FORMAT_MJPEG)) { //@@TestCase B19.1 (descript.c line 1098) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the //@@ required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", MJPEGFormatDesc->bLength, sizeof(VIDEO_FORMAT_MJPEG)); OOPS(); } if (MJPEGFormatDesc->bFormatIndex == 0 ) { //@@TestCase B19.2 (descript.c line 1103) //@@ERROR //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with //@@ the USB Video Device Specification AppendTextBuffer("*!*ERROR: bFormatIndex must be non-zero\r\n"); OOPS(); } if (MJPEGFormatDesc->bNumFrameDescriptors == 0 ) { //@@TestCase B19.3 (descript.c line 1108) //@@ERROR //@@Descriptor Field - bNumFrameDescriptors //@@bNumFrameDescriptors is set to zero which is not in accordance //@@ with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bNumFrameDescriptors must be non-zero\r\n"); OOPS(); } AppendTextBuffer("bmFlags: 0x%02X", (MJPEGFormatDesc->bmFlags & 0x01)); //@@TestCase B19.4 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bmFlags //@@We should validate that reserved bits are set to zero. if (gDoAnnotation) { if(MJPEGFormatDesc->bmFlags & 0x01) { AppendTextBuffer(" -> Sample Size is Fixed"); } else { AppendTextBuffer(" -> Sample Size is Not Fixed"); } } AppendTextBuffer("\r\nbDefaultFrameIndex: 0x%02X\r\n", MJPEGFormatDesc->bDefaultFrameIndex); if (MJPEGFormatDesc->bDefaultFrameIndex == 0 || MJPEGFormatDesc->bDefaultFrameIndex > MJPEGFormatDesc->bNumFrameDescriptors) { //@@TestCase B19.5 (descript.c line 1113) //@@ERROR //@@Descriptor Field - bDefaultFrameIndex //@@bDefaultFrameIndex is not in the domain of constrained by //@@ bNumFrameDescriptors AppendTextBuffer("*!*ERROR: bDefaultFrameIndex 0x%02X invalid, should "\ "be between 1 and 0x%02x/r/n", MJPEGFormatDesc->bDefaultFrameIndex, MJPEGFormatDesc->bNumFrameDescriptors); OOPS(); } AppendTextBuffer("bAspectRatioX: 0x%02X\r\n", MJPEGFormatDesc->bAspectRatioX); AppendTextBuffer("bAspectRatioY: 0x%02X", MJPEGFormatDesc->bAspectRatioY); if(((MJPEGFormatDesc->bmInterlaceFlags & 0x01) && ((MJPEGFormatDesc->bAspectRatioY != 0) && (MJPEGFormatDesc->bAspectRatioX != 0)))) { if (gDoAnnotation) { AppendTextBuffer(" -> Aspect Ratio is set for a %d:%d display", (MJPEGFormatDesc->bAspectRatioX), (MJPEGFormatDesc->bAspectRatioY)); } } else { if (MJPEGFormatDesc->bAspectRatioY != 0 || MJPEGFormatDesc->bAspectRatioX != 0) { //@@TestCase B19.6 //@@ERROR //@@Descriptor Field - bAspectRatioX and bAspectRatioY //@@Verify that that bAspectRatioX and bAspectRatioY are set to zero //@@ if stream is non-interlaced AppendTextBuffer("\r\n*!*ERROR: bAspectRatioX and bAspectRatioY must "\ "be 0 if stream non-Interlaced"); OOPS(); } } AppendTextBuffer("\r\nbmInterlaceFlags: 0x%02X\r\n", MJPEGFormatDesc->bmInterlaceFlags); if (gDoAnnotation) { AppendTextBuffer(" D00 = %x %sInterlaced stream or variable\r\n", (MJPEGFormatDesc->bmInterlaceFlags & 1), (MJPEGFormatDesc->bmInterlaceFlags & 1) ? "" : " non-"); AppendTextBuffer(" D01 = %x %s per frame\r\n", ((MJPEGFormatDesc->bmInterlaceFlags >> 1) & 1), ((MJPEGFormatDesc->bmInterlaceFlags >> 1) & 1) ? " 1 field" : " 2 fields"); AppendTextBuffer(" D02 = %x Field 1 %sfirst\r\n", ((MJPEGFormatDesc->bmInterlaceFlags >> 2) & 1), ((MJPEGFormatDesc->bmInterlaceFlags >> 2) & 1) ? "" : "not "); //@@TestCase B19.7 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bmInterlaceFlags //@@Validate that reserved bits (D3) are set to zero. AppendTextBuffer(" D03 = %x Reserved%s\r\n", ((MJPEGFormatDesc->bmInterlaceFlags >> 3) & 1), ((MJPEGFormatDesc->bmInterlaceFlags >> 3) & 1) ? "\r\n*!*ERROR: non zero" : "" ); AppendTextBuffer(" D4..5 = %x Field patterns ->", ((MJPEGFormatDesc->bmInterlaceFlags >> 4) & 3)); switch (MJPEGFormatDesc->bmInterlaceFlags & 0x30) { case 0x00: AppendTextBuffer(" Field 1 only"); break; case 0x10: AppendTextBuffer(" Field 2 only"); break; case 0x20: AppendTextBuffer(" Regular Pattern of fields 1 and 2"); break; case 0x30: AppendTextBuffer(" Random Pattern of fields 1 and 2"); break; } AppendTextBuffer("\r\n D6..7 = %x Display Mode ->", ((MJPEGFormatDesc->bmInterlaceFlags >> 6) & 3)); switch(MJPEGFormatDesc->bmInterlaceFlags & 0xC0) { case 0x00: AppendTextBuffer(" Bob only"); break; case 0x40: AppendTextBuffer(" Weave only"); break; case 0x80: AppendTextBuffer(" Bob or weave"); break; case 0xC0: //@@TestCase B19.8 //@@Not yet implemented - Priority 3 //@@Descriptor Field - bmInterlaceFlags //@@Question - Should we validate that reserved bits are set to zero? AppendTextBuffer(" Reserved"); break; } } //@@TestCase B19.9 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bCopyProtect //@@Question - Are their reserved bits and should we validate that //@@ reserved bits are set to zero? AppendTextBuffer("\r\nbCopyProtect: 0x%02X", MJPEGFormatDesc->bCopyProtect); if (gDoAnnotation) { if (MJPEGFormatDesc->bCopyProtect) AppendTextBuffer(" -> Duplication Restricted"); else AppendTextBuffer(" -> Duplication Unrestricted"); } AppendTextBuffer("\r\n"); // Check that the correct number of Frame Descriptors and one Color Matching // descriptor follow CheckForColorMatchingDesc ((PVIDEO_SPECIFIC) MJPEGFormatDesc, MJPEGFormatDesc->bNumFrameDescriptors, VS_FRAME_MJPEG); return TRUE; } //***************************************************************************** // // DisplayMJPEGFrameType() // //***************************************************************************** BOOL DisplayMJPEGFrameType ( PVIDEO_FRAME_MJPEG MJPEGFrameDesc ) { //@@DisplayMJPEGFrameType -MJPEG Frame size_t bLength = 0; bLength = SizeOfVideoFrameMjpeg(MJPEGFrameDesc); AppendTextBuffer("\r\n ===>Video Streaming MJPEG Frame Type Descriptor<===\r\n"); if (gDoAnnotation) { if(MJPEGFrameDesc->bFrameIndex == g_chMJPEGFrameDefault) { AppendTextBuffer(" --->This is the Default (optimum) Frame index\r\n"); } } AppendTextBuffer("bLength: 0x%02X\r\n", MJPEGFrameDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", MJPEGFrameDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", MJPEGFrameDesc->bDescriptorSubtype); AppendTextBuffer("bFrameIndex: 0x%02X\r\n", MJPEGFrameDesc->bFrameIndex); AppendTextBuffer("bmCapabilities: 0x%02X\r\n", MJPEGFrameDesc->bmCapabilities); AppendTextBuffer("wWidth: 0x%04X = %d\r\n", MJPEGFrameDesc->wWidth, MJPEGFrameDesc->wWidth); AppendTextBuffer("wHeight: 0x%04X = %d\r\n", MJPEGFrameDesc->wHeight, MJPEGFrameDesc->wHeight); AppendTextBuffer("dwMinBitRate: 0x%08X\r\n", MJPEGFrameDesc->dwMinBitRate); AppendTextBuffer("dwMaxBitRate: 0x%08X\r\n", MJPEGFrameDesc->dwMaxBitRate); AppendTextBuffer("dwMaxVideoFrameBufferSize: 0x%08X\r\n", MJPEGFrameDesc->dwMaxVideoFrameBufferSize); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwDefaultFrameInterval: 0x%08X = %lf mSec (%4.2f Hz)\r\n", MJPEGFrameDesc->dwDefaultFrameInterval, ((double)MJPEGFrameDesc->dwDefaultFrameInterval)/10000.0, (10000000.0/((double)MJPEGFrameDesc->dwDefaultFrameInterval)) ); AppendTextBuffer("bFrameIntervalType: 0x%02X\r\n", MJPEGFrameDesc->bFrameIntervalType); if (MJPEGFrameDesc->bLength != bLength) { //@@TestCase B20.1 (descript.c line 1154) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is less than required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d is incorrect, should be %d\r\n", MJPEGFrameDesc->bLength, bLength); OOPS(); } if (MJPEGFrameDesc->bFrameIndex == 0 ) { //@@TestCase B20.2 (descript.c line 1159) //@@WARNING //@@Descriptor Field - bFrameIndex //@@bFrameIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*WARNING: bFrameIndex = 0, this invalidates the descriptor\r\n"); OOPS(); } //@@TestCase B20.3 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bmCapabilities //@@Question: Should we try to verify that bmCapabilities is valid? // AppendTextBuffer("bmCapabilities: 0x%02X\r\n", MJPEGFrameDesc->bmCapabilities); if (MJPEGFrameDesc->wWidth == 0 ) { //@@TestCase B20.4 (descript.c line 1164) //@@ERROR //@@Descriptor Field - wWidth //@@wWidth is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: wWidth = 0, this invalidates the descriptor\r\n"); OOPS(); } if (MJPEGFrameDesc->wHeight == 0 ) { //@@TestCase B20.5 (descript.c line 1169) //@@ERROR //@@Descriptor Field - wHeight //@@wHeight is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: wHeight = 0, this invalidates the descriptor\r\n"); OOPS(); } if (MJPEGFrameDesc->dwMinBitRate == 0 ) { //@@TestCase B20.6 (descript.c line 1174) //@@ERROR //@@Descriptor Field - dwMinBitRate //@@dwMinBitRate is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMinBitRate = 0, this invalidates the descriptor\r\n"); OOPS(); } if (MJPEGFrameDesc->dwMaxBitRate == 0 ) { //@@TestCase B20.7 (descript.c line 1179) //@@ERROR //@@Descriptor Field - dwMaxBitRate //@@dwMaxBitRate is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMaxBitRate = 0, this invalidates the descriptor\r\n"); OOPS(); } if(MJPEGFrameDesc->dwMinBitRate > MJPEGFrameDesc->dwMaxBitRate) { //@@TestCase B20.8 //@@ERROR //@@Descriptor Field - dwMinBitRate and dwMaxBitRate //@@Verify that dwMaxBitRate is greater than dwMinBitRate AppendTextBuffer("*!*ERROR: dwMinBitRate > dwMaxBitRate, this invalidates the descriptor\r\n"); OOPS(); } else if(MJPEGFrameDesc->bFrameIntervalType == 1 && MJPEGFrameDesc->dwMinBitRate != MJPEGFrameDesc->dwMaxBitRate) { //@@TestCase B20.9 //@@WARNING //@@Descriptor Field - bFrameIntervalType, dwMinBitRate, and dwMaxBitRate //@@Verify that dwMaxBitRate is equal to dwMinBitRate if bFrameIntervalType is 1 AppendTextBuffer("*!*WARNING: if bFrameIntervalType is 1 then dwMinBitRate should equal dwMaxBitRate\r\n"); OOPS(); } if (MJPEGFrameDesc->dwMaxVideoFrameBufferSize == 0 ) { //@@TestCase B20.10 (descript.c line 1183) //@@ERROR //@@Descriptor Field - dwMaxVideoFrameBufferSize //@@dwMaxVideoFrameBufferSize is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMaxVideoFrameBufferSize = 0, this invalidates the descriptor\r\n"); OOPS(); } if (MJPEGFrameDesc->dwMaxVideoFrameBufferSize == 0 ) { //@@TestCase B20.11 (descript.c line 1188) //@@ERROR //@@Descriptor Field - dwDefaultFrameInterval //@@dwDefaultFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwDefaultFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if (0 == MJPEGFrameDesc->bFrameIntervalType) { DisplayMJPEGContinuousFrameType(MJPEGFrameDesc); } else { DisplayMJPEGDiscreteFrameType(MJPEGFrameDesc); } return TRUE; } //***************************************************************************** // // DisplayMJPEGContinuousFrameType() // //***************************************************************************** BOOL DisplayMJPEGContinuousFrameType( PVIDEO_FRAME_MJPEG MContinuousDesc ) { //@@DisplayMJPEGContinuousFrameType - MJPEG Continuous Frame ULONG dwMinFrameInterval = MContinuousDesc->adwFrameInterval[0]; ULONG dwMaxFrameInterval = MContinuousDesc->adwFrameInterval[1]; ULONG dwFrameIntervalStep = MContinuousDesc->adwFrameInterval[2]; AppendTextBuffer("===>Additional Continuous Frame Type Data\r\n"); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwMinFrameInterval: 0x%08X = %lf mSec (%d Hz)\r\n", dwMinFrameInterval, ((double)dwMinFrameInterval)/10000.0, (ULONG)(10000000.0/((double)dwMinFrameInterval) + 0.5)); AppendTextBuffer("dwMaxFrameInterval: 0x%08X = %lf mSec (%d Hz)\r\n", dwMaxFrameInterval, ((double)dwMaxFrameInterval)/10000.0, (ULONG)(10000000.0/((double)dwMaxFrameInterval) + 0.5)); AppendTextBuffer("dwFrameIntervalStep: 0x%08X\r\n", dwFrameIntervalStep); if (dwMinFrameInterval == 0 ) { //@@TestCase B21.2 (descript.c line 1188) //@@ERROR //@@Descriptor Field - dwMinFrameInterval //@@dwMinFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMinFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if (dwMaxFrameInterval == 0 ) { //@@TestCase B21.3 (descript.c line 1188) //@@ERROR //@@Descriptor Field - dwMaxFrameInterval //@@dwMaxFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMaxFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if(dwMinFrameInterval > dwMaxFrameInterval) { //@@TestCase B21.4 (descript.c line 1211) //@@ERROR //@@Descriptor Field - dwMinFrameInterval and dwMaxFrameInterval //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval AppendTextBuffer("*!*ERROR: dwMinFrameInterval is larger that dwMaxFrameInterval, this invalidates the descriptor\r\n"); OOPS(); } else if ((dwMinFrameInterval + dwFrameIntervalStep) > dwMaxFrameInterval) { //@@TestCase B21.5 //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval combined with dwFrameIntervalStep AppendTextBuffer("*!*WARNING: dwMinFrameInterval + dwFrameIntervalStep is greater than dwMaxFrameInterval, this could cause problems\r\n"); OOPS(); } else if ((dwMaxFrameInterval - dwMinFrameInterval) == 0 ) { //@@TestCase B21.6 //@@CAUTION //@@Descriptor Field - dwFrameIntervalStep //@@Suggestion to use descrite frames if dwFrameIntervalStep is zero AppendTextBuffer("*!*CAUTION: dwFrameIntervalStep equals zero, consider using discrete frames\r\n"); OOPS(); } else if ((dwMaxFrameInterval - dwMinFrameInterval) % dwFrameIntervalStep ) { //@@TestCase B21.7 (descript.c line 1220) //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that the difference between dwMaxFrameInterval and dwMinFrameInterval is evenly divisible by dwFrameIntervalStep AppendTextBuffer("*!*WARNING: dwMaxFrameInterval minus dwMinFrameInterval is not evenly divisible by dwFrameIntervalStep, this could cause problems\r\n"); OOPS(); } if (dwFrameIntervalStep == 0 && (dwMaxFrameInterval - dwMinFrameInterval)) { //@@TestCase B21.8 (descript.c line 1200) //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that the dwFrameIntervalStep is not zero if there is a difference between dwMaxFrameInterval and dwMinFrameInterval AppendTextBuffer("*!*WARNING: dwFrameIntervalStep = 0, this invalidates the descriptor when there is a difference between \r\n *!*dwMinFrameInterval and dwMaxFrameInterval\r\n"); OOPS(); } return TRUE; } //***************************************************************************** // // DisplayMJPEGDiscreteFrameType() // //***************************************************************************** BOOL DisplayMJPEGDiscreteFrameType( PVIDEO_FRAME_MJPEG MDiscreteDesc ) { //@@DisplayMJPEGDiscreteFrameType -MJPEG Discrete Frame UINT iNdex = 1; UINT iCurFrame = 0; ULONG * ulFrameInterval = NULL; AppendTextBuffer("===>Additional Discrete Frame TypeData\r\n"); // There are (MDiscreteDesc->bFrameIntervalType) dwFrameIntervals (1 based index) for (; iNdex <= MDiscreteDesc->bFrameIntervalType; iNdex++, iCurFrame++) { ulFrameInterval = &MDiscreteDesc->adwFrameInterval[iCurFrame]; // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwFrameInterval[%d]: 0x%08X = %lf mSec (%4.2f Hz)\r\n", iNdex, *ulFrameInterval, ((double)*ulFrameInterval)/10000.0, (10000000.0/((double)*ulFrameInterval)) ); if (0 == *ulFrameInterval) { //@@TestCase B22.1 (descript.c line 1229) //@@ERROR //@@Descriptor Field - dwFrameInterval[x] //@@dwFrameInterval[x] must be non-zero AppendTextBuffer("*!*ERROR: dwFrameInterval[%d] must be non-zero\r\n", iNdex); OOPS(); } if ((iNdex > 1)&&(*ulFrameInterval <= MDiscreteDesc->adwFrameInterval[iCurFrame - 1])) { //@@TestCase B22.2 (descript.c line 1235) //@@ERROR //@@Descriptor Field - dwFrameInterval[x] //@@dwFrameInterval[n] must be greater than dwFrameInterval[n - 1] AppendTextBuffer("*!*ERROR: dwFrameInterval[0x%02X] must be "\ "greater than preceding dwFrameInterval[0x%02X]\r\n", iNdex, iNdex - 1); OOPS(); } } return TRUE; } //***************************************************************************** // // DisplayMPEG1SSFormat() // //***************************************************************************** BOOL DisplayMPEG1SSFormat ( PVIDEO_FORMAT_MPEG1SS MPEG1SSFormatDesc ) { //@@DisplayMPEG1SSFormat -MPEG1 SS Format AppendTextBuffer("\r\n ===>Video Streaming MPEG1-SS Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", MPEG1SSFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", MPEG1SSFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", MPEG1SSFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", MPEG1SSFormatDesc->bFormatIndex); AppendTextBuffer("wPacketLength: 0x%02X\r\n", MPEG1SSFormatDesc->bPacketLength); AppendTextBuffer("wPackLength: 0x%02X\r\n", MPEG1SSFormatDesc->bPackLength); AppendTextBuffer("bPackdataType: 0x%02X", (MPEG1SSFormatDesc->bPackDataType)); if(gDoAnnotation) { if(MPEG1SSFormatDesc->bPackDataType & 0x01){AppendTextBuffer(" -> Pack data size fixed\r\n");} else {AppendTextBuffer(" -> Pack data size variable\r\n"); }} else {AppendTextBuffer("\r\n");} if (MPEG1SSFormatDesc->bLength != sizeof(VIDEO_FORMAT_MPEG1SS)) { //@@TestCase B23.1 (descript.c line 1514) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d. USBView cannot correctly display descriptor\r\n", MPEG1SSFormatDesc->bLength, sizeof(VIDEO_FORMAT_MPEG1SS)); OOPS(); } if (MPEG1SSFormatDesc->bFormatIndex == 0 ) { //@@TestCase B23.2 (descript.c line 1519) //@@WARNING //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*WARNING: bFormatIndex = 0, this invalidates the descriptor\r\n"); OOPS(); } //@@TestCase B23.3 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bPackdataType //@@Question - Should we validate that reserved bits are set to zero? // AppendTextBuffer("bPackdataType: 0x%02X", (MPEG1SSFormatDesc->bPackdataType & 0x01)); // This descriptor is deprecated for UVC 1.1 #ifdef H264_SUPPORT if (UVC10 != g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\r\n"); } #else if (UVC11 == g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\r\n"); } #endif return TRUE; } //***************************************************************************** // // DisplayMPEG2PSFormat() // //***************************************************************************** BOOL DisplayMPEG2PSFormat ( PVIDEO_FORMAT_MPEG2PS MPEG2PSFormatDesc ) { //@@DisplayMPEG2PSFormat -MPEG2 PS Format AppendTextBuffer("\r\n ===>Video Streaming MPEG2-PS Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", MPEG2PSFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", MPEG2PSFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", MPEG2PSFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", MPEG2PSFormatDesc->bFormatIndex); AppendTextBuffer("bPacketLength: 0x%02X\r\n", MPEG2PSFormatDesc->bPacketLength); AppendTextBuffer("bPackLength: 0x%02X\r\n", MPEG2PSFormatDesc->bPackLength); AppendTextBuffer("bPackDataType: 0x%02X", (MPEG2PSFormatDesc->bPackDataType)); if (MPEG2PSFormatDesc->bLength != sizeof(VIDEO_FORMAT_MPEG2PS)) { //@@TestCase B24.1 (descript.c line 1542) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d. USBView cannot correctly display descriptor\r\n", MPEG2PSFormatDesc->bLength, sizeof(VIDEO_FORMAT_MPEG2PS)); OOPS(); AppendTextBuffer("*!*USBView will try to display the rest of the descriptor but results may not be accurate\r\n"); } if (MPEG2PSFormatDesc->bFormatIndex == 0 ) { //@@TestCase B24.2 (descript.c line 1547) //@@WARNING //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*WARNING: bFormatIndex = 0, this invalidates the descriptor\r\n"); OOPS(); } //@@TestCase B24.3 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bPackdataType //@@Question - Should we validate that reserved bits are set to zero? // AppendTextBuffer("bPackdataType: 0x%02X", (MPEG2PSFormatDesc->bPackdataType & 0x01)); // This descriptor is deprecated for UVC 1.1 #ifdef H264_SUPPORT if (UVC10 != g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\r\n"); } #else if (UVC11 == g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\r\n"); } #endif return TRUE; } //***************************************************************************** // // DisplayMPEG2TSFormat() // //***************************************************************************** BOOL DisplayMPEG2TSFormat ( PVIDEO_FORMAT_MPEG2TS MPEG2TSFormatDesc ) { //@@DisplayMPEG2TSFormat -MPEG2 TS Format UCHAR bLength = sizeof(VIDEO_FORMAT_MPEG2TS); AppendTextBuffer("\r\n ===>Video Streaming MPEG2-TS Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", MPEG2TSFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", MPEG2TSFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", MPEG2TSFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", MPEG2TSFormatDesc->bFormatIndex); AppendTextBuffer("bDataOffset: 0x%02X\r\n", MPEG2TSFormatDesc->bDataOffset); AppendTextBuffer("bPacketLength: 0x%02X\r\n", MPEG2TSFormatDesc->bPacketLength); AppendTextBuffer("bStrideLength: 0x%02X\r\n", MPEG2TSFormatDesc->bStrideLength); #ifdef H264_SUPPORT if (UVC10 != g_chUVCversion) #else if (UVC11 == g_chUVCversion) #endif { int i = 0; PCHAR pStr = NULL; OLECHAR szGUID[256]; GUID * pStrideGuid = NULL; pStrideGuid = (GUID *) (&MPEG2TSFormatDesc->bStrideLength + 1); memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256); i = StringFromGUID2((REFGUID) pStrideGuid, (LPOLESTR) szGUID, 255); i++; AppendTextBuffer("guidStrideFormat: %S", szGUID); pStr = VidFormatGUIDCodeToName((REFGUID) pStrideGuid); if(gDoAnnotation) { if (pStr) { AppendTextBuffer(" = %s Format", pStr); } } AppendTextBuffer("\r\n"); bLength = sizeof(VIDEO_FORMAT_MPEG2TS) + sizeof(GUID); } if (MPEG2TSFormatDesc->bLength != bLength) { //@@TestCase B25.1 (descript.c line 1486) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", MPEG2TSFormatDesc->bLength, sizeof(VIDEO_FORMAT_MPEG2TS)); OOPS(); } if (MPEG2TSFormatDesc->bFormatIndex == 0 ) { //@@TestCase B25.2 (descript.c line 1491) //@@WARNING //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*WARNING: bFormatIndex = 0, this invalidates the descriptor\r\n"); OOPS(); } //@@TestCase B25.3 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bDataOffset, wPacket and wStride //@@Question - Should we check that if bDataOffset is 0 that wPacket and wStride should equal each other // AppendTextBuffer("bDataOffset: 0x%02X\r\n", MPEG2TSFormatDesc->bDataOffset); return TRUE; } //***************************************************************************** // // DisplayMPEG4SLFormat() // //***************************************************************************** BOOL DisplayMPEG4SLFormat ( PVIDEO_FORMAT_MPEG4SL MPEG4SLFormatDesc ) { //@@DisplayMPEG4SLFormat -MPEG4 SL Format AppendTextBuffer("\r\n ===>Video Streaming MPEG4-SL Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", MPEG4SLFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", MPEG4SLFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", MPEG4SLFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", MPEG4SLFormatDesc->bFormatIndex); AppendTextBuffer("bPacketLength: 0x%02X\r\n", MPEG4SLFormatDesc->bPacketLength); if (MPEG4SLFormatDesc->bLength != sizeof(VIDEO_FORMAT_MPEG4SL)) { //@@TestCase B26.1 (descript.c line 1568) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d. USBView cannot correctly display descriptor\r\n", MPEG4SLFormatDesc->bLength, sizeof(VIDEO_FORMAT_MPEG4SL)); OOPS(); } if (MPEG4SLFormatDesc->bFormatIndex == 0 ) { //@@TestCase B26.2 (descript.c line 1573) //@@WARNING //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*WARNING: bFormatIndex = 0, this invalidates the descriptor\r\n"); OOPS(); } // This descriptor is deprecated for UVC 1.1 #ifdef H264_SUPPORT if (UVC10 != g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\r\n"); } #else if (UVC11 == g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\r\n"); } #endif return TRUE; } //***************************************************************************** // // DisplayStreamPayload() // //***************************************************************************** BOOL DisplayStreamPayload ( PVIDEO_FORMAT_STREAM StreamPayloadDesc ) { //@@DisplayStreamPayload -Stream Based Payload Format PCHAR pStr = NULL; OLECHAR szGUID[256]; int i = 0; memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256); i = StringFromGUID2((REFGUID) &StreamPayloadDesc->guidFormat, (LPOLESTR) szGUID, 255); i++; AppendTextBuffer("\r\n ===>Video Streaming Stream Based Payload Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", StreamPayloadDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", StreamPayloadDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", StreamPayloadDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", StreamPayloadDesc->bFormatIndex); AppendTextBuffer("guidFormat: %S", szGUID); pStr = VidFormatGUIDCodeToName((REFGUID) &StreamPayloadDesc->guidFormat); if(gDoAnnotation) { if (pStr) { AppendTextBuffer(" = %s Format", pStr); } } AppendTextBuffer("\r\n"); AppendTextBuffer("dwPacketLength: 0x%02X\r\n", StreamPayloadDesc->dwPacketLength); if (StreamPayloadDesc->bLength != sizeof(VIDEO_FORMAT_STREAM)) { //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", StreamPayloadDesc->bLength, sizeof(PVIDEO_FORMAT_STREAM)); OOPS(); } if (StreamPayloadDesc->bFormatIndex == 0 ) { //@@WARNING //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*WARNING: bFormatIndex = 0, this is a 1 based index\r\n"); OOPS(); } // This descriptor is new for UVC 1.1 if (UVC10 == g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC 1.0 devices\r\n"); } return TRUE; } //***************************************************************************** // // DisplayDVFormat() // //***************************************************************************** BOOL DisplayDVFormat ( PVIDEO_FORMAT_DV DVFormatDesc ) { //@@DisplayDVFormat -Digital Video Format AppendTextBuffer("\r\n ===>Video Streaming DV Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", DVFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", DVFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", DVFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", DVFormatDesc->bFormatIndex); AppendTextBuffer("dwMaxVideoFrameBufferSize: 0x%08X\r\n", DVFormatDesc->dwMaxVideoFrameBufferSize); AppendTextBuffer("bFormatType: 0x%02X\r\n", DVFormatDesc->bFormatType); if (gDoAnnotation) { AppendTextBuffer(" D0..6 = Format Type ->"); switch(DVFormatDesc->bFormatType & 0x03) { case 0x00: AppendTextBuffer(" SD-DV\r\n"); break; case 0x01: AppendTextBuffer(" SDL-DV\r\n"); break; case 0x02: AppendTextBuffer(" HD-DV\r\n"); break; default: AppendTextBuffer(" Unknown Format\r\n"); break; } if (DVFormatDesc->bFormatType & 0x80) AppendTextBuffer(" D7 = 60Hz"); else AppendTextBuffer(" D7 = 50Hz"); AppendTextBuffer("\r\n");} if (DVFormatDesc->bLength != sizeof(VIDEO_FORMAT_DV)) { //@@TestCase B27.1 (descript.c line 1453) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", DVFormatDesc->bLength, sizeof(VIDEO_FORMAT_DV)); OOPS(); } if (DVFormatDesc->bFormatIndex == 0 ) { //@@TestCase B27.2 (descript.c line 1458) //@@ERROR //@@Descriptor Field - bFormatIndex //@@bFormatIndex invalid AppendTextBuffer("*!*ERROR: bFormatIndex of 0x%02X is invalid\r\n", DVFormatDesc->bFormatIndex); OOPS(); } if (DVFormatDesc->dwMaxVideoFrameBufferSize == 0 ) { //@@TestCase B27.3 (descript.c line 1463) //@@ERROR //@@Descriptor Field - dwMaxVideoFrameBufferSize //@@dwMaxVideoFrameBufferSize invalid AppendTextBuffer("*!*ERROR: dwMaxVideoFrameBufferSize of 0x%02X is invalid\r\n", DVFormatDesc->dwMaxVideoFrameBufferSize); OOPS(); } //@@TestCase B27.4 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bFormatType //@@Question - Should we validate that reserved bits are set to zero? return TRUE; } //***************************************************************************** // // DisplayVidVendorFormat() // //***************************************************************************** BOOL DisplayVendorVidFormat ( PVIDEO_FORMAT_VENDOR VendorVidFormatDesc ) { //@@DisplayVendorVidFormat -Vendor Video Format OLECHAR szGUID[256]; int i = 0; // Initialize the default Frame g_chVendorFrameDefault = VendorVidFormatDesc->bDefaultFrameIndex; memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256); i = StringFromGUID2((REFGUID) &VendorVidFormatDesc->guidMajorFormat, (LPOLESTR) szGUID, 255); i++; AppendTextBuffer("\r\n ===>Video Streaming Vendor Video Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", VendorVidFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VendorVidFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VendorVidFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", VendorVidFormatDesc->bFormatIndex); AppendTextBuffer("bNumFrameDescriptors: 0x%02X\r\n", VendorVidFormatDesc->bNumFrameDescriptors); AppendTextBuffer("guidMajorFormat: %S\r\n", szGUID); i = StringFromGUID2((REFGUID) &VendorVidFormatDesc->guidSubFormat, (LPOLESTR) szGUID, 255); i++; AppendTextBuffer("guidSubFormat: %S\r\n", szGUID); i = StringFromGUID2((REFGUID) &VendorVidFormatDesc->guidSpecifier, (LPOLESTR) szGUID, 255); i++; AppendTextBuffer("guidSpecifier: %S\r\n", szGUID); AppendTextBuffer("bPayloadClass: 0x%02X\r\n", VendorVidFormatDesc->bPayloadClass); AppendTextBuffer("bDefaultFrameIndex: 0x%02X\r\n", VendorVidFormatDesc->bDefaultFrameIndex); AppendTextBuffer("bCopyProtect: 0x%02X", VendorVidFormatDesc->bCopyProtect); if(gDoAnnotation) { if(VendorVidFormatDesc->bCopyProtect) { AppendTextBuffer(" -> Duplication Restricted\r\n");} else {AppendTextBuffer(" -> Duplication Unrestricted\r\n");}} else {AppendTextBuffer("\r\n");} if (VendorVidFormatDesc->bLength != sizeof(VIDEO_FORMAT_VENDOR)) { //@@TestCase B28.1 (descript.c line 1297) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d. USBView cannot correctly display descriptor\r\n", VendorVidFormatDesc->bLength, sizeof(VIDEO_FORMAT_VENDOR)); OOPS(); } if (VendorVidFormatDesc->bFormatIndex == 0 ) { //@@TestCase B28.2 (descript.c line 1302) //@@ERROR //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bFormatIndex = 0, this invalidates the descriptor\r\n"); OOPS(); } if (VendorVidFormatDesc->bNumFrameDescriptors == 0 ) { //@@TestCase B28.3 (descript.c line 1307) //@@ERROR //@@Descriptor Field - bNumFrameDescriptors //@@bNumFrameDescriptors is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bNumFrameDescriptors = 0, this invalidates the descriptor\r\n"); OOPS(); } if(VendorVidFormatDesc->bPayloadClass > 1) { //@@TestCase B28.4 //@@WARNING //@@Descriptor Field - bPayloadClass //@@bPayloadClass is using reserved space AppendTextBuffer("*!*WARNING: bPayloadClass is incorrectly using reserved space\r\n"); OOPS(); } else { if (gDoAnnotation) { if(VendorVidFormatDesc->bPayloadClass == 1) { AppendTextBuffer(" -> Using a Frame Based Payload\r\n");} else { AppendTextBuffer(" -> Using a Stream Based Payload\r\n");} } else {AppendTextBuffer("\r\n");} } if (VendorVidFormatDesc->bDefaultFrameIndex == 0 ) { //@@TestCase B28.5 (descript.c line 1312) //@@ERROR //@@Descriptor Field - bDefaultFrameIndex //@@bDefaultFrameIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bDefaultFrameIndex = 0, this invalidates the descriptor\r\n"); OOPS(); } if (VendorVidFormatDesc->bDefaultFrameIndex == 0 || VendorVidFormatDesc->bDefaultFrameIndex > VendorVidFormatDesc->bNumFrameDescriptors) { //@@TestCase B28.6 //@@WARNING //@@Descriptor Field - bDefaultFrameIndex //@@bDefaultFrameIndex is out of range AppendTextBuffer("*!*WARNING: The value %d for the bDefaultFrameIndex is out of range this invalidates the descriptor\r\n*!* The proper range is 1 to %d)", VendorVidFormatDesc->bDefaultFrameIndex, VendorVidFormatDesc->bNumFrameDescriptors); OOPS(); } //@@TestCase B28.7 //@@Not yet implemented - Priority 1 //@@Descriptor Field - bCopyProtect //@@Question - Are their reserved bits and should we validate that reserved bits are set to zero? // AppendTextBuffer("bCopyProtect: 0x%02X", VendorVidFormatDesc->bCopyProtect); // Check that the correct number of Frame Descriptors and one Color Matching // descriptor follow CheckForColorMatchingDesc ((PVIDEO_SPECIFIC) VendorVidFormatDesc, VendorVidFormatDesc->bNumFrameDescriptors, VS_FRAME_VENDOR); // This descriptor is deprecated for UVC 1.1 #ifdef H264_SUPPORT if (UVC10 != g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\r\n"); } #else if (UVC11 == g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\r\n"); } #endif return TRUE; } //***************************************************************************** // // DisplayVendorVidFrameType() // //***************************************************************************** BOOL DisplayVendorVidFrameType ( PVIDEO_FRAME_VENDOR VendorVidFrameDesc ) { //@@DisplayVendorVidFrameType -Vendor Video Frame size_t bLength = 0; bLength = SizeOfVideoFrameVendor(VendorVidFrameDesc); AppendTextBuffer("\r\n ===>Video Streaming Vendor Video Frame Type Descriptor<===\r\n"); if (gDoAnnotation) { if(VendorVidFrameDesc->bFrameIndex == g_chVendorFrameDefault) { AppendTextBuffer(" --->This is the Default (optimum) Frame index\r\n"); } } AppendTextBuffer("bLength: 0x%02X\r\n", VendorVidFrameDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VendorVidFrameDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VendorVidFrameDesc->bDescriptorSubtype); AppendTextBuffer("bFrameIndex: 0x%02X\r\n", VendorVidFrameDesc->bFrameIndex); if (VendorVidFrameDesc->bLength != bLength) { //@@TestCase B29.1 (descript.c line 1352) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is less than required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", VendorVidFrameDesc->bLength, bLength); OOPS(); } if (VendorVidFrameDesc->bFrameIndex == 0 ) { //@@TestCase B29.2 (descript.c line 1357) //@@ERROR //@@Descriptor Field - bFrameIndex //@@bFrameIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bFrameIndex = 0, this is a 1 based index\r\n"); OOPS(); } AppendTextBuffer("bmCapabilities: 0x%02X", VendorVidFrameDesc->bmCapabilities); if(VendorVidFrameDesc->bmCapabilities & 0x01){ if(gDoAnnotation) { AppendTextBuffer(" -> Still Images are supported\r\n");} else {AppendTextBuffer("\r\n");} } else if (VendorVidFrameDesc->bmCapabilities & 0xFF) { //@@TestCase B29.3 //@@WARNING //@@Descriptor Field - bmCapabilities //@@bmCapabilities has a bit using reserved areas that should be set to zero AppendTextBuffer("\r\n*!*WARNING: bmCapabilities is using reserved areas.\r\n"); OOPS(); } else {AppendTextBuffer("\r\n");} AppendTextBuffer("wWidth: 0x%04X = %d\r\n", VendorVidFrameDesc->wWidth, VendorVidFrameDesc->wWidth); AppendTextBuffer("wHeight: 0x%04X = %d\r\n", VendorVidFrameDesc->wHeight, VendorVidFrameDesc->wHeight); AppendTextBuffer("dwMinBitRate: 0x%08X\r\n", VendorVidFrameDesc->dwMinBitRate); AppendTextBuffer("dwMaxBitRate: 0x%08X\r\n", VendorVidFrameDesc->dwMaxBitRate); AppendTextBuffer("dwMaxVideoFrameBufferSize: 0x%08X\r\n", VendorVidFrameDesc->dwMaxVideoFrameBufferSize); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwDefaultFrameInterval: 0x%08X = %lf mSec (%4.2f Hz)\r\n", VendorVidFrameDesc->dwDefaultFrameInterval, ((double)VendorVidFrameDesc->dwDefaultFrameInterval)/10000.0, (10000000.0/((double)VendorVidFrameDesc->dwDefaultFrameInterval)) ); AppendTextBuffer("bFrameIntervalType: 0x%02X\r\n", VendorVidFrameDesc->bFrameIntervalType); if (VendorVidFrameDesc->wWidth == 0 ) { //@@TestCase B29.4 (descript.c line 1362) //@@ERROR //@@Descriptor Field - wWidth //@@wWidth is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: wWidth must be nonzero\r\n"); OOPS(); } if (VendorVidFrameDesc->wHeight == 0 ) { //@@TestCase B29.5 (descript.c line 1367) //@@ERROR //@@Descriptor Field - wHeight //@@wHeight is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: wHeight must be nonzero\r\n"); OOPS(); } if (VendorVidFrameDesc->dwMinBitRate == 0 ) { //@@TestCase B29.6 (descript.c line 1372) //@@ERROR //@@Descriptor Field - dwMinBitRate //@@dwMinBitRate is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMinBitRate must be nonzero\r\n"); OOPS(); } if (VendorVidFrameDesc->dwMaxBitRate == 0 ) { //@@TestCase B29.7 (descript.c line 1377) //@@ERROR //@@Descriptor Field - dwMaxBitRate //@@dwMaxBitRate is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMaxBitRate must be nonzero\r\n"); OOPS(); } if(VendorVidFrameDesc->dwMinBitRate > VendorVidFrameDesc->dwMaxBitRate) { //@@TestCase B29.8 //@@ERROR //@@Descriptor Field - dwMinBitRate and dwMaxBitRate //@@Verify that dwMaxBitRate is greater than dwMinBitRate AppendTextBuffer("*!*ERROR: dwMinBitRate should be less than dwMaxBitRate\r\n"); OOPS(); } else { if (VendorVidFrameDesc->bFrameIntervalType == 1 && VendorVidFrameDesc->dwMinBitRate != VendorVidFrameDesc->dwMaxBitRate) { //@@TestCase B29.9 //@@WARNING //@@Descriptor Field - bFrameIntervalType, dwMinBitRate, and dwMaxBitRate //@@Verify that dwMaxBitRate is equal to dwMinBitRate if bFrameIntervalType is 1 AppendTextBuffer("*!*WARNING: if bFrameIntervalType is 1 then dwMinBitRate "\ "should equal dwMaxBitRate\r\n"); OOPS(); } } if (VendorVidFrameDesc->dwMaxVideoFrameBufferSize == 0 ) { //@@TestCase B29.10 (descript.c line 1382) //@@WARNING //@@Descriptor Field - dwMaxVideoFrameBufferSize //@@dwMaxVideoFrameBufferSize is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*WARNING: dwMaxVideoFrameBufferSize must be nonzero\r\n"); OOPS(); } if (VendorVidFrameDesc->dwDefaultFrameInterval == 0 ) { //@@TestCase B29.11 (descript.c line 1020) //@@WARNING //@@Descriptor Field - dwDefaultFrameInterval //@@dwDefaultFrameInterval must be nonzero AppendTextBuffer("*!*WARNING: dwDefaultFrameInterval must be nonzero\r\n"); OOPS(); } if (VendorVidFrameDesc->bFrameIntervalType == 0) { DisplayVendorVidContinuousFrameType(VendorVidFrameDesc); } else { DisplayVendorVidDiscreteFrameType(VendorVidFrameDesc); } // This descriptor is deprecated for UVC 1.1 #ifdef H264_SUPPORT if (UVC10 != g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\r\n"); } #else if (UVC11 == g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\r\n"); } #endif return TRUE; } //***************************************************************************** // // DisplayVendorVidContinuousFrameType() // //***************************************************************************** BOOL DisplayVendorVidContinuousFrameType( PVIDEO_FRAME_VENDOR VContinuousDesc ) { //@@DisplayVendorVidContinuousFrameType -Vendor Video Continuous Frame ULONG dwMinFrameInterval = VContinuousDesc->adwFrameInterval[0]; ULONG dwMaxFrameInterval = VContinuousDesc->adwFrameInterval[1]; ULONG dwFrameIntervalStep = VContinuousDesc->adwFrameInterval[2]; AppendTextBuffer("===>Additional Continuous Frame Type Data\r\n"); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwMinFrameInterval: 0x%08X = %lf mSec (%d Hz)\r\n", dwMinFrameInterval, ((double)dwMinFrameInterval)/10000.0, (ULONG)(10000000.0/((double)dwMinFrameInterval) + 0.5)); AppendTextBuffer("dwMaxFrameInterval: 0x%08X = %lf mSec (%d Hz)\r\n", dwMaxFrameInterval, ((double)dwMaxFrameInterval)/10000.0, (ULONG)(10000000.0/((double)dwMaxFrameInterval) + 0.5)); AppendTextBuffer("dwFrameIntervalStep: 0x%08X\r\n", dwFrameIntervalStep); if (dwMinFrameInterval == 0 ) { //@@TestCase B30.2 (descript.c line 1388) //@@ERROR //@@Descriptor Field - dwMinFrameInterval //@@dwMinFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMinFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if (dwMaxFrameInterval == 0 ) { //@@TestCase B30.3 (descript.c line 1388) //@@ERROR //@@Descriptor Field - dwMaxFrameInterval //@@dwMaxFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMaxFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if(dwMinFrameInterval > dwMaxFrameInterval) { //@@TestCase B30.4 (descript.c line 1405) //@@ERROR //@@Descriptor Field - dwMinFrameInterval and dwMaxFrameInterval //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval AppendTextBuffer("*!*ERROR: dwMinFrameInterval is larger that dwMaxFrameInterval, this invalidates the descriptor\r\n"); OOPS(); } else if ((dwMinFrameInterval + dwFrameIntervalStep) > dwMaxFrameInterval) { //@@TestCase B30.5 //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval combined with dwFrameIntervalStep AppendTextBuffer("*!*WARNING: dwMinFrameInterval + dwFrameIntervalStep is greater than dwMaxFrameInterval, this could cause problems\r\n"); OOPS(); } else if ((dwMaxFrameInterval - dwMinFrameInterval) == 0 ) { //@@TestCase B30.6 //@@CAUTION //@@Descriptor Field - dwFrameIntervalStep //@@Suggestion to use descrite frames if dwFrameIntervalStep is zero AppendTextBuffer("*!*CAUTION: dwFrameIntervalStep equals zero, consider using discrete frames\r\n"); OOPS(); } else if ((dwMaxFrameInterval - dwMinFrameInterval) % dwFrameIntervalStep ) { //@@TestCase B30.7 (descript.c line 1414) //@@ERROR //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that the difference between dwMaxFrameInterval and dwMinFrameInterval is evenly divisible by dwFrameIntervalStep AppendTextBuffer("*!*ERROR: dwMaxFrameInterval minus dwMinFrameInterval is not evenly divisible by dwFrameIntervalStep, this could cause problems\r\n"); OOPS(); } if (dwFrameIntervalStep == 0 && (dwMaxFrameInterval - dwMinFrameInterval)) { //@@TestCase B30.8 (descript.c line 1394) //@@ERROR //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that the dwFrameIntervalStep is not zero if there is a difference between dwMaxFrameInterval and dwMinFrameInterval AppendTextBuffer("*!*ERROR: dwFrameIntervalStep = 0, this invalidates the descriptor when there is a difference between \r\n dwMinFrameInterval and dwMaxFrameInterval\r\n"); OOPS(); } return TRUE; } //***************************************************************************** // // DisplayVendorVidDiscreteFrameType() // //***************************************************************************** BOOL DisplayVendorVidDiscreteFrameType( PVIDEO_FRAME_VENDOR VDiscreteDesc ) { //@@DisplayVendorVidDiscreteFrameType -Vendor Video Discrete Frame UINT iNdex = 1; UINT iCurFrame = 0; ULONG * ulFrameInterval = NULL; AppendTextBuffer("===>Additional Discrete Frame TypeData\r\n"); // There are (VDiscreteDesc->bFrameIntervalType) dwFrameIntervals for (; iNdex <= VDiscreteDesc->bFrameIntervalType; iNdex++, iCurFrame++) { ulFrameInterval = &VDiscreteDesc->adwFrameInterval[iCurFrame]; // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwFrameInterval[%d]: 0x%08X = %lf mSec (%4.2f Hz)\r\n", iNdex, *ulFrameInterval, ((double)*ulFrameInterval)/10000.0, (10000000.0/((double)*ulFrameInterval)) ); if (0 == *ulFrameInterval) { //@@TestCase B31.1 (descript.c line 1061) //@@ERROR //@@Descriptor Field - dwFrameInterval[x] //@@dwFrameInterval[x] must be non-zero AppendTextBuffer("*!*ERROR: dwFrameInterval[%d] must be non-zero\r\n", iNdex); OOPS(); } if ((iNdex > 1)&&(*ulFrameInterval <= VDiscreteDesc->adwFrameInterval[iCurFrame - 1])) { //@@TestCase B31.2 (descript.c line 1067) //@@ERROR //@@Descriptor Field - dwFrameInterval[x] //@@dwFrameInterval[n] must be greater than dwFrameInterval[n - 1] AppendTextBuffer("*!*ERROR: dwFrameInterval[0x%02X] must be "\ "greater than preceding dwFrameInterval[0x%02X]\r\n", iNdex, iNdex - 1); OOPS(); } } return TRUE; } //***************************************************************************** // // DisplayFramePayloadFormat() // //***************************************************************************** BOOL DisplayFramePayloadFormat ( PVIDEO_FORMAT_FRAME FramePayloadFormatDesc ) { //@@DisplayFramePayloadFormat - FrameBased Payload Format PCHAR pStr = NULL; OLECHAR szGUID[256]; int i = 0; // Initialize the default Frame g_chFrameBasedFrameDefault = FramePayloadFormatDesc->bDefaultFrameIndex; memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256); i = StringFromGUID2((REFGUID) &FramePayloadFormatDesc->guidFormat, (LPOLESTR) szGUID, 255); i++; AppendTextBuffer("\r\n ===>Video Streaming Frame Based Payload Format Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X\r\n", FramePayloadFormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", FramePayloadFormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", FramePayloadFormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X\r\n", FramePayloadFormatDesc->bFormatIndex); AppendTextBuffer("bNumFrameDescriptors: 0x%02X\r\n", FramePayloadFormatDesc->bNumFrameDescriptors); AppendTextBuffer("guidFormat: %S", szGUID); pStr = VidFormatGUIDCodeToName((REFGUID) &FramePayloadFormatDesc->guidFormat); if ( pStr ) { if ( gDoAnnotation ) { AppendTextBuffer(" = %s Format", pStr); } } AppendTextBuffer("\r\n"); AppendTextBuffer("bBitsPerPixel: 0x%02X\r\n", FramePayloadFormatDesc->bBitsPerPixel); AppendTextBuffer("bDefaultFrameIndex: 0x%02X\r\n", FramePayloadFormatDesc->bDefaultFrameIndex); if (FramePayloadFormatDesc->bLength != sizeof(VIDEO_FORMAT_FRAME)) { //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required //@@length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", FramePayloadFormatDesc->bLength, sizeof(VIDEO_FORMAT_FRAME)); OOPS(); } if (FramePayloadFormatDesc->bFormatIndex == 0 ) { //@@ERROR //@@Descriptor Field - bFormatIndex //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bFormatIndex = 0, this is a 1 based index\r\n"); OOPS(); } if (FramePayloadFormatDesc->bNumFrameDescriptors == 0 ) { //@@ERROR //@@Descriptor Field - bNumFrameDescriptors //@@bNumFrameDescriptors is set to zero which is not in accordance with the //@@USB Video Device Specification AppendTextBuffer("*!*ERROR: bNumFrameDescriptors = 0, must have at least 1 Frame descriptor\r\n"); OOPS(); } if(!(pStr)) { //@@WARNING //@@Descriptor Field - guidFormat //@@guidFormat is set to unknown or undefined format AppendTextBuffer("\r\n*!*WARNING: guidFormat is an unknown format\r\n"); OOPS(); } if (FramePayloadFormatDesc->bBitsPerPixel == 0 ) { //@@ERROR //@@Descriptor Field - bBitsPerPixel //@@bBitsPerPixel is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: bBitsPerPixel = 0, this invalidates the descriptor\r\n"); OOPS(); } if (FramePayloadFormatDesc->bDefaultFrameIndex == 0 || FramePayloadFormatDesc->bDefaultFrameIndex > FramePayloadFormatDesc->bNumFrameDescriptors) { //@@ERROR //@@Descriptor Field - bDefaultFrameIndex //@@The value for bDefaultFrameIndex is not greater than 0 or less than or equal to bNumFrameDescriptors AppendTextBuffer("*!*ERROR: The value %d for the bDefaultFrameIndex is out of range, this invalidates the descriptor\r\n*!*The proper range is 1 to %d)", FramePayloadFormatDesc->bDefaultFrameIndex, FramePayloadFormatDesc->bNumFrameDescriptors); OOPS(); } AppendTextBuffer("bAspectRatioX: 0x%02X\r\n", FramePayloadFormatDesc->bAspectRatioX); AppendTextBuffer("bAspectRatioY: 0x%02X", FramePayloadFormatDesc->bAspectRatioY); if (((FramePayloadFormatDesc->bmInterlaceFlags & 0x01) && (FramePayloadFormatDesc->bAspectRatioY != 0 && FramePayloadFormatDesc->bAspectRatioX != 0))) { if(gDoAnnotation) { AppendTextBuffer(" -> Aspect Ratio is set for a %d:%d display", (FramePayloadFormatDesc->bAspectRatioX),(FramePayloadFormatDesc->bAspectRatioY)); } else { if (FramePayloadFormatDesc->bAspectRatioY != 0 || FramePayloadFormatDesc->bAspectRatioX != 0) { //@@ERROR //@@Descriptor Field - bAspectRatioX, bAspectRatioY //@@Verify that that bAspectRatioX and bAspectRatioY are set to zero //@@ if stream is non-interlaced AppendTextBuffer("\r\n*!*ERROR: Both bAspectRatioX and bAspectRatioY "\ "must equal 0 if stream is non-interlaced"); OOPS(); } } } AppendTextBuffer("\r\nbmInterlaceFlags: 0x%02X\r\n", FramePayloadFormatDesc->bmInterlaceFlags); if (gDoAnnotation) { AppendTextBuffer(" D0 = 0x%02X Interlaced stream or variable: %s\r\n", (FramePayloadFormatDesc->bmInterlaceFlags & 1), (FramePayloadFormatDesc->bmInterlaceFlags & 1) ? "Yes" : "No"); AppendTextBuffer(" D1 = 0x%02X Fields per frame: %s\r\n", ((FramePayloadFormatDesc->bmInterlaceFlags >> 1) & 1), ((FramePayloadFormatDesc->bmInterlaceFlags >> 1) & 1) ? "1 field" : "2 fields"); AppendTextBuffer(" D2 = 0x%02X Field 1 first: %s\r\n", ((FramePayloadFormatDesc->bmInterlaceFlags >> 2) & 1), ((FramePayloadFormatDesc->bmInterlaceFlags >> 2) & 1) ? "Yes" : "No"); //@@Descriptor Field - bmInterlaceFlags //@@Validate that reserved bits (D3) are set to zero. AppendTextBuffer(" D3 = 0x%02X Reserved%s\r\n", ((FramePayloadFormatDesc->bmInterlaceFlags >> 3) & 1), ((FramePayloadFormatDesc->bmInterlaceFlags >> 3) & 1) ? "\r\n*!*ERROR: Reserved to 0" : "" ); AppendTextBuffer(" D4..5 = 0x%02X Field patterns ->", ((FramePayloadFormatDesc->bmInterlaceFlags >> 4) & 3)); switch(FramePayloadFormatDesc->bmInterlaceFlags & 0x30) { case 0x00: AppendTextBuffer(" Field 1 only"); break; case 0x10: AppendTextBuffer(" Field 2 only"); break; case 0x20: AppendTextBuffer(" Regular Pattern of fields 1 and 2"); break; case 0x30: AppendTextBuffer(" Random Pattern of fields 1 and 2"); break; } AppendTextBuffer("\r\n D6..7 = 0x%02X Display Mode ->", ((FramePayloadFormatDesc->bmInterlaceFlags >> 6) & 3)); switch(FramePayloadFormatDesc->bmInterlaceFlags & 0xC0) { case 0x00: AppendTextBuffer(" Bob only"); break; case 0x40: AppendTextBuffer(" Weave only"); break; case 0x80: AppendTextBuffer(" Bob or weave"); break; case 0xC0: //@@Descriptor Field - bmInterlaceFlags //@@Question - Should we validate that reserved bits are set to zero? AppendTextBuffer(" Reserved"); break; } } //@@Descriptor Field - bCopyProtect //@@Question - Are their reserved bits and should we validate that //@@ reserved bits are set to zero? AppendTextBuffer("\r\nbCopyProtect: 0x%02X", FramePayloadFormatDesc->bCopyProtect); if (gDoAnnotation) { if (FramePayloadFormatDesc->bCopyProtect) AppendTextBuffer(" -> Duplication Restricted"); else AppendTextBuffer(" -> Duplication Unrestricted"); } //@@Descriptor Field - bVariableSize AppendTextBuffer("\r\nbVariableSize: 0x%02X", FramePayloadFormatDesc->bVariableSize); if (gDoAnnotation) { if (FramePayloadFormatDesc->bVariableSize) AppendTextBuffer(" -> Variable Size"); else AppendTextBuffer(" -> Fixed Size"); } AppendTextBuffer("\r\n"); // Check that the correct number of Frame Descriptors and one Color Matching // descriptor follow CheckForColorMatchingDesc ((PVIDEO_SPECIFIC) FramePayloadFormatDesc, FramePayloadFormatDesc->bNumFrameDescriptors, VS_FRAME_FRAME_BASED); // This descriptor is new for UVC 1.1 if (UVC10 == g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC 1.0 devices\r\n"); } return TRUE; } //***************************************************************************** // // DisplayFramePayloadFrame() // //***************************************************************************** BOOL DisplayFramePayloadFrame ( PVIDEO_FRAME_FRAME FramePayloadFrameDesc ) { size_t bLength = 0; bLength = SizeOfVideoFrameFrame(FramePayloadFrameDesc); //@@DisplayFramePayloadFrame -Frame Based Payload Frame AppendTextBuffer("\r\n ===>Video Streaming Frame Based Payload Frame Type Descriptor<===\r\n"); if (gDoAnnotation) { if(FramePayloadFrameDesc->bFrameIndex == g_chFrameBasedFrameDefault) { AppendTextBuffer(" --->This is the Default (optimum) Frame index\r\n"); } } AppendTextBuffer("bLength: 0x%02X\r\n", FramePayloadFrameDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", FramePayloadFrameDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", FramePayloadFrameDesc->bDescriptorSubtype); AppendTextBuffer("bFrameIndex: 0x%02X\r\n", FramePayloadFrameDesc->bFrameIndex); AppendTextBuffer("bmCapabilities: 0x%02X\r\n", FramePayloadFrameDesc->bmCapabilities); AppendTextBuffer("wWidth: 0x%04X = %d\r\n", FramePayloadFrameDesc->wWidth, FramePayloadFrameDesc->wWidth); AppendTextBuffer("wHeight: 0x%04X = %d\r\n", FramePayloadFrameDesc->wHeight, FramePayloadFrameDesc->wHeight); AppendTextBuffer("dwMinBitRate: 0x%08X\r\n", FramePayloadFrameDesc->dwMinBitRate); AppendTextBuffer("dwMaxBitRate: 0x%08X\r\n", FramePayloadFrameDesc->dwMaxBitRate); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwDefaultFrameInterval: 0x%08X = %lf mSec (%4.2f Hz)\r\n", FramePayloadFrameDesc->dwDefaultFrameInterval, ((double)FramePayloadFrameDesc->dwDefaultFrameInterval)/10000.0, (10000000.0/((double)FramePayloadFrameDesc->dwDefaultFrameInterval)) ); AppendTextBuffer("bFrameIntervalType: 0x%02X\r\n", FramePayloadFrameDesc->bFrameIntervalType); if (FramePayloadFrameDesc->bLength != bLength) { //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required //@@length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", FramePayloadFrameDesc->bLength, bLength); OOPS(); } if (FramePayloadFrameDesc->bFrameIndex == 0 ) { //@@ERROR //@@Descriptor Field - bFrameIndex //@@bFrameIndex must be nonzero AppendTextBuffer("*!*ERROR: bFrameIndex = 0, this is a 1 based index\r\n"); OOPS(); } //@@Descriptor Field - bmCapabilities //@@Question: Should we try to verify that bmCapabilities is valid? // AppendTextBuffer("bmCapabilities: 0x%02X\r\n", UnCompFrameDesc->bmCapabilities); if (FramePayloadFrameDesc->wWidth == 0 ) { //@@ERROR //@@Descriptor Field - wWidth //@@wWidth must be nonzero AppendTextBuffer("*!*ERROR: wWidth must be nonzero\r\n"); OOPS(); } if (FramePayloadFrameDesc->wHeight == 0 ) { //@@ERROR //@@Descriptor Field - wHeight //@@wHeight must be nonzero AppendTextBuffer("*!*ERROR: wHeight must be nonzero\r\n"); OOPS(); } if (FramePayloadFrameDesc->dwMinBitRate == 0 ) { //@@ERROR //@@Descriptor Field - dwMinBitRate //@@dwMinBitRate must be nonzero AppendTextBuffer("*!*ERROR: dwMinBitRate must be nonzero\r\n"); OOPS(); } if (FramePayloadFrameDesc->dwMaxBitRate == 0 ) { //@@ERROR //@@Descriptor Field - dwMaxBitRate //@@dwMaxBitRate must be nonzero AppendTextBuffer("*!*ERROR: dwMaxBitRate must be nonzero\r\n"); OOPS(); } if(FramePayloadFrameDesc->dwMinBitRate > FramePayloadFrameDesc->dwMaxBitRate) { //@@ERROR //@@Descriptor Field - dwMinBitRate and dwMaxBitRate //@@Verify that dwMaxBitRate is greater than dwMinBitRate AppendTextBuffer("*!*ERROR: dwMinBitRate should be less than dwMaxBitRate\r\n"); OOPS(); } else { if (FramePayloadFrameDesc->bFrameIntervalType == 1 && FramePayloadFrameDesc->dwMinBitRate != FramePayloadFrameDesc->dwMaxBitRate) { //@@WARNING //@@Descriptor Field - bFrameIntervalType, dwMinBitRate, and dwMaxBitRate //@@Verify that dwMaxBitRate is equal to dwMinBitRate if bFrameIntervalType is 1 AppendTextBuffer("*!*WARNING: if bFrameIntervalType is 1 then dwMinBitRate "\ "should equal dwMaxBitRate\r\n"); OOPS(); } } if (FramePayloadFrameDesc->dwDefaultFrameInterval == 0 ) { //@@TestCase B16.11 (descript.c line 1020) //@@WARNING //@@Descriptor Field - dwDefaultFrameInterval //@@dwDefaultFrameInterval must be nonzero AppendTextBuffer("*!*WARNING: dwDefaultFrameInterval must be nonzero\r\n"); OOPS(); } if (0 == FramePayloadFrameDesc->bFrameIntervalType) { DisplayFramePayloadContinuousFrameType(FramePayloadFrameDesc); } else { DisplayFramePayloadDiscreteFrameType(FramePayloadFrameDesc); } // This descriptor is new for UVC 1.1 if (UVC10 == g_chUVCversion) { AppendTextBuffer("*!*ERROR: This format is NOT ALLOWED for UVC 1.0 devices\r\n"); } return TRUE; } //***************************************************************************** // // DisplayFramePayloadContinuousFrameType() // //***************************************************************************** BOOL DisplayFramePayloadContinuousFrameType( PVIDEO_FRAME_FRAME FContinuousDesc ) { //@@DisplayFramePayloadContinuousFrameType -Frame Payload Continuous Frame ULONG dwMinFrameInterval = FContinuousDesc->adwFrameInterval[0]; ULONG dwMaxFrameInterval = FContinuousDesc->adwFrameInterval[1]; ULONG dwFrameIntervalStep = FContinuousDesc->adwFrameInterval[2]; AppendTextBuffer("===>Additional Continuous Frame Type Data\r\n"); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwMinFrameInterval: 0x%08X = %lf mSec (%d Hz)\r\n", dwMinFrameInterval, ((double)dwMinFrameInterval)/10000.0, (ULONG)(10000000.0/((double)dwMinFrameInterval) + 0.5)); AppendTextBuffer("dwMaxFrameInterval: 0x%08X = %lf mSec (%d Hz)\r\n", dwMaxFrameInterval, ((double)dwMaxFrameInterval)/10000.0, (ULONG)(10000000.0/((double)dwMaxFrameInterval) + 0.5)); AppendTextBuffer("dwFrameIntervalStep: 0x%08X\r\n", dwFrameIntervalStep); if (dwMinFrameInterval == 0 ) { //@@ERROR //@@Descriptor Field - dwMinFrameInterval //@@dwMinFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMinFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if (dwMaxFrameInterval == 0 ) { //@@ERROR //@@Descriptor Field - dwMaxFrameInterval //@@dwMaxFrameInterval is set to zero which is not in accordance with the USB Video Device Specification AppendTextBuffer("*!*ERROR: dwMaxFrameInterval = 0, this invalidates the descriptor\r\n"); OOPS(); } if(dwMinFrameInterval > dwMaxFrameInterval) { //@@ERROR //@@Descriptor Field - dwMinFrameInterval and dwMaxFrameInterval //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval AppendTextBuffer("*!*ERROR: dwMinFrameInterval is larger that dwMaxFrameInterval, this invalidates the descriptor\r\n"); OOPS(); } else if ((dwMinFrameInterval + dwFrameIntervalStep) > dwMaxFrameInterval) { //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval combined with dwFrameIntervalStep AppendTextBuffer("*!*WARNING: dwMinFrameInterval + dwFrameIntervalStep is greater than dwMaxFrameInterval, this could cause problems\r\n"); OOPS(); } else if ((dwMaxFrameInterval - dwMinFrameInterval) == 0 ) { //@@CAUTION //@@Descriptor Field - dwFrameIntervalStep //@@Suggestion to use descrite frames if dwFrameIntervalStep is zero AppendTextBuffer("*!*CAUTION: dwFrameIntervalStep equals zero, consider using discrete frames\r\n"); OOPS(); } else if ((dwMaxFrameInterval - dwMinFrameInterval) % dwFrameIntervalStep ) { //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that the difference between dwMaxFrameInterval and dwMinFrameInterval is evenly divisible by dwFrameIntervalStep AppendTextBuffer("*!*WARNING: dwMaxFrameInterval minus dwMinFrameInterval is not evenly divisible by dwFrameIntervalStep, this could cause problems\r\n"); OOPS(); } if (dwFrameIntervalStep == 0 && (dwMaxFrameInterval - dwMinFrameInterval)) { //@@WARNING //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval //@@Verify that the dwFrameIntervalStep is not zero if there is a difference between dwMaxFrameInterval and dwMinFrameInterval AppendTextBuffer("*!*WARNING: dwFrameIntervalStep = 0, this invalidates the descriptor when there is a difference between dwMinFrameInterval and dwMaxFrameInterval\r\n"); OOPS(); } return TRUE; } //***************************************************************************** // // DisplayFramePayloadDiscreteFrameType() // //***************************************************************************** BOOL DisplayFramePayloadDiscreteFrameType( PVIDEO_FRAME_FRAME FDiscreteDesc ) { //@@DisplayFramePayloadDiscreteFrameType -Frame Based Payload Discrete Frame UINT iNdex = 1; UINT iCurFrame = 0; ULONG * ulFrameInterval = NULL; AppendTextBuffer("===>Additional Discrete Frame Type Data\r\n"); // There are (UDiscreteDesc->bFrameIntervalType) dwFrameIntervals (1 based index) for (; iNdex <= FDiscreteDesc->bFrameIntervalType; iNdex++, iCurFrame++) { ulFrameInterval = &FDiscreteDesc->adwFrameInterval[iCurFrame]; // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse AppendTextBuffer("dwFrameInterval[%d]: 0x%08X = %lf mSec (%4.2f Hz)\r\n", iNdex, *ulFrameInterval, ((double)*ulFrameInterval)/10000.0, (10000000.0/((double)*ulFrameInterval)) ); if (0 == *ulFrameInterval) { //@@TestCase B18.1 (descript.c line 1061) //@@ERROR //@@Descriptor Field - dwFrameInterval[x] //@@dwFrameInterval[x] must be non-zero AppendTextBuffer("*!*ERROR: dwFrameInterval[%d] must be non-zero\r\n", iNdex); OOPS(); } if ((iNdex > 1)&&(*ulFrameInterval <= FDiscreteDesc->adwFrameInterval[iCurFrame - 1])) { //@@TestCase B18.2 (descript.c line 1067) //@@ERROR //@@Descriptor Field - dwFrameInterval[x] //@@dwFrameInterval[n] must be greater than dwFrameInterval[n - 1] AppendTextBuffer("*!*ERROR: dwFrameInterval[0x%02X] must be "\ "greater than preceding dwFrameInterval[0x%02X]\r\n", iNdex, iNdex - 1); OOPS(); } } return TRUE; } //***************************************************************************** // // DisplayVSEndpoint() // //***************************************************************************** BOOL DisplayVSEndpoint ( PVIDEO_CS_INTERRUPT VidEndpointDesc ) { //@@DisplayVSEndpoint - Video Streaming Endpoint AppendTextBuffer("\r\n ===>Class-specific VC Interrupt Endpoint Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X \r\n", VidEndpointDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X\r\n", VidEndpointDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X\r\n", VidEndpointDesc->bDescriptorSubtype); AppendTextBuffer("wMaxTransferSize: 0x%04X", VidEndpointDesc->wMaxTransferSize); if(gDoAnnotation) { AppendTextBuffer(" = (%d) Bytes\r\n", VidEndpointDesc->wMaxTransferSize);} else {AppendTextBuffer("\r\n");} if (VidEndpointDesc->bLength != sizeof(VIDEO_CS_INTERRUPT)) { //@@TestCase B32.1 (descript.c line 1616) //@@ERROR //@@Descriptor Field - bLength //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d. USBView cannot correctly display descriptor\r\n", VidEndpointDesc->bLength, sizeof(VIDEO_CS_INTERRUPT)); OOPS(); } return TRUE; } //***************************************************************************** // // VDisplayBytes() // //***************************************************************************** VOID VDisplayBytes ( PUCHAR Data, USHORT Len ) { USHORT i = 0; for (i = 0; i < Len; i++) { AppendTextBuffer("0x%02X ", Data[i]); if (i % 16 == 15) { AppendTextBuffer("\r\n"); } } if (i % 16 != 0) { AppendTextBuffer("\r\n"); } } //***************************************************************************** // // VidFormatGUIDCodeToName() // //***************************************************************************** PCHAR VidFormatGUIDCodeToName ( REFGUID VidFormatGUIDCode ) { // GUID pYUY2 = YUY2_Format; // GUID pNV12 = NV12_Format; if (IsEqualGUID(VidFormatGUIDCode, (REFGUID) &YUY2_Format)) { return (PCHAR) &"YUY2"; } if (IsEqualGUID(VidFormatGUIDCode, (REFGUID) &NV12_Format)) { return (PCHAR) &"NV12"; } #ifdef H264_SUPPORT // GUID pH264 = H264_Format; if (IsEqualGUID(VidFormatGUIDCode, (REFGUID) &H264_Format)) { return (PCHAR) &"H.264"; } #endif return FALSE; } /***************************************************************************** GetVCInterfaceSize() *****************************************************************************/ UINT GetVCInterfaceSize ( PVIDEO_CONTROL_HEADER_UNIT VCInterfaceDesc ) { PUSB_COMMON_DESCRIPTOR commonDesc = (PUSB_COMMON_DESCRIPTOR) VCInterfaceDesc; PUCHAR descEnd = (PUCHAR) VCInterfaceDesc + VCInterfaceDesc->wTotalLength; UINT uCount = 0; // return this interface's sum of descriptor lengths // starting from this header until (and not including) the first endpoint while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { if (commonDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) break; uCount += commonDesc->bLength; commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); } return (uCount); } /***************************************************************************** CheckForColorMatchingDesc () Given starting address of format descriptor; number of frame descriptors; subtype of frame to look for; 1) walk through each descriptor = if desc is frame of given subtype, update counter = if desc is still frame, update counter = if desc is color matching descriptor, update counter ! if frame is something else, break (all these frames should be consecutive) ! if next frame is beyond ending address of configuration, break PASS frame count == numframes passed in color match == 1 still frames are handled in the video stream input header and the frame displays *****************************************************************************/ UINT CheckForColorMatchingDesc ( PVIDEO_SPECIFIC pFormatDesc, UCHAR bNumFrameDescriptors, UCHAR bDescriptorSubtype ) { UINT uFrameCount = 0; UINT uStillFrameCount = 0; UINT uColorCount = 0; // DONE if the descriptor address is beyond the configuration range for ( ; ValidateDescAddress ((PUSB_COMMON_DESCRIPTOR) pFormatDesc); ) { // DONE if it's not an interface desc if (CS_INTERFACE != pFormatDesc->bDescriptorType) { break; } switch (pFormatDesc->bDescriptorSubtype) { case VS_STILL_IMAGE_FRAME: uStillFrameCount++; break; case VS_COLORFORMAT: uColorCount++; break; default: if (bDescriptorSubtype == pFormatDesc->bDescriptorSubtype) { uFrameCount++; } break; } pFormatDesc = (PVIDEO_SPECIFIC) ((PUCHAR) pFormatDesc + pFormatDesc->bLength); } if (uFrameCount != bNumFrameDescriptors) { AppendTextBuffer("*!*ERROR: Found %d frame descriptors (should be %d)\r\n", uFrameCount, bNumFrameDescriptors); } // We already check Still Frames in the Video Info Header and Still Frames displays if (0 == uColorCount) { AppendTextBuffer("*!*ERROR: no Color Matching Descriptor for this format\r\n"); } return (uColorCount); } /***************************************************************************** GetVSInterfaceSize() *****************************************************************************/ UINT GetVSInterfaceSize ( PUSB_COMMON_DESCRIPTOR VidInHeaderDesc, USHORT wTotalLength ) { PUSB_COMMON_DESCRIPTOR commonDesc = (PUSB_COMMON_DESCRIPTOR) VidInHeaderDesc; PUCHAR descEnd = (PUCHAR) VidInHeaderDesc + wTotalLength; UINT uCount = 0; // return this interface's sum of descriptor lengths // starting from this header until (and not including) the first endpoint while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { if (commonDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) break; uCount += commonDesc->bLength; commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); } return (uCount); } /***************************************************************************** ValidateTerminalID() *****************************************************************************/ BOOL ValidateTerminalID( UINT uTerminalID ) { UNREFERENCED_PARAMETER(uTerminalID); return (TRUE); } ================================================ FILE: tests/projects/windows/winsdk/usbview/enum.c ================================================ /*++ Copyright (c) 1997-2011 Microsoft Corporation Module Name: ENUM.C Abstract: This source file contains the routines which enumerate the USB bus and populate the TreeView control. The enumeration process goes like this: (1) Enumerate Host Controllers and Root Hubs EnumerateHostControllers() EnumerateHostController() Host controllers currently have symbolic link names of the form HCDx, where x starts at 0. Use CreateFile() to open each host controller symbolic link. Create a node in the TreeView to represent each host controller. GetRootHubName() After a host controller has been opened, send the host controller an IOCTL_USB_GET_ROOT_HUB_NAME request to get the symbolic link name of the root hub that is part of the host controller. (2) Enumerate Hubs (Root Hubs and External Hubs) EnumerateHub() Given the name of a hub, use CreateFile() to map the hub. Send the hub an IOCTL_USB_GET_NODE_INFORMATION request to get info about the hub, such as the number of downstream ports. Create a node in the TreeView to represent each hub. (3) Enumerate Downstream Ports EnumerateHubPorts() Given an handle to an open hub and the number of downstream ports on the hub, send the hub an IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX request for each downstream port of the hub to get info about the device (if any) attached to each port. If there is a device attached to a port, send the hub an IOCTL_USB_GET_NODE_CONNECTION_NAME request to get the symbolic link name of the hub attached to the downstream port. If there is a hub attached to the downstream port, recurse to step (2). GetAllStringDescriptors() GetConfigDescriptor() Create a node in the TreeView to represent each hub port and attached device. Environment: user mode Revision History: 04-25-97 : created --*/ //***************************************************************************** // I N C L U D E S //***************************************************************************** #include "uvcview.h" //***************************************************************************** // D E F I N E S //***************************************************************************** #define NUM_STRING_DESC_TO_GET 32 //***************************************************************************** // L O C A L F U N C T I O N P R O T O T Y P E S //***************************************************************************** VOID EnumerateHostControllers ( HTREEITEM hTreeParent, ULONG *DevicesConnected ); VOID EnumerateHostController ( HTREEITEM hTreeParent, HANDLE hHCDev, _Inout_ PCHAR leafName, _In_ HANDLE deviceInfo, _In_ PSP_DEVINFO_DATA deviceInfoData ); VOID EnumerateHub ( HTREEITEM hTreeParent, _In_reads_(cbHubName) PCHAR HubName, _In_ size_t cbHubName, _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo, _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2, _In_opt_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, _In_opt_ PUSB_DESCRIPTOR_REQUEST ConfigDesc, _In_opt_ PUSB_DESCRIPTOR_REQUEST BosDesc, _In_opt_ PSTRING_DESCRIPTOR_NODE StringDescs, _In_opt_ PUSB_DEVICE_PNP_STRINGS DevProps ); VOID EnumerateHubPorts ( HTREEITEM hTreeParent, HANDLE hHubDevice, ULONG NumPorts ); PCHAR GetRootHubName ( HANDLE HostController ); PCHAR GetExternalHubName ( HANDLE Hub, ULONG ConnectionIndex ); PCHAR GetHCDDriverKeyName ( HANDLE HCD ); PCHAR GetDriverKeyName ( HANDLE Hub, ULONG ConnectionIndex ); PUSB_DESCRIPTOR_REQUEST GetConfigDescriptor ( HANDLE hHubDevice, ULONG ConnectionIndex, UCHAR DescriptorIndex ); PUSB_DESCRIPTOR_REQUEST GetBOSDescriptor ( HANDLE hHubDevice, ULONG ConnectionIndex ); DWORD GetHostControllerPowerMap( HANDLE hHCDev, PUSBHOSTCONTROLLERINFO hcInfo); DWORD GetHostControllerInfo( HANDLE hHCDev, PUSBHOSTCONTROLLERINFO hcInfo); PCHAR WideStrToMultiStr ( _In_reads_bytes_(cbWideStr) PWCHAR WideStr, _In_ size_t cbWideStr ); BOOL AreThereStringDescriptors ( PUSB_DEVICE_DESCRIPTOR DeviceDesc, PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc ); PSTRING_DESCRIPTOR_NODE GetAllStringDescriptors ( HANDLE hHubDevice, ULONG ConnectionIndex, PUSB_DEVICE_DESCRIPTOR DeviceDesc, PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc ); PSTRING_DESCRIPTOR_NODE GetStringDescriptor ( HANDLE hHubDevice, ULONG ConnectionIndex, UCHAR DescriptorIndex, USHORT LanguageID ); HRESULT GetStringDescriptors ( _In_ HANDLE hHubDevice, _In_ ULONG ConnectionIndex, _In_ UCHAR DescriptorIndex, _In_ ULONG NumLanguageIDs, _In_reads_(NumLanguageIDs) USHORT *LanguageIDs, _In_ PSTRING_DESCRIPTOR_NODE StringDescNodeHead ); void EnumerateAllDevices(); void EnumerateAllDevicesWithGuid( PDEVICE_GUID_LIST DeviceList, LPGUID Guid ); void FreeDeviceInfoNode( _In_ PDEVICE_INFO_NODE *ppNode ); PDEVICE_INFO_NODE FindMatchingDeviceNodeForDriverName( _In_ PSTR DriverKeyName, _In_ BOOLEAN IsHub ); //***************************************************************************** // G L O B A L S //***************************************************************************** // List of enumerated host controllers. // LIST_ENTRY EnumeratedHCListHead = { &EnumeratedHCListHead, &EnumeratedHCListHead }; DEVICE_GUID_LIST gHubList; DEVICE_GUID_LIST gDeviceList; //***************************************************************************** // G L O B A L S P R I V A T E T O T H I S F I L E //***************************************************************************** PCHAR ConnectionStatuses[] = { "", // 0 - NoDeviceConnected "", // 1 - DeviceConnected "FailedEnumeration", // 2 - DeviceFailedEnumeration "GeneralFailure", // 3 - DeviceGeneralFailure "Overcurrent", // 4 - DeviceCausedOvercurrent "NotEnoughPower", // 5 - DeviceNotEnoughPower "NotEnoughBandwidth", // 6 - DeviceNotEnoughBandwidth "HubNestedTooDeeply", // 7 - DeviceHubNestedTooDeeply "InLegacyHub", // 8 - DeviceInLegacyHub "Enumerating", // 9 - DeviceEnumerating "Reset" // 10 - DeviceReset }; ULONG TotalDevicesConnected; //***************************************************************************** // // EnumerateHostControllers() // // hTreeParent - Handle of the TreeView item under which host controllers // should be added. // //***************************************************************************** VOID EnumerateHostControllers ( HTREEITEM hTreeParent, ULONG *DevicesConnected ) { HANDLE hHCDev = NULL; HDEVINFO deviceInfo = NULL; SP_DEVINFO_DATA deviceInfoData; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetailData = NULL; ULONG index = 0; ULONG requiredLength = 0; BOOL success; TotalDevicesConnected = 0; TotalHubs = 0; EnumerateAllDevices(); // Iterate over host controllers using the new GUID based interface // deviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); for (index=0; SetupDiEnumDeviceInfo(deviceInfo, index, &deviceInfoData); index++) { deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); success = SetupDiEnumDeviceInterfaces(deviceInfo, 0, (LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER, index, &deviceInterfaceData); if (!success) { OOPS(); break; } success = SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, NULL, 0, &requiredLength, NULL); if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER) { OOPS(); break; } deviceDetailData = ALLOC(requiredLength); if (deviceDetailData == NULL) { OOPS(); break; } deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); success = SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, deviceDetailData, requiredLength, &requiredLength, NULL); if (!success) { OOPS(); break; } hHCDev = CreateFile(deviceDetailData->DevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); // If the handle is valid, then we've successfully opened a Host // Controller. Display some info about the Host Controller itself, // then enumerate the Root Hub attached to the Host Controller. // if (hHCDev != INVALID_HANDLE_VALUE) { EnumerateHostController(hTreeParent, hHCDev, deviceDetailData->DevicePath, deviceInfo, &deviceInfoData); CloseHandle(hHCDev); } FREE(deviceDetailData); } SetupDiDestroyDeviceInfoList(deviceInfo); *DevicesConnected = TotalDevicesConnected; return; } //***************************************************************************** // // EnumerateHostController() // // hTreeParent - Handle of the TreeView item under which host controllers // should be added. // //***************************************************************************** VOID EnumerateHostController ( HTREEITEM hTreeParent, HANDLE hHCDev, _Inout_ PCHAR leafName, _In_ HANDLE deviceInfo, _In_ PSP_DEVINFO_DATA deviceInfoData ) { PCHAR driverKeyName = NULL; HTREEITEM hHCItem = NULL; PCHAR rootHubName = NULL; PLIST_ENTRY listEntry = NULL; PUSBHOSTCONTROLLERINFO hcInfo = NULL; PUSBHOSTCONTROLLERINFO hcInfoInList = NULL; DWORD dwSuccess; BOOL success = FALSE; ULONG deviceAndFunction = 0; PUSB_DEVICE_PNP_STRINGS DevProps = NULL; // Allocate a structure to hold information about this host controller. // hcInfo = (PUSBHOSTCONTROLLERINFO)ALLOC(sizeof(USBHOSTCONTROLLERINFO)); // just return if could not alloc memory if (NULL == hcInfo) return; hcInfo->DeviceInfoType = HostControllerInfo; // Obtain the driver key name for this host controller. // driverKeyName = GetHCDDriverKeyName(hHCDev); if (NULL == driverKeyName) { // Failure obtaining driver key name. OOPS(); FREE(hcInfo); return; } // Don't enumerate this host controller again if it already // on the list of enumerated host controllers. // listEntry = EnumeratedHCListHead.Flink; while (listEntry != &EnumeratedHCListHead) { hcInfoInList = CONTAINING_RECORD(listEntry, USBHOSTCONTROLLERINFO, ListEntry); if (strcmp(driverKeyName, hcInfoInList->DriverKey) == 0) { // Already on the list, exit // FREE(driverKeyName); FREE(hcInfo); return; } listEntry = listEntry->Flink; } // Obtain host controller device properties { size_t cbDriverName = 0; HRESULT hr = S_OK; hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName); if (SUCCEEDED(hr)) { DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName); } } hcInfo->DriverKey = driverKeyName; if (DevProps) { ULONG ven, dev, subsys, rev; ven = dev = subsys = rev = 0; if (sscanf_s(DevProps->DeviceId, "PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &ven, &dev, &subsys, &rev) != 4) { OOPS(); } hcInfo->VendorID = ven; hcInfo->DeviceID = dev; hcInfo->SubSysID = subsys; hcInfo->Revision = rev; hcInfo->UsbDeviceProperties = DevProps; } else { OOPS(); } if (DevProps != NULL && DevProps->DeviceDesc != NULL) { leafName = DevProps->DeviceDesc; } else { OOPS(); } // Get the USB Host Controller power map dwSuccess = GetHostControllerPowerMap(hHCDev, hcInfo); if (ERROR_SUCCESS != dwSuccess) { OOPS(); } // Get bus, device, and function // hcInfo->BusDeviceFunctionValid = FALSE; success = SetupDiGetDeviceRegistryProperty(deviceInfo, deviceInfoData, SPDRP_BUSNUMBER, NULL, (PBYTE)&hcInfo->BusNumber, sizeof(hcInfo->BusNumber), NULL); if (success) { success = SetupDiGetDeviceRegistryProperty(deviceInfo, deviceInfoData, SPDRP_ADDRESS, NULL, (PBYTE)&deviceAndFunction, sizeof(deviceAndFunction), NULL); } if (success) { hcInfo->BusDevice = deviceAndFunction >> 16; hcInfo->BusFunction = deviceAndFunction & 0xffff; hcInfo->BusDeviceFunctionValid = TRUE; } // Get the USB Host Controller info dwSuccess = GetHostControllerInfo(hHCDev, hcInfo); if (ERROR_SUCCESS != dwSuccess) { OOPS(); } // Add this host controller to the USB device tree view. // hHCItem = AddLeaf(hTreeParent, (LPARAM)hcInfo, leafName, hcInfo->Revision == UsbSuperSpeed ? GoodSsDeviceIcon : GoodDeviceIcon); if (NULL == hHCItem) { // Failure adding host controller to USB device tree // view. OOPS(); FREE(driverKeyName); FREE(hcInfo); return; } // Add this host controller to the list of enumerated // host controllers. // InsertTailList(&EnumeratedHCListHead, &hcInfo->ListEntry); // Get the name of the root hub for this host // controller and then enumerate the root hub. // rootHubName = GetRootHubName(hHCDev); if (rootHubName != NULL) { size_t cbHubName = 0; HRESULT hr = S_OK; hr = StringCbLength(rootHubName, MAX_DRIVER_KEY_NAME, &cbHubName); if (SUCCEEDED(hr)) { EnumerateHub(hHCItem, rootHubName, cbHubName, NULL, // ConnectionInfo NULL, // ConnectionInfoV2 NULL, // PortConnectorProps NULL, // ConfigDesc NULL, // BosDesc NULL, // StringDescs NULL); // We do not pass DevProps for RootHub } } else { // Failure obtaining root hub name. OOPS(); } return; } //***************************************************************************** // // EnumerateHub() // // hTreeParent - Handle of the TreeView item under which this hub should be // added. // // HubName - Name of this hub. This pointer is kept so the caller can neither // free nor reuse this memory. // // ConnectionInfo - NULL if this is a root hub, else this is the connection // info for an external hub. This pointer is kept so the caller can neither // free nor reuse this memory. // // ConfigDesc - NULL if this is a root hub, else this is the Configuration // Descriptor for an external hub. This pointer is kept so the caller can // neither free nor reuse this memory. // // StringDescs - NULL if this is a root hub. // // DevProps - Device properties of the hub // //***************************************************************************** VOID EnumerateHub ( HTREEITEM hTreeParent, _In_reads_(cbHubName) PCHAR HubName, _In_ size_t cbHubName, _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo, _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2, _In_opt_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, _In_opt_ PUSB_DESCRIPTOR_REQUEST ConfigDesc, _In_opt_ PUSB_DESCRIPTOR_REQUEST BosDesc, _In_opt_ PSTRING_DESCRIPTOR_NODE StringDescs, _In_opt_ PUSB_DEVICE_PNP_STRINGS DevProps ) { // Initialize locals to not allocated state so the error cleanup routine // only tries to cleanup things that were successfully allocated. // PUSB_NODE_INFORMATION hubInfo = NULL; PUSB_HUB_INFORMATION_EX hubInfoEx = NULL; PUSB_HUB_CAPABILITIES_EX hubCapabilityEx = NULL; HANDLE hHubDevice = INVALID_HANDLE_VALUE; HTREEITEM hItem = NULL; PVOID info = NULL; PCHAR deviceName = NULL; ULONG nBytes = 0; BOOL success = 0; DWORD dwSizeOfLeafName = 0; CHAR leafName[512] = {0}; HRESULT hr = S_OK; size_t cchHeader = 0; size_t cchFullHubName = 0; // Allocate some space for a USBDEVICEINFO structure to hold the // hub info, hub name, and connection info pointers. GPTR zero // initializes the structure for us. // info = ALLOC(sizeof(USBEXTERNALHUBINFO)); if (info == NULL) { OOPS(); goto EnumerateHubError; } // Allocate some space for a USB_NODE_INFORMATION structure for this Hub // hubInfo = (PUSB_NODE_INFORMATION)ALLOC(sizeof(USB_NODE_INFORMATION)); if (hubInfo == NULL) { OOPS(); goto EnumerateHubError; } hubInfoEx = (PUSB_HUB_INFORMATION_EX)ALLOC(sizeof(USB_HUB_INFORMATION_EX)); if (hubInfoEx == NULL) { OOPS(); goto EnumerateHubError; } hubCapabilityEx = (PUSB_HUB_CAPABILITIES_EX)ALLOC(sizeof(USB_HUB_CAPABILITIES_EX)); if(hubCapabilityEx == NULL) { OOPS(); goto EnumerateHubError; } // Keep copies of the Hub Name, Connection Info, and Configuration // Descriptor pointers // ((PUSBROOTHUBINFO)info)->HubInfo = hubInfo; ((PUSBROOTHUBINFO)info)->HubName = HubName; if (ConnectionInfo != NULL) { ((PUSBEXTERNALHUBINFO)info)->DeviceInfoType = ExternalHubInfo; ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo = ConnectionInfo; ((PUSBEXTERNALHUBINFO)info)->ConfigDesc = ConfigDesc; ((PUSBEXTERNALHUBINFO)info)->StringDescs = StringDescs; ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps = PortConnectorProps; ((PUSBEXTERNALHUBINFO)info)->HubInfoEx = hubInfoEx; ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx = hubCapabilityEx; ((PUSBEXTERNALHUBINFO)info)->BosDesc = BosDesc; ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2 = ConnectionInfoV2; ((PUSBEXTERNALHUBINFO)info)->UsbDeviceProperties = DevProps; } else { ((PUSBROOTHUBINFO)info)->DeviceInfoType = RootHubInfo; ((PUSBROOTHUBINFO)info)->HubInfoEx = hubInfoEx; ((PUSBROOTHUBINFO)info)->HubCapabilityEx = hubCapabilityEx; ((PUSBROOTHUBINFO)info)->PortConnectorProps = PortConnectorProps; ((PUSBROOTHUBINFO)info)->UsbDeviceProperties = DevProps; } // Allocate a temp buffer for the full hub device name. // hr = StringCbLength("\\\\.\\", MAX_DEVICE_PROP, &cchHeader); if (FAILED(hr)) { goto EnumerateHubError; } cchFullHubName = cchHeader + cbHubName + 1; deviceName = (PCHAR)ALLOC((DWORD) cchFullHubName); if (deviceName == NULL) { OOPS(); goto EnumerateHubError; } // Create the full hub device name // hr = StringCchCopyN(deviceName, cchFullHubName, "\\\\.\\", cchHeader); if (FAILED(hr)) { goto EnumerateHubError; } hr = StringCchCatN(deviceName, cchFullHubName, HubName, cbHubName); if (FAILED(hr)) { goto EnumerateHubError; } // Try to hub the open device // hHubDevice = CreateFile(deviceName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); // Done with temp buffer for full hub device name // FREE(deviceName); if (hHubDevice == INVALID_HANDLE_VALUE) { OOPS(); goto EnumerateHubError; } // // Now query USBHUB for the USB_NODE_INFORMATION structure for this hub. // This will tell us the number of downstream ports to enumerate, among // other things. // success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_NODE_INFORMATION, hubInfo, sizeof(USB_NODE_INFORMATION), hubInfo, sizeof(USB_NODE_INFORMATION), &nBytes, NULL); if (!success) { OOPS(); goto EnumerateHubError; } success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_HUB_INFORMATION_EX, hubInfoEx, sizeof(USB_HUB_INFORMATION_EX), hubInfoEx, sizeof(USB_HUB_INFORMATION_EX), &nBytes, NULL); // // Fail gracefully for downlevel OS's from Win8 // if (!success || nBytes < sizeof(USB_HUB_INFORMATION_EX)) { FREE(hubInfoEx); hubInfoEx = NULL; if (ConnectionInfo != NULL) { ((PUSBEXTERNALHUBINFO)info)->HubInfoEx = NULL; } else { ((PUSBROOTHUBINFO)info)->HubInfoEx = NULL; } } // // Obtain Hub Capabilities // success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_HUB_CAPABILITIES_EX, hubCapabilityEx, sizeof(USB_HUB_CAPABILITIES_EX), hubCapabilityEx, sizeof(USB_HUB_CAPABILITIES_EX), &nBytes, NULL); // // Fail gracefully // if (!success || nBytes < sizeof(USB_HUB_CAPABILITIES_EX)) { FREE(hubCapabilityEx); hubCapabilityEx = NULL; if (ConnectionInfo != NULL) { ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx = NULL; } else { ((PUSBROOTHUBINFO)info)->HubCapabilityEx = NULL; } } // Build the leaf name from the port number and the device description // dwSizeOfLeafName = sizeof(leafName); if (ConnectionInfo) { StringCchPrintf(leafName, dwSizeOfLeafName, "[Port%d] ", ConnectionInfo->ConnectionIndex); StringCchCat(leafName, dwSizeOfLeafName, ConnectionStatuses[ConnectionInfo->ConnectionStatus]); StringCchCatN(leafName, dwSizeOfLeafName, " : ", sizeof(" : ")); } if (DevProps) { size_t cbDeviceDesc = 0; hr = StringCbLength(DevProps->DeviceDesc, MAX_DRIVER_KEY_NAME, &cbDeviceDesc); if(SUCCEEDED(hr)) { StringCchCatN(leafName, dwSizeOfLeafName, DevProps->DeviceDesc, cbDeviceDesc); } } else { if(ConnectionInfo != NULL) { // External hub StringCchCatN(leafName, dwSizeOfLeafName, HubName, cbHubName); } else { // Root hub StringCchCatN(leafName, dwSizeOfLeafName, "RootHub", sizeof("RootHub")); } } // Now add an item to the TreeView with the PUSBDEVICEINFO pointer info // as the LPARAM reference value containing everything we know about the // hub. // hItem = AddLeaf(hTreeParent, (LPARAM)info, leafName, HubIcon); if (hItem == NULL) { OOPS(); goto EnumerateHubError; } // Now recursively enumerate the ports of this hub. // EnumerateHubPorts( hItem, hHubDevice, hubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts ); CloseHandle(hHubDevice); return; EnumerateHubError: // // Clean up any stuff that got allocated // if (hHubDevice != INVALID_HANDLE_VALUE) { CloseHandle(hHubDevice); hHubDevice = INVALID_HANDLE_VALUE; } if (hubInfo) { FREE(hubInfo); } if (hubInfoEx) { FREE(hubInfoEx); } if (info) { FREE(info); } if (HubName) { FREE(HubName); } if (ConnectionInfo) { FREE(ConnectionInfo); } if (ConfigDesc) { FREE(ConfigDesc); } if (BosDesc) { FREE(BosDesc); } if (StringDescs != NULL) { PSTRING_DESCRIPTOR_NODE Next; do { Next = StringDescs->Next; FREE(StringDescs); StringDescs = Next; } while (StringDescs != NULL); } } //***************************************************************************** // // EnumerateHubPorts() // // hTreeParent - Handle of the TreeView item under which the hub port should // be added. // // hHubDevice - Handle of the hub device to enumerate. // // NumPorts - Number of ports on the hub. // //***************************************************************************** VOID EnumerateHubPorts ( HTREEITEM hTreeParent, HANDLE hHubDevice, ULONG NumPorts ) { ULONG index = 0; BOOL success = 0; HRESULT hr = S_OK; PCHAR driverKeyName = NULL; PUSB_DEVICE_PNP_STRINGS DevProps; DWORD dwSizeOfLeafName = 0; CHAR leafName[512]; int icon = 0; PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx; PUSB_PORT_CONNECTOR_PROPERTIES pPortConnectorProps; USB_PORT_CONNECTOR_PROPERTIES portConnectorProps; PUSB_DESCRIPTOR_REQUEST configDesc; PUSB_DESCRIPTOR_REQUEST bosDesc; PSTRING_DESCRIPTOR_NODE stringDescs; PUSBDEVICEINFO info; PUSB_NODE_CONNECTION_INFORMATION_EX_V2 connectionInfoExV2; PDEVICE_INFO_NODE pNode; // Loop over all ports of the hub. // // Port indices are 1 based, not 0 based. // for (index = 1; index <= NumPorts; index++) { ULONG nBytesEx; ULONG nBytes = 0; connectionInfoEx = NULL; pPortConnectorProps = NULL; ZeroMemory(&portConnectorProps, sizeof(portConnectorProps)); configDesc = NULL; bosDesc = NULL; stringDescs = NULL; info = NULL; connectionInfoExV2 = NULL; pNode = NULL; DevProps = NULL; ZeroMemory(leafName, sizeof(leafName)); // // Allocate space to hold the connection info for this port. // For now, allocate it big enough to hold info for 30 pipes. // // Endpoint numbers are 0-15. Endpoint number 0 is the standard // control endpoint which is not explicitly listed in the Configuration // Descriptor. There can be an IN endpoint and an OUT endpoint at // endpoint numbers 1-15 so there can be a maximum of 30 endpoints // per device configuration. // // Should probably size this dynamically at some point. // nBytesEx = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + (sizeof(USB_PIPE_INFO) * 30); connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)ALLOC(nBytesEx); if (connectionInfoEx == NULL) { OOPS(); break; } connectionInfoExV2 = (PUSB_NODE_CONNECTION_INFORMATION_EX_V2) ALLOC(sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2)); if (connectionInfoExV2 == NULL) { OOPS(); FREE(connectionInfoEx); break; } // // Now query USBHUB for the structures // for this port. This will tell us if a device is attached to this // port, among other things. // The fault tolerate code is executed first. // portConnectorProps.ConnectionIndex = index; success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES, &portConnectorProps, sizeof(USB_PORT_CONNECTOR_PROPERTIES), &portConnectorProps, sizeof(USB_PORT_CONNECTOR_PROPERTIES), &nBytes, NULL); if (success && nBytes == sizeof(USB_PORT_CONNECTOR_PROPERTIES)) { pPortConnectorProps = (PUSB_PORT_CONNECTOR_PROPERTIES) ALLOC(portConnectorProps.ActualLength); if (pPortConnectorProps != NULL) { pPortConnectorProps->ConnectionIndex = index; success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES, pPortConnectorProps, portConnectorProps.ActualLength, pPortConnectorProps, portConnectorProps.ActualLength, &nBytes, NULL); if (!success || nBytes < portConnectorProps.ActualLength) { FREE(pPortConnectorProps); pPortConnectorProps = NULL; } } } connectionInfoExV2->ConnectionIndex = index; connectionInfoExV2->Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2); connectionInfoExV2->SupportedUsbProtocols.Usb300 = 1; success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, connectionInfoExV2, sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2), connectionInfoExV2, sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2), &nBytes, NULL); if (!success || nBytes < sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2)) { FREE(connectionInfoExV2); connectionInfoExV2 = NULL; } connectionInfoEx->ConnectionIndex = index; success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, connectionInfoEx, nBytesEx, connectionInfoEx, nBytesEx, &nBytesEx, NULL); if (success) { // // Since the USB_NODE_CONNECTION_INFORMATION_EX is used to display // the device speed, but the hub driver doesn't support indication // of superspeed, we overwrite the value if the super speed // data structures are available and indicate the device is operating // at SuperSpeed. // if (connectionInfoEx->Speed == UsbHighSpeed && connectionInfoExV2 != NULL && (connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher || connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher)) { connectionInfoEx->Speed = UsbSuperSpeed; } } else { PUSB_NODE_CONNECTION_INFORMATION connectionInfo = NULL; // Try using IOCTL_USB_GET_NODE_CONNECTION_INFORMATION // instead of IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX // nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) + sizeof(USB_PIPE_INFO) * 30; connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)ALLOC(nBytes); if (connectionInfo == NULL) { OOPS(); FREE(connectionInfoEx); if (pPortConnectorProps != NULL) { FREE(pPortConnectorProps); } if (connectionInfoExV2 != NULL) { FREE(connectionInfoExV2); } continue; } connectionInfo->ConnectionIndex = index; success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, connectionInfo, nBytes, connectionInfo, nBytes, &nBytes, NULL); if (!success) { OOPS(); FREE(connectionInfo); FREE(connectionInfoEx); if (pPortConnectorProps != NULL) { FREE(pPortConnectorProps); } if (connectionInfoExV2 != NULL) { FREE(connectionInfoExV2); } continue; } // Copy IOCTL_USB_GET_NODE_CONNECTION_INFORMATION into // IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX structure. // connectionInfoEx->ConnectionIndex = connectionInfo->ConnectionIndex; connectionInfoEx->DeviceDescriptor = connectionInfo->DeviceDescriptor; connectionInfoEx->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue; connectionInfoEx->Speed = connectionInfo->LowSpeed ? UsbLowSpeed : UsbFullSpeed; connectionInfoEx->DeviceIsHub = connectionInfo->DeviceIsHub; connectionInfoEx->DeviceAddress = connectionInfo->DeviceAddress; connectionInfoEx->NumberOfOpenPipes = connectionInfo->NumberOfOpenPipes; connectionInfoEx->ConnectionStatus = connectionInfo->ConnectionStatus; memcpy(&connectionInfoEx->PipeList[0], &connectionInfo->PipeList[0], sizeof(USB_PIPE_INFO) * 30); FREE(connectionInfo); } // Update the count of connected devices // if (connectionInfoEx->ConnectionStatus == DeviceConnected) { TotalDevicesConnected++; } if (connectionInfoEx->DeviceIsHub) { TotalHubs++; } // If there is a device connected, get the Device Description // if (connectionInfoEx->ConnectionStatus != NoDeviceConnected) { driverKeyName = GetDriverKeyName(hHubDevice, index); if (driverKeyName) { size_t cbDriverName = 0; hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName); if (SUCCEEDED(hr)) { DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName); pNode = FindMatchingDeviceNodeForDriverName(driverKeyName, connectionInfoEx->DeviceIsHub); } FREE(driverKeyName); } } // If there is a device connected to the port, try to retrieve the // Configuration Descriptor from the device. // if (gDoConfigDesc && connectionInfoEx->ConnectionStatus == DeviceConnected) { configDesc = GetConfigDescriptor(hHubDevice, index, 0); } else { configDesc = NULL; } if (configDesc != NULL && connectionInfoEx->DeviceDescriptor.bcdUSB > 0x0200) { bosDesc = GetBOSDescriptor(hHubDevice, index); } else { bosDesc = NULL; } if (configDesc != NULL && AreThereStringDescriptors(&connectionInfoEx->DeviceDescriptor, (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1))) { stringDescs = GetAllStringDescriptors ( hHubDevice, index, &connectionInfoEx->DeviceDescriptor, (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1)); } else { stringDescs = NULL; } // If the device connected to the port is an external hub, get the // name of the external hub and recursively enumerate it. // if (connectionInfoEx->DeviceIsHub) { PCHAR extHubName; size_t cbHubName = 0; extHubName = GetExternalHubName(hHubDevice, index); if (extHubName != NULL) { hr = StringCbLength(extHubName, MAX_DRIVER_KEY_NAME, &cbHubName); if (SUCCEEDED(hr)) { EnumerateHub(hTreeParent, //hPortItem, extHubName, cbHubName, connectionInfoEx, connectionInfoExV2, pPortConnectorProps, configDesc, bosDesc, stringDescs, DevProps); } } } else { // Allocate some space for a USBDEVICEINFO structure to hold the // hub info, hub name, and connection info pointers. GPTR zero // initializes the structure for us. // info = (PUSBDEVICEINFO) ALLOC(sizeof(USBDEVICEINFO)); if (info == NULL) { OOPS(); if (configDesc != NULL) { FREE(configDesc); } if (bosDesc != NULL) { FREE(bosDesc); } FREE(connectionInfoEx); if (pPortConnectorProps != NULL) { FREE(pPortConnectorProps); } if (connectionInfoExV2 != NULL) { FREE(connectionInfoExV2); } break; } info->DeviceInfoType = DeviceInfo; info->ConnectionInfo = connectionInfoEx; info->PortConnectorProps = pPortConnectorProps; info->ConfigDesc = configDesc; info->StringDescs = stringDescs; info->BosDesc = bosDesc; info->ConnectionInfoV2 = connectionInfoExV2; info->UsbDeviceProperties = DevProps; info->DeviceInfoNode = pNode; StringCchPrintf(leafName, sizeof(leafName), "[Port%d] ", index); // Add error description if ConnectionStatus is other than NoDeviceConnected / DeviceConnected StringCchCat(leafName, sizeof(leafName), ConnectionStatuses[connectionInfoEx->ConnectionStatus]); if (DevProps) { size_t cchDeviceDesc = 0; hr = StringCbLength(DevProps->DeviceDesc, MAX_DEVICE_PROP, &cchDeviceDesc); if (FAILED(hr)) { OOPS(); } dwSizeOfLeafName = sizeof(leafName); StringCchCatN(leafName, dwSizeOfLeafName - 1, " : ", sizeof(" : ")); StringCchCatN(leafName, dwSizeOfLeafName - 1, DevProps->DeviceDesc, cchDeviceDesc ); } if (connectionInfoEx->ConnectionStatus == NoDeviceConnected) { if (connectionInfoExV2 != NULL && connectionInfoExV2->SupportedUsbProtocols.Usb300 == 1) { icon = NoSsDeviceIcon; } else { icon = NoDeviceIcon; } } else if (connectionInfoEx->CurrentConfigurationValue) { if (connectionInfoEx->Speed == UsbSuperSpeed) { icon = GoodSsDeviceIcon; } else { icon = GoodDeviceIcon; } } else { icon = BadDeviceIcon; } AddLeaf(hTreeParent, //hPortItem, (LPARAM)info, leafName, icon); } } // for } //***************************************************************************** // // WideStrToMultiStr() // //***************************************************************************** PCHAR WideStrToMultiStr ( _In_reads_bytes_(cbWideStr) PWCHAR WideStr, _In_ size_t cbWideStr ) { ULONG nBytes = 0; PCHAR MultiStr = NULL; PWCHAR pWideStr = NULL; // Use local string to guarantee zero termination pWideStr = (PWCHAR) ALLOC((DWORD) cbWideStr + sizeof(WCHAR)); if (NULL == pWideStr) { return NULL; } memset(pWideStr, 0, cbWideStr + sizeof(WCHAR)); memcpy(pWideStr, WideStr, cbWideStr); // Get the length of the converted string // nBytes = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, pWideStr, -1, NULL, 0, NULL, NULL); if (nBytes == 0) { FREE(pWideStr); return NULL; } // Allocate space to hold the converted string // MultiStr = ALLOC(nBytes); if (MultiStr == NULL) { FREE(pWideStr); return NULL; } // Convert the string // nBytes = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, pWideStr, -1, MultiStr, nBytes, NULL, NULL); if (nBytes == 0) { FREE(MultiStr); FREE(pWideStr); return NULL; } FREE(pWideStr); return MultiStr; } //***************************************************************************** // // GetRootHubName() // //***************************************************************************** PCHAR GetRootHubName ( HANDLE HostController ) { BOOL success = 0; ULONG nBytes = 0; USB_ROOT_HUB_NAME rootHubName; PUSB_ROOT_HUB_NAME rootHubNameW = NULL; PCHAR rootHubNameA = NULL; // Get the length of the name of the Root Hub attached to the // Host Controller // success = DeviceIoControl(HostController, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0, &rootHubName, sizeof(rootHubName), &nBytes, NULL); if (!success) { OOPS(); goto GetRootHubNameError; } // Allocate space to hold the Root Hub name // nBytes = rootHubName.ActualLength; rootHubNameW = ALLOC(nBytes); if (rootHubNameW == NULL) { OOPS(); goto GetRootHubNameError; } // Get the name of the Root Hub attached to the Host Controller // success = DeviceIoControl(HostController, IOCTL_USB_GET_ROOT_HUB_NAME, NULL, 0, rootHubNameW, nBytes, &nBytes, NULL); if (!success) { OOPS(); goto GetRootHubNameError; } // Convert the Root Hub name // rootHubNameA = WideStrToMultiStr(rootHubNameW->RootHubName, nBytes - sizeof(USB_ROOT_HUB_NAME) + sizeof(WCHAR)); // All done, free the uncoverted Root Hub name and return the // converted Root Hub name // FREE(rootHubNameW); return rootHubNameA; GetRootHubNameError: // There was an error, free anything that was allocated // if (rootHubNameW != NULL) { FREE(rootHubNameW); rootHubNameW = NULL; } return NULL; } //***************************************************************************** // // GetExternalHubName() // //***************************************************************************** PCHAR GetExternalHubName ( HANDLE Hub, ULONG ConnectionIndex ) { BOOL success = 0; ULONG nBytes = 0; USB_NODE_CONNECTION_NAME extHubName; PUSB_NODE_CONNECTION_NAME extHubNameW = NULL; PCHAR extHubNameA = NULL; // Get the length of the name of the external hub attached to the // specified port. // extHubName.ConnectionIndex = ConnectionIndex; success = DeviceIoControl(Hub, IOCTL_USB_GET_NODE_CONNECTION_NAME, &extHubName, sizeof(extHubName), &extHubName, sizeof(extHubName), &nBytes, NULL); if (!success) { OOPS(); goto GetExternalHubNameError; } // Allocate space to hold the external hub name // nBytes = extHubName.ActualLength; if (nBytes <= sizeof(extHubName)) { OOPS(); goto GetExternalHubNameError; } extHubNameW = ALLOC(nBytes); if (extHubNameW == NULL) { OOPS(); goto GetExternalHubNameError; } // Get the name of the external hub attached to the specified port // extHubNameW->ConnectionIndex = ConnectionIndex; success = DeviceIoControl(Hub, IOCTL_USB_GET_NODE_CONNECTION_NAME, extHubNameW, nBytes, extHubNameW, nBytes, &nBytes, NULL); if (!success) { OOPS(); goto GetExternalHubNameError; } // Convert the External Hub name // extHubNameA = WideStrToMultiStr(extHubNameW->NodeName, nBytes - sizeof(USB_NODE_CONNECTION_NAME) + sizeof(WCHAR)); // All done, free the uncoverted external hub name and return the // converted external hub name // FREE(extHubNameW); return extHubNameA; GetExternalHubNameError: // There was an error, free anything that was allocated // if (extHubNameW != NULL) { FREE(extHubNameW); extHubNameW = NULL; } return NULL; } //***************************************************************************** // // GetDriverKeyName() // //***************************************************************************** PCHAR GetDriverKeyName ( HANDLE Hub, ULONG ConnectionIndex ) { BOOL success = 0; ULONG nBytes = 0; USB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyName; PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW = NULL; PCHAR driverKeyNameA = NULL; // Get the length of the name of the driver key of the device attached to // the specified port. // driverKeyName.ConnectionIndex = ConnectionIndex; success = DeviceIoControl(Hub, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, &driverKeyName, sizeof(driverKeyName), &driverKeyName, sizeof(driverKeyName), &nBytes, NULL); if (!success) { OOPS(); goto GetDriverKeyNameError; } // Allocate space to hold the driver key name // nBytes = driverKeyName.ActualLength; if (nBytes <= sizeof(driverKeyName)) { OOPS(); goto GetDriverKeyNameError; } driverKeyNameW = ALLOC(nBytes); if (driverKeyNameW == NULL) { OOPS(); goto GetDriverKeyNameError; } // Get the name of the driver key of the device attached to // the specified port. // driverKeyNameW->ConnectionIndex = ConnectionIndex; success = DeviceIoControl(Hub, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKeyNameW, nBytes, driverKeyNameW, nBytes, &nBytes, NULL); if (!success) { OOPS(); goto GetDriverKeyNameError; } // Convert the driver key name // driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName, nBytes - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) + sizeof(WCHAR)); // All done, free the uncoverted driver key name and return the // converted driver key name // FREE(driverKeyNameW); return driverKeyNameA; GetDriverKeyNameError: // There was an error, free anything that was allocated // if (driverKeyNameW != NULL) { FREE(driverKeyNameW); driverKeyNameW = NULL; } return NULL; } //***************************************************************************** // // GetHCDDriverKeyName() // //***************************************************************************** PCHAR GetHCDDriverKeyName ( HANDLE HCD ) { BOOL success = 0; ULONG nBytes = 0; USB_HCD_DRIVERKEY_NAME driverKeyName = {0}; PUSB_HCD_DRIVERKEY_NAME driverKeyNameW = NULL; PCHAR driverKeyNameA = NULL; ZeroMemory(&driverKeyName, sizeof(driverKeyName)); // Get the length of the name of the driver key of the HCD // success = DeviceIoControl(HCD, IOCTL_GET_HCD_DRIVERKEY_NAME, &driverKeyName, sizeof(driverKeyName), &driverKeyName, sizeof(driverKeyName), &nBytes, NULL); if (!success) { OOPS(); goto GetHCDDriverKeyNameError; } // Allocate space to hold the driver key name // nBytes = driverKeyName.ActualLength; if (nBytes <= sizeof(driverKeyName)) { OOPS(); goto GetHCDDriverKeyNameError; } driverKeyNameW = ALLOC(nBytes); if (driverKeyNameW == NULL) { OOPS(); goto GetHCDDriverKeyNameError; } // Get the name of the driver key of the device attached to // the specified port. // success = DeviceIoControl(HCD, IOCTL_GET_HCD_DRIVERKEY_NAME, driverKeyNameW, nBytes, driverKeyNameW, nBytes, &nBytes, NULL); if (!success) { OOPS(); goto GetHCDDriverKeyNameError; } // // Convert the driver key name // Pass the length of the DriverKeyName string // driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName, nBytes - sizeof(USB_HCD_DRIVERKEY_NAME) + sizeof(WCHAR)); // All done, free the uncoverted driver key name and return the // converted driver key name // FREE(driverKeyNameW); return driverKeyNameA; GetHCDDriverKeyNameError: // There was an error, free anything that was allocated // if (driverKeyNameW != NULL) { FREE(driverKeyNameW); driverKeyNameW = NULL; } return NULL; } //***************************************************************************** // // GetConfigDescriptor() // // hHubDevice - Handle of the hub device containing the port from which the // Configuration Descriptor will be requested. // // ConnectionIndex - Identifies the port on the hub to which a device is // attached from which the Configuration Descriptor will be requested. // // DescriptorIndex - Configuration Descriptor index, zero based. // //***************************************************************************** PUSB_DESCRIPTOR_REQUEST GetConfigDescriptor ( HANDLE hHubDevice, ULONG ConnectionIndex, UCHAR DescriptorIndex ) { BOOL success = 0; ULONG nBytes = 0; ULONG nBytesReturned = 0; UCHAR configDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + sizeof(USB_CONFIGURATION_DESCRIPTOR)]; PUSB_DESCRIPTOR_REQUEST configDescReq = NULL; PUSB_CONFIGURATION_DESCRIPTOR configDesc = NULL; // Request the Configuration Descriptor the first time using our // local buffer, which is just big enough for the Cofiguration // Descriptor itself. // nBytes = sizeof(configDescReqBuf); configDescReq = (PUSB_DESCRIPTOR_REQUEST)configDescReqBuf; configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1); // Zero fill the entire request structure // memset(configDescReq, 0, nBytes); // Indicate the port from which the descriptor will be requested // configDescReq->ConnectionIndex = ConnectionIndex; // // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. // // USBD will automatically initialize these fields: // bmRequest = 0x80 // bRequest = 0x06 // // We must inititialize these fields: // wValue = Descriptor Type (high) and Descriptor Index (low byte) // wIndex = Zero (or Language ID for String Descriptors) // wLength = Length of descriptor buffer // configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | DescriptorIndex; configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); // Now issue the get descriptor request. // success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, configDescReq, nBytes, configDescReq, nBytes, &nBytesReturned, NULL); if (!success) { OOPS(); return NULL; } if (nBytes != nBytesReturned) { OOPS(); return NULL; } if (configDesc->wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) { OOPS(); return NULL; } // Now request the entire Configuration Descriptor using a dynamically // allocated buffer which is sized big enough to hold the entire descriptor // nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + configDesc->wTotalLength; configDescReq = (PUSB_DESCRIPTOR_REQUEST)ALLOC(nBytes); if (configDescReq == NULL) { OOPS(); return NULL; } configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1); // Indicate the port from which the descriptor will be requested // configDescReq->ConnectionIndex = ConnectionIndex; // // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. // // USBD will automatically initialize these fields: // bmRequest = 0x80 // bRequest = 0x06 // // We must inititialize these fields: // wValue = Descriptor Type (high) and Descriptor Index (low byte) // wIndex = Zero (or Language ID for String Descriptors) // wLength = Length of descriptor buffer // configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | DescriptorIndex; configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); // Now issue the get descriptor request. // success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, configDescReq, nBytes, configDescReq, nBytes, &nBytesReturned, NULL); if (!success) { OOPS(); FREE(configDescReq); return NULL; } if (nBytes != nBytesReturned) { OOPS(); FREE(configDescReq); return NULL; } if (configDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST))) { OOPS(); FREE(configDescReq); return NULL; } return configDescReq; } //***************************************************************************** // // GetBOSDescriptor() // // hHubDevice - Handle of the hub device containing the port from which the // Configuration Descriptor will be requested. // // ConnectionIndex - Identifies the port on the hub to which a device is // attached from which the BOS Descriptor will be requested. // //***************************************************************************** PUSB_DESCRIPTOR_REQUEST GetBOSDescriptor ( HANDLE hHubDevice, ULONG ConnectionIndex ) { BOOL success = 0; ULONG nBytes = 0; ULONG nBytesReturned = 0; UCHAR bosDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + sizeof(USB_BOS_DESCRIPTOR)]; PUSB_DESCRIPTOR_REQUEST bosDescReq = NULL; PUSB_BOS_DESCRIPTOR bosDesc = NULL; // Request the BOS Descriptor the first time using our // local buffer, which is just big enough for the BOS // Descriptor itself. // nBytes = sizeof(bosDescReqBuf); bosDescReq = (PUSB_DESCRIPTOR_REQUEST)bosDescReqBuf; bosDesc = (PUSB_BOS_DESCRIPTOR)(bosDescReq+1); // Zero fill the entire request structure // memset(bosDescReq, 0, nBytes); // Indicate the port from which the descriptor will be requested // bosDescReq->ConnectionIndex = ConnectionIndex; // // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. // // USBD will automatically initialize these fields: // bmRequest = 0x80 // bRequest = 0x06 // // We must inititialize these fields: // wValue = Descriptor Type (high) and Descriptor Index (low byte) // wIndex = Zero (or Language ID for String Descriptors) // wLength = Length of descriptor buffer // bosDescReq->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8); bosDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); // Now issue the get descriptor request. // success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, bosDescReq, nBytes, bosDescReq, nBytes, &nBytesReturned, NULL); if (!success) { OOPS(); return NULL; } if (nBytes != nBytesReturned) { OOPS(); return NULL; } if (bosDesc->wTotalLength < sizeof(USB_BOS_DESCRIPTOR)) { OOPS(); return NULL; } // Now request the entire BOS Descriptor using a dynamically // allocated buffer which is sized big enough to hold the entire descriptor // nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + bosDesc->wTotalLength; bosDescReq = (PUSB_DESCRIPTOR_REQUEST)ALLOC(nBytes); if (bosDescReq == NULL) { OOPS(); return NULL; } bosDesc = (PUSB_BOS_DESCRIPTOR)(bosDescReq+1); // Indicate the port from which the descriptor will be requested // bosDescReq->ConnectionIndex = ConnectionIndex; // // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. // // USBD will automatically initialize these fields: // bmRequest = 0x80 // bRequest = 0x06 // // We must inititialize these fields: // wValue = Descriptor Type (high) and Descriptor Index (low byte) // wIndex = Zero (or Language ID for String Descriptors) // wLength = Length of descriptor buffer // bosDescReq->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8); bosDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); // Now issue the get descriptor request. // success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, bosDescReq, nBytes, bosDescReq, nBytes, &nBytesReturned, NULL); if (!success) { OOPS(); FREE(bosDescReq); return NULL; } if (nBytes != nBytesReturned) { OOPS(); FREE(bosDescReq); return NULL; } if (bosDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST))) { OOPS(); FREE(bosDescReq); return NULL; } return bosDescReq; } //***************************************************************************** // // AreThereStringDescriptors() // // DeviceDesc - Device Descriptor for which String Descriptors should be // checked. // // ConfigDesc - Configuration Descriptor (also containing Interface Descriptor) // for which String Descriptors should be checked. // //***************************************************************************** BOOL AreThereStringDescriptors ( PUSB_DEVICE_DESCRIPTOR DeviceDesc, PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc ) { PUCHAR descEnd = NULL; PUSB_COMMON_DESCRIPTOR commonDesc = NULL; // // Check Device Descriptor strings // if (DeviceDesc->iManufacturer || DeviceDesc->iProduct || DeviceDesc->iSerialNumber ) { return TRUE; } // // Check the Configuration and Interface Descriptor strings // descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { switch (commonDesc->bDescriptorType) { case USB_CONFIGURATION_DESCRIPTOR_TYPE: case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE: if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) { OOPS(); break; } if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration) { return TRUE; } commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); continue; case USB_INTERFACE_DESCRIPTOR_TYPE: if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) && commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)) { OOPS(); break; } if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface) { return TRUE; } commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); continue; default: commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); continue; } break; } return FALSE; } //***************************************************************************** // // GetAllStringDescriptors() // // hHubDevice - Handle of the hub device containing the port from which the // String Descriptors will be requested. // // ConnectionIndex - Identifies the port on the hub to which a device is // attached from which the String Descriptors will be requested. // // DeviceDesc - Device Descriptor for which String Descriptors should be // requested. // // ConfigDesc - Configuration Descriptor (also containing Interface Descriptor) // for which String Descriptors should be requested. // //***************************************************************************** PSTRING_DESCRIPTOR_NODE GetAllStringDescriptors ( HANDLE hHubDevice, ULONG ConnectionIndex, PUSB_DEVICE_DESCRIPTOR DeviceDesc, PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc ) { PSTRING_DESCRIPTOR_NODE supportedLanguagesString = NULL; ULONG numLanguageIDs = 0; USHORT *languageIDs = NULL; PUCHAR descEnd = NULL; PUSB_COMMON_DESCRIPTOR commonDesc = NULL; UCHAR uIndex = 1; UCHAR bInterfaceClass = 0; BOOL getMoreStrings = FALSE; HRESULT hr = S_OK; // // Get the array of supported Language IDs, which is returned // in String Descriptor 0 // supportedLanguagesString = GetStringDescriptor(hHubDevice, ConnectionIndex, 0, 0); if (supportedLanguagesString == NULL) { return NULL; } numLanguageIDs = (supportedLanguagesString->StringDescriptor->bLength - 2) / 2; languageIDs = &supportedLanguagesString->StringDescriptor->bString[0]; // // Get the Device Descriptor strings // if (DeviceDesc->iManufacturer) { GetStringDescriptors(hHubDevice, ConnectionIndex, DeviceDesc->iManufacturer, numLanguageIDs, languageIDs, supportedLanguagesString); } if (DeviceDesc->iProduct) { GetStringDescriptors(hHubDevice, ConnectionIndex, DeviceDesc->iProduct, numLanguageIDs, languageIDs, supportedLanguagesString); } if (DeviceDesc->iSerialNumber) { GetStringDescriptors(hHubDevice, ConnectionIndex, DeviceDesc->iSerialNumber, numLanguageIDs, languageIDs, supportedLanguagesString); } // // Get the Configuration and Interface Descriptor strings // descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { switch (commonDesc->bDescriptorType) { case USB_CONFIGURATION_DESCRIPTOR_TYPE: if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) { OOPS(); break; } if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration) { GetStringDescriptors(hHubDevice, ConnectionIndex, ((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration, numLanguageIDs, languageIDs, supportedLanguagesString); } commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); continue; case USB_IAD_DESCRIPTOR_TYPE: if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR)) { OOPS(); break; } if (((PUSB_IAD_DESCRIPTOR)commonDesc)->iFunction) { GetStringDescriptors(hHubDevice, ConnectionIndex, ((PUSB_IAD_DESCRIPTOR)commonDesc)->iFunction, numLanguageIDs, languageIDs, supportedLanguagesString); } commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); continue; case USB_INTERFACE_DESCRIPTOR_TYPE: if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) && commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)) { OOPS(); break; } if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface) { GetStringDescriptors(hHubDevice, ConnectionIndex, ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface, numLanguageIDs, languageIDs, supportedLanguagesString); } // // We need to display more string descriptors for the following // interface classes // bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass; if (bInterfaceClass == USB_DEVICE_CLASS_VIDEO) { getMoreStrings = TRUE; } commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); continue; default: commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); continue; } break; } if (getMoreStrings) { // // We might need to display strings later that are referenced only in // class-specific descriptors. Get String Descriptors 1 through 32 (an // arbitrary upper limit for Strings needed due to "bad devices" // returning an infinite repeat of Strings 0 through 4) until one is not // found. // // There are also "bad devices" that have issues even querying 1-32, but // historically USBView made this query, so the query should be safe for // video devices. // for (uIndex = 1; SUCCEEDED(hr) && (uIndex < NUM_STRING_DESC_TO_GET); uIndex++) { hr = GetStringDescriptors(hHubDevice, ConnectionIndex, uIndex, numLanguageIDs, languageIDs, supportedLanguagesString); } } return supportedLanguagesString; } //***************************************************************************** // // GetStringDescriptor() // // hHubDevice - Handle of the hub device containing the port from which the // String Descriptor will be requested. // // ConnectionIndex - Identifies the port on the hub to which a device is // attached from which the String Descriptor will be requested. // // DescriptorIndex - String Descriptor index. // // LanguageID - Language in which the string should be requested. // //***************************************************************************** PSTRING_DESCRIPTOR_NODE GetStringDescriptor ( HANDLE hHubDevice, ULONG ConnectionIndex, UCHAR DescriptorIndex, USHORT LanguageID ) { BOOL success = 0; ULONG nBytes = 0; ULONG nBytesReturned = 0; UCHAR stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH]; PUSB_DESCRIPTOR_REQUEST stringDescReq = NULL; PUSB_STRING_DESCRIPTOR stringDesc = NULL; PSTRING_DESCRIPTOR_NODE stringDescNode = NULL; nBytes = sizeof(stringDescReqBuf); stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf; stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1); // Zero fill the entire request structure // memset(stringDescReq, 0, nBytes); // Indicate the port from which the descriptor will be requested // stringDescReq->ConnectionIndex = ConnectionIndex; // // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. // // USBD will automatically initialize these fields: // bmRequest = 0x80 // bRequest = 0x06 // // We must inititialize these fields: // wValue = Descriptor Type (high) and Descriptor Index (low byte) // wIndex = Zero (or Language ID for String Descriptors) // wLength = Length of descriptor buffer // stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | DescriptorIndex; stringDescReq->SetupPacket.wIndex = LanguageID; stringDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); // Now issue the get descriptor request. // success = DeviceIoControl(hHubDevice, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, stringDescReq, nBytes, stringDescReq, nBytes, &nBytesReturned, NULL); // // Do some sanity checks on the return from the get descriptor request. // if (!success) { OOPS(); return NULL; } if (nBytesReturned < 2) { OOPS(); return NULL; } if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE) { OOPS(); return NULL; } if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST)) { OOPS(); return NULL; } if (stringDesc->bLength % 2 != 0) { OOPS(); return NULL; } // // Looks good, allocate some (zero filled) space for the string descriptor // node and copy the string descriptor to it. // stringDescNode = (PSTRING_DESCRIPTOR_NODE)ALLOC(sizeof(STRING_DESCRIPTOR_NODE) + stringDesc->bLength); if (stringDescNode == NULL) { OOPS(); return NULL; } stringDescNode->DescriptorIndex = DescriptorIndex; stringDescNode->LanguageID = LanguageID; memcpy(stringDescNode->StringDescriptor, stringDesc, stringDesc->bLength); return stringDescNode; } //***************************************************************************** // // GetStringDescriptors() // // hHubDevice - Handle of the hub device containing the port from which the // String Descriptor will be requested. // // ConnectionIndex - Identifies the port on the hub to which a device is // attached from which the String Descriptor will be requested. // // DescriptorIndex - String Descriptor index. // // NumLanguageIDs - Number of languages in which the string should be // requested. // // LanguageIDs - Languages in which the string should be requested. // // StringDescNodeHead - First node in linked list of device's string descriptors // // Return Value: HRESULT indicating whether the string is on the list // //***************************************************************************** HRESULT GetStringDescriptors ( _In_ HANDLE hHubDevice, _In_ ULONG ConnectionIndex, _In_ UCHAR DescriptorIndex, _In_ ULONG NumLanguageIDs, _In_reads_(NumLanguageIDs) USHORT *LanguageIDs, _In_ PSTRING_DESCRIPTOR_NODE StringDescNodeHead ) { PSTRING_DESCRIPTOR_NODE tail = NULL; PSTRING_DESCRIPTOR_NODE trailing = NULL; ULONG i = 0; // // Go to the end of the linked list, searching for the requested index to // see if we've already retrieved it // for (tail = StringDescNodeHead; tail != NULL; tail = tail->Next) { if (tail->DescriptorIndex == DescriptorIndex) { return S_OK; } trailing = tail; } tail = trailing; // // Get the next String Descriptor. If this is NULL, then we're done (return) // Otherwise, loop through all Language IDs // for (i = 0; (tail != NULL) && (i < NumLanguageIDs); i++) { tail->Next = GetStringDescriptor(hHubDevice, ConnectionIndex, DescriptorIndex, LanguageIDs[i]); tail = tail->Next; } if (tail == NULL) { return E_FAIL; } else { return S_OK; } } //***************************************************************************** // // CleanupItem() // //***************************************************************************** VOID CleanupItem ( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ) { TV_ITEM tvi; PVOID info = NULL; UNREFERENCED_PARAMETER(pContext); tvi.mask = TVIF_HANDLE | TVIF_PARAM; tvi.hItem = hTreeItem; TreeView_GetItem(hTreeWnd, &tvi); info = (PVOID)tvi.lParam; if (info) { PCHAR DriverKey = NULL; PUSB_NODE_INFORMATION HubInfo = NULL; PCHAR HubName = NULL; PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfoEx = NULL; PUSB_DESCRIPTOR_REQUEST ConfigDesc = NULL; PUSB_DESCRIPTOR_REQUEST BosDesc = NULL; PSTRING_DESCRIPTOR_NODE StringDescs = NULL; PUSB_HUB_INFORMATION_EX HubInfoEx = NULL; PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps = NULL; PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 = NULL; PUSB_HUB_CAPABILITIES_EX HubCapabilityEx = NULL; PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties = NULL; PUSB_CONTROLLER_INFO_0 ControllerInfo = NULL; // // All structures except DEVICE_INFO_NODE are free'd up here. DEVICE_INFO_NODE structures are free'd while // destroying device info lists (ClearDeviceList()) // switch (*(PUSBDEVICEINFOTYPE)info) { case HostControllerInfo: // // Remove this host controller from the list of enumerated // host controllers. // RemoveEntryList(&((PUSBHOSTCONTROLLERINFO)info)->ListEntry); DriverKey = ((PUSBHOSTCONTROLLERINFO)info)->DriverKey; ControllerInfo = ((PUSBHOSTCONTROLLERINFO)info)->ControllerInfo; UsbDeviceProperties = ((PUSBHOSTCONTROLLERINFO)info)->UsbDeviceProperties; break; case RootHubInfo: HubInfo = ((PUSBROOTHUBINFO)info)->HubInfo; HubInfoEx = ((PUSBROOTHUBINFO)info)->HubInfoEx; HubName = ((PUSBROOTHUBINFO)info)->HubName; PortConnectorProps = ((PUSBROOTHUBINFO)info)->PortConnectorProps; UsbDeviceProperties = ((PUSBROOTHUBINFO)info)->UsbDeviceProperties; HubCapabilityEx = ((PUSBROOTHUBINFO)info)->HubCapabilityEx; break; case ExternalHubInfo: HubInfo = ((PUSBEXTERNALHUBINFO)info)->HubInfo; HubInfoEx = ((PUSBEXTERNALHUBINFO)info)->HubInfoEx; HubName = ((PUSBEXTERNALHUBINFO)info)->HubName; ConnectionInfoEx = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo; PortConnectorProps = ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps; ConfigDesc = ((PUSBEXTERNALHUBINFO)info)->ConfigDesc; BosDesc = ((PUSBEXTERNALHUBINFO)info)->BosDesc; StringDescs = ((PUSBEXTERNALHUBINFO)info)->StringDescs; ConnectionInfoV2 = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2; UsbDeviceProperties = ((PUSBEXTERNALHUBINFO)info)->UsbDeviceProperties; HubCapabilityEx = ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx; break; case DeviceInfo: ConnectionInfoEx = ((PUSBDEVICEINFO)info)->ConnectionInfo; PortConnectorProps = ((PUSBDEVICEINFO)info)->PortConnectorProps; ConfigDesc = ((PUSBDEVICEINFO)info)->ConfigDesc; BosDesc = ((PUSBDEVICEINFO)info)->BosDesc; StringDescs = ((PUSBDEVICEINFO)info)->StringDescs; ConnectionInfoV2 = ((PUSBDEVICEINFO)info)->ConnectionInfoV2; UsbDeviceProperties = ((PUSBDEVICEINFO)info)->UsbDeviceProperties; break; } if(UsbDeviceProperties) { FreeDeviceProperties(&UsbDeviceProperties); } if(ControllerInfo) { FREE(ControllerInfo); } if(HubCapabilityEx) { FREE(HubCapabilityEx); } if (DriverKey) { FREE(DriverKey); } if (HubInfo) { FREE(HubInfo); } if (HubName) { FREE(HubName); } if (ConfigDesc) { FREE(ConfigDesc); } if (BosDesc) { FREE(BosDesc); } if (StringDescs) { PSTRING_DESCRIPTOR_NODE Next; do { Next = StringDescs->Next; FREE(StringDescs); StringDescs = Next; } while (StringDescs); } if (ConnectionInfoEx) { FREE(ConnectionInfoEx); } if (HubInfoEx) { FREE(HubInfoEx); } if (PortConnectorProps) { FREE(PortConnectorProps); } if (ConnectionInfoV2) { FREE(ConnectionInfoV2); } FREE(info); } } //***************************************************************************** // // GetHostControllerPowerMap() // // HANDLE hHCDev // - handle to USB Host Controller // // PUSBHOSTCONTROLLERINFO hcInfo // - data structure to receive the Power Map Info // // return DWORD dwError // - return ERROR_SUCCESS or last error // //***************************************************************************** DWORD GetHostControllerPowerMap( HANDLE hHCDev, PUSBHOSTCONTROLLERINFO hcInfo) { USBUSER_POWER_INFO_REQUEST UsbPowerInfoRequest; PUSB_POWER_INFO pUPI = &UsbPowerInfoRequest.PowerInformation ; DWORD dwError = 0; DWORD dwBytes = 0; BOOL bSuccess = FALSE; int nIndex = 0; int nPowerState = WdmUsbPowerSystemWorking; for ( ; nPowerState <= WdmUsbPowerSystemShutdown; nIndex++, nPowerState++) { // zero initialize our request memset(&UsbPowerInfoRequest, 0, sizeof(UsbPowerInfoRequest)); // set the header and request sizes UsbPowerInfoRequest.Header.UsbUserRequest = USBUSER_GET_POWER_STATE_MAP; UsbPowerInfoRequest.Header.RequestBufferLength = sizeof(UsbPowerInfoRequest); UsbPowerInfoRequest.PowerInformation.SystemState = nPowerState; // // Now query USBHUB for the USB_POWER_INFO structure for this hub. // For Selective Suspend support // bSuccess = DeviceIoControl(hHCDev, IOCTL_USB_USER_REQUEST, &UsbPowerInfoRequest, sizeof(UsbPowerInfoRequest), &UsbPowerInfoRequest, sizeof(UsbPowerInfoRequest), &dwBytes, NULL); if (!bSuccess) { dwError = GetLastError(); OOPS(); } else { // copy the data into our USB Host Controller's info structure memcpy( &(hcInfo->USBPowerInfo[nIndex]), pUPI, sizeof(USB_POWER_INFO)); } } return dwError; } void EnumerateAllDevices() { EnumerateAllDevicesWithGuid(&gDeviceList, (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE); EnumerateAllDevicesWithGuid(&gHubList, (LPGUID)&GUID_DEVINTERFACE_USB_HUB); } //***************************************************************************** // // GetHostControllerInfo() // // HANDLE hHCDev // - handle to USB Host Controller // // PUSBHOSTCONTROLLERINFO hcInfo // - data structure to receive the Power Map Info // // return DWORD dwError // - return ERROR_SUCCESS or last error // //***************************************************************************** DWORD GetHostControllerInfo( HANDLE hHCDev, PUSBHOSTCONTROLLERINFO hcInfo) { USBUSER_CONTROLLER_INFO_0 UsbControllerInfo; DWORD dwError = 0; DWORD dwBytes = 0; BOOL bSuccess = FALSE; memset(&UsbControllerInfo, 0, sizeof(UsbControllerInfo)); // set the header and request sizes UsbControllerInfo.Header.UsbUserRequest = USBUSER_GET_CONTROLLER_INFO_0; UsbControllerInfo.Header.RequestBufferLength = sizeof(UsbControllerInfo); // // Query for the USB_CONTROLLER_INFO_0 structure // bSuccess = DeviceIoControl(hHCDev, IOCTL_USB_USER_REQUEST, &UsbControllerInfo, sizeof(UsbControllerInfo), &UsbControllerInfo, sizeof(UsbControllerInfo), &dwBytes, NULL); if (!bSuccess) { dwError = GetLastError(); OOPS(); } else { hcInfo->ControllerInfo = (PUSB_CONTROLLER_INFO_0) ALLOC(sizeof(USB_CONTROLLER_INFO_0)); if(NULL == hcInfo->ControllerInfo) { dwError = GetLastError(); OOPS(); } else { // copy the data into our USB Host Controller's info structure memcpy(hcInfo->ControllerInfo, &UsbControllerInfo.Info0, sizeof(USB_CONTROLLER_INFO_0)); } } return dwError; } _Success_(return == TRUE) BOOL GetDeviceProperty( _In_ HDEVINFO DeviceInfoSet, _In_ PSP_DEVINFO_DATA DeviceInfoData, _In_ DWORD Property, _Outptr_ LPTSTR *ppBuffer ) { BOOL bResult; DWORD requiredLength = 0; DWORD lastError; if (ppBuffer == NULL) { return FALSE; } *ppBuffer = NULL; bResult = SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, Property , NULL, NULL, 0, &requiredLength); lastError = GetLastError(); if ((requiredLength == 0) || (bResult != FALSE && lastError != ERROR_INSUFFICIENT_BUFFER)) { return FALSE; } *ppBuffer = ALLOC(requiredLength); if (*ppBuffer == NULL) { return FALSE; } bResult = SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, Property , NULL, (PBYTE) *ppBuffer, requiredLength, &requiredLength); if(bResult == FALSE) { FREE(*ppBuffer); *ppBuffer = NULL; return FALSE; } return TRUE; } void EnumerateAllDevicesWithGuid( PDEVICE_GUID_LIST DeviceList, LPGUID Guid ) { if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) { ClearDeviceList(DeviceList); } DeviceList->DeviceInfo = SetupDiGetClassDevs(Guid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) { ULONG index; DWORD error; error = 0; index = 0; while (error != ERROR_NO_MORE_ITEMS) { BOOL success; PDEVICE_INFO_NODE pNode; pNode = ALLOC(sizeof(DEVICE_INFO_NODE)); if (pNode == NULL) { OOPS(); break; } pNode->DeviceInfo = DeviceList->DeviceInfo; pNode->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); pNode->DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); success = SetupDiEnumDeviceInfo(DeviceList->DeviceInfo, index, &pNode->DeviceInfoData); index++; if (success == FALSE) { error = GetLastError(); if (error != ERROR_NO_MORE_ITEMS) { OOPS(); } FreeDeviceInfoNode(&pNode); } else { BOOL bResult; ULONG requiredLength; bResult = GetDeviceProperty(DeviceList->DeviceInfo, &pNode->DeviceInfoData, SPDRP_DEVICEDESC, &pNode->DeviceDescName); if (bResult == FALSE) { FreeDeviceInfoNode(&pNode); OOPS(); break; } bResult = GetDeviceProperty(DeviceList->DeviceInfo, &pNode->DeviceInfoData, SPDRP_DRIVER, &pNode->DeviceDriverName); if (bResult == FALSE) { FreeDeviceInfoNode(&pNode); OOPS(); break; } pNode->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); success = SetupDiEnumDeviceInterfaces(DeviceList->DeviceInfo, 0, Guid, index-1, &pNode->DeviceInterfaceData); if (!success) { FreeDeviceInfoNode(&pNode); OOPS(); break; } success = SetupDiGetDeviceInterfaceDetail(DeviceList->DeviceInfo, &pNode->DeviceInterfaceData, NULL, 0, &requiredLength, NULL); error = GetLastError(); if (!success && error != ERROR_INSUFFICIENT_BUFFER) { FreeDeviceInfoNode(&pNode); OOPS(); break; } pNode->DeviceDetailData = ALLOC(requiredLength); if (pNode->DeviceDetailData == NULL) { FreeDeviceInfoNode(&pNode); OOPS(); break; } pNode->DeviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); success = SetupDiGetDeviceInterfaceDetail(DeviceList->DeviceInfo, &pNode->DeviceInterfaceData, pNode->DeviceDetailData, requiredLength, &requiredLength, NULL); if (!success) { FreeDeviceInfoNode(&pNode); OOPS(); break; } InsertTailList(&DeviceList->ListHead, &pNode->ListEntry); } } } } DEVICE_POWER_STATE AcquireDevicePowerState( _Inout_ PDEVICE_INFO_NODE pNode ) { CM_POWER_DATA cmPowerData = {0}; BOOL bResult; bResult = SetupDiGetDeviceRegistryProperty(pNode->DeviceInfo, &pNode->DeviceInfoData, SPDRP_DEVICE_POWER_DATA, NULL, (PBYTE)&cmPowerData, sizeof(cmPowerData), NULL); pNode->LatestDevicePowerState = bResult ? cmPowerData.PD_MostRecentPowerState : PowerDeviceUnspecified; return pNode->LatestDevicePowerState; } void ClearDeviceList( PDEVICE_GUID_LIST DeviceList ) { if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) { SetupDiDestroyDeviceInfoList(DeviceList->DeviceInfo); DeviceList->DeviceInfo = INVALID_HANDLE_VALUE; } while (!IsListEmpty(&DeviceList->ListHead)) { PDEVICE_INFO_NODE pNode = NULL; PLIST_ENTRY pEntry; pEntry = RemoveHeadList(&DeviceList->ListHead); pNode = CONTAINING_RECORD(pEntry, DEVICE_INFO_NODE, ListEntry); FreeDeviceInfoNode(&pNode); } } VOID FreeDeviceInfoNode( _In_ PDEVICE_INFO_NODE *ppNode ) { if (ppNode == NULL) { return; } if (*ppNode == NULL) { return; } if ((*ppNode)->DeviceDetailData != NULL) { FREE((*ppNode)->DeviceDetailData); } if ((*ppNode)->DeviceDescName != NULL) { FREE((*ppNode)->DeviceDescName); } if ((*ppNode)->DeviceDriverName != NULL) { FREE((*ppNode)->DeviceDriverName); } FREE(*ppNode); *ppNode = NULL; } PDEVICE_INFO_NODE FindMatchingDeviceNodeForDriverName( _In_ PSTR DriverKeyName, _In_ BOOLEAN IsHub ) { PDEVICE_INFO_NODE pNode = NULL; PDEVICE_GUID_LIST pList = NULL; PLIST_ENTRY pEntry = NULL; pList = IsHub ? &gHubList : &gDeviceList; pEntry = pList->ListHead.Flink; while (pEntry != &pList->ListHead) { pNode = CONTAINING_RECORD(pEntry, DEVICE_INFO_NODE, ListEntry); if (_stricmp(DriverKeyName, pNode->DeviceDriverName) == 0) { return pNode; } pEntry = pEntry->Flink; } return NULL; } ================================================ FILE: tests/projects/windows/winsdk/usbview/h264.c ================================================ //***************************************************************************** // I N C L U D E S //***************************************************************************** #include "uvcview.h" #include "h264.h" #ifdef H264_SUPPORT //***************************************************************************** // G L O B A L S //***************************************************************************** // H.264 format UCHAR g_expectedNumberOfH264FrameDescriptors = 0; UCHAR g_numberOfH264FrameDescriptors = 0; // MJPEG format UCHAR g_expectedNumberOfMJPEGFrameDescriptors = 0; UCHAR g_numberOfMJPEGFrameDescriptors = 0; // Uncompressed frame format UCHAR g_expectedNumberOfUncompressedFrameFrameDescriptors = 0; UCHAR g_numberOfUncompressedFrameFrameDescriptors = 0; //***************************************************************************** // // external function prototypes // //***************************************************************************** extern VOID VDisplayBytes (PUCHAR Data, USHORT Len ); //***************************************************************************** // // H.264 video format descriptor string tables // //***************************************************************************** STRINGLIST slSliceModes[]= { {1, "Maximum number of Macroblocks per slice mode", ""}, {2, "Target compressed size per slice mode", ""}, {4, "Number of slices per frame mode", ""}, {8, "Number of Macroblock rows per slice mode", ""}, {0x10, "Reserved", ""}, {0x20, "Reserved", ""}, {0x40, "Reserved", ""}, {0x80, "Reserved", ""}, }; STRINGLIST slSyncFrameTypes[]= { {1, "Reset" , ""}, {2, "IDR frame with SPS and PPS", ""}, {4, "IDR frame (with SPS and PPS) that is a long-term reference frame", ""}, {8, "Non-IDR random-access I frame (with SPS and PPS)", ""}, {0x10, "Non-IDR random-access I frame (with SPS and PPS) that is a long-term reference frame", ""}, {0x20, "P frame that is a long-term reference frame", ""}, {0x40, "Gradual Decoder Refresh frames", ""}, {0x80, "Reserved", ""}, }; //***************************************************************************** // // H.264 video frame rate descriptor string tables // //***************************************************************************** STRINGLIST slUsage[]= { {0x00000001, "Real-time/UCConfig mode 0", ""}, // 0 {0x00000002, "Real-time/UCConfig mode 1", ""}, {0x00000004, "Real-time/UCConfig mode 2Q" ""}, {0x00000008, "Real-time/UCConfig mode 2S" ""}, {0x00000010, "Real-time/UCConfig mode 3", ""}, {0x00000020, "Reserved", ""}, {0x00000040, "Reserved", ""}, {0x00000080, "Reserved", ""}, {0x00000100, "Broadcast mode 0", ""}, // 8 {0x00000200, "Broadcast mode 1", ""}, {0x00000400, "Broadcast mode 2", ""}, {0x00000800, "Broadcast mode 3", ""}, {0x00001000, "Broadcast mode 4", ""}, {0x00002000, "Broadcast mode 5", ""}, {0x00004000, "Broadcast mode 6", ""}, {0x00008000, "Broadcast mode 7", ""}, {0x00010000, "File Storage mode with I and P slices (e.g. IPPP)", ""}, // 16 {0x00020000, "File Storage mode with I, P, and B slices (e.g. IB...BP)", ""}, // 17 {0x00040000, "File storage all I frame mode", ""}, // 18 {0x00080000, "Reserved", ""}, // 19 {0x00100000, "Reserved", ""}, // 20 {0x00200000, "Reserved", ""}, // 21 {0x00400000, "Reserved", ""}, // 22 {0x00800000, "Reserved", ""}, // 23 {0x01000000, "MVC Stereo High Mode", ""}, // 24 {0x02000000, "MVC Multiview Mode", ""}, // 25 {0x04000000, "Reserved", ""}, // 26 {0x08000000, "Reserved", ""}, // 27 {0x10000000, "Reserved", ""}, // 28 {0x20000000, "Reserved", ""}, // 29 {0x40000000, "Reserved", ""}, // 30 {0x80000000, "Reserved", ""}, // 31 }; STRINGLIST slCapabilities[]= { {0x0001, "CAVLC only", ""}, {0x0002, "CABAC only", ""}, {0x0004, "Constant frame rate", ""}, {0x0008, "Separate QP for luma/chroma", ""}, {0x0010, "Separate QP for Cb/Cr", ""}, {0x0020, "No picture reordering", ""}, {0x0040, "Long-term reference frame", ""}, {0x0080, "Reserved", ""}, {0x0100, "Reserved", ""}, {0x0200, "Reserved", ""}, {0x0400, "Reserved", ""}, {0x0800, "Reserved", ""}, {0x1000, "Reserved", ""}, {0x2000, "Reserved", ""}, {0x4000, "Reserved", ""}, {0x8000, "Reserved", ""}, }; STRINGLIST slRateControlModes[]= { {1, "Variable Bit Rate (VBR) with underflow allowed (H.264 low_delay_hrd_flag = 1)", ""}, {2, "Constant Bit Rate (CBR) (H.264 low_delay_hrd_flag = 0)", ""}, {4, "Constant QP", ""}, {8, "Global VBR with underflow allowed (H.264 low_delay_hrd_flag = 1)", ""}, {0x10, "VBR without underflow (H.264 low_delay_hrd_flag = 0)", ""}, {0x20, "Global VBR without underflow (H.264 low_delay_hrd_flag = 0)", ""}, {0x40, "Reserved", ""}, {0x80, "Reserved", ""}, }; STRINGLIST slProfiles[]= { {0x4200, "Baseline Profile", ""}, {0x4240, "Constrained Baseline Profile", ""}, {0x4D00, "Main Profile", ""}, {0x5300, "Scalable Baseline Profile", ""}, {0x5304, "Scalable Constrained Baseline Profile", ""}, {0x5600, "Scalable High Profile", ""}, {0x5604, "Scalable Constrained High Profile", ""}, {0x6400, "High Profile", ""}, {0x640C, "Constrained High Profile", ""}, {0x7600, "Multiview High Profile", ""}, {0x8000, "Stereo High Profile", ""}, }; //***************************************************************************** // // H.264 video encoding unit descriptor string tables // //***************************************************************************** STRINGLIST slEncodingUnitControls[]= { {0x000001, "Select Layer", ""}, // D0 {0x000002, "Profile and Toolset", ""}, // D1 {0x000004, "Video Resolution", ""}, // D2 {0x000008, "Minimum Frame Interval", ""}, // D3 {0x000010, "Slice Mode", ""}, // D4 {0x000020, "Rate Control Mode", ""}, // D5 {0x000040, "Average Bit Rate", ""}, // D6 {0x000080, "CPB Size ", ""}, // D7 {0x000100, "Peak Bit Rate", ""}, // D8 {0x000200, "Quantization Parameter", ""}, // D9 {0x000400, "Synchronization and Long-Term Reference Frame", ""}, // D10 {0x000800, "Long-Term Buffer Size", ""}, // D11 {0x001000, "Picture Long-Term Reference", ""}, // D12 {0x002000, "Valid LTR", ""}, // D13 {0x004000, "Level IDC", ""}, // D14 {0x008000, "SEI Message", ""}, // D15 {0x010000, "QP Range", ""}, // D16 {0x020000, "Priority ID", ""}, // D17 {0x040000, "Start or Stop Layer/View", ""}, // D18 {0x080000, "Error Resiliency", ""}, // D19 {0x100000, "Reserved", ""}, // D20 {0x200000, "Reserved", ""}, // D21 {0x400000, "Reserved", ""}, // D22 {0x800000, "Reserved", ""}, // D23 }; //***************************************************************************** // // commaPrintNumber() // //***************************************************************************** char * commaPrintNumber( ULONG number ) { static char comma = ','; static char retbuf[30]; int digitCount = 0; // null-terminate the string char * pOutputString = &retbuf[ sizeof(retbuf)-1 ]; *pOutputString = '\0'; do { // for every 3rd digit, add a comma to the output string if ( ( digitCount%3 ) == 0 && ( digitCount != 0 ) ) { *--pOutputString = comma; } *--pOutputString = '0' + number % 10; number /= 10; digitCount++; } while( number != 0 ); return pOutputString; } //***************************************************************************** // // DisplayBitmapData() // // Note that USB is always oriented Little Endian (least significant byte // at the lowest address). // // Inputs: // PUCHAR pData - pointer to least significant byte of the data // UCHAR byteCount - number of bytes to print in the pData data buffer // char * stringLabel - string label to print for user's to identify the data type // //***************************************************************************** void DisplayBitmapData(_In_reads_(byteCount) PUCHAR pData, UCHAR byteCount, _In_ char * stringLabel) { UCHAR byteIndex; UCHAR data; UCHAR mask; UCHAR bitIndex; UCHAR checkBit = 0; // the bit we want to print // print the label and all the bytes on the first line AppendTextBuffer("%s : ", stringLabel); VDisplayBytes( pData, byteCount ); for ( byteIndex = 0; byteIndex < byteCount; byteIndex++ ) { data = pData[ byteIndex ]; checkBit = 0; // the control bit value we are going to print for ( mask = 1, bitIndex = 0; bitIndex < 8; bitIndex++ ) { checkBit = data & mask; AppendTextBuffer(" D%02d = %d %s\r\n", bitIndex + 8 * byteIndex, // increment bit count checkBit ? 1 : 0, checkBit ? "yes" : " no"); mask = mask << 1; } } } //***************************************************************************** // // DisplayBitmapDataWithStrings() // // Note that USB is always oriented Little Endian (least significant byte // at the lowest address). // // This calls GetSTringFromList() to insert a string that corresonds to // the bit value being print. // // Inputs: // PUCHAR pData - pointer to least significant byte of the data // UCHAR byteCount - number of bytes to print in the pData data buffer // char * stringLabel - string label to print for user's to identify the data type // STRINGLIST stringList - string table in which to look up bitmap strings // ULONG numEntriesInTable - number of entrys (strings) in the table //***************************************************************************** void DisplayBitmapDataWithStrings( _In_reads_(byteCount) PUCHAR pData, UCHAR byteCount, _In_ char * stringLabel, _In_ PSTRINGLIST stringList, ULONG numEntriesInTable) { UCHAR byteIndex; UCHAR data; UCHAR byteMask; ULONGLONG stringMask; UCHAR bitIndex; UCHAR checkBit = 0; // the bit we want to print // print the label and all the bytes on the first line AppendTextBuffer("%s : ", stringLabel); VDisplayBytes( pData, byteCount ); for ( stringMask = 1, byteIndex = 0; byteIndex < byteCount; byteIndex++ ) { data = pData[ byteIndex ]; checkBit = 0; // the control bit value we are going to print for ( byteMask = 1, bitIndex = 0; bitIndex < 8; bitIndex++ ) { checkBit = data & byteMask; AppendTextBuffer(" D%02d = %d %s %s\r\n", bitIndex + 8 * byteIndex, // increment bit count checkBit ? 1 : 0, checkBit ? "yes - " : " no - ", GetStringFromList(stringList, numEntriesInTable, stringMask, "Reserved")); byteMask = byteMask << 1; stringMask = stringMask << 1; } } } //***************************************************************************** // // DisplayVCH264Format() // //***************************************************************************** BOOL DisplayVCH264Format( _In_reads_(sizeof(VIDEO_FORMAT_H264)) PVIDEO_FORMAT_H264 H264FormatDesc ) { if ( H264FormatDesc->bSimulcastSupport == 0 ) { AppendTextBuffer("\r\n ===>Video Streaming H.264 Format Type Descriptor<===\r\n"); } else { AppendTextBuffer("\r\n ===>Video Streaming H.264 Simulcast Format Type Descriptor<===\r\n"); } AppendTextBuffer("bLength: 0x%02X = %d\r\n", H264FormatDesc->bLength, H264FormatDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X \r\n", H264FormatDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X \r\n", H264FormatDesc->bDescriptorSubtype); AppendTextBuffer("bFormatIndex: 0x%02X = %d\r\n", H264FormatDesc->bFormatIndex, H264FormatDesc->bFormatIndex); AppendTextBuffer("bNumFrameDescriptors: 0x%02X = %d\r\n", H264FormatDesc->bNumFrameDescriptors, H264FormatDesc->bNumFrameDescriptors); AppendTextBuffer("bDefaultFrameIndex: 0x%02X = %d\r\n", H264FormatDesc->bDefaultFrameIndex, H264FormatDesc->bDefaultFrameIndex); AppendTextBuffer("bMaxCodecConfigDelay: 0x%02X = %d frames\r\n", H264FormatDesc->bMaxCodecConfigDelay, H264FormatDesc->bMaxCodecConfigDelay); DisplayBitmapDataWithStrings( H264FormatDesc->bmSupportedSliceModes, sizeof(H264FormatDesc->bmSupportedSliceModes), "bmSupportedSliceModes", slSliceModes, sizeof(slSliceModes)/sizeof(STRINGLIST) ); DisplayBitmapDataWithStrings( H264FormatDesc->bmSupportedSyncFrameTypes, sizeof(H264FormatDesc->bmSupportedSyncFrameTypes), "bmSupportedSyncFrameTypes", slSyncFrameTypes, sizeof(slSyncFrameTypes)/sizeof(STRINGLIST) ); // handle bResolutionScaling if ( H264FormatDesc->bResolutionScaling == 0 ) { AppendTextBuffer("bResolutionScaling: 0x%02X = %d, Not Supported\r\n", H264FormatDesc->bResolutionScaling, H264FormatDesc->bResolutionScaling ); } else if ( H264FormatDesc->bResolutionScaling == 1 ) { AppendTextBuffer("bResolutionScaling: 0x%02X = %d, Limited to 1.5 or 2.0 scaling in both directions, while maintaining the aspect ratio.\r\n", H264FormatDesc->bResolutionScaling, H264FormatDesc->bResolutionScaling ); } else if ( H264FormatDesc->bResolutionScaling == 2 ) { AppendTextBuffer("bResolutionScaling: 0x%02X = %d, Limited to 1.0, 1.5 or 2.0 scaling in either direction.\r\n", H264FormatDesc->bResolutionScaling, H264FormatDesc->bResolutionScaling ); } else if ( H264FormatDesc->bResolutionScaling == 3 ) { AppendTextBuffer("bResolutionScaling: 0x%02X = %d, Limited to resolutions reported by the associated Frame Descriptors\r\n", H264FormatDesc->bResolutionScaling, H264FormatDesc->bResolutionScaling ); } else if ( H264FormatDesc->bResolutionScaling == 4 ) { AppendTextBuffer("bResolutionScaling: 0x%02X = %d, Arbitrary scaling\r\n", H264FormatDesc->bResolutionScaling, H264FormatDesc->bResolutionScaling ); } else // 5 ... 255 { AppendTextBuffer("bResolutionScaling: 0x%02X = %d, Reserved \r\n", H264FormatDesc->bResolutionScaling, H264FormatDesc->bResolutionScaling ); } // handle bSimulcastSupport if ( H264FormatDesc->bSimulcastSupport == 0 ) { AppendTextBuffer("bSimulcastSupport: 0x%02X = %d, one stream\r\n", H264FormatDesc->bSimulcastSupport, H264FormatDesc->bSimulcastSupport ); } else if ( H264FormatDesc->bSimulcastSupport == 1 ) { AppendTextBuffer("bSimulcastSupport: 0x%02X = %d, multiple streams\r\n", H264FormatDesc->bSimulcastSupport, H264FormatDesc->bSimulcastSupport ); } else // ( H264FormatDesc->bSimulcastSupport > 1 ) { AppendTextBuffer("bSimulcastSupport: 0x%02X = %d *!*ERROR: unknown bSimulcastSupport \r\n", H264FormatDesc->bSimulcastSupport, H264FormatDesc->bSimulcastSupport, H264FormatDesc->bSimulcastSupport ); } DisplayBitmapDataWithStrings( &(H264FormatDesc->bmSupportedRateControlModes), sizeof(H264FormatDesc->bmSupportedRateControlModes), "bmSupportedRateControlModes", slRateControlModes, sizeof(slRateControlModes)/sizeof(STRINGLIST) ); // Note that USB is Little Endian according to the UVC 2.0 spec // Resolutions with no scalability AppendTextBuffer("wMaxMBperSecOneResolutionNoScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecOneResolutionNoScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionNoScalability) ); AppendTextBuffer("wMaxMBperSecTwoResolutionsNoScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecTwoResolutionsNoScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsNoScalability) ); AppendTextBuffer("wMaxMBperSecThreeResolutionsNoScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecThreeResolutionsNoScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsNoScalability) ); AppendTextBuffer("wMaxMBperSecFourResolutionsNoScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecFourResolutionsNoScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsNoScalability) ); // Resolutions with temporal scalability AppendTextBuffer("wMaxMBperSecOneResolutionTemporalScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecOneResolutionTemporalScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionTemporalScalability) ); AppendTextBuffer("wMaxMBperSecTwoResolutionsTemporalScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalScalability) ); AppendTextBuffer("wMaxMBperSecThreeResolutionsTemporalScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalScalability) ); AppendTextBuffer("wMaxMBperSecFourResolutionsTemporalScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecFourResolutionsTemporalScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsTemporalScalability) ); // Resolutions with temporal and quality scalability AppendTextBuffer("wMaxMBperSecOneResolutionTemporalQualityScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecOneResolutionTemporalQualityScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionTemporalQualityScalability) ); AppendTextBuffer("wMaxMBperSecTwoResolutionsTemporalQualityScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalQualityScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalQualityScalability) ); AppendTextBuffer("wMaxMBperSecThreeResolutionsTemporalQualityScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalQualityScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalQualityScalability) ); AppendTextBuffer("wMaxMBperSecFourResolutionsTemporalQualityScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecFourResolutionsTemporalQualityScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsTemporalQualityScalability) ); // Resolutions with temporal and spatial scalability AppendTextBuffer("wMaxMBperSecOneResolutionTemporalSpatialScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecOneResolutionTemporalSpatialScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionTemporalSpatialScalability) ); AppendTextBuffer("wMaxMBperSecTwoResolutionsTemporalSpatialScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalSpatialScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalSpatialScalability) ); AppendTextBuffer("wMaxMBperSecThreeResolutionsTemporalSpatialScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalSpatialScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalSpatialScalability) ); AppendTextBuffer("wMaxMBperSecFourResolutionsTemporalSpatialScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecFourResolutionsTemporalSpatialScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsTemporalSpatialScalability) ); // Resolutions with full scalability AppendTextBuffer("wMaxMBperSecOneResolutionFullScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecOneResolutionFullScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionFullScalability) ); AppendTextBuffer("wMaxMBperSecTwoResolutionsFullScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecTwoResolutionsFullScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsFullScalability) ); AppendTextBuffer("wMaxMBperSecThreeResolutionsFullScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecThreeResolutionsFullScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsFullScalability) ); AppendTextBuffer("wMaxMBperSecFourResolutionsFullScalability: 0x%04X (%s MB/sec)\r\n", H264FormatDesc->wMaxMBperSecFourResolutionsFullScalability, commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsFullScalability) ); return TRUE; } //***************************************************************************** // // DisplayVCH264FrameType() // //***************************************************************************** BOOL DisplayVCH264FrameType( _In_reads_(sizeof(VIDEO_FRAME_H264)) PVIDEO_FRAME_H264 H264FrameDesc ) { ULONG frameIntervalIndex; ULONG value; ULONG i; AppendTextBuffer("\r\n ===>Video Streaming H.264 Frame Type Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X = %d\r\n", H264FrameDesc->bLength, H264FrameDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X \r\n", H264FrameDesc->bDescriptorType); AppendTextBuffer("bDescriptorSubtype: 0x%02X \r\n", H264FrameDesc->bDescriptorSubtype); AppendTextBuffer("bFrameIndex: 0x%02X = %d\r\n", H264FrameDesc->bFrameIndex, H264FrameDesc->bFrameIndex); AppendTextBuffer("wWidth: 0x%04X = %d\r\n", H264FrameDesc->wWidth, H264FrameDesc->wWidth); AppendTextBuffer("wHeight: 0x%04X = %d\r\n", H264FrameDesc->wHeight, H264FrameDesc->wHeight); AppendTextBuffer("wSARwidth: 0x%04X = %d\r\n", H264FrameDesc->wSARwidth, H264FrameDesc->wSARwidth); AppendTextBuffer("wSARheight: 0x%04X = %d\r\n", H264FrameDesc->wSARheight, H264FrameDesc->wSARheight); AppendTextBuffer("wProfile: 0x%04X - %s\r\n", H264FrameDesc->wProfile, GetStringFromList( slProfiles, // string table sizeof(slProfiles)/sizeof(STRINGLIST), // number of strings in the table H264FrameDesc->wProfile, // index of string we want to look up in the string table "Unknown profile" ) ); // string to use if the lookup fails AppendTextBuffer("bLevelIDC: 0x%02X = %d = Level %01.01lf \r\n", H264FrameDesc->bLevelIDC, H264FrameDesc->bLevelIDC, H264FrameDesc->bLevelIDC/10.0 ); AppendTextBuffer("wConstrainedToolset: 0x%04X %s\r\n", H264FrameDesc->wConstrainedToolset, ((H264FrameDesc->wConstrainedToolset == 0) ? "- Reserved" : "*!*ERROR: field is reserved and should be zero")); DisplayBitmapDataWithStrings( H264FrameDesc->bmSupportedUsages, sizeof(H264FrameDesc->bmSupportedUsages), "bmSupportedUsages", slUsage, sizeof(slUsage)/sizeof(STRINGLIST) ); DisplayBitmapDataWithStrings( H264FrameDesc->bmCapabilities, sizeof(H264FrameDesc->bmCapabilities), "bmCapabilities", slCapabilities, sizeof(slCapabilities)/sizeof(STRINGLIST) ); // bmSVCCapabilities[4] AppendTextBuffer("%s : ", "bmSVCCapabilities"); VDisplayBytes( &(H264FrameDesc->bmSVCCapabilities[0]), sizeof(H264FrameDesc->bmSVCCapabilities) ); AppendTextBuffer(" D2..D0 = %d Maximum number of temporal layers = %d\r\n", H264FrameDesc->bmSVCCapabilities[0] & 0x7, (H264FrameDesc->bmSVCCapabilities[0] & 0x7) + 1 ); AppendTextBuffer(" D3 = %d %s - Rewrite Support\r\n", (H264FrameDesc->bmSVCCapabilities[0] & 0x8) >> 3, ((H264FrameDesc->bmSVCCapabilities[0] & 0x8) >> 3) ? "yes" : " no" ); AppendTextBuffer(" D6..D4 = %d Maximum number of CGS layers = %d\r\n", (H264FrameDesc->bmSVCCapabilities[0] & 0x70) >> 4, ((H264FrameDesc->bmSVCCapabilities[0] & 0x70) >> 4) + 1 ); value = ( H264FrameDesc->bmSVCCapabilities[1] << 8 ) | H264FrameDesc->bmSVCCapabilities[0]; value >>= 7; // shift bit 7 right so that it ends up in the lsb of value value &= 0x7; AppendTextBuffer(" D9..D7 = %d Number of MGS sublayers\r\n", value ); AppendTextBuffer(" D10 = %d %s - Additional SNR scalability support in spatial enhancement layers\r\n", (H264FrameDesc->bmSVCCapabilities[1] & 0x4) >> 2, ((H264FrameDesc->bmSVCCapabilities[1] & 0x4) >> 2) ? "yes" : " no"); AppendTextBuffer(" D13..D11 = %d Maximum number of spatial layers = %d\r\n", (H264FrameDesc->bmSVCCapabilities[1] & 0x38) >> 3, ((H264FrameDesc->bmSVCCapabilities[1] & 0x38) >> 3) + 1 ); value = ( H264FrameDesc->bmSVCCapabilities[3] << 16 ) | ( H264FrameDesc->bmSVCCapabilities[2] << 8 ) | H264FrameDesc->bmSVCCapabilities[1]; value >>= 6; // get bit 14 at LSB for ( i = 0; i < 18; i++ ) // bits 31...14 { AppendTextBuffer(" D%02d = %d %s - Reserved \r\n", 14 + i, value & 0x1, (value & 0x1) ? "yes" : " no" ); value >>= 1; } // bmMVCCapabilities[4] AppendTextBuffer("%s : ", "bmMVCCapabilities"); VDisplayBytes( &(H264FrameDesc->bmMVCCapabilities[0]), sizeof(H264FrameDesc->bmMVCCapabilities) ); AppendTextBuffer(" D2..D0 = %d Maximum number of temporal layers = %d\r\n", H264FrameDesc->bmMVCCapabilities[0] & 0x7, ((H264FrameDesc->bmMVCCapabilities[0] & 0x7) + 1) ); value = (H264FrameDesc->bmMVCCapabilities[1] << 8) | H264FrameDesc->bmMVCCapabilities[0]; value >>= 3; // shift bit 3 right so that it ends up in the lsb of value value &= 0xff; AppendTextBuffer(" D10..D3 = %d Maximum number of view components = %d\r\n", value, value + 1); value = ( (H264FrameDesc->bmMVCCapabilities[3] << 16) | (H264FrameDesc->bmMVCCapabilities[2] << 8) | H264FrameDesc->bmMVCCapabilities[1] ); value >>= 3; // shift bit 11 right so that it ends up in the lsb of value for ( i = 0; i < 21; i++ ) // bits 31...11 { AppendTextBuffer(" D%02d = %d %s - Reserved \r\n", 11 + i, value & 0x1, (value & 0x1) ? "yes" : " no" ); value >>= 1; } AppendTextBuffer("dwMinBitRate: 0x%08X = %s bps\r\n", H264FrameDesc->dwMinBitRate, commaPrintNumber(H264FrameDesc->dwMinBitRate)); AppendTextBuffer("dwMaxBitRate: 0x%08X = %s bps\r\n", H264FrameDesc->dwMaxBitRate, commaPrintNumber(H264FrameDesc->dwMaxBitRate)); // To convert the default frame interval, which is in 100 ns units, to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds AppendTextBuffer("dwDefaultFrameInterval: 0x%08X = %lf mSec (%4.2f Hz) \r\n", H264FrameDesc->dwDefaultFrameInterval, ((double)H264FrameDesc->dwDefaultFrameInterval)/10000.0, (10000000.0/((double)H264FrameDesc->dwDefaultFrameInterval))); AppendTextBuffer("bNumFrameIntervals: 0x%02X = %d\r\n", H264FrameDesc->bNumFrameIntervals, H264FrameDesc->bNumFrameIntervals); // frame interval 100 ns units. //To convert the frame interval to seconds we would divide by 10,000,000. // 100 ns = 10^(-7) seconds = 1/10,000,000 // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse // To convert the frame interval to milliseconds, we divide by 10,000. // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds // = 1/10,000 milliseconds for ( frameIntervalIndex = 0; frameIntervalIndex < H264FrameDesc->bNumFrameIntervals; frameIntervalIndex++ ) { value = (ULONG)H264FrameDesc->dwFrameInterval[ frameIntervalIndex ]; AppendTextBuffer("dwFrameInterval[%d]: 0x%08x = %lf mSec (%4.2f Hz)\r\n", frameIntervalIndex, value, ((double)value)/10000.0, (10000000.0/((double)value)) ); } return TRUE; } //***************************************************************************** // // DisplayVCH264EncodingUnit() // //***************************************************************************** BOOL DisplayVCH264EncodingUnit( _In_reads_(sizeof(VIDEO_ENCODING_UNIT)) PVIDEO_ENCODING_UNIT VidEncodingDesc ) { PUCHAR pControlsRunTimeData = NULL; AppendTextBuffer("\r\n ===>Video Control Encoding Unit Descriptor<===\r\n"); AppendTextBuffer("bLength: 0x%02X = %d\r\n", VidEncodingDesc->bLength, VidEncodingDesc->bLength); AppendTextBuffer("bDescriptorType: 0x%02X \r\n", VidEncodingDesc->bDescriptorType ); AppendTextBuffer("bDescriptorSubtype: 0x%02X \r\n", VidEncodingDesc->bDescriptorSubtype ); AppendTextBuffer("bUnitID: 0x%02X = %d\r\n", VidEncodingDesc->bUnitID, VidEncodingDesc->bUnitID); AppendTextBuffer("bSourceID: 0x%02X = %d\r\n", VidEncodingDesc->bSourceID, VidEncodingDesc->bSourceID); AppendTextBuffer("iEncoding: 0x%02X = %d\r\n", VidEncodingDesc->iEncoding, VidEncodingDesc->iEncoding); AppendTextBuffer("bControlSize: 0x%02X = %d\r\n", VidEncodingDesc->bControlSize, VidEncodingDesc->bControlSize); if ( VidEncodingDesc->bControlSize > 0) { // Encoding Unit Descriptor bmControls field DisplayBitmapDataWithStrings( VidEncodingDesc->bmControls, VidEncodingDesc->bControlSize /* print bControlSize bytes worth of bitmap info */, "bmControls", slEncodingUnitControls, sizeof(slEncodingUnitControls)/sizeof(STRINGLIST) ); // Encoding Unit Descriptor bmControlsRuntime field pControlsRunTimeData = ((UCHAR *)(&VidEncodingDesc->bmControls)) + VidEncodingDesc->bControlSize; DisplayBitmapDataWithStrings( pControlsRunTimeData, VidEncodingDesc->bControlSize /* print bControlSize bytes worth of bitmap info */, "bmControlsRuntime", slEncodingUnitControls, sizeof(slEncodingUnitControls)/sizeof(STRINGLIST) ); } return TRUE; } //***************************************************************************** // // DoAdditionalErrorChecks() // // Currently this function only checks to see that the number of frame // descriptors actually found equals the number specified in the corresponding // format descriptor. // // Because this potentially involves parsing multiple frame descriptors, we // call this routine after the video descriptor has been parsed and displayed. // //***************************************************************************** void DoAdditionalErrorChecks() { if( g_expectedNumberOfH264FrameDescriptors > 0 || g_numberOfH264FrameDescriptors > 0 || g_expectedNumberOfUncompressedFrameFrameDescriptors > 0 || g_numberOfUncompressedFrameFrameDescriptors > 0 || g_expectedNumberOfMJPEGFrameDescriptors > 0 || g_numberOfMJPEGFrameDescriptors > 0) { AppendTextBuffer("\r\n ===>Additional Error Checking<===\r\n"); // H.264 frame descriptor if( g_expectedNumberOfH264FrameDescriptors > 0 || g_numberOfH264FrameDescriptors > 0) { if ( g_expectedNumberOfH264FrameDescriptors == g_numberOfH264FrameDescriptors ) { AppendTextBuffer("PASS: number of H.264 frame descriptors (%d) == number of frame descriptors (%d) specified in H.264 format descriptor(s)\r\n", g_expectedNumberOfH264FrameDescriptors, g_numberOfH264FrameDescriptors ); } else { AppendTextBuffer("FAIL: number of H.264 frame descriptors (%d) != number of frame descriptors (%d) specified in H.264 format descriptor(s)\r\n", g_expectedNumberOfH264FrameDescriptors, g_numberOfH264FrameDescriptors ); } } // uncompressed frame descriptor if( g_expectedNumberOfUncompressedFrameFrameDescriptors > 0 || g_numberOfUncompressedFrameFrameDescriptors > 0) { if ( g_expectedNumberOfUncompressedFrameFrameDescriptors == g_numberOfUncompressedFrameFrameDescriptors ) { AppendTextBuffer("PASS: number of uncompressed-frame frame descriptors (%d) == number of frame descriptors (%d) specified in uncompressed format descriptor(s)\r\n", g_expectedNumberOfUncompressedFrameFrameDescriptors, g_numberOfUncompressedFrameFrameDescriptors ); } else { AppendTextBuffer("FAIL: number of uncompressed-frame frame descriptors (%d) != number of frame descriptors (%d) specified in uncompressed format descriptor(s)\r\n", g_expectedNumberOfUncompressedFrameFrameDescriptors, g_numberOfUncompressedFrameFrameDescriptors ); } } // MJPEG frame descriptor if( g_expectedNumberOfMJPEGFrameDescriptors > 0 || g_numberOfMJPEGFrameDescriptors > 0) { if ( g_expectedNumberOfMJPEGFrameDescriptors == g_numberOfMJPEGFrameDescriptors ) { AppendTextBuffer("PASS: number of MJPEG frame descriptors (%d) == number of frame descriptors (%d) specified in MJPEG format descriptor(s)\r\n", g_expectedNumberOfMJPEGFrameDescriptors, g_numberOfMJPEGFrameDescriptors ); } else { AppendTextBuffer("FAIL: number of MJPEG frame descriptors (%d) != number of frame descriptors (%d) specified in MJPEG format descriptor(s)\r\n", g_expectedNumberOfMJPEGFrameDescriptors, g_numberOfMJPEGFrameDescriptors ); } } } } //***************************************************************************** // // ResetErrorCounts() // //***************************************************************************** void ResetErrorCounts() { // H.264 format g_expectedNumberOfH264FrameDescriptors = 0; g_numberOfH264FrameDescriptors = 0; // MJPEG format g_expectedNumberOfMJPEGFrameDescriptors = 0; g_numberOfMJPEGFrameDescriptors = 0; // Uncompressed frame format g_expectedNumberOfUncompressedFrameFrameDescriptors = 0; g_numberOfUncompressedFrameFrameDescriptors = 0; } #endif //H264_SUPPORT ================================================ FILE: tests/projects/windows/winsdk/usbview/h264.h ================================================ #pragma once #ifdef H264_SUPPORT //***************************************************************************** // // external variables // //***************************************************************************** extern UCHAR g_expectedNumberOfH264FrameDescriptors; extern UCHAR g_numberOfH264FrameDescriptors; extern UCHAR g_expectedNumberOfMJPEGFrameDescriptors; extern UCHAR g_numberOfMJPEGFrameDescriptors; extern UCHAR g_expectedNumberOfUncompressedFrameFrameDescriptors; extern UCHAR g_numberOfUncompressedFrameFrameDescriptors; #endif //***************************************************************************** // // defines // //***************************************************************************** //Version information printed at lower left of UI Window and top of output text window #define USBVIEW_MAJOR_VERSION 2 #define USBVIEW_MINOR_VERSION 0 #define UVC_SPEC_MAJOR_VERSION 1 #define UVC_SPEC_MINOR_VERSION 5 // definitions take from the proposed UVC 1.5 spec #define VS_FORMAT_H264 0x13 #define VS_FRAME_H264 0x14 // Video Class-Specific VC Interface Descriptor Subtypes // Note, this needs to be added to the list already in C:\nt\sdpublic\internal\drivers\inc\uvcdesc.h // Also, note that MAX_TYPE_UNIT needs to be bumped up by 1 to account for this new subtype.. #define H264_ENCODING_UNIT 7 //***************************************************************************** // // struct definitions // //***************************************************************************** // VideoStreaming H.264 Format Descriptor #pragma pack(push, 1) // pack on a 1 byte boundary typedef struct _VIDEO_FORMAT_H264 { // offset (in bytes): UCHAR bLength; // 0 UCHAR bDescriptorType; // 1 UCHAR bDescriptorSubtype; // 2 UCHAR bFormatIndex; // 3 UCHAR bNumFrameDescriptors; // 4 UCHAR bDefaultFrameIndex; // 5 UCHAR bMaxCodecConfigDelay; // 6 UCHAR bmSupportedSliceModes[1]; // 7 UCHAR bmSupportedSyncFrameTypes[1]; // 8 UCHAR bResolutionScaling; // 9 UCHAR bSimulcastSupport; // 10 UCHAR bmSupportedRateControlModes; // 11 USHORT wMaxMBperSecOneResolutionNoScalability; // 12 USHORT wMaxMBperSecTwoResolutionsNoScalability; // 14 USHORT wMaxMBperSecThreeResolutionsNoScalability; // 16 USHORT wMaxMBperSecFourResolutionsNoScalability; // 18 USHORT wMaxMBperSecOneResolutionTemporalScalability; // 20 USHORT wMaxMBperSecTwoResolutionsTemporalScalability; // 22 USHORT wMaxMBperSecThreeResolutionsTemporalScalability; // 24 USHORT wMaxMBperSecFourResolutionsTemporalScalability; // 26 USHORT wMaxMBperSecOneResolutionTemporalQualityScalability; // 28 USHORT wMaxMBperSecTwoResolutionsTemporalQualityScalability; // 30 USHORT wMaxMBperSecThreeResolutionsTemporalQualityScalability; // 32 USHORT wMaxMBperSecFourResolutionsTemporalQualityScalability; // 34 USHORT wMaxMBperSecOneResolutionTemporalSpatialScalability; // 36 USHORT wMaxMBperSecTwoResolutionsTemporalSpatialScalability; // 38 USHORT wMaxMBperSecThreeResolutionsTemporalSpatialScalability; // 40 USHORT wMaxMBperSecFourResolutionsTemporalSpatialScalability; // 42 USHORT wMaxMBperSecOneResolutionFullScalability; // 44 USHORT wMaxMBperSecTwoResolutionsFullScalability; // 46 USHORT wMaxMBperSecThreeResolutionsFullScalability; // 48 USHORT wMaxMBperSecFourResolutionsFullScalability; // 50 } VIDEO_FORMAT_H264, *PVIDEO_FORMAT_H264; #pragma pack(pop) // VideoStreaming H.264 Frame Descriptor #pragma pack(push, 1) // pack on a 1 byte boundary // Disable warning on zero sized array in CPP compiler #pragma warning(push) #pragma warning(disable:4200) // Zero sized array typedef struct _VIDEO_FRAME_H264 { // offset (in bytes): UCHAR bLength; // 0 UCHAR bDescriptorType; // 1 UCHAR bDescriptorSubtype; // 2 UCHAR bFrameIndex; // 3 USHORT wWidth; // 4 USHORT wHeight; // 6 USHORT wSARwidth; // 8 USHORT wSARheight; // 10 USHORT wProfile; // 12 UCHAR bLevelIDC; // 14 USHORT wConstrainedToolset; // 15 UCHAR bmSupportedUsages[4]; // 17 UCHAR bmCapabilities[2]; // 21 UCHAR bmSVCCapabilities[4]; // 23 UCHAR bmMVCCapabilities[4]; // 27 ULONG dwMinBitRate; // 31 ULONG dwMaxBitRate; // 35 ULONG dwDefaultFrameInterval; // 39 UCHAR bNumFrameIntervals; // 43 ULONG dwFrameInterval[]; // 44 variable-length parameter } VIDEO_FRAME_H264, *PVIDEO_FRAME_H264; #pragma warning(pop) #pragma pack(pop) // VideoControl Encoding Unit Descriptor #pragma pack(push, 1) // pack on a 1 byte boundary #pragma warning(push) #pragma warning(disable:4200) // Zero sized array typedef struct //_VIDEO_ENCODING_UNIT { // offset (in bytes): UCHAR bLength; // 0 UCHAR bDescriptorType; // 1 UCHAR bDescriptorSubtype; // 2 UCHAR bUnitID; // 3 UCHAR bSourceID; // 4 UCHAR iEncoding; // 5 UCHAR bControlSize; // 6 UCHAR bmControls[]; // 7 - variable-length parameter (bControlSize specifies the size) } VIDEO_ENCODING_UNIT, *PVIDEO_ENCODING_UNIT; // after bmControls[] there is also the variable-length parameter (bControlSize specifies the size: // UCHAR bmControlsRunTime[] #pragma warning(pop) #pragma pack(pop) //***************************************************************************** // // function prototypes // //***************************************************************************** BOOL DisplayVCH264Format( _In_reads_(sizeof(VIDEO_FORMAT_H264)) PVIDEO_FORMAT_H264 H264FormatDesc ); BOOL DisplayVCH264FrameType( _In_reads_(sizeof(VIDEO_FRAME_H264)) PVIDEO_FRAME_H264 H264FrameDesc ); BOOL DisplayVCH264EncodingUnit( _In_reads_(sizeof(VIDEO_ENCODING_UNIT)) PVIDEO_ENCODING_UNIT VidEncodingDesc ); void DisplayBitmapData( _In_reads_(byteCount) PUCHAR pData, UCHAR byteCount, _In_ char * stringLabel); void DisplayBitmapDataWithStrings( _In_reads_(byteCount) PUCHAR pData, UCHAR byteCount, _In_ char * stringLabel, _In_ PSTRINGLIST stringList, ULONG numEntriesInTable ); void DoAdditionalErrorChecks(); void ResetErrorCounts(); ================================================ FILE: tests/projects/windows/winsdk/usbview/langidlist.h ================================================ /*++ Copyright (c) 2003-2008 Microsoft Corporation Module Name: LANGIDLIST.H Abstract: This file LANGIDLIST.H contains content from USB.org, and was reviewed by LCA in June 2011. Per discussion with USB consortium counsel their material is "free to any use". This header file contains a list of all currently known USB Language IDs and the language name associated with each Language ID. Source: http://www.usb.org Environment: Kernel & user mode Revision History: 03-28-03 : created --*/ #ifndef __LANGIDLIST_H__ #define __LANGIDLIST_H__ // // Language ID structure // typedef struct { USHORT usLangID; PCHAR szLanguage; } USBLANGID, *PUSBLANGID; // // This list built from information obtained on Nov-30-2000 from // http://www.usb.org // // This information has not been independently verified and no claims // are made here as to its accuracy. // USBLANGID USBLangIDs[] = { {1078 , /* 0x0436 */ "Afrikaans"}, {1052 , /* 0x041c */ "Albanian"}, {1025 , /* 0x0401 */ "Arabic (Saudi Arabia)"}, {2049 , /* 0x0801 */ "Arabic (Iraq)"}, {3073 , /* 0x0c01 */ "Arabic (Egypt)"}, {4097 , /* 0x1001 */ "Arabic (Libya)"}, {5121 , /* 0x1401 */ "Arabic (Algeria)"}, {6145 , /* 0x1801 */ "Arabic (Morocco)"}, {7169 , /* 0x1c01 */ "Arabic (Tunisia)"}, {8193 , /* 0x2001 */ "Arabic (Oman)"}, {9217 , /* 0x2401 */ "Arabic (Yemen)"}, {10241 , /* 0x2801 */ "Arabic (Syria)"}, {11265 , /* 0x2c01 */ "Arabic (Jordan)"}, {12289 , /* 0x3001 */ "Arabic (Lebanon)"}, {13313 , /* 0x3401 */ "Arabic (Kuwait)"}, {14337 , /* 0x3801 */ "Arabic (U.A.E.)"}, {15361 , /* 0x3c01 */ "Arabic (Bahrain)"}, {16385 , /* 0x4001 */ "Arabic (Qatar) "}, {1067 , /* 0x042b */ "Armenian"}, {1101 , /* 0x044d */ "Assamese"}, {1068 , /* 0x042c */ "Azeri (Latin)"}, {2092 , /* 0x082c */ "Azeri (Cyrillic)"}, {1069 , /* 0x042d */ "Basque"}, {1059 , /* 0x0423 */ "Belarussian"}, {1093 , /* 0x0445 */ "Bengali"}, {1026 , /* 0x0402 */ "Bulgarian"}, {1109 , /* 0x0455 */ "Burmese"}, {1027 , /* 0x0403 */ "Catalan"}, {1028 , /* 0x0404 */ "Chinese (Taiwan)"}, {2052 , /* 0x0804 */ "Chinese (PRC)"}, {3076 , /* 0x0c04 */ "Chinese (Hong Kong SAR, PRC)"}, {4100 , /* 0x1004 */ "Chinese (Singapore)"}, {5124 , /* 0x1404 */ "Chinese (MACAO SAR)"}, {1050 , /* 0x041a */ "Croatian"}, {1029 , /* 0x0405 */ "Czech"}, {1030 , /* 0x0406 */ "Danish"}, {1043 , /* 0x0413 */ "Dutch (Netherlands)"}, {2067 , /* 0x0813 */ "Dutch (Belgium)"}, {1033 , /* 0x0409 */ "English (United States)"}, {2057 , /* 0x0809 */ "English (United Kingdom)"}, {3081 , /* 0x0c09 */ "English (Australian)"}, {4105 , /* 0x1009 */ "English (Canadian)"}, {5129 , /* 0x1409 */ "English (New Zealand)"}, {6153 , /* 0x1809 */ "English (Ireland)"}, {7177 , /* 0x1c09 */ "English (South Africa)"}, {8201 , /* 0x2009 */ "English (Jamaica)"}, {9225 , /* 0x2409 */ "English (Caribbean)"}, {10249 , /* 0x2809 */ "English (Belize)"}, {11273 , /* 0x2c09 */ "English (Trinidad)"}, {12297 , /* 0x3009 */ "English (Zimbabwe)"}, {13321 , /* 0x3409 */ "English (Philippines)"}, {1061 , /* 0x0425 */ "Estonian"}, {1080 , /* 0x0438 */ "Faeroese"}, {1065 , /* 0x0429 */ "Farsi "}, {1035 , /* 0x040b */ "Finnish"}, {1036 , /* 0x040c */ "French (Standard)"}, {2060 , /* 0x080c */ "French (Belgian)"}, {3084 , /* 0x0c0c */ "French (Canadian)"}, {4108 , /* 0x100c */ "French (Switzerland)"}, {5132 , /* 0x140c */ "French (Luxembourg)"}, {6156 , /* 0x180c */ "French (Monaco)"}, {1079 , /* 0x0437 */ "Georgian"}, {1031 , /* 0x0407 */ "German (Standard)"}, {2055 , /* 0x0807 */ "German (Switzerland)"}, {3079 , /* 0x0c07 */ "German (Austria)"}, {4103 , /* 0x1007 */ "German (Luxembourg)"}, {5127 , /* 0x1407 */ "German (Liechtenstein)"}, {1032 , /* 0x0408 */ "Greek"}, {1095 , /* 0x0447 */ "Gujarati"}, {1037 , /* 0x040d */ "Hebrew"}, {1081 , /* 0x0439 */ "Hindi"}, {1038 , /* 0x040e */ "Hungarian"}, {1039 , /* 0x040f */ "Icelandic"}, {1057 , /* 0x0421 */ "Indonesian"}, {1040 , /* 0x0410 */ "Italian (Standard)"}, {2064 , /* 0x0810 */ "Italian (Switzerland)"}, {1041 , /* 0x0411 */ "Japanese"}, {1099 , /* 0x044b */ "Kannada"}, {2144 , /* 0x0860 */ "Kashmiri (India)"}, {1087 , /* 0x043f */ "Kazakh"}, {1111 , /* 0x0457 */ "Konkani"}, {1042 , /* 0x0412 */ "Korean"}, {2066 , /* 0x0812 */ "Korean (Johab)"}, {1062 , /* 0x0426 */ "Latvian"}, {1063 , /* 0x0427 */ "Lithuanian"}, {2087 , /* 0x0827 */ "Lithuanian (Classic)"}, {1071 , /* 0x042f */ "Macedonia, Former Yugoslav Republic of"}, {1086 , /* 0x043e */ "Malay (Malaysian)"}, {2110 , /* 0x083e */ "Malay (Brunei Darussalam)"}, {1100 , /* 0x044c */ "Malayalam"}, {1112 , /* 0x0458 */ "Manipuri"}, {1102 , /* 0x044e */ "Marathi"}, {2145 , /* 0x0861 */ "Nepali (India)"}, {1044 , /* 0x0414 */ "Norwegian (Bokmal)"}, {2068 , /* 0x0814 */ "Norwegian (Nynorsk)"}, {1096 , /* 0x0448 */ "Odia"}, {1045 , /* 0x0415 */ "Polish"}, {1046 , /* 0x0416 */ "Portuguese (Brazil)"}, {2070 , /* 0x0816 */ "Portuguese (Portugal)"}, {1094 , /* 0x0446 */ "Punjabi"}, {1048 , /* 0x0418 */ "Romanian"}, {1049 , /* 0x0419 */ "Russian"}, {1103 , /* 0x044f */ "Sanskrit"}, {3098 , /* 0x0c1a */ "Serbian (Cyrillic)"}, {2074 , /* 0x081a */ "Serbian (Latin)"}, {1113 , /* 0x0459 */ "Sindhi"}, {1051 , /* 0x041b */ "Slovak"}, {1060 , /* 0x0424 */ "Slovenian"}, {1034 , /* 0x040a */ "Spanish (Traditional Sort)"}, {2058 , /* 0x080a */ "Spanish (Mexican)"}, {3082 , /* 0x0c0a */ "Spanish (Modern Sort)"}, {4106 , /* 0x100a */ "Spanish (Guatemala)"}, {5130 , /* 0x140a */ "Spanish (Costa Rica)"}, {6154 , /* 0x180a */ "Spanish (Panama)"}, {7178 , /* 0x1c0a */ "Spanish (Dominican Republic)"}, {8202 , /* 0x200a */ "Spanish (Venezuela)"}, {9226 , /* 0x240a */ "Spanish (Colombia)"}, {10250 , /* 0x280a */ "Spanish (Peru)"}, {11274 , /* 0x2c0a */ "Spanish (Argentina)"}, {12298 , /* 0x300a */ "Spanish (Ecuador)"}, {13322 , /* 0x340a */ "Spanish (Chile)"}, {14346 , /* 0x380a */ "Spanish (Uruguay)"}, {15370 , /* 0x3c0a */ "Spanish (Paraguay)"}, {16394 , /* 0x400a */ "Spanish (Bolivia)"}, {17418 , /* 0x440a */ "Spanish (El Salvador)"}, {18442 , /* 0x480a */ "Spanish (Honduras)"}, {19466 , /* 0x4c0a */ "Spanish (Nicaragua)"}, {20490 , /* 0x500a */ "Spanish (Puerto Rico)"}, {1072 , /* 0x0430 */ "Sutu"}, {1089 , /* 0x0441 */ "Swahili (Kenya)"}, {1053 , /* 0x041d */ "Swedish"}, {2077 , /* 0x081d */ "Swedish (Finland)"}, {1097 , /* 0x0449 */ "Tamil"}, {1092 , /* 0x0444 */ "Tatar (Tatarstan)"}, {1098 , /* 0x044a */ "Telugu"}, {1054 , /* 0x041e */ "Thai"}, {1055 , /* 0x041f */ "Turkish"}, {1058 , /* 0x0422 */ "Ukrainian"}, {1056 , /* 0x0420 */ "Urdu (Pakistan)"}, {2080 , /* 0x0820 */ "Urdu (India)"}, {1091 , /* 0x0443 */ "Uzbek (Latin)"}, {2115 , /* 0x0843 */ "Uzbek (Cyrillic)"}, {1066 , /* 0x042a */ "Vietnamese"}, {1279 , /* 0x04ff */ "HID (Usage Data Descriptor)"}, {61695 , /* 0xf0ff */ "HID (Vendor Defined 1)"}, {62719 , /* 0xf4ff */ "HID (Vendor Defined 2)"}, {63743 , /* 0xf8ff */ "HID (Vendor Defined 3)"}, {64767 , /* 0xfcff */ "HID (Vendor Defined 4)"}, { 0x00, "End"} }; #endif /* __LANGIDLIST_H__ */ ================================================ FILE: tests/projects/windows/winsdk/usbview/resource.h ================================================ /*++ Copyright (c) 1998-2008 Microsoft Corporation, All Rights Reserved. --*/ #define IDD_MAINDIALOG 101 #define IDR_MENU 102 #define IDD_ABOUT 103 #define IDI_ICON 104 #define IDC_SPLIT 105 #define IDACCEL 106 #define IDI_BADICON 107 #define IDI_COMPUTER 108 #define IDI_HUB 109 #define IDI_NODEVICE 110 #define IDI_SSICON 111 #define IDI_NOSSDEVICE 112 #define IDC_TREE 1000 #define IDC_EDIT 1001 #define IDC_STATUS 1002 #define IDS_STRINGBASE 2000 #define IDS_STANDARD_FONT 2001 #define IDS_STANDARD_FONT_HEIGHT 2002 #define IDS_STANDARD_FONT_WIDTH 2003 #define IDS_USBVIEW_USAGE 2004 #define IDS_USBVIEW_PRESSKEY 2005 #define IDS_USBVIEW_INVALIDARG 2006 #define IDS_USBVIEW_FILE_EXISTS_TXT 2007 #define IDS_USBVIEW_FILE_EXISTS_XML 2008 #define IDS_USBVIEW_INTERNAL_ERROR 2009 #define IDS_USBVIEW_SAVED_TO 2010 #define IDS_USBVIEW_INVALID_FILENAME 2011 #define IDC_VERSION 3000 #define IDC_UVCVERSION 3001 #define ID_EXIT 40001 #define ID_REFRESH 40002 #define ID_AUTO_REFRESH 40003 #define ID_CONFIG_DESCRIPTORS 40004 #define ID_ABOUT 40005 #define ID_ANNOTATION 40007 #define ID_UNUSED 40008 #define ID_LOG_DEBUG 40009 #define ID_SAVE 40010 #define ID_SAVEALL 40011 #define ID_SAVEXML 40012 #define IDC_STATIC 0xFFFFFFFF ================================================ FILE: tests/projects/windows/winsdk/usbview/usbdesc.h ================================================ /*++ Copyright (c) 1997-2008 Microsoft Corporation Module Name: USBDESC.H Abstract: This is a header file for USB descriptors which are not yet in a standard system header file. Environment: user mode Revision History: 03-06-1998 : created 03-28-2003 : minor changes to support UVC and USB200 --*/ #pragma pack(push, 1) /***************************************************************************** D E F I N E S *****************************************************************************/ // //Device Descriptor bDeviceClass values // #define USB_INTERFACE_CLASS_DEVICE 0x00 #define USB_COMMUNICATION_DEVICE 0x02 #define USB_HUB_DEVICE 0x09 #define USB_DEVICE_CLASS_BILLBOARD 0x11 #define USB_DIAGNOSTIC_DEVICE 0xDC #define USB_WIRELESS_CONTROLLER_DEVICE 0xE0 #define USB_MISCELLANEOUS_DEVICE 0xEF #define USB_VENDOR_SPECIFIC_DEVICE 0xFF // //Device Descriptor bDeviceSubClass values // #define USB_COMMON_SUB_CLASS 0x02 // //Interface Descriptor bInterfaceClass values: // //#define USB_AUDIO_INTERFACE 0x01 //#define USB_CDC_CONTROL_INTERFACE 0x02 //#define USB_HID_INTERFACE 0x03 //#define USB_PHYSICAL_INTERFACE 0x05 //#define USB_IMAGE_INTERFACE 0x06 //#define USB_PRINTER_INTERFACE 0x07 //#define USB_MASS_STORAGE_INTERFACE 0x08 //#define USB_HUB_INTERFACE 0x09 #define USB_CDC_DATA_INTERFACE 0x0A #define USB_CHIP_SMART_CARD_INTERFACE 0x0B #define USB_CONTENT_SECURITY_INTERFACE 0x0D #define USB_DIAGNOSTIC_DEVICE_INTERFACE 0xDC #define USB_WIRELESS_CONTROLLER_INTERFACE 0xE0 #define USB_APPLICATION_SPECIFIC_INTERFACE 0xFE //#define USB_VENDOR_SPECIFIC_INTERFACE 0xFF #define USB_HID_DESCRIPTOR_TYPE 0x21 // //IAD protocol values // #define USB_IAD_PROTOCOL 0x01 // //Device class specific values // #define BILLBOARD_MAX_NUM_ALT_MODE 0x34 // //USB 2.0 Specification Changes - New Descriptors // #define USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE 0x07 #define USB_INTERFACE_POWER_DESCRIPTOR_TYPE 0x08 #define USB_OTG_DESCRIPTOR_TYPE 0x09 #define USB_DEBUG_DESCRIPTOR_TYPE 0x0A #define USB_IAD_DESCRIPTOR_TYPE 0x0B // // USB Device Class Definition for Audio Devices // Appendix A. Audio Device Class Codes // // A.2 Audio Interface Subclass Codes // #define USB_AUDIO_SUBCLASS_UNDEFINED 0x00 #define USB_AUDIO_SUBCLASS_AUDIOCONTROL 0x01 #define USB_AUDIO_SUBCLASS_AUDIOSTREAMING 0x02 #define USB_AUDIO_SUBCLASS_MIDISTREAMING 0x03 // A.4 Audio Class-Specific Descriptor Types // #define USB_AUDIO_CS_UNDEFINED 0x20 #define USB_AUDIO_CS_DEVICE 0x21 #define USB_AUDIO_CS_CONFIGURATION 0x22 #define USB_AUDIO_CS_STRING 0x23 #define USB_AUDIO_CS_INTERFACE 0x24 #define USB_AUDIO_CS_ENDPOINT 0x25 // A.5 Audio Class-Specific AC (Audio Control) Interface Descriptor Subtypes // #define USB_AUDIO_AC_UNDEFINED 0x00 #define USB_AUDIO_AC_HEADER 0x01 #define USB_AUDIO_AC_INPUT_TERMINAL 0x02 #define USB_AUDIO_AC_OUTPUT_TERMINAL 0x03 #define USB_AUDIO_AC_MIXER_UNIT 0x04 #define USB_AUDIO_AC_SELECTOR_UNIT 0x05 #define USB_AUDIO_AC_FEATURE_UNIT 0x06 #define USB_AUDIO_AC_PROCESSING_UNIT 0x07 #define USB_AUDIO_AC_EXTENSION_UNIT 0x08 // A.6 Audio Class-Specific AS (Audio Streaming) Interface Descriptor Subtypes // #define USB_AUDIO_AS_UNDEFINED 0x00 #define USB_AUDIO_AS_GENERAL 0x01 #define USB_AUDIO_AS_FORMAT_TYPE 0x02 #define USB_AUDIO_AS_FORMAT_SPECIFIC 0x03 // A.7 Processing Unit Process Types // #define USB_AUDIO_PROCESS_UNDEFINED 0x00 #define USB_AUDIO_PROCESS_UPDOWNMIX 0x01 #define USB_AUDIO_PROCESS_DOLBYPROLOGIC 0x02 #define USB_AUDIO_PROCESS_3DSTEREOEXTENDER 0x03 #define USB_AUDIO_PROCESS_REVERBERATION 0x04 #define USB_AUDIO_PROCESS_CHORUS 0x05 #define USB_AUDIO_PROCESS_DYNRANGECOMP 0x06 /***************************************************************************** T Y P E D E F S *****************************************************************************/ // HID Class HID Descriptor // typedef struct _USB_HID_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; USHORT bcdHID; UCHAR bCountryCode; UCHAR bNumDescriptors; struct { UCHAR bDescriptorType; USHORT wDescriptorLength; } OptionalDescriptors[1]; } USB_HID_DESCRIPTOR, *PUSB_HID_DESCRIPTOR; // OTG Descriptor // typedef struct _USB_OTG_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bmAttributes; } USB_OTG_DESCRIPTOR, *PUSB_OTG_DESCRIPTOR; // IAD Descriptor // typedef struct _USB_IAD_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bFirstInterface; UCHAR bInterfaceCount; UCHAR bFunctionClass; UCHAR bFunctionSubClass; UCHAR bFunctionProtocol; UCHAR iFunction; } USB_IAD_DESCRIPTOR, *PUSB_IAD_DESCRIPTOR; // Common Class Endpoint Descriptor // typedef struct _USB_ENDPOINT_DESCRIPTOR2 { UCHAR bLength; // offset 0, size 1 UCHAR bDescriptorType; // offset 1, size 1 UCHAR bEndpointAddress; // offset 2, size 1 UCHAR bmAttributes; // offset 3, size 1 USHORT wMaxPacketSize; // offset 4, size 2 USHORT wInterval; // offset 6, size 2 UCHAR bSyncAddress; // offset 8, size 1 } USB_ENDPOINT_DESCRIPTOR2, *PUSB_ENDPOINT_DESCRIPTOR2; // Common Class Interface Descriptor // typedef struct _USB_INTERFACE_DESCRIPTOR2 { UCHAR bLength; // offset 0, size 1 UCHAR bDescriptorType; // offset 1, size 1 UCHAR bInterfaceNumber; // offset 2, size 1 UCHAR bAlternateSetting; // offset 3, size 1 UCHAR bNumEndpoints; // offset 4, size 1 UCHAR bInterfaceClass; // offset 5, size 1 UCHAR bInterfaceSubClass; // offset 6, size 1 UCHAR bInterfaceProtocol; // offset 7, size 1 UCHAR iInterface; // offset 8, size 1 USHORT wNumClasses; // offset 9, size 2 } USB_INTERFACE_DESCRIPTOR2, *PUSB_INTERFACE_DESCRIPTOR2; // // USB Device Class Definition for Audio Devices // typedef struct _USB_AUDIO_COMMON_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; } USB_AUDIO_COMMON_DESCRIPTOR, *PUSB_AUDIO_COMMON_DESCRIPTOR; // 4.3.2 Class-Specific AC (Audio Control) Interface Descriptor // typedef struct _USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; USHORT bcdADC; USHORT wTotalLength; UCHAR bInCollection; UCHAR baInterfaceNr[1]; } USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR, *PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR; // 4.3.2.1 Input Terminal Descriptor // typedef struct _USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bTerminalID; USHORT wTerminalType; UCHAR bAssocTerminal; UCHAR bNrChannels; USHORT wChannelConfig; UCHAR iChannelNames; UCHAR iTerminal; } USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR, *PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR; // 4.3.2.2 Output Terminal Descriptor // typedef struct _USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bTerminalID; USHORT wTerminalType; UCHAR bAssocTerminal; UCHAR bSourceID; UCHAR iTerminal; } USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR, *PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR; // 4.3.2.3 Mixer Unit Descriptor // typedef struct _USB_AUDIO_MIXER_UNIT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bUnitID; UCHAR bNrInPins; UCHAR baSourceID[1]; } USB_AUDIO_MIXER_UNIT_DESCRIPTOR, *PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR; // 4.3.2.4 Selector Unit Descriptor // typedef struct _USB_AUDIO_SELECTOR_UNIT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bUnitID; UCHAR bNrInPins; UCHAR baSourceID[1]; } USB_AUDIO_SELECTOR_UNIT_DESCRIPTOR, *PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR; // 4.3.2.5 Feature Unit Descriptor // typedef struct _USB_AUDIO_FEATURE_UNIT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bUnitID; UCHAR bSourceID; UCHAR bControlSize; UCHAR bmaControls[1]; } USB_AUDIO_FEATURE_UNIT_DESCRIPTOR, *PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR; // 4.3.2.6 Processing Unit Descriptor // typedef struct _USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bUnitID; USHORT wProcessType; UCHAR bNrInPins; UCHAR baSourceID[1]; } USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR, *PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR; // 4.3.2.7 Extension Unit Descriptor // typedef struct _USB_AUDIO_EXTENSION_UNIT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bUnitID; USHORT wExtensionCode; UCHAR bNrInPins; UCHAR baSourceID[1]; } USB_AUDIO_EXTENSION_UNIT_DESCRIPTOR, *PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR; // 4.5.2 Class-Specific AS Interface Descriptor // typedef struct _USB_AUDIO_GENERAL_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bTerminalLink; UCHAR bDelay; USHORT wFormatTag; } USB_AUDIO_GENERAL_DESCRIPTOR, *PUSB_AUDIO_GENERAL_DESCRIPTOR; // 4.6.1.2 Class-Specific AS Endpoint Descriptor // typedef struct _USB_AUDIO_ENDPOINT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bmAttributes; UCHAR bLockDelayUnits; USHORT wLockDelay; } USB_AUDIO_ENDPOINT_DESCRIPTOR, *PUSB_AUDIO_ENDPOINT_DESCRIPTOR; // // USB Device Class Definition for Audio Data Formats // typedef struct _USB_AUDIO_COMMON_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatType; } USB_AUDIO_COMMON_FORMAT_DESCRIPTOR, *PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR; // 2.1.5 Type I Format Type Descriptor // 2.3.1 Type III Format Type Descriptor // typedef struct _USB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatType; UCHAR bNrChannels; UCHAR bSubframeSize; UCHAR bBitResolution; UCHAR bSamFreqType; } USB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR, *PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR; // 2.2.6 Type II Format Type Descriptor // typedef struct _USB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatType; USHORT wMaxBitRate; USHORT wSamplesPerFrame; UCHAR bSamFreqType; } USB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR, *PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR; #pragma pack(pop) ================================================ FILE: tests/projects/windows/winsdk/usbview/usbschema.hpp ================================================ // // This file is auto-generated from XSD using the command: // xsd.exe /language:CPP /c /order /namespace:Microsoft.Kits.Samples.Usb // #pragma once #using #using #using using namespace System::Security::Permissions; // // This source code was auto-generated by xsd, Version=4.0.30319.0. // namespace Microsoft { namespace Kits { namespace Samples { namespace Usb { using namespace System::Xml::Serialization; using namespace System; ref class UvcViewAll; ref class UvcViewType; ref class MachineInfoType; ref class NoDeviceType; ref class PortConnectorType; ref class UsbPortPropertiesType; ref class NodeConnectionInfoExV2Type; ref class UsbBillboardSVIDType; ref class UsbBillboardCapabilityDescriptorType; ref class UsbDispContIdCapExtDescriptorType; ref class UsbUsb20ExtensionDescriptorType; ref class UsbSuperSpeedExtensionDescriptorType; ref class UsbBosDescriptorType; ref class UsbDeviceUnknownDescriptorType; ref class UsbDeviceIADDescriptorType; ref class UsbDeviceClassType; ref class UsbDeviceOTGDescriptorType; ref class UsbDeviceHidOptionalDescriptorsType; ref class UsbDeviceHidDescriptorType; ref class UsbDeviceInterfaceDescriptorType; ref class UsbDeviceQualifierDescriptorType; ref class UsbConfigurationDescriptorType; ref class UsbDeviceConfigurationType; ref class EndpointDescriptorType; ref class UsbDeviceType; ref class NodeConnectionInfoExType; ref class NodeConnectionInfoExStructType; ref class UsbDeviceDescriptorType; ref class UsbPipeInfoType; ref class UsbDeviceClassDetailsType; ref class ExternalHubType; ref class HubNodeInformationType; ref class HubInformationType; ref class HubDescriptorType; ref class HubCharacteristicsType; ref class HubInformationExType; ref class Hub30DescriptorType; ref class HubCapabilitiesExType; ref class RootHubType; ref class UsbHCPowerStateType; ref class UsbHCPowerStateMappingType; ref class UsbHCDeviceInfoType; ref class HostControllerType; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public enum class UsbConnectionSpeedType { /// Low, /// Full, /// High, /// Super, /// Unknown, }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public enum class UsbConnectionStatusType { /// NoDeviceConnected, /// DeviceConnected, /// DeviceFailedEnumeration, /// DeviceGeneralFailure, /// DeviceCausedOvercurrent, /// DeviceNotEnoughPower, /// DeviceNotEnoughBandwidth, /// DeviceHubNestedTooDeeply, /// DeviceInLegacyHub, /// DeviceEnumerating, /// DeviceReset, }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public enum class DevicePowerStateType { /// PowerDeviceUnspecified, /// PowerDeviceD0, /// PowerDeviceD1, /// PowerDeviceD2, /// PowerDeviceD3, /// PowerDeviceMaximum, }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public enum class HubNodeType { /// UsbHub, /// UsbMiParent, }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public enum class HubTypeType { /// UnknownHubType, /// UsbRootHub, /// Usb20Hub, /// Usb30Hub, }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(AnonymousType=true, Namespace=L"USB"), System::Xml::Serialization::XmlRootAttribute(Namespace=L"USB", IsNullable=false)] public ref class UvcViewAll { private: Microsoft::Kits::Samples::Usb::UvcViewType^ uvcViewField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::UvcViewType^ UvcView { Microsoft::Kits::Samples::Usb::UvcViewType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UvcViewType^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UvcViewType { private: Microsoft::Kits::Samples::Usb::MachineInfoType^ machineInfoField; private: cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^ >^ usbTreeField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::MachineInfoType^ MachineInfo { Microsoft::Kits::Samples::Usb::MachineInfoType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::MachineInfoType^ value); } /// public: [System::Xml::Serialization::XmlArrayAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1), System::Xml::Serialization::XmlArrayItemAttribute(L"UsbController", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, IsNullable=false)] property cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^ >^ UsbTree { cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^ >^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class MachineInfoType { private: System::Byte uvcMajorVersionField; private: System::Byte uvcMinorVersionField; private: System::Byte uvcMajorSpecVersionField; private: System::Byte uvcMinorSpecVersionField; private: System::DateTime collectionTimeField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::Byte UvcMajorVersion { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::Byte UvcMinorVersion { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::Byte UvcMajorSpecVersion { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::Byte UvcMinorSpecVersion { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::DateTime CollectionTime { System::DateTime get(); System::Void set(System::DateTime value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class NoDeviceType { private: Microsoft::Kits::Samples::Usb::PortConnectorType^ portConnectorField; private: System::String^ usbPortNumberField; private: System::String^ nameField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::PortConnectorType^ PortConnector { Microsoft::Kits::Samples::Usb::PortConnectorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::PortConnectorType^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ UsbPortNumber { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ Name { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class PortConnectorType { private: System::UInt64 connectionIndexField; private: System::UInt64 actualLengthField; private: Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^ usbPortPropertiesField; private: System::UInt16 companionIndexField; private: System::UInt16 companionPortNumberField; private: System::String^ companionHubSymbolicLinkNameField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::UInt64 ConnectionIndex { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::UInt64 ActualLength { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^ UsbPortProperties { Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::UInt16 CompanionIndex { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::UInt16 CompanionPortNumber { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property System::String^ CompanionHubSymbolicLinkName { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbPortPropertiesType { private: System::Boolean portIsUserConnectableField; private: System::Boolean portIsDebugCapableField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::Boolean PortIsUserConnectable { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::Boolean PortIsDebugCapable { System::Boolean get(); System::Void set(System::Boolean value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class NodeConnectionInfoExV2Type { private: System::UInt64 connectionIndexField; private: System::UInt64 lengthField; private: System::Boolean usb110SupportedField; private: System::Boolean usb200SupportedField; private: System::Boolean usb300SupportedField; private: System::Boolean deviceIsOperatingAtSuperSpeedOrHigherField; private: System::Boolean deviceIsSuperSpeedCapableOrHigherField; private: System::Boolean deviceIsOperatingAtSuperSpeedPlusOrHigherField; private: System::Boolean deviceIsSuperSpeedPlusCapableOrHigherField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::UInt64 ConnectionIndex { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::UInt64 Length { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::Boolean Usb110Supported { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::Boolean Usb200Supported { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::Boolean Usb300Supported { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property System::Boolean DeviceIsOperatingAtSuperSpeedOrHigher { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property System::Boolean DeviceIsSuperSpeedCapableOrHigher { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)] property System::Boolean DeviceIsOperatingAtSuperSpeedPlusOrHigher { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)] property System::Boolean DeviceIsSuperSpeedPlusCapableOrHigher { System::Boolean get(); System::Void set(System::Boolean value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbBillboardSVIDType { private: System::String^ descriptionField; private: System::String^ alternateModeStringField; private: System::UInt16 wSVIDField; private: System::Byte bAlternateModeField; private: System::Byte iAlternateModeStringField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ Description { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ AlternateModeString { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 WSVID { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BAlternateMode { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte IAlternateModeString { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbBillboardCapabilityDescriptorType { private: System::String^ vConnPowerField; private: System::String^ billboardDescriptorErrorsField; private: System::String^ addtionalInfoURLField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^ >^ usbBillboardSVIDField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::Byte bDevCapabilityTypeField; private: System::Byte iAddtionalInfoURLField; private: System::Byte bNumberOfAlternateModesField; private: System::Byte bPreferredAlternateModeField; private: System::Byte calculatedBLengthField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ VConnPower { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ BillboardDescriptorErrors { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ AddtionalInfoURL { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"UsbBillboardSVID", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^ >^ UsbBillboardSVID { cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^ >^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDevCapabilityType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte IAddtionalInfoURL { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BNumberOfAlternateModes { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BPreferredAlternateMode { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte CalculatedBLength { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDispContIdCapExtDescriptorType { private: System::String^ reservedBitErrorField; private: System::String^ containerIdStrField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::Byte bReservedField; private: System::Byte bDevCapabilityTypeField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ ReservedBitError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ ContainerIdStr { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BReserved { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDevCapabilityType { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbUsb20ExtensionDescriptorType { private: System::String^ reservedBitErrorField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::Byte bDevCapabilityTypeField; private: System::UInt64 bmAttributesField; private: System::Boolean supportsLinkPowerManagementField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ ReservedBitError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDevCapabilityType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt64 BmAttributes { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean SupportsLinkPowerManagement { System::Boolean get(); System::Void set(System::Boolean value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbSuperSpeedExtensionDescriptorType { private: System::String^ reservedAttributesBitErrorField; private: System::String^ reservedSpeedBitErrorField; private: System::String^ reservedSpeedErrorField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::Byte bDevCapabilityTypeField; private: System::UInt64 bmAttributesField; private: System::Boolean latencyToleranceMsgCapableField; private: System::Byte bFunctionalitySupportField; private: System::Byte bU1DevExitLatField; private: System::UInt16 wSpeedsSupportedField; private: System::UInt16 wU2DevExitLatField; private: System::Boolean supportsLowSpeedField; private: System::Boolean supportsFullSpeedField; private: System::Boolean supportsHighSpeedField; private: System::Boolean supportsSuperSpeedField; private: System::String^ lowestSpeedField; private: System::String^ u1DevExitLatencyStringField; private: System::String^ u2DevExitLatencyStringField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ ReservedAttributesBitError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ ReservedSpeedBitError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ ReservedSpeedError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDevCapabilityType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt64 BmAttributes { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean LatencyToleranceMsgCapable { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BFunctionalitySupport { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BU1DevExitLat { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 WSpeedsSupported { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 WU2DevExitLat { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean SupportsLowSpeed { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean SupportsFullSpeed { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean SupportsHighSpeed { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean SupportsSuperSpeed { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ LowestSpeed { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ U1DevExitLatencyString { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ U2DevExitLatencyString { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbBosDescriptorType { private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ >^ unknownDescriptorField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^ >^ usbSuperSpeedExtensionDescriptorField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^ >^ usbUsb20ExtensionDescriptorField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^ >^ usbDispContIdCapExtDescriptorField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^ >^ usbBillboardCapabilityDescriptorField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::UInt16 wTotalLengthField; private: System::Byte bNumDeviceCapsField; /// public: [System::Xml::Serialization::XmlElementAttribute(L"UnknownDescriptor", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ >^ UnknownDescriptor { cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"UsbSuperSpeedExtensionDescriptor", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^ >^ UsbSuperSpeedExtensionDescriptor { cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"UsbUsb20ExtensionDescriptor", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^ >^ UsbUsb20ExtensionDescriptor { cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"UsbDispContIdCapExtDescriptor", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^ >^ UsbDispContIdCapExtDescriptor { cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"UsbBillboardCapabilityDescriptor", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^ >^ UsbBillboardCapabilityDescriptor { cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^ >^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 WTotalLength { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BNumDeviceCaps { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceUnknownDescriptorType { private: System::String^ unknownDescriptorField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ UnknownDescriptor { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceIADDescriptorType { private: Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ functionDetailsField; private: System::String^ interfaceErrorField; private: System::String^ functionClassErrorField; private: System::String^ protocolField; private: System::String^ stringDescField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::Byte bFirstInterfaceField; private: System::Byte bInterfaceCountField; private: System::Byte bFunctionClassField; private: System::Byte bFunctionSubclassField; private: System::Byte bFunctionProtocolField; private: System::Byte iFunctionField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ FunctionDetails { Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ InterfaceError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ FunctionClassError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::String^ Protocol { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::String^ StringDesc { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BFirstInterface { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BInterfaceCount { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BFunctionClass { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BFunctionSubclass { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BFunctionProtocol { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte IFunction { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceClassType { private: System::String^ deviceClassField; private: System::String^ deviceSubclassField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ DeviceClass { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ DeviceSubclass { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceOTGDescriptorType { private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::Byte bmAttributesField; private: System::String^ attributesStringField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BmAttributes { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ AttributesString { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceHidOptionalDescriptorsType { private: System::Byte bDescriptorTypeField; private: System::UInt16 wDescriptorLengthField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 WDescriptorLength { System::UInt16 get(); System::Void set(System::UInt16 value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceHidDescriptorType { private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^ >^ optionalDescriptorField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::UInt16 bcdHIDField; private: System::Byte bCountryCodeField; private: System::Byte bNumDescriptorsField; /// public: [System::Xml::Serialization::XmlElementAttribute(L"OptionalDescriptor", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^ >^ OptionalDescriptor { cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^ >^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 BcdHID { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BCountryCode { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BNumDescriptors { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceInterfaceDescriptorType { private: Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ interfaceDetailsField; private: System::String^ protocolErrorField; private: System::String^ stringDescField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::Byte bInterfaceNumberField; private: System::Byte bAlternateSettingField; private: System::Byte bNumEndpointsField; private: System::Byte bInterfaceClassField; private: System::Byte bInterfaceSubclassField; private: System::Byte bInterfaceProtocolField; private: System::Byte iInterfaceField; private: System::UInt16 wNumClassesField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ InterfaceDetails { Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ ProtocolError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ StringDesc { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BInterfaceNumber { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BAlternateSetting { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BNumEndpoints { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BInterfaceClass { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BInterfaceSubclass { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BInterfaceProtocol { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte IInterface { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 WNumClasses { System::UInt16 get(); System::Void set(System::UInt16 value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceQualifierDescriptorType { private: System::String^ deviceClassField; private: System::Byte maxPacketSizeInBytesField; private: System::Boolean maxPacketSizeInBytesFieldSpecified; private: System::String^ deviceClassErrorField; private: System::String^ deviceSubclassErrorField; private: System::String^ deviceProtocolErrorField; private: System::String^ deviceNumConfigErrorField; private: System::String^ reservedErrorField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::UInt16 bcdUSBField; private: System::Byte bDeviceClassField; private: System::Byte bDeviceSubclassField; private: System::Byte bDeviceProtocolField; private: System::Byte bMaxPacketSize0Field; private: System::Byte numConfigurationsField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ DeviceClass { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::Byte MaxPacketSizeInBytes { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlIgnoreAttribute] property System::Boolean MaxPacketSizeInBytesSpecified { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ DeviceClassError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::String^ DeviceSubclassError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::String^ DeviceProtocolError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property System::String^ DeviceNumConfigError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property System::String^ ReservedError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 BcdUSB { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDeviceClass { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDeviceSubclass { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDeviceProtocol { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BMaxPacketSize0 { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte NumConfigurations { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbConfigurationDescriptorType { private: System::String^ configDescErrorField; private: System::String^ confValueErrorField; private: System::String^ confStringDescField; private: System::String^ attributesStrField; private: System::String^ maxCurrentField; private: System::Byte bLengthField; private: System::Byte bDescriptorTypeField; private: System::UInt16 wTotalLengthField; private: System::Byte bNumInterfacesField; private: System::Byte bConfigurationValueField; private: System::Byte iConfigurationField; private: System::Byte bmAttributesField; private: System::Byte maxPowerField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ ConfigDescError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ ConfValueError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ ConfStringDesc { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::String^ AttributesStr { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::String^ MaxCurrent { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BDescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 WTotalLength { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BNumInterfaces { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BConfigurationValue { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte IConfiguration { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte BmAttributes { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte MaxPower { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceConfigurationType { private: System::String^ deviceQualifierErrorField; private: System::String^ speedConfigurationErrorField; private: System::String^ deviceConfigurationErrorField; private: System::String^ interfaceErrorField; private: System::String^ preReleaseErrorField; private: System::String^ endpointErrorField; private: System::String^ hidErrorField; private: System::String^ otgErrorField; private: System::String^ iadErrorField; private: Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ deviceDetailsField; private: Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^ configurationDescriptorField; private: Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^ deviceQualifierDescriptorField; private: Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^ interfaceDescriptorField; private: Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ endpointDescriptorField; private: Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^ hidDescriptorField; private: Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^ otgDescriptorField; private: Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^ iadDescriptorField; private: Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ unknownDescriptorField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ DeviceQualifierError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ SpeedConfigurationError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ DeviceConfigurationError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::String^ InterfaceError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::String^ PreReleaseError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property System::String^ EndpointError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property System::String^ HidError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)] property System::String^ OtgError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)] property System::String^ IadError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)] property Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ DeviceDetails { Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)] property Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^ ConfigurationDescriptor { Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=11)] property Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^ DeviceQualifierDescriptor { Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=12)] property Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^ InterfaceDescriptor { Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=13)] property Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ EndpointDescriptor { Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=14)] property Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^ HidDescriptor { Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=15)] property Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^ OtgDescriptor { Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=16)] property Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^ IadDescriptor { Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=17)] property Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ UnknownDescriptor { Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class EndpointDescriptorType { private: System::Byte lengthField; private: System::Byte descriptorTypeField; private: System::Byte endpointAddressField; private: System::Byte attributesField; private: System::UInt16 maxPacketSizeField; private: System::Byte intervalField; private: System::UInt16 wIntervalField; private: System::Byte syncAddressField; private: System::String^ endpointDirectionField; private: System::Byte endpointIdField; private: System::String^ endpointTypeField; private: System::String^ endpointPacketInfoField; private: System::String^ endpointPacketSizeValidationField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte Length { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte DescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte EndpointAddress { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte Attributes { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 MaxPacketSize { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte Interval { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 WInterval { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte SyncAddress { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ EndpointDirection { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte EndpointId { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ EndpointType { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ EndpointPacketInfo { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ EndpointPacketSizeValidation { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceType { private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ connectionInfoField; private: Microsoft::Kits::Samples::Usb::PortConnectorType^ portConnectorField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ deviceConfigurationField; private: Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ bosDescriptorField; private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ connectionInfoV2Field; private: System::String^ usbPortNumberField; private: System::String^ serviceNameField; private: System::String^ hwIdField; private: System::String^ deviceIdField; private: System::String^ deviceNameField; private: System::String^ deviceClassField; private: System::String^ usbProtocolField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ ConnectionInfo { Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property Microsoft::Kits::Samples::Usb::PortConnectorType^ PortConnector { Microsoft::Kits::Samples::Usb::PortConnectorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::PortConnectorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"DeviceConfiguration", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ DeviceConfiguration { cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ BosDescriptor { Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ ConnectionInfoV2 { Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ get(); System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ UsbPortNumber { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ ServiceName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ HwId { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceId { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceClass { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ UsbProtocol { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class NodeConnectionInfoExType { private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^ connectionInfoStructField; private: System::String^ iProductStringDescEnField; private: Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^ deviceClassDetailsField; private: System::Byte maxPacketSizeInBytesField; private: System::String^ vendorStringField; private: System::String^ manufacturerStringField; private: System::String^ productStringField; private: System::String^ langIdStringField; private: System::String^ serialStringField; private: System::String^ pipeInfoErrorField; private: System::String^ lengthErrorField; private: System::String^ deviceErrorField; private: System::String^ packetSizeErrorField; private: System::String^ configurationCountErrorField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^ ConnectionInfoStruct { Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ IProductStringDescEn { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^ DeviceClassDetails { Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::Byte MaxPacketSizeInBytes { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::String^ VendorString { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property System::String^ ManufacturerString { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property System::String^ ProductString { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)] property System::String^ LangIdString { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)] property System::String^ SerialString { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)] property System::String^ PipeInfoError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)] property System::String^ LengthError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=11)] property System::String^ DeviceError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=12)] property System::String^ PacketSizeError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=13)] property System::String^ ConfigurationCountError { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class NodeConnectionInfoExStructType { private: System::UInt64 connectionIndexField; private: Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^ deviceDescriptorField; private: System::Byte currentConfigurationValueField; private: System::Byte speedField; private: Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType speedStrField; private: System::Boolean deviceIsHubField; private: System::Byte deviceAddressField; private: System::UInt64 numOfOpenPipesField; private: Microsoft::Kits::Samples::Usb::UsbConnectionStatusType usbConnectionStatusField; private: Microsoft::Kits::Samples::Usb::DevicePowerStateType devicePowerStateField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^ >^ pipeField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::UInt64 ConnectionIndex { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^ DeviceDescriptor { Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::Byte CurrentConfigurationValue { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::Byte Speed { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType SpeedStr { Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property System::Boolean DeviceIsHub { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property System::Byte DeviceAddress { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)] property System::UInt64 NumOfOpenPipes { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)] property Microsoft::Kits::Samples::Usb::UsbConnectionStatusType UsbConnectionStatus { Microsoft::Kits::Samples::Usb::UsbConnectionStatusType get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbConnectionStatusType value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)] property Microsoft::Kits::Samples::Usb::DevicePowerStateType DevicePowerState { Microsoft::Kits::Samples::Usb::DevicePowerStateType get(); System::Void set(Microsoft::Kits::Samples::Usb::DevicePowerStateType value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"Pipe", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)] property cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^ >^ Pipe { cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^ >^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceDescriptorType { private: System::Byte lengthField; private: System::Byte descriptorTypeField; private: System::UInt16 cdUSBField; private: System::Byte deviceClassField; private: System::Byte deviceSubclassField; private: System::Byte deviceProtocolField; private: System::Byte maxPacketSize0Field; private: System::UInt16 idVendorField; private: System::UInt16 idProductField; private: System::UInt16 cdDeviceField; private: System::Byte iManufacturerField; private: System::Byte iProductField; private: System::Byte iSerialNumberField; private: System::Byte numConfigurationsField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte Length { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte DescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 CdUSB { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte DeviceClass { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte DeviceSubclass { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte DeviceProtocol { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte MaxPacketSize0 { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 IdVendor { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 IdProduct { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 CdDevice { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte IManufacturer { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte IProduct { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte ISerialNumber { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte NumConfigurations { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbPipeInfoType { private: Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ endpointDescriptorField; private: System::UInt64 scheduleOffsetField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ EndpointDescriptor { Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::UInt64 ScheduleOffset { System::UInt64 get(); System::Void set(System::UInt64 value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbDeviceClassDetailsType { private: System::String^ deviceTypeField; private: System::String^ deviceTypeErrorField; private: System::String^ subclassTypeField; private: System::String^ subclassTypeErrorField; private: System::String^ deviceProtocolField; private: System::String^ deviceProtocolErrorField; private: System::UInt32 uvcVersionField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::String^ DeviceType { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ DeviceTypeError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ SubclassType { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::String^ SubclassTypeError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::String^ DeviceProtocol { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property System::String^ DeviceProtocolError { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property System::UInt32 UvcVersion { System::UInt32 get(); System::Void set(System::UInt32 value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class ExternalHubType { private: Microsoft::Kits::Samples::Usb::HubNodeInformationType^ hubNodeInformationField; private: System::String^ hubNameField; private: Microsoft::Kits::Samples::Usb::HubInformationExType^ hubInformationExField; private: Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ hubCapabilityExField; private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ connectionInfoField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ usbDeviceField; private: cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ noDeviceField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ deviceConfigurationField; private: Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ bosDescriptorField; private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ connectionInfoV2Field; private: cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ externalHubField; private: Microsoft::Kits::Samples::Usb::PortConnectorType^ portConnectorField; private: System::String^ serviceNameField; private: System::String^ hwIdField; private: System::String^ deviceIdField; private: System::String^ deviceNameField; private: System::String^ deviceClassField; private: System::String^ usbProtocolField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::HubNodeInformationType^ HubNodeInformation { Microsoft::Kits::Samples::Usb::HubNodeInformationType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubNodeInformationType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ HubName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property Microsoft::Kits::Samples::Usb::HubInformationExType^ HubInformationEx { Microsoft::Kits::Samples::Usb::HubInformationExType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubInformationExType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ HubCapabilityEx { Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ ConnectionInfo { Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"UsbDevice", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ UsbDevice { cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"NoDevice", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ NoDevice { cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"DeviceConfiguration", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)] property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ DeviceConfiguration { cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)] property Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ BosDescriptor { Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)] property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ ConnectionInfoV2 { Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ get(); System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"ExternalHub", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)] property cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ ExternalHub { cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=11)] property Microsoft::Kits::Samples::Usb::PortConnectorType^ PortConnector { Microsoft::Kits::Samples::Usb::PortConnectorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::PortConnectorType^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ ServiceName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ HwId { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceId { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceClass { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ UsbProtocol { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class HubNodeInformationType { private: Microsoft::Kits::Samples::Usb::HubNodeType hubNodeField; private: Microsoft::Kits::Samples::Usb::HubInformationType^ hubInformationField; private: System::UInt64 miParentNumberOfInterfacesField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::HubNodeType HubNode { Microsoft::Kits::Samples::Usb::HubNodeType get(); System::Void set(Microsoft::Kits::Samples::Usb::HubNodeType value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property Microsoft::Kits::Samples::Usb::HubInformationType^ HubInformation { Microsoft::Kits::Samples::Usb::HubInformationType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubInformationType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::UInt64 MiParentNumberOfInterfaces { System::UInt64 get(); System::Void set(System::UInt64 value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class HubInformationType { private: System::Boolean isRootHubField; private: System::Boolean isBusPoweredField; private: Microsoft::Kits::Samples::Usb::HubDescriptorType^ hubDescriptorField; private: Microsoft::Kits::Samples::Usb::HubCharacteristicsType^ hubCharacteristicsField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::Boolean IsRootHub { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::Boolean IsBusPowered { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property Microsoft::Kits::Samples::Usb::HubDescriptorType^ HubDescriptor { Microsoft::Kits::Samples::Usb::HubDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property Microsoft::Kits::Samples::Usb::HubCharacteristicsType^ HubCharacteristics { Microsoft::Kits::Samples::Usb::HubCharacteristicsType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubCharacteristicsType^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class HubDescriptorType { private: System::Byte descriptorLengthField; private: System::Byte descriptorTypeField; private: System::Byte numberOfPortsField; private: System::Byte powerOntoPowerGoodField; private: System::Byte hubControlCurrentField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte DescriptorLength { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte DescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte NumberOfPorts { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte PowerOntoPowerGood { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte HubControlCurrent { System::Byte get(); System::Void set(System::Byte value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class HubCharacteristicsType { private: System::UInt32 hubCharacteristicsValueField; private: System::String^ powerSwitchingField; private: System::Boolean compoundDeviceField; private: System::String^ overCurrentProtectionField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt32 HubCharacteristicsValue { System::UInt32 get(); System::Void set(System::UInt32 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ PowerSwitching { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean CompoundDevice { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ OverCurrentProtection { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class HubInformationExType { private: Microsoft::Kits::Samples::Usb::HubTypeType hubTypeField; private: System::UInt16 highestPortNumberField; private: Microsoft::Kits::Samples::Usb::HubDescriptorType^ hubDescriptorField; private: Microsoft::Kits::Samples::Usb::Hub30DescriptorType^ hub30DescriptorField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::HubTypeType HubType { Microsoft::Kits::Samples::Usb::HubTypeType get(); System::Void set(Microsoft::Kits::Samples::Usb::HubTypeType value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::UInt16 HighestPortNumber { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property Microsoft::Kits::Samples::Usb::HubDescriptorType^ HubDescriptor { Microsoft::Kits::Samples::Usb::HubDescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubDescriptorType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property Microsoft::Kits::Samples::Usb::Hub30DescriptorType^ Hub30Descriptor { Microsoft::Kits::Samples::Usb::Hub30DescriptorType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::Hub30DescriptorType^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class Hub30DescriptorType { private: System::Byte lengthField; private: System::Byte descriptorTypeField; private: System::Byte numberOfPortsField; private: System::UInt16 hubCharacteristicsField; private: System::Byte powerOntoPowerGoodField; private: System::Byte hubControlCurrentField; private: System::Byte hubHdrDecLatField; private: System::UInt16 hubDelayField; private: System::UInt16 deviceRemovableField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte Length { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte DescriptorType { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte NumberOfPorts { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 HubCharacteristics { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte PowerOntoPowerGood { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte HubControlCurrent { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Byte HubHdrDecLat { System::Byte get(); System::Void set(System::Byte value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 HubDelay { System::UInt16 get(); System::Void set(System::UInt16 value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::UInt16 DeviceRemovable { System::UInt16 get(); System::Void set(System::UInt16 value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class HubCapabilitiesExType { private: System::Boolean hubIsHighSpeedCapableField; private: System::Boolean hubIsHighSpeedField; private: System::Boolean hubIsMultiTtCapableField; private: System::Boolean hubIsMultiTtField; private: System::Boolean hubIsRootField; private: System::Boolean hubIsArmedWakeOnConnectField; private: System::Boolean hubIsBusPoweredField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean HubIsHighSpeedCapable { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean HubIsHighSpeed { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean HubIsMultiTtCapable { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean HubIsMultiTt { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean HubIsRoot { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean HubIsArmedWakeOnConnect { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean HubIsBusPowered { System::Boolean get(); System::Void set(System::Boolean value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class RootHubType { private: Microsoft::Kits::Samples::Usb::HubNodeInformationType^ hubNodeInformationField; private: System::String^ hubNameField; private: Microsoft::Kits::Samples::Usb::HubInformationExType^ hubInformationExField; private: Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ hubCapabilityExField; private: cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ externalHubField; private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ usbDeviceField; private: cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ noDeviceField; private: System::String^ serviceNameField; private: System::String^ hwIdField; private: System::String^ deviceIdField; private: System::String^ deviceNameField; private: System::String^ deviceClassField; private: System::String^ usbProtocolField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::HubNodeInformationType^ HubNodeInformation { Microsoft::Kits::Samples::Usb::HubNodeInformationType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubNodeInformationType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ HubName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property Microsoft::Kits::Samples::Usb::HubInformationExType^ HubInformationEx { Microsoft::Kits::Samples::Usb::HubInformationExType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubInformationExType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ HubCapabilityEx { Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"ExternalHub", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ ExternalHub { cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"UsbDevice", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ UsbDevice { cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(L"NoDevice", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ NoDevice { cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ ServiceName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ HwId { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceId { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceClass { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ UsbProtocol { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbHCPowerStateType { private: System::String^ systemStateField; private: System::String^ hostControllerStateField; private: System::String^ hubStateField; private: System::Boolean canWakeUpField; private: System::Boolean isPoweredField; /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ SystemState { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ HostControllerState { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ HubState { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean CanWakeUp { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::Boolean IsPowered { System::Boolean get(); System::Void set(System::Boolean value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbHCPowerStateMappingType { private: cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^ >^ powerMapField; private: System::String^ lastSleepStateField; /// public: [System::Xml::Serialization::XmlElementAttribute(L"PowerMap", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^ >^ PowerMap { cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^ >^ get(); System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^ >^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::String^ LastSleepState { System::String^ get(); System::Void set(System::String^ value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class UsbHCDeviceInfoType { private: System::Int64 vendorIdField; private: System::Int64 deviceIdField; private: System::String^ driverKeyField; private: System::Int64 subSysIdField; private: System::Int64 revisionField; private: System::UInt64 debugPortField; private: System::UInt64 numberOfRootPortsField; private: System::UInt64 controllerFlavorField; private: System::String^ controllerFlavorStringField; private: System::Boolean portSwitchingEnabledField; private: System::Boolean selectiveSuspendEnabledField; private: System::UInt64 legacyBiosField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property System::Int64 VendorId { System::Int64 get(); System::Void set(System::Int64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property System::Int64 DeviceId { System::Int64 get(); System::Void set(System::Int64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property System::String^ DriverKey { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)] property System::Int64 SubSysId { System::Int64 get(); System::Void set(System::Int64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)] property System::Int64 Revision { System::Int64 get(); System::Void set(System::Int64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)] property System::UInt64 DebugPort { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)] property System::UInt64 NumberOfRootPorts { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)] property System::UInt64 ControllerFlavor { System::UInt64 get(); System::Void set(System::UInt64 value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)] property System::String^ ControllerFlavorString { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)] property System::Boolean PortSwitchingEnabled { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)] property System::Boolean SelectiveSuspendEnabled { System::Boolean get(); System::Void set(System::Boolean value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=11)] property System::UInt64 LegacyBios { System::UInt64 get(); System::Void set(System::UInt64 value); } }; /// [System::CodeDom::Compiler::GeneratedCodeAttribute(L"xsd", L"4.6.24.0"), System::SerializableAttribute, System::Diagnostics::DebuggerStepThroughAttribute, System::ComponentModel::DesignerCategoryAttribute(L"code"), System::Xml::Serialization::XmlTypeAttribute(Namespace=L"USB")] public ref class HostControllerType { private: Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^ controllerInfoField; private: Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^ powerMappingField; private: Microsoft::Kits::Samples::Usb::RootHubType^ rootHubField; private: System::String^ serviceNameField; private: System::String^ hwIdField; private: System::String^ deviceIdField; private: System::String^ deviceNameField; private: System::String^ deviceClassField; private: System::String^ usbProtocolField; /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)] property Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^ ControllerInfo { Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)] property Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^ PowerMapping { Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^ value); } /// public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)] property Microsoft::Kits::Samples::Usb::RootHubType^ RootHub { Microsoft::Kits::Samples::Usb::RootHubType^ get(); System::Void set(Microsoft::Kits::Samples::Usb::RootHubType^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ ServiceName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ HwId { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceId { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceName { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ DeviceClass { System::String^ get(); System::Void set(System::String^ value); } /// public: [System::Xml::Serialization::XmlAttributeAttribute] property System::String^ UsbProtocol { System::String^ get(); System::Void set(System::String^ value); } }; } } } } namespace Microsoft { namespace Kits { namespace Samples { namespace Usb { inline Microsoft::Kits::Samples::Usb::UvcViewType^ UvcViewAll::UvcView::get() { return this->uvcViewField; } inline System::Void UvcViewAll::UvcView::set(Microsoft::Kits::Samples::Usb::UvcViewType^ value) { this->uvcViewField = value; } inline Microsoft::Kits::Samples::Usb::MachineInfoType^ UvcViewType::MachineInfo::get() { return this->machineInfoField; } inline System::Void UvcViewType::MachineInfo::set(Microsoft::Kits::Samples::Usb::MachineInfoType^ value) { this->machineInfoField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^ >^ UvcViewType::UsbTree::get() { return this->usbTreeField; } inline System::Void UvcViewType::UsbTree::set(cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^ >^ value) { this->usbTreeField = value; } inline System::Byte MachineInfoType::UvcMajorVersion::get() { return this->uvcMajorVersionField; } inline System::Void MachineInfoType::UvcMajorVersion::set(System::Byte value) { this->uvcMajorVersionField = value; } inline System::Byte MachineInfoType::UvcMinorVersion::get() { return this->uvcMinorVersionField; } inline System::Void MachineInfoType::UvcMinorVersion::set(System::Byte value) { this->uvcMinorVersionField = value; } inline System::Byte MachineInfoType::UvcMajorSpecVersion::get() { return this->uvcMajorSpecVersionField; } inline System::Void MachineInfoType::UvcMajorSpecVersion::set(System::Byte value) { this->uvcMajorSpecVersionField = value; } inline System::Byte MachineInfoType::UvcMinorSpecVersion::get() { return this->uvcMinorSpecVersionField; } inline System::Void MachineInfoType::UvcMinorSpecVersion::set(System::Byte value) { this->uvcMinorSpecVersionField = value; } inline System::DateTime MachineInfoType::CollectionTime::get() { return this->collectionTimeField; } inline System::Void MachineInfoType::CollectionTime::set(System::DateTime value) { this->collectionTimeField = value; } inline Microsoft::Kits::Samples::Usb::PortConnectorType^ NoDeviceType::PortConnector::get() { return this->portConnectorField; } inline System::Void NoDeviceType::PortConnector::set(Microsoft::Kits::Samples::Usb::PortConnectorType^ value) { this->portConnectorField = value; } inline System::String^ NoDeviceType::UsbPortNumber::get() { return this->usbPortNumberField; } inline System::Void NoDeviceType::UsbPortNumber::set(System::String^ value) { this->usbPortNumberField = value; } inline System::String^ NoDeviceType::Name::get() { return this->nameField; } inline System::Void NoDeviceType::Name::set(System::String^ value) { this->nameField = value; } inline System::UInt64 PortConnectorType::ConnectionIndex::get() { return this->connectionIndexField; } inline System::Void PortConnectorType::ConnectionIndex::set(System::UInt64 value) { this->connectionIndexField = value; } inline System::UInt64 PortConnectorType::ActualLength::get() { return this->actualLengthField; } inline System::Void PortConnectorType::ActualLength::set(System::UInt64 value) { this->actualLengthField = value; } inline Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^ PortConnectorType::UsbPortProperties::get() { return this->usbPortPropertiesField; } inline System::Void PortConnectorType::UsbPortProperties::set(Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^ value) { this->usbPortPropertiesField = value; } inline System::UInt16 PortConnectorType::CompanionIndex::get() { return this->companionIndexField; } inline System::Void PortConnectorType::CompanionIndex::set(System::UInt16 value) { this->companionIndexField = value; } inline System::UInt16 PortConnectorType::CompanionPortNumber::get() { return this->companionPortNumberField; } inline System::Void PortConnectorType::CompanionPortNumber::set(System::UInt16 value) { this->companionPortNumberField = value; } inline System::String^ PortConnectorType::CompanionHubSymbolicLinkName::get() { return this->companionHubSymbolicLinkNameField; } inline System::Void PortConnectorType::CompanionHubSymbolicLinkName::set(System::String^ value) { this->companionHubSymbolicLinkNameField = value; } inline System::Boolean UsbPortPropertiesType::PortIsUserConnectable::get() { return this->portIsUserConnectableField; } inline System::Void UsbPortPropertiesType::PortIsUserConnectable::set(System::Boolean value) { this->portIsUserConnectableField = value; } inline System::Boolean UsbPortPropertiesType::PortIsDebugCapable::get() { return this->portIsDebugCapableField; } inline System::Void UsbPortPropertiesType::PortIsDebugCapable::set(System::Boolean value) { this->portIsDebugCapableField = value; } inline System::UInt64 NodeConnectionInfoExV2Type::ConnectionIndex::get() { return this->connectionIndexField; } inline System::Void NodeConnectionInfoExV2Type::ConnectionIndex::set(System::UInt64 value) { this->connectionIndexField = value; } inline System::UInt64 NodeConnectionInfoExV2Type::Length::get() { return this->lengthField; } inline System::Void NodeConnectionInfoExV2Type::Length::set(System::UInt64 value) { this->lengthField = value; } inline System::Boolean NodeConnectionInfoExV2Type::Usb110Supported::get() { return this->usb110SupportedField; } inline System::Void NodeConnectionInfoExV2Type::Usb110Supported::set(System::Boolean value) { this->usb110SupportedField = value; } inline System::Boolean NodeConnectionInfoExV2Type::Usb200Supported::get() { return this->usb200SupportedField; } inline System::Void NodeConnectionInfoExV2Type::Usb200Supported::set(System::Boolean value) { this->usb200SupportedField = value; } inline System::Boolean NodeConnectionInfoExV2Type::Usb300Supported::get() { return this->usb300SupportedField; } inline System::Void NodeConnectionInfoExV2Type::Usb300Supported::set(System::Boolean value) { this->usb300SupportedField = value; } inline System::Boolean NodeConnectionInfoExV2Type::DeviceIsOperatingAtSuperSpeedOrHigher::get() { return this->deviceIsOperatingAtSuperSpeedOrHigherField; } inline System::Void NodeConnectionInfoExV2Type::DeviceIsOperatingAtSuperSpeedOrHigher::set(System::Boolean value) { this->deviceIsOperatingAtSuperSpeedOrHigherField = value; } inline System::Boolean NodeConnectionInfoExV2Type::DeviceIsSuperSpeedCapableOrHigher::get() { return this->deviceIsSuperSpeedCapableOrHigherField; } inline System::Void NodeConnectionInfoExV2Type::DeviceIsSuperSpeedCapableOrHigher::set(System::Boolean value) { this->deviceIsSuperSpeedCapableOrHigherField = value; } inline System::Boolean NodeConnectionInfoExV2Type::DeviceIsOperatingAtSuperSpeedPlusOrHigher::get() { return this->deviceIsOperatingAtSuperSpeedPlusOrHigherField; } inline System::Void NodeConnectionInfoExV2Type::DeviceIsOperatingAtSuperSpeedPlusOrHigher::set(System::Boolean value) { this->deviceIsOperatingAtSuperSpeedPlusOrHigherField = value; } inline System::Boolean NodeConnectionInfoExV2Type::DeviceIsSuperSpeedPlusCapableOrHigher::get() { return this->deviceIsSuperSpeedPlusCapableOrHigherField; } inline System::Void NodeConnectionInfoExV2Type::DeviceIsSuperSpeedPlusCapableOrHigher::set(System::Boolean value) { this->deviceIsSuperSpeedPlusCapableOrHigherField = value; } inline System::String^ UsbBillboardSVIDType::Description::get() { return this->descriptionField; } inline System::Void UsbBillboardSVIDType::Description::set(System::String^ value) { this->descriptionField = value; } inline System::String^ UsbBillboardSVIDType::AlternateModeString::get() { return this->alternateModeStringField; } inline System::Void UsbBillboardSVIDType::AlternateModeString::set(System::String^ value) { this->alternateModeStringField = value; } inline System::UInt16 UsbBillboardSVIDType::WSVID::get() { return this->wSVIDField; } inline System::Void UsbBillboardSVIDType::WSVID::set(System::UInt16 value) { this->wSVIDField = value; } inline System::Byte UsbBillboardSVIDType::BAlternateMode::get() { return this->bAlternateModeField; } inline System::Void UsbBillboardSVIDType::BAlternateMode::set(System::Byte value) { this->bAlternateModeField = value; } inline System::Byte UsbBillboardSVIDType::IAlternateModeString::get() { return this->iAlternateModeStringField; } inline System::Void UsbBillboardSVIDType::IAlternateModeString::set(System::Byte value) { this->iAlternateModeStringField = value; } inline System::String^ UsbBillboardCapabilityDescriptorType::VConnPower::get() { return this->vConnPowerField; } inline System::Void UsbBillboardCapabilityDescriptorType::VConnPower::set(System::String^ value) { this->vConnPowerField = value; } inline System::String^ UsbBillboardCapabilityDescriptorType::BillboardDescriptorErrors::get() { return this->billboardDescriptorErrorsField; } inline System::Void UsbBillboardCapabilityDescriptorType::BillboardDescriptorErrors::set(System::String^ value) { this->billboardDescriptorErrorsField = value; } inline System::String^ UsbBillboardCapabilityDescriptorType::AddtionalInfoURL::get() { return this->addtionalInfoURLField; } inline System::Void UsbBillboardCapabilityDescriptorType::AddtionalInfoURL::set(System::String^ value) { this->addtionalInfoURLField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^ >^ UsbBillboardCapabilityDescriptorType::UsbBillboardSVID::get() { return this->usbBillboardSVIDField; } inline System::Void UsbBillboardCapabilityDescriptorType::UsbBillboardSVID::set(cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^ >^ value) { this->usbBillboardSVIDField = value; } inline System::Byte UsbBillboardCapabilityDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbBillboardCapabilityDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbBillboardCapabilityDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbBillboardCapabilityDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::Byte UsbBillboardCapabilityDescriptorType::BDevCapabilityType::get() { return this->bDevCapabilityTypeField; } inline System::Void UsbBillboardCapabilityDescriptorType::BDevCapabilityType::set(System::Byte value) { this->bDevCapabilityTypeField = value; } inline System::Byte UsbBillboardCapabilityDescriptorType::IAddtionalInfoURL::get() { return this->iAddtionalInfoURLField; } inline System::Void UsbBillboardCapabilityDescriptorType::IAddtionalInfoURL::set(System::Byte value) { this->iAddtionalInfoURLField = value; } inline System::Byte UsbBillboardCapabilityDescriptorType::BNumberOfAlternateModes::get() { return this->bNumberOfAlternateModesField; } inline System::Void UsbBillboardCapabilityDescriptorType::BNumberOfAlternateModes::set(System::Byte value) { this->bNumberOfAlternateModesField = value; } inline System::Byte UsbBillboardCapabilityDescriptorType::BPreferredAlternateMode::get() { return this->bPreferredAlternateModeField; } inline System::Void UsbBillboardCapabilityDescriptorType::BPreferredAlternateMode::set(System::Byte value) { this->bPreferredAlternateModeField = value; } inline System::Byte UsbBillboardCapabilityDescriptorType::CalculatedBLength::get() { return this->calculatedBLengthField; } inline System::Void UsbBillboardCapabilityDescriptorType::CalculatedBLength::set(System::Byte value) { this->calculatedBLengthField = value; } inline System::String^ UsbDispContIdCapExtDescriptorType::ReservedBitError::get() { return this->reservedBitErrorField; } inline System::Void UsbDispContIdCapExtDescriptorType::ReservedBitError::set(System::String^ value) { this->reservedBitErrorField = value; } inline System::String^ UsbDispContIdCapExtDescriptorType::ContainerIdStr::get() { return this->containerIdStrField; } inline System::Void UsbDispContIdCapExtDescriptorType::ContainerIdStr::set(System::String^ value) { this->containerIdStrField = value; } inline System::Byte UsbDispContIdCapExtDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbDispContIdCapExtDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbDispContIdCapExtDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbDispContIdCapExtDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::Byte UsbDispContIdCapExtDescriptorType::BReserved::get() { return this->bReservedField; } inline System::Void UsbDispContIdCapExtDescriptorType::BReserved::set(System::Byte value) { this->bReservedField = value; } inline System::Byte UsbDispContIdCapExtDescriptorType::BDevCapabilityType::get() { return this->bDevCapabilityTypeField; } inline System::Void UsbDispContIdCapExtDescriptorType::BDevCapabilityType::set(System::Byte value) { this->bDevCapabilityTypeField = value; } inline System::String^ UsbUsb20ExtensionDescriptorType::ReservedBitError::get() { return this->reservedBitErrorField; } inline System::Void UsbUsb20ExtensionDescriptorType::ReservedBitError::set(System::String^ value) { this->reservedBitErrorField = value; } inline System::Byte UsbUsb20ExtensionDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbUsb20ExtensionDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbUsb20ExtensionDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbUsb20ExtensionDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::Byte UsbUsb20ExtensionDescriptorType::BDevCapabilityType::get() { return this->bDevCapabilityTypeField; } inline System::Void UsbUsb20ExtensionDescriptorType::BDevCapabilityType::set(System::Byte value) { this->bDevCapabilityTypeField = value; } inline System::UInt64 UsbUsb20ExtensionDescriptorType::BmAttributes::get() { return this->bmAttributesField; } inline System::Void UsbUsb20ExtensionDescriptorType::BmAttributes::set(System::UInt64 value) { this->bmAttributesField = value; } inline System::Boolean UsbUsb20ExtensionDescriptorType::SupportsLinkPowerManagement::get() { return this->supportsLinkPowerManagementField; } inline System::Void UsbUsb20ExtensionDescriptorType::SupportsLinkPowerManagement::set(System::Boolean value) { this->supportsLinkPowerManagementField = value; } inline System::String^ UsbSuperSpeedExtensionDescriptorType::ReservedAttributesBitError::get() { return this->reservedAttributesBitErrorField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::ReservedAttributesBitError::set(System::String^ value) { this->reservedAttributesBitErrorField = value; } inline System::String^ UsbSuperSpeedExtensionDescriptorType::ReservedSpeedBitError::get() { return this->reservedSpeedBitErrorField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::ReservedSpeedBitError::set(System::String^ value) { this->reservedSpeedBitErrorField = value; } inline System::String^ UsbSuperSpeedExtensionDescriptorType::ReservedSpeedError::get() { return this->reservedSpeedErrorField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::ReservedSpeedError::set(System::String^ value) { this->reservedSpeedErrorField = value; } inline System::Byte UsbSuperSpeedExtensionDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbSuperSpeedExtensionDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::Byte UsbSuperSpeedExtensionDescriptorType::BDevCapabilityType::get() { return this->bDevCapabilityTypeField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::BDevCapabilityType::set(System::Byte value) { this->bDevCapabilityTypeField = value; } inline System::UInt64 UsbSuperSpeedExtensionDescriptorType::BmAttributes::get() { return this->bmAttributesField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::BmAttributes::set(System::UInt64 value) { this->bmAttributesField = value; } inline System::Boolean UsbSuperSpeedExtensionDescriptorType::LatencyToleranceMsgCapable::get() { return this->latencyToleranceMsgCapableField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::LatencyToleranceMsgCapable::set(System::Boolean value) { this->latencyToleranceMsgCapableField = value; } inline System::Byte UsbSuperSpeedExtensionDescriptorType::BFunctionalitySupport::get() { return this->bFunctionalitySupportField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::BFunctionalitySupport::set(System::Byte value) { this->bFunctionalitySupportField = value; } inline System::Byte UsbSuperSpeedExtensionDescriptorType::BU1DevExitLat::get() { return this->bU1DevExitLatField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::BU1DevExitLat::set(System::Byte value) { this->bU1DevExitLatField = value; } inline System::UInt16 UsbSuperSpeedExtensionDescriptorType::WSpeedsSupported::get() { return this->wSpeedsSupportedField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::WSpeedsSupported::set(System::UInt16 value) { this->wSpeedsSupportedField = value; } inline System::UInt16 UsbSuperSpeedExtensionDescriptorType::WU2DevExitLat::get() { return this->wU2DevExitLatField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::WU2DevExitLat::set(System::UInt16 value) { this->wU2DevExitLatField = value; } inline System::Boolean UsbSuperSpeedExtensionDescriptorType::SupportsLowSpeed::get() { return this->supportsLowSpeedField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::SupportsLowSpeed::set(System::Boolean value) { this->supportsLowSpeedField = value; } inline System::Boolean UsbSuperSpeedExtensionDescriptorType::SupportsFullSpeed::get() { return this->supportsFullSpeedField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::SupportsFullSpeed::set(System::Boolean value) { this->supportsFullSpeedField = value; } inline System::Boolean UsbSuperSpeedExtensionDescriptorType::SupportsHighSpeed::get() { return this->supportsHighSpeedField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::SupportsHighSpeed::set(System::Boolean value) { this->supportsHighSpeedField = value; } inline System::Boolean UsbSuperSpeedExtensionDescriptorType::SupportsSuperSpeed::get() { return this->supportsSuperSpeedField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::SupportsSuperSpeed::set(System::Boolean value) { this->supportsSuperSpeedField = value; } inline System::String^ UsbSuperSpeedExtensionDescriptorType::LowestSpeed::get() { return this->lowestSpeedField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::LowestSpeed::set(System::String^ value) { this->lowestSpeedField = value; } inline System::String^ UsbSuperSpeedExtensionDescriptorType::U1DevExitLatencyString::get() { return this->u1DevExitLatencyStringField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::U1DevExitLatencyString::set(System::String^ value) { this->u1DevExitLatencyStringField = value; } inline System::String^ UsbSuperSpeedExtensionDescriptorType::U2DevExitLatencyString::get() { return this->u2DevExitLatencyStringField; } inline System::Void UsbSuperSpeedExtensionDescriptorType::U2DevExitLatencyString::set(System::String^ value) { this->u2DevExitLatencyStringField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ >^ UsbBosDescriptorType::UnknownDescriptor::get() { return this->unknownDescriptorField; } inline System::Void UsbBosDescriptorType::UnknownDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ >^ value) { this->unknownDescriptorField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^ >^ UsbBosDescriptorType::UsbSuperSpeedExtensionDescriptor::get() { return this->usbSuperSpeedExtensionDescriptorField; } inline System::Void UsbBosDescriptorType::UsbSuperSpeedExtensionDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^ >^ value) { this->usbSuperSpeedExtensionDescriptorField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^ >^ UsbBosDescriptorType::UsbUsb20ExtensionDescriptor::get() { return this->usbUsb20ExtensionDescriptorField; } inline System::Void UsbBosDescriptorType::UsbUsb20ExtensionDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^ >^ value) { this->usbUsb20ExtensionDescriptorField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^ >^ UsbBosDescriptorType::UsbDispContIdCapExtDescriptor::get() { return this->usbDispContIdCapExtDescriptorField; } inline System::Void UsbBosDescriptorType::UsbDispContIdCapExtDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^ >^ value) { this->usbDispContIdCapExtDescriptorField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^ >^ UsbBosDescriptorType::UsbBillboardCapabilityDescriptor::get() { return this->usbBillboardCapabilityDescriptorField; } inline System::Void UsbBosDescriptorType::UsbBillboardCapabilityDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^ >^ value) { this->usbBillboardCapabilityDescriptorField = value; } inline System::Byte UsbBosDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbBosDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbBosDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbBosDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::UInt16 UsbBosDescriptorType::WTotalLength::get() { return this->wTotalLengthField; } inline System::Void UsbBosDescriptorType::WTotalLength::set(System::UInt16 value) { this->wTotalLengthField = value; } inline System::Byte UsbBosDescriptorType::BNumDeviceCaps::get() { return this->bNumDeviceCapsField; } inline System::Void UsbBosDescriptorType::BNumDeviceCaps::set(System::Byte value) { this->bNumDeviceCapsField = value; } inline System::String^ UsbDeviceUnknownDescriptorType::UnknownDescriptor::get() { return this->unknownDescriptorField; } inline System::Void UsbDeviceUnknownDescriptorType::UnknownDescriptor::set(System::String^ value) { this->unknownDescriptorField = value; } inline System::Byte UsbDeviceUnknownDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbDeviceUnknownDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbDeviceUnknownDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbDeviceUnknownDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ UsbDeviceIADDescriptorType::FunctionDetails::get() { return this->functionDetailsField; } inline System::Void UsbDeviceIADDescriptorType::FunctionDetails::set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ value) { this->functionDetailsField = value; } inline System::String^ UsbDeviceIADDescriptorType::InterfaceError::get() { return this->interfaceErrorField; } inline System::Void UsbDeviceIADDescriptorType::InterfaceError::set(System::String^ value) { this->interfaceErrorField = value; } inline System::String^ UsbDeviceIADDescriptorType::FunctionClassError::get() { return this->functionClassErrorField; } inline System::Void UsbDeviceIADDescriptorType::FunctionClassError::set(System::String^ value) { this->functionClassErrorField = value; } inline System::String^ UsbDeviceIADDescriptorType::Protocol::get() { return this->protocolField; } inline System::Void UsbDeviceIADDescriptorType::Protocol::set(System::String^ value) { this->protocolField = value; } inline System::String^ UsbDeviceIADDescriptorType::StringDesc::get() { return this->stringDescField; } inline System::Void UsbDeviceIADDescriptorType::StringDesc::set(System::String^ value) { this->stringDescField = value; } inline System::Byte UsbDeviceIADDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbDeviceIADDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbDeviceIADDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbDeviceIADDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::Byte UsbDeviceIADDescriptorType::BFirstInterface::get() { return this->bFirstInterfaceField; } inline System::Void UsbDeviceIADDescriptorType::BFirstInterface::set(System::Byte value) { this->bFirstInterfaceField = value; } inline System::Byte UsbDeviceIADDescriptorType::BInterfaceCount::get() { return this->bInterfaceCountField; } inline System::Void UsbDeviceIADDescriptorType::BInterfaceCount::set(System::Byte value) { this->bInterfaceCountField = value; } inline System::Byte UsbDeviceIADDescriptorType::BFunctionClass::get() { return this->bFunctionClassField; } inline System::Void UsbDeviceIADDescriptorType::BFunctionClass::set(System::Byte value) { this->bFunctionClassField = value; } inline System::Byte UsbDeviceIADDescriptorType::BFunctionSubclass::get() { return this->bFunctionSubclassField; } inline System::Void UsbDeviceIADDescriptorType::BFunctionSubclass::set(System::Byte value) { this->bFunctionSubclassField = value; } inline System::Byte UsbDeviceIADDescriptorType::BFunctionProtocol::get() { return this->bFunctionProtocolField; } inline System::Void UsbDeviceIADDescriptorType::BFunctionProtocol::set(System::Byte value) { this->bFunctionProtocolField = value; } inline System::Byte UsbDeviceIADDescriptorType::IFunction::get() { return this->iFunctionField; } inline System::Void UsbDeviceIADDescriptorType::IFunction::set(System::Byte value) { this->iFunctionField = value; } inline System::String^ UsbDeviceClassType::DeviceClass::get() { return this->deviceClassField; } inline System::Void UsbDeviceClassType::DeviceClass::set(System::String^ value) { this->deviceClassField = value; } inline System::String^ UsbDeviceClassType::DeviceSubclass::get() { return this->deviceSubclassField; } inline System::Void UsbDeviceClassType::DeviceSubclass::set(System::String^ value) { this->deviceSubclassField = value; } inline System::Byte UsbDeviceOTGDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbDeviceOTGDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbDeviceOTGDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbDeviceOTGDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::Byte UsbDeviceOTGDescriptorType::BmAttributes::get() { return this->bmAttributesField; } inline System::Void UsbDeviceOTGDescriptorType::BmAttributes::set(System::Byte value) { this->bmAttributesField = value; } inline System::String^ UsbDeviceOTGDescriptorType::AttributesString::get() { return this->attributesStringField; } inline System::Void UsbDeviceOTGDescriptorType::AttributesString::set(System::String^ value) { this->attributesStringField = value; } inline System::Byte UsbDeviceHidOptionalDescriptorsType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbDeviceHidOptionalDescriptorsType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::UInt16 UsbDeviceHidOptionalDescriptorsType::WDescriptorLength::get() { return this->wDescriptorLengthField; } inline System::Void UsbDeviceHidOptionalDescriptorsType::WDescriptorLength::set(System::UInt16 value) { this->wDescriptorLengthField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^ >^ UsbDeviceHidDescriptorType::OptionalDescriptor::get() { return this->optionalDescriptorField; } inline System::Void UsbDeviceHidDescriptorType::OptionalDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^ >^ value) { this->optionalDescriptorField = value; } inline System::Byte UsbDeviceHidDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbDeviceHidDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbDeviceHidDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbDeviceHidDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::UInt16 UsbDeviceHidDescriptorType::BcdHID::get() { return this->bcdHIDField; } inline System::Void UsbDeviceHidDescriptorType::BcdHID::set(System::UInt16 value) { this->bcdHIDField = value; } inline System::Byte UsbDeviceHidDescriptorType::BCountryCode::get() { return this->bCountryCodeField; } inline System::Void UsbDeviceHidDescriptorType::BCountryCode::set(System::Byte value) { this->bCountryCodeField = value; } inline System::Byte UsbDeviceHidDescriptorType::BNumDescriptors::get() { return this->bNumDescriptorsField; } inline System::Void UsbDeviceHidDescriptorType::BNumDescriptors::set(System::Byte value) { this->bNumDescriptorsField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ UsbDeviceInterfaceDescriptorType::InterfaceDetails::get() { return this->interfaceDetailsField; } inline System::Void UsbDeviceInterfaceDescriptorType::InterfaceDetails::set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ value) { this->interfaceDetailsField = value; } inline System::String^ UsbDeviceInterfaceDescriptorType::ProtocolError::get() { return this->protocolErrorField; } inline System::Void UsbDeviceInterfaceDescriptorType::ProtocolError::set(System::String^ value) { this->protocolErrorField = value; } inline System::String^ UsbDeviceInterfaceDescriptorType::StringDesc::get() { return this->stringDescField; } inline System::Void UsbDeviceInterfaceDescriptorType::StringDesc::set(System::String^ value) { this->stringDescField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbDeviceInterfaceDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbDeviceInterfaceDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::BInterfaceNumber::get() { return this->bInterfaceNumberField; } inline System::Void UsbDeviceInterfaceDescriptorType::BInterfaceNumber::set(System::Byte value) { this->bInterfaceNumberField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::BAlternateSetting::get() { return this->bAlternateSettingField; } inline System::Void UsbDeviceInterfaceDescriptorType::BAlternateSetting::set(System::Byte value) { this->bAlternateSettingField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::BNumEndpoints::get() { return this->bNumEndpointsField; } inline System::Void UsbDeviceInterfaceDescriptorType::BNumEndpoints::set(System::Byte value) { this->bNumEndpointsField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::BInterfaceClass::get() { return this->bInterfaceClassField; } inline System::Void UsbDeviceInterfaceDescriptorType::BInterfaceClass::set(System::Byte value) { this->bInterfaceClassField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::BInterfaceSubclass::get() { return this->bInterfaceSubclassField; } inline System::Void UsbDeviceInterfaceDescriptorType::BInterfaceSubclass::set(System::Byte value) { this->bInterfaceSubclassField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::BInterfaceProtocol::get() { return this->bInterfaceProtocolField; } inline System::Void UsbDeviceInterfaceDescriptorType::BInterfaceProtocol::set(System::Byte value) { this->bInterfaceProtocolField = value; } inline System::Byte UsbDeviceInterfaceDescriptorType::IInterface::get() { return this->iInterfaceField; } inline System::Void UsbDeviceInterfaceDescriptorType::IInterface::set(System::Byte value) { this->iInterfaceField = value; } inline System::UInt16 UsbDeviceInterfaceDescriptorType::WNumClasses::get() { return this->wNumClassesField; } inline System::Void UsbDeviceInterfaceDescriptorType::WNumClasses::set(System::UInt16 value) { this->wNumClassesField = value; } inline System::String^ UsbDeviceQualifierDescriptorType::DeviceClass::get() { return this->deviceClassField; } inline System::Void UsbDeviceQualifierDescriptorType::DeviceClass::set(System::String^ value) { this->deviceClassField = value; } inline System::Byte UsbDeviceQualifierDescriptorType::MaxPacketSizeInBytes::get() { return this->maxPacketSizeInBytesField; } inline System::Void UsbDeviceQualifierDescriptorType::MaxPacketSizeInBytes::set(System::Byte value) { this->maxPacketSizeInBytesField = value; } inline System::Boolean UsbDeviceQualifierDescriptorType::MaxPacketSizeInBytesSpecified::get() { return this->maxPacketSizeInBytesFieldSpecified; } inline System::Void UsbDeviceQualifierDescriptorType::MaxPacketSizeInBytesSpecified::set(System::Boolean value) { this->maxPacketSizeInBytesFieldSpecified = value; } inline System::String^ UsbDeviceQualifierDescriptorType::DeviceClassError::get() { return this->deviceClassErrorField; } inline System::Void UsbDeviceQualifierDescriptorType::DeviceClassError::set(System::String^ value) { this->deviceClassErrorField = value; } inline System::String^ UsbDeviceQualifierDescriptorType::DeviceSubclassError::get() { return this->deviceSubclassErrorField; } inline System::Void UsbDeviceQualifierDescriptorType::DeviceSubclassError::set(System::String^ value) { this->deviceSubclassErrorField = value; } inline System::String^ UsbDeviceQualifierDescriptorType::DeviceProtocolError::get() { return this->deviceProtocolErrorField; } inline System::Void UsbDeviceQualifierDescriptorType::DeviceProtocolError::set(System::String^ value) { this->deviceProtocolErrorField = value; } inline System::String^ UsbDeviceQualifierDescriptorType::DeviceNumConfigError::get() { return this->deviceNumConfigErrorField; } inline System::Void UsbDeviceQualifierDescriptorType::DeviceNumConfigError::set(System::String^ value) { this->deviceNumConfigErrorField = value; } inline System::String^ UsbDeviceQualifierDescriptorType::ReservedError::get() { return this->reservedErrorField; } inline System::Void UsbDeviceQualifierDescriptorType::ReservedError::set(System::String^ value) { this->reservedErrorField = value; } inline System::Byte UsbDeviceQualifierDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbDeviceQualifierDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbDeviceQualifierDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbDeviceQualifierDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::UInt16 UsbDeviceQualifierDescriptorType::BcdUSB::get() { return this->bcdUSBField; } inline System::Void UsbDeviceQualifierDescriptorType::BcdUSB::set(System::UInt16 value) { this->bcdUSBField = value; } inline System::Byte UsbDeviceQualifierDescriptorType::BDeviceClass::get() { return this->bDeviceClassField; } inline System::Void UsbDeviceQualifierDescriptorType::BDeviceClass::set(System::Byte value) { this->bDeviceClassField = value; } inline System::Byte UsbDeviceQualifierDescriptorType::BDeviceSubclass::get() { return this->bDeviceSubclassField; } inline System::Void UsbDeviceQualifierDescriptorType::BDeviceSubclass::set(System::Byte value) { this->bDeviceSubclassField = value; } inline System::Byte UsbDeviceQualifierDescriptorType::BDeviceProtocol::get() { return this->bDeviceProtocolField; } inline System::Void UsbDeviceQualifierDescriptorType::BDeviceProtocol::set(System::Byte value) { this->bDeviceProtocolField = value; } inline System::Byte UsbDeviceQualifierDescriptorType::BMaxPacketSize0::get() { return this->bMaxPacketSize0Field; } inline System::Void UsbDeviceQualifierDescriptorType::BMaxPacketSize0::set(System::Byte value) { this->bMaxPacketSize0Field = value; } inline System::Byte UsbDeviceQualifierDescriptorType::NumConfigurations::get() { return this->numConfigurationsField; } inline System::Void UsbDeviceQualifierDescriptorType::NumConfigurations::set(System::Byte value) { this->numConfigurationsField = value; } inline System::String^ UsbConfigurationDescriptorType::ConfigDescError::get() { return this->configDescErrorField; } inline System::Void UsbConfigurationDescriptorType::ConfigDescError::set(System::String^ value) { this->configDescErrorField = value; } inline System::String^ UsbConfigurationDescriptorType::ConfValueError::get() { return this->confValueErrorField; } inline System::Void UsbConfigurationDescriptorType::ConfValueError::set(System::String^ value) { this->confValueErrorField = value; } inline System::String^ UsbConfigurationDescriptorType::ConfStringDesc::get() { return this->confStringDescField; } inline System::Void UsbConfigurationDescriptorType::ConfStringDesc::set(System::String^ value) { this->confStringDescField = value; } inline System::String^ UsbConfigurationDescriptorType::AttributesStr::get() { return this->attributesStrField; } inline System::Void UsbConfigurationDescriptorType::AttributesStr::set(System::String^ value) { this->attributesStrField = value; } inline System::String^ UsbConfigurationDescriptorType::MaxCurrent::get() { return this->maxCurrentField; } inline System::Void UsbConfigurationDescriptorType::MaxCurrent::set(System::String^ value) { this->maxCurrentField = value; } inline System::Byte UsbConfigurationDescriptorType::BLength::get() { return this->bLengthField; } inline System::Void UsbConfigurationDescriptorType::BLength::set(System::Byte value) { this->bLengthField = value; } inline System::Byte UsbConfigurationDescriptorType::BDescriptorType::get() { return this->bDescriptorTypeField; } inline System::Void UsbConfigurationDescriptorType::BDescriptorType::set(System::Byte value) { this->bDescriptorTypeField = value; } inline System::UInt16 UsbConfigurationDescriptorType::WTotalLength::get() { return this->wTotalLengthField; } inline System::Void UsbConfigurationDescriptorType::WTotalLength::set(System::UInt16 value) { this->wTotalLengthField = value; } inline System::Byte UsbConfigurationDescriptorType::BNumInterfaces::get() { return this->bNumInterfacesField; } inline System::Void UsbConfigurationDescriptorType::BNumInterfaces::set(System::Byte value) { this->bNumInterfacesField = value; } inline System::Byte UsbConfigurationDescriptorType::BConfigurationValue::get() { return this->bConfigurationValueField; } inline System::Void UsbConfigurationDescriptorType::BConfigurationValue::set(System::Byte value) { this->bConfigurationValueField = value; } inline System::Byte UsbConfigurationDescriptorType::IConfiguration::get() { return this->iConfigurationField; } inline System::Void UsbConfigurationDescriptorType::IConfiguration::set(System::Byte value) { this->iConfigurationField = value; } inline System::Byte UsbConfigurationDescriptorType::BmAttributes::get() { return this->bmAttributesField; } inline System::Void UsbConfigurationDescriptorType::BmAttributes::set(System::Byte value) { this->bmAttributesField = value; } inline System::Byte UsbConfigurationDescriptorType::MaxPower::get() { return this->maxPowerField; } inline System::Void UsbConfigurationDescriptorType::MaxPower::set(System::Byte value) { this->maxPowerField = value; } inline System::String^ UsbDeviceConfigurationType::DeviceQualifierError::get() { return this->deviceQualifierErrorField; } inline System::Void UsbDeviceConfigurationType::DeviceQualifierError::set(System::String^ value) { this->deviceQualifierErrorField = value; } inline System::String^ UsbDeviceConfigurationType::SpeedConfigurationError::get() { return this->speedConfigurationErrorField; } inline System::Void UsbDeviceConfigurationType::SpeedConfigurationError::set(System::String^ value) { this->speedConfigurationErrorField = value; } inline System::String^ UsbDeviceConfigurationType::DeviceConfigurationError::get() { return this->deviceConfigurationErrorField; } inline System::Void UsbDeviceConfigurationType::DeviceConfigurationError::set(System::String^ value) { this->deviceConfigurationErrorField = value; } inline System::String^ UsbDeviceConfigurationType::InterfaceError::get() { return this->interfaceErrorField; } inline System::Void UsbDeviceConfigurationType::InterfaceError::set(System::String^ value) { this->interfaceErrorField = value; } inline System::String^ UsbDeviceConfigurationType::PreReleaseError::get() { return this->preReleaseErrorField; } inline System::Void UsbDeviceConfigurationType::PreReleaseError::set(System::String^ value) { this->preReleaseErrorField = value; } inline System::String^ UsbDeviceConfigurationType::EndpointError::get() { return this->endpointErrorField; } inline System::Void UsbDeviceConfigurationType::EndpointError::set(System::String^ value) { this->endpointErrorField = value; } inline System::String^ UsbDeviceConfigurationType::HidError::get() { return this->hidErrorField; } inline System::Void UsbDeviceConfigurationType::HidError::set(System::String^ value) { this->hidErrorField = value; } inline System::String^ UsbDeviceConfigurationType::OtgError::get() { return this->otgErrorField; } inline System::Void UsbDeviceConfigurationType::OtgError::set(System::String^ value) { this->otgErrorField = value; } inline System::String^ UsbDeviceConfigurationType::IadError::get() { return this->iadErrorField; } inline System::Void UsbDeviceConfigurationType::IadError::set(System::String^ value) { this->iadErrorField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ UsbDeviceConfigurationType::DeviceDetails::get() { return this->deviceDetailsField; } inline System::Void UsbDeviceConfigurationType::DeviceDetails::set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^ value) { this->deviceDetailsField = value; } inline Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^ UsbDeviceConfigurationType::ConfigurationDescriptor::get() { return this->configurationDescriptorField; } inline System::Void UsbDeviceConfigurationType::ConfigurationDescriptor::set(Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^ value) { this->configurationDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^ UsbDeviceConfigurationType::DeviceQualifierDescriptor::get() { return this->deviceQualifierDescriptorField; } inline System::Void UsbDeviceConfigurationType::DeviceQualifierDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^ value) { this->deviceQualifierDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^ UsbDeviceConfigurationType::InterfaceDescriptor::get() { return this->interfaceDescriptorField; } inline System::Void UsbDeviceConfigurationType::InterfaceDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^ value) { this->interfaceDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ UsbDeviceConfigurationType::EndpointDescriptor::get() { return this->endpointDescriptorField; } inline System::Void UsbDeviceConfigurationType::EndpointDescriptor::set(Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ value) { this->endpointDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^ UsbDeviceConfigurationType::HidDescriptor::get() { return this->hidDescriptorField; } inline System::Void UsbDeviceConfigurationType::HidDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^ value) { this->hidDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^ UsbDeviceConfigurationType::OtgDescriptor::get() { return this->otgDescriptorField; } inline System::Void UsbDeviceConfigurationType::OtgDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^ value) { this->otgDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^ UsbDeviceConfigurationType::IadDescriptor::get() { return this->iadDescriptorField; } inline System::Void UsbDeviceConfigurationType::IadDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^ value) { this->iadDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ UsbDeviceConfigurationType::UnknownDescriptor::get() { return this->unknownDescriptorField; } inline System::Void UsbDeviceConfigurationType::UnknownDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^ value) { this->unknownDescriptorField = value; } inline System::Byte EndpointDescriptorType::Length::get() { return this->lengthField; } inline System::Void EndpointDescriptorType::Length::set(System::Byte value) { this->lengthField = value; } inline System::Byte EndpointDescriptorType::DescriptorType::get() { return this->descriptorTypeField; } inline System::Void EndpointDescriptorType::DescriptorType::set(System::Byte value) { this->descriptorTypeField = value; } inline System::Byte EndpointDescriptorType::EndpointAddress::get() { return this->endpointAddressField; } inline System::Void EndpointDescriptorType::EndpointAddress::set(System::Byte value) { this->endpointAddressField = value; } inline System::Byte EndpointDescriptorType::Attributes::get() { return this->attributesField; } inline System::Void EndpointDescriptorType::Attributes::set(System::Byte value) { this->attributesField = value; } inline System::UInt16 EndpointDescriptorType::MaxPacketSize::get() { return this->maxPacketSizeField; } inline System::Void EndpointDescriptorType::MaxPacketSize::set(System::UInt16 value) { this->maxPacketSizeField = value; } inline System::Byte EndpointDescriptorType::Interval::get() { return this->intervalField; } inline System::Void EndpointDescriptorType::Interval::set(System::Byte value) { this->intervalField = value; } inline System::UInt16 EndpointDescriptorType::WInterval::get() { return this->wIntervalField; } inline System::Void EndpointDescriptorType::WInterval::set(System::UInt16 value) { this->wIntervalField = value; } inline System::Byte EndpointDescriptorType::SyncAddress::get() { return this->syncAddressField; } inline System::Void EndpointDescriptorType::SyncAddress::set(System::Byte value) { this->syncAddressField = value; } inline System::String^ EndpointDescriptorType::EndpointDirection::get() { return this->endpointDirectionField; } inline System::Void EndpointDescriptorType::EndpointDirection::set(System::String^ value) { this->endpointDirectionField = value; } inline System::Byte EndpointDescriptorType::EndpointId::get() { return this->endpointIdField; } inline System::Void EndpointDescriptorType::EndpointId::set(System::Byte value) { this->endpointIdField = value; } inline System::String^ EndpointDescriptorType::EndpointType::get() { return this->endpointTypeField; } inline System::Void EndpointDescriptorType::EndpointType::set(System::String^ value) { this->endpointTypeField = value; } inline System::String^ EndpointDescriptorType::EndpointPacketInfo::get() { return this->endpointPacketInfoField; } inline System::Void EndpointDescriptorType::EndpointPacketInfo::set(System::String^ value) { this->endpointPacketInfoField = value; } inline System::String^ EndpointDescriptorType::EndpointPacketSizeValidation::get() { return this->endpointPacketSizeValidationField; } inline System::Void EndpointDescriptorType::EndpointPacketSizeValidation::set(System::String^ value) { this->endpointPacketSizeValidationField = value; } inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ UsbDeviceType::ConnectionInfo::get() { return this->connectionInfoField; } inline System::Void UsbDeviceType::ConnectionInfo::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ value) { this->connectionInfoField = value; } inline Microsoft::Kits::Samples::Usb::PortConnectorType^ UsbDeviceType::PortConnector::get() { return this->portConnectorField; } inline System::Void UsbDeviceType::PortConnector::set(Microsoft::Kits::Samples::Usb::PortConnectorType^ value) { this->portConnectorField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ UsbDeviceType::DeviceConfiguration::get() { return this->deviceConfigurationField; } inline System::Void UsbDeviceType::DeviceConfiguration::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ value) { this->deviceConfigurationField = value; } inline Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ UsbDeviceType::BosDescriptor::get() { return this->bosDescriptorField; } inline System::Void UsbDeviceType::BosDescriptor::set(Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ value) { this->bosDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ UsbDeviceType::ConnectionInfoV2::get() { return this->connectionInfoV2Field; } inline System::Void UsbDeviceType::ConnectionInfoV2::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ value) { this->connectionInfoV2Field = value; } inline System::String^ UsbDeviceType::UsbPortNumber::get() { return this->usbPortNumberField; } inline System::Void UsbDeviceType::UsbPortNumber::set(System::String^ value) { this->usbPortNumberField = value; } inline System::String^ UsbDeviceType::ServiceName::get() { return this->serviceNameField; } inline System::Void UsbDeviceType::ServiceName::set(System::String^ value) { this->serviceNameField = value; } inline System::String^ UsbDeviceType::HwId::get() { return this->hwIdField; } inline System::Void UsbDeviceType::HwId::set(System::String^ value) { this->hwIdField = value; } inline System::String^ UsbDeviceType::DeviceId::get() { return this->deviceIdField; } inline System::Void UsbDeviceType::DeviceId::set(System::String^ value) { this->deviceIdField = value; } inline System::String^ UsbDeviceType::DeviceName::get() { return this->deviceNameField; } inline System::Void UsbDeviceType::DeviceName::set(System::String^ value) { this->deviceNameField = value; } inline System::String^ UsbDeviceType::DeviceClass::get() { return this->deviceClassField; } inline System::Void UsbDeviceType::DeviceClass::set(System::String^ value) { this->deviceClassField = value; } inline System::String^ UsbDeviceType::UsbProtocol::get() { return this->usbProtocolField; } inline System::Void UsbDeviceType::UsbProtocol::set(System::String^ value) { this->usbProtocolField = value; } inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^ NodeConnectionInfoExType::ConnectionInfoStruct::get() { return this->connectionInfoStructField; } inline System::Void NodeConnectionInfoExType::ConnectionInfoStruct::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^ value) { this->connectionInfoStructField = value; } inline System::String^ NodeConnectionInfoExType::IProductStringDescEn::get() { return this->iProductStringDescEnField; } inline System::Void NodeConnectionInfoExType::IProductStringDescEn::set(System::String^ value) { this->iProductStringDescEnField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^ NodeConnectionInfoExType::DeviceClassDetails::get() { return this->deviceClassDetailsField; } inline System::Void NodeConnectionInfoExType::DeviceClassDetails::set(Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^ value) { this->deviceClassDetailsField = value; } inline System::Byte NodeConnectionInfoExType::MaxPacketSizeInBytes::get() { return this->maxPacketSizeInBytesField; } inline System::Void NodeConnectionInfoExType::MaxPacketSizeInBytes::set(System::Byte value) { this->maxPacketSizeInBytesField = value; } inline System::String^ NodeConnectionInfoExType::VendorString::get() { return this->vendorStringField; } inline System::Void NodeConnectionInfoExType::VendorString::set(System::String^ value) { this->vendorStringField = value; } inline System::String^ NodeConnectionInfoExType::ManufacturerString::get() { return this->manufacturerStringField; } inline System::Void NodeConnectionInfoExType::ManufacturerString::set(System::String^ value) { this->manufacturerStringField = value; } inline System::String^ NodeConnectionInfoExType::ProductString::get() { return this->productStringField; } inline System::Void NodeConnectionInfoExType::ProductString::set(System::String^ value) { this->productStringField = value; } inline System::String^ NodeConnectionInfoExType::LangIdString::get() { return this->langIdStringField; } inline System::Void NodeConnectionInfoExType::LangIdString::set(System::String^ value) { this->langIdStringField = value; } inline System::String^ NodeConnectionInfoExType::SerialString::get() { return this->serialStringField; } inline System::Void NodeConnectionInfoExType::SerialString::set(System::String^ value) { this->serialStringField = value; } inline System::String^ NodeConnectionInfoExType::PipeInfoError::get() { return this->pipeInfoErrorField; } inline System::Void NodeConnectionInfoExType::PipeInfoError::set(System::String^ value) { this->pipeInfoErrorField = value; } inline System::String^ NodeConnectionInfoExType::LengthError::get() { return this->lengthErrorField; } inline System::Void NodeConnectionInfoExType::LengthError::set(System::String^ value) { this->lengthErrorField = value; } inline System::String^ NodeConnectionInfoExType::DeviceError::get() { return this->deviceErrorField; } inline System::Void NodeConnectionInfoExType::DeviceError::set(System::String^ value) { this->deviceErrorField = value; } inline System::String^ NodeConnectionInfoExType::PacketSizeError::get() { return this->packetSizeErrorField; } inline System::Void NodeConnectionInfoExType::PacketSizeError::set(System::String^ value) { this->packetSizeErrorField = value; } inline System::String^ NodeConnectionInfoExType::ConfigurationCountError::get() { return this->configurationCountErrorField; } inline System::Void NodeConnectionInfoExType::ConfigurationCountError::set(System::String^ value) { this->configurationCountErrorField = value; } inline System::UInt64 NodeConnectionInfoExStructType::ConnectionIndex::get() { return this->connectionIndexField; } inline System::Void NodeConnectionInfoExStructType::ConnectionIndex::set(System::UInt64 value) { this->connectionIndexField = value; } inline Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^ NodeConnectionInfoExStructType::DeviceDescriptor::get() { return this->deviceDescriptorField; } inline System::Void NodeConnectionInfoExStructType::DeviceDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^ value) { this->deviceDescriptorField = value; } inline System::Byte NodeConnectionInfoExStructType::CurrentConfigurationValue::get() { return this->currentConfigurationValueField; } inline System::Void NodeConnectionInfoExStructType::CurrentConfigurationValue::set(System::Byte value) { this->currentConfigurationValueField = value; } inline System::Byte NodeConnectionInfoExStructType::Speed::get() { return this->speedField; } inline System::Void NodeConnectionInfoExStructType::Speed::set(System::Byte value) { this->speedField = value; } inline Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType NodeConnectionInfoExStructType::SpeedStr::get() { return this->speedStrField; } inline System::Void NodeConnectionInfoExStructType::SpeedStr::set(Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType value) { this->speedStrField = value; } inline System::Boolean NodeConnectionInfoExStructType::DeviceIsHub::get() { return this->deviceIsHubField; } inline System::Void NodeConnectionInfoExStructType::DeviceIsHub::set(System::Boolean value) { this->deviceIsHubField = value; } inline System::Byte NodeConnectionInfoExStructType::DeviceAddress::get() { return this->deviceAddressField; } inline System::Void NodeConnectionInfoExStructType::DeviceAddress::set(System::Byte value) { this->deviceAddressField = value; } inline System::UInt64 NodeConnectionInfoExStructType::NumOfOpenPipes::get() { return this->numOfOpenPipesField; } inline System::Void NodeConnectionInfoExStructType::NumOfOpenPipes::set(System::UInt64 value) { this->numOfOpenPipesField = value; } inline Microsoft::Kits::Samples::Usb::UsbConnectionStatusType NodeConnectionInfoExStructType::UsbConnectionStatus::get() { return this->usbConnectionStatusField; } inline System::Void NodeConnectionInfoExStructType::UsbConnectionStatus::set(Microsoft::Kits::Samples::Usb::UsbConnectionStatusType value) { this->usbConnectionStatusField = value; } inline Microsoft::Kits::Samples::Usb::DevicePowerStateType NodeConnectionInfoExStructType::DevicePowerState::get() { return this->devicePowerStateField; } inline System::Void NodeConnectionInfoExStructType::DevicePowerState::set(Microsoft::Kits::Samples::Usb::DevicePowerStateType value) { this->devicePowerStateField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^ >^ NodeConnectionInfoExStructType::Pipe::get() { return this->pipeField; } inline System::Void NodeConnectionInfoExStructType::Pipe::set(cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^ >^ value) { this->pipeField = value; } inline System::Byte UsbDeviceDescriptorType::Length::get() { return this->lengthField; } inline System::Void UsbDeviceDescriptorType::Length::set(System::Byte value) { this->lengthField = value; } inline System::Byte UsbDeviceDescriptorType::DescriptorType::get() { return this->descriptorTypeField; } inline System::Void UsbDeviceDescriptorType::DescriptorType::set(System::Byte value) { this->descriptorTypeField = value; } inline System::UInt16 UsbDeviceDescriptorType::CdUSB::get() { return this->cdUSBField; } inline System::Void UsbDeviceDescriptorType::CdUSB::set(System::UInt16 value) { this->cdUSBField = value; } inline System::Byte UsbDeviceDescriptorType::DeviceClass::get() { return this->deviceClassField; } inline System::Void UsbDeviceDescriptorType::DeviceClass::set(System::Byte value) { this->deviceClassField = value; } inline System::Byte UsbDeviceDescriptorType::DeviceSubclass::get() { return this->deviceSubclassField; } inline System::Void UsbDeviceDescriptorType::DeviceSubclass::set(System::Byte value) { this->deviceSubclassField = value; } inline System::Byte UsbDeviceDescriptorType::DeviceProtocol::get() { return this->deviceProtocolField; } inline System::Void UsbDeviceDescriptorType::DeviceProtocol::set(System::Byte value) { this->deviceProtocolField = value; } inline System::Byte UsbDeviceDescriptorType::MaxPacketSize0::get() { return this->maxPacketSize0Field; } inline System::Void UsbDeviceDescriptorType::MaxPacketSize0::set(System::Byte value) { this->maxPacketSize0Field = value; } inline System::UInt16 UsbDeviceDescriptorType::IdVendor::get() { return this->idVendorField; } inline System::Void UsbDeviceDescriptorType::IdVendor::set(System::UInt16 value) { this->idVendorField = value; } inline System::UInt16 UsbDeviceDescriptorType::IdProduct::get() { return this->idProductField; } inline System::Void UsbDeviceDescriptorType::IdProduct::set(System::UInt16 value) { this->idProductField = value; } inline System::UInt16 UsbDeviceDescriptorType::CdDevice::get() { return this->cdDeviceField; } inline System::Void UsbDeviceDescriptorType::CdDevice::set(System::UInt16 value) { this->cdDeviceField = value; } inline System::Byte UsbDeviceDescriptorType::IManufacturer::get() { return this->iManufacturerField; } inline System::Void UsbDeviceDescriptorType::IManufacturer::set(System::Byte value) { this->iManufacturerField = value; } inline System::Byte UsbDeviceDescriptorType::IProduct::get() { return this->iProductField; } inline System::Void UsbDeviceDescriptorType::IProduct::set(System::Byte value) { this->iProductField = value; } inline System::Byte UsbDeviceDescriptorType::ISerialNumber::get() { return this->iSerialNumberField; } inline System::Void UsbDeviceDescriptorType::ISerialNumber::set(System::Byte value) { this->iSerialNumberField = value; } inline System::Byte UsbDeviceDescriptorType::NumConfigurations::get() { return this->numConfigurationsField; } inline System::Void UsbDeviceDescriptorType::NumConfigurations::set(System::Byte value) { this->numConfigurationsField = value; } inline Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ UsbPipeInfoType::EndpointDescriptor::get() { return this->endpointDescriptorField; } inline System::Void UsbPipeInfoType::EndpointDescriptor::set(Microsoft::Kits::Samples::Usb::EndpointDescriptorType^ value) { this->endpointDescriptorField = value; } inline System::UInt64 UsbPipeInfoType::ScheduleOffset::get() { return this->scheduleOffsetField; } inline System::Void UsbPipeInfoType::ScheduleOffset::set(System::UInt64 value) { this->scheduleOffsetField = value; } inline System::String^ UsbDeviceClassDetailsType::DeviceType::get() { return this->deviceTypeField; } inline System::Void UsbDeviceClassDetailsType::DeviceType::set(System::String^ value) { this->deviceTypeField = value; } inline System::String^ UsbDeviceClassDetailsType::DeviceTypeError::get() { return this->deviceTypeErrorField; } inline System::Void UsbDeviceClassDetailsType::DeviceTypeError::set(System::String^ value) { this->deviceTypeErrorField = value; } inline System::String^ UsbDeviceClassDetailsType::SubclassType::get() { return this->subclassTypeField; } inline System::Void UsbDeviceClassDetailsType::SubclassType::set(System::String^ value) { this->subclassTypeField = value; } inline System::String^ UsbDeviceClassDetailsType::SubclassTypeError::get() { return this->subclassTypeErrorField; } inline System::Void UsbDeviceClassDetailsType::SubclassTypeError::set(System::String^ value) { this->subclassTypeErrorField = value; } inline System::String^ UsbDeviceClassDetailsType::DeviceProtocol::get() { return this->deviceProtocolField; } inline System::Void UsbDeviceClassDetailsType::DeviceProtocol::set(System::String^ value) { this->deviceProtocolField = value; } inline System::String^ UsbDeviceClassDetailsType::DeviceProtocolError::get() { return this->deviceProtocolErrorField; } inline System::Void UsbDeviceClassDetailsType::DeviceProtocolError::set(System::String^ value) { this->deviceProtocolErrorField = value; } inline System::UInt32 UsbDeviceClassDetailsType::UvcVersion::get() { return this->uvcVersionField; } inline System::Void UsbDeviceClassDetailsType::UvcVersion::set(System::UInt32 value) { this->uvcVersionField = value; } inline Microsoft::Kits::Samples::Usb::HubNodeInformationType^ ExternalHubType::HubNodeInformation::get() { return this->hubNodeInformationField; } inline System::Void ExternalHubType::HubNodeInformation::set(Microsoft::Kits::Samples::Usb::HubNodeInformationType^ value) { this->hubNodeInformationField = value; } inline System::String^ ExternalHubType::HubName::get() { return this->hubNameField; } inline System::Void ExternalHubType::HubName::set(System::String^ value) { this->hubNameField = value; } inline Microsoft::Kits::Samples::Usb::HubInformationExType^ ExternalHubType::HubInformationEx::get() { return this->hubInformationExField; } inline System::Void ExternalHubType::HubInformationEx::set(Microsoft::Kits::Samples::Usb::HubInformationExType^ value) { this->hubInformationExField = value; } inline Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ ExternalHubType::HubCapabilityEx::get() { return this->hubCapabilityExField; } inline System::Void ExternalHubType::HubCapabilityEx::set(Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ value) { this->hubCapabilityExField = value; } inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ ExternalHubType::ConnectionInfo::get() { return this->connectionInfoField; } inline System::Void ExternalHubType::ConnectionInfo::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^ value) { this->connectionInfoField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ ExternalHubType::UsbDevice::get() { return this->usbDeviceField; } inline System::Void ExternalHubType::UsbDevice::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ value) { this->usbDeviceField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ ExternalHubType::NoDevice::get() { return this->noDeviceField; } inline System::Void ExternalHubType::NoDevice::set(cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ value) { this->noDeviceField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ ExternalHubType::DeviceConfiguration::get() { return this->deviceConfigurationField; } inline System::Void ExternalHubType::DeviceConfiguration::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^ >^ value) { this->deviceConfigurationField = value; } inline Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ ExternalHubType::BosDescriptor::get() { return this->bosDescriptorField; } inline System::Void ExternalHubType::BosDescriptor::set(Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^ value) { this->bosDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ ExternalHubType::ConnectionInfoV2::get() { return this->connectionInfoV2Field; } inline System::Void ExternalHubType::ConnectionInfoV2::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^ value) { this->connectionInfoV2Field = value; } inline cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ ExternalHubType::ExternalHub::get() { return this->externalHubField; } inline System::Void ExternalHubType::ExternalHub::set(cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ value) { this->externalHubField = value; } inline Microsoft::Kits::Samples::Usb::PortConnectorType^ ExternalHubType::PortConnector::get() { return this->portConnectorField; } inline System::Void ExternalHubType::PortConnector::set(Microsoft::Kits::Samples::Usb::PortConnectorType^ value) { this->portConnectorField = value; } inline System::String^ ExternalHubType::ServiceName::get() { return this->serviceNameField; } inline System::Void ExternalHubType::ServiceName::set(System::String^ value) { this->serviceNameField = value; } inline System::String^ ExternalHubType::HwId::get() { return this->hwIdField; } inline System::Void ExternalHubType::HwId::set(System::String^ value) { this->hwIdField = value; } inline System::String^ ExternalHubType::DeviceId::get() { return this->deviceIdField; } inline System::Void ExternalHubType::DeviceId::set(System::String^ value) { this->deviceIdField = value; } inline System::String^ ExternalHubType::DeviceName::get() { return this->deviceNameField; } inline System::Void ExternalHubType::DeviceName::set(System::String^ value) { this->deviceNameField = value; } inline System::String^ ExternalHubType::DeviceClass::get() { return this->deviceClassField; } inline System::Void ExternalHubType::DeviceClass::set(System::String^ value) { this->deviceClassField = value; } inline System::String^ ExternalHubType::UsbProtocol::get() { return this->usbProtocolField; } inline System::Void ExternalHubType::UsbProtocol::set(System::String^ value) { this->usbProtocolField = value; } inline Microsoft::Kits::Samples::Usb::HubNodeType HubNodeInformationType::HubNode::get() { return this->hubNodeField; } inline System::Void HubNodeInformationType::HubNode::set(Microsoft::Kits::Samples::Usb::HubNodeType value) { this->hubNodeField = value; } inline Microsoft::Kits::Samples::Usb::HubInformationType^ HubNodeInformationType::HubInformation::get() { return this->hubInformationField; } inline System::Void HubNodeInformationType::HubInformation::set(Microsoft::Kits::Samples::Usb::HubInformationType^ value) { this->hubInformationField = value; } inline System::UInt64 HubNodeInformationType::MiParentNumberOfInterfaces::get() { return this->miParentNumberOfInterfacesField; } inline System::Void HubNodeInformationType::MiParentNumberOfInterfaces::set(System::UInt64 value) { this->miParentNumberOfInterfacesField = value; } inline System::Boolean HubInformationType::IsRootHub::get() { return this->isRootHubField; } inline System::Void HubInformationType::IsRootHub::set(System::Boolean value) { this->isRootHubField = value; } inline System::Boolean HubInformationType::IsBusPowered::get() { return this->isBusPoweredField; } inline System::Void HubInformationType::IsBusPowered::set(System::Boolean value) { this->isBusPoweredField = value; } inline Microsoft::Kits::Samples::Usb::HubDescriptorType^ HubInformationType::HubDescriptor::get() { return this->hubDescriptorField; } inline System::Void HubInformationType::HubDescriptor::set(Microsoft::Kits::Samples::Usb::HubDescriptorType^ value) { this->hubDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::HubCharacteristicsType^ HubInformationType::HubCharacteristics::get() { return this->hubCharacteristicsField; } inline System::Void HubInformationType::HubCharacteristics::set(Microsoft::Kits::Samples::Usb::HubCharacteristicsType^ value) { this->hubCharacteristicsField = value; } inline System::Byte HubDescriptorType::DescriptorLength::get() { return this->descriptorLengthField; } inline System::Void HubDescriptorType::DescriptorLength::set(System::Byte value) { this->descriptorLengthField = value; } inline System::Byte HubDescriptorType::DescriptorType::get() { return this->descriptorTypeField; } inline System::Void HubDescriptorType::DescriptorType::set(System::Byte value) { this->descriptorTypeField = value; } inline System::Byte HubDescriptorType::NumberOfPorts::get() { return this->numberOfPortsField; } inline System::Void HubDescriptorType::NumberOfPorts::set(System::Byte value) { this->numberOfPortsField = value; } inline System::Byte HubDescriptorType::PowerOntoPowerGood::get() { return this->powerOntoPowerGoodField; } inline System::Void HubDescriptorType::PowerOntoPowerGood::set(System::Byte value) { this->powerOntoPowerGoodField = value; } inline System::Byte HubDescriptorType::HubControlCurrent::get() { return this->hubControlCurrentField; } inline System::Void HubDescriptorType::HubControlCurrent::set(System::Byte value) { this->hubControlCurrentField = value; } inline System::UInt32 HubCharacteristicsType::HubCharacteristicsValue::get() { return this->hubCharacteristicsValueField; } inline System::Void HubCharacteristicsType::HubCharacteristicsValue::set(System::UInt32 value) { this->hubCharacteristicsValueField = value; } inline System::String^ HubCharacteristicsType::PowerSwitching::get() { return this->powerSwitchingField; } inline System::Void HubCharacteristicsType::PowerSwitching::set(System::String^ value) { this->powerSwitchingField = value; } inline System::Boolean HubCharacteristicsType::CompoundDevice::get() { return this->compoundDeviceField; } inline System::Void HubCharacteristicsType::CompoundDevice::set(System::Boolean value) { this->compoundDeviceField = value; } inline System::String^ HubCharacteristicsType::OverCurrentProtection::get() { return this->overCurrentProtectionField; } inline System::Void HubCharacteristicsType::OverCurrentProtection::set(System::String^ value) { this->overCurrentProtectionField = value; } inline Microsoft::Kits::Samples::Usb::HubTypeType HubInformationExType::HubType::get() { return this->hubTypeField; } inline System::Void HubInformationExType::HubType::set(Microsoft::Kits::Samples::Usb::HubTypeType value) { this->hubTypeField = value; } inline System::UInt16 HubInformationExType::HighestPortNumber::get() { return this->highestPortNumberField; } inline System::Void HubInformationExType::HighestPortNumber::set(System::UInt16 value) { this->highestPortNumberField = value; } inline Microsoft::Kits::Samples::Usb::HubDescriptorType^ HubInformationExType::HubDescriptor::get() { return this->hubDescriptorField; } inline System::Void HubInformationExType::HubDescriptor::set(Microsoft::Kits::Samples::Usb::HubDescriptorType^ value) { this->hubDescriptorField = value; } inline Microsoft::Kits::Samples::Usb::Hub30DescriptorType^ HubInformationExType::Hub30Descriptor::get() { return this->hub30DescriptorField; } inline System::Void HubInformationExType::Hub30Descriptor::set(Microsoft::Kits::Samples::Usb::Hub30DescriptorType^ value) { this->hub30DescriptorField = value; } inline System::Byte Hub30DescriptorType::Length::get() { return this->lengthField; } inline System::Void Hub30DescriptorType::Length::set(System::Byte value) { this->lengthField = value; } inline System::Byte Hub30DescriptorType::DescriptorType::get() { return this->descriptorTypeField; } inline System::Void Hub30DescriptorType::DescriptorType::set(System::Byte value) { this->descriptorTypeField = value; } inline System::Byte Hub30DescriptorType::NumberOfPorts::get() { return this->numberOfPortsField; } inline System::Void Hub30DescriptorType::NumberOfPorts::set(System::Byte value) { this->numberOfPortsField = value; } inline System::UInt16 Hub30DescriptorType::HubCharacteristics::get() { return this->hubCharacteristicsField; } inline System::Void Hub30DescriptorType::HubCharacteristics::set(System::UInt16 value) { this->hubCharacteristicsField = value; } inline System::Byte Hub30DescriptorType::PowerOntoPowerGood::get() { return this->powerOntoPowerGoodField; } inline System::Void Hub30DescriptorType::PowerOntoPowerGood::set(System::Byte value) { this->powerOntoPowerGoodField = value; } inline System::Byte Hub30DescriptorType::HubControlCurrent::get() { return this->hubControlCurrentField; } inline System::Void Hub30DescriptorType::HubControlCurrent::set(System::Byte value) { this->hubControlCurrentField = value; } inline System::Byte Hub30DescriptorType::HubHdrDecLat::get() { return this->hubHdrDecLatField; } inline System::Void Hub30DescriptorType::HubHdrDecLat::set(System::Byte value) { this->hubHdrDecLatField = value; } inline System::UInt16 Hub30DescriptorType::HubDelay::get() { return this->hubDelayField; } inline System::Void Hub30DescriptorType::HubDelay::set(System::UInt16 value) { this->hubDelayField = value; } inline System::UInt16 Hub30DescriptorType::DeviceRemovable::get() { return this->deviceRemovableField; } inline System::Void Hub30DescriptorType::DeviceRemovable::set(System::UInt16 value) { this->deviceRemovableField = value; } inline System::Boolean HubCapabilitiesExType::HubIsHighSpeedCapable::get() { return this->hubIsHighSpeedCapableField; } inline System::Void HubCapabilitiesExType::HubIsHighSpeedCapable::set(System::Boolean value) { this->hubIsHighSpeedCapableField = value; } inline System::Boolean HubCapabilitiesExType::HubIsHighSpeed::get() { return this->hubIsHighSpeedField; } inline System::Void HubCapabilitiesExType::HubIsHighSpeed::set(System::Boolean value) { this->hubIsHighSpeedField = value; } inline System::Boolean HubCapabilitiesExType::HubIsMultiTtCapable::get() { return this->hubIsMultiTtCapableField; } inline System::Void HubCapabilitiesExType::HubIsMultiTtCapable::set(System::Boolean value) { this->hubIsMultiTtCapableField = value; } inline System::Boolean HubCapabilitiesExType::HubIsMultiTt::get() { return this->hubIsMultiTtField; } inline System::Void HubCapabilitiesExType::HubIsMultiTt::set(System::Boolean value) { this->hubIsMultiTtField = value; } inline System::Boolean HubCapabilitiesExType::HubIsRoot::get() { return this->hubIsRootField; } inline System::Void HubCapabilitiesExType::HubIsRoot::set(System::Boolean value) { this->hubIsRootField = value; } inline System::Boolean HubCapabilitiesExType::HubIsArmedWakeOnConnect::get() { return this->hubIsArmedWakeOnConnectField; } inline System::Void HubCapabilitiesExType::HubIsArmedWakeOnConnect::set(System::Boolean value) { this->hubIsArmedWakeOnConnectField = value; } inline System::Boolean HubCapabilitiesExType::HubIsBusPowered::get() { return this->hubIsBusPoweredField; } inline System::Void HubCapabilitiesExType::HubIsBusPowered::set(System::Boolean value) { this->hubIsBusPoweredField = value; } inline Microsoft::Kits::Samples::Usb::HubNodeInformationType^ RootHubType::HubNodeInformation::get() { return this->hubNodeInformationField; } inline System::Void RootHubType::HubNodeInformation::set(Microsoft::Kits::Samples::Usb::HubNodeInformationType^ value) { this->hubNodeInformationField = value; } inline System::String^ RootHubType::HubName::get() { return this->hubNameField; } inline System::Void RootHubType::HubName::set(System::String^ value) { this->hubNameField = value; } inline Microsoft::Kits::Samples::Usb::HubInformationExType^ RootHubType::HubInformationEx::get() { return this->hubInformationExField; } inline System::Void RootHubType::HubInformationEx::set(Microsoft::Kits::Samples::Usb::HubInformationExType^ value) { this->hubInformationExField = value; } inline Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ RootHubType::HubCapabilityEx::get() { return this->hubCapabilityExField; } inline System::Void RootHubType::HubCapabilityEx::set(Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^ value) { this->hubCapabilityExField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ RootHubType::ExternalHub::get() { return this->externalHubField; } inline System::Void RootHubType::ExternalHub::set(cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^ >^ value) { this->externalHubField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ RootHubType::UsbDevice::get() { return this->usbDeviceField; } inline System::Void RootHubType::UsbDevice::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^ >^ value) { this->usbDeviceField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ RootHubType::NoDevice::get() { return this->noDeviceField; } inline System::Void RootHubType::NoDevice::set(cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^ >^ value) { this->noDeviceField = value; } inline System::String^ RootHubType::ServiceName::get() { return this->serviceNameField; } inline System::Void RootHubType::ServiceName::set(System::String^ value) { this->serviceNameField = value; } inline System::String^ RootHubType::HwId::get() { return this->hwIdField; } inline System::Void RootHubType::HwId::set(System::String^ value) { this->hwIdField = value; } inline System::String^ RootHubType::DeviceId::get() { return this->deviceIdField; } inline System::Void RootHubType::DeviceId::set(System::String^ value) { this->deviceIdField = value; } inline System::String^ RootHubType::DeviceName::get() { return this->deviceNameField; } inline System::Void RootHubType::DeviceName::set(System::String^ value) { this->deviceNameField = value; } inline System::String^ RootHubType::DeviceClass::get() { return this->deviceClassField; } inline System::Void RootHubType::DeviceClass::set(System::String^ value) { this->deviceClassField = value; } inline System::String^ RootHubType::UsbProtocol::get() { return this->usbProtocolField; } inline System::Void RootHubType::UsbProtocol::set(System::String^ value) { this->usbProtocolField = value; } inline System::String^ UsbHCPowerStateType::SystemState::get() { return this->systemStateField; } inline System::Void UsbHCPowerStateType::SystemState::set(System::String^ value) { this->systemStateField = value; } inline System::String^ UsbHCPowerStateType::HostControllerState::get() { return this->hostControllerStateField; } inline System::Void UsbHCPowerStateType::HostControllerState::set(System::String^ value) { this->hostControllerStateField = value; } inline System::String^ UsbHCPowerStateType::HubState::get() { return this->hubStateField; } inline System::Void UsbHCPowerStateType::HubState::set(System::String^ value) { this->hubStateField = value; } inline System::Boolean UsbHCPowerStateType::CanWakeUp::get() { return this->canWakeUpField; } inline System::Void UsbHCPowerStateType::CanWakeUp::set(System::Boolean value) { this->canWakeUpField = value; } inline System::Boolean UsbHCPowerStateType::IsPowered::get() { return this->isPoweredField; } inline System::Void UsbHCPowerStateType::IsPowered::set(System::Boolean value) { this->isPoweredField = value; } inline cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^ >^ UsbHCPowerStateMappingType::PowerMap::get() { return this->powerMapField; } inline System::Void UsbHCPowerStateMappingType::PowerMap::set(cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^ >^ value) { this->powerMapField = value; } inline System::String^ UsbHCPowerStateMappingType::LastSleepState::get() { return this->lastSleepStateField; } inline System::Void UsbHCPowerStateMappingType::LastSleepState::set(System::String^ value) { this->lastSleepStateField = value; } inline System::Int64 UsbHCDeviceInfoType::VendorId::get() { return this->vendorIdField; } inline System::Void UsbHCDeviceInfoType::VendorId::set(System::Int64 value) { this->vendorIdField = value; } inline System::Int64 UsbHCDeviceInfoType::DeviceId::get() { return this->deviceIdField; } inline System::Void UsbHCDeviceInfoType::DeviceId::set(System::Int64 value) { this->deviceIdField = value; } inline System::String^ UsbHCDeviceInfoType::DriverKey::get() { return this->driverKeyField; } inline System::Void UsbHCDeviceInfoType::DriverKey::set(System::String^ value) { this->driverKeyField = value; } inline System::Int64 UsbHCDeviceInfoType::SubSysId::get() { return this->subSysIdField; } inline System::Void UsbHCDeviceInfoType::SubSysId::set(System::Int64 value) { this->subSysIdField = value; } inline System::Int64 UsbHCDeviceInfoType::Revision::get() { return this->revisionField; } inline System::Void UsbHCDeviceInfoType::Revision::set(System::Int64 value) { this->revisionField = value; } inline System::UInt64 UsbHCDeviceInfoType::DebugPort::get() { return this->debugPortField; } inline System::Void UsbHCDeviceInfoType::DebugPort::set(System::UInt64 value) { this->debugPortField = value; } inline System::UInt64 UsbHCDeviceInfoType::NumberOfRootPorts::get() { return this->numberOfRootPortsField; } inline System::Void UsbHCDeviceInfoType::NumberOfRootPorts::set(System::UInt64 value) { this->numberOfRootPortsField = value; } inline System::UInt64 UsbHCDeviceInfoType::ControllerFlavor::get() { return this->controllerFlavorField; } inline System::Void UsbHCDeviceInfoType::ControllerFlavor::set(System::UInt64 value) { this->controllerFlavorField = value; } inline System::String^ UsbHCDeviceInfoType::ControllerFlavorString::get() { return this->controllerFlavorStringField; } inline System::Void UsbHCDeviceInfoType::ControllerFlavorString::set(System::String^ value) { this->controllerFlavorStringField = value; } inline System::Boolean UsbHCDeviceInfoType::PortSwitchingEnabled::get() { return this->portSwitchingEnabledField; } inline System::Void UsbHCDeviceInfoType::PortSwitchingEnabled::set(System::Boolean value) { this->portSwitchingEnabledField = value; } inline System::Boolean UsbHCDeviceInfoType::SelectiveSuspendEnabled::get() { return this->selectiveSuspendEnabledField; } inline System::Void UsbHCDeviceInfoType::SelectiveSuspendEnabled::set(System::Boolean value) { this->selectiveSuspendEnabledField = value; } inline System::UInt64 UsbHCDeviceInfoType::LegacyBios::get() { return this->legacyBiosField; } inline System::Void UsbHCDeviceInfoType::LegacyBios::set(System::UInt64 value) { this->legacyBiosField = value; } inline Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^ HostControllerType::ControllerInfo::get() { return this->controllerInfoField; } inline System::Void HostControllerType::ControllerInfo::set(Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^ value) { this->controllerInfoField = value; } inline Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^ HostControllerType::PowerMapping::get() { return this->powerMappingField; } inline System::Void HostControllerType::PowerMapping::set(Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^ value) { this->powerMappingField = value; } inline Microsoft::Kits::Samples::Usb::RootHubType^ HostControllerType::RootHub::get() { return this->rootHubField; } inline System::Void HostControllerType::RootHub::set(Microsoft::Kits::Samples::Usb::RootHubType^ value) { this->rootHubField = value; } inline System::String^ HostControllerType::ServiceName::get() { return this->serviceNameField; } inline System::Void HostControllerType::ServiceName::set(System::String^ value) { this->serviceNameField = value; } inline System::String^ HostControllerType::HwId::get() { return this->hwIdField; } inline System::Void HostControllerType::HwId::set(System::String^ value) { this->hwIdField = value; } inline System::String^ HostControllerType::DeviceId::get() { return this->deviceIdField; } inline System::Void HostControllerType::DeviceId::set(System::String^ value) { this->deviceIdField = value; } inline System::String^ HostControllerType::DeviceName::get() { return this->deviceNameField; } inline System::Void HostControllerType::DeviceName::set(System::String^ value) { this->deviceNameField = value; } inline System::String^ HostControllerType::DeviceClass::get() { return this->deviceClassField; } inline System::Void HostControllerType::DeviceClass::set(System::String^ value) { this->deviceClassField = value; } inline System::String^ HostControllerType::UsbProtocol::get() { return this->usbProtocolField; } inline System::Void HostControllerType::UsbProtocol::set(System::String^ value) { this->usbProtocolField = value; } } } } } ================================================ FILE: tests/projects/windows/winsdk/usbview/usbviddesc.h ================================================ /*++ Copyright (c) 2002-2003 Microsoft Corporation Module Name: USBVIDDESC.H Abstract: This is a header file for USB Video Class Specific descriptors which are not yet in a standard system header file. Environment: user mode Revision History: 11-20-2002 : created 03-28-2003 : major updates to support latest UVC specs --*/ #pragma pack(push, 1) /***************************************************************************** D E F I N E S *****************************************************************************/ //global version for USB Video Class spec version #define BCDVDC 0x0083 // // USB Device Class Definition for Video Devices v8.c // Appendix A. Video Device Class Codes // // A.1 Video Interface Class Code //TBD Normally would be in USB100.h but not official yet #define USB_DEVICE_CLASS_VIDEO 0x0E #define USB_DEVICE_CLASS_VIDEO_PRERELEASE 0xFF //CC_VIDEO in spec. The rest of the codes will be USB_VIDEO plus text from spec codes // A.2 Video Interface Subclass Codes // #define USB_VIDEO_SC_UNDEFINED 0x00 #define USB_VIDEO_SC_VIDEOCONTROL 0x01 #define USB_VIDEO_SC_VIDEOSTREAMING 0x02 #define USB_VIDEO_SC_VIDEO_INTERFACE_COLLECTION 0x03 // A.3 Video Interface Protocol Codes // #define USB_VIDEO_PC_PROTOCOL_UNDEFINED 0x00 // A.4 Video Class-Specific Descriptor Types // #define USB_VIDEO_CS_UNDEFINED 0x20 #define USB_VIDEO_CS_DEVICE 0x21 #define USB_VIDEO_CS_CONFIGURATION 0x22 #define USB_VIDEO_CS_STRING 0x23 #define USB_VIDEO_CS_INTERFACE 0x24 #define USB_VIDEO_CS_ENDPOINT 0x25 // A.5 Video Class-Specific VC (Video Control) Interface Descriptor Subtypes // #define USB_VIDEO_VC_DESCRIPTOR_UNDEFINED 0x00 #define USB_VIDEO_VC_HEADER 0x01 #define USB_VIDEO_VC_INPUT_TERMINAL 0x02 #define USB_VIDEO_VC_OUTPUT_TERMINAL 0x03 #define USB_VIDEO_VC_SELECTOR_UNIT 0x04 #define USB_VIDEO_VC_PROCESSING_UNIT 0x05 #define USB_VIDEO_VC_EXTENSION_UNIT 0x06 // A.6 Video Class-Specific VS (Video Streaming) Interface Descriptor Subtypes // #define USB_VIDEO_VS_UNDEFINED 0x00 #define USB_VIDEO_VS_INPUT_HEADER 0x01 #define USB_VIDEO_VS_OUTPUT_HEADER 0x02 #define USB_VIDEO_VS_STILL_IMAGE_FRAME 0x03 #define USB_VIDEO_VS_FORMAT_UNCOMPRESSED 0x04 #define USB_VIDEO_VS_FRAME_UNCOMPRESSED 0x05 #define USB_VIDEO_VS_FORMAT_MJPEG 0x06 #define USB_VIDEO_VS_FRAME_MJPEG 0x07 #define USB_VIDEO_VS_FORMAT_MPEG1 0x08 #define USB_VIDEO_VS_FORMAT_MPEG2PS 0x09 #define USB_VIDEO_VS_FORMAT_MPEG2TS 0x0A #define USB_VIDEO_VS_FORMAT_MPEG4SL 0x0B #define USB_VIDEO_VS_FORMAT_DV 0x0C #define USB_VIDEO_VS_COLORFORMAT 0x0D #define USB_VIDEO_VS_FORMAT_VENDOR 0x0E #define USB_VIDEO_VS_FRAME_VENDOR 0x0F // A.7 Video Class-Specific Endpoint Descriptor Subtypes // #define USB_VIDEO_EP_UNDEFINED 0x00 #define USB_VIDEO_EP_GENERAL 0x01 #define USB_VIDEO_EP_ENDPOINT 0x02 #define USB_VIDEO_EP_INTERRUPT 0x03 // // Below definitions only necessary if testing requests // // A.8 Video Class-Specific Request Codes // #define USB_VIDEO_RC_UNDEFINED 0x00 #define USB_VIDEO_SET_CUR 0x01 #define USB_VIDEO_GET_CUR 0x81 #define USB_VIDEO_GET_MIN 0x82 #define USB_VIDEO_GET_MAX 0x83 #define USB_VIDEO_GET_RES 0x84 #define USB_VIDEO_GET_LEN 0x85 #define USB_VIDEO_GET_INFO 0x86 #define USB_VIDEO_GET_DEF 0x87 // A.9 Control Selector Codes // A.9.1 VideoControl Interface Control Selectors #define USB_VIDEO_VC_UNDEFINED_CONTROL 0x00 #define USB_VIDEO_VC_VIDEO_POWER_MODE_CONTROL 0x01 #define USB_VIDEO_VC_REQUEST_ERROR_CODE_CONTROL 0x02 #define USB_VIDEO_VC_INDICATE_HOST_CLOCK_CONTROL 0x03 //A.9.2 Terminal Control Selectors // #define USB_VIDEO_TE_CONTROL_UNDEFINED 0x00 //A.9.3 Selector Unit Control Selectors // #define USB_VIDEO_SU_CONTROL_UNDEFINED 0x00 #define USB_VIDEO_SU_INPUT_SELECT_CONTROL 0x01 //A.9.4 Camera Terminal Control Selectors // #define USB_VIDEO_CT_CONTROL_UNDEFINED 0x00 #define USB_VIDEO_CT_SCANNING_MODE_CONTROL 0x01 #define USB_VIDEO_CT_AE_MODE_CONTROL 0x02 #define USB_VIDEO_CT_AE_PRIORITY_CONTROL 0x03 #define USB_VIDEO_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 #define USB_VIDEO_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 #define USB_VIDEO_CT_FOCUS_ABSOLUTE_CONTROL 0x06 #define USB_VIDEO_CT_FOCUS_RELATIVE_CONTROL 0x07 #define USB_VIDEO_CT_FOCUS_AUTO_CONTROL 0x08 #define USB_VIDEO_CT_IRIS_ABSOLUTE_CONTROL 0x09 #define USB_VIDEO_CT_IRIS_RELATIVE_CONTROL 0x0A #define USB_VIDEO_CT_ZOOM_ABSOLUTE_CONTROL 0x0B #define USB_VIDEO_CT_ZOOM_RELATIVE_CONTROL 0x0C #define USB_VIDEO_CT_PANTILT_ABSOLUTE_CONTROL 0x0D #define USB_VIDEO_CT_PANTILT_RELATIVE_CONTROL 0x0E #define USB_VIDEO_CT_ROLL_ABSOLUTE_CONTROL 0x0F #define USB_VIDEO_CT_ROLL_RELATIVE_CONTROL 0x10 //A.9.5 Processing Unit Control Selectors // #define USB_VIDEO_PU_CONTROL_UNDEFINED 0x04 #define USB_VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 #define USB_VIDEO_PU_BRIGHTNESS_CONTROL 0x02 #define USB_VIDEO_PU_CONTRAST_CONTROL 0x03 #define USB_VIDEO_PU_GAIN_CONTROL 0x04 #define USB_VIDEO_PU_POWER_LINE_FREQUENCY_CONTROL 0x05 #define USB_VIDEO_PU_HUE_CONTROL 0x06 #define USB_VIDEO_PU_SATURATION_CONTROL 0x07 #define USB_VIDEO_PU_SHARPNESS_CONTROL 0x08 #define USB_VIDEO_PU_GAMMA_CONTROL 0x09 #define USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0A #define USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0B #define USB_VIDEO_PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0C #define USB_VIDEO_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0D #define USB_VIDEO_PU_DIGITAL_MULTIPLIER_CONTROL 0x0E #define USB_VIDEO_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0F #define USB_VIDEO_PU_HUE_AUTO_CONTROL 0x10 //A.9.6 Extension Unit Control Selectors // #define USB_VIDEO_XU_CONTROL_UNDEFINED 0x00 //A.9.7 VideoStreaming Interface Control Selectors // #define USB_VIDEO_VS_CONTROL_UNDEFINED 0x00 #define USB_VIDEO_VS_PROBE_CONTROL 0x01 #define USB_VIDEO_VS_COMMIT_CONTROL 0x02 #define USB_VIDEO_VS_STILL_PROBE_CONTROL 0x03 #define USB_VIDEO_VS_STILL_COMMIT_CONTROL 0x04 #define USB_VIDEO_VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 #define USB_VIDEO_VS_STREAM_ERROR_CODE_CONTROL 0x06 #define USB_VIDEO_VS_GENERATE_KEY_FRAME_CONTROL 0x07 #define USB_VIDEO_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 #define USB_VIDEO_VS_SYNCH_DELAY_CONTROL 0x09 #define TapeControls 0 #define TransportModes 1 #define CameraControls 2 #define ProcessorControls 3 #define InHeaderControls 4 /***************************************************************************** T Y P E D E F S *****************************************************************************/ /***************************************************************************** USB Device Class Definition for Video Devices v8.b *****************************************************************************/ typedef struct _USB_VIDEO_COMMON_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; } USB_VIDEO_COMMON_DESCRIPTOR, *PUSB_VIDEO_COMMON_DESCRIPTOR; // 3.6.2 Class-Specific VC (Video Control) Interface Descriptor // typedef struct _USB_VIDEO_VC_INTERFACE_HEADER_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; USHORT bcdVDC; USHORT wTotalLength; ULONG32 dwClockFrequency; UCHAR bInCollection; // UCHAR baInterfaceNr; // variable length (0 minimum) } USB_VIDEO_VC_INTERFACE_HEADER_DESCRIPTOR, *PUSB_VIDEO_VC_INTERFACE_HEADER_DESCRIPTOR; // 3.6.2.1 Input Terminal Descriptor // typedef struct _USB_VIDEO_INPUT_TERMINAL_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bTerminalID; USHORT wTerminalType; UCHAR bAssocTerminal; UCHAR iTerminal; } USB_VIDEO_INPUT_TERMINAL_DESCRIPTOR, *PUSB_VIDEO_INPUT_TERMINAL_DESCRIPTOR; // 3.6.2.2 Output Terminal Descriptor // typedef struct _USB_VIDEO_OUTPUT_TERMINAL_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bTerminalID; USHORT wTerminalType; UCHAR bAssocTerminal; UCHAR bSourceID; UCHAR iTerminal; } USB_VIDEO_OUTPUT_TERMINAL_DESCRIPTOR, *PUSB_VIDEO_OUTPUT_TERMINAL_DESCRIPTOR; // 3.6.2.3 Camera Unit Descriptor // typedef struct _USB_VIDEO_CAMERA_TERMINAL_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bTerminalID; USHORT wTerminalType; UCHAR bAssocTerminal; UCHAR iTerminal; USHORT wObjectiveFocalLengthMin; USHORT wObjectiveFocalLengthMax; USHORT wOcularFocalLength; UCHAR bControlSize; // UCHAR bmControls; // variable length (0 min, 3 max) } USB_VIDEO_CAMERA_TERMINAL_DESCRIPTOR, *PUSB_VIDEO_CAMERA_TERMINAL_DESCRIPTOR; // 3.6.2.4 Selector Unit Descriptor // typedef struct _USB_VIDEO_SELECTOR_UNIT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bUnitID; UCHAR bNrInPins; UCHAR baSourceID; // variable length (1 minimum) UCHAR iSelector; } USB_VIDEO_SELECTOR_UNIT_DESCRIPTOR, *PUSB_VIDEO_SELECTOR_UNIT_DESCRIPTOR; // 3.6.2.5 Processing Unit Descriptor // typedef struct _USB_VIDEO_PROCESSING_UNIT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bUnitID; UCHAR bSourceID; USHORT wMaxMultiplier; UCHAR bControlSize; // UCHAR bmControls; // variable length (0 minimum) UCHAR iProcessing; } USB_VIDEO_PROCESSING_UNIT_DESCRIPTOR, *PUSB_VIDEO_PROCESSING_UNIT_DESCRIPTOR; // 3.6.2.6 Extension Unit Descriptor // typedef struct _USB_VIDEO_EXTENSION_UNIT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bUnitID; GUID guidExtensionCode; UCHAR bNumControls; UCHAR bNrInPins; UCHAR baSourceID; // variable length (1 minimum) // UCHAR bControlSize; // UCHAR bmControls; // variable length (0 minimum) // UCHAR iExtension; } USB_VIDEO_EXTENSION_UNIT_DESCRIPTOR, *PUSB_VIDEO_EXTENSION_UNIT_DESCRIPTOR; // 3.7.2.2 Class-Specific VC Interrupt EndPoint Descriptor // typedef struct _USB_VIDEO_VC_INTERRUPT_ENDPOINT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubType; USHORT wMaxTransferSize; } USB_VIDEO_VC_INTERRUPT_ENDPOINT_DESCRIPTOR, *PUSB_VIDEO_VC_INTERRUPT_ENDPOINT_DESCRIPTOR; // 3.8.2.1 Class-Specific Input Header Descriptor // typedef struct _USB_VIDEO_INPUT_HEADER_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bNumFormats; USHORT wTotalLength; UCHAR bEndpointAddress; UCHAR bmInfo; UCHAR bTerminalLink; UCHAR bStillCaptureMethod; UCHAR bTriggerSupport; UCHAR bTriggerUsage; UCHAR bControlSize; // UCHAR bmaControls; // variable length (0 minimum) } USB_VIDEO_INPUT_HEADER_DESCRIPTOR, *PUSB_VIDEO_INPUT_HEADER_DESCRIPTOR; // 3.8.2.2 Class-Specific Output Header Descriptor // typedef struct _USB_VIDEO_OUTPUT_HEADER_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bNumFormats; USHORT wTotalLength; UCHAR bEndpointAddress; UCHAR bTerminalLink; } USB_VIDEO_OUTPUT_HEADER_DESCRIPTOR, *PUSB_VIDEO_OUTPUT_HEADER_DESCRIPTOR; // 3.8.2.3 Payload Format Descriptors //Payload Format Descriptor Document //Uncompressed Video DWGVideo Payload Uncompressed 0.xx.doc //MJPEG Video DWGVideo Payload MJPEG Format Ver0.xx.doc //MPEG1 System Stream DWGVideo Payload MPEG1 System Stream, MPEG2-PS Format Ver0.xx.doc //MPEG2 PS DWGVideo Payload MPEG1 System Stream, MPEG2-PS Format Ver0.xx.doc //MPEG-2 TS DWGVideo Payload MPEG2TS Format Ver0.xx.doc //MPEG-4 SL DWGVideo Payload MPEG4 SL format Ver0.xx.doc //DV DWGVideo Payload DV Format Ver0.xx.doc // 3.8.2.4 Video Frame Descriptor // //Video Frame Descriptor Document //Uncompressed DWGVideo Payload Uncompressed 0.xx.doc //MJPEG DWGVideo Payload MJPEG Format Ver0.xx.doc // 3.8.2.5 Still Image Frame Descriptor // typedef struct _VIDEO_STILL_IMAGE { USHORT wWidth; USHORT wHeight; } VIDEO_STILL_IMAGE, *PVIDEO_STILL_IMAGE; typedef struct _USB_VIDEO_STILL_IMAGE_FRAME_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bEndpointAddress; UCHAR bNumImageSizePatterns; VIDEO_STILL_IMAGE dwStillImage; // variable count UCHAR bNumCompressionPattern; UCHAR bCompression; // variable count } USB_VIDEO_STILL_IMAGE_FRAME_DESCRIPTOR, *PUSB_VIDEO_STILL_IMAGE_FRAME_DESCRIPTOR; // 3.8.2.6 Color Matching Descriptor // typedef struct _USB_VIDEO_COLOR_MATCHING_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bColorPrimaries; UCHAR bTransferCharacteristics; UCHAR bMatrixCoefficients; } USB_VIDEO_COLOR_MATCHING_DESCRIPTOR, *PUSB_VIDEO_COLOR_MATCHING_DESCRIPTOR; /* // 3.9.1 Class-specific VC Interrupt Endpoint Descriptor typedef struct _USB_VIDEO_VS_ENDPOINT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubType; USHORT wMaxTransferSize; } USB_VIDEO_VS_ENDPOINT_DESCRIPTOR, *PUSB_VIDEO_VS_ENDPOINT_DESCRIPTOR; */ // // USB Device Class Definition for Video Devices: Uncompressed Payload 0.8a Draft Revision // // 3.1.1 Uncompressed Video Format Descriptor // typedef struct _USB_VIDEO_UNCOMPRESSED_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bNumFrameDescriptors; GUID guidFormat; UCHAR bBitsPerPixel; UCHAR bDefaultFrameIndex; UCHAR bAspectRatioX; UCHAR bAspectRatioY; UCHAR bmInterlaceFlags; UCHAR bCopyProtect; } USB_VIDEO_UNCOMPRESSED_FORMAT_DESCRIPTOR, *PUSB_VIDEO_UNCOMPRESSED_FORMAT_DESCRIPTOR; // 3.1.2 Uncompressed Video Frame Descriptor Common // typedef struct _USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_COMMON { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; } USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_COMMON, *PUSB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_COMMON; // 3.1.2 Uncompressed Video Frame Descriptor - Continuous // typedef struct _USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_CONTINUOUS { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG32 dwMinFrameInterval; ULONG32 dwMaxFrameInterval; ULONG32 dwFrameIntervalStep; } USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_CONTINUOUS, *PUSB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_CONTINUOUS; // 3.1.2 Uncompressed Video Frame Descriptor - Discrete // typedef struct _USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_DISCRETE { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG32 dwFrameInterval; // variable count } USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_DISCRETE, *PUSB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_DISCRETE; // // USB Device Class Definition for Video Devices: Motion-JPEG Payload 0.8a Draft Revision // 3.1.1 MJPEG Video Format Descriptor // typedef struct _USB_VIDEO_MJPEG_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bNumFrameDescriptors; UCHAR bmFlags; UCHAR bDefaultFrameIndex; UCHAR bAspectRatioX; UCHAR bAspectRatioY; UCHAR bmInterlaceFlags; UCHAR bCopyProtect; } USB_VIDEO_MJPEG_FORMAT_DESCRIPTOR, *PUSB_VIDEO_MJPEG_FORMAT_DESCRIPTOR; // 3.1.2 MJPEG Video Frame Descriptors Common // typedef struct _USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_COMMON { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; } USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_COMMON, *PUSB_VIDEO_MJPEG_FRAME_DESCRIPTOR_COMMON; // 3.1.2 MJPEG Video Frame Descriptors - Continuous // typedef struct _USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_CONTINUOUS { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG32 dwMinFrameInterval; ULONG32 dwMaxFrameInterval; ULONG32 dwFrameIntervalStep; } USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_CONTINUOUS, *PUSB_VIDEO_MJPEG_FRAME_DESCRIPTOR_CONTINUOUS; // 3.1.2 MJPEG Video Frame Descriptors -Discrete // typedef struct _USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_DISCRETE { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG32 dwFrameInterval; // variable count } USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_DISCRETE, *PUSB_VIDEO_MJPEG_FRAME_DESCRIPTOR_DISCRETE; // // USB Device Class Definition for Video Devices: MPEG1-SS, MPEG2-PS Payload 0.8a Draft Revision // 3.1.1 MPEG1 System Stream Format Descriptor // typedef struct _USB_VIDEO_MPEG1_SS_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; USHORT wPacketLength; USHORT wPackLength; UCHAR bPackdataType; } USB_VIDEO_MPEG1_SS_FORMAT_DESCRIPTOR, *PUSB_VIDEO_MPEG1_SS_FORMAT_DESCRIPTOR; // 3.1.2 MPEG2 PS Format Descriptor // typedef struct _USB_VIDEO_MPEG2_PS_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; USHORT wPacketLength; USHORT wPackLength; UCHAR bPackdataType; } USB_VIDEO_MPEG2_PS_FORMAT_DESCRIPTOR, *PUSB_VIDEO_MPEG2_PS_FORMAT_DESCRIPTOR; // // USB Device Class Definition for Video Devices: MPEG-2 TS Payload 0.8a Draft Revision // 3.1.1 MPEG-2 TS Format Descriptor // typedef struct _USB_VIDEO_MPEG2_TS_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bDataOffset; UCHAR bPacketLength; UCHAR bStrideLength; } USB_VIDEO_MPEG2_TS_FORMAT_DESCRIPTOR, *PUSB_VIDEO_MPEG2_TS_FORMAT_DESCRIPTOR; // // USB Device Class Definition for Video Devices: MPEG4 SL Payload 0.8a Draft Revision // 3.1.1 MPEG4 SL Format Descriptor // typedef struct _USB_VIDEO_MPEG4_SL_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; USHORT wPacketLength; } USB_VIDEO_MPEG4_SL_FORMAT_DESCRIPTOR, *PUSB_VIDEO_MPEG4_SL_FORMAT_DESCRIPTOR; // USB Device Class Definition for Video Devices: DV Payload 0.8a Draft Revision // 3.1.1 DV Format Descriptor typedef struct _USB_VIDEO_DV_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; ULONG32 dwMaxVideoFrameBufferSize; UCHAR bFormatType; } USB_VIDEO_DV_FORMAT_DESCRIPTOR, *PUSB_VIDEO_DV_FORMAT_DESCRIPTOR; // USB Device Class Definition for Video Devices: Vendor Payload 0.8c Draft Revision // 3.1.1 Vendor Video Format Descriptor typedef struct _USB_VIDEO_VENDOR_VIDEO_FORMAT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bNumFrameDescriptors; GUID guidMajorFormat; GUID guidSubFormat; GUID guidSpecifier; UCHAR bPayloadClass; UCHAR bDefaultFrameIndex; UCHAR bCopyProtect; } USB_VIDEO_VENDOR_VIDEO_FORMAT_DESCRIPTOR, *PUSB_VIDEO_VENDOR_VIDEO_FORMAT_DESCRIPTOR; // USB Device Class Definition for Video Devices: Vendor Payload 0.8c Draft Revision // 3.1.2 Vendor Video Frame Descriptor typedef struct _USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_COMMON { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; } USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_COMMON, *PUSB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_COMMON; typedef struct _USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_CONTINUOUS { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG32 dwMinFrameInterval; ULONG32 dwMaxFrameInterval; ULONG32 dwFrameIntervalStep; } USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_CONTINUOUS, *PUSB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_CONTINUOUS; typedef struct _USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_DISCRETE { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG32 dwMinBitRate; ULONG32 dwMaxBitRate; ULONG32 dwMaxVideoFrameBufferSize; ULONG32 dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG32 dwFrameInterval; // variable count } USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_DISCRETE, *PUSB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_DISCRETE; // USB Device Class Definition for Video Devices: Media Transport Terminal 0.8a Draft Revision // 3.1 Media Transport Input Descriptor typedef struct _USB_VIDEO_MEDIA_TRANSPORT_INPUT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bTerminalID; USHORT wTerminalType; UCHAR bAssocTerminal; UCHAR iTerminal; UCHAR bControlSize; UCHAR bmControls; // variable size (min 1) // UCHAR bTransportModeSize; // variable count (min 0) // UCHAR bmTransportModes; // variable count (min 0) } USB_VIDEO_MEDIA_TRANSPORT_INPUT_DESCRIPTOR, *PUSB_VIDEO_MEDIA_TRANSPORT_INPUT_DESCRIPTOR; // 3.2 Media Transport Output Descriptor typedef struct _USB_VIDEO_MEDIA_TRANSPORT_OUTPUT_DESCRIPTOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bTerminalID; USHORT wTerminalType; UCHAR bAssocTerminal; UCHAR bSourceID; UCHAR iTerminal; UCHAR bControlSize; UCHAR bmControls; // variable size (min 1) // UCHAR bTransportModeSize; // variable count (min 0) // UCHAR bmTransportModes; // variable count (min 0) } USB_VIDEO_MEDIA_TRANSPORT_OUTPUT_DESCRIPTOR, *PUSB_VIDEO_MEDIA_TRANSPORT_OUTPUT_DESCRIPTOR; #pragma pack(pop) ================================================ FILE: tests/projects/windows/winsdk/usbview/uvcdesc.h ================================================ //+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 2008 // // File: uvcdesc.h // // This header is from the UVC 1.1 USBVideo driver // //-------------------------------------------------------------------------- #ifndef ___UVCDESC_H___ #define ___UVCDESC_H___ // USB Video Device Class Code #define USB_DEVICE_CLASS_VIDEO 0x0E // Video sub-classes #define SUBCLASS_UNDEFINED 0x00 #define VIDEO_SUBCLASS_CONTROL 0x01 #define VIDEO_SUBCLASS_STREAMING 0x02 // Video Class-Specific Descriptor Types #define CS_UNDEFINED 0x20 #define CS_DEVICE 0x21 #define CS_CONFIGURATION 0x22 #define CS_STRING 0x23 #define CS_INTERFACE 0x24 #define CS_ENDPOINT 0x25 // Video Class-Specific VC Interface Descriptor Subtypes #define VC_HEADER 0x01 #define INPUT_TERMINAL 0x02 #define OUTPUT_TERMINAL 0x03 #define SELECTOR_UNIT 0x04 #define PROCESSING_UNIT 0x05 #define EXTENSION_UNIT 0x06 #define MAX_TYPE_UNIT 0x07 // Video Class-Specific VS Interface Descriptor Subtypes #define VS_DESCRIPTOR_UNDEFINED 0x00 #define VS_INPUT_HEADER 0x01 #define VS_OUTPUT_HEADER 0x02 #define VS_STILL_IMAGE_FRAME 0x03 #define VS_FORMAT_UNCOMPRESSED 0x04 #define VS_FRAME_UNCOMPRESSED 0x05 #define VS_FORMAT_MJPEG 0x06 #define VS_FRAME_MJPEG 0x07 #define VS_FORMAT_MPEG1 0x08 #define VS_FORMAT_MPEG2PS 0x09 #define VS_FORMAT_MPEG2TS 0x0A #define VS_FORMAT_MPEG4SL 0x0B #define VS_FORMAT_DV 0x0C #define VS_COLORFORMAT 0x0D #define VS_FORMAT_VENDOR 0x0E #define VS_FRAME_VENDOR 0x0F // Video Class-Specific Endpoint Descriptor Subtypes #define EP_UNDEFINED 0x00 #define EP_GENERAL 0x01 #define EP_ENDPOINT 0x02 #define EP_INTERRUPT 0x03 // Video Class-Specific Terminal Types #define TERMINAL_TYPE_VENDOR_SPECIFIC 0x0100 #define TERMINAL_TYPE_USB_STREAMING 0x0101 #define TERMINAL_TYPE_INPUT_MASK 0x0200 #define TERMINAL_TYPE_INPUT_VENDOR_SPECIFIC 0x0200 #define TERMINAL_TYPE_INPUT_CAMERA 0x0201 #define TERMINAL_TYPE_INPUT_MEDIA_TRANSPORT 0x0202 #define TERMINAL_TYPE_OUTPUT_MASK 0x0300 #define TERMINAL_TYPE_OUTPUT_VENDOR_SPECIFIC 0x0300 #define TERMINAL_TYPE_OUTPUT_DISPLAY 0x0301 #define TERMINAL_TYPE_OUTPUT_MEDIA_TRANSPORT 0x0302 #define TERMINAL_TYPE_EXTERNAL_VENDOR_SPECIFIC 0x0400 #define TERMINAL_TYPE_EXTERNAL_UNDEFINED 0x0400 #define TERMINAL_TYPE_EXTERNAL_COMPOSITE 0x0401 #define TERMINAL_TYPE_EXTERNAL_SVIDEO 0x0402 #define TERMINAL_TYPE_EXTERNAL_COMPONENT 0x0403 // Controls for error checking only #define DEV_SPECIFIC_CONTROL 0x1001 // Map KSNODE_TYPE GUIDs to Indexes #define NODE_TYPE_NONE 0 #define NODE_TYPE_STREAMING 1 #define NODE_TYPE_INPUT_TERMINAL 2 #define NODE_TYPE_OUTPUT_TERMINAL 3 #define NODE_TYPE_SELECTOR 4 #define NODE_TYPE_PROCESSING 5 #define NODE_TYPE_CAMERA_TERMINAL 6 #define NODE_TYPE_INPUT_MTT 7 #define NODE_TYPE_OUTPUT_MTT 8 #define NODE_TYPE_DEV_SPEC 9 #define NODE_TYPE_MAX 9 // USB bmRequestType values #define USBVIDEO_INTERFACE_SET 0x21 #define USBVIDEO_ENDPOINT_SET 0x22 #define USBVIDEO_INTERFACE_GET 0xA1 #define USBVIDEO_ENDPOINT_GET 0xA2 // Video Class-specific specific requests #define CLASS_SPECIFIC_GET_MASK 0x80 #define RC_UNDEFINED 0x00 #define SET_CUR 0x01 #define GET_CUR 0x81 #define GET_MIN 0x82 #define GET_MAX 0x83 #define GET_RES 0x84 #define GET_LEN 0x85 #define GET_INFO 0x86 #define GET_DEF 0x87 // Power Mode Control constants #define POWER_MODE_CONTROL_FULL 0x0 #define POWER_MODE_CONTROL_DEV_DEPENDENT 0x1 // Video Class-specific Processing Unit Controls #define PU_CONTROL_UNDEFINED 0x00 #define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 #define PU_BRIGHTNESS_CONTROL 0x02 #define PU_CONTRAST_CONTROL 0x03 #define PU_GAIN_CONTROL 0x04 #define PU_POWER_LINE_FREQUENCY_CONTROL 0x05 #define PU_HUE_CONTROL 0x06 #define PU_SATURATION_CONTROL 0x07 #define PU_SHARPNESS_CONTROL 0x08 #define PU_GAMMA_CONTROL 0x09 #define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0A #define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0B #define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0C #define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0D #define PU_DIGITAL_MULTIPLIER_CONTROL 0x0E #define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0F #define PU_HUE_AUTO_CONTROL 0x10 #define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 #define PU_ANALOG_LOCK_STATUS_CONTROL 0x12 // Video Class-specific Camera Terminal Controls #define CT_CONTROL_UNDEFINED 0x00 #define CT_SCANNING_MODE_CONTROL 0x01 #define CT_AE_MODE_CONTROL 0x02 #define CT_AE_PRIORITY_CONTROL 0x03 #define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 #define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 #define CT_FOCUS_ABSOLUTE_CONTROL 0x06 #define CT_FOCUS_RELATIVE_CONTROL 0x07 #define CT_FOCUS_AUTO_CONTROL 0x08 #define CT_IRIS_ABSOLUTE_CONTROL 0x09 #define CT_IRIS_RELATIVE_CONTROL 0x0A #define CT_ZOOM_ABSOLUTE_CONTROL 0x0B #define CT_ZOOM_RELATIVE_CONTROL 0x0C #define CT_PANTILT_ABSOLUTE_CONTROL 0x0D #define CT_PANTILT_RELATIVE_CONTROL 0x0E #define CT_ROLL_ABSOLUTE_CONTROL 0x0F #define CT_ROLL_RELATIVE_CONTROL 0x10 #define CT_PRIVACY_CONTROL 0x11 #define CT_RELATIVE_INCREASE 0x01 #define CT_RELATIVE_DECREASE 0xff #define CT_RELATIVE_STOP 0x00 // Selector Unit Control Selector #define SU_INPUT_SELECT_CONTROL 0x01 // Media Tape Transport Control Selector #define MTT_CONTROL_UNDEFINED 0x00 #define MTT_TRANSPORT_CONTROL 0x01 #define MTT_ATN_INFORMATION_CONTROL 0x02 #define MTT_MEDIA_INFORMATION_CONTROL 0x03 #define MTT_TIME_CODE_INFORMATION_CONTROL 0x04 // Media Transport Terminal States #define MTT_STATE_PLAY_NEXT_FRAME 0x00 #define MTT_STATE_PLAY_FWD_SLOWEST 0x01 #define MTT_STATE_PLAY_SLOW_FWD_4 0x02 #define MTT_STATE_PLAY_SLOW_FWD_3 0x03 #define MTT_STATE_PLAY_SLOW_FWD_2 0x04 #define MTT_STATE_PLAY_SLOW_FWD_1 0x05 #define MTT_STATE_PLAY_X1 0x06 #define MTT_STATE_PLAY_FAST_FWD_1 0x07 #define MTT_STATE_PLAY_FAST_FWD_2 0x08 #define MTT_STATE_PLAY_FAST_FWD_3 0x09 #define MTT_STATE_PLAY_FAST_FWD_4 0x0A #define MTT_STATE_PLAY_FASTEST_FWD 0x0B #define MTT_STATE_PLAY_PREV_FRAME 0x0C #define MTT_STATE_PLAY_SLOWEST_REV 0x0D #define MTT_STATE_PLAY_SLOW_REV_4 0x0E #define MTT_STATE_PLAY_SLOW_REV_3 0x0F #define MTT_STATE_PLAY_SLOW_REV_2 0x10 #define MTT_STATE_PLAY_SLOW_REV_1 0x11 #define MTT_STATE_PLAY_REV 0x12 #define MTT_STATE_PLAY_FAST_REV_1 0x13 #define MTT_STATE_PLAY_FAST_REV_2 0x14 #define MTT_STATE_PLAY_FAST_REV_3 0x15 #define MTT_STATE_PLAY_FAST_REV_4 0x16 #define MTT_STATE_PLAY_FASTEST_REV 0x17 #define MTT_STATE_PLAY 0x18 #define MTT_STATE_PAUSE 0x19 #define MTT_STATE_PLAY_REVERSE_PAUSE 0x1A #define MTT_STATE_STOP 0x40 #define MTT_STATE_FAST_FORWARD 0x41 #define MTT_STATE_REWIND 0x42 #define MTT_STATE_HIGH_SPEED_REWIND 0x43 #define MTT_STATE_RECORD_START 0x50 #define MTT_STATE_RECORD_PAUSE 0x51 #define MTT_STATE_EJECT 0x60 #define MTT_STATE_PLAY_SLOW_FWD_X 0x70 #define MTT_STATE_PLAY_FAST_FWD_X 0x71 #define MTT_STATE_PLAY_SLOW_REV_X 0x72 #define MTT_STATE_PLAY_FAST_REV_X 0x73 #define MTT_STATE_STOP_START 0x74 #define MTT_STATE_STOP_END 0x75 #define MTT_STATE_STOP_EMERGENCY 0x76 #define MTT_STATE_STOP_CONDENSATION 0x77 #define MTT_STATE_UNSPECIFIED 0x7F // Video Control Interface Control Selectors #define VC_UNDEFINED_CONTROL 0x00 #define VC_VIDEO_POWER_MODE_CONTROL 0x01 #define VC_REQUEST_ERROR_CODE_CONTROL 0x02 // VideoStreaming Interface Control Selectors #define VS_CONTROL_UNDEFINED 0x00 #define VS_PROBE_CONTROL 0x01 #define VS_COMMIT_CONTROL 0x02 #define VS_STILL_PROBE_CONTROL 0x03 #define VS_STILL_COMMIT_CONTROL 0x04 #define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 #define VS_STREAM_ERROR_CODE_CONTROL 0x06 #define VS_GENERATE_KEY_FRAME_CONTROL 0x07 #define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 #define VS_SYNC_DELAY_CONTROL 0x09 // Probe commit bitmap framing info #define VS_PROBE_COMMIT_BIT_FID 0x01 #define VS_PROBE_COMMIT_BIT_EOF 0x02 // Stream payload header Bit Field Header bits #define BFH_FID 0x01 // Frame ID bit #define BFH_EOF 0x02 // End of Frame bit #define BFH_PTS 0x04 // Presentation Time Stamp bit #define BFH_SCR 0x08 // Source Clock Reference bit #define BFH_RES 0x10 // Reserved bit #define BFH_STI 0x20 // Still image bit #define BFH_ERR 0x40 // Error bit #define BFH_EOH 0x80 // End of header bit #define HDR_LENGTH 1 // Length of header length field in bytes #define BFH_LENGTH 1 // Length of BFH field in bytes #define PTS_LENGTH 4 // Length of PTS field in bytes #define SCR_LENGTH 6 // Length of SCR field in bytes // USB Video Status Codes (Request Error Code Control) #define USBVIDEO_RE_STATUS_NOERROR 0x00 #define USBVIDEO_RE_STATUS_NOT_READY 0x01 #define USBVIDEO_RE_STATUS_WRONG_STATE 0x02 #define USBVIDEO_RE_STATUS_POWER 0x03 #define USBVIDEO_RE_STATUS_OUT_OF_RANGE 0x04 #define USBVIDEO_RE_STATUS_INVALID_UNIT 0x05 #define USBVIDEO_RE_STATUS_INVALID_CONTROL 0x06 #define USBVIDEO_RE_STATUS_UNKNOWN 0x07 // USB Video Device Status Codes (Stream Error Code Control) #define USBVIDEO_SE_STATUS_NOERROR 0x00 #define USBVIDEO_SE_STATUS_PROTECTED_CONTENT 0x01 #define USBVIDEO_SE_STATUS_INPUT_BUFFER_UNDERRUN 0x02 #define USBVIDEO_SE_STATUS_DATA_DICONTINUITY 0x03 #define USBVIDEO_SE_STATUS_OUTPUT_BUFFER_UNDERRUN 0x04 #define USBVIDEO_SE_STATUS_OUTPUT_BUFFER_OVERRUN 0x05 #define USBVIDEO_SE_STATUS_FORMAT_CHANGE 0x06 #define USBVIDEO_SE_STATUS_STILL_IMAGE_ERROR 0x07 #define USBVIDEO_SE_STATUS_UNKNOWN 0x08 // Status Interrupt Types #define STATUS_INTERRUPT_VC 1 #define STATUS_INTERRUPT_VS 2 // Status Interrupt Attributes #define STATUS_INTERRUPT_ATTRIBUTE_VALUE 0x00 #define STATUS_INTERRUPT_ATTRIBUTE_INFO 0x01 #define STATUS_INTERRUPT_ATTRIBUTE_FAILURE 0x02 // VideoStreaming interface interrupt types #define VS_INTERRUPT_EVENT_BUTTON_PRESS 0x00 #define VS_INTERRUPT_VALUE_BUTTON_RELEASE 0x00 #define VS_INTERRUPT_VALUE_BUTTON_PRESS 0x01 // Get Info Values #define USBVIDEO_ASYNC_CONTROL 0x10 #define USBVIDEO_SETTABLE_CONTROL 0x2 #define MAX_INTERRUPT_PACKET_VALUE_SIZE 8 // Frame descriptor frame interval array offsets #define MIN_FRAME_INTERVAL_OFFSET 0 #define MAX_FRAME_INTERVAL_OFFSET 1 #define FRAME_INTERVAL_STEP_OFFSET 2 // Still image capture methods #define STILL_CAPTURE_METHOD_NONE 0 #define STILL_CAPTURE_METHOD_1 1 #define STILL_CAPTURE_METHOD_2 2 #define STILL_CAPTURE_METHOD_3 3 // Still image trigger control states #define STILL_IMAGE_TRIGGER_NORMAL 0 #define STILL_IMAGE_TRIGGER_TRANSMIT 1 #define STILL_IMAGE_TRIGGER_TRANSMIT_BULK 2 #define STILL_IMAGE_TRIGGER_TRANSMIT_ABORT 3 // Endpoint descriptor masks #define EP_DESCRIPTOR_TRANSACTION_SIZE_MASK 0x07ff #define EP_DESCRIPTOR_NUM_TRANSACTION_MASK 0x1800 #define EP_DESCRIPTOR_NUM_TRANSACTION_OFFSET 11 // Copy protection flag defined in the Uncompressed Payload Spec #define USB_VIDEO_UNCOMPRESSED_RESTRICT_DUPLICATION 1 // Interlace flags #define INTERLACE_FLAGS_SUPPORTED_MASK 0x01 #define INTERLACE_FLAGS_FIELDS_PER_FRAME_MASK 0x02 #define INTERLACE_FLAGS_FIELDS_PER_FRAME_2 0x00 #define INTERLACE_FLAGS_FIELDS_PER_FRAME_1 0x02 #define INTERLACE_FLAGS_FIELD_1_FIRST_MASK 0x04 #define INTERLACE_FLAGS_FIELD_PATTERN_MASK 0x30 #define INTERLACE_FLAGS_FIELD_PATTERN_FIELD1 0x00 #define INTERLACE_FLAGS_FIELD_PATTERN_FIELD2 0x10 #define INTERLACE_FLAGS_FIELD_PATTERN_REGULAR 0x20 #define INTERLACE_FLAGS_FIELD_PATTERN_RANDOM 0x30 #define INTERLACE_FLAGS_DISPLAY_MODE_MASK 0xC0 #define INTERLACE_FLAGS_DISPLAY_MODE_BOB 0x00 #define INTERLACE_FLAGS_DISPLAY_MODE_WEAVE 0x40 #define INTERLACE_FLAGS_DISPLAY_MODE_BOB_WEAVE 0x80 // Color Matching Flags #define UVC_PRIMARIES_UNKNOWN 0x0 #define UVC_PRIMARIES_BT709 0x1 #define UVC_PRIMARIES_BT470_2M 0x2 #define UVC_PRIMARIES_BT470_2BG 0x3 #define UVC_PRIMARIES_SMPTE_170M 0x4 #define UVC_PRIMARIES_SMPTE_240M 0x5 #define UVC_GAMMA_UNKNOWN 0x0 #define UVC_GAMMA_BT709 0x1 #define UVC_GAMMA_BT470_2M 0x2 #define UVC_GAMMA_BT470_2BG 0x3 #define UVC_GAMMA_SMPTE_170M 0x4 #define UVC_GAMMA_SMPTE_240M 0x5 #define UVC_GAMMA_LINEAR 0x6 #define UVC_GAMMA_sRGB 0x7 #define UVC_TRANSFER_MATRIX_UNKNOWN 0x0 #define UVC_TRANSFER_MATRIX_BT709 0x1 #define UVC_TRANSFER_MATRIX_FCC 0x2 #define UVC_TRANSFER_MATRIX_BT470_2BG 0x3 #define UVC_TRANSFER_MATRIX_BT601 0x4 #define UVC_TRANSFER_MATRIX_SMPTE_240M 0x5 // // BEGIN - VDC Descriptor and Control Structures // #pragma warning( disable : 4200 ) // Allow zero-sized arrays at end of structs #pragma pack( push, vdc_descriptor_structs, 1) // Video Specific Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // descriptor subtype } VIDEO_SPECIFIC, *PVIDEO_SPECIFIC; #define SIZEOF_VIDEO_SPECIFIC(pDesc) sizeof(VIDEO_SPECIFIC) // Video Unit Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // descriptor subtype UCHAR bUnitID; // Constant uniquely identifying the Unit } VIDEO_UNIT, *PVIDEO_UNIT; #define SIZEOF_VIDEO_UNIT(pDesc) sizeof(VIDEO_UNIT) // VideoControl Header Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // VC_HEADER descriptor subtype USHORT bcdVideoSpec; // USB video class spec revision number USHORT wTotalLength; // Total length, including all units and terminals ULONG dwClockFreq; // Device clock frequency in Hz UCHAR bInCollection; // number of video streaming interfaces UCHAR baInterfaceNr[]; // interface number array } VIDEO_CONTROL_HEADER_UNIT, *PVIDEO_CONTROL_HEADER_UNIT; #define SIZEOF_VIDEO_CONTROL_HEADER_UNIT(pDesc) \ ((sizeof(VIDEO_CONTROL_HEADER_UNIT) + (pDesc)->bInCollection)) // VideoControl Input Terminal Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype UCHAR bTerminalID; // Constant uniquely identifying the Terminal USHORT wTerminalType; // Constant characterizing the terminal type UCHAR bAssocTerminal; // ID of associated output terminal UCHAR iTerminal; // Index of string descriptor } VIDEO_INPUT_TERMINAL, *PVIDEO_INPUT_TERMINAL; #define SIZEOF_VIDEO_INPUT_TERMINAL(pDesc) sizeof(VIDEO_INPUT_TERMINAL) // VideoControl Output Terminal Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // OUTPUT_TERMINAL descriptor subtype UCHAR bTerminalID; // Constant uniquely identifying the Terminal USHORT wTerminalType; // Constant characterizing the terminal type UCHAR bAssocTerminal; // ID of associated input terminal UCHAR bSourceID; // ID of source unit/terminal UCHAR iTerminal; // Index of string descriptor } VIDEO_OUTPUT_TERMINAL, *PVIDEO_OUTPUT_TERMINAL; #define SIZEOF_VIDEO_OUTPUT_TERMINAL(pDesc) sizeof(VIDEO_OUTPUT_TERMINAL) // VideoControl Camera Terminal Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype UCHAR bTerminalID; // Constant uniquely identifying the Terminal USHORT wTerminalType; // Sensor type UCHAR bAssocTerminal; // ID of associated output terminal UCHAR iTerminal; // Index of string descriptor USHORT wObjectiveFocalLengthMin; // Min focal length for zoom USHORT wObjectiveFocalLengthMax; // Max focal length for zoom USHORT wOcularFocalLength; // Ocular focal length for zoom UCHAR bControlSize; // Size of bmControls field UCHAR bmControls[]; // Bitmap of controls supported } VIDEO_CAMERA_TERMINAL, *PVIDEO_CAMERA_TERMINAL; #define SIZEOF_VIDEO_CAMERA_TERMINAL(pDesc) \ (sizeof(VIDEO_CAMERA_TERMINAL) + (pDesc)->bControlSize) // Media Transport Input Terminal Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype UCHAR bTerminalID; // Constant uniquely identifying the Terminal USHORT wTerminalType; // Media Transport type UCHAR bAssocTerminal; // ID of associated output terminal UCHAR iTerminal; // Index of string descriptor UCHAR bControlSize; // Size of bmControls field UCHAR bmControls[]; // Bitmap of controls supported } VIDEO_INPUT_MTT, *PVIDEO_INPUT_MTT; __inline size_t SizeOfVideoInputMTT(_In_ PVIDEO_INPUT_MTT pDesc) { UCHAR bTransportModeSize; PUCHAR pbCurr; pbCurr = pDesc->bmControls + pDesc->bControlSize; bTransportModeSize = *pbCurr; return sizeof(VIDEO_INPUT_MTT) + pDesc->bControlSize + 1 + bTransportModeSize; } #define SIZEOF_VIDEO_INPUT_MTT(pDesc) SizeOfVideoInputMTT(pDesc) // Media Transport Output Terminal Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // OUTPUT_TERMINAL descriptor subtype UCHAR bTerminalID; // Constant uniquely identifying the Terminal USHORT wTerminalType; // Media Transport type UCHAR bAssocTerminal; // ID of associated output terminal UCHAR bSourceID; // ID of source unit/terminal UCHAR iTerminal; // Index of string descriptor UCHAR bControlSize; // Size of bmControls field UCHAR bmControls[]; // Bitmap of controls supported } VIDEO_OUTPUT_MTT, *PVIDEO_OUTPUT_MTT; __inline size_t SizeOfVideoOutputMTT(_In_ PVIDEO_OUTPUT_MTT pDesc) { UCHAR bTransportModeSize; PUCHAR pbCurr; pbCurr = pDesc->bmControls + pDesc->bControlSize; bTransportModeSize = *pbCurr; return sizeof(VIDEO_OUTPUT_MTT) + pDesc->bControlSize + 1+ bTransportModeSize; } #define SIZEOF_VIDEO_OUTPUT_MTT(pDesc) SizeOfVideoOutputMTT(pDesc) // VideoControl Selector Unit Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // SELECTOR_UNIT descriptor subtype UCHAR bUnitID; // Constant uniquely identifying the Unit UCHAR bNrInPins; // Number of input pins UCHAR baSourceID[]; // IDs of connected units/terminals } VIDEO_SELECTOR_UNIT, *PVIDEO_SELECTOR_UNIT; #define SIZEOF_VIDEO_SELECTOR_UNIT(pDesc) \ (sizeof(VIDEO_SELECTOR_UNIT) + (pDesc)->bNrInPins + 1) // VideoControl Processing Unit Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // PROCESSING_UNIT descriptor subtype UCHAR bUnitID; // Constant uniquely identifying the Unit UCHAR bSourceID; // ID of connected unit/terminal USHORT wMaxMultiplier; // Maximum digital magnification UCHAR bControlSize; // Size of bmControls field UCHAR bmControls[]; // Bitmap of controls supported } VIDEO_PROCESSING_UNIT, *PVIDEO_PROCESSING_UNIT; #define SIZEOF_VIDEO_PROCESSING_UNIT(pDesc) \ (sizeof(VIDEO_PROCESSING_UNIT) + 1 + (pDesc)->bControlSize) // VideoControl Extension Unit Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // EXTENSION_UNIT descriptor subtype UCHAR bUnitID; // Constant uniquely identifying the Unit GUID guidExtensionCode; // Vendor-specific code identifying extension unit UCHAR bNumControls; // Number of controls in Extension Unit UCHAR bNrInPins; // Number of input pins UCHAR baSourceID[]; // IDs of connected units/terminals } VIDEO_EXTENSION_UNIT, *PVIDEO_EXTENSION_UNIT; // this is followed by bControlSize, bmControls and iExtension (1 byte) __inline size_t SizeOfVideoExtensionUnit(PVIDEO_EXTENSION_UNIT pDesc) { UCHAR bControlSize; PUCHAR pbCurr; // baSourceID is an array, and hence understood to be an address pbCurr = pDesc->baSourceID + pDesc->bNrInPins; if (((ULONG_PTR) pbCurr < (ULONG_PTR) pDesc->baSourceID) || (ULONG_PTR) pbCurr >= (ULONG_PTR)((UCHAR *) pDesc + pDesc->bLength)) return 0; bControlSize = *pbCurr; return 24 + pDesc->bNrInPins + bControlSize; } #define SIZEOF_VIDEO_EXTENSION_UNIT(pDesc) SizeOfVideoExtensionUnit(pDesc) // Class-specific Interrupt Endpoint Descriptor typedef struct { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_ENDPOINT descriptor type UCHAR bDescriptorSubtype; // EP_INTERRUPT descriptor subtype USHORT wMaxTransferSize; // Max interrupt payload size } VIDEO_CS_INTERRUPT, *PVIDEO_CS_INTERRUPT; #define SIZEOF_VIDEO_CS_INTERRUPT(pDesc) sizeof(VIDEO_CS_INTERRUPT) // VideoStreaming Input Header Descriptor typedef struct _VIDEO_STREAMING_INPUT_HEADER { UCHAR bLength; // Size of this descriptor in bytes UCHAR bDescriptorType; // CS_INTERFACE descriptor type UCHAR bDescriptorSubtype; // VS_INPUT_HEADER descriptor subtype UCHAR bNumFormats; USHORT wTotalLength; UCHAR bEndpointAddress; UCHAR bmInfo; UCHAR bTerminalLink; UCHAR bStillCaptureMethod; UCHAR bTriggerSupport; UCHAR bTriggerUsage; UCHAR bControlSize; UCHAR bmaControls[]; } VIDEO_STREAMING_INPUT_HEADER, *PVIDEO_STREAMING_INPUT_HEADER; #define SIZEOF_VIDEO_STREAMING_INPUT_HEADER(pDesc) \ (sizeof(VIDEO_STREAMING_INPUT_HEADER) + (pDesc->bNumFormats * pDesc->bControlSize)) // VideoStreaming Output Header Descriptor typedef struct _VIDEO_STREAMING_OUTPUT_HEADER { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bNumFormats; USHORT wTotalLength; UCHAR bEndpointAddress; UCHAR bTerminalLink; } VIDEO_STREAMING_OUTPUT_HEADER, *PVIDEO_STREAMING_OUTPUT_HEADER; #define SIZEOF_VIDEO_STREAMING_OUTPUT_HEADER(pDesc) sizeof(VIDEO_STREAMING_OUTPUT_HEADER) typedef struct _VIDEO_STILL_IMAGE_RECT { USHORT wWidth; USHORT wHeight; } VIDEO_STILL_IMAGE_RECT; // VideoStreaming Still Image Frame Descriptor typedef struct _VIDEO_STILL_IMAGE_FRAME { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bEndpointAddress; UCHAR bNumImageSizePatterns; VIDEO_STILL_IMAGE_RECT aStillRect[]; } VIDEO_STILL_IMAGE_FRAME, *PVIDEO_STILL_IMAGE_FRAME; __inline size_t SizeOfVideoStillImageFrame(PVIDEO_STILL_IMAGE_FRAME pDesc) { UCHAR bNumCompressionPatterns; PUCHAR pbCurr; pbCurr = (PUCHAR) pDesc->aStillRect + (sizeof(VIDEO_STILL_IMAGE_RECT) * pDesc->bNumImageSizePatterns); bNumCompressionPatterns = *pbCurr; return (sizeof(VIDEO_STILL_IMAGE_FRAME) + (sizeof(VIDEO_STILL_IMAGE_RECT) * pDesc->bNumImageSizePatterns) + 1 + bNumCompressionPatterns); } #define SIZEOF_VIDEO_STILL_IMAGE_FRAME(pDesc) SizeOfVideoStillImageFrame(pDesc) // VideoStreaming Color Matching Descriptor typedef struct _VIDEO_COLORFORMAT { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bColorPrimaries; UCHAR bTransferCharacteristics; UCHAR bMatrixCoefficients; } VIDEO_COLORFORMAT, *PVIDEO_COLORFORMAT; #define SIZEOF_VIDEO_COLORFORMAT(pDesc) sizeof(VIDEO_COLORFORMAT) // VideoStreaming Uncompressed Format Descriptor typedef struct _VIDEO_FORMAT_UNCOMPRESSED { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bNumFrameDescriptors; GUID guidFormat; UCHAR bBitsPerPixel; UCHAR bDefaultFrameIndex; UCHAR bAspectRatioX; UCHAR bAspectRatioY; UCHAR bmInterlaceFlags; UCHAR bCopyProtect; } VIDEO_FORMAT_UNCOMPRESSED, *PVIDEO_FORMAT_UNCOMPRESSED; #define SIZEOF_VIDEO_FORMAT_UNCOMPRESSED(pDesc) sizeof(VIDEO_FORMAT_UNCOMPRESSED) // VideoStreaming Uncompressed Frame Descriptor typedef struct _VIDEO_FRAME_UNCOMPRESSED { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG dwMinBitRate; ULONG dwMaxBitRate; ULONG dwMaxVideoFrameBufferSize; ULONG dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG adwFrameInterval[]; } VIDEO_FRAME_UNCOMPRESSED, *PVIDEO_FRAME_UNCOMPRESSED; __inline size_t SizeOfVideoFrameUncompressed(_In_ PVIDEO_FRAME_UNCOMPRESSED pDesc) { if (pDesc->bFrameIntervalType == 0) { // Continuous return sizeof(VIDEO_FRAME_UNCOMPRESSED) + (3 * sizeof(ULONG)); } else { // Discrete return sizeof(VIDEO_FRAME_UNCOMPRESSED) + (pDesc->bFrameIntervalType * sizeof(ULONG)); } } #define SIZEOF_VIDEO_FRAME_UNCOMPRESSED(pDesc) SizeOfVideoFrameUncompressed(pDesc) // VideoStreaming MJPEG Format Descriptor typedef struct _VIDEO_FORMAT_MJPEG { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bNumFrameDescriptors; UCHAR bmFlags; UCHAR bDefaultFrameIndex; UCHAR bAspectRatioX; UCHAR bAspectRatioY; UCHAR bmInterlaceFlags; UCHAR bCopyProtect; } VIDEO_FORMAT_MJPEG, *PVIDEO_FORMAT_MJPEG; #define SIZEOF_VIDEO_FORMAT_MJPEG(pDesc) sizeof(VIDEO_FORMAT_MJPEG) // VideoStreaming MJPEG Frame Descriptor typedef struct _VIDEO_FRAME_MJPEG { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG dwMinBitRate; ULONG dwMaxBitRate; ULONG dwMaxVideoFrameBufferSize; ULONG dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG adwFrameInterval[]; } VIDEO_FRAME_MJPEG, *PVIDEO_FRAME_MJPEG; __inline size_t SizeOfVideoFrameMjpeg(_In_ PVIDEO_FRAME_MJPEG pDesc) { if (pDesc->bFrameIntervalType == 0) { // Continuous return sizeof(VIDEO_FRAME_MJPEG) + (3 * sizeof(ULONG)); } else { // Discrete return sizeof(VIDEO_FRAME_MJPEG) + (pDesc->bFrameIntervalType * sizeof(ULONG)); } } #define SIZEOF_VIDEO_FRAME_MJPEG(pDesc) SizeOfVideoFrameMjpeg(pDesc) // VideoStreaming Vendor Format Descriptor typedef struct _VIDEO_FORMAT_VENDOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bNumFrameDescriptors; GUID guidMajorFormat; GUID guidSubFormat; GUID guidSpecifier; UCHAR bPayloadClass; UCHAR bDefaultFrameIndex; UCHAR bCopyProtect; } VIDEO_FORMAT_VENDOR, *PVIDEO_FORMAT_VENDOR; #define SIZEOF_VIDEO_FORMAT_VENDOR(pDesc) sizeof(VIDEO_FORMAT_VENDOR) // VideoStreaming Vendor Frame Descriptor typedef struct _VIDEO_FRAME_VENDOR { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG dwMinBitRate; ULONG dwMaxBitRate; ULONG dwMaxVideoFrameBufferSize; ULONG dwDefaultFrameInterval; UCHAR bFrameIntervalType; DWORD adwFrameInterval[]; } VIDEO_FRAME_VENDOR, *PVIDEO_FRAME_VENDOR; __inline size_t SizeOfVideoFrameVendor(_In_ PVIDEO_FRAME_VENDOR pDesc) { if (pDesc->bFrameIntervalType == 0) { // Continuous return sizeof(VIDEO_FRAME_VENDOR) + (3 * sizeof(ULONG)); } else { // Discrete return sizeof(VIDEO_FRAME_VENDOR) + (pDesc->bFrameIntervalType * sizeof(ULONG)); } } #define SIZEOF_VIDEO_FRAME_VENDOR(pDesc) SizeOfVideoFrameVendor(pDesc) // VideoStreaming DV Format Descriptor typedef struct _VIDEO_FORMAT_DV { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; ULONG dwMaxVideoFrameBufferSize; UCHAR bFormatType; } VIDEO_FORMAT_DV, *PVIDEO_FORMAT_DV; #define SIZEOF_VIDEO_FORMAT_DV(pDesc) sizeof(VIDEO_FORMAT_DV) // VideoStreaming MPEG2-TS Format Descriptor typedef struct _VIDEO_FORMAT_MPEG2TS { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bDataOffset; UCHAR bPacketLength; UCHAR bStrideLength; } VIDEO_FORMAT_MPEG2TS, *PVIDEO_FORMAT_MPEG2TS; #define SIZEOF_VIDEO_FORMAT_MPEG2TS(pDesc) sizeof(VIDEO_FORMAT_MPEG2TS) // VideoStreaming MPEG1 System Stream Format Descriptor typedef struct _VIDEO_FORMAT_MPEG1SS { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bPacketLength; UCHAR bPackLength; UCHAR bPackDataType; } VIDEO_FORMAT_MPEG1SS, *PVIDEO_FORMAT_MPEG1SS; #define SIZEOF_VIDEO_FORMAT_MPEG1SS(pDesc) sizeof(VIDEO_FORMAT_MPEG1SS) // VideoStreaming MPEG2-PS Format Descriptor typedef struct _VIDEO_FORMAT_MPEG2PS { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bPacketLength; UCHAR bPackLength; UCHAR bPackDataType; } VIDEO_FORMAT_MPEG2PS, *PVIDEO_FORMAT_MPEG2PS; #define SIZEOF_VIDEO_FORMAT_MPEG2PS(pDesc) sizeof(VIDEO_FORMAT_MPEG2PS) // VideoStreaming MPEG4-SL Format Descriptor typedef struct _VIDEO_FORMAT_MPEG4SL { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bPacketLength; } VIDEO_FORMAT_MPEG4SL, *PVIDEO_FORMAT_MPEG4SL; #define SIZEOF_VIDEO_FORMAT_MPEG4SL(pDesc) sizeof(VIDEO_FORMAT_MPEG4SL) // VideoStreaming Probe/Commit Control typedef struct _VS_PROBE_COMMIT_CONTROL { USHORT bmHint; UCHAR bFormatIndex; UCHAR bFrameIndex; ULONG dwFrameInterval; USHORT wKeyFrameRate; USHORT wPFrameRate; USHORT wCompQuality; USHORT wCompWindowSize; USHORT wDelay; ULONG dwMaxVideoFrameSize; ULONG dwMaxPayloadTransferSize; } VS_PROBE_COMMIT_CONTROL, *PVS_PROBE_COMMIT_CONTROL; // VideoStreaming Still Probe/Commit Control typedef struct _VS_STILL_PROBE_COMMIT_CONTROL { UCHAR bFormatIndex; UCHAR bFrameIndex; UCHAR bCompressionIndex; ULONG dwMaxVideoFrameSize; ULONG dwMaxPayloadTransferSize; } VS_STILL_PROBE_COMMIT_CONTROL, *PVS_STILL_PROBE_COMMIT_CONTROL; // Status Interrupt Packet (Video Control) typedef struct _VC_INTERRUPT_PACKET { UCHAR bStatusType; UCHAR bOriginator; UCHAR bEvent; UCHAR bSelector; UCHAR bAttribute; UCHAR bValue[1]; } VC_INTERRUPT_PACKET, *PVC_INTERRUPT_PACKET; // Status Interrupt Packet (Video Control) typedef struct _VC_INTERRUPT_PACKET_EX { UCHAR bStatusType; UCHAR bOriginator; UCHAR bEvent; UCHAR bSelector; UCHAR bAttribute; UCHAR bValue[MAX_INTERRUPT_PACKET_VALUE_SIZE]; } VC_INTERRUPT_PACKET_EX, *PVC_INTERRUPT_PACKET_EX; // Status Interrupt Packet (Video Streaming) typedef struct _VS_INTERRUPT_PACKET { UCHAR bStatusType; UCHAR bOriginator; UCHAR bEvent; UCHAR bValue[1]; } VS_INTERRUPT_PACKET, *PVS_INTERRUPT_PACKET; // Status Interrupt Packet (Generic) typedef struct _VIDEO_INTERRUPT_PACKET { UCHAR bStatusType; UCHAR bOriginator; } VIDEO_INTERRUPT_PACKET, *PVIDEO_INTERRUPT_PACKET; // Relative property struct typedef struct _VIDEO_RELATIVE_PROPERTY { UCHAR bValue; UCHAR bSpeed; } VIDEO_RELATIVE_PROPERTY, *PVIDEO_RELATIVE_PROPERTY; // Relative Zoom control struct typedef struct _ZOOM_RELATIVE_PROPERTY { UCHAR bZoom; UCHAR bDigitalZoom; UCHAR bSpeed; } ZOOM_RELATIVE_PROPERTY, *PZOOM_RELATIVE_PROPERTY; // Relative pan-tilt struct typedef struct _PANTILT_RELATIVE_PROPERTY { UCHAR bPanRelative; UCHAR bPanSpeed; UCHAR bTiltRelative; UCHAR bTiltSpeed; } PANTILT_RELATIVE_PROPERTY, *PPANTILT_RELATIVE_PROPERTY; typedef struct _MEDIA_INFORMATION_CONTROL { UCHAR bmMediaType; UCHAR bmWriteProtect; } MEDIA_INFORMATION_CONTROL, *PMEDIA_INFORMATION_CONTROL; typedef struct _TIME_CODE_INFORMATION_CONTROL { UCHAR bcdFrame; UCHAR bcdSecond; UCHAR bcdMinute; UCHAR bcdHour; } TIME_CODE_INFORMATION_CONTROL, *PTIME_CODE_INFORMATION_CONTROL; typedef struct _ATN_INFORMATION_CONTROL { UCHAR bmMediaType; DWORD dwATN_Data; } ATN_INFORMATION_CONTROL, *PATN_INFORMATION_CONTROL; #define VS_FORMAT_FRAME_BASED 0x10 #define VS_FRAME_FRAME_BASED 0x11 #define VS_FORMAT_STREAM_BASED 0x12 // Format Descriptor for UVC 1.1 frame based format typedef struct _VIDEO_FORMAT_FRAME { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; UCHAR bNumFrameDescriptors; GUID guidFormat; UCHAR bBitsPerPixel; UCHAR bDefaultFrameIndex; UCHAR bAspectRatioX; UCHAR bAspectRatioY; UCHAR bmInterlaceFlags; UCHAR bCopyProtect; UCHAR bVariableSize; } VIDEO_FORMAT_FRAME, *PVIDEO_FORMAT_FRAME; #define SIZEOF_VIDEO_FORMAT_FRAME(pDesc) sizeof(VIDEO_FORMAT_FRAME) // Frame Descriptor for UVC 1.1 frame based format typedef struct _VIDEO_FRAME_FRAME { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFrameIndex; UCHAR bmCapabilities; USHORT wWidth; USHORT wHeight; ULONG dwMinBitRate; ULONG dwMaxBitRate; ULONG dwDefaultFrameInterval; UCHAR bFrameIntervalType; ULONG dwBytesPerLine; ULONG adwFrameInterval[]; } VIDEO_FRAME_FRAME, *PVIDEO_FRAME_FRAME; __inline size_t SizeOfVideoFrameFrame(_In_ PVIDEO_FRAME_FRAME pDesc) { if (pDesc->bFrameIntervalType == 0) { // Continuous return sizeof(VIDEO_FRAME_FRAME) + (3 * sizeof(ULONG)); } else { // Discrete return sizeof(VIDEO_FRAME_FRAME) + (pDesc->bFrameIntervalType * sizeof(ULONG)); } } #define SIZEOF_VIDEO_FRAME_FRAME(pDesc) SizeOfVideoFrameFrame(pDesc) // VideoStreaming Stream Based Format Descriptor typedef struct _VIDEO_FORMAT_STREAM { UCHAR bLength; UCHAR bDescriptorType; UCHAR bDescriptorSubtype; UCHAR bFormatIndex; GUID guidFormat; ULONG dwPacketLength; } VIDEO_FORMAT_STREAM, *PVIDEO_FORMAT_STREAM; #define SIZEOF_VIDEO_FORMAT_STREAM(pDesc) sizeof(VIDEO_FORMAT_STREAM) // VideoStreaming Probe/Commit Control typedef struct _VS_PROBE_COMMIT_CONTROL2 { USHORT bmHint; UCHAR bFormatIndex; UCHAR bFrameIndex; ULONG dwFrameInterval; USHORT wKeyFrameRate; USHORT wPFrameRate; USHORT wCompQuality; USHORT wCompWindowSize; USHORT wDelay; ULONG dwMaxVideoFrameSize; ULONG dwMaxPayloadTransferSize; ULONG dwClockFrequency; UCHAR bmFramingInfo; UCHAR bPreferredVersion; UCHAR bMinVersion; UCHAR bMaxVersion; } VS_PROBE_COMMIT_CONTROL2, *PVS_PROBE_COMMIT_CONTROL2; #pragma pack( pop, vdc_descriptor_structs ) #pragma warning( default : 4200 ) // // END - VDC Descriptor and Control Structures // #endif // ___UVCDESC_H___ ================================================ FILE: tests/projects/windows/winsdk/usbview/uvcview.c ================================================ /*++ Copyright (c) 1997-2011 Microsoft Corporation Module Name: USBVIEW.C Abstract: This is the GUI goop for the USBVIEW application. Environment: user mode Revision History: 04-25-97 : created 11-20-02 : minor changes to support more reporting options 04/13/2005 : major bug fixing 07/01/2008 : add UVC 1.1 support and move to Dev branch --*/ /***************************************************************************** I N C L U D E S *****************************************************************************/ #include "resource.h" #include "uvcview.h" #include "h264.h" #include "xmlhelper.h" #include /***************************************************************************** D E F I N E S *****************************************************************************/ // window control defines // #define SIZEBAR 0 #define WINDOWSCALEFACTOR 15 /***************************************************************************** L O C A L T Y P E D E F S *****************************************************************************/ typedef struct _TREEITEMINFO { struct _TREEITEMINFO *Next; USHORT Depth; PCHAR Name; } TREEITEMINFO, *PTREEITEMINFO; /***************************************************************************** L O C A L E N U M S *****************************************************************************/ typedef enum _USBVIEW_SAVE_FILE_TYPE { UsbViewNone = 0, UsbViewXmlFile, UsbViewTxtFile } USBVIEW_SAVE_FILE_TYPE; /***************************************************************************** L O C A L F U N C T I O N P R O T O T Y P E S *****************************************************************************/ int WINAPI WinMain ( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpszCmdLine, _In_ int nCmdShow ); BOOL CreateMainWindow ( int nCmdShow ); VOID ResizeWindows ( BOOL bSizeBar, int BarLocation ); LRESULT CALLBACK MainDlgProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); BOOL USBView_OnInitDialog ( HWND hWnd, HWND hWndFocus, LPARAM lParam ); VOID USBView_OnClose ( HWND hWnd ); VOID USBView_OnCommand ( HWND hWnd, int id, HWND hwndCtl, UINT codeNotify ); VOID USBView_OnLButtonDown ( HWND hWnd, BOOL fDoubleClick, int x, int y, UINT keyFlags ); VOID USBView_OnLButtonUp ( HWND hWnd, int x, int y, UINT keyFlags ); VOID USBView_OnMouseMove ( HWND hWnd, int x, int y, UINT keyFlags ); VOID USBView_OnSize ( HWND hWnd, UINT state, int cx, int cy ); LRESULT USBView_OnNotify ( HWND hWnd, int DlgItem, LPNMHDR lpNMHdr ); BOOL USBView_OnDeviceChange ( HWND hwnd, UINT uEvent, DWORD dwEventData ); VOID DestroyTree (VOID); VOID RefreshTree (VOID); LRESULT CALLBACK AboutDlgProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); VOID WalkTree ( _In_ HTREEITEM hTreeItem, _In_ LPFNTREECALLBACK lpfnTreeCallback, _In_opt_ PVOID pContext ); VOID ExpandItem ( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ); VOID AddItemInformationToFile( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ); DWORD DisplayLastError( _Inout_updates_bytes_(count) char *szString, int count); VOID AddItemInformationToXmlView( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ); HRESULT InitializeConsole(); VOID UnInitializeConsole(); BOOL IsStdOutFile(); VOID DisplayMessage(DWORD dwMsgId, ...); VOID PrintString(LPTSTR lpszString); LPTSTR WStringToAnsiString(LPWSTR lpwszString); VOID WaitForKeyPress(); BOOL ProcessCommandLine(); HRESULT ProcessCommandSaveFile(LPTSTR szFileName, DWORD dwCreationDisposition, USBVIEW_SAVE_FILE_TYPE fileType); HRESULT SaveAllInformationAsText(LPTSTR lpstrTextFileName, DWORD dwCreationDisposition); HRESULT SaveAllInformationAsXml(LPTSTR lpstrTextFileName , DWORD dwCreationDisposition); /***************************************************************************** G L O B A L S *****************************************************************************/ BOOL gDoConfigDesc = TRUE; BOOL gDoAnnotation = TRUE; BOOL gLogDebug = FALSE; int TotalHubs = 0; extern DEVICE_GUID_LIST gHubList; extern DEVICE_GUID_LIST gDeviceList; /***************************************************************************** G L O B A L S P R I V A T E T O T H I S F I L E *****************************************************************************/ HINSTANCE ghInstance = NULL; HWND ghMainWnd = NULL; HWND ghTreeWnd = NULL; HWND ghEditWnd = NULL; HWND ghStatusWnd = NULL; HMENU ghMainMenu = NULL; HTREEITEM ghTreeRoot = NULL; HCURSOR ghSplitCursor = NULL; HDEVNOTIFY gNotifyDevHandle = NULL; HDEVNOTIFY gNotifyHubHandle = NULL; HANDLE ghStdOut = NULL; BOOL gbConsoleFile = FALSE; BOOL gbConsoleInitialized = FALSE; BOOL gbButtonDown = FALSE; BOOL gDoAutoRefresh = TRUE; int gBarLocation = 0; int giGoodDevice = 0; int giBadDevice = 0; int giComputer = 0; int giHub = 0; int giNoDevice = 0; int giGoodSsDevice = 0; int giNoSsDevice = 0; /***************************************************************************** WinMain() *****************************************************************************/ int WINAPI WinMain ( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpszCmdLine, _In_ int nCmdShow ) { MSG msg; HACCEL hAccel; int retStatus = 0; UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpszCmdLine); InitXmlHelper(); ghInstance = hInstance; ghSplitCursor = LoadCursor(ghInstance, MAKEINTRESOURCE(IDC_SPLIT)); if (!ghSplitCursor) { OOPS(); return retStatus; } hAccel = LoadAccelerators(ghInstance, MAKEINTRESOURCE(IDACCEL)); if (!hAccel) { OOPS(); return retStatus; } if (!CreateTextBuffer()) { return retStatus; } if (!ProcessCommandLine()) { // There were no command line flags, open GUI if (CreateMainWindow(nCmdShow)) { while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(ghMainWnd, hAccel, &msg) && !IsDialogMessage(ghMainWnd, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } retStatus = 1; } } DestroyTextBuffer(); ReleaseXmlWriter(); CHECKFORLEAKS(); return retStatus; } /***************************************************************************** ProcessCommandLine() Parses the command line and takes appropriate actions. Returns FALSE If there is no action to perform *****************************************************************************/ BOOL ProcessCommandLine() { LPWSTR *szArgList = NULL; LPTSTR szArg = NULL; LPTSTR szAnsiArg= NULL; BOOL quietMode = FALSE; HRESULT hr = S_OK; DWORD dwCreationDisposition = CREATE_NEW; USBVIEW_SAVE_FILE_TYPE fileType = UsbViewNone; int nArgs = 0; int i = 0; BOOL bStatus = FALSE; BOOL bStopArgProcessing = FALSE; szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs); // If there are no arguments we return false bStatus = (nArgs > 1)? TRUE:FALSE; if (NULL != szArgList) { if (nArgs > 1) { // If there are arguments, initialize console for ouput InitializeConsole(); } for (i = 1; (i < nArgs) && (bStopArgProcessing == FALSE); i++) { // Convert argument to ANSI string for futher processing szAnsiArg = WStringToAnsiString(szArgList[i]); if(NULL == szAnsiArg) { DisplayMessage(IDS_USBVIEW_INVALIDARG, szAnsiArg); DisplayMessage(IDS_USBVIEW_USAGE); break; } if (0 == _stricmp(szAnsiArg, "/?")) { DisplayMessage(IDS_USBVIEW_USAGE); break; } else if (NULL != StrStrI(szAnsiArg, "/saveall:")) { fileType = UsbViewTxtFile; } else if (NULL != StrStrI(szAnsiArg, "/savexml:")) { fileType = UsbViewXmlFile; } else if (0 == _stricmp(szAnsiArg, "/f")) { dwCreationDisposition = CREATE_ALWAYS; } else if (0 == _stricmp(szAnsiArg, "/q")) { quietMode = TRUE; } else { DisplayMessage(IDS_USBVIEW_INVALIDARG, szAnsiArg); DisplayMessage(IDS_USBVIEW_USAGE); bStopArgProcessing = TRUE; } if (fileType != UsbViewNone) { // Save view information as to file szArg = strchr(szAnsiArg, ':'); if (NULL == szArg || strlen(szArg) == 1) { // No ':' or just a ':' DisplayMessage(IDS_USBVIEW_INVALID_FILENAME, szAnsiArg); DisplayMessage(IDS_USBVIEW_USAGE); bStopArgProcessing = TRUE; } else { hr = ProcessCommandSaveFile(szArg + 1, dwCreationDisposition, fileType); if (FAILED(hr)) { // No more processing bStopArgProcessing = TRUE; } fileType = UsbViewNone; } } if (NULL != szAnsiArg) { LocalFree(szAnsiArg); } } if(!quietMode) { WaitForKeyPress(); } if (gbConsoleInitialized) { UnInitializeConsole(); } LocalFree(szArgList); } return bStatus; } /***************************************************************************** ProcessCommandSaveFile() Process the save file command line *****************************************************************************/ HRESULT ProcessCommandSaveFile(LPTSTR szFileName, DWORD dwCreationDisposition, USBVIEW_SAVE_FILE_TYPE fileType) { HRESULT hr = S_OK; LPTSTR szErrorBuffer = NULL; if (UsbViewNone == fileType || NULL == szFileName) { hr = E_INVALIDARG; // Invalid arguments, return return (hr); } // The UI is not created yet, open the UI, but HIDE it CreateMainWindow(SW_HIDE); if (UsbViewXmlFile == fileType) { hr = SaveAllInformationAsXml(szFileName, dwCreationDisposition); } if (UsbViewTxtFile == fileType) { hr = SaveAllInformationAsText(szFileName, dwCreationDisposition); } if (FAILED(hr)) { if (GetLastError() == ERROR_FILE_EXISTS || hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)) { // The operation failed because the file we tried to write to already existed and '/f' option // was not present. Display error message to user describing '/f' option switch(fileType) { case UsbViewXmlFile: DisplayMessage(IDS_USBVIEW_FILE_EXISTS_XML, szFileName); break; case UsbViewTxtFile: DisplayMessage(IDS_USBVIEW_FILE_EXISTS_TXT, szFileName); break; default: DisplayMessage(IDS_USBVIEW_INTERNAL_ERROR); break; } } else { // Try to obtain system error message FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &szErrorBuffer, // FormatMessage expects this buffer to be cast as LPTSTR 0, NULL); PrintString("Unable to save file.\n"); PrintString(szErrorBuffer); LocalFree(szErrorBuffer); } } else { // Display file saved to message in console DisplayMessage(IDS_USBVIEW_SAVED_TO, szFileName); } return (hr); } /***************************************************************************** InitializeConsole() Initializes the std output in console *****************************************************************************/ HRESULT InitializeConsole() { HRESULT hr = S_OK; SetLastError(0); // Find if STD_OUTPUT is a console or has been redirected to a File gbConsoleFile = IsStdOutFile(); if (!gbConsoleFile) { // Output is not redirected and GUI application do not have console by default, create a console if(AllocConsole()) { #pragma warning(disable:4996) // We don' need the FILE * returned by freopen // Reopen STDOUT , STDIN and STDERR if((freopen("conout$", "w", stdout) != NULL) && (freopen("conin$", "r", stdin) != NULL) && (freopen("conout$","w", stderr) != NULL)) { gbConsoleInitialized = TRUE; ghStdOut = GetStdHandle(STD_OUTPUT_HANDLE); } #pragma warning(default:4996) } } if (INVALID_HANDLE_VALUE == ghStdOut || FALSE == gbConsoleInitialized) { hr = HRESULT_FROM_WIN32(GetLastError()); OOPS(); } return hr; } /***************************************************************************** UnInitializeConsole() UnInitializes the console *****************************************************************************/ VOID UnInitializeConsole() { gbConsoleInitialized = FALSE; FreeConsole(); } /***************************************************************************** IsStdOutFile() Finds if the STD_OUTPUT has been redirected to a file *****************************************************************************/ BOOL IsStdOutFile() { unsigned htype; HANDLE hFile; // 1 = STDOUT hFile = (HANDLE) _get_osfhandle(1); htype = GetFileType(hFile); htype &= ~FILE_TYPE_REMOTE; // Check if file type is character file if (FILE_TYPE_DISK == htype) { return TRUE; } return FALSE; } /***************************************************************************** DisplayMessage() Displays a message to standard output *****************************************************************************/ VOID DisplayMessage(DWORD dwResId, ...) { CHAR szFormat[4096]; HRESULT hr = S_OK; LPTSTR lpszMessage = NULL; DWORD dwLen = 0; va_list ap; va_start(ap, dwResId); // Initialize console if needed if (!gbConsoleInitialized) { hr = InitializeConsole(); if (FAILED(hr)) { OOPS(); return; } } // Load the string resource dwLen = LoadString(GetModuleHandle(NULL), dwResId, szFormat, ARRAYSIZE(szFormat) ); if(0 == dwLen) { PrintString("Unable to find message for given resource ID"); // Return if resource ID could not be found return; } dwLen = FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, szFormat, dwResId, 0, (LPTSTR) &lpszMessage, ARRAYSIZE(szFormat), &ap); if (dwLen > 0) { PrintString(lpszMessage); LocalFree(lpszMessage); } else { PrintString("Unable to find message for given ID"); } va_end(ap); return; } /***************************************************************************** WStringToAnsiString() Converts the Wide char string to ANSI string and returns the allocated ANSI string. *****************************************************************************/ LPTSTR WStringToAnsiString(LPWSTR lpwszString) { int strLen = 0; LPTSTR szAnsiBuffer = NULL; szAnsiBuffer = LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(CHAR)); // Convert string from from WCHAR to ANSI if (NULL != szAnsiBuffer) { strLen = WideCharToMultiByte( CP_ACP, 0, lpwszString, -1, szAnsiBuffer, MAX_PATH + 1, NULL, NULL); if (strLen > 0) { return szAnsiBuffer; } } return NULL; } /***************************************************************************** PrintString() Displays a string to standard output *****************************************************************************/ VOID PrintString(LPTSTR lpszString) { DWORD dwBytesWritten = 0; size_t Len = 0; LPSTR lpOemString = NULL; if (INVALID_HANDLE_VALUE == ghStdOut || NULL == lpszString) { OOPS(); // Return if invalid inputs return; } if (FAILED(StringCchLength(lpszString, OUTPUT_MESSAGE_MAX_LENGTH, &Len))) { OOPS(); // Return if string is too long return; } if (gbConsoleFile) { // Console has been redirected to a file, ex: `usbview /savexml:xx > test.txt`. We need to use WriteFile instead of // WriteConsole for text output. lpOemString = (LPSTR) LocalAlloc(LPTR, (Len + 1) * sizeof(CHAR)); if (lpOemString != NULL) { if (CharToOemBuff(lpszString, lpOemString, (DWORD) Len)) { WriteFile(ghStdOut, (LPVOID) lpOemString, (DWORD) Len, &dwBytesWritten, NULL); } else { OOPS(); } } } else { // Write to std out in console WriteConsole(ghStdOut, (LPVOID) lpszString, (DWORD) Len, &dwBytesWritten, NULL); } return; } /***************************************************************************** WaitForKeyPress() Waits for key press in case of console *****************************************************************************/ VOID WaitForKeyPress() { // Wait for key press if console if (!gbConsoleFile && gbConsoleInitialized) { DisplayMessage(IDS_USBVIEW_PRESSKEY); (VOID) _getch(); } return; } /***************************************************************************** CreateMainWindow() *****************************************************************************/ BOOL CreateMainWindow ( int nCmdShow ) { RECT rc; InitCommonControls(); ghMainWnd = CreateDialog(ghInstance, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL, (DLGPROC) MainDlgProc); if (ghMainWnd == NULL) { OOPS(); return FALSE; } GetWindowRect(ghMainWnd, &rc); gBarLocation = (rc.right - rc.left) / 3; ResizeWindows(FALSE, 0); ShowWindow(ghMainWnd, nCmdShow); UpdateWindow(ghMainWnd); return TRUE; } /***************************************************************************** ResizeWindows() Handles resizing the two child windows of the main window. If bSizeBar is true, then the sizing is happening because the user is moving the bar. If bSizeBar is false, the sizing is happening because of the WM_SIZE or something like that. *****************************************************************************/ VOID ResizeWindows ( BOOL bSizeBar, int BarLocation ) { RECT MainClientRect; RECT MainWindowRect; RECT TreeWindowRect; RECT StatusWindowRect; int right; // Is the user moving the bar? // if (!bSizeBar) { BarLocation = gBarLocation; } GetClientRect(ghMainWnd, &MainClientRect); GetWindowRect(ghStatusWnd, &StatusWindowRect); // Make sure the bar is in a OK location // if (bSizeBar) { if (BarLocation < GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR) { return; } if ((MainClientRect.right - BarLocation) < GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR) { return; } } // Save the bar location // gBarLocation = BarLocation; // Move the tree window // MoveWindow(ghTreeWnd, 0, 0, BarLocation, MainClientRect.bottom - StatusWindowRect.bottom + StatusWindowRect.top, TRUE); // Get the size of the window (in case move window failed // GetWindowRect(ghTreeWnd, &TreeWindowRect); GetWindowRect(ghMainWnd, &MainWindowRect); right = TreeWindowRect.right - MainWindowRect.left; // Move the edit window with respect to the tree window // MoveWindow(ghEditWnd, right+SIZEBAR, 0, MainClientRect.right-(right+SIZEBAR), MainClientRect.bottom - StatusWindowRect.bottom + StatusWindowRect.top, TRUE); // Move the Status window with respect to the tree window // MoveWindow(ghStatusWnd, 0, MainClientRect.bottom - StatusWindowRect.bottom + StatusWindowRect.top, MainClientRect.right, StatusWindowRect.bottom - StatusWindowRect.top, TRUE); } /***************************************************************************** MainWndProc() *****************************************************************************/ LRESULT CALLBACK MainDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch (uMsg) { HANDLE_MSG(hWnd, WM_INITDIALOG, USBView_OnInitDialog); HANDLE_MSG(hWnd, WM_CLOSE, USBView_OnClose); HANDLE_MSG(hWnd, WM_COMMAND, USBView_OnCommand); HANDLE_MSG(hWnd, WM_LBUTTONDOWN, USBView_OnLButtonDown); HANDLE_MSG(hWnd, WM_LBUTTONUP, USBView_OnLButtonUp); HANDLE_MSG(hWnd, WM_MOUSEMOVE, USBView_OnMouseMove); HANDLE_MSG(hWnd, WM_SIZE, USBView_OnSize); HANDLE_MSG(hWnd, WM_NOTIFY, USBView_OnNotify); HANDLE_MSG(hWnd, WM_DEVICECHANGE, USBView_OnDeviceChange); } return 0; } /***************************************************************************** USBView_OnInitDialog() *****************************************************************************/ BOOL USBView_OnInitDialog ( HWND hWnd, HWND hWndFocus, LPARAM lParam ) { HFONT hFont; HIMAGELIST himl; HICON hicon; DEV_BROADCAST_DEVICEINTERFACE broadcastInterface; UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(hWndFocus); // Register to receive notification when a USB device is plugged in. broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; memcpy( &(broadcastInterface.dbcc_classguid), &(GUID_DEVINTERFACE_USB_DEVICE), sizeof(struct _GUID)); gNotifyDevHandle = RegisterDeviceNotification(hWnd, &broadcastInterface, DEVICE_NOTIFY_WINDOW_HANDLE); // Now register for Hub notifications. memcpy( &(broadcastInterface.dbcc_classguid), &(GUID_CLASS_USBHUB), sizeof(struct _GUID)); gNotifyHubHandle = RegisterDeviceNotification(hWnd, &broadcastInterface, DEVICE_NOTIFY_WINDOW_HANDLE); gHubList.DeviceInfo = INVALID_HANDLE_VALUE; InitializeListHead(&gHubList.ListHead); gDeviceList.DeviceInfo = INVALID_HANDLE_VALUE; InitializeListHead(&gDeviceList.ListHead); //end add ghTreeWnd = GetDlgItem(hWnd, IDC_TREE); //added if ((himl = ImageList_Create(15, 15, FALSE, 2, 0)) == NULL) { OOPS(); } if(himl != NULL) { hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_ICON)); giGoodDevice = ImageList_AddIcon(himl, hicon); hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_BADICON)); giBadDevice = ImageList_AddIcon(himl, hicon); hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_COMPUTER)); giComputer = ImageList_AddIcon(himl, hicon); hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_HUB)); giHub = ImageList_AddIcon(himl, hicon); hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_NODEVICE)); giNoDevice = ImageList_AddIcon(himl, hicon); hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_SSICON)); giGoodSsDevice = ImageList_AddIcon(himl, hicon); hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_NOSSDEVICE)); giNoSsDevice = ImageList_AddIcon(himl, hicon); TreeView_SetImageList(ghTreeWnd, himl, TVSIL_NORMAL); // end add } ghEditWnd = GetDlgItem(hWnd, IDC_EDIT); #ifdef H264_SUPPORT // set the edit control to have a max text limit size SendMessage(ghEditWnd, EM_LIMITTEXT, 0 /* USE DEFAULT MAX*/, 0); #endif ghStatusWnd = GetDlgItem(hWnd, IDC_STATUS); ghMainMenu = GetMenu(hWnd); if (ghMainMenu == NULL) { OOPS(); } { CHAR pszFont[256]; CHAR pszHeight[8]; memset(pszFont, 0, sizeof(pszFont)); LoadString(ghInstance, IDS_STANDARD_FONT, pszFont, sizeof(pszFont) - 1); memset(pszHeight, 0, sizeof(pszHeight)); LoadString(ghInstance, IDS_STANDARD_FONT_HEIGHT, pszHeight, sizeof(pszHeight) - 1); hFont = CreateFont((int) pszHeight[0], 0, 0, 0, 400, 0, 0, 0, 0, 1, 2, 1, 49, pszFont); } SendMessage(ghEditWnd, WM_SETFONT, (WPARAM) hFont, 0); RefreshTree(); return FALSE; } /***************************************************************************** USBView_OnClose() *****************************************************************************/ VOID USBView_OnClose ( HWND hWnd ) { UNREFERENCED_PARAMETER(hWnd); DestroyTree(); PostQuitMessage(0); } /***************************************************************************** AddItemInformationToFile() Saves the information about the current item to the list *****************************************************************************/ VOID AddItemInformationToFile( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ) { HRESULT hr = S_OK; HANDLE hf = NULL; DWORD dwBytesWritten = 0; hf = *((PHANDLE) pContext); ResetTextBuffer(); hr = UpdateTreeItemDeviceInfo(hTreeWnd, hTreeItem); if (FAILED(hr)) { OOPS(); } else { WriteFile(hf, GetTextBuffer(), GetTextBufferPos()*sizeof(CHAR), &dwBytesWritten, NULL); } ResetTextBuffer(); } /***************************************************************************** SaveAllInformationAsText() Saves the entire USB tree as a text file *****************************************************************************/ HRESULT SaveAllInformationAsText( LPTSTR lpstrTextFileName, DWORD dwCreationDisposition ) { HRESULT hr = S_OK; HANDLE hf = NULL; hf = CreateFile(lpstrTextFileName, GENERIC_WRITE, 0, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); if (hf == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); OOPS(); } else { if (GetLastError() == ERROR_ALREADY_EXISTS) { // CreateFile() sets this error if we are overwriting an existing file // Reset this error to avoid false alarms SetLastError(0); } if (ghTreeRoot == NULL) { // If tree has not been populated yet, try a refresh RefreshTree(); } if (ghTreeRoot) { LockFile(hf, 0, 0, 0, 0); WalkTreeTopDown(ghTreeRoot, AddItemInformationToFile, &hf, NULL); UnlockFile(hf, 0, 0, 0, 0); CloseHandle(hf); hr = S_OK; } else { hr = HRESULT_FROM_WIN32(GetLastError()); OOPS(); } } ResetTextBuffer(); return hr; } /***************************************************************************** USBView_OnCommand() *****************************************************************************/ VOID USBView_OnCommand ( HWND hWnd, int id, HWND hwndCtl, UINT codeNotify ) { MENUITEMINFO menuInfo; char szFile[MAX_PATH + 1]; OPENFILENAME ofn; HANDLE hf = NULL; DWORD dwBytesWritten = 0; int nTextLength = 0; size_t lengthToNull = 0; HRESULT hr = S_OK; UNREFERENCED_PARAMETER(hwndCtl); UNREFERENCED_PARAMETER(codeNotify); //initialize save dialog variables memset(szFile, 0, sizeof(szFile)); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = 0; ofn.lpstrTitle = NULL; ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; switch (id) { case ID_AUTO_REFRESH: gDoAutoRefresh = !gDoAutoRefresh; menuInfo.cbSize = sizeof(menuInfo); menuInfo.fMask = MIIM_STATE; menuInfo.fState = gDoAutoRefresh ? MFS_CHECKED : MFS_UNCHECKED; SetMenuItemInfo(ghMainMenu, id, FALSE, &menuInfo); break; case ID_SAVE: { // initialize the save file name StringCchCopy(szFile, MAX_PATH, "USBView.txt"); ofn.lpstrFilter = "Text\0*.TXT\0\0"; ofn.lpstrDefExt = "txt"; //call dialog box if (! GetSaveFileName(&ofn)) { OOPS(); break; } //create new file hf = CreateFile((LPTSTR)ofn.lpstrFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hf == INVALID_HANDLE_VALUE) { OOPS(); } else { char *szText = NULL; //get data from display window to transfer to file nTextLength = GetWindowTextLength(ghEditWnd); nTextLength++; szText = ALLOC((DWORD)nTextLength); if (NULL != szText) { GetWindowText(ghEditWnd, (LPSTR) szText, nTextLength); // // Constrain length to the first null, which should be at // the end of the window text. This prevents writing extra // null characters. // if (StringCchLength(szText, nTextLength, &lengthToNull) == S_OK) { nTextLength = (int) lengthToNull; //lock the file, write to the file, unlock file LockFile(hf, 0, 0, 0, 0); WriteFile(hf, szText, nTextLength, &dwBytesWritten, NULL); UnlockFile(hf, 0, 0, 0, 0); } else { OOPS(); } CloseHandle(hf); FREE(szText); } else { OOPS(); } } break; } case ID_SAVEALL: { // initialize the save file name StringCchCopy(szFile, MAX_PATH, "USBViewAll.txt"); ofn.lpstrFilter = "Text\0*.txt\0\0"; ofn.lpstrDefExt = "txt"; //call dialog box if (! GetSaveFileName(&ofn)) { OOPS(); break; } // Save the file, overwrite in case of UI since UI gives popup for confirmation hr = SaveAllInformationAsText(ofn.lpstrFile, CREATE_ALWAYS); if (FAILED(hr)) { OOPS(); } break; } case ID_SAVEXML: { // initialize the save file name StringCchCopy(szFile, MAX_PATH, "USBViewAll.xml"); ofn.lpstrFilter = "Xml\0*.xml\0\0"; ofn.lpstrDefExt = "xml"; //call dialog box if (! GetSaveFileName(&ofn)) { OOPS(); break; } // Save the file, overwrite in case of UI since UI gives popup for confirmation hr = SaveAllInformationAsXml(ofn.lpstrFile, CREATE_ALWAYS); if (FAILED(hr)) { OOPS(); } break; } case ID_CONFIG_DESCRIPTORS: gDoConfigDesc = !gDoConfigDesc; menuInfo.cbSize = sizeof(menuInfo); menuInfo.fMask = MIIM_STATE; menuInfo.fState = gDoConfigDesc ? MFS_CHECKED : MFS_UNCHECKED; SetMenuItemInfo(ghMainMenu, id, FALSE, &menuInfo); break; case ID_ANNOTATION: gDoAnnotation = !gDoAnnotation; menuInfo.cbSize = sizeof(menuInfo); menuInfo.fMask = MIIM_STATE; menuInfo.fState = gDoAnnotation ? MFS_CHECKED : MFS_UNCHECKED; SetMenuItemInfo(ghMainMenu, id, FALSE, &menuInfo); break; case ID_LOG_DEBUG: gLogDebug = !gLogDebug; menuInfo.cbSize = sizeof(menuInfo); menuInfo.fMask = MIIM_STATE; menuInfo.fState = gLogDebug ? MFS_CHECKED : MFS_UNCHECKED; SetMenuItemInfo(ghMainMenu, id, FALSE, &menuInfo); break; case ID_ABOUT: DialogBox(ghInstance, MAKEINTRESOURCE(IDD_ABOUT), ghMainWnd, (DLGPROC) AboutDlgProc); break; case ID_EXIT: UnregisterDeviceNotification(gNotifyDevHandle); UnregisterDeviceNotification(gNotifyHubHandle); DestroyTree(); PostQuitMessage(0); break; case ID_REFRESH: RefreshTree(); break; } } /***************************************************************************** USBView_OnLButtonDown() *****************************************************************************/ VOID USBView_OnLButtonDown ( HWND hWnd, BOOL fDoubleClick, int x, int y, UINT keyFlags ) { UNREFERENCED_PARAMETER(fDoubleClick); UNREFERENCED_PARAMETER(x); UNREFERENCED_PARAMETER(y); UNREFERENCED_PARAMETER(keyFlags); gbButtonDown = TRUE; SetCapture(hWnd); } /***************************************************************************** USBView_OnLButtonUp() *****************************************************************************/ VOID USBView_OnLButtonUp ( HWND hWnd, int x, int y, UINT keyFlags ) { UNREFERENCED_PARAMETER(hWnd); UNREFERENCED_PARAMETER(x); UNREFERENCED_PARAMETER(y); UNREFERENCED_PARAMETER(keyFlags); gbButtonDown = FALSE; ReleaseCapture(); } /***************************************************************************** USBView_OnMouseMove() *****************************************************************************/ VOID USBView_OnMouseMove ( HWND hWnd, int x, int y, UINT keyFlags ) { UNREFERENCED_PARAMETER(hWnd); UNREFERENCED_PARAMETER(y); UNREFERENCED_PARAMETER(keyFlags); SetCursor(ghSplitCursor); if (gbButtonDown) { ResizeWindows(TRUE, x); } } /***************************************************************************** USBView_OnSize(); *****************************************************************************/ VOID USBView_OnSize ( HWND hWnd, UINT state, int cx, int cy ) { UNREFERENCED_PARAMETER(hWnd); UNREFERENCED_PARAMETER(state); UNREFERENCED_PARAMETER(cx); UNREFERENCED_PARAMETER(cy); ResizeWindows(FALSE, 0); } /***************************************************************************** USBView_OnNotify() *****************************************************************************/ LRESULT USBView_OnNotify ( HWND hWnd, int DlgItem, LPNMHDR lpNMHdr ) { UNREFERENCED_PARAMETER(hWnd); UNREFERENCED_PARAMETER(DlgItem); if (lpNMHdr->code == TVN_SELCHANGED) { HTREEITEM hTreeItem; hTreeItem = ((NM_TREEVIEW *)lpNMHdr)->itemNew.hItem; if (hTreeItem) { UpdateEditControl(ghEditWnd, ghTreeWnd, hTreeItem); } } return 0; } /***************************************************************************** USBView_OnDeviceChange() *****************************************************************************/ BOOL USBView_OnDeviceChange ( HWND hwnd, UINT uEvent, DWORD dwEventData ) { UNREFERENCED_PARAMETER(hwnd); UNREFERENCED_PARAMETER(dwEventData); if (gDoAutoRefresh) { switch (uEvent) { case DBT_DEVICEARRIVAL: case DBT_DEVICEREMOVECOMPLETE: RefreshTree(); break; } } return TRUE; } /***************************************************************************** DestroyTree() *****************************************************************************/ VOID DestroyTree (VOID) { // Clear the selection of the TreeView, so that when the tree is // destroyed, the control won't try to constantly "shift" the // selection to another item. // TreeView_SelectItem(ghTreeWnd, NULL); // Destroy the current contents of the TreeView // if (ghTreeRoot) { WalkTree(ghTreeRoot, CleanupItem, NULL); TreeView_DeleteAllItems(ghTreeWnd); ghTreeRoot = NULL; } ClearDeviceList(&gDeviceList); ClearDeviceList(&gHubList); } /***************************************************************************** RefreshTree() *****************************************************************************/ VOID RefreshTree (VOID) { CHAR statusText[128]; ULONG devicesConnected; // Clear the edit control // SetWindowText(ghEditWnd, ""); // Destroy the current contents of the TreeView // DestroyTree(); // Create the root tree node // ghTreeRoot = AddLeaf(TVI_ROOT, 0, "My Computer", ComputerIcon); if (ghTreeRoot != NULL) { // Enumerate all USB buses and populate the tree // EnumerateHostControllers(ghTreeRoot, &devicesConnected); // // Expand all tree nodes // WalkTree(ghTreeRoot, ExpandItem, NULL); // Update Status Line with number of devices connected // memset(statusText, 0, sizeof(statusText)); StringCchPrintf(statusText, sizeof(statusText), #ifdef H264_SUPPORT "UVC Spec Version: %d.%d Version: %d.%d Devices Connected: %d Hubs Connected: %d", UVC_SPEC_MAJOR_VERSION, UVC_SPEC_MINOR_VERSION, USBVIEW_MAJOR_VERSION, USBVIEW_MINOR_VERSION, devicesConnected, TotalHubs); #else "Devices Connected: %d Hubs Connected: %d", devicesConnected, TotalHubs); #endif SetWindowText(ghStatusWnd, statusText); } else { OOPS(); } } /***************************************************************************** AboutDlgProc() *****************************************************************************/ LRESULT CALLBACK AboutDlgProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { UNREFERENCED_PARAMETER(lParam); switch (uMsg) { case WM_INITDIALOG: { HRESULT hr; char TextBuffer[TEXT_ITEM_LENGTH]; HWND hItem; hItem = GetDlgItem(hwnd, IDC_VERSION); if (hItem != NULL) { hr = StringCbPrintfA(TextBuffer, sizeof(TextBuffer), "USBView version: %d.%d", USBVIEW_MAJOR_VERSION, USBVIEW_MINOR_VERSION); if (SUCCEEDED(hr)) { SetWindowText(hItem,TextBuffer); } } hItem = GetDlgItem(hwnd, IDC_UVCVERSION); if (hItem != NULL) { hr = StringCbPrintfA(TextBuffer, sizeof(TextBuffer), "USB Video Class Spec version: %d.%d", UVC_SPEC_MAJOR_VERSION, UVC_SPEC_MINOR_VERSION); if (SUCCEEDED(hr)) { SetWindowText(hItem,TextBuffer); } } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: EndDialog (hwnd, 0); break; } break; } return FALSE; } /***************************************************************************** AddLeaf() *****************************************************************************/ HTREEITEM AddLeaf ( HTREEITEM hTreeParent, LPARAM lParam, _In_ LPTSTR lpszText, TREEICON TreeIcon ) { TV_INSERTSTRUCT tvins; HTREEITEM hti; memset(&tvins, 0, sizeof(tvins)); // Set the parent item // tvins.hParent = hTreeParent; tvins.hInsertAfter = TVI_LAST; // pszText and lParam members are valid // tvins.item.mask = TVIF_TEXT | TVIF_PARAM; // Set the text of the item. // tvins.item.pszText = lpszText; // Set the user context item // tvins.item.lParam = lParam; // Add the item to the tree-view control. // hti = TreeView_InsertItem(ghTreeWnd, &tvins); // added tvins.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; tvins.item.hItem = hti; // Determine which icon to display for the device // switch (TreeIcon) { case ComputerIcon: tvins.item.iImage = giComputer; tvins.item.iSelectedImage = giComputer; break; case HubIcon: tvins.item.iImage = giHub; tvins.item.iSelectedImage = giHub; break; case NoDeviceIcon: tvins.item.iImage = giNoDevice; tvins.item.iSelectedImage = giNoDevice; break; case GoodDeviceIcon: tvins.item.iImage = giGoodDevice; tvins.item.iSelectedImage = giGoodDevice; break; case GoodSsDeviceIcon: tvins.item.iImage = giGoodSsDevice; tvins.item.iSelectedImage = giGoodSsDevice; break; case NoSsDeviceIcon: tvins.item.iImage = giNoSsDevice; tvins.item.iSelectedImage = giNoSsDevice; break; case BadDeviceIcon: default: tvins.item.iImage = giBadDevice; tvins.item.iSelectedImage = giBadDevice; break; } TreeView_SetItem(ghTreeWnd, &tvins.item); return hti; } /***************************************************************************** WalkTreeTopDown() *****************************************************************************/ VOID WalkTreeTopDown( _In_ HTREEITEM hTreeItem, _In_ LPFNTREECALLBACK lpfnTreeCallback, _In_opt_ PVOID pContext, _In_opt_ LPFNTREENOTIFYCALLBACK lpfnTreeNotifyCallback ) { if (hTreeItem) { HTREEITEM hTreeChild = TreeView_GetChild(ghTreeWnd, hTreeItem); HTREEITEM hTreeSibling = TreeView_GetNextSibling(ghTreeWnd, hTreeItem); // // Call the lpfnCallBack on the node itself. // (*lpfnTreeCallback)(ghTreeWnd, hTreeItem, pContext); // // Recursively call WalkTree on the node's first child. // if (hTreeChild) { WalkTreeTopDown(hTreeChild, lpfnTreeCallback, pContext, lpfnTreeNotifyCallback); } // // Recursively call WalkTree on the node's first sibling. // if (hTreeSibling) { WalkTreeTopDown(hTreeSibling, lpfnTreeCallback, pContext, lpfnTreeNotifyCallback); } else { // If there are no more siblings, we have reached the end of // list of child nodes. Call notify function if (lpfnTreeNotifyCallback != NULL) { (*lpfnTreeNotifyCallback)(pContext); } } } } /***************************************************************************** WalkTree() *****************************************************************************/ VOID WalkTree ( _In_ HTREEITEM hTreeItem, _In_ LPFNTREECALLBACK lpfnTreeCallback, _In_opt_ PVOID pContext ) { if (hTreeItem) { // Recursively call WalkTree on the node's first child. // WalkTree(TreeView_GetChild(ghTreeWnd, hTreeItem), lpfnTreeCallback, pContext); // // Call the lpfnCallBack on the node itself. // (*lpfnTreeCallback)(ghTreeWnd, hTreeItem, pContext); // // // Recursively call WalkTree on the node's first sibling. // WalkTree(TreeView_GetNextSibling(ghTreeWnd, hTreeItem), lpfnTreeCallback, pContext); } } /***************************************************************************** ExpandItem() *****************************************************************************/ VOID ExpandItem ( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ) { // // Make this node visible. // UNREFERENCED_PARAMETER(pContext); TreeView_Expand(hTreeWnd, hTreeItem, TVE_EXPAND); } /***************************************************************************** SaveAllInformationAsXML() Saves the entire USB tree as an XML file *****************************************************************************/ HRESULT SaveAllInformationAsXml( LPTSTR lpstrTextFileName, DWORD dwCreationDisposition ) { HRESULT hr = S_OK; if (ghTreeRoot == NULL) { // If tree has not been populated yet, try a refresh RefreshTree(); } if (ghTreeRoot) { WalkTreeTopDown(ghTreeRoot, AddItemInformationToXmlView, NULL, XmlNotifyEndOfNodeList); hr = SaveXml(lpstrTextFileName, dwCreationDisposition); } else { hr = E_FAIL; OOPS(); } ResetTextBuffer(); return hr; } //***************************************************************************** // // AddItemInformationToXmlView // // hTreeItem - Handle of selected TreeView item for which information should // be added to the XML View // //***************************************************************************** VOID AddItemInformationToXmlView( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ) { TV_ITEM tvi; PVOID info; PCHAR tviName = NULL; UNREFERENCED_PARAMETER(pContext); #ifdef H264_SUPPORT ResetErrorCounts(); #endif tviName = (PCHAR) ALLOC(256); if (NULL == tviName) { return; } // // Get the name of the TreeView item, along with the a pointer to the // info we stored about the item in the item's lParam. // tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM; tvi.hItem = hTreeItem; tvi.pszText = (LPSTR) tviName; tvi.cchTextMax = 256; TreeView_GetItem(hTreeWnd, &tvi); info = (PVOID)tvi.lParam; if (NULL != info) { // // Add Item to XML object // switch (*(PUSBDEVICEINFOTYPE)info) { case HostControllerInfo: XmlAddHostController(tviName, (PUSBHOSTCONTROLLERINFO) info); break; case RootHubInfo: XmlAddRootHub(tviName, (PUSBROOTHUBINFO) info); break; case ExternalHubInfo: XmlAddExternalHub(tviName, (PUSBEXTERNALHUBINFO) info); break; case DeviceInfo: XmlAddUsbDevice(tviName, (PUSBDEVICEINFO) info); break; } } return; } /***************************************************************************** DisplayLastError() *****************************************************************************/ DWORD DisplayLastError( _Inout_updates_bytes_(count) char *szString, int count) { LPVOID lpMsgBuf; // get the last error code DWORD dwError = GetLastError(); // get the system message for this error code if (FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL )) { StringCchPrintf(szString, count, "Error: %s", (LPTSTR)lpMsgBuf ); } // Free the local buffer LocalFree( lpMsgBuf ); // return the error return dwError; } #if DBG /***************************************************************************** Oops() *****************************************************************************/ VOID Oops ( _In_ PCHAR File, ULONG Line ) { char szBuf[1024]; LPTSTR lpMsgBuf; DWORD dwGLE = GetLastError(); memset(szBuf, 0, sizeof(szBuf)); // get the system message for this error code if (FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwGLE, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL)) { StringCchPrintf(szBuf, sizeof(szBuf), "File: %s, Line %d\r\nGetLastError 0x%x %u %s\n", File, Line, dwGLE, dwGLE, lpMsgBuf); } else { StringCchPrintf(szBuf, sizeof(szBuf), "File: %s, Line %d\r\nGetLastError 0x%x %u\r\n", File, Line, dwGLE, dwGLE); } OutputDebugString(szBuf); // Free the system allocated local buffer LocalFree(lpMsgBuf); return; } #endif ================================================ FILE: tests/projects/windows/winsdk/usbview/uvcview.h ================================================ /*++ Copyright (c) 1997-2008 Microsoft Corporation Module Name: UVCVIEW.H Abstract: This is the header file for UVCVIEW Environment: user mode Revision History: 04-25-97 : created 04/13/2005 : major bug fixing --*/ /***************************************************************************** I N C L U D E S *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // This is mostly a private USB Audio descriptor header #include "usbdesc.h" // This is the inbox USBVideo driver descriptor header (copied locally) #include "uvcdesc.h" /***************************************************************************** P R A G M A S *****************************************************************************/ #pragma once /***************************************************************************** D E F I N E S *****************************************************************************/ // define H264_SUPPORT to add H.264 support to uvcview.exe #define H264_SUPPORT #define TEXT_ITEM_LENGTH 64 #ifdef DEBUG #undef DBG #define DBG 1 #endif #if DBG #define OOPS() Oops(__FILE__, __LINE__) #else #define OOPS() #endif #if DBG #define ALLOC(dwBytes) MyAlloc(__FILE__, __LINE__, (dwBytes)) #define REALLOC(hMem, dwBytes) MyReAlloc((hMem), (dwBytes)) #define FREE(hMem) MyFree((hMem)) #define CHECKFORLEAKS() MyCheckForLeaks() #else #define ALLOC(dwBytes) GlobalAlloc(GPTR,(dwBytes)) #define REALLOC(hMem, dwBytes) GlobalReAlloc((hMem), (dwBytes), (GMEM_MOVEABLE|GMEM_ZEROINIT)) #define FREE(hMem) GlobalFree((hMem)) #define CHECKFORLEAKS() #endif #define DEVICE_CONFIGURATION_TEXT_LENGTH 10240 #define STR_INVALID_POWER_STATE "(invalid state) " #define STR_UNKNOWN_CONTROLLER_FLAVOR "Unknown" FORCEINLINE VOID InitializeListHead( _Out_ PLIST_ENTRY ListHead ) { ListHead->Flink = ListHead->Blink = ListHead; } // // BOOLEAN // IsListEmpty( // PLIST_ENTRY ListHead // ); // #define IsListEmpty(ListHead) \ ((ListHead)->Flink == (ListHead)) // // PLIST_ENTRY // RemoveHeadList( // PLIST_ENTRY ListHead // ); // #define RemoveHeadList(ListHead) \ (ListHead)->Flink;\ {RemoveEntryList((ListHead)->Flink)} // // VOID // RemoveEntryList( // PLIST_ENTRY Entry // ); // #define RemoveEntryList(Entry) {\ PLIST_ENTRY _EX_Blink;\ PLIST_ENTRY _EX_Flink;\ _EX_Flink = (Entry)->Flink;\ _EX_Blink = (Entry)->Blink;\ _EX_Blink->Flink = _EX_Flink;\ _EX_Flink->Blink = _EX_Blink;\ } // // VOID // InsertTailList( // PLIST_ENTRY ListHead, // PLIST_ENTRY Entry // ); // #define InsertTailList(ListHead,Entry) {\ PLIST_ENTRY _EX_Blink;\ PLIST_ENTRY _EX_ListHead;\ _EX_ListHead = (ListHead);\ _EX_Blink = _EX_ListHead->Blink;\ (Entry)->Flink = _EX_ListHead;\ (Entry)->Blink = _EX_Blink;\ _EX_Blink->Flink = (Entry);\ _EX_ListHead->Blink = (Entry);\ } // global version for USB Video Class spec version (pre-release) #define BCDVDC 0x0083 // A.2 Video Interface Subclass Codes #define SC_VIDEO_INTERFACE_COLLECTION 0x03 // A.3 Video Interface Protocol Codes #define PC_PROTOCOL_UNDEFINED 0x00 // USB Video Class spec version #define NOT_UVC 0x0 #define UVC10 0x100 #define UVC11 0x110 #ifdef H264_SUPPORT #define UVC15 0x150 #endif #define OUTPUT_MESSAGE_MAX_LENGTH 1024 #define MAX_DEVICE_PROP 200 #define MAX_DRIVER_KEY_NAME 256 /***************************************************************************** T Y P E D E F S *****************************************************************************/ typedef enum _TREEICON { ComputerIcon, HubIcon, NoDeviceIcon, GoodDeviceIcon, BadDeviceIcon, GoodSsDeviceIcon, NoSsDeviceIcon } TREEICON; // Callback function for walking TreeView items // typedef VOID (*LPFNTREECALLBACK)( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ); // Callback notification function called at end of every tree depth typedef VOID (*LPFNTREENOTIFYCALLBACK)(PVOID pContext); // // Structure used to build a linked list of String Descriptors // retrieved from a device. // typedef struct _STRING_DESCRIPTOR_NODE { struct _STRING_DESCRIPTOR_NODE *Next; UCHAR DescriptorIndex; USHORT LanguageID; USB_STRING_DESCRIPTOR StringDescriptor[1]; } STRING_DESCRIPTOR_NODE, *PSTRING_DESCRIPTOR_NODE; // // A collection of device properties. The device can be hub, host controller or usb device // typedef struct _USB_DEVICE_PNP_STRINGS { PCHAR DeviceId; PCHAR DeviceDesc; PCHAR HwId; PCHAR Service; PCHAR DeviceClass; PCHAR PowerState; } USB_DEVICE_PNP_STRINGS, *PUSB_DEVICE_PNP_STRINGS; typedef struct _DEVICE_INFO_NODE { HDEVINFO DeviceInfo; LIST_ENTRY ListEntry; SP_DEVINFO_DATA DeviceInfoData; SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceDetailData; PSTR DeviceDescName; ULONG DeviceDescNameLength; PSTR DeviceDriverName; ULONG DeviceDriverNameLength; DEVICE_POWER_STATE LatestDevicePowerState; } DEVICE_INFO_NODE, *PDEVICE_INFO_NODE; // // Structures assocated with TreeView items through the lParam. When an item // is selected, the lParam is retrieved and the structure it which it points // is used to display information in the edit control. // typedef enum _USBDEVICEINFOTYPE { HostControllerInfo, RootHubInfo, ExternalHubInfo, DeviceInfo } USBDEVICEINFOTYPE, *PUSBDEVICEINFOTYPE; typedef struct _USBHOSTCONTROLLERINFO { USBDEVICEINFOTYPE DeviceInfoType; LIST_ENTRY ListEntry; PCHAR DriverKey; ULONG VendorID; ULONG DeviceID; ULONG SubSysID; ULONG Revision; USB_POWER_INFO USBPowerInfo[6]; BOOL BusDeviceFunctionValid; ULONG BusNumber; USHORT BusDevice; USHORT BusFunction; PUSB_CONTROLLER_INFO_0 ControllerInfo; PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; } USBHOSTCONTROLLERINFO, *PUSBHOSTCONTROLLERINFO; typedef struct _USBROOTHUBINFO { USBDEVICEINFOTYPE DeviceInfoType; PUSB_NODE_INFORMATION HubInfo; PUSB_HUB_INFORMATION_EX HubInfoEx; PCHAR HubName; PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps; PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; PDEVICE_INFO_NODE DeviceInfoNode; PUSB_HUB_CAPABILITIES_EX HubCapabilityEx; } USBROOTHUBINFO, *PUSBROOTHUBINFO; typedef struct _USBEXTERNALHUBINFO { USBDEVICEINFOTYPE DeviceInfoType; PUSB_NODE_INFORMATION HubInfo; PUSB_HUB_INFORMATION_EX HubInfoEx; PCHAR HubName; PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo; PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps; PUSB_DESCRIPTOR_REQUEST ConfigDesc; PUSB_DESCRIPTOR_REQUEST BosDesc; PSTRING_DESCRIPTOR_NODE StringDescs; PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2; // NULL if root HUB PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; PDEVICE_INFO_NODE DeviceInfoNode; PUSB_HUB_CAPABILITIES_EX HubCapabilityEx; } USBEXTERNALHUBINFO, *PUSBEXTERNALHUBINFO; // HubInfo, HubName may be in USBDEVICEINFOTYPE, so they can be removed typedef struct { USBDEVICEINFOTYPE DeviceInfoType; PUSB_NODE_INFORMATION HubInfo; // NULL if not a HUB PUSB_HUB_INFORMATION_EX HubInfoEx; // NULL if not a HUB PCHAR HubName; // NULL if not a HUB PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo; // NULL if root HUB PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps; PUSB_DESCRIPTOR_REQUEST ConfigDesc; // NULL if root HUB PUSB_DESCRIPTOR_REQUEST BosDesc; // NULL if root HUB PSTRING_DESCRIPTOR_NODE StringDescs; PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2; // NULL if root HUB PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; PDEVICE_INFO_NODE DeviceInfoNode; PUSB_HUB_CAPABILITIES_EX HubCapabilityEx; // NULL if not a HUB } USBDEVICEINFO, *PUSBDEVICEINFO; typedef struct _STRINGLIST { #ifdef H264_SUPPORT ULONGLONG ulFlag; #else ULONG ulFlag; #endif PCHAR pszString; PCHAR pszModifier; } STRINGLIST, * PSTRINGLIST; typedef struct _DEVICE_GUID_LIST { HDEVINFO DeviceInfo; LIST_ENTRY ListHead; } DEVICE_GUID_LIST, *PDEVICE_GUID_LIST; /***************************************************************************** G L O B A L S *****************************************************************************/ // // USBVIEW.C // BOOL gDoConfigDesc; BOOL gDoAnnotation; BOOL gLogDebug; int TotalHubs; // // ENUM.C // PCHAR ConnectionStatuses[]; // // DISPVID.C // DEFINE_GUID(YUY2_Format,0x32595559L,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); DEFINE_GUID(NV12_Format,0x3231564EL,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); #ifdef H264_SUPPORT DEFINE_GUID(H264_Format,0x34363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); #endif // The following flags/variables are all initialized in Display.c InitializePerDeviceSettings() // // Save the default frame from the MJPEG, Uncompressed, Vendor and Frame Based Format descriptor // Check for this when processing the individual Frame descriptors UCHAR g_chMJPEGFrameDefault; UCHAR g_chUNCFrameDefault; UCHAR g_chVendorFrameDefault; UCHAR g_chFrameBasedFrameDefault; // Spec version of UVC device UINT g_chUVCversion; // Base address of the USBDEVICEINFO for device we're parsing PUSBDEVICEINFO CurrentUSBDeviceInfo; // Base address of the Configuration descriptor we're parsing PUSB_CONFIGURATION_DESCRIPTOR CurrentConfigDesc; // Length of the current configuration descriptor DWORD dwConfigLength; // Our current position from the beginning of the config descriptor DWORD dwConfigIndex; // // DISPLAY.C // int gDeviceSpeed; // Save the current Configuration starting and ending addresses // Used in ValidateDescAddress() // PUSB_CONFIGURATION_DESCRIPTOR g_pConfigDesc; PSTRING_DESCRIPTOR_NODE g_pStringDescs; PUCHAR g_descEnd; /***************************************************************************** F U N C T I O N P R O T O T Y P E S *****************************************************************************/ // // USBVIEW.C // HTREEITEM AddLeaf ( HTREEITEM hTreeParent, LPARAM lParam, _In_ LPTSTR lpszText, TREEICON TreeIcon ); VOID Oops ( _In_ PCHAR File, ULONG Line ); // // DISPLAY.C // EXTERN_C UINT IsIADDevice (PUSBDEVICEINFO info); EXTERN_C UINT IsUVCDevice (PUSBDEVICEINFO info); EXTERN_C PCHAR GetVendorString(USHORT idVendor); EXTERN_C PCHAR GetLangIDString(USHORT idLang); EXTERN_C UINT GetConfigurationSize (PUSBDEVICEINFO info); EXTERN_C PUSB_COMMON_DESCRIPTOR GetNextDescriptor( _In_reads_bytes_(TotalLength) PUSB_COMMON_DESCRIPTOR FirstDescriptor, _In_ ULONG TotalLength, _In_ PUSB_COMMON_DESCRIPTOR StartDescriptor, _In_ long DescriptorType ); HRESULT UpdateTreeItemDeviceInfo( HWND hTreeWnd, HTREEITEM hTreeItem ); PCHAR GetTextBuffer( ); BOOL ResetTextBuffer( ); BOOL CreateTextBuffer ( ); VOID DestroyTextBuffer ( ); UINT GetTextBufferPos ( ); VOID UpdateEditControl ( HWND hEditWnd, HWND hTreeWnd, HTREEITEM hTreeItem ); VOID __cdecl AppendBuffer ( LPCTSTR lpFormat, ... ); VOID __cdecl AppendTextBuffer ( LPCTSTR lpFormat, ... ); VOID DisplayStringDescriptor ( UCHAR Index, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); PCHAR GetStringFromList( PSTRINGLIST slPowerState, ULONG ulNumElements, #ifdef H264_SUPPORT ULONGLONG ulFlag, #else ULONG ulFlag, #endif _In_ PCHAR szDefault ); EXTERN_C PCHAR GetPowerStateString( WDMUSB_POWER_STATE powerState ); EXTERN_C PCHAR GetControllerFlavorString( USB_CONTROLLER_FLAVOR flavor ); EXTERN_C ULONG GetEhciDebugPort( ULONG vendorId, ULONG deviceId ); VOID WalkTreeTopDown( _In_ HTREEITEM hTreeItem, _In_ LPFNTREECALLBACK lpfnTreeCallback, _In_opt_ PVOID pContext, _In_opt_ LPFNTREENOTIFYCALLBACK lpfnTreeNotifyCallback ); VOID RefreshTree (VOID); // // ENUM.C // VOID EnumerateHostControllers ( HTREEITEM hTreeParent, ULONG *DevicesConnected ); VOID CleanupItem ( HWND hTreeWnd, HTREEITEM hTreeItem, PVOID pContext ); DEVICE_POWER_STATE AcquireDevicePowerState( _Inout_ PDEVICE_INFO_NODE pNode ); _Success_(return == TRUE) BOOL GetDeviceProperty( _In_ HDEVINFO DeviceInfoSet, _In_ PSP_DEVINFO_DATA DeviceInfoData, _In_ DWORD Property, _Outptr_ LPTSTR *ppBuffer ); void ClearDeviceList( PDEVICE_GUID_LIST DeviceList ); // // DEBUG.C // _Success_(return != NULL) _Post_writable_byte_size_(dwBytes) HGLOBAL MyAlloc ( _In_ PCHAR File, ULONG Line, DWORD dwBytes ); _Success_(return != NULL) _Post_writable_byte_size_(dwBytes) HGLOBAL MyReAlloc ( HGLOBAL hMem, DWORD dwBytes ); HGLOBAL MyFree ( HGLOBAL hMem ); VOID MyCheckForLeaks ( VOID ); // // DEVNODE.C // PUSB_DEVICE_PNP_STRINGS DriverNameToDeviceProperties( _In_reads_bytes_(cbDriverName) PCHAR DriverName, _In_ size_t cbDriverName ); VOID FreeDeviceProperties( _In_ PUSB_DEVICE_PNP_STRINGS *ppDevProps ); // // DISPAUD.C // BOOL DisplayAudioDescriptor ( PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc, UCHAR bInterfaceSubClass ); // // DISPVID.C // BOOL DisplayVideoDescriptor ( PVIDEO_SPECIFIC VidCommonDesc, UCHAR bInterfaceSubClass, PSTRING_DESCRIPTOR_NODE StringDescs, DEVICE_POWER_STATE LatestDevicePowerState ); // // DISPLAY.C // BOOL ValidateDescAddress ( PUSB_COMMON_DESCRIPTOR commonDesc ); ================================================ FILE: tests/projects/windows/winsdk/usbview/uvcview.rc ================================================ #include #include #include "resource.h" #include ////////////////////////////////////////////////////////////////////////////// // // VERSION // #define VER_FILEDESCRIPTION_STR "Microsoft\256 Windows(TM) USB device viewer" #define VER_INTERNALNAME_STR "USBView" #define VER_ORIGINALFILENAME_STR VER_INTERNALNAME_STR #define VER_LEGALCOPYRIGHT_STR "Copyright \251 Microsoft Corporation 1996-2011 All Rights Reserved." #define VER_FILETYPE VFT_APP #define VER_FILESUBTYPE VFT2_UNKNOWN #include ////////////////////////////////////////////////////////////////////////////// // // ICON // IDI_ICON ICON DISCARDABLE "USB.ICO" IDI_BADICON ICON DISCARDABLE "BANG.ICO" IDI_COMPUTER ICON DISCARDABLE "MONITOR.ICO" IDI_HUB ICON DISCARDABLE "HUB.ICO" IDI_NODEVICE ICON DISCARDABLE "PORT.ICO" IDI_NOSSDEVICE ICON DISCARDABLE "SSPORT.ICO" IDI_SSICON ICON DISCARDABLE "SSUSB.ICO" ////////////////////////////////////////////////////////////////////////////// // // Cursor // IDC_SPLIT CURSOR DISCARDABLE "SPLIT.CUR" ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_MAINDIALOG DIALOGEX 0, 0, 415, 243 STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "USB Device Viewer" MENU IDR_MENU FONT 8, "MS Shell Dlg" BEGIN CONTROL "Tree1",IDC_TREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | WS_BORDER | WS_TABSTOP, 0,0,120,234,WS_EX_CLIENTEDGE EDITTEXT IDC_EDIT,120,0,295,234,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL CONTROL "Devices Connected: 0",IDC_STATUS,"msctls_statusbar32", SBARS_SIZEGRIP, 0,235,415,8 END IDD_ABOUT DIALOG DISCARDABLE 0, 0, 230, 117 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About USBView" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "OK",IDOK,90,100,50,14 LTEXT "USB Device Viewer",IDC_STATIC,54,15,104,8 LTEXT VER_LEGALCOPYRIGHT_STR,IDC_STATIC,54,45,145,8 EDITTEXT IDC_VERSION,54,60,110,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_UVCVERSION,54,75,110,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER ICON IDI_ICON,IDC_STATIC,15,15,21,20 END ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_MENU MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Refresh\tF5", ID_REFRESH MENUITEM SEPARATOR MENUITEM "Save Current &View ..." ID_SAVE MENUITEM "Save As (&txt) ...", ID_SAVEALL MENUITEM "Save As (&xml) ...\tF2", ID_SAVEXML MENUITEM SEPARATOR MENUITEM "E&xit", ID_EXIT END POPUP "&Options" BEGIN MENUITEM "&Auto Refresh", ID_AUTO_REFRESH, CHECKED MENUITEM "Show &Config Descriptors", ID_CONFIG_DESCRIPTORS, CHECKED MENUITEM SEPARATOR // MENUITEM "&Show Description Annotations", ID_ANNOTATION, CHECKED MENUITEM "&Log to debugger", ID_LOG_DEBUG END POPUP "&Help" BEGIN MENUITEM "&About", ID_ABOUT END END ////////////////////////////////////////////////////////////////////////////// // // Accelerator // IDACCEL ACCELERATORS DISCARDABLE BEGIN VK_F5, ID_REFRESH, VIRTKEY,NOINVERT VK_F2, ID_SAVEXML, VIRTKEY,NOINVERT END ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDS_STRINGBASE "Base string" END STRINGTABLE BEGIN IDS_STANDARD_FONT "Courier" IDS_STANDARD_FONT_HEIGHT "\13" IDS_STANDARD_FONT_WIDTH "\8" END STRINGTABLE DISCARDABLE BEGIN IDS_USBVIEW_USAGE "usbview usage:\nusbview [/?]\n\t/? - this usage message.\ \n\t/q quiet mode, does not display 'Press any key to continue ...\n\t\ \nusbview [/q] [/f] /saveall:\ \n\tsaveall - saves the USB tree view as a text file\ \n\t/f - overwrite file if it already exists\n\nusbview [/q] [/f] /savexml:\ \n\tsavexml - saves the USB tree view as a xml file\n\t/f - overwrite file if it already exists\n\n" IDS_USBVIEW_PRESSKEY "Press any key to continue ...\n" IDS_USBVIEW_INVALIDARG "Invalid argument: [%1]\n" IDS_USBVIEW_FILE_EXISTS_TXT "File: [%1] already exists, try `usbview /f /saveall:[%1]` to force overwrite\n" IDS_USBVIEW_FILE_EXISTS_XML "File: [%1] already exists, try `usbview /f /savexml:[%1]` to force overwrite\n" IDS_USBVIEW_INTERNAL_ERROR "An internal error occured, please report this as a bug\n" IDS_USBVIEW_SAVED_TO "Usbview information saved to file : [%1]\n" IDS_USBVIEW_INVALID_FILENAME "The argument : [%1] is invalid or incomplete.\n" END ================================================ FILE: tests/projects/windows/winsdk/usbview/vndrlist.h ================================================ /*++ Copyright (c) 1997-2008 Microsoft Corporation Module Name: VNDRLIST.H Abstract: This header file contains a list of all currently known USB Vendor IDs and the vendor name associated with each Vendor ID. Source: http://www.usb.org Environment: Kernel & user mode Revision History: 04-25-97 : created 03-28-03 : refreshed with latest list from usb.org 05-04-05 : refreshed with latest list from usb.org 05-02-07 : refreshed with latest list from usb.org 03-19-08 : refreshed with latest list from usb.org --*/ #ifndef __VNDRLIST_H__ #define __VNDRLIST_H__ // // Vendor ID structure // typedef struct _VENDOR_ID { USHORT usVendorID; PCHAR szVendor; } VENDOR_ID, *PVENDOR_ID; // // This list built from information obtained from // http://www.usb.org/developers/tools/ // // This information has not been independently verified and no claims // are made here as to its accuracy. // // 10978 total // VENDOR_ID USBVendorIDs[] = { { 0x0079, "Shenzhen Longshengwei Technology, Co., Ltd." }, { 0x013A, "Aimgene Technology Co., Ltd" }, { 0x03CC, "GN OTOMETRICS" }, { 0x03E8, "EndPoints Inc." }, { 0x03E9, "Thesys Microelectronics" }, { 0x03EA, "Data Broadcasting Corp." }, { 0x03EB, "Atmel Corporation" }, { 0x03EC, "Iwatsu America Inc." }, { 0x03ED, "Mitel Corporation" }, { 0x03EE, "Mitsumi" }, { 0x03F0, "HP Inc." }, { 0x03F1, "Genoa Technology" }, { 0x03F2, "Oak Technology, Inc" }, { 0x03F3, "Adaptec, Inc." }, { 0x03F4, "Diebold, Inc." }, { 0x03F5, "Siemens Electromechanical" }, { 0x03F7, "Tulip Computers International" }, { 0x03F8, "Epson Imaging Technology Center" }, { 0x03F9, "KeyTronic Corp." }, { 0x03FB, "OPTi Inc." }, { 0x03FC, "Elitegroup Computer Systems" }, { 0x03FD, "Xilinx Inc." }, { 0x03FE, "Farallon Comunications" }, { 0x03FF, "Weitek Corporation" }, { 0x0400, "National Semiconductor" }, { 0x0401, "National Registry Inc." }, { 0x0402, "ALi Corporation" }, { 0x0403, "Future Technology Devices International Limited" }, { 0x0404, "NCR Corporation" }, { 0x0405, "inSilicon" }, { 0x0406, "Fujitsu-ICL Computers" }, { 0x0407, "Fujitsu Personal Systems, Inc." }, { 0x0408, "Quanta Computer Inc." }, { 0x0409, "NEC Corporation" }, { 0x040A, "Eastman Kodak Company" }, { 0x040B, "Weltrend Semiconductor" }, { 0x040C, "VTech Computers Ltd" }, { 0x040D, "VIA Technologies, Inc." }, { 0x040E, "MCCI Corporation" }, { 0x040F, "Echo Speech Corporation" }, { 0x0410, "Isis Distributed Systems, Inc." }, { 0x0411, "BUFFALO INC." }, { 0x0412, "Award Software International" }, { 0x0413, "Leadtek Research Inc." }, { 0x0414, "Giga-Byte Technology Co., Ltd." }, { 0x0416, "Nuvoton Technology Corp." }, { 0x0417, "Symbios, Inc." }, { 0x0418, "AST Research" }, { 0x0419, "Samsung Info. Systems America Inc." }, { 0x041A, "Phoenix Technologies Ltd." }, { 0x041B, "d'TV" }, { 0x041D, "S3 Incorporated" }, { 0x041E, "Creative Labs" }, { 0x041F, "LCS Telegraphics" }, { 0x0420, "Chips and Technologies" }, { 0x0421, "Nokia Corporation" }, { 0x0422, "ADI Systems Inc." }, { 0x0423, "CATC" }, { 0x0424, "Microchip-SMSC" }, { 0x0425, "Freescale Semiconductor Hong Kong Limited" }, { 0x0426, "Integrated Device Technology" }, { 0x0427, "Motorola Electronics Taiwan Ltd." }, { 0x0428, "Advanced Gravis Computer Ltd." }, { 0x0429, "Cirrus Logic Inc." }, { 0x042A, "Ericsson Austrian, AG" }, { 0x042C, "Innovative Semiconductors, Inc." }, { 0x042D, "Micronics" }, { 0x042E, "Acer, Inc.(2)" }, { 0x042F, "Molex Inc." }, { 0x0430, "Fujitsu Component Limited" }, { 0x0431, "ITAC Systems, Inc." }, { 0x0432, "Unisys Corp." }, { 0x0433, "Alps Electric Inc." }, { 0x0434, "Samsung Info. Systems America Inc.(2)" }, { 0x0435, "Hyundai Electronics America" }, { 0x0436, "Taugagreining HF" }, { 0x0437, "Framatome Connectors USA" }, { 0x0438, "Advanced Micro Devices" }, { 0x0439, "Voice Technologies Group" }, { 0x043C, "Lucid Designs" }, { 0x043D, "Lexmark International Inc." }, { 0x043E, "LG Electronics USA Inc." }, { 0x043F, "RadiSys Corporation" }, { 0x0440, "EIZO NANAO CORPORATION" }, { 0x0441, "Winbond Systems Lab." }, { 0x0442, "Cygnion Corp." }, { 0x0443, "Gateway 2000" }, { 0x0445, "Agere Systems" }, { 0x0446, "NMB Technologies Corporation" }, { 0x0447, "Momentum Microsystems" }, { 0x0449, "Eldim" }, { 0x044A, "Shamrock Technology Co., Ltd." }, { 0x044B, "WSI" }, { 0x044C, "CCL/ITRI" }, { 0x044D, "Siemens Nixdorf AG" }, { 0x044E, "Alps Electric Co., Ltd." }, { 0x044F, "ThrustMaster, Inc." }, { 0x0450, "DFI Inc." }, { 0x0451, "Texas Instruments" }, { 0x0452, "Mitsubishi Electric & Electronics US, Inc." }, { 0x0453, "CMD Technology" }, { 0x0454, "Vobis Microcomputer AGO" }, { 0x0455, "Telematics International, Inc." }, { 0x0456, "Analog Devices, Inc." }, { 0x0457, "Silicon Integrated Systems Corp." }, { 0x0458, "KYE Systems Corp." }, { 0x0459, "Adobe Systems, Inc." }, { 0x045A, "SONICblue Incorporated" }, { 0x045B, "Renesas Electronics Corp." }, { 0x045D, "Nortel Networks" }, { 0x045E, "Microsoft Corporation" }, { 0x0460, "Ace Cad Enterprise Co., Ltd." }, { 0x0461, "Primax Electronics" }, { 0x0463, "EATON" }, { 0x0464, "AMP/Tycoelectronics" }, { 0x0465, "Pacific Micro Computing" }, { 0x0467, "AT&T Paradyne" }, { 0x0468, "Wieson Technologies Co., Ltd." }, { 0x046A, "CHERRY" }, { 0x046B, "American Megatrends" }, { 0x046C, "Toshiba Corporation, Digital Media Network Company" }, { 0x046D, "Logitech Inc." }, { 0x046E, "Behavior Tech Computer Corporation" }, { 0x046F, "Crystal Semiconductor" }, { 0x0471, "Philips Consumer Lifestyle BV" }, { 0x0472, "Oracle" }, { 0x0473, "Sanyo Information Business Co., Ltd." }, { 0x0474, "Sanyo Electric Co. Ltd." }, { 0x0475, "TECO Electric & Machinery Co., Ltd." }, { 0x0476, "AESP" }, { 0x0477, "Seagate Technology" }, { 0x0478, "Connectix Corp." }, { 0x0479, "Advanced Peripheral Laboratories" }, { 0x047A, "Semtech Corporation" }, { 0x047B, "Silitek Corp." }, { 0x047D, "Kensington" }, { 0x047E, "Avago Technologies Inc." }, { 0x047F, "Plantronics, Inc." }, { 0x0480, "Toshiba America Info. Systems, Inc." }, { 0x0481, "Zenith Data Systems" }, { 0x0482, "Kyocera Corporation" }, { 0x0483, "STMicroelectronics" }, { 0x0484, "Specialix" }, { 0x0485, "Nokia Monitors" }, { 0x0486, "ASUS Computers Inc." }, { 0x0487, "Stewart Connector" }, { 0x0488, "Cirque Corporation" }, { 0x0489, "Foxconn - Hon Hai" }, { 0x048A, "S-MOS Systems, Inc." }, { 0x048C, "Alps Electric Ireland Ltd." }, { 0x048D, "ITE Tech Inc." }, { 0x048F, "Eicon Tech." }, { 0x0490, "United Microelectronic Corporation (UMC)" }, { 0x0491, "Capetronic Kaohsiung Corp." }, { 0x0492, "Samsung Semiconductor, Inc." }, { 0x0493, "MAG Technology Co., Ltd." }, { 0x0495, "ESS Technology, Inc." }, { 0x0496, "Micron Electronics" }, { 0x0497, "Smile International, Inc." }, { 0x0498, "Capetronic (Kaohsiung) Corp." }, { 0x0499, "Yamaha Corporation" }, { 0x049A, "Gandalf Technologies Ltd." }, { 0x049B, "Curtis Computer Products" }, { 0x049C, "Acer Advanced Labs, Inc." }, { 0x049D, "VLSI Technology, Inc." }, { 0x049F, "Compaq Computer Corporation" }, { 0x04A0, "Digital Equipment Corp." }, { 0x04A1, "SystemSoft Corporation" }, { 0x04A2, "FirePower Systems" }, { 0x04A3, "Trident Microsystems Inc." }, { 0x04A4, "Hitachi, Ltd." }, { 0x04A5, "BenQ Corporation" }, { 0x04A6, "Nokia Display Products" }, { 0x04A7, "Visioneer" }, { 0x04A8, "Multivideo Labs, Inc." }, { 0x04A9, "Canon Inc." }, { 0x04AA, "Daewoo Teletech Co., Ltd." }, { 0x04AB, "Chromatic Research" }, { 0x04AC, "Micro Audiometrics Corp." }, { 0x04AD, "Dooin Electronics" }, { 0x04AE, "Brooktree Corporation" }, { 0x04AF, "Winnov L.P." }, { 0x04B0, "Nikon Corporation" }, { 0x04B1, "Pan International" }, { 0x04B3, "IBM Corporation" }, { 0x04B4, "Cypress Semiconductor" }, { 0x04B5, "ROHM Co., Ltd." }, { 0x04B6, "Hint Corporation" }, { 0x04B7, "Compal Electronics, Inc." }, { 0x04B8, "Seiko Epson Corp." }, { 0x04B9, "SafeNet, Inc." }, { 0x04BA, "Toucan Systems Limited" }, { 0x04BB, "I-O Data Device, Inc." }, { 0x04BC, "Digital Systems Associates" }, { 0x04BD, "Toshiba Electronics Taiwan Corp." }, { 0x04BE, "Telia Research AB" }, { 0x04BF, "TDK Corporation" }, { 0x04C2, "Methode Electronics Far East Pte Ltd." }, { 0x04C3, "Maxi Switch, Inc." }, { 0x04C4, "Lockheed Martin Energy Research" }, { 0x04C5, "Fujitsu Ltd." }, { 0x04C6, "Toshiba America Electronic Components" }, { 0x04C7, "Micro Macro Technologies" }, { 0x04C8, "Konica Corporation" }, { 0x04CA, "Lite-On Technology Corp." }, { 0x04CB, "FUJIFILM Corporation" }, { 0x04CC, "ST-Ericsson" }, { 0x04CD, "Tatung Company of America, Inc." }, { 0x04CE, "ScanLogic Corporation" }, { 0x04CF, "Myson Century, Inc." }, { 0x04D0, "Digi International" }, { 0x04D1, "ITT Cannon" }, { 0x04D2, "Altec Lansing Technologies, Inc." }, { 0x04D3, "VidUS, Inc." }, { 0x04D4, "LSI Logic Inc." }, { 0x04D5, "Forte Technologies, Inc." }, { 0x04D6, "Mentor Graphics" }, { 0x04D7, "Oki Semiconductor" }, { 0x04D8, "Microchip Technology Inc." }, { 0x04D9, "Holtek Semiconductor, Inc." }, { 0x04DA, "Panasonic Corporation" }, { 0x04DB, "Hypertec Ltd." }, { 0x04DC, "Huan Hsin Holdings Ltd." }, { 0x04DD, "Sharp Corporation" }, { 0x04DE, "MindShare, Inc." }, { 0x04DF, "ePadLink" }, { 0x04E1, "Iiyama Corporation" }, { 0x04E2, "Exar Corporation" }, { 0x04E3, "Zilog" }, { 0x04E4, "ACC Microelectronics" }, { 0x04E5, "Promise Technology" }, { 0x04E6, "Identiv, Inc." }, { 0x04E7, "Elo TouchSystems" }, { 0x04E8, "Samsung Electronics Co., Ltd." }, { 0x04E9, "PC-Tel, Inc." }, { 0x04EA, "Sipex Corporation" }, { 0x04EB, "Northstar Systems Corp." }, { 0x04EC, "Tokyo Electron Device Limited" }, { 0x04ED, "Annabooks" }, { 0x04EF, "Pacific Electronic International, Inc." }, { 0x04F0, "Daewoo Electronics Co., Ltd." }, { 0x04F1, "Victor Company of Japan, Limited" }, { 0x04F2, "Chicony Electronics Co., Ltd." }, { 0x04F3, "ELAN Microelectronics Corportation" }, { 0x04F4, "Harting Elektronik Inc." }, { 0x04F5, "Fujitsu-ICL Systems, Inc." }, { 0x04F6, "Norand Corporation" }, { 0x04F7, "Newnex Technology Corp." }, { 0x04F8, "FuturePlus Systems" }, { 0x04F9, "Brother Industries, Ltd." }, { 0x04FA, "Dallas Semiconductor" }, { 0x04FB, "Biostar Microtech Int'l Corp." }, { 0x04FC, "SUNPLUS TECHNOLOGY CO., LTD." }, { 0x04FD, "Soliton Systems K.K." }, { 0x04FE, "PFU Limited" }, { 0x04FF, "E-CMOS Corp." }, { 0x0500, "Siam United Hi-Tech" }, { 0x0501, "Fujikura/DDK" }, { 0x0502, "Acer, Inc." }, { 0x0503, "Hitachi America Ltd." }, { 0x0504, "Hayes Microcomputer Products" }, { 0x0505, "Digital Home Corporation" }, { 0x0506, "3Com Corporation" }, { 0x0507, "Hosiden Corporation" }, { 0x0508, "Clarion Co., Ltd." }, { 0x0509, "Aztech Systems Ltd" }, { 0x050A, "Cinch Connectors" }, { 0x050B, "Cable System International" }, { 0x050C, "InnoMedia, Inc." }, { 0x050D, "Belkin International, Inc." }, { 0x050E, "Neon Technology, Inc." }, { 0x050F, "KC Technology Inc." }, { 0x0510, "Sejin Electron Inc." }, { 0x0511, "N*ABLE Technologies, Inc (Data Book)" }, { 0x0512, "Hualon Microelectronics Corp." }, { 0x0513, "digital-X, Inc." }, { 0x0514, "FCI Electronics" }, { 0x0515, "ACTC" }, { 0x0516, "Longwell Electronics/Longwell Company" }, { 0x0517, "Butterfly Communications" }, { 0x0518, "EzKEY Corp." }, { 0x0519, "Star Micronics Co., LTD" }, { 0x051A, "WYSE Technology" }, { 0x051C, "Shuttle Inc." }, { 0x051D, "American Power Conversion" }, { 0x051E, "Scientific Atlanta, Inc." }, { 0x051F, "IO Systems Inc." }, { 0x0520, "Taiwan Semiconductor Manufacturing Co." }, { 0x0521, "Airborn Connectors" }, { 0x0522, "ACON, Advanced-Connectek, Inc." }, { 0x0523, "ATEN GMBH" }, { 0x0524, "Sola Electronics" }, { 0x0525, "PLX Technology, Inc." }, { 0x0526, "Temic MHS S.A." }, { 0x0527, "ALTRA" }, { 0x0528, "ATI Technologies, Inc." }, { 0x0529, "SafeNet Data Security (Israel) Ltd." }, { 0x052A, "Crescent Heart Software" }, { 0x052B, "Tekom Technologies, Inc" }, { 0x052C, "Canon Development Americas" }, { 0x052D, "Avid Electronics Corp." }, { 0x052E, "Standard Microsystems Corp. (1)" }, { 0x052F, "Unicore Software, Inc." }, { 0x0530, "American Microsystems Inc." }, { 0x0531, "Wacom Technology Corp." }, { 0x0532, "Systech Corporation" }, { 0x0533, "Alcatel Mobile Phones" }, { 0x0534, "Motorola" }, { 0x0535, "LIH TZU Electric Co., Ltd." }, { 0x0536, "Hand Held Products (Honeywell International Inc.)" }, { 0x0537, "Inventec Corporation" }, { 0x0538, "The SCO Group" }, { 0x0539, "Shyh Shiun Terminals Co. LTD" }, { 0x053A, "Preh KeyTec GmbH" }, { 0x053B, "Global Village Communication" }, { 0x053C, "Institut of Microelectronic & Mechatronic Systems" }, { 0x053D, "Silicon Architect" }, { 0x053E, "Mobility Electronics" }, { 0x053F, "Synopsys, Inc." }, { 0x0540, "UniAccess AB" }, { 0x0541, "Sirf Technology, Inc" }, { 0x0542, "MICOM Communications Corp." }, { 0x0543, "ViewSonic Corporation" }, { 0x0544, "Cristie Electronics Ltd." }, { 0x0545, "Veo" }, { 0x0546, "Polaroid Corporation" }, { 0x0547, "Anchor Chips Inc." }, { 0x0548, "Tyan Computer Corp." }, { 0x0549, "Pixera Corporation" }, { 0x054A, "Fujitsu Microelectronics, Inc." }, { 0x054B, "New Media Corporation" }, { 0x054C, "Sony Corporation" }, { 0x054D, "Try Corporation" }, { 0x054E, "Proside Corporation" }, { 0x054F, "WYSE Technology Taiwan" }, { 0x0550, "Fuji Xerox Co., Ltd." }, { 0x0551, "CompuTrend Systems, Inc." }, { 0x0552, "Philips Monitors" }, { 0x0553, "STMicroelectronics Imaging Division" }, { 0x0554, "Dictaphone Corp." }, { 0x0555, "ANAM S&T Co., Ltd." }, { 0x0556, "Asahi Kasei Microdevices Corporation" }, { 0x0557, "ATEN International Co. Ltd." }, { 0x0558, "Truevision, Inc." }, { 0x0559, "Cadence Design Systems, Inc." }, { 0x055A, "Kenwood USA" }, { 0x055B, "KnowledgeTek, Inc." }, { 0x055C, "Proton Electronic Ind." }, { 0x055D, "Samsung Electro-Mechanics Co." }, { 0x055E, "Optoma Corporation" }, { 0x055F, "Mustek Systems Inc." }, { 0x0560, "Interface Corporation" }, { 0x0561, "Oasis Design, Inc." }, { 0x0562, "Telex Communications Inc." }, { 0x0563, "Immersion Corporation" }, { 0x0564, "Kodak Digital Product Center, Japan Ltd." }, { 0x0565, "Peracom Networks, Inc." }, { 0x0566, "Monterey International Corp." }, { 0x0567, "Xyratex" }, { 0x0568, "Quartz Ingenierie" }, { 0x0569, "SegaSoft" }, { 0x056A, "WACOM Co., Ltd." }, { 0x056B, "Decicon Incorporated" }, { 0x056C, "Belkin Research & Development" }, { 0x056D, "EIZO Corporation" }, { 0x056E, "Elecom Co., Ltd." }, { 0x056F, "Korea Data Systems Co., Ltd." }, { 0x0570, "Epson America" }, { 0x0571, "XLR8, Inc." }, { 0x0572, "Conexant Systems, Inc." }, { 0x0573, "Zoran Corporation" }, { 0x0574, "City University of Hong Kong" }, { 0x0575, "Philips Creative Display Solutions" }, { 0x0576, "BAFO/Quality Computer Accessories" }, { 0x0577, "ELSA" }, { 0x0578, "Intrinsix Corp." }, { 0x0579, "GVC Corporation" }, { 0x057A, "Samsung Electronics America" }, { 0x057B, "Y-E Data, Inc." }, { 0x057C, "AVM GmbH" }, { 0x057D, "Shark Multimedia Inc." }, { 0x057E, "Nintendo Co., Ltd." }, { 0x057F, "QuickShot Limited" }, { 0x0580, "Denron Inc." }, { 0x0581, "Racal Data Group" }, { 0x0582, "Roland Corporation" }, { 0x0583, "Padix Co., Ltd." }, { 0x0584, "RATOC Systems, Inc." }, { 0x0585, "FlashPoint Technology, Inc." }, { 0x0586, "ZyXEL Communications Corp" }, { 0x0587, "Matsushita Kotobuki Electronics Industries America" }, { 0x0588, "Sapien Design" }, { 0x0589, "Victron" }, { 0x058A, "Nohau Corporation" }, { 0x058B, "Infineon Technologies" }, { 0x058C, "In Focus Systems" }, { 0x058D, "Micrel Semiconductor" }, { 0x058E, "Tripath Technology Inc." }, { 0x058F, "Alcor Micro, Corp." }, { 0x0590, "OMRON Corporation" }, { 0x0591, "Questra Consulting" }, { 0x0592, "Powerware Corporation" }, { 0x0593, "Incite" }, { 0x0594, "Princeton Graphic Systems" }, { 0x0595, "Zoran Microelectronics Ltd." }, { 0x0596, "3M Touch Systems" }, { 0x0597, "Trisignal Communications" }, { 0x0598, "Niigata Canotec Co., Inc." }, { 0x0599, "Brilliance Semiconductor Inc." }, { 0x059A, "Spectrum Signal Processing Inc." }, { 0x059B, "Iomega Corporation" }, { 0x059C, "A-Trend Technology Co., Ltd." }, { 0x059D, "Advanced Input Devices" }, { 0x059E, "Intelligent Instrumentation" }, { 0x059F, "LaCie" }, { 0x05A0, "Vetronix Corporation" }, { 0x05A1, "UKC Electronics Corporation" }, { 0x05A2, "Fuji Film Microdevices Co. Ltd." }, { 0x05A3, "TransDimension-NH LLC" }, { 0x05A4, "Ortek Technology, Inc." }, { 0x05A5, "Sampo Technology Corp." }, { 0x05A6, "Cisco Systems, Inc." }, { 0x05A7, "Bose Corporation" }, { 0x05A8, "Spacetec IMC Corporation" }, { 0x05A9, "OmniVision Technologies, Inc." }, { 0x05AA, "Utilux South China Ltd." }, { 0x05AB, "In-System Design" }, { 0x05AC, "Apple" }, { 0x05AD, "Y.C. Cable U.S.A., Inc" }, { 0x05AE, "Synopsys, Inc.(2)" }, { 0x05AF, "Sunrex Technology Corp." }, { 0x05B0, "Fountain Technologies, Inc" }, { 0x05B1, "First International Computer, Inc." }, { 0x05B2, "Focus Electronics" }, { 0x05B4, "HYUNDAI Electronics Industries Co., Ltd." }, { 0x05B5, "Dialogic Corp" }, { 0x05B6, "Proxima Corporation" }, { 0x05B7, "Medianix Semiconductor, Inc." }, { 0x05B8, "Sysgration" }, { 0x05B9, "Philips Research Laboratories" }, { 0x05BA, "DigitalPersona, Inc." }, { 0x05BB, "Grey Cell Systems" }, { 0x05BD, "RAFI GmbH & Co. KG" }, { 0x05BE, "Tyco Electronics Corp., a TE Connectivity Ltd. company" }, { 0x05BF, "S & S Research" }, { 0x05C0, "Keil Software" }, { 0x05C1, "MegaChips Corporation" }, { 0x05C2, "Media Phonics (Suisse) S.A." }, { 0x05C3, "VME Microsystems" }, { 0x05C5, "Digi International Inc." }, { 0x05C6, "Qualcomm, Inc" }, { 0x05C7, "Qtronix Corp" }, { 0x05C8, "Foxlink/Cheng Uei Precision Industry Co., Ltd" }, { 0x05C9, "Semtech" }, { 0x05CA, "Ricoh Company Ltd." }, { 0x05CB, "PowerVision Technologies Inc." }, { 0x05CC, "Neue ELSA GmbH" }, { 0x05CD, "Silicom LTD." }, { 0x05CE, "sci-worx GmbH" }, { 0x05CF, "Sung Forn Co. LTD." }, { 0x05D0, "GE Medical Systems Lunar" }, { 0x05D1, "Brainboxes Limited" }, { 0x05D2, "Wave Systems Corp." }, { 0x05D3, "Tohoku Ricoh Co., Ltd." }, { 0x05D5, "Super Gate Technology Co., LTD" }, { 0x05D6, "Philips Semiconductors, CICT" }, { 0x05D7, "Thomas & Betts" }, { 0x05D8, "Ultima Electronics Corp." }, { 0x05D9, "TPG IPB, Inc." }, { 0x05DA, "Microtek International Inc." }, { 0x05DB, "Sun Corporation" }, { 0x05DC, "Lexar Media, Inc." }, { 0x05DD, "Delta Electronics Inc." }, { 0x05DE, "Crucial Technology" }, { 0x05DF, "Silicon Vision Inc." }, { 0x05E0, "Symbol Technologies" }, { 0x05E1, "Syntek Semiconductor Co., Ltd." }, { 0x05E2, "ElecVision Inc." }, { 0x05E3, "Genesys Logic, Inc." }, { 0x05E4, "Red Wing Corporation" }, { 0x05E5, "Fuji Electric Co., Ltd." }, { 0x05E6, "Keithley Instruments" }, { 0x05E7, "EIZO Nanao Technologies Inc." }, { 0x05E8, "ICC, Inc." }, { 0x05E9, "Kawasaki Microelectronics America, Inc." }, { 0x05EA, "Evergreen Systems International" }, { 0x05EB, "FFC Limited" }, { 0x05EC, "COM21, Inc." }, { 0x05EE, "Cytechinfo Inc." }, { 0x05EF, "Anko Electronic Co., Ltd." }, { 0x05F0, "Canopus Co., Ltd." }, { 0x05F2, "Dexin Corporation, Ltd." }, { 0x05F3, "PI Engineering, Inc." }, { 0x05F4, "Davis AS" }, { 0x05F5, "Unixtar Technology Inc." }, { 0x05F6, "Envision Peripherals, Inc." }, { 0x05F7, "Silicon Portals Inc." }, { 0x05F8, "Phase Metrics" }, { 0x05F9, "Datalogic ADC" }, { 0x05FA, "Siemens Telecommunications Systems Limited" }, { 0x05FC, "Harman Multimedia" }, { 0x05FD, "STD Manufacturing Ltd." }, { 0x05FE, "CHIC TECHNOLOGY CORP" }, { 0x05FF, "LeCroy Corporation" }, { 0x0600, "Barco" }, { 0x0601, "Jazz Hipster Corporation" }, { 0x0602, "Vista Imaging Inc." }, { 0x0603, "Novatek Microelectronics Corp." }, { 0x0604, "Jean Co, Ltd." }, { 0x0605, "Anchor C&C Co., Ltd." }, { 0x0606, "Royal Information Electronics Co., Ltd." }, { 0x0607, "Bridge Information Co., Ltd." }, { 0x0608, "Genrad Ads" }, { 0x0609, "SMK Manufacturing Inc." }, { 0x060A, "Worth Data, Inc." }, { 0x060B, "Solid Year Co., LTD." }, { 0x060C, "EEH Datalink Gmbh" }, { 0x060D, "Auctor Corporation" }, { 0x060E, "Transmonde Technologies, Inc." }, { 0x060F, "Joinsoon Electronics Mfg. Co., Ltd." }, { 0x0610, "Costar Electronics Inc." }, { 0x0611, "JVCKENWOOD Nagaoka Corp." }, { 0x0612, "TV Interactive Corp." }, { 0x0613, "TransAct Technologies Incorporated" }, { 0x0614, "Bio-Rad Laboratories" }, { 0x0615, "Quabbin Wire & Cable Co., INC." }, { 0x0616, "Future Techno Designs PVT. LTD." }, { 0x0617, "Swiss Federal Institute of Technology" }, { 0x0618, "Chia Shin Technology Corp." }, { 0x0619, "Seiko Instruments Inc." }, { 0x061A, "Veridicom2" }, { 0x061B, "Promptus Communications, Inc." }, { 0x061C, "Act Labs, Ltd." }, { 0x061D, "Quatech, Inc." }, { 0x061E, "Nissei Electric Co." }, { 0x0620, "Alaris, Inc." }, { 0x0621, "ODU-Steckverbindungssysteme GmbH & Co. KG" }, { 0x0622, "Iotech, Inc." }, { 0x0623, "Littelfuse, Inc." }, { 0x0624, "Avocent Corporation" }, { 0x0625, "TiMedia Technology Co., Ltd." }, { 0x0626, "Nippon Systems Development Co., Ltd." }, { 0x0627, "Adomax Technology Co., Ltd." }, { 0x0628, "Tasking Software Inc." }, { 0x0629, "Zida Technologies Limited" }, { 0x062A, "MosArt Semiconductor Corp." }, { 0x062B, "Greatlink Electronics Taiwan Ltd." }, { 0x062C, "Institute for Information Industry" }, { 0x062D, "Taiwan Tai-Hao Enterprises Co. Ltd." }, { 0x062E, "JPC-MAIN SUPER Inc." }, { 0x062F, "Sin Sheng Terminal & Machine Inc." }, { 0x0630, "ORL" }, { 0x0631, "JUJO Electronics Corporation" }, { 0x0632, "Marquette Medical Systems, Inc." }, { 0x0633, "Cyrix Corporation" }, { 0x0634, "Micron Technology, Inc." }, { 0x0635, "Methode Electronics, Inc." }, { 0x0636, "Sierra Imaging, Inc." }, { 0x0637, "Gunz Limited" }, { 0x0638, "Avision, Inc." }, { 0x0639, "Chrontel, Inc." }, { 0x063A, "Techwin Corporation" }, { 0x063B, "Taugagreining HF (2)" }, { 0x063C, "Yamaichi Electronics Co., Ltd. (Sakura)" }, { 0x063D, "Fong Kai Industrial Co., Ltd." }, { 0x063E, "RealMedia Technology, Inc." }, { 0x063F, "New Technology Cable Ltd." }, { 0x0640, "Hitex Development Tools" }, { 0x0641, "Woods Industries, Inc." }, { 0x0642, "VIA Medical Corporation" }, { 0x0643, "NOVATUS, Inc." }, { 0x0644, "TEAC Corporation" }, { 0x0645, "Ethentica Inc." }, { 0x0647, "Acton Research Corporation" }, { 0x0649, "Weli Science Co., Ltd" }, { 0x064A, "Technical Corp." }, { 0x064B, "Analog Devices, Inc. Development Tools" }, { 0x064C, "Ji-Haw Industrial Co., Ltd" }, { 0x064D, "TriTech Microelectronics Ltd" }, { 0x064E, "Suyin Corporation" }, { 0x064F, "WIBU-Systems AG" }, { 0x0650, "Dynapro Systems" }, { 0x0651, "Likom Technology Sdn. Bhd." }, { 0x0652, "Stargate Solutions, Inc." }, { 0x0653, "CNF Inc." }, { 0x0654, "Granite Microsystems, Inc." }, { 0x0655, "Space Shuttle Hi-Tech Co.,Ltd." }, { 0x0656, "Glory Mark Electronic Ltd." }, { 0x0657, "Tekcon Electronics Corp." }, { 0x0658, "Sigma Designs, Inc." }, { 0x0659, "AETHRA" }, { 0x065A, "Optoelectronics Co., Ltd." }, { 0x065B, "Tracewell Systems" }, { 0x065C, "Brentwood Medical Technology Corp." }, { 0x065D, "ATTO Technology, Inc." }, { 0x065E, "Silicon Graphics" }, { 0x065F, "Good Way Technology Co., Ltd. & GWC technology Inc" }, { 0x0660, "TSAY-E (BVI) International Inc." }, { 0x0661, "Hamamatsu Photonics K.K." }, { 0x0662, "Kansai Electric Co., Ltd." }, { 0x0663, "Topmax Electronic Co., Ltd." }, { 0x0664, "ET&T" }, { 0x0665, "WayTech Development, Inc." }, { 0x0667, "Antona Corporation" }, { 0x0668, "WordWand" }, { 0x0669, "Oce' Printing Systems GmbH" }, { 0x066A, "Total Technologies, Ltd." }, { 0x066B, "SCM Microsystems Japan, Inc." }, { 0x066C, "ASK ASA" }, { 0x066D, "Entrega Technologies Inc." }, { 0x066E, "Acer Semiconductor America, Inc." }, { 0x066F, "Freescale Semiconductor, Inc. - Sigmatel" }, { 0x0670, "Sequel Imaging, Inc." }, { 0x0671, "Keisoku Giken Co., Ltd." }, { 0x0672, "Labtec Inc." }, { 0x0673, "HCL Peripherals Limited" }, { 0x0674, "Key Mouse Electronic Enterprise Co., Ltd." }, { 0x0675, "DrayTek Corp." }, { 0x0676, "Teles AG" }, { 0x0677, "Aiwa Co., Ltd." }, { 0x0678, "ACARD Technology Corp." }, { 0x0679, "WaterGate Software, Inc." }, { 0x067A, "ADS ANKER GmbH" }, { 0x067B, "Prolific Technology, Inc." }, { 0x067C, "Efficient Networks, Inc." }, { 0x067D, "Hohner Corp." }, { 0x067E, "Intermec Technologies (S) Pte Ltd." }, { 0x067F, "Virata Ltd." }, { 0x0680, "Realtek Semiconductor Corp., CPP Div." }, { 0x0681, "Siemens Information and Communication Products" }, { 0x0683, "Dataq Instruments, Inc." }, { 0x0684, "Cytec Corporation" }, { 0x0685, "ISDN*tek" }, { 0x0686, "KONICA MINOLTA TECHNOLOGY CENTER, INC." }, { 0x0687, "Sycard Technology" }, { 0x0688, "Microprocess Ingenierie" }, { 0x0689, "Elesys Inc." }, { 0x068A, "Pertech Inc." }, { 0x068B, "Potrans International, Inc." }, { 0x068C, "Tokin Corporation, Card Media Systems Department" }, { 0x068D, "Medical Measurement Systems B.V." }, { 0x068E, "CH Products" }, { 0x068F, "Nihon Kohden Corporation" }, { 0x0690, "Golden Bridge Electech Inc." }, { 0x0691, "Denter System Co., Ltd." }, { 0x0692, "Klippel GmbH" }, { 0x0693, "Hagiwara Solutions Co., Ltd." }, { 0x0694, "The LEGO Company" }, { 0x0695, "ODU-USA, Inc." }, { 0x0696, "Carroll Touch" }, { 0x0697, "Oxford Instruments (Medical Systems Division)" }, { 0x0698, "Chuntex (CTX)" }, { 0x0699, "Tektronix, Inc." }, { 0x069A, "Askey Computer Corporation" }, { 0x069B, "Technicolor SA" }, { 0x069C, "HST High Soft Tech GmbH" }, { 0x069D, "Hughes Network Systems (HNS)" }, { 0x069E, "Welcat Inc." }, { 0x069F, "Tron b.v." }, { 0x06A0, "USB Systems Design" }, { 0x06A1, "Alexon Co., Ltd." }, { 0x06A2, "Topro Technology Inc." }, { 0x06A3, "Logitech Europe S.A." }, { 0x06A4, "Xiamen Doowell Electron Co., Ltd." }, { 0x06A5, "Divio" }, { 0x06A7, "MicroStore, Inc." }, { 0x06A8, "Topaz Systems, Inc." }, { 0x06A9, "Westell" }, { 0x06AA, "Sysgration Ltd." }, { 0x06AB, "Johnathon Freeman Technologies" }, { 0x06AC, "Fujitsu Laboratories of America, Inc." }, { 0x06AD, "Greatland Electronics Taiwan Ltd." }, { 0x06AE, "Eurofins Digital Testing Belgium" }, { 0x06AF, "Harting, Inc. of North America" }, { 0x06B0, "Alva B.V." }, { 0x06B1, "Signtech USA, Ltd." }, { 0x06B2, "N*ABLE Technologies, Inc." }, { 0x06B3, "Galil Motion Control" }, { 0x06B4, "Citron GmbH" }, { 0x06B5, "Stanford Research Systems" }, { 0x06B6, "Leda Media Products" }, { 0x06B8, "Pixela Corporation" }, { 0x06B9, "Thomson Telecom" }, { 0x06BA, "Smooth Cord & Connector Co., Ltd." }, { 0x06BB, "EDA Inc." }, { 0x06BC, "Oki Data Corporation" }, { 0x06BD, "AGFA-Gevaert NV" }, { 0x06BE, "AME Optimedia Technology Co. Ltd." }, { 0x06BF, "Leoco Corporation" }, { 0x06C0, "AllSpirit Co., Ltd." }, { 0x06C2, "Microlynx Systems Ltd." }, { 0x06C3, "Foss Tecator AB" }, { 0x06C4, "Bizlink Technology, Inc." }, { 0x06C5, "Hagenuk, GmbH" }, { 0x06C6, "Infowave Software Inc." }, { 0x06C7, "Storm Technology Inc." }, { 0x06C8, "SIIG, Inc." }, { 0x06C9, "Taxan (Europe) Ltd." }, { 0x06CA, "Newer Technology, Inc." }, { 0x06CB, "Synaptics Inc." }, { 0x06CC, "Terayon Communication Systems" }, { 0x06CD, "Keyspan" }, { 0x06CE, "Contec Co., Ltd." }, { 0x06CF, "Spheron VR- Bonnet und Steuerwald GdbR" }, { 0x06D0, "LapLink, Inc." }, { 0x06D1, "Daewoo Electronics Co Ltd" }, { 0x06D2, "Pioneer Microsystems" }, { 0x06D3, "Mitsubishi Electric Corporation" }, { 0x06D4, "Cisco Systems(2)" }, { 0x06D5, "Toshiba America Electronic Components, Inc." }, { 0x06D6, "Aashima Technology B.V." }, { 0x06D7, "Network Computing Devices (NCD)" }, { 0x06D8, "Technical Marketing Research, Inc." }, { 0x06D9, "Atmel-TEMIC Semiconductor GmbH" }, { 0x06DA, "Phoenixtec Power Co., Ltd." }, { 0x06DB, "Paradyne" }, { 0x06DC, "Foxlink Image Technology Co., Ltd." }, { 0x06DD, "Impact Technologies" }, { 0x06DE, "Heisei Technology Co., Ltd." }, { 0x06E0, "Multi-Tech Systems, Inc." }, { 0x06E1, "ADS Technologies, Inc." }, { 0x06E2, "Trio Motion Technology Limited" }, { 0x06E4, "Alcatel Microelectronics" }, { 0x06E5, "Lusher Technologies" }, { 0x06E6, "Tiger Jet Network, Inc." }, { 0x06E7, "Universal Electronics Inc." }, { 0x06E8, "Braemar Inc." }, { 0x06E9, "Nippon Electric Industry Co., Ltd." }, { 0x06EA, "Sirius Technologies Limited" }, { 0x06EB, "PC Expert Tech. Co., Ltd." }, { 0x06EC, "ADInstruments Ltd." }, { 0x06ED, "Datastor Technology" }, { 0x06EF, "I.A.C. Geometrische Ingenieurs B.V." }, { 0x06F0, "T.N.C Industrial Co., Ltd." }, { 0x06F1, "Opcode Systems Inc." }, { 0x06F2, "Emine Technology Company" }, { 0x06F3, "Flexion Systems Ltd." }, { 0x06F4, "First Person Gaming" }, { 0x06F5, "Midian Production Distribution" }, { 0x06F6, "Wintrend Technology Co., Ltd." }, { 0x06F7, "Wish Technologies" }, { 0x06F8, "Guillemot Corporation" }, { 0x06F9, "Asyst Electronic" }, { 0x06FA, "HSD S.r.L" }, { 0x06FB, "Hitachi Device Engineering Ltd." }, { 0x06FC, "Motorola Semiconductor Products Sector/US" }, { 0x06FD, "Boston Acoustics" }, { 0x06FE, "Gallant Computer, Inc." }, { 0x06FF, "Mediacom Technologies Pte Ltd." }, { 0x0701, "Supercomal Wire & Cable SDN. BHD." }, { 0x0702, "PixStream Incorporated" }, { 0x0703, "Bvtech Industry Inc." }, { 0x0704, "Vorum Research Corporation" }, { 0x0705, "NKK Corporation" }, { 0x0706, "Ariel Corporation" }, { 0x0707, "SMC Networks, Inc." }, { 0x0708, "Putercom Co., Ltd." }, { 0x0709, "Parthus Technologies" }, { 0x070A, "Oki Electric Industry Co., Ltd." }, { 0x070B, "Hasco Int., Inc." }, { 0x070C, "Titan Electronics Inc." }, { 0x070D, "Comoss Electronic Co., Ltd." }, { 0x070E, "Excel Cell Electronic Co., Ltd." }, { 0x070F, "Oce' -Technologies B.V." }, { 0x0710, "Connect Tech Inc." }, { 0x0711, "Magic Control Technology Corp." }, { 0x0712, "Verity Instruments, Inc." }, { 0x0713, "Interval Research Corp." }, { 0x0714, "New Motion International Co., Ltd" }, { 0x0715, "Liang Tei Co., Ltd." }, { 0x0716, "Oxus Research S.A." }, { 0x0717, "ZNK Corporation" }, { 0x0718, "Imation Corp." }, { 0x0719, "Tremon Enterprises Co., Ltd." }, { 0x071A, "FLIR Explosives" }, { 0x071B, "Domain Technologies, Inc." }, { 0x071C, "Xionics Document Technologies, Inc." }, { 0x071D, "Dialogic Corporation" }, { 0x071E, "Ariston Technologies" }, { 0x071F, "ARS Technologies Ltd." }, { 0x0720, "Keyence Corporation" }, { 0x0721, "HMedia Technology Inc." }, { 0x0722, "Consero" }, { 0x0723, "Centillium Communications Corporation" }, { 0x0724, "Lawson Labs, Inc." }, { 0x0725, "Applied Precision Inc." }, { 0x0726, "Vanguard International Semiconductor-America" }, { 0x0727, "C&H Technologies, Inc." }, { 0x0728, "Avermedia" }, { 0x0729, "CY&S Industrial Co., Ltd." }, { 0x072A, "Luminex Corporation" }, { 0x072B, "Dnova Corporation" }, { 0x072C, "OTSO" }, { 0x072D, "Able Communications, Inc." }, { 0x072E, "Sunix Co., Ltd." }, { 0x072F, "Advanced Card Systems Ltd." }, { 0x0730, "Indus Instruments" }, { 0x0731, "Susteen, Inc." }, { 0x0732, "Goldfull Electronics & Telecommunications Corp." }, { 0x0733, "ViewQuest Technologies, Inc." }, { 0x0734, "LASAT Communications A/S" }, { 0x0735, "Asuscom Network, Inc." }, { 0x0736, "Lorom Industrial Co., Ltd." }, { 0x0737, "Snap-on Diagnostics" }, { 0x0738, "Mad Catz, Inc." }, { 0x0739, "Cue Network Corporation" }, { 0x073A, "Chaplet Systems, Inc." }, { 0x073B, "Suncom Technologies" }, { 0x073C, "Industrial Electronic Engineers, Inc." }, { 0x073D, "Eutronsec Spa" }, { 0x073E, "Sigma Itec, Inc." }, { 0x073F, "Data Electronics (Aust) Pty, Ltd." }, { 0x0740, "Full Enterprise Corp." }, { 0x0741, "Momentum US Inc." }, { 0x0742, "Stollmann EtV GmbH" }, { 0x0743, "Bonig und Kallenback oHG" }, { 0x0744, "GMK Electronic Design GmbH" }, { 0x0745, "Syntech Information Co., Ltd." }, { 0x0746, "ONKYO Corporation" }, { 0x0747, "Labway Corporation" }, { 0x0748, "Strong Man Enterprise Co., Ltd." }, { 0x0749, "EVer Electronics Corp." }, { 0x074A, "Ming Fortune Industry Co., Ltd." }, { 0x074B, "Polestar Tech. Corp." }, { 0x074C, "C-C-C Group PLC" }, { 0x074D, "Micronas GmbH" }, { 0x074E, "Digital Stream Corporation" }, { 0x074F, "Microflip, Inc" }, { 0x0750, "Innovative Integration" }, { 0x0751, "Info Network Systems" }, { 0x0752, "Non-Standard, TSG" }, { 0x0753, "Mocom Softeare GmbH & Co. KG" }, { 0x0754, "SyQuest Technology" }, { 0x0755, "Aureal Semiconductor" }, { 0x0756, "RSI Systems" }, { 0x0757, "Network Technologies, Inc." }, { 0x0758, "Carl Zeiss Jena GmbH" }, { 0x0759, "Cellvision Systems, Inc." }, { 0x075A, "SEL Inc." }, { 0x075B, "Sophisticated Circuits, Inc." }, { 0x075C, "Ulan Co., Ltd." }, { 0x075D, "Microdowell SRL" }, { 0x075E, "ABIT Corporation" }, { 0x075F, "CITEL Technologies, Ltd." }, { 0x0760, "JL Cooper Electronics" }, { 0x0761, "MasTech, Inc." }, { 0x0762, "Coretex Corporation" }, { 0x0763, "M-Audio" }, { 0x0764, "Cyber Power Systems, Inc." }, { 0x0765, "X-Rite Incorporated" }, { 0x0766, "Jess-Link Products Co., Ltd. (JPC)" }, { 0x0767, "Tokheim Corporation" }, { 0x0768, "Camtel Technology Corp." }, { 0x0769, "SURECOM Technology Corp." }, { 0x076A, "Conceptual Systems" }, { 0x076B, "HID Global GmbH" }, { 0x076C, "Partner Tech" }, { 0x076D, "Denso Corporation" }, { 0x076E, "Kuan Tech Enterprise Co., Ltd." }, { 0x076F, "Jhen Vei Electronic Co., Ltd." }, { 0x0770, "Welch Allyn, Inc - Medical Division" }, { 0x0771, "MicroCraft" }, { 0x0772, "TFL LAN, Inc" }, { 0x0773, "Spital Sangyo Co., Ltd." }, { 0x0774, "AmTRAN Technology Co., Ltd." }, { 0x0775, "Longshine Electronics Corp." }, { 0x0776, "Inalways Corporation" }, { 0x0777, "Comda Advanced Technology Corporation" }, { 0x0778, "Volex, Inc." }, { 0x0779, "Fairchild Semiconductor" }, { 0x077A, "NIDEC SANKYO CORPORATION" }, { 0x077B, "Linksys" }, { 0x077C, "Forward Electronics Co., Ltd." }, { 0x077D, "Griffin Technology LLC" }, { 0x077E, "Softing GmbH" }, { 0x077F, "Well Excellent & Most Corp." }, { 0x0780, "ORGA Kartensysteme GmbH" }, { 0x0781, "Western Digital, Sandisk" }, { 0x0782, "Trackerball" }, { 0x0783, "C3PO, S.L." }, { 0x0784, "Pretec Corporation" }, { 0x0785, "Willnet Inc." }, { 0x0786, "Jeil Data Systems Co., Ltd." }, { 0x0787, "Abera System Corp" }, { 0x0788, "3Cam Technology, Inc" }, { 0x0789, "Logitec Corporation" }, { 0x078A, "Tandy Electronics (China) Ltd." }, { 0x078B, "Happ Controls" }, { 0x078C, "CalComp" }, { 0x078D, "Presto Technologies Inc." }, { 0x078E, "San Shih Electrical Enterprise Co. Ltd." }, { 0x078F, "Troy XCD, Inc." }, { 0x0790, "Pro-Image Manufacturing Co., Ltd" }, { 0x0791, "Copartner Technology Corporation" }, { 0x0792, "Axis Communications AB" }, { 0x0793, "Wha Yu Industrial Co., Ltd." }, { 0x0794, "ABL Electronics Corporation" }, { 0x0795, "RealChip Inc." }, { 0x0796, "Certicom Corp." }, { 0x0797, "Grandtech Semiconductor Corporation" }, { 0x0798, "F.J. Tieman BV" }, { 0x0799, "Boulder Creek Engineering" }, { 0x079A, "Aptec Instruments" }, { 0x079B, "Sagem SA" }, { 0x079C, "Sun Communications Inc." }, { 0x079D, "Alfadata Computer Corp." }, { 0x079E, "Tokin Corporation" }, { 0x079F, "VMETRO asa" }, { 0x07A0, "Leiderdorp Instruments" }, { 0x07A1, "Digicom Spa" }, { 0x07A2, "National Technical Systems" }, { 0x07A3, "ONNTO Corp." }, { 0x07A4, "Be Incorporated" }, { 0x07A5, "Tietech Co., Ltd." }, { 0x07A6, "Infineon-ADMtek Co., Ltd." }, { 0x07A7, "Mediatronix BV" }, { 0x07A8, "Home Office PSDB" }, { 0x07A9, "Sandmartin Company Ltd." }, { 0x07AA, "Corega Inc." }, { 0x07AB, "Freecom Technologies" }, { 0x07AC, "Fortress U&T Ltd." }, { 0x07AD, "ECO Chemie" }, { 0x07AE, "C&C Technic Taiwan Co., Ltd." }, { 0x07AF, "Microtech International, Inc." }, { 0x07B0, "Billion Electric Co., Ltd" }, { 0x07B1, "IMP, Inc." }, { 0x07B2, "Motorola BCS" }, { 0x07B3, "Plustek, Inc." }, { 0x07B4, "OLYMPUS CORPORATION" }, { 0x07B5, "Mega World International Ltd." }, { 0x07B6, "Marubun Corp." }, { 0x07B7, "TIME Interconnect Ltd." }, { 0x07B8, "AboCom Systems, Inc." }, { 0x07B9, "Reynolds Medical" }, { 0x07BA, "Accurate Technologies, Inc." }, { 0x07BB, "Intelogis Inc" }, { 0x07BC, "Canon Computer Systems, Inc." }, { 0x07BD, "Webgear Inc." }, { 0x07BE, "Veridicom" }, { 0x07BF, "TestQuest, Inc." }, { 0x07C0, "Code Mercenaries" }, { 0x07C1, "Keisokugiken Corporation" }, { 0x07C2, "Varatouch Technology Inc." }, { 0x07C3, "J-Works, Inc." }, { 0x07C4, "Datafab Systems Inc." }, { 0x07C5, "APG Cash Drawer" }, { 0x07C6, "ShareWave, Inc." }, { 0x07C7, "Powertech Industrial Co., Ltd." }, { 0x07C8, "B.U.G., Inc." }, { 0x07C9, "Allied Telesis Inc" }, { 0x07CA, "AVerMedia Technologies, Inc." }, { 0x07CB, "Kingmax Technology Inc." }, { 0x07CC, "LIWANLI Innovation Co., Ltd" }, { 0x07CD, "Hteck Corp." }, { 0x07CE, "Nidec-Shimpo Corp." }, { 0x07CF, "Casio Computer Co., Ltd." }, { 0x07D0, "Dazzle Multimedia" }, { 0x07D2, "Aptio Products Inc." }, { 0x07D3, "Cyberdata Corp." }, { 0x07D4, "Aloka Co., Ltd." }, { 0x07D5, "Radiant Systems, Inc." }, { 0x07D6, "MENICX International Co., Ltd." }, { 0x07D7, "GCC Technologies, Inc." }, { 0x07D8, "Network Suginami Kokoto" }, { 0x07D9, "Compuapps" }, { 0x07DA, "Arasan Chip Systems Inc." }, { 0x07DB, "Mental Models, Inc." }, { 0x07DC, "OCTAL-Engenharia de Sistemas S.A." }, { 0x07DD, "Hampshire Company, Inc." }, { 0x07DE, "Best Data Products" }, { 0x07DF, "David Electronics Company, Ltd." }, { 0x07E0, "NCP Engineering" }, { 0x07E1, "Acer Netxus Incorporated" }, { 0x07E2, "Elmeg GmbH & Co., Ltd." }, { 0x07E3, "Planex Communications, Inc." }, { 0x07E4, "Movado Enterprise Co., Ltd." }, { 0x07E5, "QPS, Inc." }, { 0x07E6, "Allied Cable Corporation" }, { 0x07E7, "Mirvo Toys, Inc." }, { 0x07E8, "Labsystems" }, { 0x07E9, "Sanyo Technosound Co., Ltd." }, { 0x07EA, "Iwatsu Electric Co., Ltd." }, { 0x07EB, "Double-H Technology Co., Ltd." }, { 0x07EC, "Taiyo Electric Wire & Cable Co., Ltd." }, { 0x07ED, "Precision MicroDynamics, Inc." }, { 0x07EE, "Logware GmbH" }, { 0x07EF, "Suite Technology Systems" }, { 0x07F0, "PS Communications Ltd." }, { 0x07F1, "Picostar, Inc." }, { 0x07F2, "BPT Enterprises" }, { 0x07F3, "L3 Systems" }, { 0x07F4, "Joritel International B.V." }, { 0x07F5, "Amiable Technologies, Inc." }, { 0x07F6, "Circuit Assembly Corp." }, { 0x07F7, "Century Corporation" }, { 0x07F8, "Eskape Labs" }, { 0x07F9, "Dotop Technology, Inc." }, { 0x07FA, "FHLP" }, { 0x07FB, "Digi-Tek, Inc." }, { 0x07FC, "Protec Microsystems" }, { 0x07FD, "Mark of the Unicorn, Inc." }, { 0x07FE, "Net Eyes, Inc." }, { 0x07FF, "Sectra AB" }, { 0x0800, "Kortex International" }, { 0x0801, "Mag-Tek" }, { 0x0802, "Mako Technologies, LLC" }, { 0x0803, "Zoom Telephonics, Inc." }, { 0x0804, "Neuron Corporation" }, { 0x0805, "Iruma Soft Co., Ltd." }, { 0x0806, "Clinton Electronics Corp." }, { 0x0807, "SIIX Corporation" }, { 0x0808, "InfiMed, Inc." }, { 0x0809, "Genicom LP" }, { 0x080A, "Evermuch Technology Co., Ltd." }, { 0x080B, "Cross Match Technologies, Inc." }, { 0x080C, "Datalogic S.p.A." }, { 0x080D, "TECO Image Systems Co., Ltd." }, { 0x080E, "Sound Technology, Inc." }, { 0x080F, "Deschutes Corporation" }, { 0x0810, "Personal Communication Systems, Inc." }, { 0x0811, "Fimet" }, { 0x0812, "E-Tech, Inc." }, { 0x0813, "Mattel, Inc." }, { 0x0814, "EBI Systems, Inc." }, { 0x0815, "Scintrex" }, { 0x0816, "ABB Automation Products AB" }, { 0x0817, "Interzeag Medical Technology" }, { 0x0818, "NTT Electronics Corporation" }, { 0x0819, "Syncrosoft GMBH" }, { 0x081A, "MG Logic Pte Ltd." }, { 0x081B, "Indigita Corporation" }, { 0x081C, "MIPSYS" }, { 0x081D, "VlerZwo Software GbR" }, { 0x081E, "AlphaSmart, Inc." }, { 0x081F, "Totsu Engineering, Inc." }, { 0x0820, "Verax Engineering" }, { 0x0821, "A.T. Cross" }, { 0x0822, "REUDO Corporation" }, { 0x0823, "Tactex Controls, Inc." }, { 0x0824, "M.S.E. GmbH" }, { 0x0825, "GC Protronics" }, { 0x0826, "Data Transit" }, { 0x0827, "BroadLogic, Inc." }, { 0x0828, "Sato Corporation" }, { 0x0829, "DirecTV Broadband" }, { 0x082A, "Object Co., Ltd." }, { 0x082B, "TrophyTrex" }, { 0x082C, "Japan Digital Laboratory Co., Ltd." }, { 0x082D, "Handspring, Inc." }, { 0x082E, "Suni Imaging Microsystems, Inc." }, { 0x082F, "ACACIA" }, { 0x0830, "Palm Inc." }, { 0x0831, "Chong Tsi Su Enterprise Co., Ltd" }, { 0x0832, "Kouwell Electronics Corp." }, { 0x0833, "Sourcenext Corporation" }, { 0x0834, "Ciponic Technology Co., Ltd." }, { 0x0835, "Action Star Technology Co., Ltd." }, { 0x0836, "Evertz Microsystems Ltd." }, { 0x0837, "Renishaw PLC" }, { 0x0838, "Precision MicroControl Corporation" }, { 0x0839, "Samsung Techwin" }, { 0x083A, "Accton Technology Corporation" }, { 0x083B, "Dr. Neuhaus Telekommunikation GmbH" }, { 0x083C, "Jaeger Messtechnik GmbH" }, { 0x083D, "Nakayo Telecommunication, Inc." }, { 0x083E, "2-Tel B.V." }, { 0x083F, "Boca Global, Inc." }, { 0x0840, "Argosy Research Inc." }, { 0x0841, "Rioport.com Inc." }, { 0x0842, "ESA MESSTECHNIK GMBH" }, { 0x0843, "Mcom As" }, { 0x0844, "Welland Industrial Co., Ltd." }, { 0x0845, "EES Technik fur Musik" }, { 0x0846, "NETGEAR, Inc." }, { 0x0847, "Interack Communications Inc." }, { 0x0848, "Accton Technology Co., Ltd." }, { 0x0849, "SC&T International, Inc." }, { 0x084A, "Wipro Limited" }, { 0x084B, "Castlewood Systems" }, { 0x084C, "The Japan Steel Works, Ltd." }, { 0x084D, "Minton Optic Industry Co., Ltd." }, { 0x084E, "KidBoard, Inc. dba KBGear Interactive" }, { 0x084F, "EMPEG Ltd" }, { 0x0850, "FastPoint Technologies, Inc." }, { 0x0851, "Macronix International Co., Ltd." }, { 0x0852, "CSEM" }, { 0x0853, "Topre Corporation" }, { 0x0854, "Active Wire, Inc." }, { 0x0855, "JMBS Developpements" }, { 0x0856, "B&B Electronics" }, { 0x0857, "Gerber Scientific Products, Inc." }, { 0x0858, "Hitachi Maxell Ltd." }, { 0x0859, "Minolta Systems Laboratory, Inc." }, { 0x085A, "Xircom" }, { 0x085B, "Kurt Manufacturing" }, { 0x085C, "Color Vision Inc." }, { 0x085D, "Ambient Technologies, Inc." }, { 0x085E, "NaftEL Technologies LTD." }, { 0x085F, "Canberra Industries" }, { 0x0860, "Momentum Data System" }, { 0x0861, "Cambridge Research Systems Ltd." }, { 0x0862, "Teletrol Systems, Inc." }, { 0x0863, "Filanet Corporation" }, { 0x0864, "Roper International Ltd." }, { 0x0865, "MICROLAB" }, { 0x0866, "PEI Electronics, Inc." }, { 0x0867, "Data Translation, Inc." }, { 0x0868, "Electrical Geodesics, Inc." }, { 0x0869, "Visual Interaction" }, { 0x086A, "Emagic Soft-und Hardware Gmbh" }, { 0x086B, "ROHM Co. Ltd." }, { 0x086C, "DeTeWe" }, { 0x086D, "ICE Technology" }, { 0x086E, "System TALKS Inc." }, { 0x086F, "MEC IMEX INC-HPT" }, { 0x0870, "Metricom, Inc." }, { 0x0871, "Merge Technologies Inc." }, { 0x0872, "Broadxent, Inc." }, { 0x0873, "Xpeed Inc." }, { 0x0874, "A-Tec Subsystem, Inc." }, { 0x0875, "Mecel AB" }, { 0x0876, "3M Home Health Systems" }, { 0x0877, "Lew Engineering" }, { 0x0878, "SYSTEC Computer Gmbh" }, { 0x0879, "Comtrol Corporation" }, { 0x087A, "Getemed GmbH" }, { 0x087B, "Cornerstone Peripherals Technology" }, { 0x087C, "ADESSO/Kbtek America Inc." }, { 0x087D, "JATON Corporation" }, { 0x087E, "Fujitsu Computer Products of America" }, { 0x087F, "QualCore Logic Inc" }, { 0x0880, "APT Technologies Inc." }, { 0x0881, "Sistemas Y Redes Telematicas, Sire S.L." }, { 0x0882, "Rightec Research" }, { 0x0883, "Recording Industry Association of America (RIAA)" }, { 0x0884, "USB Systems" }, { 0x0885, "Boca Research, Inc." }, { 0x0887, "Hannstar Electronics Corp." }, { 0x0889, "Current Works, Inc." }, { 0x088A, "TechTools" }, { 0x088B, "MassWorks" }, { 0x088C, "Swecoin AB" }, { 0x088D, "Engineering Spirit" }, { 0x088E, "Pace Anti-Piracy, Inc." }, { 0x088F, "Husky Computers Limited" }, { 0x0890, "Consultronics Ltd." }, { 0x0891, "Drager Medizintechnik Gmbh." }, { 0x0892, "DioGraphy Inc." }, { 0x0893, "Bartec" }, { 0x0894, "TSI Incorporated" }, { 0x0895, "Kanitech A/S" }, { 0x0896, "Starseed Enterprises AG" }, { 0x0897, "Lauterbach GmbH" }, { 0x0898, "3M Canada" }, { 0x0899, "Grieshaber & Co. AG" }, { 0x089A, "Koepruelue Engineering" }, { 0x089B, "Digital-3, LLC." }, { 0x089C, "United Technologies Research Cntr." }, { 0x089D, "Icron Technologies Corporation" }, { 0x089E, "NST Co., Ltd." }, { 0x089F, "Primex Aerospace Co." }, { 0x08A0, "Logic Meca Co., Ltd." }, { 0x08A1, "Studio Zee" }, { 0x08A2, "Millennia Systems, Inc." }, { 0x08A3, "Hyowon Software" }, { 0x08A4, "YTG Smartech Inc." }, { 0x08A5, "e9 Inc." }, { 0x08A6, "Toshiba Tec Corporation" }, { 0x08A7, "General Cybernetics Inc." }, { 0x08A8, "Andrea Electronics" }, { 0x08A9, "CWAV" }, { 0x08AA, "Kernel Productions, Inc." }, { 0x08AB, "Innolab Pte. Ltd." }, { 0x08AC, "Macraigor Systems LLC" }, { 0x08AD, "Toyota Technical Development Corporation (TTDC)" }, { 0x08AE, "Macally (Mace Group, Inc.)" }, { 0x08AF, "Hamilton Co." }, { 0x08B0, "Metrohm Ltd." }, { 0x08B1, "High Technology Laboratory s.r.l" }, { 0x08B2, "BIOTRONIK GmbH & Co." }, { 0x08B3, "Voice It Worldwide, Inc." }, { 0x08B4, "Sorenson Communications" }, { 0x08B5, "Correlator.com" }, { 0x08B6, "Imagek, Inc." }, { 0x08B7, "NATSU Corporation Limited" }, { 0x08B8, "J. Gordon Electronic Design, Inc." }, { 0x08B9, "General Wireless Operations Inc" }, { 0x08BA, "Fujitsu General Limited" }, { 0x08BB, "Texas Instruments Japan" }, { 0x08BC, "Dr. G. Schuhfried GmbH" }, { 0x08BD, "Citizen Watch Co., Ltd." }, { 0x08BE, "Meilenstein GmbH" }, { 0x08BF, "Nova Engineering, Inc." }, { 0x08C0, "Braintronics B.V." }, { 0x08C1, "Timestep Electronics Ltd." }, { 0x08C2, "ArgoCraft Co., Ltd." }, { 0x08C3, "Precise Biometrics" }, { 0x08C4, "Proxim CBU" }, { 0x08C5, "Moreton Bay" }, { 0x08C6, "Scalex Corporation" }, { 0x08C7, "TAI TWUN ENTERPRISE CO., LTD." }, { 0x08C8, "2Wire, Inc" }, { 0x08C9, "Nippon Telegraph and Telephone Corp." }, { 0x08CA, "AIPTEK International Inc." }, { 0x08CB, "Cyber Innovate, Inc." }, { 0x08CC, "ifak system GmbH" }, { 0x08CD, "Jue Hsun Ind. Corp." }, { 0x08CE, "Long Well Electronics Corp." }, { 0x08CF, "Productivity Enhancement Products" }, { 0x08D0, "Tasco Electronics Co., Inc." }, { 0x08D1, "Smartbridges Pte. Ltd." }, { 0x08D2, "Dialog4 System Engineering Gmbh." }, { 0x08D3, "Virtual Ink" }, { 0x08D4, "Siemens PC Systeme GmbH" }, { 0x08D5, "Cambridge Heart, Inc." }, { 0x08D6, "Itautec Philco S.A." }, { 0x08D7, "Opticon, Inc." }, { 0x08D8, "Huntsville Microsystems, Inc." }, { 0x08D9, "Increment P Corporation" }, { 0x08DA, "A W Electronics, Inc." }, { 0x08DB, "IXXAT Automation GmbH" }, { 0x08DC, "Animo Limited" }, { 0x08DD, "Billionton Systems, Inc." }, { 0x08DE, "Touchstone Software" }, { 0x08DF, "Spyrus Inc." }, { 0x08E0, "Geodesic Designs, Inc." }, { 0x08E1, "LSI JAPAN Co., Ltd" }, { 0x08E2, "SafeNet China Ltd." }, { 0x08E3, "OLITEC" }, { 0x08E4, "Pioneer Corporation" }, { 0x08E5, "LITRONIC" }, { 0x08E6, "Gemalto SA" }, { 0x08E7, "PAN-INTERNATIONAL WIRE & CABLE (M) SDN BHD" }, { 0x08E8, "Integrated Memory Logic" }, { 0x08E9, "Extended Systems, Inc." }, { 0x08EA, "Ericsson Inc." }, { 0x08EB, "Asulab SA" }, { 0x08EC, "M-Systems Flash Disk Pioneers" }, { 0x08ED, "Instrumentation Metrics, Inc." }, { 0x08EE, "CCSI/HESSO" }, { 0x08EF, "PixelVision" }, { 0x08F0, "CardScan Inc." }, { 0x08F1, "CTI Electronics Corporation" }, { 0x08F2, "Constance Technology Co., Ltd." }, { 0x08F3, "Wintime Electronics Corp." }, { 0x08F4, "Telia ProSoft AB" }, { 0x08F5, "SYSTEC Co., Ltd." }, { 0x08F6, "Logic 3 International Limited" }, { 0x08F7, "Vernier Software" }, { 0x08F8, "Keen Top International Enterprise Co., Ltd." }, { 0x08F9, "Wipro Technologies" }, { 0x08FA, "CAERE" }, { 0x08FB, "Socket Mobile, Inc." }, { 0x08FC, "Sicon International" }, { 0x08FD, "Digianswer A/S" }, { 0x08FE, "GDSYSTEMS" }, { 0x08FF, "AuthenTec, Inc." }, { 0x0901, "VST Technologies" }, { 0x0902, "iDream Technologies Pte Ltd" }, { 0x0903, "Infolibria" }, { 0x0904, "Frank Audiodata" }, { 0x0905, "ISDG" }, { 0x0906, "FARADAY Technology Corp." }, { 0x0907, "Addison Technology Europe B.V." }, { 0x0908, "Siemens Automation & Drives" }, { 0x0909, "Audio-Technica Corp." }, { 0x090A, "Trumpion Microelectronics Inc" }, { 0x090B, "Neurosmith" }, { 0x090C, "Silicon Motion, Inc. - Taiwan" }, { 0x090D, "MULTIPORT Computer Vertriebs GmbH" }, { 0x090E, "Shining Technology, Inc." }, { 0x090F, "Fujitsu Devices Inc." }, { 0x0910, "Alation Systems, Inc." }, { 0x0911, "Philips Speech Processing" }, { 0x0912, "Voquette, Inc." }, { 0x0913, "Asante' Technologies, Inc." }, { 0x0914, "Bally Gaming, Inc." }, { 0x0915, "GlobespanVirata, Inc." }, { 0x0916, "DH electronics GmbH" }, { 0x0917, "SmartDisk Corporation" }, { 0x0918, "Planet Portal.com" }, { 0x0919, "Sound Vision Inc." }, { 0x091A, "Inter-Cable Systems, Inc." }, { 0x091B, "Raleigh Technology Corporation" }, { 0x091C, "Bormann EDV + Zubehoer GmbH" }, { 0x091D, "A. K. Barns Ltd." }, { 0x091E, "Garmin International" }, { 0x091F, "U-JIN Mesco Co., Ltd." }, { 0x0920, "Echelon Corporation" }, { 0x0921, "GoHubs, inc." }, { 0x0922, "Dymo Corporation" }, { 0x0923, "IC Media Corporation" }, { 0x0924, "Xerox Corporation" }, { 0x0925, "Lakeview Research" }, { 0x0926, "Sound Devices, LLC" }, { 0x0927, "Summus, Ltd." }, { 0x0928, "Oxford Semiconductor Ltd." }, { 0x0929, "American Biometric Company" }, { 0x092A, "Toshiba Information & Industrial Sys. And Services" }, { 0x092B, "Sena Technologies, Inc." }, { 0x092C, "Shanghai Bell Company Limited" }, { 0x092D, "OYO Instruments" }, { 0x092E, "Markpoint AB" }, { 0x092F, "Northern Embedded Science" }, { 0x0930, "Toshiba Corporation" }, { 0x0931, "Harmonic Data Systems Ltd." }, { 0x0932, "Crescentec Corporation" }, { 0x0933, "Quantum Corp." }, { 0x0934, "Spirent Communications" }, { 0x0935, "Accurite Technologies, Inc." }, { 0x0936, "DynamicNakedAudio Inc." }, { 0x0937, "Scania CV AB" }, { 0x0938, "Virtual DSP Corporation" }, { 0x0939, "Lumberg, Inc." }, { 0x093A, "Pixart Imaging, Inc." }, { 0x093B, "Plextor LLC" }, { 0x093C, "Intrepid Control Systems, Inc." }, { 0x093D, "InnoSync, Inc." }, { 0x093E, "J.S.T. Mfg. Co., Ltd." }, { 0x093F, "OLYMPIA Telecom Vertriebs GmbH" }, { 0x0940, "Japan Storage Battery Co., Ltd." }, { 0x0941, "Photobit Corporation" }, { 0x0942, "i2Go.com, LLC" }, { 0x0943, "HCL Technologies Ltd." }, { 0x0944, "KORG, Inc." }, { 0x0945, "PASCO Scientific" }, { 0x0946, "GEMSTAR TECHOLOGY DEVELOPMENT LIMITED" }, { 0x0947, "Videonics, Inc." }, { 0x0948, "Kronauer Music In Digital" }, { 0x0949, "Hitachi Kokusai Electric Inc." }, { 0x094A, "Luckytech Technology Co., Ltd" }, { 0x094B, "Linkup Systems Corporation" }, { 0x094C, "Metanetics Corporation" }, { 0x094D, "Cable Television Laboratories" }, { 0x094E, "Head Acoustics" }, { 0x094F, "Yano Electric Co., Ltd." }, { 0x0950, "TechniSat Sateliltenfernsehprodukte Gmbh" }, { 0x0951, "Kingston Technology Company" }, { 0x0952, "DCOM Enterprise Co., Ltd." }, { 0x0953, "PLG" }, { 0x0954, "RPM Systems Corporation" }, { 0x0955, "NVIDIA" }, { 0x0956, "BSquare Corporation" }, { 0x0957, "Agilent Technologies, Inc." }, { 0x0958, "BioLink Technologies International, Inc." }, { 0x0959, "Cologne Chip AG" }, { 0x095A, "Portsmith" }, { 0x095B, "Medialogic Corporation" }, { 0x095C, "K-Tec Electronics" }, { 0x095D, "Polycom, Inc." }, { 0x095E, "USB Design Labs" }, { 0x095F, "TTO Engineering" }, { 0x0960, "Bcom Electronics, Inc." }, { 0x0961, "Portatec Corporation" }, { 0x0962, "SAMx" }, { 0x0963, "Instrument Solutions" }, { 0x0964, "Bitran Corporation" }, { 0x0965, "PAR Technologies, Inc." }, { 0x0966, "HanGo Electronics Co., Ltd." }, { 0x0967, "Acer NeWeb Corporation" }, { 0x0969, "Magellan Corp." }, { 0x096A, "Koizumi Computer, Inc." }, { 0x096B, "ML Electronics Ltd." }, { 0x096C, "GOPEL electronic GmbH" }, { 0x096D, "PennyLan" }, { 0x096E, "Feitian Technologies Co., Ltd." }, { 0x096F, "Memory Link" }, { 0x0970, "K.S. Vector Co., Ltd." }, { 0x0971, "GretagMacbeth AG" }, { 0x0972, "Musicbird" }, { 0x0973, "Axalto" }, { 0x0974, "Eye Communication Systems, Inc" }, { 0x0975, "OL'E Communications, Inc." }, { 0x0976, "Adirondack Wire & Cable" }, { 0x0977, "Lightsurf Technologies" }, { 0x0978, "Beckhoff Gmbh" }, { 0x0979, "Jeilin Technology Corp., Ltd." }, { 0x097A, "Minds At Work LLC" }, { 0x097B, "Knudsen Engineering Limited" }, { 0x097C, "Marunix Co., Ltd." }, { 0x097D, "Rosun Technologies, Inc." }, { 0x097E, "Biopac Systems Inc." }, { 0x097F, "Barun Electronics Co. Ltd." }, { 0x0980, "Posh Mfg. Ltd." }, { 0x0981, "Oak Technology Ltd." }, { 0x0982, "Covadis S.A." }, { 0x0983, "Nissha Printing Co., Ltd." }, { 0x0984, "Apricorn" }, { 0x0985, "Cab Produkttechnik" }, { 0x0986, "Panasonic Electric Works Co., Ltd." }, { 0x0987, "MicroSpeed Inc" }, { 0x0988, "Teraoka Seiko Co. Ltd" }, { 0x0989, "Digitel Co. LTD" }, { 0x098A, "Neopost" }, { 0x098B, "Kingtel Telecommunication Corp." }, { 0x098C, "Vitana Corporation" }, { 0x098D, "INDesign" }, { 0x098E, "Integrated Intellectual Property Inc." }, { 0x098F, "TEXIO CORPORATION" }, { 0x0990, "General Instrument Corp." }, { 0x0992, "Bandai Co., Ltd." }, { 0x0993, "NuvoMedia, Inc." }, { 0x0994, "Dionex Softron GmbH" }, { 0x0995, "Simple Jet Technology Co., Ltd." }, { 0x0996, "Integrated Telecom Express, Inc." }, { 0x0997, "Xerox Corporation/Non-Networked Products" }, { 0x0998, "Atech Totalsolution Co., Ltd." }, { 0x0999, "Ocean Optics, Inc." }, { 0x099A, "ZIPPY TECHNOLOGY CORP." }, { 0x099B, "HIROTA SEISAKUSHO LTD." }, { 0x099C, "Florida Probe, Inc." }, { 0x099D, "NEC San-ei Instruments, Ltd." }, { 0x099E, "Trimble" }, { 0x099F, "Summa N.V." }, { 0x09A0, "Altec Computersysteme GmbH" }, { 0x09A1, "ELMO COMPANY, LIMITED" }, { 0x09A2, "Telemann Co., Ltd." }, { 0x09A3, "PairGain Technologies" }, { 0x09A4, "Contech Research, Inc." }, { 0x09A5, "VCON Telecommunications" }, { 0x09A6, "Poinchips" }, { 0x09A7, "Data Transmission Network Corp." }, { 0x09A8, "Lin Shiung Enterprise Co., Ltd." }, { 0x09A9, "Smart Card Technologies Co., Ltd." }, { 0x09AA, "Intersil Corporation" }, { 0x09AB, "Japan Cash Machine Co., Ltd." }, { 0x09AC, "DIGIGRAM" }, { 0x09AD, "The MITRE Corporation" }, { 0x09AE, "Tripp Lite" }, { 0x09AF, "G.i.N. mbH" }, { 0x09B0, "Fargo Electronics, Inc." }, { 0x09B1, "Ositech Communications Incorporated" }, { 0x09B2, "Franklin Electronic Publishers" }, { 0x09B3, "Simplex Solution Inc." }, { 0x09B4, "MDS Gateways" }, { 0x09B5, "Celltrix Technology Co., Ltd." }, { 0x09B6, "SmithMyers Communications Limited" }, { 0x09B7, "FAIRLIGHT ESP" }, { 0x09B8, "PhoeniX . Incorporated" }, { 0x09B9, "CentLand inc." }, { 0x09BA, "Chumtronix N.V." }, { 0x09BB, "Eule Industrie- & Datentechnik GmbH & Co. KG" }, { 0x09BC, "Audivo GmbH" }, { 0x09BD, "Haptix Creation Pte Ltd" }, { 0x09BE, "Prosisa Overseas LLC" }, { 0x09BF, "Auerswald GmbH & Co. KG" }, { 0x09C0, "Molecular Devices LLC" }, { 0x09C1, "ARRIS International" }, { 0x09C2, "NISCA Corporation" }, { 0x09C3, "ACTIVCARD, INC." }, { 0x09C4, "ACTiSYS Corporation" }, { 0x09C5, "Memory Corporation" }, { 0x09C6, "Inovatec S.p.A." }, { 0x09C7, "PUBCOMPANY s.r.l." }, { 0x09C8, "Carrot Systems Inc." }, { 0x09C9, "U.S. Digital Corp." }, { 0x09CA, "BMC Messsysteme GmbH" }, { 0x09CB, "Flir Systems" }, { 0x09CC, "Workbit Corporation" }, { 0x09CD, "Psion Connect Ltd." }, { 0x09CE, "City Electronics Ltd." }, { 0x09CF, "Electronics Testing Center, Taiwan" }, { 0x09D1, "NeoMagic Inc." }, { 0x09D2, "Vreelin Engineering Inc." }, { 0x09D3, "COM ONE" }, { 0x09D4, "Asahi Engineering Co., Ltd." }, { 0x09D5, "DigiTech" }, { 0x09D6, "Berkeley Varitronics Systems" }, { 0x09D7, "NovAtel Inc." }, { 0x09D8, "Elatec GmbH" }, { 0x09D9, "Jungo" }, { 0x09DA, "A-FOUR TECH CO., LTD." }, { 0x09DB, "Measurement Computing Corporation" }, { 0x09DC, "AIMEX Corporation" }, { 0x09DD, "Fellowes Inc." }, { 0x09DE, "ViQuest Technology" }, { 0x09DF, "Addonics Technologies Corp." }, { 0x09E0, "Johnson Matthey PLC, Trading as Tracerco" }, { 0x09E1, "Intellon Corporation" }, { 0x09E2, "Surface Imaging Systems (S.I.S.)" }, { 0x09E3, "WIZnet" }, { 0x09E4, "Unidata" }, { 0x09E5, "Jo-Dan International, Inc." }, { 0x09E6, "Silutia, Inc." }, { 0x09E7, "Real 3D, Inc." }, { 0x09E8, "AKAI professional M.I. Corp." }, { 0x09E9, "CHEN-SOURCE INC." }, { 0x09EA, "ShareCall Technologies" }, { 0x09EB, "Sonicbox, Inc." }, { 0x09EC, "COINT Multimedia Systems" }, { 0x09ED, "Viking Sewing Machines AB" }, { 0x09EE, "Jesmay Electronics Co., Ltd." }, { 0x09EF, "XITEL PTY Limited" }, { 0x09F0, "Perpetual Technologies, LLC" }, { 0x09F1, "Eshed Robotec" }, { 0x09F2, "hema Elektronik GmbH" }, { 0x09F3, "GoFlight, Inc." }, { 0x09F4, "Microlink Corporation" }, { 0x09F5, "ARESCOM" }, { 0x09F6, "RocketChips, Inc." }, { 0x09F7, "EDU-SCIENCE (H.K.) LIMITED" }, { 0x09F8, "SoftConnex Technologies, Inc." }, { 0x09F9, "Bay Associates" }, { 0x09FA, "Mtek Vision" }, { 0x09FB, "Altera" }, { 0x09FC, "Silicon Mountain Design" }, { 0x09FD, "MM - Manager Memory" }, { 0x09FE, "Goldteck International Inc." }, { 0x09FF, "Gain Technology Corp." }, { 0x0A00, "Liquid Audio" }, { 0x0A01, "ViA, Inc." }, { 0x0A02, "DIATECNIC" }, { 0x0A03, "Globe Wireless, Inc." }, { 0x0A04, "Star, Inc." }, { 0x0A05, "University of Kansas" }, { 0x0A06, "BSQUARE Slicon Valley" }, { 0x0A07, "Ontrak Control Systems Inc." }, { 0x0A08, "Lorenz GmbH" }, { 0x0A09, "Datadesk Technologies Inc." }, { 0x0A0A, "LIEWENTHAL ELECTRONICS LTD." }, { 0x0A0B, "Cybex Computer Products Corporation" }, { 0x0A0C, "MIRAD" }, { 0x0A0D, "VIPS France" }, { 0x0A0E, "AGFEO" }, { 0x0A0F, "Liesegang" }, { 0x0A10, "Combinova AB" }, { 0x0A11, "Xentec Incorporated" }, { 0x0A12, "Cambridge Silicon Radio Ltd." }, { 0x0A13, "Telebyte Inc." }, { 0x0A14, "Spacelabs Healthcare" }, { 0x0A15, "Scalar Corporation" }, { 0x0A16, "Trek Technology (S) Pte Ltd" }, { 0x0A17, "HOYA Corporation" }, { 0x0A18, "Heidelberger Druckmaschinen AG" }, { 0x0A19, "Hua Geng Technologies Inc." }, { 0x0A1A, "Astro-Med, Inc." }, { 0x0A1B, "Wolfvision GmbH" }, { 0x0A1C, "Micro Systemation AB" }, { 0x0A1D, "T-Nova Deutsche Telekom Innovationsgesellschaft" }, { 0x0A1E, "Netcraft (Pty) Ltd." }, { 0x0A1F, "Tesco Co." }, { 0x0A20, "SystemBase Co., Ltd." }, { 0x0A21, "Physio-Control, Inc." }, { 0x0A22, "Century Semiconductor USA, Inc." }, { 0x0A23, "NDS Technologies Israel Ltd." }, { 0x0A24, "Boca Design, Inc." }, { 0x0A25, "3M Germany" }, { 0x0A26, "Cyberware" }, { 0x0A27, "Datacard Group" }, { 0x0A28, "Ensure Technologies, Inc." }, { 0x0A29, "Marketcast" }, { 0x0A2A, "Fortune Electronics & Plastic (International) Ltd." }, { 0x0A2B, "Muller & Sebastiani Elektronik GmbH" }, { 0x0A2C, "Ak Modul Bus Computer GmbH" }, { 0x0A2D, "Advanced Measurement Technology" }, { 0x0A2E, "ONE-O-ONE iSOLUTIONS" }, { 0x0A2F, "Prime Systems, Inc." }, { 0x0A30, "WAW-Tronics" }, { 0x0A31, "Data System Co., Ltd." }, { 0x0A32, "Addatel ApS" }, { 0x0A33, "Intermind Inc." }, { 0x0A34, "TG3 Electronics, Inc." }, { 0x0A35, "Radikal Technologies" }, { 0x0A36, "GS Technical Support Center" }, { 0x0A37, "Concept Development" }, { 0x0A38, "I.R.I.S." }, { 0x0A39, "Gilat Satellite Networks Ltd." }, { 0x0A3A, "PentaMedia Co., Ltd." }, { 0x0A3B, "Hitachi Information Technology Co., Ltd." }, { 0x0A3C, "NTT DoCoMo,Inc." }, { 0x0A3D, "Varo Vision" }, { 0x0A3E, "REINHARDT System- und Messelectronic GmbH" }, { 0x0A3F, "Swissonic AG" }, { 0x0A40, "PaloDEx Group Oy" }, { 0x0A41, "SEKONIC corporation" }, { 0x0A42, "Medtronic Functional Diagnostics" }, { 0x0A43, "Boca Systems Inc." }, { 0x0A44, "TurboLinux" }, { 0x0A45, "Look&Say co., Ltd." }, { 0x0A46, "Davicom Semiconductor, Inc." }, { 0x0A47, "Hirose Electric Co., Ltd." }, { 0x0A48, "I/O Interconnect" }, { 0x0A4A, "propagamma kommunikation" }, { 0x0A4B, "Fujitsu Media Devices Limited" }, { 0x0A4C, "COMPUTEX Co., Ltd." }, { 0x0A4D, "Evolution Electronics Ltd." }, { 0x0A4E, "Steinberg Soft-und Hardware GmbH" }, { 0x0A4F, "Litton Systems Inc." }, { 0x0A50, "Mimaki Engineering Co., Ltd." }, { 0x0A51, "Sony Electronics Inc." }, { 0x0A52, "JEBSEE ELECTRONICS CO., LTD." }, { 0x0A53, "Portable Peripheral Co., Ltd." }, { 0x0A54, "Applied Signal Technology, Inc." }, { 0x0A55, "ThermoQuest Corporation" }, { 0x0A56, "EAE electronics GmbH" }, { 0x0A57, "Joachim Koopmann Software" }, { 0x0A58, "DIGIDENT LTD." }, { 0x0A59, "Convergence Instruments" }, { 0x0A5B, "EASICS NV" }, { 0x0A5C, "Broadcom Corp." }, { 0x0A5D, "Diatrend Corporation" }, { 0x0A5E, "Spinnaker Systems Inc." }, { 0x0A5F, "Zebra Technologies" }, { 0x0A60, "Future Networks, Inc." }, { 0x0A61, "DTI sa" }, { 0x0A62, "MPMan.com, Inc." }, { 0x0A63, "Prism Media Products Ltd." }, { 0x0A64, "Padcom Inc." }, { 0x0A65, "FullAudio, Inc." }, { 0x0A66, "ClearCube Technology" }, { 0x0A67, "Medeli Electronics Co, Ltd." }, { 0x0A68, "COMAIDE Corporation" }, { 0x0A69, "Chroma ate Inc." }, { 0x0A6A, "Newcom Inc." }, { 0x0A6B, "Green House Co., Ltd." }, { 0x0A6C, "Integrated Circuit Systems Inc." }, { 0x0A6D, "UPS Manufacturing" }, { 0x0A6E, "Benwin" }, { 0x0A6F, "Core Technology, Inc." }, { 0x0A70, "International Game Technology" }, { 0x0A71, "VIPColor Technologies USA, Inc." }, { 0x0A72, "Sanwa Denshi" }, { 0x0A73, "SYDEC N.V." }, { 0x0A74, "Adaptive Networks, Inc." }, { 0x0A75, "Jeol USA, Inc." }, { 0x0A76, "I-Jam Multi-Media, LLC" }, { 0x0A77, "Janome Sewing Machine Co., Ltd." }, { 0x0A78, "GREATSUN" }, { 0x0A79, "Geocast Network Systems, Inc." }, { 0x0A7A, "Towitoko AG" }, { 0x0A7B, "R & D Co., Ltd." }, { 0x0A7C, "QUANCOM Informationssysteme GmbH" }, { 0x0A7D, "Intertek NSTL" }, { 0x0A7E, "Octagon Systems Corporation" }, { 0x0A7F, "AVerMedia MicroSystems" }, { 0x0A80, "Rexon Technology Corp., Ltd" }, { 0x0A81, "CHESEN ELECTRONICS CORP." }, { 0x0A82, "SYSCAN" }, { 0x0A83, "NextComm, Inc." }, { 0x0A84, "Maui Innovative Peripherals" }, { 0x0A85, "IDEXX LABS" }, { 0x0A86, "NITGen Co., Ltd." }, { 0x0A87, "Tucker-Davis Technologies, Inc." }, { 0x0A88, "PAH-RAN TECH., INC." }, { 0x0A89, "Active Company" }, { 0x0A8A, "American Magnetics" }, { 0x0A8B, "Intelliworxx Inc." }, { 0x0A8C, "Tecmar" }, { 0x0A8D, "Picturetel" }, { 0x0A8E, "Japan Aviation Electronics Industry Ltd. (JAE)" }, { 0x0A8F, "Young Chang Co. Ltd." }, { 0x0A90, "Candy Technology Co., Ltd." }, { 0x0A91, "Globlink Technology Inc." }, { 0x0A92, "EGO SYStems Inc." }, { 0x0A93, "C Technologies AB (publ)" }, { 0x0A94, "Intersense" }, { 0x0A95, "Origin Instruments Corporation" }, { 0x0A96, "Evation.com" }, { 0x0A97, "Guardware Systems Ltd." }, { 0x0A98, "TECHNO ART CO., LTD" }, { 0x0A99, "Talon Technology" }, { 0x0A9A, "Business Navigator" }, { 0x0A9B, "Input/Output Inc." }, { 0x0A9C, "Applied Cytometry Systems" }, { 0x0A9D, "Jung & Dusch GmbH" }, { 0x0A9E, "Performance Concepts, Inc." }, { 0x0A9F, "Sim-Addicts Design Group" }, { 0x0AA0, "Vtech Communications Ltd." }, { 0x0AA1, "Amer.com" }, { 0x0AA2, "Delta Tau Data Systems, Inc." }, { 0x0AA3, "Lava Computer Mfg. Inc." }, { 0x0AA4, "Develco Elektronik" }, { 0x0AA5, "First International Digital" }, { 0x0AA6, "Perception Digital Limited" }, { 0x0AA7, "Wincor Nixdorf GmbH & Co KG" }, { 0x0AA8, "TriGem Computer, Inc." }, { 0x0AA9, "Baromtec Co." }, { 0x0AAA, "Japan CBM Corporation" }, { 0x0AAB, "Vision Shape Europe SA." }, { 0x0AAC, "iCompression Inc." }, { 0x0AAD, "Rohde & Schwarz GmbH & Co. KG" }, { 0x0AAE, "NEC infrontia Corporation" }, { 0x0AAF, "digitalway co., ltd." }, { 0x0AB0, "Arrow Strong Electronics CO. LTD" }, { 0x0AB1, "Feig Electronic GmbH" }, { 0x0AB2, "Sintefex Audio LDA" }, { 0x0AB3, "CANON FINETECH INC." }, { 0x0AB4, "esd electronic system design gmbh" }, { 0x0AB5, "Beckman Coulter, Inc." }, { 0x0AB6, "Labsystems Oy" }, { 0x0AB7, "Cross electronics, inc." }, { 0x0AB8, "TelePhotogenics, Inc." }, { 0x0AB9, "Identcode Ltd." }, { 0x0ABA, "University of Geneva" }, { 0x0ABB, "Travsys BV" }, { 0x0ABC, "Life-Tech, Inc." }, { 0x0ABD, "Wako Rubber Industries Co., Ltd." }, { 0x0ABE, "STEREOLINK.COM" }, { 0x0ABF, "DeVaSys" }, { 0x0AC0, "Nidek Co., Ltd." }, { 0x0AC1, "MicroDatec GmbH" }, { 0x0AC2, "BrainMaster Technologies, Inc." }, { 0x0AC3, "ON Semiconductor (System Solutions Co., Ltd)" }, { 0x0AC4, "LECO CORPORATION" }, { 0x0AC5, "I & C Corporation" }, { 0x0AC6, "Singing Electrons, Inc." }, { 0x0AC7, "Panwest Corporation" }, { 0x0AC8, "Vimicro Corporation" }, { 0x0AC9, "Micro Solutions, Inc." }, { 0x0ACA, "The Open Group" }, { 0x0ACB, "DEICY CORPORATION" }, { 0x0ACC, "Koga Electronics Co." }, { 0x0ACD, "ID Tech" }, { 0x0ACE, "ZyDAS Technology Corporation" }, { 0x0ACF, "Intoto, Inc." }, { 0x0AD0, "Intellix Corp." }, { 0x0AD1, "Remotec Technology Ltd." }, { 0x0AD2, "Service & Quality Technology Co., Ltd." }, { 0x0AD3, "Bolton Engineering, Inc." }, { 0x0AD4, "TIGEREX ENTERPRISE CO., LTD." }, { 0x0AD5, "kuwatec, Inc." }, { 0x0AD6, "Vir A/S" }, { 0x0AD7, "Lynium L.L.C." }, { 0x0AD8, "Aidonic Corporation" }, { 0x0AD9, "Avolites Ltd." }, { 0x0ADA, "Data Encryption Systems Ltd" }, { 0x0ADB, "T.A.M. Co., Ltd." }, { 0x0ADC, "KE Knestel Elektronik GmbH" }, { 0x0ADD, "Alliance Distribution" }, { 0x0ADE, "Microft Co., Ltd." }, { 0x0ADF, "Arial Phone L.L.C." }, { 0x0AE0, "Collins Medical" }, { 0x0AE1, "Protein Solutions, Inc." }, { 0x0AE2, "NERA SATCOM ASA" }, { 0x0AE3, "Allion Labs, Inc." }, { 0x0AE4, "Taito Corporation" }, { 0x0AE5, "MacroSystem Digital Video AG" }, { 0x0AE6, "EVI, Inc." }, { 0x0AE7, "Neodym Systems Inc." }, { 0x0AE8, "System Support Co., Ltd." }, { 0x0AE9, "North Shore Circuit Design L.L.P." }, { 0x0AEA, "SciEssence, LLC" }, { 0x0AEB, "TTP Communications Ltd." }, { 0x0AEC, "Neodio Technologies Corporation" }, { 0x0AED, "ScottCare Corporation" }, { 0x0AEE, "Max Co., Ltd." }, { 0x0AEF, "Simple Systems, Ltd." }, { 0x0AF0, "Option NV" }, { 0x0AF1, "KYOEI Co., Ltd." }, { 0x0AF2, "CARTS, LLC" }, { 0x0AF3, "Scale Master Technology, LLC." }, { 0x0AF4, "ARTRONICS CO. LTD" }, { 0x0AF5, "Nakamichi" }, { 0x0AF6, "SILVER I CO., LTD." }, { 0x0AF7, "B2C2, Inc." }, { 0x0AF8, "Taiwan Regular Electronics Co., Ltd." }, { 0x0AF9, "NEW AFA TECHNOLOGY CO., LTD" }, { 0x0AFA, "DMC Co., Ltd." }, { 0x0AFB, "OO-ALC/TISMD-CAPRE" }, { 0x0AFC, "Zaptronix Ltd" }, { 0x0AFD, "Tateno Dennou, Inc." }, { 0x0AFE, "Cummins Engine Company" }, { 0x0AFF, "Jump Zone Network Products, Inc." }, { 0x0B00, "INGENICO" }, { 0x0B01, "Techno-Holon Corporation" }, { 0x0B02, "Avery Weigh-Tronix" }, { 0x0B03, "ARCA TECHNOLOGIES, LTD." }, { 0x0B04, "EURESYS S.A." }, { 0x0B05, "ASUSTek Computer Inc." }, { 0x0B06, "Digital Ink, Inc." }, { 0x0B07, "Telebau GmbH" }, { 0x0B08, "Lightwell Co., Ltd ZAX Division" }, { 0x0B09, "Allophonic Electronics L.t.d." }, { 0x0B0A, "FARO Technologies INC." }, { 0x0B0B, "Datamax Corporation" }, { 0x0B0C, "Todos Data System AB" }, { 0x0B0D, "Project Lab" }, { 0x0B0E, "GN Audio" }, { 0x0B0F, "AVID Technology" }, { 0x0B10, "Pcally" }, { 0x0B11, "I Tech Solutions Co., Ltd." }, { 0x0B12, "T-Metrics, Inc." }, { 0x0B13, "Practical Micro Design, Inc." }, { 0x0B14, "Real Sport, Inc." }, { 0x0B15, "Actia Do Brasil Ind. E. Com. Ltda." }, { 0x0B16, "onscreen24" }, { 0x0B17, "Scantron Corporation" }, { 0x0B18, "Shimizu Works, Hitachi Air Conditioning Systems Co" }, { 0x0B19, "Color Kinetics Inc." }, { 0x0B1B, "Bematech Ind. Com. Equip. Elect. S.A." }, { 0x0B1C, "York Electronics Centre" }, { 0x0B1D, "Erich Jaeger GmbH" }, { 0x0B1E, "Electronic Warfare Associates, Inc. (EWA)" }, { 0x0B1F, "Insyde Software Corp." }, { 0x0B20, "TransDimension Inc." }, { 0x0B21, "Yokogawa Electric Corporation" }, { 0x0B22, "Japan System Development Co. Ltd." }, { 0x0B23, "Pan-Asia Electronics Co., Ltd." }, { 0x0B24, "ITX E-Globaledge Corporation" }, { 0x0B25, "Advanced Programming Concepts, Inc." }, { 0x0B26, "Applied Scientific Instrumentation Inc." }, { 0x0B27, "Ritek Corporation" }, { 0x0B28, "Kenwood Corporation" }, { 0x0B29, "Intertex Data AB" }, { 0x0B2A, "Glotrex Co., Ltd." }, { 0x0B2C, "Village Center, Inc." }, { 0x0B2D, "Akatsuki Electronic work & study Corp." }, { 0x0B2E, "CTL Inc." }, { 0x0B2F, "Clarkspur Design, Inc." }, { 0x0B30, "NewHeights Software" }, { 0x0B31, "Kyowa Electronic Instruments Co., Ltd." }, { 0x0B32, "Utrecht University MBF" }, { 0x0B33, "Contour Design, Inc." }, { 0x0B34, "KNP Technologies" }, { 0x0B35, "Solutions Cubed" }, { 0x0B36, "Iizuna Signal Processing Lab Inc." }, { 0x0B37, "Hitachi ULSI Systems Co., Ltd." }, { 0x0B39, "Omnidirectional Control Technology Inc." }, { 0x0B3A, "IPaxess" }, { 0x0B3B, "Bromax Communications, Inc." }, { 0x0B3C, "Olivetti S.p.A" }, { 0x0B3E, "Kikusui Electronics Corporation" }, { 0x0B3F, "Mitec Systems, Inc." }, { 0x0B40, "RF Solutions Ltd." }, { 0x0B41, "Hal Corporation" }, { 0x0B42, "LENZE GmbH & Co KG" }, { 0x0B43, "Sixth Avenue Designs" }, { 0x0B44, "Programa Tools, Inc." }, { 0x0B45, "Event Electronics, LLC" }, { 0x0B46, "Nuark Co., Ltd." }, { 0x0B47, "Sportbug.com, Inc" }, { 0x0B48, "TechnoTrend AG" }, { 0x0B49, "ASCII Corporation" }, { 0x0B4A, "Pocket Pyro, Inc." }, { 0x0B4B, "XFX Creation Inc." }, { 0x0B4C, "Comvurgent" }, { 0x0B4D, "Graphtec" }, { 0x0B4E, "Musical Electronics Ltd." }, { 0x0B4F, "Neuralog, Inc." }, { 0x0B50, "Starlight Marketing (H.K.) Ltd." }, { 0x0B51, "USB KITS" }, { 0x0B52, "Zight Corporation" }, { 0x0B54, "Sinbon Electronics Co., Ltd." }, { 0x0B55, "Sendtek Corporation" }, { 0x0B56, "TYI Systems Ltd." }, { 0x0B57, "Hanwang Technology Co., LTD." }, { 0x0B59, "Lake Communications Ltd." }, { 0x0B5A, "Corel Corporation" }, { 0x0B5B, "Anritsu Corporation" }, { 0x0B5C, "IDEAL Industries Inc." }, { 0x0B5D, "Music Playground Inc." }, { 0x0B5E, "Luciol Instruments" }, { 0x0B5F, "Green Electronics Co., Ltd." }, { 0x0B60, "SiConnect Ltd." }, { 0x0B61, "NEC Display Solutions, Ltd." }, { 0x0B62, "Orange Micro, Inc." }, { 0x0B63, "ADLink Technology Inc." }, { 0x0B64, "Wonderful Wire Cable Co., Ltd" }, { 0x0B65, "Expert Magnetics Corp." }, { 0x0B66, "Cybiko Inc." }, { 0x0B67, "Fairbanks Scales" }, { 0x0B68, "SenDEC Corporation" }, { 0x0B69, "CacheVision" }, { 0x0B6A, "Maxim Integrated Products" }, { 0x0B6B, "Ashling Microsystems Ltd." }, { 0x0B6C, "FreeSystems Pte Ltd" }, { 0x0B6D, "The Graphics Network Limited" }, { 0x0B6E, "Neurosoft, Inc." }, { 0x0B6F, "Nagano Japan Radio Co., Ltd" }, { 0x0B70, "PortalPlayer, Inc." }, { 0x0B71, "SHIN-EI Sangyo Co., Ltd." }, { 0x0B72, "Embedded Wireless Technology Co. Ltd." }, { 0x0B73, "Computone Corp." }, { 0x0B75, "Roland DG Corporation" }, { 0x0B76, "Pro-Tech Services Inc." }, { 0x0B77, "RJS, Inc." }, { 0x0B78, "ATSKY" }, { 0x0B79, "Sunrise Telecom, Inc." }, { 0x0B7A, "Zeevo, Inc." }, { 0x0B7B, "Taiko Denki Co., Ltd." }, { 0x0B7C, "ITRAN Communications Ltd." }, { 0x0B7D, "Astrodesign, Inc." }, { 0x0B7E, "Kurusugawa Electronics Incorporate" }, { 0x0B7F, "Scantech BV" }, { 0x0B80, "Omtronix Engineering Corp." }, { 0x0B81, "id3 Semiconductors" }, { 0x0B82, "TravRoute, a division of ALK Associates, Inc." }, { 0x0B83, "OCTAX Microscience" }, { 0x0B84, "Rextron Technology, Inc." }, { 0x0B85, "Elkat Electronics (M) SDN. BHD." }, { 0x0B86, "Exputer Systems, Inc." }, { 0x0B87, "Plus-One I & T Inc." }, { 0x0B88, "Sigma Koki Co., Ltd. Technology Center" }, { 0x0B89, "Advanced Digital Broadcast Ltd." }, { 0x0B8A, "YARC Systems Corporation" }, { 0x0B8B, "American Microsystems, Ltd." }, { 0x0B8C, "SMART Technologies Inc." }, { 0x0B8D, "Microsystems Development Technologies, Inc." }, { 0x0B8E, "Dartcom" }, { 0x0B8F, "Visual Environment" }, { 0x0B90, "DACTRON INC." }, { 0x0B91, "DesignTech International, Inc." }, { 0x0B92, "SINAR AG" }, { 0x0B93, "Marantz Japan, Inc." }, { 0x0B94, "NEOREX Co., Ltd." }, { 0x0B95, "ASIX Electronics Corporation" }, { 0x0B96, "SEWON TELECOM" }, { 0x0B97, "O2Micro, Inc." }, { 0x0B98, "Playmates Toys Inc." }, { 0x0B99, "Audio International, Inc." }, { 0x0B9A, "Namco Limited" }, { 0x0B9B, "Dipl.-Ing. Stefan Kunde" }, { 0x0B9C, "Melco Embroidery Systems" }, { 0x0B9D, "Softprotec Co." }, { 0x0B9E, "Asylum Research" }, { 0x0B9F, "Chippo Technologies" }, { 0x0BA0, "Turtle Industry Co., Ltd." }, { 0x0BA1, "Jowit Company Limited" }, { 0x0BA2, "Line Media Research CO., LTD." }, { 0x0BA3, "Taiko Electric Works, Ltd." }, { 0x0BA4, "Nagano Oki Electric Co., Ltd." }, { 0x0BA5, "Clemex Technologies Inc." }, { 0x0BA6, "3DM Devices Inc" }, { 0x0BA7, "CVC Networks Co., Ltd." }, { 0x0BA8, "CastleNet Technology Inc." }, { 0x0BA9, "Misawa Homes Co., Ltd." }, { 0x0BAA, "Dr. Gerhard Schmidt GmbH" }, { 0x0BAB, "House Ear Institute" }, { 0x0BAC, "Biometric Access Corporation" }, { 0x0BAD, "Festo Didactic Ltd/Ltee" }, { 0x0BAE, "IGEN International, Inc." }, { 0x0BAF, "U.S. Robotics" }, { 0x0BB0, "Concord Camera Corp." }, { 0x0BB1, "Infinilink Corporation" }, { 0x0BB2, "Ambit Microsystems Corporation" }, { 0x0BB3, "Ofuji Technology" }, { 0x0BB4, "HTC Corporation" }, { 0x0BB5, "Murata Manufacturing Co., Ltd." }, { 0x0BB6, "Network Alchemy" }, { 0x0BB7, "Joytech Computer Company Limited" }, { 0x0BB8, "Renesas Technology Sales Co., Ltd." }, { 0x0BB9, "Eiger M & C CO., LTD." }, { 0x0BBA, "ZACCESS Systems" }, { 0x0BBB, "General Meters Corporation" }, { 0x0BBC, "Assistive Technology, Inc." }, { 0x0BBD, "System Connection, Inc" }, { 0x0BBE, "ShibaSoku Co., Ltd." }, { 0x0BBF, "Algo Communication Products Ltd." }, { 0x0BC0, "Knilink Technology Inc." }, { 0x0BC1, "FUW YNG ELECTRONICS COMPANY LTD" }, { 0x0BC2, "Seagate Technology LLC" }, { 0x0BC3, "IPWireless, Inc." }, { 0x0BC4, "Microcube Corp." }, { 0x0BC5, "JCN Co., Ltd." }, { 0x0BC6, "ExWAY Inc." }, { 0x0BC7, "X10 Wireless Technology, Inc." }, { 0x0BC8, "Telmax Communications" }, { 0x0BC9, "ECI Telecom Ltd" }, { 0x0BCA, "Startek Engineering Incorporated" }, { 0x0BCB, "Perfect Technic Enterprise Co. LTD" }, { 0x0BCC, "Dolphin Interactive" }, { 0x0BCD, "Mbeware Inc." }, { 0x0BCE, "I-TEC hanshin Incorporated Company" }, { 0x0BCF, "Chuo-Engineering Ltd." }, { 0x0BD0, "Trenz Electronic" }, { 0x0BD1, "Blue Sky Labs, Inc." }, { 0x0BD2, "Union Biometrica" }, { 0x0BD3, "OPHIR OPTRONICS LTD" }, { 0x0BD4, "NISSIN INC." }, { 0x0BD5, "Rabbit House Corporation" }, { 0x0BD6, "Renaissance Learning Inc." }, { 0x0BD7, "Andrew Pargeter & Associates" }, { 0x0BD8, "Gamry Instruments, Inc." }, { 0x0BD9, "Liberty Instruments, Inc." }, { 0x0BDA, "Realtek Semiconductor Corp." }, { 0x0BDB, "Ericsson AB" }, { 0x0BDC, "Y Media Corporation" }, { 0x0BDD, "Orange PCS" }, { 0x0BDE, "Thuris Corporation" }, { 0x0BDF, "PopcomNet Co., Ltd" }, { 0x0BE0, "Silicon Magic Co., LTD" }, { 0x0BE1, "COM DEV Wireless" }, { 0x0BE2, "Kanda Tsushin Kogyo Co., LTD" }, { 0x0BE3, "TOYO Corporation" }, { 0x0BE4, "Elka International Ltd." }, { 0x0BE5, "DOME Imaging Systems, Inc" }, { 0x0BE6, "Wonderful Photoelectricity (DongGuan), Co., Ltd." }, { 0x0BE7, "Zanthic Technologies Inc." }, { 0x0BE8, "M@inNet Communication" }, { 0x0BE9, "Realistic Interactive, Inc." }, { 0x0BEA, "Bryce Office Systems" }, { 0x0BEB, "RPA Electronics Design, LLC" }, { 0x0BEC, "Idaho Technology" }, { 0x0BED, "MEI, Inc." }, { 0x0BEE, "LTK International Limited" }, { 0x0BEF, "Way2Call Communications" }, { 0x0BF0, "Pace Micro Technology PLC" }, { 0x0BF1, "Intracom S.A." }, { 0x0BF2, "Konexx" }, { 0x0BF3, "CTI Co., Ltd." }, { 0x0BF4, "Kuraya-Sanseido Co., Ltd." }, { 0x0BF5, "Xactex Corporation" }, { 0x0BF6, "Addonics Technologies, Inc." }, { 0x0BF7, "Sunny Giken Inc." }, { 0x0BF8, "Fujitsu Technology Solutions GmbH" }, { 0x0BF9, "QPICT, Inc." }, { 0x0BFA, "NKE Corporation" }, { 0x0BFB, "Grass Valley Group" }, { 0x0BFC, "Zero Mass Products Inc." }, { 0x0BFD, "KVASER AB" }, { 0x0BFE, "Morphy Planning & Co., Ltd" }, { 0x0BFF, "Damotech Inc." }, { 0x0C00, "ATM Computer" }, { 0x0C01, "K-One Telecom Co., Ltd." }, { 0x0C02, "Shinko Seisakusho Co., LTD" }, { 0x0C03, "SAXA Inc." }, { 0x0C04, "MOTO Development Group, Inc." }, { 0x0C05, "Appian Graphics" }, { 0x0C06, "Hasbro, Inc." }, { 0x0C07, "Infinite Data Storage LTD" }, { 0x0C08, "ei Corporation" }, { 0x0C09, "Comjet Information System" }, { 0x0C0A, "Highpoint Technologies, Inc." }, { 0x0C0B, "Dura Micro, Inc." }, { 0x0C0C, "OPTIKON 2000 S.P.A." }, { 0x0C0D, "Callify Communications & Software Ltd." }, { 0x0C0E, "Korea eBook Inc." }, { 0x0C0F, "IDS Innomic GmbH" }, { 0x0C10, "Silicon Wave" }, { 0x0C11, "Multigon Industries" }, { 0x0C12, "Zeroplus Technology Co; LTD" }, { 0x0C13, "Orion Electronics International" }, { 0x0C14, "Parallel Technologies, Inc." }, { 0x0C15, "Iris Graphics" }, { 0x0C16, "Gyration, Inc." }, { 0x0C17, "Cyberboard A/S" }, { 0x0C18, "SynerTek Korea, Inc." }, { 0x0C19, "cyberPIXIE, Inc." }, { 0x0C1A, "Silicon Motion, Inc." }, { 0x0C1B, "MIPS TECHNOLOGIES" }, { 0x0C1C, "Hang Zhou Silan Microelectronics Co. Ltd" }, { 0x0C1D, "Digital Audio Corporation" }, { 0x0C1E, "TAKAYA CORP." }, { 0x0C1F, "Magicard Ltd" }, { 0x0C20, "Viditec Inc." }, { 0x0C21, "Lunatronic" }, { 0x0C22, "TallyGenicom LP" }, { 0x0C23, "Lernout + Hauspie (L + H)" }, { 0x0C24, "Taiyo Yuden Co., Ltd." }, { 0x0C25, "Sampo Corporation" }, { 0x0C26, "Icom Inc." }, { 0x0C27, "RF Ideas" }, { 0x0C28, "ICCC" }, { 0x0C29, "SOGECLAIR aerospace" }, { 0x0C2A, "AFP Imaging Corp." }, { 0x0C2B, "AT system" }, { 0x0C2C, "Controller Technologies Corporation" }, { 0x0C2D, "Scientific Data Systems, Inc." }, { 0x0C2E, "Honeywell Scanning & Mobility" }, { 0x0C2F, "Starcover GmbH" }, { 0x0C30, "MUTOH EUROPE N.V." }, { 0x0C31, "Cosmo Techs Co., Ltd." }, { 0x0C32, "Weibel Scientific A/S" }, { 0x0C33, "GN Otometrics A/S" }, { 0x0C34, "Interisa Electronica" }, { 0x0C35, "Eagletron Inc." }, { 0x0C36, "E INK CORPORATION" }, { 0x0C37, "e.Digital" }, { 0x0C38, "Der An Electric Wire & Cable Co. Ltd." }, { 0x0C39, "Aeroflex" }, { 0x0C3A, "Furui Precise Component (Kunshan) Co., Ltd" }, { 0x0C3B, "Komatsu Ltd." }, { 0x0C3C, "Radius Co., Ltd." }, { 0x0C3D, "Innocom, Inc." }, { 0x0C3E, "NEXTCELL INC." }, { 0x0C3F, "Street Smart Security" }, { 0x0C40, "Navini Networks, Inc" }, { 0x0C41, "findtheDOT" }, { 0x0C42, "OMAX Corporation" }, { 0x0C43, "BIOMETRIKA" }, { 0x0C44, "Motorola iDEN" }, { 0x0C45, "Sonix Technology Co., Ltd." }, { 0x0C46, "WaveRider Communications, Inc" }, { 0x0C47, "TECAN Group AG" }, { 0x0C48, "MARPOSS S.p.A." }, { 0x0C49, "Gigahertz-Optik GmbH" }, { 0x0C4A, "ALGE-TIMING GmbH & Co" }, { 0x0C4B, "REINER Kartengeraete GmbH & Co.KG" }, { 0x0C4C, "Needham's Electronics Inc" }, { 0x0C4D, "ICHIRO.ORG" }, { 0x0C4E, "Sonic Innovations, Inc." }, { 0x0C4F, "01dB-Stell" }, { 0x0C50, "Forvus Research Inc." }, { 0x0C51, "Trax Softworks, Inc." }, { 0x0C52, "Sealevel Systems, Inc." }, { 0x0C53, "ViewPLUS Inc." }, { 0x0C54, "GLORY LTD." }, { 0x0C55, "Spectrum Digital Inc." }, { 0x0C56, "Billion Bright (HK) Corporation Limited" }, { 0x0C57, "Imaginative Design Operation Co. Ltd." }, { 0x0C58, "Vidar Systems Corporation" }, { 0x0C59, "Dong Guan Shinko Wire Co., Ltd." }, { 0x0C5A, "TRS International Mfg., Inc." }, { 0x0C5B, "EDEC Co., Ltd." }, { 0x0C5C, "Obbligato Objectives" }, { 0x0C5D, "Musitronics GmbH" }, { 0x0C5E, "Xytronix Research & Design" }, { 0x0C5F, "WAVESYSTEMS" }, { 0x0C60, "Apogee Electronics Corporation" }, { 0x0C61, "Network Security Technology Co." }, { 0x0C62, "Chant Sincere Co., Ltd" }, { 0x0C63, "Toko, Inc." }, { 0x0C64, "Signality System Engineering Co., Ltd." }, { 0x0C65, "Eminence Enterprise Co., Ltd." }, { 0x0C66, "REXON ELECTRONICS CORP." }, { 0x0C67, "Concept Telecom Ltd" }, { 0x0C68, "Whanam Electronics Co., Ltd." }, { 0x0C69, "COMPUTechnic AG" }, { 0x0C6A, "Ackerman Computer Sciences" }, { 0x0C6B, "Spectrum Techniques, Inc" }, { 0x0C6C, "JETI Technische Instrumente GmbH" }, { 0x0C6D, "Aardvark" }, { 0x0C6E, "Zaxus Limited" }, { 0x0C6F, "SCC Research" }, { 0x0C70, "MCT Elektronikladen" }, { 0x0C71, "Fa. Hydrotechnik" }, { 0x0C72, "PEAK-System-Technik" }, { 0x0C73, "Omega Well Monitoring" }, { 0x0C74, "Optronic Laboratories, Inc." }, { 0x0C75, "Ripmax Plc" }, { 0x0C76, "Solid State System Co., Ltd." }, { 0x0C77, "SIPIX GROUP LIMITED" }, { 0x0C78, "Detto Corporation" }, { 0x0C79, "NuConnex Technologies PTE LTD" }, { 0x0C7A, "Wing-Span Enterprise Co., Ltd." }, { 0x0C7B, "Link Instruments, Inc." }, { 0x0C7C, "TMS International BV" }, { 0x0C7E, "KIRK telecom" }, { 0x0C7F, "SoftBaugh, Inc." }, { 0x0C80, "Optim Electronics" }, { 0x0C81, "Dragon State Ltd." }, { 0x0C82, "Impeccable Instruments, LLC" }, { 0x0C83, "Cylink" }, { 0x0C84, "Howell Instruments, Inc." }, { 0x0C85, "Lectra Systemes" }, { 0x0C86, "NDA Technologies, Inc." }, { 0x0C87, "Aubit, Ltd." }, { 0x0C88, "Kyocera Wireless Inc." }, { 0x0C89, "Honda Tsushin Kogyo Co., Ltd" }, { 0x0C8A, "Cast Lighting Limited" }, { 0x0C8B, "Wavefly Corporation" }, { 0x0C8C, "Coactive Networks" }, { 0x0C8D, "Greenlee Textron, Inc." }, { 0x0C8E, "Cesscom Co., Ltd." }, { 0x0C8F, "Applied Microsystems" }, { 0x0C90, "American Arium" }, { 0x0C91, "FPGA Information" }, { 0x0C92, "Nixvue Systems PTE LTD" }, { 0x0C93, "Alara Inc." }, { 0x0C94, "SAGEM Denmark" }, { 0x0C95, "Kyushu-Kyohan Co., Ltd." }, { 0x0C96, "TOPCON Positioning Systems" }, { 0x0C97, "GRE America, Inc." }, { 0x0C98, "Berkshire Products, Inc." }, { 0x0C99, "Innochips Co., Ltd." }, { 0x0C9A, "Hanool Robotics Corp" }, { 0x0C9B, "Jobin Yvon, Inc." }, { 0x0C9C, "Brand Innovators" }, { 0x0C9D, "DyOcean" }, { 0x0C9E, "PLEXUS MULTIMEDIA PTE LTD" }, { 0x0C9F, "Extenex Corporation" }, { 0x0CA0, "Robert Bosch GmbH - Automotive Aftermarket" }, { 0x0CA1, "Mentor Engineering, Inc." }, { 0x0CA2, "Zyfer" }, { 0x0CA3, "SEGA CORPORATION" }, { 0x0CA4, "ST&T INSTRUMENT CORP." }, { 0x0CA5, "BAE SYSTEMS CANADA INC." }, { 0x0CA6, "Castles Technology Co. Ltd." }, { 0x0CA7, "Information Systems Laboratories" }, { 0x0CA8, "Digital Audio Labs, Inc." }, { 0x0CA9, "Institut fuer Rundfunktechnik" }, { 0x0CAA, "Allied Telesis K.K." }, { 0x0CAB, "Melon Technos Co., Ltd." }, { 0x0CAC, "NEC Electronics (Europe) GmbH" }, { 0x0CAD, "Motorola Solutions" }, { 0x0CAE, "swissvoice ag" }, { 0x0CAF, "Buslink" }, { 0x0CB0, "Flying Pig Systems" }, { 0x0CB1, "Innovonics, Inc." }, { 0x0CB2, "Softmark" }, { 0x0CB3, "FitzSimons Automation" }, { 0x0CB4, "PalmMicro Communications, Inc." }, { 0x0CB5, "Esel International Company Ltd." }, { 0x0CB6, "Celestix Networks PTE LTD" }, { 0x0CB7, "Singatron Enterprise Co. Ltd." }, { 0x0CB8, "Opticis Co., Ltd." }, { 0x0CB9, "VTECH INFORMATIONS LTD." }, { 0x0CBA, "Trust Electronic (Shanghai) Co., Ltd." }, { 0x0CBB, "Shanghai Darong Electronics Co., Ltd." }, { 0x0CBC, "PALMAX Technology Co., Ltd." }, { 0x0CBD, "Pentel Co., Ltd. (Electronics Equipment Div.)" }, { 0x0CBE, "Keryx Technologies, Inc." }, { 0x0CBF, "Union Genius Computer Co., Ltd" }, { 0x0CC0, "Kuon Yi Industrial Corp." }, { 0x0CC2, "Timex Corporation" }, { 0x0CC3, "Rimage Corporation" }, { 0x0CC4, "emsys Embedded Systems GmbH" }, { 0x0CC5, "SENDO" }, { 0x0CC6, "INTERMAGIC CORP." }, { 0x0CC7, "Kontron Medical AG" }, { 0x0CC8, "Technotools Corporation" }, { 0x0CC9, "BroadMAX Technologies, Inc." }, { 0x0CCA, "Amphenol Corporation" }, { 0x0CCB, "SKNET CORPORATION LTD." }, { 0x0CCC, "DOMEX TECHNOLOGY CORPORATION" }, { 0x0CCD, "TerraTec Electronic GmbH" }, { 0x0CCE, "Optical Imaging Inc." }, { 0x0CCF, "T&D CORPORATION" }, { 0x0CD0, "Art Haven 9 Co., Ltd" }, { 0x0CD1, "Premier Technologies, Inc." }, { 0x0CD2, "C-MAP SRL" }, { 0x0CD3, "Pretorian Manufacturing Ltd" }, { 0x0CD4, "Amplex" }, { 0x0CD5, "Colorado Circuitworks, Inc." }, { 0x0CD6, "Scheldt & Bachmann GmbH" }, { 0x0CD7, "NEWCHIP S.r.l." }, { 0x0CD8, "JS Digitech, Inc." }, { 0x0CD9, "Shin Din Cable Ltd." }, { 0x0CDA, "INTERFACE K.K." }, { 0x0CDB, "OSMOOZE S.A." }, { 0x0CDC, "HIJI HIGH-TECH CO., LTD." }, { 0x0CDD, "Fidelica Microsystems, Inc." }, { 0x0CDE, "Z-Com INC." }, { 0x0CDF, "BUZZ-VC" }, { 0x0CE0, "ZAPEX Research Ltd." }, { 0x0CE1, "Pepperoni Light" }, { 0x0CE2, "Eltech Solutions Inc." }, { 0x0CE3, "MaxVision Corporation" }, { 0x0CE4, "JOOHONG" }, { 0x0CE5, "Hemisphere West" }, { 0x0CE6, "First Silicon Solutions, Inc." }, { 0x0CE7, "Bakker IT Services BV" }, { 0x0CE8, "Interflex Datensysteme GmbH" }, { 0x0CE9, "Pico Technology Limited" }, { 0x0CEA, "PRO TECH COMMUNICATIONS INC." }, { 0x0CEB, "Sophia Systems Co., Ltd." }, { 0x0CEC, "Cyverse Corp." }, { 0x0CED, "MAYCOM Audio Systems b.v." }, { 0x0CEE, "Gaitmat II" }, { 0x0CEF, "Contex A/S" }, { 0x0CF0, "Cadac Electronics plc." }, { 0x0CF1, "e-CONN ELECTRONIC CO., LTD." }, { 0x0CF2, "ENE Technology Inc." }, { 0x0CF3, "Qualcomm Atheros, Inc." }, { 0x0CF4, "Fomtex Corporation" }, { 0x0CF5, "Cellink Co., Ltd." }, { 0x0CF6, "Compucable Corporation" }, { 0x0CF7, "ishoni Networks" }, { 0x0CF8, "Clarisys Incorporated" }, { 0x0CF9, "Central System Research Co., Ltd." }, { 0x0CFA, "Inviso, Inc." }, { 0x0CFB, "SEnergy Corporation" }, { 0x0CFC, "Konica-Minolta" }, { 0x0CFD, "Hitex UK Ltd." }, { 0x0CFE, "L.J. Technical Systems Ltd." }, { 0x0CFF, "SAFA MEDIA CO., LTD." }, { 0x0D00, "Polar Instruments Ltd" }, { 0x0D01, "Red Bird LLC" }, { 0x0D02, "Vestibular Technolgies" }, { 0x0D03, "Triad Spectrum Ltd." }, { 0x0D04, "Addmaster Corporation" }, { 0x0D05, "Chung Nam Electronics Co. Ltd." }, { 0x0D06, "telos EDV Systementwicklung GmbH" }, { 0x0D07, "TAUREUS s.r.o." }, { 0x0D08, "UTStarcom (Hangzhou) Telecom Co., Ltd" }, { 0x0D09, "MMELECTRONICS" }, { 0x0D0A, "Colourfull Creations" }, { 0x0D0B, "Contemporary Controls" }, { 0x0D0C, "Astron Electronics Co., Ltd." }, { 0x0D0D, "MKNet Corporation" }, { 0x0D0E, "Hybrid Networks, Inc" }, { 0x0D0F, "Feng Shin Cable Co. Ltd." }, { 0x0D10, "Elastic Networks" }, { 0x0D11, "Maspro Denkoh Corp." }, { 0x0D12, "Hansol Electronics Inc." }, { 0x0D13, "BMF CORPORATION" }, { 0x0D14, "Array Comm, Inc." }, { 0x0D15, "OnStream b.v." }, { 0x0D16, "Hi-Touch Imaging Technologies Co., Ltd." }, { 0x0D17, "NALTEC, Inc." }, { 0x0D18, "coaXmedia" }, { 0x0D19, "Shanghai Hank Connection Co., Ltd." }, { 0x0D1A, "COMTECH SYSTEMS, INC" }, { 0x0D1B, "EC Engineering, LLC" }, { 0x0D1C, "MACSEMA, INC" }, { 0x0D1D, "GEMAC mbH" }, { 0x0D1E, "Eone Inc." }, { 0x0D1F, "imc MessSysteme GmbH" }, { 0x0D20, "Malcom Co., Ltd." }, { 0x0D22, "Rojone Pty Ltd" }, { 0x0D23, "SATAKE USA INC." }, { 0x0D24, "Trapper Data AB" }, { 0x0D25, "PENTTECH Engineering Systems AB" }, { 0x0D26, "Micro-Vu" }, { 0x0D27, "CLEARJET GmbH" }, { 0x0D28, "ARM Ltd" }, { 0x0D29, "Eng Resource Inc" }, { 0x0D2A, "FIELDSERVER TECHNOLOGIES" }, { 0x0D2B, "DAINIPPON SCREEN" }, { 0x0D2C, "3M Library Systems" }, { 0x0D2D, "GigaSysNet" }, { 0x0D2E, "Feedback Instruments Ltd" }, { 0x0D2F, "Andamiro Co., Ltd." }, { 0x0D30, "Vision Electronics Co., Ltd." }, { 0x0D31, "Arizona Cooperative Power" }, { 0x0D32, "Leo Hui Electric Wire & Cable Co., Ltd." }, { 0x0D33, "AirSpeak Inc." }, { 0x0D34, "Moxi Digital, Inc." }, { 0x0D35, "Dah Kun Co., Ltd." }, { 0x0D36, "Tellabs" }, { 0x0D37, "PRISM" }, { 0x0D38, "Nihon Culture-soft Service Co., Ltd." }, { 0x0D3A, "Posiflex Technologies, Inc." }, { 0x0D3B, "SANYO TECNICA Co., Ltd." }, { 0x0D3C, "SRI CABLE TECHNOLOGY LTD." }, { 0x0D3D, "TANGTOP TECHNOLOGY CO., LTD." }, { 0x0D3E, "Fitcom, inc." }, { 0x0D3F, "MTS Systems Corporation" }, { 0x0D40, "Ascor Inc." }, { 0x0D41, "Ta Yun Electronic Technology Co., Ltd." }, { 0x0D42, "FULL DER CO., LTD." }, { 0x0D43, "iCableSystem Co., Ltd." }, { 0x0D44, "AFG Elektronik GmbH" }, { 0x0D45, "Union Data Corporation" }, { 0x0D46, "KOBIL Systems GmbH" }, { 0x0D47, "KOPEK PACIFIC LTD." }, { 0x0D48, "PROMETHEAN" }, { 0x0D49, "Maxtor" }, { 0x0D4A, "NF Corporation" }, { 0x0D4B, "Grape Systems Inc." }, { 0x0D4C, "TEDAS AG" }, { 0x0D4D, "Coherent Inc." }, { 0x0D4E, "Agere Systems Netherland BV" }, { 0x0D4F, "EADS AIRBUS FRANCE" }, { 0x0D50, "Cleware GmbH" }, { 0x0D51, "Volex (Asia) Pte Ltd" }, { 0x0D52, "YAMAHA Motor Co., Ltd" }, { 0x0D53, "HMI Co., Ltd." }, { 0x0D54, "HOLON Corporation" }, { 0x0D55, "ASKA Technologies Inc." }, { 0x0D56, "AVLAB Technology, Inc." }, { 0x0D57, "SOLOMON Microtech Ltd." }, { 0x0D59, "CDS electronics bv" }, { 0x0D5A, "Hoshino Metal Industries, Ltd." }, { 0x0D5B, "LOGIC CORPORATION" }, { 0x0D5C, "Eumitcom Technology Inc." }, { 0x0D5D, "Telesis Technologies, Inc." }, { 0x0D5E, "MYACOM LTD" }, { 0x0D5F, "CSI, Inc." }, { 0x0D60, "IVL Technologies Ltd." }, { 0x0D61, "MEILU ELECTRONICS (SHENZHEN) CO., LTD." }, { 0x0D62, "Darfon Electronics Corp." }, { 0x0D63, "Fritz Gegauf AG" }, { 0x0D64, "DXG Technology Corp." }, { 0x0D65, "KMJP CO., LTD." }, { 0x0D66, "TMT" }, { 0x0D67, "Advanet Inc." }, { 0x0D68, "Super Link Electronics Co., Ltd." }, { 0x0D69, "NSI" }, { 0x0D6A, "eMegaTech International Corp." }, { 0x0D6B, "And-Or Logic" }, { 0x0D6C, "CANMAX Technology Ltd." }, { 0x0D6D, "Mitsubishi Elec. Micro-Computer App. Software Co." }, { 0x0D6E, "Forum Trading Ltd. (UK)" }, { 0x0D70, "Try Computer Co. LTD." }, { 0x0D71, "Hirakawa Hewtech Corp." }, { 0x0D72, "Winmate Communication Inc." }, { 0x0D73, "Hit's Communications INC." }, { 0x0D74, "Dreams Come True Co., Ltd." }, { 0x0D75, "LET'S Corporation, Ltd." }, { 0x0D76, "MFP Korea, Inc." }, { 0x0D77, "Power Sentry/Newpoint" }, { 0x0D78, "Japan Distributor Corporation" }, { 0x0D79, "Assistive Technology Engineering Lab" }, { 0x0D7A, "MARX CryptoTech LP" }, { 0x0D7B, "Wellco Technology Co., Ltd." }, { 0x0D7C, "Taiwan Line Tek Electronic Co., Ltd." }, { 0x0D7D, "Add-On Technology Co., Ltd." }, { 0x0D7E, "American Computer & Digital Components" }, { 0x0D7F, "Essential Reality LLC" }, { 0x0D80, "H.R. Silvine Electronics Inc." }, { 0x0D81, "TechnoVision" }, { 0x0D83, "Think Outside, Inc." }, { 0x0D84, "ELECTRO-SYSTEM Co., Ltd." }, { 0x0D85, "Identix Incorporated" }, { 0x0D86, "Marconi" }, { 0x0D87, "Dolby Laboratories Inc." }, { 0x0D88, "Miyoshi Corp." }, { 0x0D89, "Oz Software" }, { 0x0D8A, "KING JIM CO., LTD." }, { 0x0D8B, "Ascom Telecommunications Ltd." }, { 0x0D8C, "C-MEDIA ELECTRONICS INC." }, { 0x0D8D, "Promotion & Display Technology Ltd." }, { 0x0D8E, "Global Sun Technology Inc." }, { 0x0D8F, "Pitney Bowes" }, { 0x0D90, "Sure-Fire Electrical Corporation" }, { 0x0D91, "ALPHA PROJECT Co., Ltd." }, { 0x0D92, "Mega & Game" }, { 0x0D93, "Nishitomo Co., Ltd." }, { 0x0D94, "Advanced Logic Technology (ALT)" }, { 0x0D95, "Numonics Corp." }, { 0x0D96, "Skanhex Technology Inc." }, { 0x0D97, "Santa Barbara Instrument Group (SBIG)" }, { 0x0D98, "Mars Semiconductor Corp." }, { 0x0D99, "Trazer Technologies Inc." }, { 0x0D9A, "RTX Telecom A/S" }, { 0x0D9B, "Tat Shing Electrical Co." }, { 0x0D9C, "Chee Chen Hi-Technology Co., Ltd." }, { 0x0D9D, "Sanwa Supply Inc" }, { 0x0D9E, "Avaya" }, { 0x0D9F, "Powercom Co., Ltd." }, { 0x0DA0, "Danger Research" }, { 0x0DA1, "Suzhou Peter's Precise Industrial Co., Ltd." }, { 0x0DA2, "Land Instruments International Ltd." }, { 0x0DA3, "Nippon Electro-Sensory Devices Corporation" }, { 0x0DA4, "POLAR ELECTRO OY" }, { 0x0DA5, "TOKYO MAGNETIC PRINTING CO., LTD." }, { 0x0DA6, "Aimtron Technology Corp." }, { 0x0DA7, "IOGEAR, Inc." }, { 0x0DA8, "softDSP Co., Ltd." }, { 0x0DA9, "DigiLife Technology Inc." }, { 0x0DAA, "Derelek" }, { 0x0DAB, "Diasonic Technology Co., Ltd." }, { 0x0DAC, "Smart Card Technology, Inc." }, { 0x0DAD, "Westover Scientific" }, { 0x0DAE, "SERIAL SYSTEM LTD" }, { 0x0DAF, "NXTV, Inc." }, { 0x0DB0, "Micro-Star International Co., Ltd." }, { 0x0DB1, "Wen Te Electronics Co., Ltd." }, { 0x0DB2, "Shian Hwi Plug Parts, Plastic Factory" }, { 0x0DB3, "Tekram Technology Co. Ltd." }, { 0x0DB4, "Chung Fu Chen Yeh Enterprise Corporation" }, { 0x0DB5, "Azio Ltd." }, { 0x0DB6, "SIMS Valley Co., Ltd." }, { 0x0DB7, "ELCON Systemtechnik GmbH" }, { 0x0DB8, "Garear Taiwan Co., Ltd." }, { 0x0DB9, "EMKAY" }, { 0x0DBA, "DIGIDESIGN" }, { 0x0DBB, "Luna Analytics, Inc." }, { 0x0DBC, "A&D Company, Limited" }, { 0x0DBD, "Bruker Biospin" }, { 0x0DBE, "Jiuh Shiuh Precision Industry Co., Ltd." }, { 0x0DBF, "Jess-Link International" }, { 0x0DC0, "G7 Solutions" }, { 0x0DC1, "Tamagawa Seiki Co., Ltd." }, { 0x0DC3, "Athena Smartcard Solutions Inc." }, { 0x0DC4, "inXtron, Inc." }, { 0x0DC5, "SDK Co, Ltd." }, { 0x0DC6, "Precision Squared Technology Corporation" }, { 0x0DC7, "First Cable Line, Inc." }, { 0x0DC8, "WINTEC Corporation" }, { 0x0DC9, "Arvel Corp." }, { 0x0DCA, "SMaL Camera Technologies, Inc." }, { 0x0DCB, "RocketPod, Inc." }, { 0x0DCC, "Largan Digital" }, { 0x0DCD, "NetworkFab Corporation" }, { 0x0DCE, "E-MU Systems, Inc., d.b.a. E-MU/ENSONIQ" }, { 0x0DCF, "Analytik Jena AG" }, { 0x0DD0, "Access Solutions" }, { 0x0DD1, "Contek Electronics Co., Ltd." }, { 0x0DD2, "Power Quotient International Co., Ltd." }, { 0x0DD3, "MediaQ" }, { 0x0DD4, "Custom Engineering SPA" }, { 0x0DD5, "California Micro Devices" }, { 0x0DD6, "TECHKON GmbH" }, { 0x0DD7, "KOCOM CO., LTD" }, { 0x0DD8, "Netac Technology Co., Ltd." }, { 0x0DD9, "HighSpeed Surfing" }, { 0x0DDA, "Integrated Silicon Solution, Inc" }, { 0x0DDB, "Tamarack Inc." }, { 0x0DDC, "Takaotec" }, { 0x0DDD, "Datelink Technology Co., Ltd." }, { 0x0DDE, "UBICOM, INC" }, { 0x0DDF, "DriveCam Video Systems" }, { 0x0DE1, "Vidicode Datacommunicatie BV" }, { 0x0DE2, "Acom Data" }, { 0x0DE3, "RFTECH CO., LTD." }, { 0x0DE4, "Aron Digital Inc." }, { 0x0DE5, "Secure2Net, Inc. USA" }, { 0x0DE6, "Dentsply Int'l - Gendex Dental Division" }, { 0x0DE7, "USBmicro" }, { 0x0DE8, "Delsy Electronic Components AG" }, { 0x0DE9, "Technische Industrie TACX BV" }, { 0x0DEA, "UTECH Electronic (D.G.) Co., Ltd." }, { 0x0DEB, "Lean Horn Co." }, { 0x0DEC, "Callserve Communications Ltd." }, { 0x0DED, "Novasonics" }, { 0x0DEE, "Lifetime Memory Products" }, { 0x0DEF, "Full Rise Electronic Co., Ltd." }, { 0x0DF0, "GE Yokogawa Medical Systems, Ltd." }, { 0x0DF1, "Envoy Medical Corporation" }, { 0x0DF2, "Nisshin Electronics Co., Ltd." }, { 0x0DF3, "VeriTek Co., Ltd." }, { 0x0DF4, "Net & Sys Co., Ltd." }, { 0x0DF5, "Yamatake Corporation" }, { 0x0DF6, "Sitecom Europe B.V." }, { 0x0DF7, "Mobile Action Technology Inc." }, { 0x0DF8, "Hoya Computer Co., Ltd." }, { 0x0DF9, "Nice Fountain Industrial Co., Ltd." }, { 0x0DFA, "Toyo Networks & System Integration Co., Ltd." }, { 0x0DFB, "Daisy Technology" }, { 0x0DFC, "General Touch Technology Co., Ltd." }, { 0x0DFD, "Suruga Seiki Co., Ltd." }, { 0x0DFE, "Interactive Metronome" }, { 0x0DFF, "Deodeo Corporation" }, { 0x0E00, "Novar GmbH" }, { 0x0E01, "Sheng Xiang Investment Ltd." }, { 0x0E02, "Doowon Co., LTD" }, { 0x0E03, "Nippon Systemware Co., Ltd." }, { 0x0E04, "PowerCom Technology Co., Ltd." }, { 0x0E05, "Nordic ID" }, { 0x0E06, "Personal Telecom, Inc." }, { 0x0E07, "Viewtek Co., Ltd" }, { 0x0E08, "Winbest Technology Co., Ltd." }, { 0x0E09, "Winskon Cabling Specialist Co., Ltd." }, { 0x0E0A, "JAEIK Information & Communication Co., Ltd." }, { 0x0E0B, "Fujitsu Denso Ltd." }, { 0x0E0C, "Gesytec GmbH" }, { 0x0E0D, "Picoquant GmbH" }, { 0x0E0E, "Fuji Data System Co., Ltd." }, { 0x0E0F, "VMWare, Inc." }, { 0x0E10, "TERUMO Corporation (Suruga Factory)" }, { 0x0E11, "Neurotec" }, { 0x0E12, "Danam Communications Inc." }, { 0x0E13, "Lugh Networks, Inc." }, { 0x0E14, "Hunter Engineering Co." }, { 0x0E15, "Tellert Elektronik GmbH" }, { 0x0E16, "JMTEK, LLC" }, { 0x0E17, "Walex Electronic Ltd." }, { 0x0E18, "UNIWIDE Technologies" }, { 0x0E19, "OeRSTED, Inc." }, { 0x0E1A, "RDM Corporation" }, { 0x0E1B, "Crewave Co., Ltd." }, { 0x0E1C, "Beijing Hi-tech Wealth Software Technology Co." }, { 0x0E1D, "International Parts & Information Co., Ltd." }, { 0x0E1E, "Green Hills Software, Inc." }, { 0x0E1F, "Cabin Industrial Co., Ltd." }, { 0x0E20, "Pegasus Technologies Ltd." }, { 0x0E21, "Cowon Systems, Inc." }, { 0x0E22, "Symbian Ltd." }, { 0x0E23, "Liou Yuane International Ltd." }, { 0x0E24, "Samson Electric Wire Co., Ltd." }, { 0x0E25, "VinChip Systems, Inc." }, { 0x0E26, "J-Phone East Co., Ltd." }, { 0x0E27, "Thunder Island Limited" }, { 0x0E28, "Industrial Control Systems" }, { 0x0E29, "CB Sciences, Inc." }, { 0x0E2A, "Flight Link Inc." }, { 0x0E2B, "Kumamoto Techno Corporation" }, { 0x0E2C, "Intersoft Electronics N.V." }, { 0x0E2D, "SKF Condition Monitoring" }, { 0x0E2E, "Brady Corporation" }, { 0x0E2F, "Daisen Electronic Industrial Co., Ltd." }, { 0x0E30, "HeartMath LLC" }, { 0x0E31, "Biosign" }, { 0x0E32, "ICONAG - Intelligent Control AG" }, { 0x0E33, "Luna Innovations, Inc." }, { 0x0E34, "Micro Computer Control Corp." }, { 0x0E35, "3Pea Technologies, Inc." }, { 0x0E36, "TiePie engineering" }, { 0x0E37, "Alpha Data Corp." }, { 0x0E38, "Stratitec, Inc." }, { 0x0E39, "Smart Modular Technologies, Inc." }, { 0x0E3A, "Neostar Technology Co., Ltd." }, { 0x0E3B, "Mansella Ltd." }, { 0x0E3C, "Raytec Electronic Co., Ltd." }, { 0x0E3D, "Metex Corporation" }, { 0x0E3E, "Good Technology, Inc." }, { 0x0E3F, "AM Group Corp." }, { 0x0E40, "Proteq LTDA" }, { 0x0E41, "Line 6, Inc." }, { 0x0E42, "Puretek Industrial Co., Ltd." }, { 0x0E43, "Holly Lin International Technology Inc." }, { 0x0E44, "Sun-Riseful Technology Co., Ltd." }, { 0x0E45, "SafeNet B.V." }, { 0x0E46, "Delphi Corporation" }, { 0x0E47, "AMANO Corporation" }, { 0x0E48, "Julia Corporation Limited" }, { 0x0E49, "Ingenieurbuero Chanda AG" }, { 0x0E4A, "Shenzhen Bao Hing Electric Wire & Cable Mfr. Co." }, { 0x0E4B, "System General Corp." }, { 0x0E4C, "Radica Games Ltd." }, { 0x0E4D, "Hong Shi Precision Corp." }, { 0x0E4E, "Lih Duo Intl. Co., Ltd." }, { 0x0E4F, "Data Ray Corp." }, { 0x0E50, "TDi GmbH TechnoData Interware" }, { 0x0E51, "Therapy Information & Communication System Inc." }, { 0x0E52, "Mindready Solutions (NI) Ltd." }, { 0x0E53, "King Tester Corporation" }, { 0x0E54, "KDE, Inc." }, { 0x0E55, "Speed Dragon Multimedia Ltd." }, { 0x0E56, "Cenix Digicom Co., Ltd." }, { 0x0E57, "Loas Co., Ltd" }, { 0x0E58, "Technology For Energy Corp." }, { 0x0E59, "Bourns, Inc." }, { 0x0E5A, "ACTIVE CO., LTD." }, { 0x0E5B, "Union Power Information Industrial Co., Ltd." }, { 0x0E5C, "Shenzhen Bitland Information Technology Co., Ltd." }, { 0x0E5D, "Neltron Industrial Co., Ltd." }, { 0x0E5E, "Conwise Technology Co., Ltd." }, { 0x0E5F, "Entone Technologies" }, { 0x0E60, "XAVi Technologies Corp." }, { 0x0E61, "E-Pen InMotion Inc." }, { 0x0E62, "Shandong CVIC Software Engineering Co., Ltd." }, { 0x0E63, "SECUREPIA Inc." }, { 0x0E64, "Nida Corporation" }, { 0x0E65, "Skycom Tek Co., Ltd" }, { 0x0E66, "Hawking Technologies, Inc." }, { 0x0E67, "Fossil" }, { 0x0E68, "Artec" }, { 0x0E69, "A Global Partner Corporation" }, { 0x0E6A, "Megawin Technology Co., Ltd." }, { 0x0E6B, "DMA Korea Co., Ltd" }, { 0x0E6C, "E & D Co., Ltd." }, { 0x0E6D, "Tenovis Business Communication" }, { 0x0E6E, "Volvo Car Corporation" }, { 0x0E6F, "Performance Designed Products, LLC" }, { 0x0E70, "Tokyo Electronic Industry Co, LTD." }, { 0x0E71, "Schwarzer GmbH" }, { 0x0E72, "Hsi-Chin Electronics Co., Ltd." }, { 0x0E73, "MCK Communications, Inc." }, { 0x0E74, "Accu-Automation Corp." }, { 0x0E75, "TVS Electronics Limited" }, { 0x0E76, "Seiko S-Yard Co., Ltd" }, { 0x0E77, "Weinzierl Engineering GmbH" }, { 0x0E78, "Ascom Powerline Communications Ltd." }, { 0x0E79, "ARCHOS SA" }, { 0x0E7A, "Indocomp Systems Inc." }, { 0x0E7B, "On-Tech Industry Co., Ltd." }, { 0x0E7C, "Legend Holdings Limited" }, { 0x0E7D, "Eutectics Inc." }, { 0x0E7E, "G.Mate, Inc." }, { 0x0E7F, "Keysight Technologies, Inc. - AFM division" }, { 0x0E80, "GateHouse A/S" }, { 0x0E81, "System Consultants Co., Ltd." }, { 0x0E82, "Ching Tai Electric Wire & Cable Co., Ltd." }, { 0x0E83, "Shin An Wire & Cable Co." }, { 0x0E84, "Elelux International Ltd." }, { 0x0E85, "Dynavox Systems LLC" }, { 0x0E86, "Watthour Engineering Co., Inc." }, { 0x0E87, "Internet Security Co., Ltd" }, { 0x0E88, "ELBIO" }, { 0x0E89, "PRT Manufacturing Ltd." }, { 0x0E8A, "FinePoint Innovations, Inc." }, { 0x0E8B, "KAO SHIN PRECISION INDUSTRY CO., LTD." }, { 0x0E8C, "Well Force Electronic Co., Ltd" }, { 0x0E8D, "MediaTek Inc." }, { 0x0E8E, "Stuart Tyrrell Developments" }, { 0x0E8F, "Pansignal Technology Inc." }, { 0x0E90, "CRU" }, { 0x0E91, "VTech Engineering Canada Ltd." }, { 0x0E92, "C'S GLORY ENTERPRISE CO., LTD." }, { 0x0E93, "eM Technics Co., Ltd." }, { 0x0E94, "Sirona Dental Systems GmbH" }, { 0x0E95, "Future Technology Co., Ltd" }, { 0x0E96, "APLUX Communications Ltd." }, { 0x0E97, "Fingerworks, Inc." }, { 0x0E98, "Advanced Analogic Technologies, Inc." }, { 0x0E99, "Parallel Dice Co., Ltd." }, { 0x0E9A, "TA HSING INDUSTRIES LTD." }, { 0x0E9B, "ADTEC CORPORATION" }, { 0x0E9C, "StreamZap, Inc." }, { 0x0E9D, "Hitron Technologies, Inc." }, { 0x0E9E, "Japan System Design Co." }, { 0x0E9F, "TAMURA CORPORATION" }, { 0x0EA0, "Ours Technology Inc." }, { 0x0EA1, "Infinite Communication Terminals Ltd." }, { 0x0EA2, "Triumph Technology Corp." }, { 0x0EA3, "Rion Co., Ltd." }, { 0x0EA4, "Intelligent Hearing Systems" }, { 0x0EA5, "DATA SYSTEM TECHNOLOGY CO., LTD." }, { 0x0EA6, "Nihon Computer Co., Ltd." }, { 0x0EA7, "MSL Enterprises Corp." }, { 0x0EA8, "CenDyne, Inc." }, { 0x0EA9, "J&J ENGINEERING INC." }, { 0x0EAA, "TOKYO SOKKI KENKYUJO CO., LTD." }, { 0x0EAB, "Yiso Telecom" }, { 0x0EAC, "ALCATech GmbH" }, { 0x0EAD, "HUMAX Co., Ltd." }, { 0x0EAE, "Alcon Labs" }, { 0x0EAF, "Grandex International Corporation" }, { 0x0EB0, "Amigo Technology Co., Ltd." }, { 0x0EB1, "WIS Technologies, Inc." }, { 0x0EB2, "Y-S ELECTRONIC CO., LTD." }, { 0x0EB3, "Saint Technology Corp." }, { 0x0EB4, "IPLAN Inc." }, { 0x0EB5, "@pos.com" }, { 0x0EB6, "GAMEPARK, Inc." }, { 0x0EB7, "Endor AG" }, { 0x0EB8, "Mettler-Toledo (Albstadt) GmbH" }, { 0x0EB9, "SKY Electronics" }, { 0x0EBA, "iWOW Connections Pte Ltd" }, { 0x0EBB, "Thermo Nicolet Corp." }, { 0x0EBC, "CHOIS Technology" }, { 0x0EBD, "Kyowa Electronics Co., Ltd." }, { 0x0EBE, "VWEB Corporation" }, { 0x0EBF, "Omega Technology Inc." }, { 0x0EC0, "LHI Technology (China) Co., Ltd." }, { 0x0EC1, "ABIT Computer Corporation" }, { 0x0EC2, "Sweetray Industrial Ltd." }, { 0x0EC3, "Axell Corporation" }, { 0x0EC4, "Ballracing Developments Ltd." }, { 0x0EC5, "GT Information System Co., Ltd." }, { 0x0EC6, "InnoVISION Multimedia Limited" }, { 0x0EC7, "Theta Link Corporation" }, { 0x0EC8, "Mitechno Co., Ltd." }, { 0x0EC9, "HemoCue AB" }, { 0x0ECA, "Mit System Co., Ltd." }, { 0x0ECB, "Harman Kardon" }, { 0x0ECC, "Samsung SDS" }, { 0x0ECD, "Lite-On IT Corp." }, { 0x0ECE, "TaiSol Electronics Co., Ltd." }, { 0x0ECF, "Phogenix Imaging, LLC" }, { 0x0ED0, "LANergy Limited" }, { 0x0ED1, "Tai Guen Enterprise Co., Ltd." }, { 0x0ED2, "Kyoto Micro Computer Co., LTD." }, { 0x0ED3, "Wing-Tech Enterprise Co., Ltd." }, { 0x0ED4, "Ross Video" }, { 0x0ED5, "ChronoLogic Pty. Ltd." }, { 0x0ED6, "TECHNOS JAPAN Co., LTD." }, { 0x0ED7, "COSMODOG, LTD." }, { 0x0ED8, "ASAHI SPECTRA CO., LTD." }, { 0x0ED9, "Holy Stone Enterprise Co., Ltd." }, { 0x0EDA, "NORITAKE ITRON CORPORATION" }, { 0x0EDB, "AboveTech, Inc." }, { 0x0EDC, "GALTRONICS" }, { 0x0EDD, "KOWA COMPANY, LTD." }, { 0x0EDE, "TOD Co., Ltd." }, { 0x0EDF, "e-MDT Co., Ltd." }, { 0x0EE0, "SHIMA SEIKI MFG., LTD." }, { 0x0EE1, "Sarotech Co., Ltd." }, { 0x0EE2, "AMI Semiconductor Inc." }, { 0x0EE3, "ComTrue Technology Corporation (Taiwan)" }, { 0x0EE4, "Sunrich Technology (H.K.) Ltd." }, { 0x0EE5, "Medical Graphics Corporation" }, { 0x0EE6, "Takacom Corporation" }, { 0x0EE7, "Furuno Electric Co., Ltd." }, { 0x0EE8, "Triz Communications Group" }, { 0x0EE9, "JPK Systems Limited" }, { 0x0EEA, "William Demant Holding A/S" }, { 0x0EEB, "Design Of Systems On Silicon, S.A. (DS2)" }, { 0x0EEC, "Tritek Co., Ltd." }, { 0x0EED, "CCP Co., Ltd." }, { 0x0EEE, "Digital STREAM Technology, Inc." }, { 0x0EEF, "eGalax Inc." }, { 0x0EF0, "Hitachi Cable, Ltd." }, { 0x0EF1, "Aichi Micro Intelligent Corporation" }, { 0x0EF2, "I/OMAGIC CORPORATION" }, { 0x0EF3, "Lynn Products, Inc." }, { 0x0EF4, "DSI Datotech" }, { 0x0EF5, "PointChips" }, { 0x0EF6, "Yield Microelectronics Corp." }, { 0x0EF7, "SM Tech Co., Ltd." }, { 0x0EF8, "ECT Inc." }, { 0x0EF9, "eHome TV, Inc. DBA Fuze3 Technologies" }, { 0x0EFA, "Corepro Entertainment" }, { 0x0EFB, "ARKRAY, Inc." }, { 0x0EFC, "ELMEX COMPANY Ltd." }, { 0x0EFD, "Oasis Semiconductor" }, { 0x0EFE, "WEM TECHNOLOGY INC." }, { 0x0EFF, "CSIRO-TIP" }, { 0x0F00, "ndd Medizintechnik AG" }, { 0x0F01, "EXPAN Electronics Co., Ltd." }, { 0x0F02, "MobileAria" }, { 0x0F03, "Jet Power Technology Co., Ltd." }, { 0x0F04, "Softlok International Limited" }, { 0x0F05, "Quanta Network Systems Inc." }, { 0x0F06, "Visual Frontier Precision Corp." }, { 0x0F07, "Pakon" }, { 0x0F08, "CSL Wire & Plug (Shen Zhen) Company" }, { 0x0F09, "Sandel Arionics Inc." }, { 0x0F0B, "Great Computer Corporation" }, { 0x0F0C, "CAS Corporation" }, { 0x0F0D, "HORI CO., LTD." }, { 0x0F0E, "Energyfull & Hi-Top International Ltd." }, { 0x0F0F, "NANOPTIX INC." }, { 0x0F10, "Personal Information Systems Co., Ltd." }, { 0x0F11, "Leybold Didactic GMBH" }, { 0x0F12, "MARS ENGINEERING CORPORATION" }, { 0x0F13, "Acetek Technology Co., Ltd." }, { 0x0F14, "XIRING" }, { 0x0F15, "PlayMore Corporation" }, { 0x0F16, "GLOBAL VIEW CO. LTD." }, { 0x0F17, "Correlant Communications" }, { 0x0F18, "Finger Lakes Instrumentation, LLC" }, { 0x0F19, "ORACOM CO., Ltd." }, { 0x0F1A, "General Information Systems Ltd." }, { 0x0F1B, "Onset Computer Corporation" }, { 0x0F1C, "Funai Electric Co., Ltd." }, { 0x0F1D, "Iwill Corporation" }, { 0x0F1E, "INVAIR Technologies AG" }, { 0x0F1F, "Laxtha" }, { 0x0F20, "GENNUM CORPORATION" }, { 0x0F21, "IOI Technology Corporation" }, { 0x0F22, "SENIOR INDUSTRIES, INC." }, { 0x0F23, "Leader Tech Manufacturer Co., Ltd" }, { 0x0F24, "FLEX-P INDUSTRIES SDN.BHD." }, { 0x0F25, "Primera Technology Inc." }, { 0x0F26, "B.G. Technologies, Inc." }, { 0x0F27, "Alpes DEIS" }, { 0x0F28, "ESEC SA" }, { 0x0F29, "TIPTEL AG" }, { 0x0F2A, "Marconi Data Systems" }, { 0x0F2B, "XEMICS SA" }, { 0x0F2D, "ViPower, Inc." }, { 0x0F2E, "Good Man Corporation" }, { 0x0F2F, "Priva Design Services" }, { 0x0F30, "Jess Technology Co., Ltd." }, { 0x0F31, "Chrysalis Development" }, { 0x0F32, "YFC-BonEagle Electric Co., Ltd." }, { 0x0F33, "Futek Electronics, Co., Ltd." }, { 0x0F34, "Hokuto Denshi Co., Ltd." }, { 0x0F35, "Kinpo Electronics, Inc." }, { 0x0F36, "Philips Medical Systems Ultrasound" }, { 0x0F37, "Kokuyo Co., Ltd." }, { 0x0F38, "Nien-Yi Industrial Corp." }, { 0x0F39, "Heng Yu Technology (HK) Ltd." }, { 0x0F3A, "Aidensi Giken" }, { 0x0F3B, "IR-LINK" }, { 0x0F3C, "Numesa, Inc." }, { 0x0F3D, "AirPrime Inc." }, { 0x0F3E, "Aastra Broadband" }, { 0x0F3F, "FEI Electron Optics B.V." }, { 0x0F40, "Denver Instrument Company" }, { 0x0F41, "RDC Semiconductor Co., Ltd." }, { 0x0F42, "Nital Consulting Services, Inc." }, { 0x0F43, "LiteON Semiconductor Corp." }, { 0x0F44, "Polhemus Incorporated" }, { 0x0F45, "International Road Dynamics" }, { 0x0F46, "KIHOKU Electronic Co., Ltd." }, { 0x0F47, "SN Systems Ltd." }, { 0x0F48, "Durand Interstellar, Inc." }, { 0x0F49, "Evolis" }, { 0x0F4A, "Planmeca Oy" }, { 0x0F4B, "St. John Technology Co., Ltd." }, { 0x0F4C, "WORLDWIDE CABLE OPTO CORP." }, { 0x0F4D, "Microtune, Inc." }, { 0x0F4E, "Freedom Scientific" }, { 0x0F4F, "INVENTEL" }, { 0x0F50, "LeadingSpect Corporation" }, { 0x0F51, "Zeta Broadband Inc." }, { 0x0F52, "Wing Kei Electrical Production Ltd." }, { 0x0F53, "Taiyo Cable (Dongguan) Co. Ltd." }, { 0x0F54, "Kawai Musical Instruments Mfg. Co., Ltd." }, { 0x0F55, "AmbiCom, Inc." }, { 0x0F56, "SecureTech Corp." }, { 0x0F57, "WavePlus Tech. Co., Ltd." }, { 0x0F58, "JASCO Corporation" }, { 0x0F59, "NCI/Newcomb Company, Inc." }, { 0x0F5A, "Cogency Semiconductor Inc." }, { 0x0F5B, "Ritech International Ltd." }, { 0x0F5C, "PRAIRIECOMM, INC." }, { 0x0F5D, "NewAge International, LLC" }, { 0x0F5E, "LEADER ELECTRONICS CORP." }, { 0x0F5F, "Key Technology Corporation" }, { 0x0F60, "GuangZhou Chief Tech Electronic Technology Co. Ltd." }, { 0x0F61, "Varian Inc." }, { 0x0F62, "Acrox Technologies Co., Ltd." }, { 0x0F63, "Leapfrog Enterprises" }, { 0x0F64, "ZAE Research, Inc." }, { 0x0F65, "Dataflex Design Communications Limited" }, { 0x0F66, "Toshiba Global Commerce Solutions" }, { 0x0F67, "Quantum3D, Inc." }, { 0x0F68, "UQUEST, LTD." }, { 0x0F69, "DIONEX CORPORATION" }, { 0x0F6A, "Vibren Technologies Inc." }, { 0x0F6B, "OHM ELECTRIC CO., LTD." }, { 0x0F6C, "DnC Tech., Inc." }, { 0x0F6D, "WillPoD Co., Ltd." }, { 0x0F6E, "INTELLIGENT SYSTEMS CO., LTD." }, { 0x0F6F, "Samtec GmbH" }, { 0x0F70, "YOZAN Inc." }, { 0x0F71, "Systems Integration Solutions Inc." }, { 0x0F72, "Robert Bosch GmbH - Chassis Systems Control" }, { 0x0F73, "DFI" }, { 0x0F74, "KOSUGI GIKEN Co, Ltd." }, { 0x0F75, "Future Internet" }, { 0x0F76, "Vacon Plc" }, { 0x0F77, "Fasstech" }, { 0x0F78, "Guntermann & Drunck GmbH" }, { 0x0F79, "Transonic Systems, Inc." }, { 0x0F7A, "EE Tools, Inc." }, { 0x0F7B, "Hivertec Inc." }, { 0x0F7C, "DQ Technology, Inc." }, { 0x0F7D, "NetBotz, Inc." }, { 0x0F7E, "Fluke" }, { 0x0F7F, "Lansmont Corporation" }, { 0x0F80, "OCULUS Optikgeraete GmbH" }, { 0x0F81, "DP Computers Pte. Ltd." }, { 0x0F82, "IMedia Semiconductor Corporation" }, { 0x0F83, "Ernst Reiner GmbH & Co. KG" }, { 0x0F84, "A.E.B. S.R.L." }, { 0x0F85, "IDX Company, Ltd." }, { 0x0F86, "Cedar Audio Limited" }, { 0x0F87, "HUMANDATA LTD." }, { 0x0F88, "VTech Holdings Ltd." }, { 0x0F89, "Leading Edge Co., Ltd." }, { 0x0F8A, "Centro De Tecnologia de las Comunicaciones, S.A." }, { 0x0F8B, "Yazaki Corporation" }, { 0x0F8C, "Young Generation International Corp." }, { 0x0F8D, "Uniwill Computer Corp." }, { 0x0F8E, "Kingnet Technology Co., Ltd." }, { 0x0F8F, "SOMA NETWORKS" }, { 0x0F90, "Quad Engineering Solutions LLC" }, { 0x0F91, "UNIPULSE Corporation" }, { 0x0F92, "JASTEC CO., LTD." }, { 0x0F93, "Sondex Limited" }, { 0x0F94, "FALCOM GmbH" }, { 0x0F95, "TOKYO SOKUSHIN CO., LTD." }, { 0x0F96, "NEC-Mitsubishi Electric Visual Systems Corp." }, { 0x0F97, "CviLux Corporation" }, { 0x0F98, "CYBERBANK CORP." }, { 0x0F99, "Biopia Co., Ltd." }, { 0x0F9A, "Sistel S.R.L." }, { 0x0F9B, "G-Card Technology Co., Ltd." }, { 0x0F9C, "HYUN WON INC." }, { 0x0F9D, "Opteon Corporation" }, { 0x0F9E, "Lucent Technologies" }, { 0x0F9F, "Racewood Technology Co., Ltd." }, { 0x0FA0, "TRITTON TECHNOLOGIES" }, { 0x0FA1, "AIJI System Co., Ltd." }, { 0x0FA2, "TAG Systems Racing Products, Inc." }, { 0x0FA3, "Chief Land Electronic Co., Ltd." }, { 0x0FA4, "ATL Technology" }, { 0x0FA5, "SOTEC CO., LTD." }, { 0x0FA6, "CMD AG" }, { 0x0FA7, "EPOX COMPUTER CO., LTD." }, { 0x0FA8, "Logic Controls, Inc." }, { 0x0FA9, "Shenzhen Motion Control Technology Co., Ltd." }, { 0x0FAA, "Changrime Telecom Co., Ltd." }, { 0x0FAB, "ISZ" }, { 0x0FAC, "Current Stone Co., Ltd." }, { 0x0FAD, "Ultravision Ltd." }, { 0x0FAE, "Redsun Technology Corp." }, { 0x0FAF, "Winpoint Electronic Corp." }, { 0x0FB0, "Haurtian Wire & Cable Co., Ltd." }, { 0x0FB1, "SuperGate Technologies" }, { 0x0FB2, "Conteck Co., Ltd." }, { 0x0FB3, "SYMAGERY MICROSYSTEMS INC." }, { 0x0FB4, "Smiths Detection" }, { 0x0FB5, "NIHON DENJI SOKKI CO., LTD." }, { 0x0FB6, "Heber Ltd." }, { 0x0FB7, "East Press Co., Ltd." }, { 0x0FB8, "Wistron Corporation" }, { 0x0FB9, "AACOM CORPORATION" }, { 0x0FBA, "SAN SHING ELECTRONICS CO., LTD.." }, { 0x0FBB, "Bitwise Systems, Inc." }, { 0x0FBC, "Schick Technologies" }, { 0x0FBD, "Siblings Investment Inc. (dba vantecusa)" }, { 0x0FBE, "Applied Diabetes Research, Inc." }, { 0x0FBF, "Certifiable Innovations" }, { 0x0FC0, "NUDIAN ELECTRON CO., LTD." }, { 0x0FC1, "MITAC INTERNATIONAL CORP." }, { 0x0FC2, "PLUG AND JACK INDUSTRIAL INC." }, { 0x0FC3, "BRAINTREE COMMUNICATIONS" }, { 0x0FC4, "Yamato Electric Industry Co., Ltd." }, { 0x0FC5, "Delcom Engineering" }, { 0x0FC6, "Dataplus Supplies, Inc." }, { 0x0FC7, "BES Technology Group" }, { 0x0FC8, "Phoenix Co., Ltd." }, { 0x0FC9, "Tecom Co., Ltd." }, { 0x0FCA, "BlackBerry Limited" }, { 0x0FCB, "Suzuken Co., Ltd." }, { 0x0FCC, "Marushin-Denshi Co., Ltd." }, { 0x0FCD, "Centurion, Inc." }, { 0x0FCE, "Sony Mobile Communications" }, { 0x0FCF, "Dynastream Innovations Inc." }, { 0x0FD0, "2L international B.V." }, { 0x0FD1, "Giant Electronics Ltd." }, { 0x0FD2, "SEAC BANCHE S.P.A." }, { 0x0FD3, "Marconi Applied Technologies Ltd." }, { 0x0FD4, "Tenovis GmbH & Co., KG" }, { 0x0FD5, "Direct Access Technology, Inc." }, { 0x0FD6, "Mexmal Mayorista S.A. de C.V." }, { 0x0FD7, "Jeulin S.A." }, { 0x0FD8, "LARSEN & BRUSGAARD" }, { 0x0FD9, "El Gato Software LLC" }, { 0x0FDA, "Quantec Networks GmbH" }, { 0x0FDB, "Comtech EF Data" }, { 0x0FDC, "Micro Plus" }, { 0x0FDD, "Yuyama Mfg. Co., Ltd." }, { 0x0FDE, "IDT DATA SYSTEM LIMITED" }, { 0x0FDF, "Foveon Inc." }, { 0x0FE0, "AONEPROTECH Co., Ltd." }, { 0x0FE1, "MADWAVES ApS" }, { 0x0FE2, "Air Techniques, Inc." }, { 0x0FE3, "ACCEL CORP." }, { 0x0FE4, "IN-TECH ELECTRONICS LIMITED" }, { 0x0FE5, "TC&C ELECTRONIC CO.,LTD (SUNTECC, INC.)" }, { 0x0FE6, "Sospita ASA" }, { 0x0FE7, "Mitutoyo Corporation" }, { 0x0FE8, "TurboComm Tech. Inc." }, { 0x0FE9, "DVICO Inc." }, { 0x0FEA, "United Computer Accessories" }, { 0x0FEB, "CRS ELECTRONIC CO., LTD." }, { 0x0FEC, "UMC Electronics Co., Ltd." }, { 0x0FED, "ACCESS CO., LTD." }, { 0x0FEE, "Xsido Corporation" }, { 0x0FEF, "MJ RESEARCH, INC." }, { 0x0FF0, "Physical Electronics" }, { 0x0FF1, "Minato Electronics, Inc." }, { 0x0FF2, "EZMAX CO., LTD." }, { 0x0FF3, "Dimentor" }, { 0x0FF4, "POLYMATECH CO., LTD." }, { 0x0FF5, "OYO-ELECTRIC CO., LTD." }, { 0x0FF6, "Core Valley Co., Ltd." }, { 0x0FF7, "CHI SHING COMPUTER ACCESSORIES CO., LTD." }, { 0x0FF8, "iXs Research Corporation" }, { 0x0FF9, "FHC., Inc. Frederick Haer & Co." }, { 0x0FFA, "ELENTEC CO., LTD." }, { 0x0FFB, "Avail Corporation" }, { 0x0FFC, "Clavia Digital Musical Instruments AB" }, { 0x0FFD, "AKATSUKI ELECTRIC MFG. CO., LTD." }, { 0x0FFE, "ASKA Corporation" }, { 0x0FFF, "Aopen Inc." }, { 0x1000, "Speed Tech Corp." }, { 0x1001, "Ritronics Components (S) Pte. Ltd." }, { 0x1002, "Spa Design Ltd." }, { 0x1003, "SIGMA CORPORATION" }, { 0x1004, "LG Electronics Inc." }, { 0x1005, "Apacer Technology Inc." }, { 0x1006, "Reign Com Ltd." }, { 0x1007, "Samphone Electronic Co., Ltd." }, { 0x1008, "Futaba Corporation" }, { 0x1009, "Lumanate, Inc." }, { 0x100A, "AVC Technology" }, { 0x100B, "Chou Chin Industrial Co., Ltd." }, { 0x100C, "eMachines, inc" }, { 0x100D, "NETOPIA, INC." }, { 0x100E, "North American Pacific Industries, Corp." }, { 0x100F, "Trek Inc." }, { 0x1010, "FUKUDA DENSHI CO., LTD." }, { 0x1011, "Mobile Media Tech." }, { 0x1012, "SDKM Fibres, Wires & Cables Berhad" }, { 0x1013, "TST-Touchless Sensor Technology AG" }, { 0x1014, "Densitron Technologies PLC" }, { 0x1015, "Softronics Pty. Ltd." }, { 0x1016, "Xiamen Hung's Enterprise Co., Ltd." }, { 0x1017, "SPEEDY INDUSTRIAL SUPPLIES PTE. LTD." }, { 0x1018, "Mindtell Inc." }, { 0x1019, "Fostex Corporation" }, { 0x101A, "Annecy Electronique" }, { 0x101B, "Digital Innovations" }, { 0x101C, "Teradyne Diagnostic Solutions Ltd." }, { 0x101D, "Aerospace Information Corporation Limited" }, { 0x101E, "Fronius International GmbH" }, { 0x101F, "Pocketec" }, { 0x1020, "Paten Wireless Technology Inc." }, { 0x1021, "Time Management, Inc." }, { 0x1022, "Shinko Shoji Co., Ltd." }, { 0x1023, "CHRONIX Inc." }, { 0x1024, "ASEC CO., LTD." }, { 0x1025, "Technology Testing Lab" }, { 0x1026, "Newly Corporation" }, { 0x1027, "Time Domain" }, { 0x1028, "Inovys Corporation" }, { 0x1029, "Atlantic Coast Telesys" }, { 0x102A, "RAMOS Technology Co., Ltd." }, { 0x102B, "Infotronic America, Inc." }, { 0x102C, "Etoms Electronics Corp." }, { 0x102D, "Winic Corporation" }, { 0x102E, "Binstead Systems Ltd." }, { 0x102F, "WENZHOU YIHUA CONNECTOR CO.,LTD." }, { 0x1030, "Asoka USA Corporation" }, { 0x1031, "Comax Technology Inc." }, { 0x1032, "C-One Technology Corp." }, { 0x1033, "Nucam Corporation" }, { 0x1034, "Teramecs Co., Ltd." }, { 0x1035, "Cyber Solid Laboratory" }, { 0x1036, "ELLAB A/S" }, { 0x1037, "Red Lion Controls LP" }, { 0x1038, "SteelSeries ApS" }, { 0x1039, "devolo AG" }, { 0x103A, "I+ME ACTIA GmbH" }, { 0x103B, "Quatographic AG" }, { 0x103C, "AMX Corp." }, { 0x103D, "Stanton Magnetics, Inc." }, { 0x103E, "Thurlby-Thandar Instruments Ltd." }, { 0x103F, "Tectech inc." }, { 0x1040, "Valiant Technology Ltd." }, { 0x1041, "Kongsberg Defence Communications AS" }, { 0x1042, "CARDIO SISTEMAS COML. INDL. LTDA." }, { 0x1043, "iCreate Technologies Corporation" }, { 0x1044, "Chu Yuen Enterprise Co., Ltd." }, { 0x1045, "Transiciel Technologies" }, { 0x1046, "Hitachi Asahi Electronics Co., Ltd." }, { 0x1047, "HOYA CORPORATION Vision Care Company" }, { 0x1048, "Targus International LLC" }, { 0x1049, "Studio Technologies, Inc." }, { 0x104A, "WACOH Corporation" }, { 0x104B, "CSM GmbH" }, { 0x104C, "AMCO TEC International Inc." }, { 0x104D, "Newport Corporation" }, { 0x104E, "Halliburton Energy Services" }, { 0x104F, "W B Electronics" }, { 0x1050, "Yubico AB" }, { 0x1051, "Nippon Printer Engineering Inc." }, { 0x1052, "U-Medica Inc." }, { 0x1053, "Immanuel Electronics Co., Ltd." }, { 0x1054, "BMS International Beheer N.V." }, { 0x1055, "Complex Micro Interconnection Co., Ltd." }, { 0x1056, "Hsin Chen Ent Co., Ltd." }, { 0x1057, "ON Semiconductor" }, { 0x1058, "Western Digital, Branded" }, { 0x1059, "Giesecke & Devrient GmbH" }, { 0x105A, "DDS, Inc." }, { 0x105B, "TOKIWA WEST Co., Ltd." }, { 0x105C, "Freeway Electronic Wire & Cable (Dongguan) Co., Ltd." }, { 0x105D, "Delkin Devices, Inc." }, { 0x105E, "Valence Semiconductor Design Limited" }, { 0x105F, "Chin Shong Enterprise Co., Ltd." }, { 0x1060, "Easthome Industrial Co., Ltd." }, { 0x1061, "Cardinal Components Inc." }, { 0x1062, "Sumitomo Electric Industries, Ltd." }, { 0x1063, "LPKF Laser & Electronics AG" }, { 0x1064, "INNOPLUS Co., Ltd." }, { 0x1065, "ImageQuest Co., Ltd." }, { 0x1066, "Eten Information Systems Co., Ltd." }, { 0x1067, "L-3 Communications" }, { 0x1068, "Micropi Elettronica" }, { 0x1069, "Easy Digital Concept" }, { 0x106A, "Loyal Legend Limited" }, { 0x106B, "MED Associates Inc. , sue@med-associates.com" }, { 0x106C, "Curitel Communications, Inc." }, { 0x106D, "San Chieh Manufacturing Ltd." }, { 0x106E, "ConectL" }, { 0x106F, "Money Controls" }, { 0x1070, "TAKAMISAWA CYBERNETICS CO., LTD." }, { 0x1071, "Paxton Access Ltd." }, { 0x1072, "FDI Matelec" }, { 0x1073, "Lifetron Co., Ltd." }, { 0x1074, "TECHNO SOFT SYSTEMNICS INC." }, { 0x1075, "TOKYO KEIKI INC." }, { 0x1076, "GCT Semiconductor, Inc." }, { 0x1077, "VoiceBox Technologies Inc." }, { 0x1078, "Maycom Co., Ltd." }, { 0x1079, "Suisei Electronics System Co., Ltd." }, { 0x107A, "Optionexist Limited" }, { 0x107B, "X E Systems Inc." }, { 0x107C, "Whelen Engineering Company Inc." }, { 0x107D, "Arlec Australia Limited" }, { 0x107E, "MIDORIYA ELECTRIC CO., LTD." }, { 0x107F, "KidzMouse, Inc." }, { 0x1080, "Musetel Co., Ltd." }, { 0x1081, "VG Electracon, Inc." }, { 0x1082, "Shin-Etsukaken Co., Ltd." }, { 0x1083, "CANON ELECTRONICS INC." }, { 0x1084, "PANTECH CO., LTD." }, { 0x1085, "Datalaster" }, { 0x1086, "Smart System Inc." }, { 0x1087, "Shanghai Ewaytek Co., Ltd." }, { 0x1088, "Archtek Telecom Co." }, { 0x1089, "On Track Innovations Ltd." }, { 0x108A, "Chloride Power Protection" }, { 0x108B, "Grand-tek Technology Co., Ltd." }, { 0x108C, "Robert Bosch GmbH" }, { 0x108D, "Mitsui Zosen Systems Research Inc." }, { 0x108E, "Lotes Co., Ltd." }, { 0x108F, "HIOKI E.E. CORPORATION" }, { 0x1090, "DSP Research Inc." }, { 0x1091, "DR. JOHANNES HEIDENHAIN GmbH" }, { 0x1092, "TOPDEK Semiconductor Inc." }, { 0x1093, "SongPro, Inc." }, { 0x1094, "NextEngine, Inc." }, { 0x1095, "Good Work Systems" }, { 0x1096, "NIO Corporation" }, { 0x1097, "Computational Systems Incorporated" }, { 0x1098, "Raytek Corp." }, { 0x1099, "Surface Optics Corporation" }, { 0x109A, "DATASOFT Systems GmbH" }, { 0x109B, "Qingdao Hisense Communication Co., Ltd." }, { 0x109C, "Electronic Trade Solutions Ltd." }, { 0x109D, "NAVIUS CO., LTD." }, { 0x109E, "Finger System Inc." }, { 0x109F, "eSOL Co., Ltd." }, { 0x10A0, "HIROTECH, INC." }, { 0x10A1, "target-systemelectronic gmbh" }, { 0x10A2, "HYUNDAI NETWORKS, INC." }, { 0x10A3, "MITSUBISHI MATERIALS CORPORATION" }, { 0x10A4, "Frontier Silicon Ltd." }, { 0x10A5, "FINGERPRINT CARDS AB" }, { 0x10A6, "SKYUP TECHNOLOGY CORPORATION" }, { 0x10A7, "3i techs Development Corp" }, { 0x10A8, "Imaging Devices, Inc." }, { 0x10A9, "SK Teletech Co., Ltd." }, { 0x10AA, "Cables To Go" }, { 0x10AB, "Universal Global Scientific Industrial Co., Ltd." }, { 0x10AC, "Honeywell, Inc." }, { 0x10AD, "Impact Instrumentation Inc." }, { 0x10AE, "Princeton Technology Corp." }, { 0x10AF, "Liebert Corporation" }, { 0x10B0, "IPmental Inc." }, { 0x10B1, "Safe Valley Inc." }, { 0x10B2, "Data East Corporation" }, { 0x10B3, "Roke Manor Research Limited" }, { 0x10B4, "Guardtec, Inc." }, { 0x10B5, "Comodo" }, { 0x10B6, "Dynojet Research, Inc." }, { 0x10B7, "VSM Medtech Ltd." }, { 0x10B8, "DIBCOM" }, { 0x10B9, "Prime Electronics & Satellitics, Inc." }, { 0x10BA, "Dong-Guan Sintai Optical Co., Ltd." }, { 0x10BB, "TM Technology Inc." }, { 0x10BC, "Dinging Technology Co., Ltd." }, { 0x10BD, "TMT TECHNOLOGY, INC." }, { 0x10BE, "KBM Electronic System Design" }, { 0x10BF, "Smarthome" }, { 0x10C0, "SougaSoft Co., Ltd." }, { 0x10C1, "Kyokuto Electric Co., Ltd." }, { 0x10C2, "Phasespace, Inc." }, { 0x10C3, "Universal Laser Systems" }, { 0x10C4, "Silicon Laboratories, Inc." }, { 0x10C5, "Sanei Electric Inc." }, { 0x10C6, "Intec, Inc." }, { 0x10C7, "Touchstone Technology Co., Ltd." }, { 0x10C8, "SIGMACOM CO., LTD." }, { 0x10C9, "ZUKEN Inc." }, { 0x10CA, "Xrosstech, Inc." }, { 0x10CB, "eratech" }, { 0x10CC, "GBM Connector Co., Ltd." }, { 0x10CD, "Kycon Inc." }, { 0x10CE, "Shinko Electric Co., Ltd." }, { 0x10CF, "Velleman Components" }, { 0x10D0, "Tokai University Educational System" }, { 0x10D1, "HBM GmbH" }, { 0x10D2, "Adams IT Services" }, { 0x10D3, "Trimos SA" }, { 0x10D4, "Man Boon Manufactory Ltd." }, { 0x10D5, "Uni Class Technology Co., Ltd." }, { 0x10D6, "Actions Semiconductor Co., Ltd." }, { 0x10D7, "Array Corporation" }, { 0x10D8, "ACTIKEY S.A." }, { 0x10D9, "Tecnova Corporation" }, { 0x10DA, "HOWTEL CO., LTD." }, { 0x10DB, "Prior Scientific Instruments Ltd." }, { 0x10DC, "Evolve Communications" }, { 0x10DD, "VerNova, Inc." }, { 0x10DE, "Authenex, Inc." }, { 0x10DF, "In-Win Development Inc." }, { 0x10E0, "Bella Corporation" }, { 0x10E1, "CABLEPLUS LTD." }, { 0x10E2, "Nada Electronics, Ltd." }, { 0x10E3, "tec5 AG" }, { 0x10E4, "Trans-Lux Corporation & Subsidiaries" }, { 0x10E5, "MACTek" }, { 0x10E6, "Altotec Hard- und Software GmbH" }, { 0x10E7, "dSPACE GmbH" }, { 0x10E8, "Kumahira Co., Ltd." }, { 0x10E9, "XIA LLC" }, { 0x10EA, "ELITRONIC s.r.o." }, { 0x10EB, "FREEBOX SA" }, { 0x10EC, "Vast Technologies Inc." }, { 0x10ED, "KDS USA, Inc." }, { 0x10EE, "Compuprint" }, { 0x10EF, "Integrity Instruments Inc." }, { 0x10F0, "Etronics Corp." }, { 0x10F1, "Inventec Multimedia & Telecom Corp." }, { 0x10F2, "Autonics Co., Ltd." }, { 0x10F3, "Vercel Development Inc." }, { 0x10F4, "INcoder Technology CO., Ltd." }, { 0x10F5, "Voyetra Turtle Beach, Inc." }, { 0x10F6, "IMAGENICS Co., Ltd." }, { 0x10F7, "Hando Computer Co., Ltd" }, { 0x10F8, "CESYS GmbH" }, { 0x10F9, "NSD Corporation" }, { 0x10FA, "CHINO Corporation" }, { 0x10FB, "Pictos Technologies, Inc." }, { 0x10FC, "MICRELEC" }, { 0x10FD, "Animation Technologies Inc." }, { 0x10FE, "Thrane & Thrane A/S" }, { 0x10FF, "Bellwave" }, { 0x1100, "VirTouch Ltd." }, { 0x1101, "EASYPASS INDUSTRIAL CO., LTD." }, { 0x1102, "Instrument Systems GmbH" }, { 0x1103, "Brain Products GmbH" }, { 0x1104, "TOA Corporation" }, { 0x1105, "MAP Medizin-Technologie GmbH" }, { 0x1106, "OrangeHouse Co., Ltd." }, { 0x1107, "CreamWare GmbH" }, { 0x1108, "BRIGHTCOM TECHNOLOGIES LTD." }, { 0x1109, "LG Industrial Systems Co., Ltd." }, { 0x110A, "Moxa Inc." }, { 0x110B, "NAKI INTERNATIONAL" }, { 0x110C, "Computer Network Technology" }, { 0x110D, "Hitachi Car Engineering Co., Ltd." }, { 0x110E, "Innotrac Diagnostics OY" }, { 0x110F, "OneVision Corporation" }, { 0x1110, "Analog Devices Canada Ltd." }, { 0x1111, "Siemens Healthcare Diagnostics Inc." }, { 0x1112, "Golden Bright (Sichuan) Electronic Technology Co Ltd" }, { 0x1113, "Medion AG" }, { 0x1114, "Psion Teklogix Inc." }, { 0x1115, "Data Link Co., Ltd." }, { 0x1116, "Compro Technology Inc." }, { 0x1117, "11 WAVE TECHNOLOGY, INC." }, { 0x1118, "MotoSAT" }, { 0x1119, "GCS General Control Systems GmbH" }, { 0x111A, "The Nippon Signal Co., Ltd." }, { 0x111B, "Kyusyu Ten Ltd." }, { 0x111C, "point electronic GmbH" }, { 0x111D, "Centon Electronics" }, { 0x111E, "VSO ELECTRONICS CO., LTD." }, { 0x111F, "BANCOR S.R.L." }, { 0x1120, "Voipac, s.r.o." }, { 0x1121, "Kore Technology Limited" }, { 0x1122, "Klein & Melgert Developments B.V." }, { 0x1123, "Hi-Tech Instruments, Inc." }, { 0x1124, "REnex Technology Limited" }, { 0x1125, "Industrial Computing Ltd." }, { 0x1126, "Protonic - Holland" }, { 0x1127, "BANK25 Co., Ltd." }, { 0x1128, "STEAG ETA-Optik GmbH" }, { 0x1129, "Jung Myung Telecom Co., Ltd." }, { 0x112A, "RedRat Ltd." }, { 0x112B, "Stenograph L.L.C." }, { 0x112C, "Ethics Organization of Computer Software" }, { 0x112D, "SYSMEX CORPORATION" }, { 0x112E, "Master Hill Electric Wire and Cable Co., Ltd." }, { 0x112F, "Cellon International" }, { 0x1130, "Tenx Technology, Inc." }, { 0x1131, "Integrated System Solution Corp." }, { 0x1132, "Visoduck discount GmbH" }, { 0x1133, "Sanei Electric Co., Ltd." }, { 0x1134, "Tri-L Data Systems, Inc." }, { 0x1135, "imo-elektronik GmbH" }, { 0x1136, "CTS ELECTRONICS" }, { 0x1137, "Beyond LSI, Inc." }, { 0x1138, "Greenwood Engineering A/S" }, { 0x1139, "Wavetrend" }, { 0x113B, "Hana Micron, Inc." }, { 0x113C, "Arintech Co., Ltd." }, { 0x113D, "Mapower Electronics Co. Ltd." }, { 0x113E, "KDK Electric Wire (H.K.) Co., Ltd." }, { 0x113F, "Integrated Biometrics" }, { 0x1140, "Ultra-Scan Corporation" }, { 0x1141, "V ONE MULTIMEDIA PTE LTD" }, { 0x1142, "CYBERSCAN TECH. INC." }, { 0x1143, "Wako Pure Chemical Industries, Ltd.." }, { 0x1144, "MURATA MACHINERY, LTD." }, { 0x1145, "Japan Radio Co., Ltd." }, { 0x1146, "Shimane SANYO Electric Co., Ltd." }, { 0x1147, "Ever Great Electric Wire and Cable Co., Ltd." }, { 0x1148, "KGS Corporation" }, { 0x1149, "TAMA TECH LAB CORP." }, { 0x114A, "TANITA Corporation (1)" }, { 0x114B, "Sphairon Technologies GmbH" }, { 0x114C, "Tinius Olsen Testing Machine Co., Inc." }, { 0x114D, "Alpha Imaging Technology Corp." }, { 0x114E, "Digital Electronics Corporation" }, { 0x114F, "WAVECOM" }, { 0x1150, "Don Alan Pty. Ltd." }, { 0x1151, "World Wide Licenses Limited" }, { 0x1152, "Codonics, Inc." }, { 0x1153, "Tritec Co., Ltd." }, { 0x1154, "BEB Industrie-Elektronik AG" }, { 0x1155, "DICESVA S.L." }, { 0x1156, "Cybertech bv" }, { 0x1157, "EKS Oy" }, { 0x1158, "Syn-Tech Systems Inc." }, { 0x1159, "Micro Application Laboratory Corp." }, { 0x115A, "Extreme Speed" }, { 0x115B, "Salix Technology Co., Ltd." }, { 0x115C, "CORESMA" }, { 0x115D, "ADTEK SYSTEM SCIENCE CO., LTD." }, { 0x115E, "Group Sense Ltd." }, { 0x115F, "Dataring Systems" }, { 0x1160, "Invocon, Inc." }, { 0x1161, "Port Denshi Co., Ltd." }, { 0x1162, "Secugen Corporation" }, { 0x1163, "DeLorme Publishing Inc." }, { 0x1164, "YUAN High-Tech Development Co., Ltd." }, { 0x1165, "Telson Electronics Co., Ltd." }, { 0x1166, "Bantam Interactive Technologies" }, { 0x1167, "Salient Systems Corporation" }, { 0x1168, "BizConn International Corp." }, { 0x1169, "Adirondack Optics" }, { 0x116A, "JJL Technologies, LLC" }, { 0x116B, "Pigeon Point Systems" }, { 0x116C, "SecureEye, Inc." }, { 0x116D, "Filmetrics, Inc." }, { 0x116E, "Gigastorage Corp." }, { 0x116F, "Silicon 10 Technology Corp." }, { 0x1170, "Tadiran Com. Ltd." }, { 0x1171, "CRE Technology Co., Ltd." }, { 0x1172, "Telegate Co., Ltd." }, { 0x1173, "Esko-Graphics" }, { 0x1174, "Techno-One Co., Ltd." }, { 0x1175, "Sheng Yih Technologies Co., Ltd." }, { 0x1176, "Japan Touchscreen Distributions, Inc." }, { 0x1177, "Hitachi Communication Technologies, Ltd." }, { 0x1178, "Kamaya Electric Co., Ltd." }, { 0x1179, "Bio-logic Systems Corp." }, { 0x117A, "Ishikawa Seisakusho, Ltd." }, { 0x117B, "Primetech Engineering Corporation" }, { 0x117C, "SOFTIDEA s.r.o." }, { 0x117D, "Santa Electronic Inc." }, { 0x117E, "JNC, Inc." }, { 0x117F, "Princeton Technology, Ltd." }, { 0x1180, "Spectra-Physics" }, { 0x1181, "USB NET" }, { 0x1182, "Venture Corporation Limited" }, { 0x1183, "Digital Dream Co. Europe Ltd." }, { 0x1184, "Kyocera Elco Corporation" }, { 0x1185, "Projectiondesign AS" }, { 0x1186, "Scientec System" }, { 0x1187, "Techno Valley Co., Ltd." }, { 0x1188, "Bloomberg L.P." }, { 0x1189, "Trisat IndTry Computer Co. LTD." }, { 0x118A, "KEBA AG" }, { 0x118B, "AXIOMTEK Co., Ltd." }, { 0x118C, "INFINIT GmbH" }, { 0x118D, "Gould Instrument Systems" }, { 0x118E, "Hermstedt AG" }, { 0x118F, "You Yang Technology Co., Ltd." }, { 0x1190, "Tripace" }, { 0x1191, "Loyalty Founder Enterprise Co., Ltd." }, { 0x1192, "Matsusada Precision Inc." }, { 0x1193, "H2I TECHNOLOGIES" }, { 0x1194, "GLORY AZ System Co., Ltd." }, { 0x1195, "ELECTROLINE" }, { 0x1196, "Yankee Robotics, LLC" }, { 0x1197, "Technoimagia Co., Ltd." }, { 0x1198, "StarShine Technology Corp." }, { 0x1199, "Sierra Wireless Inc." }, { 0x119A, "DONG GUAN JALINK ELECTRONICES CO.,LTD" }, { 0x119B, "ruwido austria GmbH" }, { 0x119C, "SK MEDICAL ELECTRONICS CO.,LTD" }, { 0x119D, "Saka-Techno Science Co., Ltd." }, { 0x119E, "Engineered Audio, LLC." }, { 0x119F, "TECNOS CO., LTD." }, { 0x11A0, "Chipcon" }, { 0x11A1, "Mikrap AG" }, { 0x11A2, "SitecSoft Co., Ltd." }, { 0x11A3, "Technovas Co., Ltd." }, { 0x11A4, "THE FURUKAWA ELECTRIC CO., LTD." }, { 0x11A5, "TOKYO RIKAKIKAI CO., LTD." }, { 0x11A6, "VRmagic GmbH" }, { 0x11A7, "SNAPSHIELD LTD." }, { 0x11A8, "Hoeft & Wessel AG" }, { 0x11A9, "Parker Hannifin" }, { 0x11AA, "GlobalMedia Group, LLC" }, { 0x11AB, "Exito Electronics Co., Ltd." }, { 0x11AC, "Nike, Inc." }, { 0x11AD, "SANWA ELECTRIC INSTRUMENT CO., LTD." }, { 0x11AE, "Stoelting Co." }, { 0x11AF, "Valence Semiconductor" }, { 0x11B0, "ATECH FLASH TECHNOLOGY" }, { 0x11B1, "New Motion Tec. Corp." }, { 0x11B2, "Bizerba GmbH & Co. KG" }, { 0x11B3, "MONYA Corporation" }, { 0x11B4, "SPIELO" }, { 0x11B5, "ADVANTECH EQUIPMENT CORP." }, { 0x11B6, "Diskware Co., Ltd." }, { 0x11B7, "Embla" }, { 0x11B8, "CROSS S&T Inc." }, { 0x11B9, "IST Electronics, Inc." }, { 0x11BA, "Sasem Co., Ltd." }, { 0x11BB, "YaMu Solutions" }, { 0x11BC, "Taipei EELY-ECW Co., Ltd." }, { 0x11BD, "UBINETICS LIMITED" }, { 0x11BE, "Martin Professional A/S" }, { 0x11BF, "SonoSite, Inc." }, { 0x11C0, "Sanmos Microelectronics Corp." }, { 0x11C1, "Wako Giken Kogyo Co., Ltd." }, { 0x11C2, "EYESPYFX" }, { 0x11C3, "Kaizen Frogpad, LLC" }, { 0x11C4, "DALLANTBANK, INC." }, { 0x11C5, "INMAX TECHNOLOGY CORP." }, { 0x11C6, "Guzik Technical Enterprises" }, { 0x11C7, "Reliance Electric Limited" }, { 0x11C8, "Fullcom Technology Corp." }, { 0x11C9, "Monster Cable Products, Inc." }, { 0x11CA, "VeriFone" }, { 0x11CB, "Magni Systems, Inc." }, { 0x11CC, "AIM SRL" }, { 0x11CD, "KTEK Co., Ltd." }, { 0x11CE, "Argolis BV" }, { 0x11CF, "Nemoto Kyorindo Co., Ltd." }, { 0x11D0, "TOPCON CORPORATION, Opthalmic & Medical Instrument Dept" }, { 0x11D1, "Far Touch Inc." }, { 0x11D2, "BW Technologies Ltd." }, { 0x11D3, "Elias Technology, Inc." }, { 0x11D4, "Unitac Co., Ltd." }, { 0x11D5, "Polyvision Corporation" }, { 0x11D6, "FUJIFILM AXIA CO., LTD." }, { 0x11D7, "Kokusai Electric Alpha Co., Ltd." }, { 0x11D8, "Zybertek" }, { 0x11D9, "Itronix Corporation" }, { 0x11DA, "Tekscan, Inc." }, { 0x11DB, "Topfield Co., Ltd." }, { 0x11DC, "STELECTRIC A/S" }, { 0x11DD, "DRAGONCHIP LTD." }, { 0x11DE, "La Generale Multimedia" }, { 0x11DF, "ROI Computer AG" }, { 0x11E0, "SUNX Limited" }, { 0x11E1, "Encentuate Pte. Ltd." }, { 0x11E2, "SPECSOFT CONSULTING INC" }, { 0x11E3, "GfS-Hofheim" }, { 0x11E4, "STANDARD ELECTRONICS TELECOM INC." }, { 0x11E5, "CHUFON Technology Co., Ltd." }, { 0x11E6, "K.I. Technology Co. Ltd." }, { 0x11E7, "Rockford Corporation" }, { 0x11E8, "NAAT Technology Corp." }, { 0x11E9, "Wincan Technology Co., Ltd." }, { 0x11EA, "Panram International Corp." }, { 0x11EB, "VTech Innovation L.P. dba Advanced American Telephones" }, { 0x11EC, "Hitachi Computer Peripherals Co., Ltd." }, { 0x11ED, "Shimizu Technology Inc." }, { 0x11EE, "ASAHI ELECTRIC CO., LTD." }, { 0x11EF, "Cableplus Industrial Co., Ltd." }, { 0x11F0, "Matthew Ward Solutions" }, { 0x11F1, "Cal-Comp Electronics (Thailand) Public Co., Ltd." }, { 0x11F2, "Chain Tay Technology Co., Ltd." }, { 0x11F3, "ROUND Co., Ltd." }, { 0x11F4, "Kyoritsu Electric Corporation" }, { 0x11F5, "Siemens Mobile Phones" }, { 0x11F6, "NetIndex Inc." }, { 0x11F7, "ALCATEL BUSINESS SYSTEMS" }, { 0x11F8, "BodyMedia, Inc." }, { 0x11F9, "Cryptocard Corporation" }, { 0x11FA, "Code Corporation" }, { 0x11FB, "HORIBA, Ltd." }, { 0x11FC, "ANCOT CORPORATION" }, { 0x11FD, "EKE-Electronics Ltd." }, { 0x11FE, "SHENZHEN CHANGXUNXING ELECTRONIC CO., LTD." }, { 0x11FF, "LITE STAR ELECTRONICS TECHNOLOGIES, CO. LTD." }, { 0x1200, "Spellman High Voltage Electronics Corp." }, { 0x1201, "Practical Automation, Inc." }, { 0x1202, "KUK JE TONG SHIN CO., LTD." }, { 0x1203, "Taiwan Semiconductor Co., Ltd." }, { 0x1204, "SATEC" }, { 0x1205, "NV ADB TTV TECHNOLOGIES SA" }, { 0x1206, "Synnix Technology Co." }, { 0x1207, "Cardinal Health UK 232 Ltd." }, { 0x1208, "Seiko Epson Corp.- System Device" }, { 0x120A, "Wintest Corp." }, { 0x120B, "Dension Audio Systems Ltd." }, { 0x120C, "ALF, Inc." }, { 0x120D, "(AVL) DiTEST Fahrzeugdiagnose GmbH" }, { 0x120E, "HUDSON SOFT CO., LTD." }, { 0x120F, "Magellan Navigation, Inc." }, { 0x1210, "Harman" }, { 0x1211, "COSMED S.r.l." }, { 0x1212, "D'Crypt Pte Ltd." }, { 0x1213, "Fukko System Co., Ltd." }, { 0x1214, "Dr. Bott KG" }, { 0x1215, "Towa Engineering Corporation" }, { 0x1216, "ProMinent Dosiertechnik GmbH" }, { 0x1217, "Goyatek Technology Inc." }, { 0x1218, "Geutebrueck GmbH" }, { 0x1219, "COMPAL COMMUNICATIONS, INC." }, { 0x121A, "TimeKeeping Systems, Inc." }, { 0x121B, "FEC Inc." }, { 0x121C, "Raysis Co., Ltd." }, { 0x121D, "Intelligent Computer Solutions" }, { 0x121E, "Jungsoft Co., Ltd." }, { 0x121F, "Panini S.P.A." }, { 0x1220, "TC Group A/S" }, { 0x1221, "Averatec, Inc." }, { 0x1222, "Tipro Keyboards D.O.O." }, { 0x1223, "SKYCABLE ENTERPRISE CO., LTD." }, { 0x1224, "SCATT, ZAO" }, { 0x1225, "HI-P Tech Corporation" }, { 0x1226, "Keihin Corporation" }, { 0x1227, "T-RAC INTERNATIONAL, INC." }, { 0x1228, "DATAPAQ" }, { 0x1229, "EPO Science & Technology Inc." }, { 0x122A, "WABCO GmbH & Co., OHG" }, { 0x122B, "Midas Lab Inc." }, { 0x122C, "Qbtech AB" }, { 0x122D, "Hitachi Information & Control Solutions, Ltd." }, { 0x122E, "IOLINE" }, { 0x122F, "Takimaging" }, { 0x1230, "MIPSABG Chipidea, Lda." }, { 0x1231, "CHI MEI COMMUNICATION SYSTEMS, INC." }, { 0x1232, "SolitonWave Co., Ltd." }, { 0x1233, "Targa Systems Div. L-3 Communications" }, { 0x1234, "Micro Science Co., Ltd." }, { 0x1235, "Focusrite Audio Engineering Ltd" }, { 0x1236, "Nozaki Insatsu Shigyo Co., Ltd." }, { 0x1237, "Technowave Ltd." }, { 0x1238, "Bridgekey Corp." }, { 0x1239, "Antex Electronics" }, { 0x123A, "Spectra Technologies Holdings Co., Ltd." }, { 0x123B, "De La Rue Systems Automatizacao" }, { 0x123C, "K-Won C & C Co., Ltd." }, { 0x123D, "Microplex Printware AG" }, { 0x123E, "A.T. WORKS, Inc." }, { 0x123F, "DURAPOWER TECHNOLOGY LTD." }, { 0x1240, "HUMUS MOG CO., LTD." }, { 0x1241, "OTSUKA ELECTRONICS CO., LTD." }, { 0x1242, "MAC SYSTEM CO., LTD." }, { 0x1243, "Fujikura Ltd., Fiber Optic System Division" }, { 0x1244, "DResearch Digital Media Systems GmbH" }, { 0x1245, "R/D Tech Inc." }, { 0x1246, "CTO S.p.A." }, { 0x1247, "JAPAN PRECISION INSTRUMENTS, INC." }, { 0x1248, "Vector Informatik GmbH" }, { 0x1249, "TRACESPAN Communications Ltd." }, { 0x124A, "AirVast Technology Inc." }, { 0x124B, "NYKO Technologies, Inc." }, { 0x124C, "MEMORY EXPERTS International Inc." }, { 0x124D, "Just Rams PLC" }, { 0x124E, "YEM Inc." }, { 0x124F, "Beijing JingHuiJiaDe Tech. Co., Ltd." }, { 0x1250, "TECMAG" }, { 0x1251, "Iwaya Corporation" }, { 0x1252, "Nextway Co., Ltd." }, { 0x1253, "Erebus Limited" }, { 0x1254, "Empirical Systems" }, { 0x1255, "ASCII Solutions, Inc." }, { 0x1256, "Spectronic Denmark A/S" }, { 0x1257, "AudioScience" }, { 0x1258, "Continental Automotive Trading UK Ltd." }, { 0x1259, "Deutsche Montan Technologie GmbH" }, { 0x125A, "Shintake Sangyo Co., Ltd." }, { 0x125B, "VIDEX" }, { 0x125C, "Apogee Instruments, Inc." }, { 0x125D, "Advanced Technology (UK) PLC" }, { 0x125E, "Bosch Automotive Service Solutions" }, { 0x125F, "ADATA Technology Co., Ltd." }, { 0x1260, "Cores Inc." }, { 0x1261, "All Ring Tech Co., Ltd." }, { 0x1262, "MICRO VISION CO., LTD." }, { 0x1263, "Opti Japan Corporation" }, { 0x1264, "Covidien Energy-based Devices" }, { 0x1265, "Good Mind Industries Co., Ltd." }, { 0x1266, "Pirelli Cavi e Sistemi Telecom S.p.A." }, { 0x1267, "SILCOR" }, { 0x1268, "icube Corp." }, { 0x1269, "Sequoia Voting Systems Inc." }, { 0x126A, "CHH Electronics Ltd." }, { 0x126B, "Veridian Systems" }, { 0x126C, "Aristocrat Technologies" }, { 0x126D, "Bel Stewart" }, { 0x126E, "Strobe Data, Inc." }, { 0x126F, "TwinMOS Technologies ME FZE" }, { 0x1270, "Procomp Informatics Ltd." }, { 0x1271, "Foxda Technology Industrial (Shenzhen) Co., Ltd." }, { 0x1272, "Linear Technology Corporation" }, { 0x1273, "HANEX Co., Ltd." }, { 0x1274, "Matin, Inc." }, { 0x1275, "Xaxero Marine Software Engineering Ltd." }, { 0x1276, "QVS" }, { 0x1277, "Silicon Media Inc." }, { 0x1278, "Starlight Xpress Ltd." }, { 0x1279, "Cheesecote Mountain Camac" }, { 0x127A, "Electrophysics Corp." }, { 0x127B, "The Technology Partnership (TTP)" }, { 0x127C, "Comarco Wireless" }, { 0x127D, "RAiO Technology Inc." }, { 0x127E, "Hugelent Telecommunication (SuZhou) Co., Ltd." }, { 0x127F, "IPACS Hans-Borchers-Gruentjens GbR (IPACS)" }, { 0x1280, "Animeta Systems Inc." }, { 0x1281, "Gean Sen Electronic Co., Ltd." }, { 0x1282, "Falco Electronics Mexico" }, { 0x1283, "zebris Medizintechnik GmbH" }, { 0x1284, "YEC Co., Ltd." }, { 0x1285, "Schindler Aufzuge AG" }, { 0x1286, "MARVELL SEMICONDUCTOR, INC." }, { 0x1287, "Infomove Co., Ltd." }, { 0x1288, "Micro Advantage Inc." }, { 0x1289, "Nippon Telesoft Co., Ltd." }, { 0x128A, "Asia Vital Components Co., Ltd." }, { 0x128B, "Medicapture, Inc." }, { 0x128C, "ITW Food Equipment Group, LLC dba Hobart Corporation" }, { 0x128D, "Testo AG" }, { 0x128E, "Stormblue Co., Ltd." }, { 0x128F, "Guidant Corporation" }, { 0x1290, "Musicus GmbH" }, { 0x1291, "Flarion Technologies" }, { 0x1292, "Fire International Ltd." }, { 0x1293, "Mitsubishi Electric Engineering Co., Ltd." }, { 0x1294, "RISO KAGAKU CORP." }, { 0x1295, "A & G Souzioni Digitali" }, { 0x1296, "RadioScape" }, { 0x1297, "DEKTEC Digital Video B.V." }, { 0x1298, "Genlyte Controls" }, { 0x1299, "DGStation Co., Ltd." }, { 0x129A, "PULSTEC INDUSTRIAL CO., LTD." }, { 0x129B, "CyberTAN Technology Inc." }, { 0x129C, "Min Aik Technology Co., Ltd." }, { 0x129D, "Yueqing Longhua Electronics Factory" }, { 0x129E, "Aceeca Limited" }, { 0x129F, "Howtek Devices Corp." }, { 0x12A0, "CDC Point S.p.A." }, { 0x12A1, "Tohken Co., Ltd." }, { 0x12A2, "E28 (Shanghai) Ltd." }, { 0x12A3, "KENT WORLD CO., LTD." }, { 0x12A4, "Guangdong Matsunichi Communications Technology Co., Ltd" }, { 0x12A5, "Sola/Hevi-Duty" }, { 0x12A6, "ULVAC-PHI, Inc." }, { 0x12A7, "Trendchip Technologies Corp." }, { 0x12A8, "Clovertech Inc." }, { 0x12A9, "Sunwave Technology Corp." }, { 0x12AA, "Bustec Production Ltd." }, { 0x12AB, "Honey Bee (Hong Kong) Limited" }, { 0x12AC, "Compact Light System Norway A/S" }, { 0x12AD, "Asahi Seiko Co., Ltd." }, { 0x12AE, "Matsunichi Communication Holdings Limited" }, { 0x12AF, "Baldor UK Ltd." }, { 0x12B0, "Axciton Systems, Inc." }, { 0x12B1, "HIMECS CO., LTD." }, { 0x12B2, "DICKSON Company" }, { 0x12B3, "Megaforce Company Ltd." }, { 0x12B4, "Hanchang System Corporation" }, { 0x12B5, "World Touch Gaming , Inc." }, { 0x12B6, "Naito Densei Machida Mfg. Co., Ltd." }, { 0x12B7, "Genesis Microchip Inc." }, { 0x12B8, "Zhejiang Xinya Electronic Technology Co., Ltd." }, { 0x12B9, "Freehand Systems, Inc." }, { 0x12BA, "Sony Computer Entertainment America" }, { 0x12BB, "Paltronics, Inc." }, { 0x12BC, "Hakusan Corporation" }, { 0x12BD, "Sun Light Application Co., Ltd." }, { 0x12BE, "Dynex Technologies" }, { 0x12BF, "Matrix Multimedia Ltd." }, { 0x12C0, "Sencore, Inc." }, { 0x12C1, "ARTRAY CO., LTD." }, { 0x12C2, "HHB Communications Ltd." }, { 0x12C3, "Fiso Technologies, Inc." }, { 0x12C4, "Autocue Ltd." }, { 0x12C5, "XN Technologies, Inc." }, { 0x12C6, "Bosch Security Systems" }, { 0x12C7, "Hismartech Co., Ltd." }, { 0x12C8, "XiMeta Inc." }, { 0x12C9, "Newmen Technology Corp. Ltd." }, { 0x12CA, "Cables To Go International Manufacturing Co., Ltd." }, { 0x12CB, "Dallmeier electronic GmbH" }, { 0x12CC, "Printherm" }, { 0x12CD, "Cables Unlimited" }, { 0x12CE, "Hakko Electronics Co., Ltd." }, { 0x12CF, "Dexin Corporation" }, { 0x12D0, "ITG Research & Development Center" }, { 0x12D1, "Huawei Technologies Co., Ltd." }, { 0x12D2, "LINE TECH INDUSTRIAL CO., LTD." }, { 0x12D3, "Linak A/S" }, { 0x12D4, "Infonics Pty. Limited" }, { 0x12D5, "Strategic Vista Corp." }, { 0x12D6, "EMS Dr. Thomas Wuensche" }, { 0x12D7, "Better Holdings (HK) Limited" }, { 0x12D8, "Araneus Information Systems Oy" }, { 0x12D9, "DIGITFAB INTERNATIONAL CO., LTD." }, { 0x12DA, "Simavionics, Inc." }, { 0x12DB, "Planar Systems, Inc." }, { 0x12DC, "MMGEAR Co., Ltd." }, { 0x12DD, "JFE Advantech Co., Ltd." }, { 0x12DE, "National Display Systems" }, { 0x12DF, "Sumitomo 3M Limited" }, { 0x12E0, "Electronica Mecanica Y Control S.A." }, { 0x12E1, "FDK CORPORATION" }, { 0x12E2, "Bonso Electronic Ltd." }, { 0x12E3, "1417188 Ontario Ltd." }, { 0x12E4, "Bruel & Kjaer Sound & Vibration Meas. A/S" }, { 0x12E5, "Interactive Computer Products, Inc." }, { 0x12E6, "Waldorf-Music AG" }, { 0x12E7, "Sugiyama Electron Co., Ltd." }, { 0x12E8, "ZAN Messgeraete" }, { 0x12E9, "Mindspeed Technologies" }, { 0x12EA, "Microlink Systems" }, { 0x12EB, "MITSUI & CO., LTD." }, { 0x12EC, "KYORITSU ELECTRICAL INSTRUMENTS WORKS, LTD. (R&D Center" }, { 0x12ED, "Techno Kit Corporation" }, { 0x12EE, "Avery Dennison Deutschland GmbH" }, { 0x12EF, "Tapwave, Inc." }, { 0x12F0, "KROHNE" }, { 0x12F1, "OHIRA GIKEN, IND. CO., LTD." }, { 0x12F2, "VIEWPLUS TECHNOLOGIES, INC." }, { 0x12F3, "FORMOSA TELETEK CORPORATION" }, { 0x12F4, "Glovic Electronics Corp." }, { 0x12F5, "Dynamic System Electronics Corp." }, { 0x12F6, "Aichi Tokei Denki Co., Ltd." }, { 0x12F7, "Memorex Products, Inc." }, { 0x12F8, "Evolution Technologies, Inc." }, { 0x12F9, "RF-LINK SYSTEMS, INC." }, { 0x12FA, "RF Micro Devices" }, { 0x12FB, "SSD JAPAN CO., Ltd" }, { 0x12FC, "eGenium S.r.l." }, { 0x12FD, "AIN COMM. TECHNOLOGY CO., LTD." }, { 0x12FE, "E.U CONNECTOR(M) SDN BHD." }, { 0x12FF, "Fascinating Electronics, Inc." }, { 0x1300, "Muscle Corporation" }, { 0x1301, "Woehler Messgeraete Kehrgeraete GmbH" }, { 0x1302, "Wildseed Ltd." }, { 0x1303, "Lloyd Research (Projects) Ltd." }, { 0x1304, "MEDIALINK-I, Inc." }, { 0x1305, "ELSE Ltd." }, { 0x1306, "Torcon Instruments Inc." }, { 0x1307, "USBest Technology Inc." }, { 0x1308, "Precision Photonics Corp." }, { 0x1309, "Sabine, Inc." }, { 0x130A, "SIBATA SCIENTIFIC TECHNOLOGY, LTD." }, { 0x130B, "MPC Products" }, { 0x130C, "Quest Technologies" }, { 0x130D, "Loyal Technology Corporation" }, { 0x130E, "Microlink Communications Inc." }, { 0x130F, "AGFA NDT, Krautkramer Ultrasonic Systems" }, { 0x1310, "Air2U Inc." }, { 0x1311, "EDX Epi-Scan Corp" }, { 0x1312, "ICS Electronics" }, { 0x1313, "THORLABS, INC" }, { 0x1314, "Ryoko Electric Co., Ltd." }, { 0x1315, "Prairie Systems & Equip. Ltd. O/A Massload Technologies" }, { 0x1316, "JUNGLE Inc" }, { 0x1317, "PC-CRAFT Co., Ltd." }, { 0x1318, "O'RITE TECHNOLOGY Co., Ltd." }, { 0x1319, "Peekel Instruments B.V." }, { 0x131A, "VERYWELL CO., LTD." }, { 0x131B, "Rowley Associates Ltd." }, { 0x131C, "Staples, Inc." }, { 0x131D, "Natural Point" }, { 0x131E, "Duerr Dental GmbH & Co., KG" }, { 0x131F, "Ayuttha Technology Corp." }, { 0x1320, "Jaguar International Corporation" }, { 0x1321, "Lectrosonics, Inc." }, { 0x1322, "Z/I Imaging" }, { 0x1323, "Zeustech Company Limited" }, { 0x1324, "H-Mod, Inc." }, { 0x1325, "Austriamicrosystems AG" }, { 0x1326, "Force Control Industries Inc." }, { 0x1327, "Avtec, Inc." }, { 0x1328, "Iris Power Engineering" }, { 0x1329, "Appairent Technologies, Inc." }, { 0x132A, "Envara" }, { 0x132B, "Konica Minolta, Inc." }, { 0x132C, "Le Prestique International (H.K.) Ltd." }, { 0x132D, "GE Healthcare Life Sciences" }, { 0x132E, "Kwang Jang Corporation" }, { 0x132F, "ViALUX GmbH" }, { 0x1330, "ALFANUCLEAR S.A." }, { 0x1331, "Panic Inc." }, { 0x1332, "Moral Follow System Co., Ltd." }, { 0x1333, "Ultra Electronics Precision Air & Land Systems" }, { 0x1334, "ADC Corporation" }, { 0x1335, "PLUS Corporation" }, { 0x1336, "IMM-Gruppe" }, { 0x1337, "Radiant Networks Plc" }, { 0x1338, "IT CONCEPTS LLC" }, { 0x1339, "Akashi Corporation" }, { 0x133A, "Vyyo Inc." }, { 0x133B, "FLASH SUPPORT GROUP, INC." }, { 0x133C, "G-Design Technology" }, { 0x133D, "Jasco Products Company" }, { 0x133E, "Kemper Digital GmbH" }, { 0x133F, "Hwayoung RF Solution Inc." }, { 0x1340, "Escherlogic Inc." }, { 0x1341, "Lavry Engineering" }, { 0x1342, "Sutter Instrument Company" }, { 0x1343, "Heiwa Tokei Mfg. Co., Ltd" }, { 0x1344, "TCI, Inc. d/b/a TCI Medical" }, { 0x1345, "Sino Lite Technology Corp." }, { 0x1346, "Mediatek Corp." }, { 0x1347, "Moravian Instruments, Inc." }, { 0x1348, "Katsuragawa Electric Co., Ltd." }, { 0x1349, "Esaote/Pie Medical Equipment" }, { 0x134A, "iX Group" }, { 0x134B, "El Pusk Co., Ltd." }, { 0x134C, "Panjit International Inc." }, { 0x134D, "Danfoss Drives A/S" }, { 0x134E, "Digby's Bitpile, Inc. D.B.A. D Bit" }, { 0x134F, "Addvalue Communications Pte Ltd." }, { 0x1350, "UniqueICs, LLC" }, { 0x1351, "Crossware Associates" }, { 0x1352, "Km2Net" }, { 0x1353, "Shenzhen Coship Software Co., Ltd." }, { 0x1354, "FACTS Engineering LLC" }, { 0x1355, "Ethicon Endo-Surgery, Inc." }, { 0x1356, "Techpoint Electric Wire & Cable Co., Ltd." }, { 0x1357, "P & E Microcomputer Systems, Inc." }, { 0x1358, "SKYLIGHT DIGITAL INC." }, { 0x1359, "RKC INSTRUMENT INC." }, { 0x135A, "URMET TLC S.p.A. - Servizio Amministrativo" }, { 0x135B, "M-System Co., Ltd." }, { 0x135C, "Real-Time Essentials, Inc." }, { 0x135D, "ALGOTEX SRL" }, { 0x135E, "Insta Elektro GmbH" }, { 0x135F, "Control Development, Inc." }, { 0x1360, "FREETRON COM LTD." }, { 0x1361, "Thinktel Korea Co., Ltd." }, { 0x1362, "IMAGICA Corp." }, { 0x1363, "Axsun Technologies, Inc." }, { 0x1364, "SHARP TAKAYA ELECTRONICS INDUSTRY CO., LTD." }, { 0x1365, "TOYO JIKI INDUSTRY CO., LTD." }, { 0x1366, "SEGGER Microcontroller Systems GmbH" }, { 0x1367, "The Soundbeam Project" }, { 0x1368, "TelePaq Technology Inc." }, { 0x1369, "FASL LLC." }, { 0x136A, "Pelco" }, { 0x136B, "STEC" }, { 0x136C, "Datastor Technology Co., Ltd." }, { 0x136D, "Brainchild" }, { 0x136E, "Andor Technology" }, { 0x136F, "Nielsen Media Research" }, { 0x1370, "Swissbit AG" }, { 0x1371, "Micro Technology Co., Ltd." }, { 0x1372, "AMAC Tek Co., Ltd." }, { 0x1373, "Radical Research, Inc." }, { 0x1374, "American Anko Co." }, { 0x1375, "TCL MOBILE COMMUNICATION CO., LTD." }, { 0x1376, "Vimtron Electronics Co., Ltd." }, { 0x1377, "Sennheiser Electronic" }, { 0x1378, "HIRATA Corporation" }, { 0x1379, "Inprocomm, Inc." }, { 0x137A, "Weldon Technologies, Inc." }, { 0x137B, "SCAPS GmbH" }, { 0x137C, "Yaskawa Electric Corporation" }, { 0x137D, "Diodes Incorporated" }, { 0x137E, "XL Microwave, Inc." }, { 0x137F, "Sata Hi Tech Services" }, { 0x1380, "Staveley Instruments" }, { 0x1381, "N-LINE SYSTEM CO., LTD." }, { 0x1382, "Systemware Inc." }, { 0x1383, "Application Corporation" }, { 0x1384, "Device Drivers Limited" }, { 0x1385, "Variscite Ltd." }, { 0x1386, "SCD Tech Inc." }, { 0x1387, "Advanced Technical Group" }, { 0x1388, "Southern Vision Systems, Inc." }, { 0x1389, "Coolnection Technology Co., Ltd." }, { 0x138A, "Validity Inc." }, { 0x138B, "AMS Limited, Integrated Systems" }, { 0x138C, "Fortemedia, Inc." }, { 0x138D, "CPI GmbH" }, { 0x138E, "RAISONANCE" }, { 0x138F, "Saia-Burgess Controls Ltd." }, { 0x1390, "TomTom International B.V." }, { 0x1391, "IdealTEK" }, { 0x1392, "SAGE INSTRUMENTS" }, { 0x1393, "ELNEC s.r.o." }, { 0x1394, "Gemini 2000 Ltd." }, { 0x1395, "Sennheiser Communications A/S" }, { 0x1396, "Greenliant Systems, Inc." }, { 0x1397, "Behringer Spezielle Studiotechnik GmbH" }, { 0x1398, "Nintendo of America" }, { 0x1399, "Thai Wonderful Wire Cable Co., Ltd." }, { 0x139A, "Infinitec Co., Ltd." }, { 0x139B, "Thomas Enterprises, Inc." }, { 0x139C, "Deltronics" }, { 0x139D, "Digisafe Pte. Ltd." }, { 0x139E, "Valueplus Inc." }, { 0x139F, "Audio Technology Switzerland SA" }, { 0x13A0, "Essilor International" }, { 0x13A1, "Canas Co., Ltd." }, { 0x13A2, "Pesa Switching Systems, Inc." }, { 0x13A3, "Dynon Instruments" }, { 0x13A4, "Equipment Systems & Devices" }, { 0x13A5, "Sammy Corporation" }, { 0x13A6, "Jeppesen Sanderson Inc." }, { 0x13A7, "Circuit Design, Inc." }, { 0x13A8, "Grandtec Electronic Corp" }, { 0x13A9, "YAMAMOTO-MS CO., LTD." }, { 0x13AA, "Sinar Electronics Limited" }, { 0x13AB, "MicroMade Galka i Drozdz sp.j" }, { 0x13AC, "DAQ Systems" }, { 0x13AD, "Baltech AG" }, { 0x13AE, "CIM-USA Inc." }, { 0x13AF, "Handheld Entertainment" }, { 0x13B0, "PerkinElmer Optoelectronics" }, { 0x13B1, "Cisco-Linksys, LLC" }, { 0x13B2, "ALESIS" }, { 0x13B3, "Nippon Dics Co., Ltd." }, { 0x13B4, "Dolch Computer Systems" }, { 0x13B5, "INVENTECH, INC." }, { 0x13B6, "ISABELLENHUETTE Heusler GmbH KG" }, { 0x13B7, "Keymark Technology Co., Ltd." }, { 0x13B8, "PDM Electronic Co., Ltd." }, { 0x13B9, "Cimcore" }, { 0x13BA, "Yung Ray Technology Co., Ltd." }, { 0x13BB, "Covidien Respiratory and Monitoring Solutions" }, { 0x13BC, "Imaging Supersonic Laboratories Co., Ltd." }, { 0x13BD, "Remote Technologies, Inc." }, { 0x13BE, "Ricoh Printing Systems, Ltd." }, { 0x13BF, "Accusys, Inc." }, { 0x13C0, "Stream Labs" }, { 0x13C1, "Vivitar Corporation" }, { 0x13C2, "SATO KEIRYOKI MFG. CO., LTD." }, { 0x13C3, "SCT Performance, LLC" }, { 0x13C4, "StationZ Inc." }, { 0x13C5, "MELFAS, INC." }, { 0x13C6, "Hasointech Co., Ltd." }, { 0x13C7, "ANDO ELECTRIC CO., LTD." }, { 0x13C8, "Togami Electric Mfg. Co., Ltd." }, { 0x13C9, "LinearX Systems Inc." }, { 0x13CA, "JyeTai Precision Industrial Co., Ltd." }, { 0x13CB, "JTEK Technology Corporation" }, { 0x13CC, "Cellvic Corporation" }, { 0x13CD, "ABCD Aging Biorhythms and Computer Diagnostics GmbH" }, { 0x13CE, "Cypherix (Pty) Ltd." }, { 0x13CF, "Wisair Ltd." }, { 0x13D0, "Swedect AB" }, { 0x13D1, "A-Max Technology Macao Commercial Offshore Co. Ltd." }, { 0x13D2, "Intelligraphics, Inc." }, { 0x13D3, "AzureWave Technologies, Inc." }, { 0x13D4, "IWATSU TEST INSTRUMENTS CORPORATION" }, { 0x13D5, "International Electronics Inc." }, { 0x13D6, "Appside" }, { 0x13D7, "Tableau, LLC" }, { 0x13D8, "University of Stirling" }, { 0x13D9, "Blazepoint Limited" }, { 0x13DA, "OPTEX CO., LTD." }, { 0x13DB, "Zastron Electronic (Shenzhen) Co. Ltd." }, { 0x13DC, "ALEREON, INC." }, { 0x13DD, "i.Tech Dynamic Limited" }, { 0x13DE, "LANKOM ELECTRONICS CO., LTD." }, { 0x13DF, "Good Fancy Enterprise Co., Ltd." }, { 0x13E0, "Taiwan Silicon Electronics Corp." }, { 0x13E1, "Kaibo Wire & Cable (Shenzhen) Co., Ltd." }, { 0x13E2, "Parallax, Inc." }, { 0x13E3, "SoniqCast, LLC" }, { 0x13E4, "Audio Precision" }, { 0x13E5, "Sigma Audio Research Ltd." }, { 0x13E6, "TechnoScope Co., Ltd." }, { 0x13E7, "Gantner Pigeon Systems GmbH" }, { 0x13E8, "PalmSource Inc." }, { 0x13E9, "Ununpentium, LLC" }, { 0x13EA, "I/F - COM A/S" }, { 0x13EB, "PILZ GMBH & CO. KG" }, { 0x13EC, "Chyau Yuan Technology Co., Ltd." }, { 0x13ED, "Wooju Communications Co., Ltd." }, { 0x13EE, "ATLab Inc." }, { 0x13EF, "Turner Technology" }, { 0x13F0, "DIGENT CO., Ltd." }, { 0x13F1, "AP Instruments" }, { 0x13F2, "Tech Micro Corporation" }, { 0x13F3, "Amulet Hotkey" }, { 0x13F4, "Verisity Design Inc." }, { 0x13F5, "X-TEL Communications, Inc." }, { 0x13F6, "Aspen Touch Solutions, Inc." }, { 0x13F7, "Corevalley Co., Ltd." }, { 0x13F8, "EZPnP Technologies Corp." }, { 0x13F9, "Impsys Digital Security AB" }, { 0x13FA, "Radiantech, Inc." }, { 0x13FB, "Noritsu Koki Co., Ltd." }, { 0x13FC, "Compucat Research Pty Limited" }, { 0x13FD, "Initio (HK) Corporation Limited" }, { 0x13FE, "Phison Electronics Corp." }, { 0x13FF, "VIEWCON ELECTRONIC LTD." }, { 0x1400, "Axxion Group Corp." }, { 0x1401, "Fulhua Microelectronics Corp." }, { 0x1402, "Bowe Bell & Howell" }, { 0x1403, "Sitronix Technology Corp." }, { 0x1404, "Fundamental Software Incorporated" }, { 0x1405, "Cooper Security Ltd." }, { 0x1406, "Systemneeds, Inc." }, { 0x1407, "Coin Mechanisms Inc." }, { 0x1408, "Comark Ltd." }, { 0x1409, "IDS Imaging Development Systems GmbH" }, { 0x140A, "Koyo Electronics Industries Co., Ltd." }, { 0x140B, "Vertex Standard Co., Ltd." }, { 0x140C, "MITS Electronics" }, { 0x140D, "Japan Novel Corporation" }, { 0x140E, "Telechips, Inc." }, { 0x140F, "i-WAVER" }, { 0x1410, "Novatel Wireless, Inc." }, { 0x1411, "SKIDATA AG" }, { 0x1412, "IMADA CO., LTD." }, { 0x1413, "Telsey S.p.A." }, { 0x1415, "Sony Computer Entertainment Europe" }, { 0x1416, "Axeon Limited" }, { 0x1417, "Butterfly Media" }, { 0x1418, "MediaPower Technology Corporation" }, { 0x1419, "ABILITY ENTERPRISE CO., LTD." }, { 0x141A, "Realm Systems Inc." }, { 0x141B, "METRAWARE" }, { 0x141C, "Leviton Manufacturing" }, { 0x141D, "J.FIT Co., Ltd." }, { 0x141E, "Ikegami Tsushinki Co., Ltd." }, { 0x141F, "SHIMADZU CORPORATION" }, { 0x1420, "Lyrtech Inc." }, { 0x1421, "Sentech Co., Ltd." }, { 0x1422, "Bird Electronic Corporation" }, { 0x1423, "ANCA Pty. Ltd." }, { 0x1424, "Posnet Polska S.A." }, { 0x1425, "IBEX Technology Co., Ltd." }, { 0x1426, "NADEX Co., Ltd." }, { 0x1427, "Global Display Solutions S.P.A." }, { 0x1428, "Improvision Ltd." }, { 0x1429, "Vega Technologies Industrial (Austria) Co." }, { 0x142A, "Thales-e-Transactions" }, { 0x142B, "Arbiter Systems, Inc." }, { 0x142C, "SOMA OPTICS, LTD." }, { 0x142D, "Sanblaze Technology, Inc." }, { 0x142E, "TAMS Inc." }, { 0x142F, "IO Display Systems" }, { 0x1430, "Activision" }, { 0x1431, "Pertech Resources, Inc." }, { 0x1432, "Beijing Watertek Information Technology Co., Ltd." }, { 0x1433, "TRANWO TECHNOLOGY CORP." }, { 0x1434, "Comart System Co., Ltd." }, { 0x1435, "Wistron NeWeb Corp." }, { 0x1436, "Denali Software, Inc." }, { 0x1437, "Carl Zeiss" }, { 0x1438, "My3ia (Beijing) Technology Ltd." }, { 0x1439, "Wind River Systems Inc." }, { 0x143A, "CP Technologies" }, { 0x143B, "RHESCA Company Limited" }, { 0x143C, "Altek Corporation" }, { 0x143D, "FUKOKU INDUSTRY CO., LTD." }, { 0x143E, "IAV GmbH" }, { 0x143F, "IDEC IZUMI CORPORATION" }, { 0x1440, "Jaalaa, Inc." }, { 0x1441, "MARIAN GbR" }, { 0x1442, "Canadian Bank Note Company, Limited" }, { 0x1443, "Digilent Inc." }, { 0x1444, "H & S Instruments Inc." }, { 0x1445, "JUSTER CO., LTD." }, { 0x1446, "X.J. Group Ltd." }, { 0x1447, "Cognex Corporation" }, { 0x1448, "Biosystems LLC" }, { 0x1449, "SHIMADEN CO., LTD." }, { 0x144A, "Megger" }, { 0x144B, "MADENTEC LTD." }, { 0x144C, "Always On UPS Systems Inc." }, { 0x144D, "K-SUN Corporation" }, { 0x144E, "Westar Corporation" }, { 0x144F, "K-jump Health Co., Ltd." }, { 0x1450, "Melec Inc." }, { 0x1451, "Force Dimension LLC" }, { 0x1452, "DAI NIPPON PRINTING CO., LTD." }, { 0x1453, "Epilog Corporation" }, { 0x1454, "China IWNCOMM Co., Ltd." }, { 0x1455, "Georgia Technology Corp." }, { 0x1456, "Extending Wire & Cable Co., Ltd." }, { 0x1457, "DAE-A Mediatech Co., Ltd." }, { 0x1458, "Rauland-Borg Corporation" }, { 0x1459, "Shanghai Simax Micro-electronics Co., Ltd." }, { 0x145A, "All-Systems Electronics Pty. Ltd." }, { 0x145B, "Lead-Type Precision Electronics Co., Ltd." }, { 0x145C, "Busch-Jaeger-Elektro GmbH" }, { 0x145D, "Sopac Ltd." }, { 0x145E, "Forschungszentrum Karlsruhe GmbH" }, { 0x145F, "Trust International BV" }, { 0x1460, "TATUNG Company" }, { 0x1461, "Staccato Communications" }, { 0x1462, "Bright Computech Co., Ltd." }, { 0x1463, "BBWM Corp." }, { 0x1464, "Asiamajor Inc." }, { 0x1465, "Michilin Prosperity Co., Ltd." }, { 0x1466, "H2 Developer Group" }, { 0x1467, "Clearly Superior Technologies" }, { 0x1468, "CSE Co., Ltd." }, { 0x1469, "ELECTRIM CORPORATION" }, { 0x146A, "Knobloch GmbH" }, { 0x146B, "BigBen Interactive Limited" }, { 0x146C, "HETEC Datensysteme GmbH" }, { 0x146D, "Progeny Inc." }, { 0x146E, "ClearOne Communications" }, { 0x146F, "Unity Electrical Ind. Ltd." }, { 0x1470, "STARRIVER TECHNOLOGY CO., LTD." }, { 0x1471, "Open Labs, Inc." }, { 0x1472, "Hangzhou H3C Technologies Co., Ltd." }, { 0x1473, "Dingo Incorporated" }, { 0x1474, "Lamp Express USA, Inc." }, { 0x1475, "NAC Image Technology Incorporated" }, { 0x1476, "Westech Korea Inc." }, { 0x1477, "XIROKU INC." }, { 0x1478, "Link World Electric Inc." }, { 0x1479, "Datalux Corporation" }, { 0x147A, "Formosa21 Inc." }, { 0x147B, "ABB STOTZ-KONTAKT GmbH" }, { 0x147C, "KeyGhost Ltd." }, { 0x147D, "Tosoh Corporation" }, { 0x147E, "UPEK Inc." }, { 0x147F, "Hama GmbH & Co., KG" }, { 0x1480, "SITEK S.p.a." }, { 0x1481, "MHT S.p.A." }, { 0x1482, "Vaillant GmbH" }, { 0x1483, "Shenzhen MingWah Aohan High Technology Co., Ltd." }, { 0x1484, "Triad Semiconductor, Inc." }, { 0x1485, "OrangeWare Corp." }, { 0x1486, "SCM PC-CARD GmbH" }, { 0x1487, "DSP Group, Ltd." }, { 0x1488, "Orion Technology Corp." }, { 0x1489, "Sakura Finetek USA, Inc." }, { 0x148A, "MICROVISION" }, { 0x148B, "HandEra, Inc." }, { 0x148C, "Colortrac Ltd." }, { 0x148D, "DESMA Co., Ltd." }, { 0x148E, "EVATRONIX SA" }, { 0x148F, "Ralink Technology, Corp." }, { 0x1490, "Digitek Spa" }, { 0x1491, "Futronic Technology Co., Ltd." }, { 0x1492, "Farsharp Imaging Technology Corp." }, { 0x1493, "Suunto" }, { 0x1495, "Elprotronic Inc." }, { 0x1496, "Tunturi Oy Ltd." }, { 0x1497, "Panstrong Company Ltd." }, { 0x1498, "ULi Electronics Inc." }, { 0x1499, "G-STAR Communications, Ltd." }, { 0x149A, "Imagination Technologies" }, { 0x149B, "Ivoclar Vivadent AG" }, { 0x149C, "TonerHead.com" }, { 0x149D, "QMotions Inc." }, { 0x149E, "Amkor Technology" }, { 0x149F, "Wits Technologies Pte. Ltd." }, { 0x14A0, "WAVE Corporation" }, { 0x14A1, "Sunhayato Corp." }, { 0x14A2, "Big Dutchman (Skandinavien) A/S" }, { 0x14A3, "Wipotec GmbH" }, { 0x14A4, "Kyerim Industrial Co." }, { 0x14A5, "I-ROCKS TECHNOLOGY CO., LTD." }, { 0x14A6, "Interface Masters, Inc." }, { 0x14A7, "LanReady Technologies, Inc." }, { 0x14A8, "1C Company" }, { 0x14A9, "Smar Research Corp." }, { 0x14AA, "WideView Technology Inc." }, { 0x14AB, "Technisches Buero Koenig" }, { 0x14AC, "Coolstf.com" }, { 0x14AD, "CTK Corporation" }, { 0x14AE, "Printronix Inc." }, { 0x14AF, "ATP Electronics Inc." }, { 0x14B0, "StarTech.com Ltd." }, { 0x14B1, "I.E. Gesellschaft fuer Industrieelektronik mbH" }, { 0x14B2, "Alpha Networks Inc." }, { 0x14B3, "CHUO ELECTRIC WORKS CO., LTD." }, { 0x14B4, "Appliances Corp." }, { 0x14B5, "NTS Telecom" }, { 0x14B6, "Mimic Technologies Inc." }, { 0x14B7, "In2Games Limited" }, { 0x14B8, "UNITEK TECHNOLOGY CORPORATION" }, { 0x14B9, "BP Microsystems" }, { 0x14BA, "FLOVEL CO., LTD." }, { 0x14BB, "Assembly Tech. Co., Ltd." }, { 0x14BC, "NordNav Technologies AB" }, { 0x14BD, "Eintech Co., Ltd." }, { 0x14BE, "Crestron Electronics, Inc." }, { 0x14BF, "Everbee Networks" }, { 0x14C0, "Rockwell Automation, Inc." }, { 0x14C1, "SOHYA TECHNOLOGY CO., LTD." }, { 0x14C2, "Gemlight Computer Ltd." }, { 0x14C3, "VOXELLE LTD." }, { 0x14C4, "CLOVER Electronics Co., Ltd." }, { 0x14C5, "AudioControl" }, { 0x14C6, "Trigon Components, Inc." }, { 0x14C7, "Hartmann GmbH" }, { 0x14C8, "Zytronic Displays Limited" }, { 0x14C9, "IXOS Ltd. Bvi" }, { 0x14CA, "Technol Seven Co., Ltd." }, { 0x14CB, "Dynapoint, Inc." }, { 0x14CC, "WIN TONG ELECTRONICS CO., LTD." }, { 0x14CD, "MOAI ELECTRONICS CORPORATION" }, { 0x14CE, "Spectra, Inc." }, { 0x14CF, "Measurement Systems Inc." }, { 0x14D0, "Dentrix Dental Systems, Inc." }, { 0x14D1, "Maximo Products LLC" }, { 0x14D2, "BITS CO., LTD." }, { 0x14D3, "Y2 Corporation" }, { 0x14D4, "Telequip Corporation" }, { 0x14D5, "Electronic Theatre Controls" }, { 0x14D6, "Beijing Zhijiu Technology Co., Ltd." }, { 0x14D7, "Toppan Printing Co., Ltd." }, { 0x14D8, "JAMER INDUSTRIES CO., LTD." }, { 0x14D9, "Advanced Flash Memory Card Technology Ltd." }, { 0x14DA, "Horng Technical Enterprise Co., Ltd." }, { 0x14DB, "TOA Musendenki Co., Ltd." }, { 0x14DC, "Ftech Co., Ltd." }, { 0x14DD, "Raritan Computer, Inc." }, { 0x14DE, "Jetway Information Co., Ltd." }, { 0x14DF, "COMPRION GmbH" }, { 0x14E0, "Winradio Communications" }, { 0x14E1, "Imagination Broadway Ltd" }, { 0x14E2, "Avistar Communications Corporation" }, { 0x14E3, "Medmont Pty Ltd." }, { 0x14E4, "S.CAM Co., Ltd." }, { 0x14E5, "Zinitix Co., Ltd" }, { 0x14E6, "Micromed Biotecnologia Ltda." }, { 0x14E7, "ISS Incorporated" }, { 0x14E8, "Animated Lighting LC" }, { 0x14E9, "Lifetouch, Inc." }, { 0x14EA, "Kosaka Laboratory Ltd." }, { 0x14EB, "Pendulum Instruments AB" }, { 0x14EC, "Vansco Electronics Ltd." }, { 0x14ED, "Shure Inc." }, { 0x14EE, "INFORAD Ltd." }, { 0x14EF, "AVICLink Corporation" }, { 0x14F0, "GE" }, { 0x14F1, "America Hears, LLC." }, { 0x14F2, "Axess AG" }, { 0x14F3, "BAP IMAGE SYSTEMS" }, { 0x14F4, "Accell Corporation" }, { 0x14F5, "SourceQuest, Inc." }, { 0x14F6, "Symbium Corporation" }, { 0x14F7, "TechniSat Digital GmbH" }, { 0x14F8, "Chenrol Electric Wire & Cable Co., Ltd." }, { 0x14F9, "Full Conductor Electric Appliance Manufacturer" }, { 0x14FA, "The Wild Divine Project" }, { 0x14FB, "JAI" }, { 0x14FC, "Signami LLC" }, { 0x14FD, "IPC Information Systems" }, { 0x14FE, "Madrics Media GmbH Europe" }, { 0x14FF, "Twinhead International Corp." }, { 0x1500, "Ellisys" }, { 0x1501, "Pine-Tum Enterprise Co., Ltd." }, { 0x1502, "Peavey Electronics" }, { 0x1503, "Stretch Inc." }, { 0x1504, "Bixolon Co., Ltd." }, { 0x1505, "Extraordinary Technologies Pty. Ltd.-Trading as Halcro" }, { 0x1506, "T.D. Technecon Ltd." }, { 0x1507, "APIM INFORMATIQUE" }, { 0x1508, "MAATEL" }, { 0x1509, "LI-COR Biosciences, Inc." }, { 0x150A, "TiVo Inc." }, { 0x150B, "COLLEX COMMUNICATION CORP." }, { 0x150C, "Brightwell Dispenses Ltd." }, { 0x150D, "PR Electronics A/S" }, { 0x150E, "Ono Sokki Co., Ltd." }, { 0x150F, "Nidec Nemicon Corporation" }, { 0x1510, "RACEWOOD TELECOM CO., LTD." }, { 0x1511, "BridgeCo, AG" }, { 0x1512, "Software Technologies Group, Inc." }, { 0x1513, "Hypercom" }, { 0x1514, "Microsemi, SOC Products Group" }, { 0x1515, "Hexon Media Pte Ltd" }, { 0x1516, "Skymedi Corporation" }, { 0x1517, "Precisa Instruments AG" }, { 0x1518, "Cheshire Engineering Corporation" }, { 0x1519, "Comneon GmbH Co., Ohg." }, { 0x151A, "RoyalTek Company Ltd." }, { 0x151B, "HOSTNET CO." }, { 0x151C, "VeriSilicon Holdings Co., Ltd." }, { 0x151D, "P W Allen & Co." }, { 0x151E, "Circad Design Ltd." }, { 0x151F, "Opal Kelly Incorporated" }, { 0x1520, "Bitwire Corp." }, { 0x1521, "S++ Simulation Services" }, { 0x1522, "Educational Insights" }, { 0x1523, "Hitachi High-Tech Science Corporation" }, { 0x1524, "SCIENTEX Inc." }, { 0x1525, "Newson Engineering NV" }, { 0x1526, "ARDUC Co., Ltd." }, { 0x1527, "iQue Ltd." }, { 0x1528, "HighAndes Limited" }, { 0x1529, "UBIQUAM CO., LTD." }, { 0x152A, "Thesycon Systemsoftware & Consulting GmbH" }, { 0x152B, "MIR-Medical International Research" }, { 0x152C, "titel++" }, { 0x152D, "JMicron Technology Corp." }, { 0x152E, "HLDS (Hitachi-LG Data Storage, Inc.)" }, { 0x152F, "PRO-MECH CORPORATION" }, { 0x1530, "Martsoft Corp." }, { 0x1531, "MICRODIA Ltd." }, { 0x1532, "Razer (Asia-Pacific) Pte Ltd." }, { 0x1533, "AEPTEC Microsystems, Inc." }, { 0x1534, "Advanced Research Corporation" }, { 0x1535, "Practical Engineering Incorporated" }, { 0x1536, "Neonode Technologies AB" }, { 0x1537, "Power Up Manufacturing" }, { 0x1538, "IES Elektronikentwicklung" }, { 0x1539, "AFG-Engineering GmbH" }, { 0x153A, "WMS Gaming Inc." }, { 0x153B, "ERCO Leuchten GmbH" }, { 0x153C, "Guger Technologies OEG" }, { 0x153D, "Adam Tech" }, { 0x153E, "abKey ptd ltd." }, { 0x153F, "UNIBRAIN S.A." }, { 0x1540, "Phihong Technology Co., Ltd." }, { 0x1541, "Better Light, Inc." }, { 0x1542, "Gemini Industries, Inc." }, { 0x1543, "Buxco Research Systems" }, { 0x1544, "Alphamosaic Ltd." }, { 0x1545, "Kistler Instrumente AG" }, { 0x1546, "u-blox AG" }, { 0x1547, "S. Goers IT-Solutions" }, { 0x1548, "Centrepoint Technologies" }, { 0x1549, "Beamex Oy Ab" }, { 0x154A, "ID Innovations Incorporated" }, { 0x154B, "PNY Technologies Inc." }, { 0x154C, "AutoXray Inc." }, { 0x154D, "Rapid Conn, Connect County Holdings Bhd" }, { 0x154E, "D & M Holdings, Inc." }, { 0x154F, "Shandong New Beiyang Information Technology Co., Ltd." }, { 0x1550, "Cardinal Health, Inc." }, { 0x1551, "SAIC/IISBU" }, { 0x1552, "DALLAB (M) SDN BHD (587734-A)" }, { 0x1553, "Raytheon Commercial Infrared" }, { 0x1554, "Prolink Microsystems Corporation" }, { 0x1555, "OWEN Ltd." }, { 0x1556, "CERN" }, { 0x1557, "OQO" }, { 0x1558, "Microbus Designs Ltd." }, { 0x1559, "The Toro Company" }, { 0x155A, "ELDAT GmbH" }, { 0x155B, "Shanghai Huahong Integrated Circuit Co., Ltd." }, { 0x155C, "Meyers Technology" }, { 0x155D, "National Rejectors, Inc. GmbH" }, { 0x155E, "DUPLO SEIKO CORPORATION" }, { 0x155F, "Cobra Electronics Corporation" }, { 0x1560, "Supra, A UTC Fire & Security Company" }, { 0x1561, "LaunchPadOffice Inc." }, { 0x1562, "Infowize Technologies Corporation" }, { 0x1563, "Micronet Corporation" }, { 0x1564, "Gizmondo Europe Ltd." }, { 0x1565, "Advance Modules" }, { 0x1566, "WIN ACCORD LTD." }, { 0x1567, "MUTOH Industries Ltd." }, { 0x1568, "Sunf Pu Technology (Dong-Guan) Co., Ltd." }, { 0x1569, "Mad City Labs, Inc." }, { 0x156A, "Logical Solutions, Inc." }, { 0x156B, "Cairn Research Ltd." }, { 0x156C, "Meade Instruments Corp." }, { 0x156D, "OMICRON electronics GmbH" }, { 0x156E, "MVox Electronics" }, { 0x156F, "Quantum Corporation" }, { 0x1570, "ALLTOP TECHNOLOGY CO., LTD." }, { 0x1571, "NIKON-TRIMBLE CO., LTD." }, { 0x1572, "Ricreations, Inc." }, { 0x1573, "Gradiente Eletronica S.A." }, { 0x1574, "HKW-Elektronik GmbH" }, { 0x1575, "Video Associates Labs, Inc." }, { 0x1576, "Maretron" }, { 0x1577, "MIYUKI ELEX CO., LTD." }, { 0x1578, "Beijing Huaqi Information Digital Technology Co., Ltd." }, { 0x1579, "Reputed Industrial Company Limited" }, { 0x157A, "Lowrance Electronics, Inc." }, { 0x157B, "Ketron SRL" }, { 0x157C, "Eurosoft (UK) Ltd." }, { 0x157D, "Tokyo Sokuteikizai Co., Ltd." }, { 0x157E, "U-MEDIA Communications, Inc." }, { 0x157F, "Levon Limited" }, { 0x1580, "Real Time Logic, Inc." }, { 0x1581, "IGB Communication Co., Ltd." }, { 0x1582, "Asia Pacifc Microsystems, Inc." }, { 0x1583, "EUCHNER GmbH & Co. KG" }, { 0x1584, "Prueftechnik AG" }, { 0x1585, "IKeyInfinity Inc." }, { 0x1586, "Palconn Technology Co., Ltd." }, { 0x1587, "SMA Solar Technology AG" }, { 0x1588, "Fine Instruments Corporation" }, { 0x1589, "Arcus Technology Inc." }, { 0x158A, "BOBE Industrie-Elektronik" }, { 0x158B, "Righttag Inc." }, { 0x158C, "LINFOS CO., LTD." }, { 0x158D, "Oakley Inc." }, { 0x158E, "Acterna Germany GmbH" }, { 0x158F, "Tai Yip Electrical Co., Ltd." }, { 0x1590, "Onsu Data Telecommunication Technology (Shenzhen) Fty." }, { 0x1591, "Advanced Product Design & Mfg. Inc." }, { 0x1592, "Tokyo Drawing Ltd." }, { 0x1593, "Vector International bvba" }, { 0x1594, "Lockheed Martin Missiles & Fire Control" }, { 0x1595, "Flexiworld Technologies, Inc." }, { 0x1596, "Kilodyne LLC" }, { 0x1597, "KCodes Corporation" }, { 0x1598, "Kunshan Guoji Electronics Co., Ltd." }, { 0x1599, "ANRITSU METER CO., LTD." }, { 0x159A, "SkuTek Instrumentation" }, { 0x159B, "Zitte Corporation" }, { 0x159C, "Binary Acoustic Technology" }, { 0x159D, "Boone Cable Works & Electronics" }, { 0x159E, "SmartSwing, Inc." }, { 0x159F, "Beijer Electronics AB" }, { 0x15A0, "Zarlink Semiconductor" }, { 0x15A1, "Nicety Technologies Inc." }, { 0x15A2, "Freescale Semiconductor, Inc." }, { 0x15A3, "Larson Davis, Inc." }, { 0x15A4, "Afa Technologies, Inc." }, { 0x15A5, "CIT Engineering NV" }, { 0x15A6, "Unicos Corporation" }, { 0x15A7, "APPSware Wireless LLC dba Apriva" }, { 0x15A8, "Shen Zhen Teamspower Electronics Co., Ltd." }, { 0x15A9, "Gemtek Technology Co., Ltd." }, { 0x15AA, "GuangDong Ya Lian Technology Co., Ltd" }, { 0x15AB, "Virgin HealthMiles, Inc." }, { 0x15AC, "Smartware" }, { 0x15AD, "Bleile Datentechnik GmbH" }, { 0x15AE, "KAYSER-THREDE GMBH" }, { 0x15AF, "Jenaer Antriebstechnik GmbH" }, { 0x15B0, "Pacific Instruments, Inc." }, { 0x15B1, "MiTAC Technology Corporation" }, { 0x15B2, "Audio Dev AB" }, { 0x15B3, "GL Sciences Inc." }, { 0x15B4, "Orient Power Multimedia Ltd." }, { 0x15B5, "ANUBIS ELECTRONIC GmbH" }, { 0x15B6, "Dialog Semiconductor GmbH" }, { 0x15B7, "Hyper Stimulator International Pty Ltd." }, { 0x15B8, "Serome Electronics, Inc." }, { 0x15B9, "USD Corporation" }, { 0x15BA, "Olimex Ltd." }, { 0x15BB, "CopyPro , Inc." }, { 0x15BC, "Daktronics Inc." }, { 0x15BD, "Sigmaelectronics Co., Ltd." }, { 0x15BE, "EssNet Interactive AB" }, { 0x15BF, "ESA, Inc." }, { 0x15C0, "CJM" }, { 0x15C1, "Amirix Systems Inc." }, { 0x15C2, "SoundGraph, Inc." }, { 0x15C3, "m.u.t - GmbH" }, { 0x15C4, "Global Marketing Alliance, Inc." }, { 0x15C5, "Pressure Profile Systems, Inc." }, { 0x15C6, "Laboratoires MXM" }, { 0x15C7, "IRI-Ubiteq, Inc." }, { 0x15C8, "KTF Technologies" }, { 0x15C9, "D-Box Technologies" }, { 0x15CA, "TEXTECH INTERNATIONAL LTD." }, { 0x15CB, "Activis Polska" }, { 0x15CC, "GL Communications Inc." }, { 0x15CD, "DeFelsko Corporation" }, { 0x15CE, "Oriental R&D Co., Ltd." }, { 0x15CF, "AVTOR Ltd.." }, { 0x15D0, "AIRSTAR Inc." }, { 0x15D1, "Hokuyo Automatic Co., Ltd." }, { 0x15D2, "REA Elektronik GmbH" }, { 0x15D3, "Symmetric Research" }, { 0x15D4, "Opinionmeter International, Ltd." }, { 0x15D5, "Coulomb Electronics Ltd." }, { 0x15D6, "Fitness Expert" }, { 0x15D7, "amaxa GmbH" }, { 0x15D8, "Grundig Business Systems GmbH" }, { 0x15D9, "Apexone Microelectronics Inc." }, { 0x15DA, "Cooper - Atkins Corporation" }, { 0x15DB, "Philip Harris Education" }, { 0x15DC, "Hynix Semiconductor Inc." }, { 0x15DD, "Axona Limited" }, { 0x15DE, "Spatial Freedom, Inc." }, { 0x15DF, "Helmut Fischer GmbH + Co. KG" }, { 0x15E0, "Seong Ji Industrial Co., Ltd." }, { 0x15E1, "RSA Security Inc." }, { 0x15E2, "Bionopoly LLC" }, { 0x15E3, "NEURICAM SPA" }, { 0x15E4, "Numark Industries" }, { 0x15E5, "Micro Systems Inc." }, { 0x15E6, "Turnkey Ltd." }, { 0x15E7, "Media Systems Ltd." }, { 0x15E8, "Micro Tools Inc." }, { 0x15E9, "Pacific Digital Corp." }, { 0x15EA, "C-guys Inc." }, { 0x15EB, "VIA Telecom" }, { 0x15EC, "Belcarra Technologies Corp." }, { 0x15ED, "UCA Technology Inc." }, { 0x15EE, "Quorum Communications, Inc." }, { 0x15EF, "MSilicon Electronics, Inc." }, { 0x15F0, "Technex Lab Co., Ltd." }, { 0x15F1, "Mortara Instrument, Inc." }, { 0x15F2, "Chyron Corp." }, { 0x15F3, "AquaCube Inc." }, { 0x15F4, "Computer & Entertainment, Inc." }, { 0x15F5, "Mobitek Communication Corp." }, { 0x15F6, "ASICS World Services Ltd." }, { 0x15F7, "HANTEL CO., LTD." }, { 0x15F8, "Vianet, Inc." }, { 0x15F9, "SunCorp Industrial Limited" }, { 0x15FA, "Department of Defense" }, { 0x15FB, "R-Quest Technologies , LLC" }, { 0x15FC, "Humen Xintai Electrical Wires Factory" }, { 0x15FD, "XEMAX Co., Ltd." }, { 0x15FE, "Bio-Rad Laboratories Deeside" }, { 0x15FF, "Heartsine Technologies Ltd." }, { 0x1600, "Monisys Limited" }, { 0x1601, "Avenues in Leather" }, { 0x1602, "CompUSA Inc." }, { 0x1603, "ERGODEX Corp." }, { 0x1604, "Kyokko Seiko Co., Ltd." }, { 0x1605, "Acces I/O Products, Inc." }, { 0x1606, "UMAX Data Systems Inc." }, { 0x1607, "ESE Corporate" }, { 0x1608, "Inside Out Networks, a division of Digi International" }, { 0x1609, "K-byte (ACI Group)" }, { 0x160A, "VIA Networking Technologies, Inc." }, { 0x160B, "CSI Wireless Inc." }, { 0x160C, "Shanghai Tiananxin Information & Tech., Co., Ltd." }, { 0x160D, "Samtec" }, { 0x160E, "INRO Consultants Inc." }, { 0x160F, "Strand Lighting Limited" }, { 0x1610, "Q-Sense AB" }, { 0x1611, "Vita-Mix Corporation" }, { 0x1612, "Soft DB Inc." }, { 0x1613, "Airconnect Solutions (Asia) Ltd." }, { 0x1614, "Amoi Electronics Co., Ltd." }, { 0x1615, "Rock Data Services Ltd." }, { 0x1616, "Cute Mobile Corp." }, { 0x1617, "Navman" }, { 0x1618, "Redpine Signals, Inc." }, { 0x1619, "L & K Precision Technology Co., Ltd." }, { 0x161A, "Celeraise Investments Ltd." }, { 0x161B, "MYCOM, INC." }, { 0x161C, "DigiTech Systems Co., Ltd." }, { 0x161D, "Delfin Technologies Ltd." }, { 0x161E, "Aerotech Inc." }, { 0x161F, "Prosisa International LLC" }, { 0x1620, "Accesstek Inc." }, { 0x1621, "Wionics Research" }, { 0x1622, "California Instruments" }, { 0x1623, "Mindtech Limited" }, { 0x1624, "AIOI Systems, USA Corp." }, { 0x1625, "ViaSat UK" }, { 0x1626, "Advance Data Technology Corporation" }, { 0x1627, "IPextreme, Inc." }, { 0x1628, "Stonestreet One, Inc." }, { 0x1629, "Erae Electronics" }, { 0x162A, "Airgo Networks Inc." }, { 0x162B, "Acksys" }, { 0x162C, "Ecler Laboratorio de Electroacustica S.A." }, { 0x162D, "Control Instruments Development (Pty) Ltd." }, { 0x162E, "Joytech Europe Ltd." }, { 0x162F, "WiQuest Communications, Inc." }, { 0x1630, "QformX" }, { 0x1631, "Focus Enhancements" }, { 0x1632, "Data Ray Inc." }, { 0x1633, "AIM GmbH" }, { 0x1634, "ABB Switzerland Ltd." }, { 0x1635, "Doble Engineering Co." }, { 0x1636, "Kobe-Addtech Co., Ltd." }, { 0x1637, "LZAE LUMEL SA" }, { 0x1638, "Skyworks Solutions" }, { 0x1639, "BeRiver Electronics Co., Ltd." }, { 0x163A, "Traficon N.V." }, { 0x163B, "Controlled Speed Engineering Ltd." }, { 0x163C, "Watchdata System Co., Ltd." }, { 0x163D, "Million Tech Dev. Ltd." }, { 0x163E, "Dezhou HongJu Communication Technology Co., Ltd." }, { 0x163F, "AVEX Technologies, Inc." }, { 0x1640, "M3 Electronics, Inc." }, { 0x1641, "eMagin Corporation" }, { 0x1642, "AquaSensors LLC" }, { 0x1643, "Sanwa Newtec Co., Ltd." }, { 0x1644, "Active Technologies SRL" }, { 0x1645, "Smiths Heimann Biometrics GmbH" }, { 0x1646, "Altronic, Inc." }, { 0x1647, "Horizon Navigation, Inc." }, { 0x1648, "Wood Head Software & Electronics" }, { 0x1649, "Softec Microsystems" }, { 0x164A, "ChipX" }, { 0x164B, "Lytech Technology Inc." }, { 0x164C, "Matrix Vision GmbH" }, { 0x164D, "DASAN Networks, Inc." }, { 0x164E, "Picotest Corp." }, { 0x164F, "Kinkei System Co., Ltd." }, { 0x1650, "Remopro Technology Inc." }, { 0x1651, "PACOMP" }, { 0x1652, "EFull Tech. Corp. Ltd." }, { 0x1653, "Nissho Electronics Co., Ltd." }, { 0x1654, "Stamer Musikanlagen GmbH" }, { 0x1655, "Dtron Co., Ltd." }, { 0x1656, "QSC Audio Products, Inc." }, { 0x1657, "Struck Innovative Systeme GmbH" }, { 0x1658, "Grayhill Inc." }, { 0x1659, "Lathem Time Corp." }, { 0x165A, "E.D.P. SRL" }, { 0x165B, "Frontier Design Group" }, { 0x165C, "Kondo Kagaku Co., Ltd." }, { 0x165D, "Orange Tree Technologies Ltd." }, { 0x165E, "Pangolin" }, { 0x165F, "Ansync Inc." }, { 0x1660, "Creatix Polymedia GmbH" }, { 0x1661, "DVS Korea Co., Ltd." }, { 0x1662, "Positivo Informatica LTDA" }, { 0x1663, "Sercel, Inc." }, { 0x1664, "ARGOX INFORMATION CO., LTD." }, { 0x1665, "General Dynamics Canada" }, { 0x1666, "Vanguard Instruments Co., Inc." }, { 0x1667, "GIGA-TMS, INC." }, { 0x1668, "Actiontec Electronics, Inc." }, { 0x1669, "PiKRON s.r.o." }, { 0x166A, "Clipsal Integrated Systems" }, { 0x166B, "PedalPax Corporation" }, { 0x166C, "Technology Driven Solutions Ltd" }, { 0x166D, "MCS Logic Inc." }, { 0x166E, "SerComm Corporation" }, { 0x166F, "Idetech Europe S.A." }, { 0x1670, "Hach Company" }, { 0x1671, "Telular Corporation" }, { 0x1672, "MBS GmbH" }, { 0x1673, "ROBOTIKER" }, { 0x1674, "Pantone, Inc." }, { 0x1675, "SE-IR Corporation" }, { 0x1676, "I-Ware Laboratory Co., Ltd." }, { 0x1677, "China Integrated Circuit Design Corp., Ltd." }, { 0x1678, "Matsunichi Information Technology (Shenzhen) Co., Ltd." }, { 0x1679, "Total Phase" }, { 0x167A, "USBWARE" }, { 0x167B, "Pure Digital Technologies" }, { 0x167C, "Vionics" }, { 0x167D, "SIM Security & Electronic System GmbH" }, { 0x167E, "Videa Technology Inc." }, { 0x167F, "Actigraph, LLC" }, { 0x1680, "KaVo Dental GmbH" }, { 0x1681, "Prevo Technologies, Inc." }, { 0x1682, "Maxwise Production Enterprise Ltd." }, { 0x1683, "DualCor Technologies, Inc." }, { 0x1684, "Godspeed Computer Corp." }, { 0x1685, "Tanic Electroics Ltd." }, { 0x1686, "ZOOM Corporation" }, { 0x1687, "Kingmax Digital Inc." }, { 0x1688, "AerotechTelub AB" }, { 0x1689, "Griffin International Companies, Inc." }, { 0x168A, "Veeco Instruments" }, { 0x168B, "BTC Secu Co., Ltd." }, { 0x168C, "Tabor Electroics Ltd." }, { 0x168D, "YSI, Inc." }, { 0x168E, "iMetrikus Inc." }, { 0x168F, "ETA S.A. Manufacture Horlogere Suisse" }, { 0x1690, "Simple Solutions" }, { 0x1691, "Landers Instruments" }, { 0x1692, "Weatherford" }, { 0x1693, "Zultys Technologies" }, { 0x1694, "Cassidian Communications" }, { 0x1695, "FATAR, S.r.l." }, { 0x1696, "Hitachi Advanced Digital, Inc." }, { 0x1697, "VTEC TEST, INC." }, { 0x1698, "Eurosmart" }, { 0x1699, "United RadioTek Inc." }, { 0x169A, "Ten X Technology Inc." }, { 0x169B, "aitronic GmbH" }, { 0x169C, "DMS" }, { 0x169E, "Groupics.com, Inc." }, { 0x169F, "Monolith Inc." }, { 0x16A0, "Real Thoughts GmbH" }, { 0x16A1, "Trilithic, Inc." }, { 0x16A2, "Sypris Test and Measurement (FW Bell)" }, { 0x16A3, "B & W Tek Inc." }, { 0x16A4, "Sagutech Microsystems" }, { 0x16A5, "Shenzhen Zhengerya Technology Co., Ltd." }, { 0x16A6, "UNIGRAF OY" }, { 0x16A7, "Sauer-Danfoss" }, { 0x16A8, "Nice Systems" }, { 0x16A9, "Worth-Pfaff Innovations, Inc." }, { 0x16AA, "Symtx Inc." }, { 0x16AB, "InnoWireless Co. Ltd." }, { 0x16AC, "Dongguan ChingLung Wire & Cable Co., Ltd." }, { 0x16AD, "Siemens VDO Trading GmbH" }, { 0x16AE, "ELSA Japan Inc." }, { 0x16AF, "Intelligent Mechatronic Systems" }, { 0x16B0, "Infosight Corp." }, { 0x16B1, "Cami Research Inc." }, { 0x16B2, "Bruxton Corporation" }, { 0x16B3, "Eizoken Inc." }, { 0x16B4, "Digital Cube" }, { 0x16B5, "PerSen Technologies, Inc." }, { 0x16B6, "Nexus Technology Inc." }, { 0x16B7, "Pulsafeeder Inc." }, { 0x16B8, "Honeywell Life Safety" }, { 0x16B9, "Origin Technologies Limited" }, { 0x16BA, "SmarTec" }, { 0x16BB, "Tomra Systems ASA" }, { 0x16BC, "JOBO AG" }, { 0x16BD, "Leica Geosystems AG" }, { 0x16BE, "RyuSyo Industrial Co., Ltd." }, { 0x16BF, "CAST, INC." }, { 0x16C0, "Van Ooijen Technische Informatica" }, { 0x16C1, "Lucas-Nuelle GmbH" }, { 0x16C2, "Amphenol-Data Telecom" }, { 0x16C3, "Nihon Kaiheiki Ind. Co., Ltd." }, { 0x16C4, "SavaJe Technologies, Inc." }, { 0x16C5, "Cryptek Inc." }, { 0x16C6, "NDS Surgical Imaging, LLC" }, { 0x16C7, "Crystal Technology, Inc." }, { 0x16C8, "Technische Universiteit Eindhoven" }, { 0x16C9, "OCT Co., Ltd." }, { 0x16CA, "Wireless Cables Inc." }, { 0x16CB, "Highwater Designs Limited" }, { 0x16CC, "silex technology, Inc." }, { 0x16CD, "Brian Moore Guitars, Inc." }, { 0x16CE, "IPFlex Inc." }, { 0x16CF, "YAZAKI PARTS CO., LTD." }, { 0x16D1, "SUPREMA, INC." }, { 0x16D2, "TOMEY" }, { 0x16D3, "Frontline Test Equipment, Inc." }, { 0x16D4, "SRTechnologies" }, { 0x16D5, "AnyDATA Corporation" }, { 0x16D6, "Jablotron" }, { 0x16D7, "Aprilis, Inc." }, { 0x16D8, "CMOTECH CO., LTD." }, { 0x16D9, "A7 Engineering, Inc." }, { 0x16DA, "Linkam Scientific Instruments Ltd." }, { 0x16DB, "Eridon Corporation" }, { 0x16DC, "W-IE-NE-R, Plein & Baus GmbH" }, { 0x16DD, "YOSHIDA SEIKI CO., LTD." }, { 0x16DE, "Schneider Electric" }, { 0x16DF, "King Billion Electronics Co., Ltd." }, { 0x16E0, "Lumex Ltd." }, { 0x16E1, "Bed Check Corporation" }, { 0x16E2, "Hitachi I E Systems Co., Ltd." }, { 0x16E3, "ITM Inc." }, { 0x16E4, "Franklin Electric Co., Inc." }, { 0x16E5, "TOKYO KEIKI RAIL TECHNO INC." }, { 0x16E6, "Diginfo Technology Corporation" }, { 0x16E7, "United Keys, Inc." }, { 0x16E8, "Frontier Information Enterprise, Inc." }, { 0x16E9, "Dr. Gal Ben-David" }, { 0x16EA, "Avionica, Inc." }, { 0x16EB, "Helvar" }, { 0x16EC, "ASAHI GLASS CO., LTD." }, { 0x16ED, "Parker Vision Inc." }, { 0x16EE, "Ryvor Corp." }, { 0x16EF, "Global Safety & Security Solutions OY" }, { 0x16F0, "GN ReSound" }, { 0x16F1, "Versus Technology, Inc." }, { 0x16F2, "St. Jude Medical AB" }, { 0x16F3, "Hammer Storage/Bell Microproducts" }, { 0x16F4, "Lineeye Co., Ltd." }, { 0x16F5, "Futurelogic Inc." }, { 0x16F6, "Shin Tek Inc." }, { 0x16F7, "Japan Gals Co., Ltd." }, { 0x16F8, "Ever Bright Wire Factory" }, { 0x16F9, "Astrosys International Limited" }, { 0x16FA, "Shachihata Inc." }, { 0x16FB, "MICRONIX CORPORATION" }, { 0x16FC, "TRICOM TECHNOLOGIES, INC." }, { 0x16FD, "Reakin Technology Corporation" }, { 0x16FE, "Su Zhou Song Qing Electronical Co., Ltd." }, { 0x16FF, "Ultimate Technology Corp." }, { 0x1700, "Hunt Engineering (UK) Ltd." }, { 0x1701, "Peyroutet Telecom" }, { 0x1702, "Softcare Ltd." }, { 0x1703, "NormSoft, Inc." }, { 0x1704, "ANIMATICS CORP." }, { 0x1705, "Aerosonic Corporation" }, { 0x1706, "BlueView Technologies, Inc." }, { 0x1707, "ARTIMI" }, { 0x1708, "Mibudenki Industrial Co., Ltd." }, { 0x1709, "Sanmina-SCI" }, { 0x170A, "MAXTEK, INC." }, { 0x170B, "Phonic Corp." }, { 0x170C, "BlueTree Wireless Data" }, { 0x170D, "Avnera" }, { 0x170E, "Iris Corporation Berhad" }, { 0x170F, "UbiBro Technolgies Inc." }, { 0x1710, "AZIO Corporation" }, { 0x1711, "Leica Microsystems CMS GmbH" }, { 0x1712, "Fujitsu LSI Technology Ltd." }, { 0x1713, "Enter Tech Co., Ltd" }, { 0x1714, "iCRco" }, { 0x1715, "NL Technology" }, { 0x1716, "LHR Technologies" }, { 0x1717, "Formats Unlimited, Inc." }, { 0x1718, "Mobile Doctor Co., Ltd." }, { 0x1719, "American Technology Corp." }, { 0x171A, "PSi Printer Systems international GmbH" }, { 0x171B, "NT Ware Systemprogrammierung GmbH" }, { 0x171C, "IER" }, { 0x171E, "PACIFIC CORPORATION" }, { 0x171F, "CHIPNUTS TECHNOLOGY INC." }, { 0x1720, "Innova Electronics Corp." }, { 0x1721, "ELAD SRL" }, { 0x1722, "Axicon Auto ID LTD" }, { 0x1723, "Datatronics Technology, Inc" }, { 0x1724, "Lumenera Corporation" }, { 0x1725, "HI-TECH Software" }, { 0x1726, "Axesstel, Inc." }, { 0x1727, "RiCHIP Incorporated" }, { 0x1728, "BYTE TOOLS INC." }, { 0x1729, "CONSULTRONICS EUROPE LTD." }, { 0x172A, "wenglor sensoric gmbh" }, { 0x172B, "CompuSoft A/S" }, { 0x172C, "Silicon Optix" }, { 0x172D, "AccFast Technology Corp." }, { 0x172E, "ELECTION SYSTEMS & Software" }, { 0x172F, "WALTOP International Corporation" }, { 0x1730, "MERCURY" }, { 0x1731, "DATA DISPLAY AG" }, { 0x1732, "NETENRICH INC." }, { 0x1733, "NUBYTECH INC." }, { 0x1734, "IPdrum AB" }, { 0x1735, "Satloc LLC (CSI Wireless)" }, { 0x1736, "CANON IMAGING SYSTEMS INC." }, { 0x1737, "Hong Kong Applied Science and Technology Research Inst." }, { 0x1738, "Asicen Technology Corp." }, { 0x1739, "Radiant Technologies Inc." }, { 0x173A, "F. Hoffmann-La Roche AG" }, { 0x173B, "Cadillac Jack Inc." }, { 0x173C, "Signalcraft Technologies Inc." }, { 0x173D, "Great Pleasure Electronics Co. LTD." }, { 0x173E, "Devlin Electronics Ltd." }, { 0x173F, "Peyer Engineering" }, { 0x1740, "Senao International Co., Ltd." }, { 0x1741, "Techino Science Co., Ltd." }, { 0x1742, "Nippon Chemi-Con Corp." }, { 0x1743, "General Atomics" }, { 0x1744, "Sanwa Electronic Instrument Co. Ltd." }, { 0x1745, "Video Simplex, Inc." }, { 0x1746, "Edge Products" }, { 0x1747, "CML MICROCIRCUITS (UK) LTD" }, { 0x1748, "MQP Electronics Ltd." }, { 0x1749, "MAGO MOBILE LTD" }, { 0x174A, "Endress + Hauser" }, { 0x174B, "BARACODA" }, { 0x174C, "ASMedia Technology Inc." }, { 0x174D, "Broadcast System & Design ApS" }, { 0x174E, "Xi'an Tongshi Data Co., Ltd." }, { 0x174F, "D-MAX Technology Co., Ltd." }, { 0x1750, "Hirschmann Automation and Control GmbH" }, { 0x1751, "EMPIRISOFT CORPORATION" }, { 0x1752, "Liyitec Incorporated" }, { 0x1753, "Tecvan Informatica LTDA" }, { 0x1754, "GERSTEL GmbH & Co. KG" }, { 0x1755, "Electronics and Telecommunication Research Institute" }, { 0x1756, "ENENSYS Technologies" }, { 0x1757, "ST-MICHAEL STRATEGIES" }, { 0x1758, "FUTURECOM SYSTEMS GROUP INC." }, { 0x1759, "LucidPort Technology, Inc." }, { 0x175A, "Lantronix" }, { 0x175B, "Dongguan Init Technology Co., Ltd." }, { 0x175C, "Isolcell Italia SpA" }, { 0x175D, "Caterpillar Inc." }, { 0x175E, "AT KidSystems Inc." }, { 0x175F, "I-BIT Corporation" }, { 0x1760, "RAYLASE AG" }, { 0x1761, "RC GROUP (Holdings) Limited" }, { 0x1763, "USAF" }, { 0x1764, "KANOMAX JAPAN INC." }, { 0x1765, "VK Corporation" }, { 0x1766, "Hip Interactive Inc." }, { 0x1767, "KIS Photo Mc Group" }, { 0x1769, "ARTEK Inc." }, { 0x176A, "GLOBALSAT TECHNOLOGY CORPORATION" }, { 0x176B, "ATOP ELECTRONICS CO., LTD." }, { 0x176C, "Advanced Electronic Designs" }, { 0x176D, "Mbridge Systems, Inc." }, { 0x176E, "UD electronic corp." }, { 0x176F, "Astralink Technology Pte Ltd" }, { 0x1770, "precisionWave Corporation" }, { 0x1771, "Shenzhen Alex Connector Co., Ltd." }, { 0x1772, "System Level Solutions, Inc." }, { 0x1773, "InSync Speech Technologies, Inc." }, { 0x1774, "Strawberry Linux Co., Ltd." }, { 0x1775, "RADAR-TRONIC KFT." }, { 0x1776, "HYPERLABS, Inc." }, { 0x1777, "Microscan Systems, Inc." }, { 0x1778, "PChome Online Inc." }, { 0x1779, "Optek Electronics Co., Ltd." }, { 0x177A, "Explore Semiconductor, Inc." }, { 0x177B, "Cetus Engineering" }, { 0x177C, "AD Information & Communications Co., Ltd" }, { 0x177D, "Delta Industrie Service" }, { 0x177E, "mils electronic GmbH & Co Kg" }, { 0x177F, "Sweex Europe B.V." }, { 0x1780, "TENDYRON CORPORATION" }, { 0x1781, "MECANIQUE" }, { 0x1782, "Spreadtrum Hong Kong Limited" }, { 0x1783, "Foster Flight, Inc." }, { 0x1784, "TopSeed Technology Corp." }, { 0x1785, "CARALLON LIMITED" }, { 0x1786, "Xeltek Inc." }, { 0x1787, "TRIDENT SYSTEMS, INC." }, { 0x1788, "ShenZhen Litkconn Technology Co., Ltd." }, { 0x1789, "Ascom (Schweiz) AG" }, { 0x178A, "Prentke Romich Company" }, { 0x178B, "Panduit Corp." }, { 0x178C, "URTEK TECHNOLOGIES INC." }, { 0x178D, "CEIVA Logic, Inc." }, { 0x178E, "Movimento Group AB" }, { 0x1790, "Ueda Japan Radio Co., Ltd." }, { 0x1791, "SYNTHETIC PLANNING INDUSTRY CO., LTD." }, { 0x1792, "LINK GmbH" }, { 0x1793, "Heim Systems GmbH" }, { 0x1794, "MA'AGALIM COMPUTER SYSTEMS Ltd." }, { 0x1795, "INTEGRATION ASSOCIATES INCORPORATED" }, { 0x1796, "Printrex, Inc." }, { 0x1797, "JALCO CO., LTD." }, { 0x1798, "TYPE TECHNOLOGY INC." }, { 0x1799, "Thales Norway AS" }, { 0x179A, "Conrad Electronic GmbH" }, { 0x179B, "HANDSFULL TECHNOLOGY CORP." }, { 0x179C, "Net-2Com Corporation" }, { 0x179D, "Ricavision International Inc." }, { 0x179E, "Silicon Engines" }, { 0x179F, "CLIQ LIMITED" }, { 0x17A0, "Samson Technologies Corp." }, { 0x17A1, "Taiwan Advanced Sensors Corporation" }, { 0x17A2, "Vantage Controls, Inc." }, { 0x17A3, "OnTime tek Inc." }, { 0x17A4, "Concept 2" }, { 0x17A5, "Advanced Connection Technology Inc." }, { 0x17A6, "Astron Clinica Ltd." }, { 0x17A7, "MICOMSOFT CO., LTD." }, { 0x17A8, "Kamstrup A/S" }, { 0x17A9, "MULTIMEDIA GAMES, INC." }, { 0x17AA, "SETEK Elektronik AB" }, { 0x17AB, "i-Bulldog Co., Ltd." }, { 0x17AC, "Dengen Automation Co., Ltd." }, { 0x17AD, "TRIOC AB" }, { 0x17AE, "NAD Electronics International/A Div. of Lenbrook Ind." }, { 0x17AF, "GIGABYTE Communications Inc." }, { 0x17B0, "Weinmann Geraete fuer Medizen GmbH+Co. KG" }, { 0x17B1, "ViaSat, Inc." }, { 0x17B2, "Metec GmbH" }, { 0x17B3, "Grey Innovation Pty., Ltd." }, { 0x17B4, "Apres Health & Fitness" }, { 0x17B5, "Lunatone Industrielle Elektronik GmbH" }, { 0x17B6, "Hydronix Limited" }, { 0x17B7, "Sinter Information Corp." }, { 0x17B8, "Trojan Technologies Private Limited" }, { 0x17B9, "Green Bit S.p.A." }, { 0x17BA, "Sauris GmbH" }, { 0x17BB, "Weihai Dongxing Electronics Co., Ltd." }, { 0x17BC, "Advanced Peripherals Technologies, Inc." }, { 0x17BD, "Citron Electronic Co., Ltd." }, { 0x17BE, "Dongguan Yangming Precision of Plastic Metal Elec Co Lt" }, { 0x17BF, "Ampere Inc." }, { 0x17C0, "ED Co., Ltd." }, { 0x17C1, "Sirius XM Radio" }, { 0x17C2, "Ingenient Technologies" }, { 0x17C3, "SGB Group Ltd." }, { 0x17C4, "VISIOWAVE SA" }, { 0x17C5, "Hantle System Co., Ltd." }, { 0x17C6, "Magnetox" }, { 0x17C7, "AIM Infrarot-Module GmbH" }, { 0x17C8, "Ringway Tech (JiangSu) Co., Ltd." }, { 0x17C9, "Andros Incorporated" }, { 0x17CA, "CyberPak Co." }, { 0x17CB, "CHINA HUAXU GOLDEN CARD CO., LTD." }, { 0x17CC, "Native Instruments Software Synthesis GmbH" }, { 0x17CD, "Basler Electric" }, { 0x17CE, "Keymile AG" }, { 0x17CF, "Hip Hing Cable & Plug Mfy. Ltd." }, { 0x17D0, "Sanford L.P." }, { 0x17D1, "ViDisys GmbH" }, { 0x17D2, "Radiometer Medical ApS" }, { 0x17D3, "Korea Techtron Co., Ltd." }, { 0x17D4, "Kenetics Innovations Pte. Ltd., Singapore" }, { 0x17D5, "ImageMap Inc." }, { 0x17D6, "Samsung Electronics Research Institute" }, { 0x17D7, "Copley Controls Corp." }, { 0x17D8, "Rapattoni Corporation" }, { 0x17D9, "Rasteme Systems Co., Ltd." }, { 0x17DA, "GEMIT GmbH" }, { 0x17DB, "CYNOVE" }, { 0x17DC, "Thermoteknix Systems Ltd." }, { 0x17DD, "Simply Automated, Incorporated" }, { 0x17DE, "Grant Instruments" }, { 0x17DF, "SOUTHWING" }, { 0x17E0, "Big Sky Laser" }, { 0x17E1, "ORTHOFIX" }, { 0x17E2, "PIKAONE" }, { 0x17E3, "Beck IPC GmbH" }, { 0x17E4, "OKB SAPR" }, { 0x17E5, "Memcorp Inc." }, { 0x17E6, "Quantel Medical" }, { 0x17E7, "Sirah Laser-und Plasmatechnik GmbH" }, { 0x17E8, "Visionee S.R.L." }, { 0x17E9, "DisplayLink (UK) Ltd." }, { 0x17EA, "Web Technology Corp" }, { 0x17EB, "Cornice, Inc." }, { 0x17EC, "Telsource" }, { 0x17ED, "Sumita Optical Glass, Inc." }, { 0x17EE, "Personal Media Corporation" }, { 0x17EF, "Lenovo" }, { 0x17F0, "Bestronic Industry Co., Ltd." }, { 0x17F1, "Microjet Technology Co., Ltd." }, { 0x17F2, "Xmultiple Technologies Inc." }, { 0x17F3, "Terascala, Inc." }, { 0x17F4, "AgaMatrix, Inc." }, { 0x17F5, "K.K. Rocky" }, { 0x17F6, "Unicomp, Inc" }, { 0x17F7, "Metroptic Technologies Ltd." }, { 0x17F8, "Enustech, Inc." }, { 0x17F9, "GIE Sesam-Vitale" }, { 0x17FA, "DOSHISHA CORPORATION" }, { 0x17FB, "Emutec Inc." }, { 0x17FC, "Vitesse Semiconductor Corp." }, { 0x17FD, "Formac GmbH" }, { 0x17FE, "NIPPON PULSE MOTOR CO., LTD." }, { 0x17FF, "Unication Co., Ltd" }, { 0x1800, "Shandong Yuanda Net & Multimedia Co., Ltd." }, { 0x1801, "Southern Data Comm, Inc." }, { 0x1802, "SYN-TEK Technologies Inc." }, { 0x1803, "Secutronix" }, { 0x1804, "Clemens GmbH" }, { 0x1805, "Digital Peripheral Solutions Inc." }, { 0x1806, "New Index AS" }, { 0x1807, "Par-Tech Inc." }, { 0x1808, "Multiplex Engineering Inc." }, { 0x1809, "Advantech Co., Ltd." }, { 0x180A, "Technosystem Co., Ltd." }, { 0x180B, "Photo Research, Inc." }, { 0x180C, "Power Digital Card Co., Ltd." }, { 0x180D, "U3, LLC" }, { 0x180E, "Audisoft Technologies" }, { 0x180F, "Phonak Communications AG" }, { 0x1810, "Wanshih Electronic Co., Ltd." }, { 0x1811, "Blackspot Interactive Ltd." }, { 0x1812, "GEWI GmbH" }, { 0x1813, "HAGIWARA ELECTRIC Co., Ltd." }, { 0x1814, "Fashionow Co. Ltd." }, { 0x1815, "Horizon Semiconductors Ltd." }, { 0x1816, "Directed Electronics" }, { 0x1817, "Digital Authentication Technologies, Inc." }, { 0x1818, "Osteosys Co., Ltd." }, { 0x1819, "Quality Vision International, Inc." }, { 0x181A, "Fotonation" }, { 0x181B, "Current Designs, Inc." }, { 0x181C, "Rensselaer Polytechnic Institute" }, { 0x181D, "Axon Systems Inc." }, { 0x181E, "Advanced Tracking Technologies, Inc." }, { 0x181F, "NAKAJIMA ALL Co., Ltd." }, { 0x1820, "DSM - Messtechnik GmbH" }, { 0x1821, "INwireless Co., Ltd" }, { 0x1822, "DIGIBIO TECHNOLOGY CORP." }, { 0x1823, "CelleBrite Mobile Synchronization" }, { 0x1824, "Aval Nagasaki Corp." }, { 0x1825, "Star-Dundee Ltd." }, { 0x1826, "Xitron Inc." }, { 0x1827, "Sanko Electronics Co., Ltd." }, { 0x1828, "TSR Silicon Resources, Inc." }, { 0x1829, "Dongguan YuQiu Electronics Co., Ltd." }, { 0x182A, "Signalion GmbH" }, { 0x182B, "Chest M.I., Incorporated" }, { 0x182C, "Caliper LifeSciences" }, { 0x182D, "Accutron Limited" }, { 0x182E, "System Instruments Co., Ltd." }, { 0x182F, "Worldwide Productions Inc." }, { 0x1830, "I CAP Technologies, Inc." }, { 0x1831, "Gwo Jinn Industries Co., Ltd." }, { 0x1832, "Huizhou Shenghua Industrial Co., Ltd." }, { 0x1833, "Genuine Technologies Co., Ltd." }, { 0x1834, "SONEL S.A." }, { 0x1835, "Lust Drivetronics GmbH" }, { 0x1836, "ePoint Technology" }, { 0x1837, "Hokuto Denko Corporation" }, { 0x1838, "Real Networks, Inc." }, { 0x1839, "AnexTEK Global Inc." }, { 0x183A, "Mediafour Corporation" }, { 0x183B, "SIDACON Systemtechnik GmbH" }, { 0x183C, "Saab AB" }, { 0x183D, "F3 Inc." }, { 0x183E, "Robonik India Pvt. Ltd." }, { 0x183F, "i-BEAD Co., Ltd." }, { 0x1840, "Cognitive Solutions, Inc." }, { 0x1841, "SEIKO TIME SYSTEM INC." }, { 0x1842, "Keen High Technologies (HK) Ltd." }, { 0x1843, "Vaisala" }, { 0x1844, "Radiotechnika Marketing Sp.zo.o" }, { 0x1845, "Cion Technology Corporation" }, { 0x1846, "microEngineering Labs, Inc." }, { 0x1847, "Global Payment Technologies, Inc." }, { 0x1848, "Eurochannels Holding B.V." }, { 0x1849, "Centurion Systems (Pty) Ltd." }, { 0x184A, "EB Neuro SPA" }, { 0x184B, "ARION Technology Inc." }, { 0x184C, "Centice" }, { 0x184D, "Dansk Automat Expert A/S" }, { 0x184E, "SyGade Solutions (Pty) Ltd." }, { 0x184F, "K2L GmbH" }, { 0x1850, "Andigilog, Inc." }, { 0x1851, "ULTRASONIC ENGINEERING CO., LTD." }, { 0x1852, "Galaxy Far East Corp" }, { 0x1853, "MITSUBISHI PRECISION CO., LTD." }, { 0x1854, "Memory Devices Ltd." }, { 0x1855, "Redpay Secure Payments" }, { 0x1856, "Imaginova" }, { 0x1857, "Picosecond Pulse Labs" }, { 0x1858, "CELLSYSTEM CO., LTD" }, { 0x1859, "Speech Technology Center, Ltd." }, { 0x185A, "WinProbe Corporation" }, { 0x185B, "IG-Development" }, { 0x185C, "Omnisec AG" }, { 0x185D, "Origgio Limited" }, { 0x185E, "Meritech Co., Ltd." }, { 0x185F, "Stinger Systems Inc." }, { 0x1860, "HYUPJIN I & C CO, LTD." }, { 0x1861, "Tech Technology Industrial Company" }, { 0x1862, "Teridian Semiconductor Corp." }, { 0x1863, "Wave Technology Co., Ltd." }, { 0x1864, "Digital Art System" }, { 0x1865, "Europlex Technologies" }, { 0x1866, "Union Community Co., Ltd." }, { 0x1867, "Control Microsystems" }, { 0x1868, "Index Braille AB" }, { 0x1869, "RTS Automation GmbH" }, { 0x186A, "Pivot International, Inc." }, { 0x186B, "Holophase Incorporated" }, { 0x186C, "Miyachi Corporation" }, { 0x186D, "Evermore Innovations" }, { 0x186E, "Reel Stream LLC" }, { 0x186F, "Motion Lingo, LLC" }, { 0x1870, "Nexio Co., Ltd." }, { 0x1871, "Aveo Technology Corp." }, { 0x1872, "Cobalt Technologies Co., Ltd." }, { 0x1873, "Etrovision Technology" }, { 0x1874, "Nexilion Inc." }, { 0x1875, "Humo Laboratory, Ltd." }, { 0x1876, "MG Industrieelektronik GmbH" }, { 0x1877, "SANEI HYTECHS Co., Ltd." }, { 0x1878, "Sumitomo Heavy Industries, Ltd." }, { 0x1879, "Spin Semiconductor Inc." }, { 0x187A, "Mediachorus Inc." }, { 0x187B, "Dent Instruments, Inc." }, { 0x187C, "Alienware Corporation" }, { 0x187D, "Ardware Ltd." }, { 0x187E, "Sentelic Corporation" }, { 0x187F, "Siano Mobile Silicon Ltd." }, { 0x1880, "Vericon Co., Ltd./Jinn Shyang Precision Industrial Co.," }, { 0x1881, "Interactive Learning Technologies" }, { 0x1882, "TransChip Israel Ltd." }, { 0x1883, "Tanaka S/S Ltd." }, { 0x1884, "Liyuh Technology Ltd." }, { 0x1885, "Ascalade Communications Inc." }, { 0x1886, "Metalink Ltd." }, { 0x1887, "Fishcamp Engineering" }, { 0x1888, "Livingston Products, Inc." }, { 0x1889, "DME Corporation" }, { 0x188A, "Moeller" }, { 0x188B, "Showa Electric Laboratory Co., Ltd." }, { 0x188C, "Epos Development Ltd." }, { 0x188D, "Across Techno, Inc." }, { 0x188E, "Neopost Technologies" }, { 0x188F, "Zefatek Co., Ltd." }, { 0x1890, "MEDIAN Inc." }, { 0x1891, "XSENSOR Technology Corp." }, { 0x1892, "Accuri Instruments, Inc." }, { 0x1893, "Ginga Software, Inc." }, { 0x1894, "SyntheSys Research, Inc." }, { 0x1895, "tesa scribos GmbH" }, { 0x1896, "Legacy Electronics, Inc." }, { 0x1897, "Evertop Wire Cable Co." }, { 0x1898, "Summit Microelectronics" }, { 0x1899, "Linkiss Co., Ltd." }, { 0x189A, "Earth Computer Technologies, Inc." }, { 0x189B, "Trimax Electronics Co., Ltd." }, { 0x189C, "Walletex Microelectronics Ltd." }, { 0x189D, "Navionics Inc." }, { 0x189E, "Net Insight AB" }, { 0x189F, "3Shape A/S" }, { 0x18A0, "Kongsberg Maritime AS" }, { 0x18A1, "Ionwerks, Inc." }, { 0x18A2, "PSIA Corp." }, { 0x18A3, "DIGIFRIENDS CO., LTD." }, { 0x18A4, "CSSN, Inc. dba Card Scanning Solutions" }, { 0x18A5, "Verbatim Americas LLC" }, { 0x18A6, "Peripheral Dynamics Inc." }, { 0x18A7, "Omniprint Inc." }, { 0x18A8, "Smiths Medical MD" }, { 0x18A9, "Veri-Tek International" }, { 0x18AA, "MedRx Inc." }, { 0x18AB, "Applied Data Systems, Inc." }, { 0x18AC, "STRATEC Biomedical Systems AG" }, { 0x18AD, "Invisible Technologies, Inc." }, { 0x18AE, "MTT Corporation" }, { 0x18AF, "LN Systems Limited" }, { 0x18B0, "Mikrodidakt AB" }, { 0x18B1, "Elmak Ltd." }, { 0x18B2, "CINTEL FRANCE" }, { 0x18B3, "RAYDON Corporation" }, { 0x18B4, "e3C Inc." }, { 0x18B5, "Klipsch Audio" }, { 0x18B6, "Mikkon Technology Limited" }, { 0x18B7, "Zotek Electronic Co., Ltd." }, { 0x18B8, "Securewave SA" }, { 0x18B9, "Clixxun GmbH" }, { 0x18BA, "Bell Fruit Games" }, { 0x18BB, "G7 Productivity Systems" }, { 0x18BC, "Muro Co., Ltd" }, { 0x18BD, "MNBT Co., Ltd." }, { 0x18BE, "Kingfisher International" }, { 0x18BF, "Ensyc Technologies" }, { 0x18C0, "Gatekeeper Systems Inc." }, { 0x18C1, "Shenzhen SDMC Microelectronics Co., Ltd." }, { 0x18C2, "AccuSport International, Inc." }, { 0x18C3, "Elite Semiconductor Memory Technology Inc. (ESMT)" }, { 0x18C4, "ServerEngines LLC" }, { 0x18C5, "Corega Taiwan, Inc." }, { 0x18C6, "Aurora Photonics" }, { 0x18C7, "Nagano Tectron Co., Ltd" }, { 0x18C8, "Computerprox Corp." }, { 0x18C9, "Exfo Electro-Optical Engineering Inc." }, { 0x18CA, "Canon Korea Business Solutions Inc." }, { 0x18CB, "Fr. Sauter AG" }, { 0x18CC, "Osaki Electric Co., Ltd." }, { 0x18CD, "Pico Instruments LLC" }, { 0x18CE, "DTC Communications, Inc" }, { 0x18CF, "Tung Shu Mei Industrial Co., Ltd." }, { 0x18D0, "Uniform Industrial Corp." }, { 0x18D1, "Google Inc." }, { 0x18D2, "Raptor Gaming Technology GmbH" }, { 0x18D3, "L&V Design" }, { 0x18D4, "ABI Electronics Ltd." }, { 0x18D5, "Starline International Group Limited" }, { 0x18D6, "Ruetz Technologies" }, { 0x18D7, "New Scale Technologies" }, { 0x18D8, "Individual Computers" }, { 0x18D9, "Kaba" }, { 0x18DA, "Phonol Inc." }, { 0x18DB, "Compix Incorporated" }, { 0x18DC, "LKC Technologies, Inc." }, { 0x18DD, "Docuport WC" }, { 0x18DE, "Cyto Pulse Sciences, Inc" }, { 0x18DF, "Cinea Inc." }, { 0x18E0, "Source Technologies, LLC" }, { 0x18E1, "Drew Technologies Inc." }, { 0x18E2, "S.J. Electronics Co., Ltd" }, { 0x18E3, "Fitilink Integrated Technology, Inc." }, { 0x18E4, "SB Solutions, Inc" }, { 0x18E5, "Ablaze Systems LLC" }, { 0x18E6, "Gobex AS" }, { 0x18E7, "Truscott Designs" }, { 0x18E8, "Mondo Systems" }, { 0x18E9, "Numsite Corporation" }, { 0x18EA, "Matrox Electronic Systems" }, { 0x18EB, "nDezign, Inc." }, { 0x18EC, "Arkmicro Technologies Inc." }, { 0x18ED, "Tyco Safety Products" }, { 0x18EE, "Holm Acoustics" }, { 0x18EF, "ELV Elektronik AG" }, { 0x18F0, "AVAL DATA CORPORATION" }, { 0x18F1, "AL Tech, Inc." }, { 0x18F2, "Rasotto S.N.C." }, { 0x18F3, "Miglia Technology Ltd." }, { 0x18F4, "Vtech Engineering Corporation" }, { 0x18F5, "Esterline Mason" }, { 0x18F6, "Zermatt Systems Inc" }, { 0x18F7, "ImageStream Internet Solutions Inc.." }, { 0x18F8, "Teitsu Denshi Kenkyusho Co., Ltd." }, { 0x18F9, "EX COMPANY LIMITED" }, { 0x18FA, "Kuang Ying Computer Equipment Co., Ltd." }, { 0x18FB, "Scriptel Corporation" }, { 0x18FC, "Kinyo Co., Ltd." }, { 0x18FD, "FineArch Inc." }, { 0x18FE, "SecuriMetrics, Inc." }, { 0x18FF, "HYUNDAI Digital Technology Co., Ltd." }, { 0x1900, "Future Wave, Inc." }, { 0x1901, "GE Healthcare" }, { 0x1902, "CSIRO Marine & Atmospheric Research" }, { 0x1903, "ANEX SYSTEM LTD." }, { 0x1904, "LVI Low Vision International AB" }, { 0x1905, "EGEMEN Bilgisayar Muh ve San LTD STI" }, { 0x1906, "Seoro Tech Co., Ltd." }, { 0x1907, "Elcoteq Design Center Oy" }, { 0x1908, "APPOTECH LIMITED" }, { 0x1909, "ABB Inc. Totalflow Division" }, { 0x190A, "Freewide Inc." }, { 0x190B, "Metasoft S.C." }, { 0x190C, "ierise Inc." }, { 0x190D, "Motorola GSG" }, { 0x190E, "YAMASA Tokei-Keiki Co, Ltd" }, { 0x190F, "YA HORNG ELECTRONIC CO., LTD." }, { 0x1910, "Seriprint-Ziprip UK Limited" }, { 0x1911, "Nihon Dengyo Kosaku Co., Ltd." }, { 0x1912, "Yukyung Technologies Co, Ltd" }, { 0x1913, "Atomynet, Inc." }, { 0x1914, "Alco Digital Devices Limited" }, { 0x1915, "Nordic Semiconductor ASA" }, { 0x1916, "Juniper Systems, Inc." }, { 0x1917, "Imagetech Corporation" }, { 0x1918, "NanoSystem Solutions, Inc." }, { 0x1919, "Pixelworks" }, { 0x191A, "PATLITE Corporation" }, { 0x191B, "PICOCEL Co., Ltd." }, { 0x191C, "Innovative Technology Limited" }, { 0x191D, "Midtronics, Inc." }, { 0x191E, "Monsoon Multimedia Inc." }, { 0x191F, "Venetex Co., Ltd." }, { 0x1920, "U.S. Digital Television, LLC" }, { 0x1921, "Interson Corporation" }, { 0x1922, "Power 7 Technologies Corp." }, { 0x1923, "FitSense Technology, Inc." }, { 0x1924, "QnAp iT" }, { 0x1925, "InnoFaith beauty sciences B.V." }, { 0x1926, "NextWindow Limited" }, { 0x1927, "Vulcan Portals Inc." }, { 0x1928, "PROCEQ SA" }, { 0x1929, "Wagner Owen Corporation" }, { 0x192A, "Intek" }, { 0x192B, "KVH Industries, Inc." }, { 0x192C, "Twig Com Oy" }, { 0x192D, "AgileTV" }, { 0x192E, "Bioanalytical Systems" }, { 0x192F, "Avago Technologies, Pte." }, { 0x1930, "Shenzhen Xianhe Technology Co., Ltd." }, { 0x1931, "Ningbo Broad Telecommunication Co., Ltd." }, { 0x1932, "Daniels Electronics Ltd." }, { 0x1933, "TASER INTERNATIONAL INC." }, { 0x1934, "SAKAI Medical Co., Ltd." }, { 0x1935, "Elektron Music Machines AB" }, { 0x1936, "Asaka Riken Co., Ltd" }, { 0x1937, "Dynjab Technologies Pty. Ltd." }, { 0x1938, "Meinberg Funkuhren GmbH & Co. KG" }, { 0x1939, "Hilscher GmbH" }, { 0x193A, "Lipman Electronic Engineering Ltd." }, { 0x193B, "Power Monitors, Inc." }, { 0x193C, "COGELEC" }, { 0x193D, "MAXIAN Co., Ltd." }, { 0x193E, "Chestnut Hill Sound Inc." }, { 0x193F, "OPDICOM PTY LTD" }, { 0x1940, "U.S. Music Corporation" }, { 0x1941, "Top Eight Industrial Corp." }, { 0x1942, "GAMING PARTNERS INTERNATIONAL" }, { 0x1943, "Sensoray" }, { 0x1944, "Wegener Communications" }, { 0x1945, "O-Pen" }, { 0x1946, "Irisguard UK Ltd" }, { 0x1947, "Harris Corporation" }, { 0x1948, "Darlitech International Co., Ltd." }, { 0x1949, "Lab126" }, { 0x194A, "Secure Design Institute Co., Ltd." }, { 0x194B, "Yanago Design Inc." }, { 0x194C, "Scanivalve Corp." }, { 0x194D, "Kern AG" }, { 0x194E, "acam-messelectronic GmbH" }, { 0x194F, "PreSonus Audio Electronics" }, { 0x1950, "FUJINON CORPORATION" }, { 0x1951, "Hyperstone GmbH" }, { 0x1952, "X-TEMPO DESIGNS LLC" }, { 0x1953, "Ironkey Inc." }, { 0x1954, "Radiient Technologies" }, { 0x1955, "4G Systems GmbH" }, { 0x1956, "The SmartPill Corporation" }, { 0x1957, "BIOS Corporation" }, { 0x1958, "Office Depot, Inc." }, { 0x1959, "DRS Signal Solutions Inc." }, { 0x195A, "Technology Link Corporation" }, { 0x195B, "Huge China Industrial Ltd." }, { 0x195C, "NewSight" }, { 0x195D, "Itron Technology Inc." }, { 0x195E, "Datakey Electronics" }, { 0x195F, "GODEX INTERNATIONAL CO., LTD." }, { 0x1960, "Brains Corporation" }, { 0x1961, "Grupo CD World S.L." }, { 0x1962, "Vstone Corp." }, { 0x1963, "IK MULTIMEDIA PRODUCTION srl" }, { 0x1964, "ID Technica Sales Co., Ltd." }, { 0x1965, "Uniden Corporation" }, { 0x1966, "ELESTA GmbH" }, { 0x1967, "CASIO HITACHI Mobile Communications Co., Ltd." }, { 0x1968, "Global Silicon Ltd." }, { 0x1969, "TM-Research, Inc." }, { 0x196A, "SmartCom" }, { 0x196B, "Wispro Technology Inc." }, { 0x196C, "EMKA Technologies" }, { 0x196D, "InnoDisk Corporation" }, { 0x196E, "SEI" }, { 0x196F, "Otoichi Corporation" }, { 0x1970, "Dane-Elec Corp. USA" }, { 0x1971, "Real ID Technology Co., Ltd." }, { 0x1972, "Diagnostic Instruments, Inc." }, { 0x1973, "SpectraLink Corporation" }, { 0x1974, "LOSTEAKA, Inc." }, { 0x1975, "Dongguan Guneetal Wire & Cable Co., Ltd." }, { 0x1976, "Chipsbrand Microelectronics (HK) Co., Ltd." }, { 0x1977, "Thales" }, { 0x1978, "Lismore Instruments Limited" }, { 0x1979, "Suga Digital Technology Limited" }, { 0x197A, "Kellendonk Elektronik GmbH" }, { 0x197B, "Way Systems Inc." }, { 0x197C, "JSC Videofon MV" }, { 0x197D, "Leuze electronic GmbH & Co. KG" }, { 0x197E, "scemtec Transponder Technology GmbH" }, { 0x197F, "Triton" }, { 0x1980, "Storage Appliance Corp." }, { 0x1981, "Matrix Audio Designs Inc." }, { 0x1982, "Hitel Italia S.P.A." }, { 0x1983, "Icera Inc." }, { 0x1984, "Targetti Sankey S.P.A." }, { 0x1985, "Elmos Co., Ltd." }, { 0x1986, "Excelitas Technologies Corporation" }, { 0x1987, "Camille Bauer AG" }, { 0x1988, "Novar Controls" }, { 0x1989, "Nuconn Technology Corp." }, { 0x198A, "MODMEN Co., Ltd." }, { 0x198B, "Fluid Imaging Technologies, Inc" }, { 0x198C, "c-scape" }, { 0x198D, "Fairchild Imaging" }, { 0x198E, "Ingrid, Inc." }, { 0x198F, "Beceem Communications Inc." }, { 0x1990, "Acron Precision Industrial Co., Ltd." }, { 0x1991, "AAI Corporation" }, { 0x1992, "Avantes B.V." }, { 0x1993, "Bluetop Technology Co., Ltd." }, { 0x1994, "ZMM Ltd." }, { 0x1995, "Trillium Technology PTY LTD." }, { 0x1996, "PixeLINK" }, { 0x1997, "CEFLA S.C.R.L." }, { 0x1998, "JENOPTIK Laser, Optik, Systeme GmbH" }, { 0x1999, "iba AG" }, { 0x199A, "DNA-Technology" }, { 0x199B, "MicroStrain, Inc." }, { 0x199C, "Richnex Microelectronics Corporation" }, { 0x199D, "Dexxon Groupe" }, { 0x199E, "The Imaging Source Europe GmbH" }, { 0x199F, "Benica Corporation" }, { 0x19A0, "Krautkramer Japan Co., Ltd." }, { 0x19A1, "Zeecraft Tech." }, { 0x19A2, "SICK AG" }, { 0x19A3, "ASmobile Communication Inc." }, { 0x19A4, "Unique Medical Co., Ltd." }, { 0x19A5, "Harris RF Communication" }, { 0x19A6, "UBISYS TECHNOLOGIES" }, { 0x19A7, "SuperTop International Corp." }, { 0x19A8, "Biforst Technology Inc." }, { 0x19A9, "Musashi Co., Ltd." }, { 0x19AA, "musicobo" }, { 0x19AB, "Bodelin Technologies" }, { 0x19AC, "Hardworks, Inc." }, { 0x19AD, "RiTTO GmbH & Co. KG" }, { 0x19AE, "KeeLog" }, { 0x19AF, "Innomax Technology Ltd." }, { 0x19B0, "Sobal Corporation" }, { 0x19B1, "Kyoritsu Radio Co., Ltd." }, { 0x19B2, "Batronix Elektronik" }, { 0x19B3, "SPOTWAVE WIRELESS" }, { 0x19B4, "CELESTRON" }, { 0x19B5, "B & W Group" }, { 0x19B6, "Infotech Logistic, LLC" }, { 0x19B7, "SK-Electronics Co. Ltd." }, { 0x19B8, "Control Technology Inc." }, { 0x19B9, "Drobo, Inc." }, { 0x19BA, "ebro Electronic GmbH & Co. KG" }, { 0x19BB, "Informtest" }, { 0x19BC, "ioLab Systems Inc." }, { 0x19BD, "Celluon, Inc." }, { 0x19BE, "Guidance Software, Inc." }, { 0x19BF, "HASHIMOTO Electronic Industry Co., Ltd." }, { 0x19C0, "TeraTron GmbH" }, { 0x19C1, "Digital Info Technology Pte. Ltd." }, { 0x19C2, "TARGA GmbH" }, { 0x19C3, "Riskema Informatica e Automacao Ltda." }, { 0x19C4, "Control Gaging, Inc." }, { 0x19C5, "Danaher Sensors and Controls" }, { 0x19C6, "Harmony Microelectronic Inc." }, { 0x19C7, "WEG Equipamentos Eltricos S.A. - Automao" }, { 0x19C8, "Secure Key LLC" }, { 0x19C9, "Electronic Sports" }, { 0x19CA, "Sandio Technology Corp." }, { 0x19CB, "EMS (European) LTD." }, { 0x19CC, "SCIEN Co." }, { 0x19CD, "D. O. Tel Co., Ltd." }, { 0x19CE, "SINUS Messtechnik GmbH" }, { 0x19CF, "Parrot SA" }, { 0x19D0, "Pan Pacific Enterprise Co., Inc." }, { 0x19D1, "Channaa" }, { 0x19D2, "ZTE Corporation" }, { 0x19D3, "Zucchetti Centro Sistemi SPA" }, { 0x19D4, "I Bee, K.K." }, { 0x19D5, "CNB Technology Inc." }, { 0x19D6, "WIDE Corporation" }, { 0x19D7, "Unitop New Technology Co., Ltd." }, { 0x19D8, "Smart Point SA" }, { 0x19D9, "Fujitsu Ten Limited" }, { 0x19DA, "MUSE Inc." }, { 0x19DB, "GeBE Elektronik und Feinwerktechnik GmbH" }, { 0x19DC, "Communications & Power Industries" }, { 0x19DD, "NEXVU TECHNOLOGIES, Inc." }, { 0x19DE, "MITEQ Inc." }, { 0x19DF, "AlpnaCom" }, { 0x19E0, "Micro-Nits Co., Ltd." }, { 0x19E1, "WeiDuan Electronic Accessory (S.Z.) Co., Ltd." }, { 0x19E2, "Solomon Systech Limited" }, { 0x19E3, "Bae Systems IEWS" }, { 0x19E4, "In-Situ Inc." }, { 0x19E5, "Jetmobile" }, { 0x19E6, "Apex Digital Inc." }, { 0x19E7, "Charismathics GmbH" }, { 0x19E8, "Industrial Technology Research Institute" }, { 0x19E9, "Bartec Auto ID Ltd." }, { 0x19EA, "Lung Hwa Electronics Co., Ltd." }, { 0x19EB, "ACE Antenna, Advanced Technology R&D Team." }, { 0x19EC, "Forth Dimension Displays Ltd." }, { 0x19ED, "Plastic Logic Ltd." }, { 0x19EE, "Modern Marketing Concepts Inc." }, { 0x19EF, "Pak Heng Technology (Shenzhen) Co., Ltd." }, { 0x19F0, "Jyh Woei Industrial Co., Ltd." }, { 0x19F1, "SindoRicoh Co., LTD." }, { 0x19F2, "INFOMARK Co., Ltd." }, { 0x19F3, "JAPAN Kyastem Co., Ltd." }, { 0x19F4, "Malvern Instruments Ltd" }, { 0x19F5, "Nationz Technologies Inc." }, { 0x19F6, "J. A. Woollam Co. Inc." }, { 0x19F7, "Rode Microphones" }, { 0x19F8, "RoboTech srl" }, { 0x19F9, "Megadata (Europe) PLC" }, { 0x19FA, "SHENZHEN GAMEWARE ELECTRONIC CO., LTD." }, { 0x19FB, "VLSI Solution Oy" }, { 0x19FC, "BioControl A/S" }, { 0x19FD, "MTI Instruments" }, { 0x19FE, "Micromap Corporation" }, { 0x19FF, "Best Buy China Ltd." }, { 0x1A00, "Polymax Precision Industry Co., Ltd." }, { 0x1A01, "Siemens Power Transmission & Dist. Energy Automation" }, { 0x1A02, "DLoG GmbH" }, { 0x1A03, "HORIBA ITECH Co., Ltd." }, { 0x1A04, "ASTRO MACHINE CORP." }, { 0x1A05, "Media Lab., Inc" }, { 0x1A06, "Beijing Deng Hong Technology Co., Ltd." }, { 0x1A07, "HID" }, { 0x1A08, "Bellwood International, Inc." }, { 0x1A09, "DILANO GmbH" }, { 0x1A0B, "Teleste OYJ" }, { 0x1A0C, "Sunkorea Electronics Co., Ltd." }, { 0x1A0D, "Ladybug Technologies LLC" }, { 0x1A0E, "Sasse Elektronik GmbH" }, { 0x1A0F, "HT-ITALIA" }, { 0x1A10, "KWANG SUNG ELECTRONICS H.K. Co., Ltd." }, { 0x1A11, "eMDee Technology, Inc." }, { 0x1A12, "KES Co., Ltd." }, { 0x1A13, "Plasmon" }, { 0x1A14, "Brainvision Inc." }, { 0x1A15, "Amphenol-Tuchel Electronics GmbH" }, { 0x1A16, "General Dynamics" }, { 0x1A17, "Oticon A/S" }, { 0x1A18, "Quadzilla Performance Technologies, Inc." }, { 0x1A19, "DDTIC Corporation Ltd." }, { 0x1A1A, "ASIACORP INTERNATIONAL LTD." }, { 0x1A1B, "Fischer-Zoth GmbH" }, { 0x1A1C, "Mercury Computer Systems AG" }, { 0x1A1D, "Syncomm Technology Corp." }, { 0x1A1E, "Dekart s.r.l." }, { 0x1A1F, "Ikanos Communications Inc." }, { 0x1A20, "Mind Logic Co., Ltd." }, { 0x1A21, "ASITEQ Co., Ltd." }, { 0x1A22, "Kenwin Industrial (HK) Ltd." }, { 0x1A23, "Hangzhou YiHeng Technologies Co., Ltd." }, { 0x1A24, "Beyondwiz Co., Ltd." }, { 0x1A25, "Amphenol East Asia Ltd." }, { 0x1A26, "APSI (Asia Pacific Satellite Industry)" }, { 0x1A27, "Senior Technologies" }, { 0x1A28, "NOVITUS SA" }, { 0x1A29, "ABOV Semiconductor Co., Ltd." }, { 0x1A2A, "Seagate Branded Solutions" }, { 0x1A2B, "NTI Corporation" }, { 0x1A2C, "Wuxi China Resources Semico Co., Ltd." }, { 0x1A2D, "WEBSYNC Co., Ltd." }, { 0x1A2E, "Lanner Electronics Inc." }, { 0x1A2F, "Tetradyne Software Inc." }, { 0x1A30, "New Media Life" }, { 0x1A31, "SPEX SamplePrep, LLC" }, { 0x1A32, "Verint Video Technology GmbH" }, { 0x1A33, "Schmid & Partner Engineering AG" }, { 0x1A34, "King Chuang Tech & Electronic Co., Ltd." }, { 0x1A35, "Artesyn Technologies Inc." }, { 0x1A36, "Topdisk Technology Limited" }, { 0x1A37, "Stayhealthy Inc." }, { 0x1A38, "Nemo-Q International AB" }, { 0x1A39, "GBC Scientific Equipment" }, { 0x1A3A, "Laerdal Medical AS" }, { 0x1A3B, "South Mountain Technologies, Ltd." }, { 0x1A3C, "New Image Co., Ltd." }, { 0x1A3D, "ELGA LabWater (VWS UK LTD)" }, { 0x1A3E, "INTEVAC" }, { 0x1A3F, "Hokkei Industries Co., Ltd." }, { 0x1A40, "TERMINUS TECHNOLOGY INC." }, { 0x1A41, "Action Electronics Co., Ltd." }, { 0x1A42, "CROSSLINK GmbH" }, { 0x1A43, "JTEKT CORPORATION" }, { 0x1A44, "VASCO Data Security NV" }, { 0x1A45, "Wavelength Electronics Inc." }, { 0x1A46, "JAVAD GNSS, Inc." }, { 0x1A47, "iQBio, Inc." }, { 0x1A48, "KYOHRITSU ELECTRONIC INDUSTRY Co., Ltd." }, { 0x1A49, "TOKYO SEIMITSU CO., LTD." }, { 0x1A4A, "Silicon Image" }, { 0x1A4B, "SafeBoot International B.V." }, { 0x1A4C, "PMC" }, { 0x1A4D, "N-CRYPT, Inc." }, { 0x1A4E, "SIMS Corp." }, { 0x1A4F, "Haliplex PTY Ltd." }, { 0x1A50, "Mechatro Inc." }, { 0x1A51, "FRWD Technologies Ltd." }, { 0x1A52, "MediaPhy Corporation" }, { 0x1A53, "SANDBOX Co., Ltd" }, { 0x1A54, "Oestling Markiersysteme GmbH" }, { 0x1A55, "Raytheon Systems Limited" }, { 0x1A56, "East Port Technology Co., Ltd." }, { 0x1A57, "ARESIS d.o.o." }, { 0x1A58, "Miranda Technologies Inc." }, { 0x1A59, "HAAG-STREIT AG" }, { 0x1A5A, "Tandberg Data" }, { 0x1A5B, "Entner Electronics KEG" }, { 0x1A5C, "Arkino Corporation Limited" }, { 0x1A5D, "Daikin Denshi Kogyo Co., Ltd." }, { 0x1A5E, "Edixia" }, { 0x1A5F, "Sonatest Limited" }, { 0x1A60, "Joytoto Co., Ltd." }, { 0x1A61, "Abbott Diabetes Care" }, { 0x1A62, "DAT H.K. LIMITED" }, { 0x1A63, "Canfield Scientific, Inc." }, { 0x1A64, "MASTERVOLT INTERNATIONAL" }, { 0x1A65, "ELEKTRINA d.o.o., podjetje za razvoj elektronike" }, { 0x1A66, "Andatek Technology, Ltd." }, { 0x1A67, "Privaris" }, { 0x1A68, "Double Top Technology Ltd." }, { 0x1A69, "Kalon Semiconductor, Inc." }, { 0x1A6A, "Cypress Semiconductor GmbH" }, { 0x1A6B, "Taiwin Electronics Co., Ltd." }, { 0x1A6C, "Hivion Co., Ltd." }, { 0x1A6D, "SamYoung Electronics Co., Ltd" }, { 0x1A6E, "Global Unichip Corp." }, { 0x1A6F, "Sagem Orga GmbH" }, { 0x1A70, "Items Technology Co., Ltd." }, { 0x1A71, "SEIDEL Elektronik GmbH Nfg. KG" }, { 0x1A72, "Physik Instrumente (PI) GmbH & Co. KG" }, { 0x1A73, "Huntron Inc." }, { 0x1A74, "Oberthur Technologies" }, { 0x1A75, "Nautilus Hyosung" }, { 0x1A76, "JADAK Technologies, Inc." }, { 0x1A77, "American Master Import 26, Inc." }, { 0x1A78, "AirLink Communications, Inc." }, { 0x1A79, "Ascensia Diabetes Care" }, { 0x1A7A, "Softron Co., Ltd." }, { 0x1A7B, "Lumberg Connect GmbH" }, { 0x1A7C, "Evoluent LLC" }, { 0x1A7D, "Systex Corporation" }, { 0x1A7E, "MELTEC Systementwicklung" }, { 0x1A7F, "SSD COMPANY LIMITED" }, { 0x1A80, "Zhong Ming Wire Cable Technology (Xiamen) Co., Ltd." }, { 0x1A81, "G.Tech Technology Ltd." }, { 0x1A82, "Proconn Technology Co., Ltd." }, { 0x1A83, "Socle Technology Corp." }, { 0x1A84, "COBB Tuning, Inc." }, { 0x1A85, "Southwest Research Institute" }, { 0x1A86, "Nanjing Qinherg Electronics Co., Ltd." }, { 0x1A87, "TechLab 2000 Ltd. Co., Sp Zo.o." }, { 0x1A88, "WowWee Limited" }, { 0x1A89, "Dynalith Systems Co., Ltd." }, { 0x1A8A, "Simula Technology Inc." }, { 0x1A8B, "SGS Taiwan Ltd." }, { 0x1A8C, "MagicEyes Digital Co., Ltd" }, { 0x1A8D, "BandRich Inc." }, { 0x1A8E, "XiTRON Technologies" }, { 0x1A8F, "Harman Becker Automotive Systems, GmbH" }, { 0x1A90, "Resource Data Management" }, { 0x1A91, "GEOMC Co., Ltd." }, { 0x1A92, "Berkash Enterprise" }, { 0x1A93, "Promotional Technologies International Corp." }, { 0x1A94, "STWTECH Co., Ltd." }, { 0x1A95, "Sextant Labs, Inc." }, { 0x1A96, "Harman Becker Automotive Systems, Inc." }, { 0x1A97, "XM Satellite Radio Inc." }, { 0x1A98, "Leica Camera AG" }, { 0x1A99, "Asia Tai Technology (Dongguan) Co., Ltd." }, { 0x1A9A, "Verari Systems, Inc." }, { 0x1A9B, "Balboa Instruments" }, { 0x1A9C, "Inomed Medizintechnik GmbH" }, { 0x1A9D, "TrafficSim Co., Ltd." }, { 0x1A9E, "Epicenter, Inc." }, { 0x1A9F, "Hysitron Incorporated" }, { 0x1AA0, "Auto Enginuity, L.L.C." }, { 0x1AA1, "Vestax Corporation" }, { 0x1AA2, "ORIENTAL MOTOR CO., LTD." }, { 0x1AA3, "ZOLL Medical Corporation" }, { 0x1AA4, "Data Drive Thru, Inc." }, { 0x1AA5, "UBeacon Technologies, Inc." }, { 0x1AA6, "eFortune Technology Corp." }, { 0x1AA7, "SiliconSystems, Inc." }, { 0x1AA8, "Waves Audio Ltd." }, { 0x1AA9, "Home Phone Tunes Inc." }, { 0x1AAA, "Taylor Associates/Communications, Inc." }, { 0x1AAB, "SilverCreations Software AG" }, { 0x1AAC, "Witschi Electronic AG" }, { 0x1AAD, "KeeTouch Electronic Co., Ltd." }, { 0x1AAE, "Johnson Component & Equipments Co., Ltd." }, { 0x1AAF, "Intellectual Property Library Company" }, { 0x1AB0, "DAEWOO ELECTRONIC COMPONENTS CO., LTD." }, { 0x1AB1, "Rigol Technologies, Inc." }, { 0x1AB2, "Allied Vision Technologies GmbH" }, { 0x1AB3, "M and C System" }, { 0x1AB4, "Japan Remote Control Co., Ltd." }, { 0x1AB5, "Hamamatsu TOA Electronics, Inc." }, { 0x1AB6, "Integrated Technology Corp." }, { 0x1AB7, "GLOBAL VR, Inc." }, { 0x1AB8, "Pen Laboratory Inc." }, { 0x1AB9, "Nomadio Inc." }, { 0x1ABA, "Kenton Electronics Limited" }, { 0x1ABB, "Airo Wireless Media Inc." }, { 0x1ABC, "Fuji Photo Film USA" }, { 0x1ABD, "PERTO S.A." }, { 0x1ABE, "MP3Car.com Inc" }, { 0x1ABF, "ANIMA Corporation" }, { 0x1AC0, "SOKKIA Co., Ltd." }, { 0x1AC1, "LIANHE TECHNOLOGIES, INC." }, { 0x1AC2, "DESKO GmbH" }, { 0x1AC3, "DISK KING Technology Co., Ltd." }, { 0x1AC4, "CAO Group, Inc." }, { 0x1AC5, "Electronic Engineering Solutions S.L." }, { 0x1AC6, "JAPAN ADE LTD." }, { 0x1AC7, "Modular Communication Systems, Inc." }, { 0x1AC8, "Toyota Industries Corporation" }, { 0x1AC9, "Broadxent Pte. Ltd." }, { 0x1ACA, "Bluebird Soft Inc." }, { 0x1ACB, "Salcomp Plc" }, { 0x1ACC, "Ta Horng Musical Instrument Co., Ltd." }, { 0x1ACD, "MKS Instruments" }, { 0x1ACE, "Temento Systems" }, { 0x1ACF, "International Manufacturing & Engineering Services Co." }, { 0x1AD0, "Cygnetron, Inc." }, { 0x1AD1, "Desan Wire Co., Ltd." }, { 0x1AD2, "Mesa Imaging AG" }, { 0x1AD3, "Advanced Technetix, Inc." }, { 0x1AD4, "Advanced Printing Systems" }, { 0x1AD5, "Gentec-EO" }, { 0x1AD6, "General Dynamics SATCOM Technologies, State College Fac" }, { 0x1AD7, "A.B.O. Co., Ltd." }, { 0x1AD8, "Motion Control i Vsters AB" }, { 0x1AD9, "Rocket Gaming Systems" }, { 0x1ADA, "VEGA Grieshaber KG" }, { 0x1ADB, "Schweitzer Engineering Laboratories" }, { 0x1ADC, "Turbolinux, Inc." }, { 0x1ADD, "Marshall Electronics, Inc." }, { 0x1ADE, "SpinMaster Ltd." }, { 0x1ADF, "digital design GmbH" }, { 0x1AE0, "Axiomatic Technologies Corp." }, { 0x1AE1, "Hoffman Engineering" }, { 0x1AE2, "A-JET Technology Co., LTD." }, { 0x1AE3, "Chung Young Digital Corp., Ltd." }, { 0x1AE4, "ic-design Reinhard Gottinger GmbH" }, { 0x1AE5, "Jianduan Technology (Shenzhen) Co., Ltd" }, { 0x1AE6, "JOA Telecom Co., Ltd." }, { 0x1AE7, "Joellenbeck GmbH" }, { 0x1AE8, "Myway Labs Co., Ltd." }, { 0x1AE9, "arnotec GmbH" }, { 0x1AEA, "Mobilygen Corporation" }, { 0x1AEB, "NIHON UNICA CORPORATION" }, { 0x1AEC, "PORTEK TECHNOLOGY CORPORATION" }, { 0x1AED, "High Top Precision Electronic Co., Ltd." }, { 0x1AEE, "SHEN ZHEN REX TECHNOLOGY CO., LTD." }, { 0x1AEF, "Octekconn Incorporation" }, { 0x1AF0, "SuperPix Micro Technology Limited" }, { 0x1AF1, "Connect One, Ltd." }, { 0x1AF2, "AXSionics AG" }, { 0x1AF3, "Smarthome Technology Limited" }, { 0x1AF4, "NCS Pearson, Inc." }, { 0x1AF5, "Arima Communications Corp." }, { 0x1AF6, "SL International Ltd." }, { 0x1AF7, "GRAPHIN CO., LTD." }, { 0x1AF8, "JS-ROBOTICS" }, { 0x1AF9, "Alvarion Ltd." }, { 0x1AFA, "Mobinnova Corp." }, { 0x1AFB, "Kirche Jesu Christi der Heiligen der Letzten Tage" }, { 0x1AFC, "Blue Orb" }, { 0x1AFD, "FarSite Communications Limited" }, { 0x1AFE, "A. Eberle GmbH & Co. KG" }, { 0x1AFF, "Defibtech, LLC" }, { 0x1B00, "Uster Technologies, Inc." }, { 0x1B01, "ETA Chips, Co." }, { 0x1B02, "MEN Mikro Elektronik GmbH" }, { 0x1B03, "Moog Japan Ltd." }, { 0x1B04, "MEILHAUS Electronic GmbH" }, { 0x1B05, "Cracol Developments Ltd." }, { 0x1B06, "OPGAL" }, { 0x1B07, "WEY Technology AG" }, { 0x1B08, "Actimo Inc." }, { 0x1B09, "MISUZU INDUSTRIES CORPORATION" }, { 0x1B0A, "Sense Technology Inc." }, { 0x1B0B, "Lambda Systems Inc." }, { 0x1B0C, "MYTECS Co., Ltd." }, { 0x1B0D, "SmarDTV" }, { 0x1B0E, "BLUTRONICS S.R.L." }, { 0x1B0F, "EKS-ELEKTRONIKSERVICE GmbH" }, { 0x1B10, "KAGA COMPONENTS CO., LTD." }, { 0x1B11, "OneClick Technologies Ltd." }, { 0x1B12, "Eventide, Inc." }, { 0x1B13, "Neuf Cegetel" }, { 0x1B14, "Ergotron, Inc." }, { 0x1B15, "i3micro technology ab" }, { 0x1B16, "LinTech GmbH Berlin" }, { 0x1B17, "SHENZHEN e-loam Technology Co., Ltd." }, { 0x1B18, "Mikrolab Entwicklungsgesellschaft fur Elektroniksysteme" }, { 0x1B19, "RADA Electronic Industries Ltd." }, { 0x1B1A, "Tianjin China-Silicon Microelectronics Co., Ltd." }, { 0x1B1B, "Shenzhen MD Electric Co., Ltd." }, { 0x1B1C, "CORSAIR MEMORY INC." }, { 0x1B1D, "Torian Wireless Ltd." }, { 0x1B1E, "General Imaging Company" }, { 0x1B1F, "eQ-3 Entwicklung GmbH" }, { 0x1B20, "MStar Semiconductor, Inc." }, { 0x1B21, "XenICs nv" }, { 0x1B22, "WiLinx Corp." }, { 0x1B23, "Skyray Instrument Co., Ltd." }, { 0x1B24, "Telegent Systems Inc." }, { 0x1B25, "ALE" }, { 0x1B26, "Plug Power" }, { 0x1B27, "Current Electronics Inc." }, { 0x1B28, "NAVIsis Inc." }, { 0x1B29, "Industrie Dial Face S.p.A." }, { 0x1B2A, "MICRO EMISSION CO., LTD." }, { 0x1B2B, "Neural Image Co., Ltd." }, { 0x1B2C, "Advanced Thermal Solutions, Inc." }, { 0x1B2D, "Photon Inc." }, { 0x1B2E, "ETANI ELECTRONICS CO., LTD." }, { 0x1B2F, "Ihara Electronic Industries Co.,Ltd." }, { 0x1B30, "STZ QSBV Ilmenau" }, { 0x1B31, "Renu Electronics Pvt. Ltd." }, { 0x1B32, "Ugobe, Inc." }, { 0x1B33, "3DV Systems Ltd." }, { 0x1B34, "EyeTalk Systems, Inc." }, { 0x1B35, "Paradigm Electronics Inc." }, { 0x1B36, "ViXS Systems, Inc." }, { 0x1B37, "Savant Systems, LLC" }, { 0x1B38, "ALBAHITH TECHNOLOGIES" }, { 0x1B39, "ViaMichelin SAS" }, { 0x1B3A, "JUMO GmbH & Co. KG" }, { 0x1B3B, "iPassion Technology Inc." }, { 0x1B3C, "DEVI A/S" }, { 0x1B3D, "Matrix Orbital" }, { 0x1B3E, "STIL SA" }, { 0x1B3F, "Generalplus Technology Inc." }, { 0x1B40, "AISIN SEIKI CO., LTD." }, { 0x1B41, "Fujitsu Australia Limited" }, { 0x1B42, "Cardinal Scale Manufacturing Company" }, { 0x1B43, "Extron Design Services" }, { 0x1B44, "Elite Co., Ltd." }, { 0x1B45, "Cyan Technology Ltd." }, { 0x1B46, "Holylite Microelectronics Corp." }, { 0x1B47, "Energizer Holdings, Inc." }, { 0x1B48, "Plastron Precision Co., Ltd." }, { 0x1B49, "Applied Printed Electronics Research, LLC" }, { 0x1B4A, "Gem-Med, S.L." }, { 0x1B4B, "Watson Marlow Ltd." }, { 0x1B4C, "Unitron Group" }, { 0x1B4D, "Objet Geometries Ltd." }, { 0x1B4E, "ELPRO-BUCHS AG" }, { 0x1B4F, "Spark Fun Electronics" }, { 0x1B50, "DictaNet Software AG" }, { 0x1B51, "Kundisch GmbH & Co. KG" }, { 0x1B52, "A.R. Hungary, Inc." }, { 0x1B53, "DANI Instruments S.p.A." }, { 0x1B54, "COMMIT Incorporated" }, { 0x1B55, "ZKSoftware Inc." }, { 0x1B56, "V.I.O., Inc." }, { 0x1B57, "ATREE Inc." }, { 0x1B58, "Sumitomo Elec Ind Ltd. Lightwave Network Products Div." }, { 0x1B59, "K.S. Terminals Inc." }, { 0x1B5A, "Chao Zhou Kai Yuan Electric Co., Ltd." }, { 0x1B5B, "Homoth Medizinelektronik" }, { 0x1B5C, "ICP DAS Co., Ltd." }, { 0x1B5D, "MV Circuit Design, Inc." }, { 0x1B5E, "General Engine Management Systems Ltd." }, { 0x1B5F, "Wayne Dalton Corp." }, { 0x1B60, "NanoDrop Technologies, Inc." }, { 0x1B61, "n-Trance Security Ltd." }, { 0x1B62, "Shenzhen Aoni Electronic Industry Co., Ltd." }, { 0x1B63, "Seedsware Corporation" }, { 0x1B64, "C.G. Development Ltd." }, { 0x1B65, "The Hong Kong Standards and Testing Centre Ltd." }, { 0x1B66, "Bontempi-Farfisa Sigma S.p.A." }, { 0x1B67, "Toradex AG" }, { 0x1B68, "ZAFENA AB" }, { 0x1B69, "KLA-Tencor" }, { 0x1B6A, "HIKARI Co., Ltd." }, { 0x1B6B, "Modiotek Co., Ltd." }, { 0x1B6C, "Techno Veins Co., Ltd." }, { 0x1B6D, "IDpendant GmbH" }, { 0x1B6E, "HS Automatic ApS" }, { 0x1B6F, "Federal Signal Vama S.A." }, { 0x1B70, "Minicom Advanced Systems" }, { 0x1B71, "Huizhou 10Moons Technology Development Co., Ltd." }, { 0x1B72, "ATERGI TECHNOLOGY CO., LTD." }, { 0x1B73, "Vehicle Camera Systems Ltd" }, { 0x1B74, "MODAFUN, Inc." }, { 0x1B75, "OvisLink Corp." }, { 0x1B76, "Legend Silicon Corp." }, { 0x1B77, "Protec, Inc." }, { 0x1B78, "LOGICPACK CO., LTD." }, { 0x1B79, "WingsTek, Inc." }, { 0x1B7A, "Electrox" }, { 0x1B7B, "Ingersoll Rand Co." }, { 0x1B7C, "io Corporation" }, { 0x1B7D, "SUNGIL TELECOM" }, { 0x1B7E, "Lutron Electronics Inc." }, { 0x1B7F, "EMC Corporation" }, { 0x1B80, "KWorld Computer Co., Ltd." }, { 0x1B81, "Kratos Analytical Ltd." }, { 0x1B82, "Mcube Technology Co., Ltd." }, { 0x1B83, "Megatone systems and Technologies LTD." }, { 0x1B84, "WALTHER Data GmbH Scan-Solutions" }, { 0x1B85, "INNOVA S.A." }, { 0x1B86, "Dongguan Guanshang Electronics Co., Ltd." }, { 0x1B87, "Davis Instruments" }, { 0x1B88, "ShenMing Electron (Dong Guan) Co., Ltd." }, { 0x1B89, "iCache, Incorporated" }, { 0x1B8A, "Quellan, Inc." }, { 0x1B8B, "PROCES-DATA A/S" }, { 0x1B8C, "Altium Limited" }, { 0x1B8D, "e-MOVE Technology Co., Ltd." }, { 0x1B8E, "Amlogic, Inc." }, { 0x1B8F, "Super Talent Technology, Inc." }, { 0x1B90, "Deep Sea Electronics Plc" }, { 0x1B91, "Zicplay SA" }, { 0x1B92, "Trysys Co., Ltd." }, { 0x1B93, "Phoenix Contact GmbH & Co. KG" }, { 0x1B94, "Yoggie Security Systems" }, { 0x1B95, "EVC electronic GmbH" }, { 0x1B96, "N-Trig" }, { 0x1B97, "Metronix GmbH" }, { 0x1B98, "YMax Communications Corp." }, { 0x1B99, "Shenzhen Yuanchuan Electronic" }, { 0x1B9A, "Applied Vision Systems Corporation" }, { 0x1B9B, "Microtrac, Inc." }, { 0x1B9C, "Maki Manufacturing Co., Ltd." }, { 0x1B9D, "Sigma Instruments, Inc." }, { 0x1B9E, "ARCoptix S.A" }, { 0x1B9F, "GHI Electronics, LLC" }, { 0x1BA0, "Jiangmen Kong Yue Jolimark Information Technology Ltd." }, { 0x1BA1, "JINQ CHERN ENTERPRISE CO., LTD." }, { 0x1BA2, "Lite Metals & Plastic (Shenzhen) Co., Ltd." }, { 0x1BA3, "EmbeddedFusion Ltd." }, { 0x1BA4, "Ember Corporation" }, { 0x1BA5, "Futiro" }, { 0x1BA6, "Abilis Systems" }, { 0x1BA7, "Xantech Corporation" }, { 0x1BA8, "China Telecommunication Technology Labs" }, { 0x1BA9, "Renau Electronic Laboratories" }, { 0x1BAA, "Transcell Technology, Inc." }, { 0x1BAB, "MATT R.P.Traczynscy Sp.J." }, { 0x1BAC, "Bernecker + Rainer Industrie-Elektronik Ges.m.b.H." }, { 0x1BAD, "Harmonix Music Systems, Inc." }, { 0x1BAE, "Vuzix Corporation" }, { 0x1BAF, "NIIGATA SEIMITSU CO., LTD." }, { 0x1BB0, "LBS PLUS Co., Ltd." }, { 0x1BB1, "Commodore International Corporation" }, { 0x1BB2, "G.T. trading Srl" }, { 0x1BB3, "Holzworth Instrumentation LLC" }, { 0x1BB4, "Satmap Systems Ltd." }, { 0x1BB5, "SEF Roboter GmbH" }, { 0x1BB6, "PdMA Corporation" }, { 0x1BB7, "DGT Sp. z o.o." }, { 0x1BB8, "MIZOUE PROJECT JAPAN Corporation" }, { 0x1BB9, "Qpixel Technology, Inc." }, { 0x1BBA, "Medicomp, Inc." }, { 0x1BBB, "TCL Communication Ltd" }, { 0x1BBC, "KATHREIN-Werke KG" }, { 0x1BBD, "Videology Imaging Solutions, Inc." }, { 0x1BBE, "CE+T s.a." }, { 0x1BBF, "Littfinski DatenTechnik (LDT)" }, { 0x1BC0, "Senselock Software Technology Co.,Ltd" }, { 0x1BC1, "ACE ELECTRONIQUE" }, { 0x1BC2, "SEW-EURODRIVE GmbH & Co. KG" }, { 0x1BC3, "Fujian START Computer Equipment Co., Ltd." }, { 0x1BC4, "Ford Motor Co." }, { 0x1BC5, "AVIXE Technology (China) Ltd." }, { 0x1BC6, "Yurex, Inc." }, { 0x1BC7, "Telit Wireless Solutions" }, { 0x1BC8, "MDS Technology Co., Ltd." }, { 0x1BC9, "Alti-2 Inc." }, { 0x1BCA, "Ishii Hyoki Co., Ltd." }, { 0x1BCB, "Cubic Defence NZ Limited" }, { 0x1BCC, "TopScan Ltd." }, { 0x1BCD, "AZKOYEN" }, { 0x1BCE, "Contac Cable Industrial Limited" }, { 0x1BCF, "Sunplus Innovation Technology Inc." }, { 0x1BD0, "Hangzhou Riyue Electronics Co., Ltd." }, { 0x1BD1, "Companion Worlds, Inc." }, { 0x1BD2, "Beijing G & D Card Systems Co., Ltd." }, { 0x1BD3, "3layer Engineering" }, { 0x1BD4, "FastVDO Inc." }, { 0x1BD5, "BG Systems, Inc." }, { 0x1BD6, "Lodam electronics" }, { 0x1BD7, "TouchNetworks, Inc." }, { 0x1BD8, "Image Computer Systems Limited" }, { 0x1BD9, "Emerson" }, { 0x1BDA, "University of Southampton" }, { 0x1BDB, "Spectral Applied Research" }, { 0x1BDC, "Slacker" }, { 0x1BDD, "QiGO Inc" }, { 0x1BDE, "P-TWO INDUSTRIES, INC." }, { 0x1BDF, "Electrone Americas Ltd., Co." }, { 0x1BE0, "Analog Devices, Inc. - Test Technology Group" }, { 0x1BE1, "LG-Ericsson Co., Ltd" }, { 0x1BE2, "Shenzhen Fametech Electronic Co., Ltd." }, { 0x1BE3, "WAGO Kontakttechnik GmbH & Co. KG" }, { 0x1BE4, "Integrated Digital Technologies, Inc. (IDTI)" }, { 0x1BE5, "NetLogic Microsystems" }, { 0x1BE6, "NAVENTO TECHNOLOGIES" }, { 0x1BE7, "CPR Tools, Inc." }, { 0x1BE8, "MEDAV GmbH" }, { 0x1BE9, "CONCH ELECTRONIC CO., LTD." }, { 0x1BEA, "ATTO Corporation" }, { 0x1BEB, "HOYA CANDEO OPTRONICS CORPORATION" }, { 0x1BEC, "isMedia Co., Ltd." }, { 0x1BED, "OPT Corporation" }, { 0x1BEE, "KCI Medical Products (UK) Ltd." }, { 0x1BEF, "Shenzhen Tongyuan Network-Communication Cables Co., Ltd" }, { 0x1BF0, "RealVision Inc." }, { 0x1BF1, "HENGSTLER" }, { 0x1BF2, "Newport Media, Inc." }, { 0x1BF3, "WAVES SYSTEM / SONAMIX" }, { 0x1BF4, "ABB / Drives" }, { 0x1BF5, "Extranet Systems Inc." }, { 0x1BF6, "Orient Semiconductor Electronics, Ltd." }, { 0x1BF7, "Axiotron, Inc." }, { 0x1BF8, "Game Mechanisms LLC" }, { 0x1BF9, "TRACTEL SAS" }, { 0x1BFA, "METROLAB TECHNOLOGY SA" }, { 0x1BFB, "ALLIED PANELS" }, { 0x1BFC, "Guidance Interactive Healthcare" }, { 0x1BFD, "RISINTECH INC." }, { 0x1BFE, "SEOHWA TELECOM Co., LTD." }, { 0x1BFF, "IonOptix Corp." }, { 0x1C00, "prodaSafe GmbH" }, { 0x1C01, "No Climb Products Ltd." }, { 0x1C02, "Kreton Corporation" }, { 0x1C03, "DDL CO., LTD." }, { 0x1C04, "QNAP System Inc." }, { 0x1C05, "Rockwell Collins" }, { 0x1C06, "SeekTech, Inc." }, { 0x1C07, "CEntrance, Inc." }, { 0x1C08, "Arcus-EDS GmbH" }, { 0x1C09, "RAMTEX Engineering ApS" }, { 0x1C0A, "MaxRise Inc." }, { 0x1C0B, "Kato Tech Co., Ltd." }, { 0x1C0C, "Ionics EMS Inc." }, { 0x1C0D, "Relm Wireless" }, { 0x1C0E, "Qstik plc" }, { 0x1C0F, "NEOTECHKNO" }, { 0x1C10, "Lanterra Industrial Co., Ltd." }, { 0x1C11, "UNIMTEC Co., Ltd." }, { 0x1C12, "CONITEC DATENSYSTEME GmbH" }, { 0x1C13, "ALECTRONIC LIMITED" }, { 0x1C14, "SENSITIVE OBJECT" }, { 0x1C15, "TeleWell Oy" }, { 0x1C16, "Afit Corporation" }, { 0x1C17, "LAB REHAB PTE LTD." }, { 0x1C18, "Apria Technology" }, { 0x1C19, "Charder Electronic Co., Ltd." }, { 0x1C1A, "Datel Electronics Ltd." }, { 0x1C1B, "Volkswagen of America, Inc." }, { 0x1C1C, "Schmartz Inc." }, { 0x1C1D, "GASTEC CORPORATION" }, { 0x1C1E, "Focused Test, Inc." }, { 0x1C1F, "Goldvish S.A." }, { 0x1C20, "Fuji Electric Device Technology Co., Ltd." }, { 0x1C21, "ADDMM LLC" }, { 0x1C22, "ZHONGSHAN CHIANG YU ELECTRIC CO., LTD." }, { 0x1C23, "Enzytek Technology Inc." }, { 0x1C24, "DIGITAL IMAGING SYSTEMS GmbH" }, { 0x1C25, "Sunwell Electronics Ltd." }, { 0x1C26, "Shanghai Haiying Electronics Co., Ltd." }, { 0x1C27, "SHENZHEN DNS INDUSTRIES CO., LTD." }, { 0x1C28, "PMDTechnologies" }, { 0x1C29, "Elster Group" }, { 0x1C2A, "NAVIGON AG" }, { 0x1C2B, "SIEB & MEYER AG" }, { 0x1C2C, "QUANTEL LTD." }, { 0x1C2D, "Barloworld Scientific Limited" }, { 0x1C2E, "LiveWire Test Labs, Inc." }, { 0x1C2F, "Wessex Advanced Switching Products Ltd." }, { 0x1C30, "Li Creative Technologies, Inc." }, { 0x1C31, "LS Mtron Ltd." }, { 0x1C32, "INTELBANQ" }, { 0x1C33, "EK-TEAM GmbH" }, { 0x1C34, "Pro-Active" }, { 0x1C35, "Superna Inc." }, { 0x1C36, "Axiom Manufacturing" }, { 0x1C37, "Sonavation, Inc." }, { 0x1C38, "Kirin Techno-System Company, Limited" }, { 0x1C39, "Quantronix, Inc." }, { 0x1C3A, "CCV Deutschland GmbH" }, { 0x1C3B, "Nivis, LLC" }, { 0x1C3C, "INFOTURE, INC." }, { 0x1C3D, "NONIN MEDICAL INC." }, { 0x1C3E, "Wep Peripherals" }, { 0x1C3F, "Amfit, Inc." }, { 0x1C40, "EZ PROTOTYPES" }, { 0x1C41, "CompX Fort" }, { 0x1C42, "VERCET LLC" }, { 0x1C43, "PeCon GmbH" }, { 0x1C44, "Fukasawa Co." }, { 0x1C45, "NavCom Technology Inc." }, { 0x1C46, "Hitachi Zosen Corporation" }, { 0x1C47, "Andrew Telecommunication Product SRL" }, { 0x1C48, "International Truck and Engine Corporation" }, { 0x1C49, "Cherng Weei Technology Corp." }, { 0x1C4A, "Cathay Tri-Tech., Inc." }, { 0x1C4B, "Geratherm Respiratory GmbH" }, { 0x1C4C, "SYSTECH" }, { 0x1C4D, "Everest Display Inc." }, { 0x1C4E, "Koninklijke Gazelle N.V." }, { 0x1C4F, "Beijing Sigmachip Co., Ltd." }, { 0x1C50, "Chatsworth Data Corporation" }, { 0x1C51, "Wisecube Co., Ltd." }, { 0x1C52, "FLEETWOOD ELECTRONICS LTD." }, { 0x1C53, "Heartland Data Co." }, { 0x1C54, "NU-LEC INDUSTRIES" }, { 0x1C55, "LGS" }, { 0x1C56, "RED DIGITAL CINEMA" }, { 0x1C57, "Zalman Tech Co., Ltd." }, { 0x1C58, "IVA Corporation" }, { 0x1C59, "SIXNET, LLC" }, { 0x1C5A, "Fisher and Paykel Healthcare Limited" }, { 0x1C5B, "FUTURE WAVES PTE Ltd." }, { 0x1C5C, "CELLMETRIC LTD." }, { 0x1C5D, "KB Kommutatcionnoy apparatury LTD." }, { 0x1C5E, "Fueltech Ind. & Com. Prod. Elet. Ltda." }, { 0x1C5F, "Watec Co., Ltd." }, { 0x1C60, "Vision & Control GmbH" }, { 0x1C61, "ASI DataMyte, Inc." }, { 0x1C62, "LITEPOINT CORP." }, { 0x1C63, "DLP Design, Inc." }, { 0x1C64, "QSI Corporation" }, { 0x1C65, "PROCENTEC" }, { 0x1C66, "The Trane Company" }, { 0x1C67, "Sugar Creek Solutions LLC" }, { 0x1C68, "Trace Systems, Inc." }, { 0x1C69, "MPB Communications" }, { 0x1C6A, "Regula Ltd." }, { 0x1C6B, "Philips & Lite-ON Digital Solutions Corporation" }, { 0x1C6C, "Skydigital Inc." }, { 0x1C6D, "Bioptigen Inc." }, { 0x1C6E, "MINELAB ELECTRONICS PTY LTD." }, { 0x1C6F, "SUN-A CORPORATION" }, { 0x1C70, "Wessa Engineering" }, { 0x1C71, "HUMANWARE LTD." }, { 0x1C72, "EMTEC Elektronische Messtechnik GmbH" }, { 0x1C73, "AMT Co., Ltd." }, { 0x1C74, "PHOTOVOX srl" }, { 0x1C75, "ARTURIA" }, { 0x1C76, "Sun-Light Electronic Technologies Inc." }, { 0x1C77, "Kaetat Industrial Co., Ltd." }, { 0x1C78, "Mindray DS USA, Inc." }, { 0x1C79, "Unigen Corporation" }, { 0x1C7A, "Egis Technology, Inc." }, { 0x1C7B, "Shenzhen Luxshare Precision Industry Co., Ltd." }, { 0x1C7C, "DELCOP LLC" }, { 0x1C7D, "STARKEY LABORATORIES INC." }, { 0x1C7E, "Hydrometer GmbH" }, { 0x1C7F, "FILTRONIC DEFENCE LIMITED" }, { 0x1C80, "Hoffmann + Krippner GmbH" }, { 0x1C81, "MOTOSOFT b.v." }, { 0x1C82, "Atracsys LLC" }, { 0x1C83, "BEKA Elektronik" }, { 0x1C84, "DRS Tactical Systems" }, { 0x1C85, "Audyssey Laboratories, Inc." }, { 0x1C86, "Tallahassee Technologies, Inc." }, { 0x1C87, "2N TELEKOMUNIKACE a.s." }, { 0x1C88, "Somagic, Inc." }, { 0x1C89, "HONGKONG WEIDIDA ELECTRON LIMITED" }, { 0x1C8A, "SHIN HEUNG PRECISION CO., LTD." }, { 0x1C8B, "Bridgestone Cycle Co., Ltd." }, { 0x1C8C, "noax Technologies AG" }, { 0x1C8D, "Payter BV" }, { 0x1C8E, "ASTRON INTERNATIONAL CORP." }, { 0x1C8F, "Scolis Technologies (India) Pvt. Ltd." }, { 0x1C90, "Pixela (Shanghai) Co., Ltd." }, { 0x1C91, "Hutchinson Technology Incorporated" }, { 0x1C92, "JDD Enterprises" }, { 0x1C93, "Airspan Networks" }, { 0x1C94, "Maerzhaeuser Wetzlar GmbH & Co. KG." }, { 0x1C95, "OVATION SYSTEMS LIMITED" }, { 0x1C96, "Tesselon, LLC" }, { 0x1C97, "PEBBLE ENTERTAINMENT GmbH" }, { 0x1C98, "ALPINE ELECTRONICS, INC." }, { 0x1C99, "KETEREX, Inc." }, { 0x1C9A, "Simple Step LLC" }, { 0x1C9B, "Ohden Co., Ltd." }, { 0x1C9C, "Technological Solutions Laboratory" }, { 0x1C9D, "Descuentos y Electronicos AVA" }, { 0x1C9E, "Shanghai Longcheer 3G Technology Co., Ltd." }, { 0x1C9F, "SISS Technology Inc." }, { 0x1CA0, "ACCARIO Inc." }, { 0x1CA1, "Symwave, Inc." }, { 0x1CA2, "G-coder Systems AB" }, { 0x1CA3, "CAPAZ GmbH" }, { 0x1CA4, "METRICO WIRELESS INC." }, { 0x1CA5, "HASLER RAIL AG" }, { 0x1CA6, "TECHNO-AP Limited Company" }, { 0x1CA7, "BAE SYSTEMS AUSTRALIA LIMITED" }, { 0x1CA8, "ROCCAT STUDIO GmbH" }, { 0x1CA9, "THE TINTOMETER LTD." }, { 0x1CAA, "Accel Semiconductor Corp." }, { 0x1CAB, "SCS Engineering, Inc." }, { 0x1CAC, "SHENZHEN KINSTONE D&T DEVELOP CO., LTD." }, { 0x1CAD, "ONE-TOO" }, { 0x1CAE, "MPMAN" }, { 0x1CAF, "2WCOM GmbH" }, { 0x1CB0, "LEGRAND FRANCE" }, { 0x1CB1, "Enforce Device Inc." }, { 0x1CB2, "PCO AG" }, { 0x1CB3, "Aces Electronics Co., Ltd." }, { 0x1CB4, "OPEX CORPORATION" }, { 0x1CB5, "Boonton Electronics" }, { 0x1CB6, "IDEACOM TECHNOLOGY INC." }, { 0x1CB7, "EASTERN TIMES TECHNOLOGY CO., LTD." }, { 0x1CB8, "Ferguson Beauregard" }, { 0x1CB9, "DIVERSIFIED TECHNICAL SYSTEMS, INC." }, { 0x1CBA, "MERIDIAN AUDIO LTD." }, { 0x1CBB, "DATATEC CO., LTD." }, { 0x1CBC, "Zizzle, LLC" }, { 0x1CBD, "Wha Shin Co., Ltd." }, { 0x1CBE, "Texas Instruments - Stellaris" }, { 0x1CBF, "FORTAT SKYMARK INDUSTRIAL COMPANY" }, { 0x1CC0, "PlantSense" }, { 0x1CC1, "EXAKTIME INC." }, { 0x1CC2, "CC Systems AB" }, { 0x1CC3, "Biocomfort Diagnostics GmbH & Co. KG" }, { 0x1CC4, "Byte Paradigm sprl" }, { 0x1CC5, "Rane Corporation" }, { 0x1CC6, "Digital Force Technologies" }, { 0x1CC7, "GELOGIC" }, { 0x1CC8, "Iofy Corporation" }, { 0x1CC9, "COMAP, spol. s r. o." }, { 0x1CCA, "NextWave Broadband Inc." }, { 0x1CCB, "Lattebox Co., Ltd." }, { 0x1CCC, "DA-DESIGN OY" }, { 0x1CCD, "Bodatong Technology (Shenzhen) Co., Ltd." }, { 0x1CCE, "DATA MODUL" }, { 0x1CCF, "Konami Digital Entertainment Co., Ltd." }, { 0x1CD0, "VEGATECH CO., LTD." }, { 0x1CD1, "ARTAFLEX" }, { 0x1CD2, "Christ Elektronik GmbH" }, { 0x1CD3, "ATSUMI ELECTRIC CO., LTD." }, { 0x1CD4, "adp corporation" }, { 0x1CD5, "Firecomms Ltd." }, { 0x1CD6, "Antonio Precise Products Manufactory Ltd." }, { 0x1CD7, "GMC-I Gossen-Metrawatt GmbH" }, { 0x1CD8, "Dash Navigation, Inc." }, { 0x1CD9, "TL Industries" }, { 0x1CDA, "NAVICO" }, { 0x1CDB, "Cat Technologies Ltd." }, { 0x1CDC, "Advanced Medical Electronics Corp." }, { 0x1CDD, "YOOSAMFLUTE CO., LTD." }, { 0x1CDE, "Telecommunications Technology Association (TTA)" }, { 0x1CDF, "WonTen Technology Co., Ltd." }, { 0x1CE0, "EDIMAX TECHNOLOGY CO., LTD." }, { 0x1CE1, "Amphenol KAE" }, { 0x1CE2, "Extron Electronics" }, { 0x1CE3, "Australian Simulation Control Systems Pty., Ltd." }, { 0x1CE4, "High Leah Electronics, Inc." }, { 0x1CE5, "SimPhonics, Inc." }, { 0x1CE6, "SOPRO" }, { 0x1CE7, "FASY SPA" }, { 0x1CE8, "Alcorn McBride, Inc." }, { 0x1CE9, "Cadmus Payment Solutions Ltd." }, { 0x1CEA, "MESTEK, INC." }, { 0x1CEB, "SMARTWI" }, { 0x1CEC, "Siemens AG I & S Postal Automation" }, { 0x1CED, "DEWESOFT d.o.o." }, { 0x1CEE, "Production Technology Center Kyushuu" }, { 0x1CEF, "Siemens LD-A" }, { 0x1CF0, "SA VALIDY" }, { 0x1CF1, "dresden elektronik ingenieurtechnik gmbh" }, { 0x1CF2, "TrellisWare Technologies, Inc." }, { 0x1CF3, "Lion Power Co., Ltd." }, { 0x1CF4, "SK INTERFACES LTD." }, { 0x1CF5, "Swirlnet A/S" }, { 0x1CF6, "Atlantic Zeiser GmbH" }, { 0x1CF7, "Electric-Spin" }, { 0x1CF8, "Biometric Associates" }, { 0x1CF9, "Aipermon GmbH & Co. KG" }, { 0x1CFA, "Daco Scientific Limited" }, { 0x1CFB, "Livescribe Inc." }, { 0x1CFC, "ANDES TECHNOLOGY CORPORATION" }, { 0x1CFD, "Flextronics Digital Design Japan, LTD." }, { 0x1CFE, "Cryptsoft Pty. Ltd." }, { 0x1CFF, "Tad Radio of Canada Inc." }, { 0x1D00, "MicroStone Corporation" }, { 0x1D01, "SNIF Labs" }, { 0x1D02, "DevGuru" }, { 0x1D03, "ICON INTERNATIONAL DIGITAL LIMITED" }, { 0x1D04, "Itronics" }, { 0x1D05, "DESTURA S.R.L." }, { 0x1D06, "BBK ELECTRONICS CORPORATION LIMITED" }, { 0x1D07, "Solid-Motion" }, { 0x1D08, "NINGBO HENTEK DRAGON ELECTRONICS CO., LTD." }, { 0x1D09, "TechFaith Wireless Technology Limited" }, { 0x1D0A, "Visteon Corporation" }, { 0x1D0B, "HAN HUA CABLE & WIRE TECHNOLOGY (J.X.) CO., LTD." }, { 0x1D0C, "LAKS GmbH" }, { 0x1D0D, "TDK Marketing Europe GmbH" }, { 0x1D0E, "deister electronic GmbH" }, { 0x1D0F, "NEO ELECTRONICS (HK) CO., LIMITED" }, { 0x1D10, "Jiangsu Shinco Digital Technology Co., Ltd." }, { 0x1D11, "Xtend Technologies Pvt. Ltd." }, { 0x1D12, "UAB TELTONIKA" }, { 0x1D13, "L3 Communications - Telemetry West" }, { 0x1D14, "ALPHA-SAT TECHNOLOGY LIMITED" }, { 0x1D15, "FUJIFILM RECORDING MEDIA GmbH" }, { 0x1D16, "KABA MAS CORPORATION" }, { 0x1D17, "C-THRU MUSIC Ltd." }, { 0x1D18, "APICAL INSTRUMENTS, INC." }, { 0x1D19, "Dexatek Technology Ltd." }, { 0x1D1A, "Boeckeler Instruments, Inc." }, { 0x1D1B, "HumanBeams Inc." }, { 0x1D1C, "Novatron Oy" }, { 0x1D1D, "SYNESTHESIA CORPORATION" }, { 0x1D1E, "OFFCODE" }, { 0x1D1F, "Diostech Co., Ltd." }, { 0x1D20, "SAMTACK INC." }, { 0x1D21, "COMPUSULT LIMITED" }, { 0x1D22, "ELCOM s.r.o." }, { 0x1D23, "Netsushin Co., Ltd." }, { 0x1D24, "PHOTON KINETICS" }, { 0x1D25, "Trinity Security Systems, Inc." }, { 0x1D26, "ADVANCED ELECTRONICS LTD." }, { 0x1D27, "Prime Sense Ltd." }, { 0x1D28, "JORDAN VALLEY SEMICONDUCTORS LTD." }, { 0x1D29, "Horng Tong Enterprise Co., Ltd." }, { 0x1D2A, "LyconSys GmbH & Co. KG" }, { 0x1D2B, "BEN-RI ELECTRONICA S.A." }, { 0x1D2C, "equinux AG" }, { 0x1D2D, "Fraunhofer IBMT" }, { 0x1D2E, "I.S.V. Co., Ltd." }, { 0x1D2F, "JACO, INC." }, { 0x1D30, "Sinosun Technology Ltd." }, { 0x1D31, "XINTRONIX LIMITED" }, { 0x1D32, "ELECTRONICA MECHATRONIC SYSTEMS (I) PVT. LTD." }, { 0x1D33, "Lockheed Martin - Maritime Systems & Sensors" }, { 0x1D34, "DREAM LINK LTD." }, { 0x1D35, "ISS Manufacturing Limited" }, { 0x1D36, "Volucris, Inc." }, { 0x1D37, "Phoenix Microelectronics (China) Co., Ltd." }, { 0x1D38, "Ergowerx Int'l LLC/Smartfish Technologies" }, { 0x1D39, "XECURENEXUS Co., LTD." }, { 0x1D3A, "P. R. Glassel & Associates, Inc." }, { 0x1D3B, "J & C Technology Co., Ltd." }, { 0x1D3C, "Tomei Tsushin Kogyo Co., Ltd." }, { 0x1D3D, "R&D Center of Biometric Technology-BMSTU" }, { 0x1D3E, "EMCON Emanation Control Limited" }, { 0x1D3F, "Photon Control Inc." }, { 0x1D40, "EDANIS Elektronik AG" }, { 0x1D41, "Teletronic Rossendorf GmbH" }, { 0x1D42, "DRAGON JOY LIMITED" }, { 0x1D43, "Montage Technology, Inc." }, { 0x1D44, "Adirondack Digital Imaging Systems, Inc." }, { 0x1D45, "Qisda Corporation" }, { 0x1D46, "nSys Design Systems" }, { 0x1D47, "ATAUCE" }, { 0x1D48, "Shenzhen XinYonghui Precise Technology Co., Ltd." }, { 0x1D49, "SHENZHEN LINKCONN ELECTRONICS CO., LTD." }, { 0x1D4A, "HKS Co., Ltd." }, { 0x1D4B, "DARIM VISION CO." }, { 0x1D4C, "ARK-DESIGN Co., Ltd." }, { 0x1D4D, "Pegatron Corporation" }, { 0x1D4E, "INPHI CORPORATION" }, { 0x1D4F, "ADVANCED CHIP EXPRESS INC." }, { 0x1D50, "OPENMOKO, Inc." }, { 0x1D51, "Sengital Limited" }, { 0x1D52, "ELECTROBYTE di GARAVAGLIA MATTIA" }, { 0x1D53, "Innofidei Inc." }, { 0x1D54, "ZARAM TECHNOLOGY, Inc." }, { 0x1D55, "XRONet Corporation" }, { 0x1D56, "Verico International Co., Ltd." }, { 0x1D57, "Feeling Technology Corp." }, { 0x1D58, "SUZUKI Engineering" }, { 0x1D59, "3DSP" }, { 0x1D5A, "Hillcrest Laboratories, Inc." }, { 0x1D5B, "Smartronix, Inc." }, { 0x1D5C, "Fresco Logic Inc." }, { 0x1D5D, "QIXING INDUSTRIAL (HK) CO." }, { 0x1D5E, "Tonium AB" }, { 0x1D5F, "ViVOtech, Inc." }, { 0x1D60, "ASAP International Co., Ltd." }, { 0x1D61, "ACCEMIC GmbH & CO. KG" }, { 0x1D62, "KYORITSU ELECTRIC CO., LTD." }, { 0x1D63, "Nippon Seiki Co., Ltd." }, { 0x1D64, "MobilMAX Technology Inc." }, { 0x1D65, "Moteurs LEROY SOMER" }, { 0x1D66, "StreamBuster" }, { 0x1D67, "DYNAMIC INNOVATIONS LIMITED" }, { 0x1D68, "SEMA ELECTRONICS (H.K.) CO., Ltd." }, { 0x1D69, "Walta Electronic Co., Ltd." }, { 0x1D6A, "ARICENT TECHNOLOGIES (HOLDINGS) LTD." }, { 0x1D6B, "The Linux Foundation" }, { 0x1D6C, "Man & Machine, Inc." }, { 0x1D6D, "VARISYS LIMITED" }, { 0x1D6E, "EUROTECH" }, { 0x1D6F, "Seluxit" }, { 0x1D70, "MULTIPLE ACCESS COMMUNICATIONS LTD." }, { 0x1D71, "Finisar Corporation" }, { 0x1D72, "Mobiltex Data Ltd." }, { 0x1D73, "Signal Processing Devices Sweden AB" }, { 0x1D74, "LG Innotek Co., Ltd." }, { 0x1D75, "DICOM, spol. s r.o." }, { 0x1D76, "LongCheng Electronic & Communication CO., LTD." }, { 0x1D77, "Yueqing Changling Electronic Instrument Corp., Ltd." }, { 0x1D78, "CAMBRIDGE SEMICONDUCTOR LTD." }, { 0x1D79, "Shenzhen Innosystem Technology Ltd." }, { 0x1D7A, "SHINWA INTERNATIONAL HOLDINGS LTD." }, { 0x1D7B, "Single Strand Co., Ltd." }, { 0x1D7C, "KarmelSonix" }, { 0x1D7D, "Seoul Commtech Co., Ltd." }, { 0x1D7E, "WAVESAT" }, { 0x1D7F, "MoBeam, Inc." }, { 0x1D80, "PLDA" }, { 0x1D81, "YongXin Plastic & Hardware Co., Ltd." }, { 0x1D82, "HERTZ SYSTEMTECHNIK GmbH" }, { 0x1D83, "Mantech International" }, { 0x1D84, "Kechenda Plastic Electronic Factory" }, { 0x1D85, "NINGBO SHUNSHENG COMMUNICATION APPARATUS CO., LTD." }, { 0x1D86, "C.D.N. CORPORATION" }, { 0x1D87, "RHK TECHNOLOGY, INC." }, { 0x1D88, "Mahr GmbH" }, { 0x1D89, "Hunter Associates" }, { 0x1D8A, "OSASI Technos Inc. (Tokyo Headquarters)" }, { 0x1D8B, "MEDTRONIC" }, { 0x1D8C, "Wuxi AlphaScale IC Systems, Inc." }, { 0x1D8D, "EXEO SYSTEMS" }, { 0x1D8E, "Capistrano Labs, Inc." }, { 0x1D8F, "Viprinet GmbH" }, { 0x1D90, "CITIZEN SYSTEMS JAPAN CO., LTD." }, { 0x1D91, "BYD COMPANY LIMITED" }, { 0x1D92, "SPECTRONIC DEVICES LTD." }, { 0x1D93, "Tokyo System Development Co., Ltd." }, { 0x1D94, "ENCIRIS TECHNOLOGIES" }, { 0x1D95, "SYSTRONIK Elektronik und Systemtechnik GmbH" }, { 0x1D96, "CHIRSON LTD." }, { 0x1D97, "Telonics" }, { 0x1D98, "OUTLINE ELECTRONICS LTD." }, { 0x1D99, "Shanghai HSIC Application System Co., Ltd." }, { 0x1D9A, "Vubiq, Inc." }, { 0x1D9B, "Techno Source" }, { 0x1D9C, "SONIM TECHNOLOGIES, INC." }, { 0x1D9D, "Sigma Elektro GmbH" }, { 0x1D9E, "CSR, Inc." }, { 0x1D9F, "KUNMING ELECTRONICS CO., LTD." }, { 0x1DA0, "Parade Technologies, Inc." }, { 0x1DA1, "COVIDENCE A/S" }, { 0x1DA2, "LAMBDA, INC." }, { 0x1DA3, "bebro electronic GmbH" }, { 0x1DA4, "BTICINO" }, { 0x1DA5, "CATHEXIS INNOVATIONS INC." }, { 0x1DA6, "Inepro BV" }, { 0x1DA7, "ENDRA Inc." }, { 0x1DA8, "VIOLET" }, { 0x1DA9, "In-Circuit GmbH" }, { 0x1DAA, "Alcatel-Lucent" }, { 0x1DAB, "MAGELLAN GPS" }, { 0x1DAC, "MOBOTIX AG" }, { 0x1DAD, "DATNET KFT" }, { 0x1DAE, "ellipsis INC." }, { 0x1DAF, "Breas Medical AB" }, { 0x1DB0, "GreenPeak Technologies NV" }, { 0x1DB1, "Reliable Controls Corporation" }, { 0x1DB2, "Duali Inc." }, { 0x1DB3, "Arcelik A.S." }, { 0x1DB4, "Montalvo Systems" }, { 0x1DB5, "BRYSTON LTD." }, { 0x1DB6, "eDimensional, Inc." }, { 0x1DB7, "SMedia Technology Corporation" }, { 0x1DB8, "HD MEDICAL INC." }, { 0x1DB9, "LITEN UP TECHNOLOGIES INC." }, { 0x1DBA, "BancTec, Inc." }, { 0x1DBB, "Condalo GmbH" }, { 0x1DBC, "Shenzhen HOJY Technology Co., Ltd." }, { 0x1DBD, "Terawins" }, { 0x1DBE, "S.R.N. Corporation" }, { 0x1DBF, "Signostics Pty. Ltd." }, { 0x1DC0, "DATAFIELD INDIA PVT.LTD." }, { 0x1DC1, "Laser Drive" }, { 0x1DC2, "Datalogic Mobile Inc." }, { 0x1DC3, "PoLabs" }, { 0x1DC4, "TRANSICS" }, { 0x1DC5, "Pixim Inc." }, { 0x1DC6, "Miyama, Inc." }, { 0x1DC7, "Leroy Automatique Industrielle" }, { 0x1DC8, "GC Corporation" }, { 0x1DC9, "Hitachi Koki Co., Ltd." }, { 0x1DCA, "The IVOXX Corp." }, { 0x1DCB, "IFTEST AG" }, { 0x1DCC, "Document Capture Technologies, Inc." }, { 0x1DCD, "HIN KUI MACHINE & METAL INDUSTRIAL CO., LTD." }, { 0x1DCE, "SIMTEC Elektronik GmbH" }, { 0x1DCF, "INVIX Co., Ltd." }, { 0x1DD0, "ABB AS, Division Automation Products" }, { 0x1DD1, "EFJohnson" }, { 0x1DD2, "LEO BODNAR" }, { 0x1DD3, "Dajac, Inc." }, { 0x1DD4, "ARMELIN WIDGET CORPORATION" }, { 0x1DD5, "MetaGeek, LLC" }, { 0x1DD6, "Solomon Technology Corp." }, { 0x1DD7, "REDMERE TECHNOLOGY" }, { 0x1DD8, "BUFFALO KOKUYO SUPPLY INC." }, { 0x1DD9, "EFFICERE TECHNOLOGIES" }, { 0x1DDA, "TA Instruments" }, { 0x1DDB, "Abon Touchsystems Inc." }, { 0x1DDC, "id Quantique" }, { 0x1DDD, "DOKING ELECTRONIC TECHNOLOGY CO., LTD." }, { 0x1DDE, "TridonicAtco" }, { 0x1DDF, "L&T Technology Services" }, { 0x1DE0, "Shenzhen Excelstor Technology Ltd." }, { 0x1DE1, "Actions Microelectronics Co., Ltd." }, { 0x1DE2, "ENTERY INDUSTRIAL CO., LTD." }, { 0x1DE3, "SHENZHEN REX ELECTRONICS CO., LTD." }, { 0x1DE4, "DAEWOO ELECTRONICS CORPORATION" }, { 0x1DE5, "AMONTEC" }, { 0x1DE6, "MICRORISC S.R.O." }, { 0x1DE7, "MIDAS TECHNOLOGY" }, { 0x1DE8, "Applied Systems Engineering, Inc." }, { 0x1DE9, "Seco Technology Co., Ltd." }, { 0x1DEA, "Yesin Electronics Technology Co., Ltd." }, { 0x1DEB, "SHIUH CHI PRECISION INDUSTRY CO., LTD." }, { 0x1DEC, "HAGER CONTROLS SAS" }, { 0x1DED, "COOLIT SYSTEMS, INC." }, { 0x1DEE, "JCM II, Inc." }, { 0x1DEF, "KYOTO KAGAKU CO., LTD." }, { 0x1DF0, "TRICKLESTAR LIMITED" }, { 0x1DF1, "HUATIANYUAN ELECTRONIC INDUSTRY CO., LTD." }, { 0x1DF2, "China Telecommunication Technology Labs - Terminals" }, { 0x1DF3, "CRESYN CO., LTD." }, { 0x1DF4, "SHEN ZHEN FORMAN PRECISION INDUSTRY CO., LTD." }, { 0x1DF5, "Universal Remote Control, Inc." }, { 0x1DF6, "TakeMS International AG" }, { 0x1DF7, "Mirics Semiconductor Ltd." }, { 0x1DF8, "The Charles Machine Works, Inc." }, { 0x1DF9, "Komax AG" }, { 0x1DFA, "BLOCKMASTER AB" }, { 0x1DFB, "marco Systemanalyse und Entwicklung GmbH" }, { 0x1DFC, "YUNNAN NANTIAN ELECTRONICS INFORMATION CO., LTD." }, { 0x1DFD, "Quality Thermistor, Inc." }, { 0x1DFE, "BEDA Precision" }, { 0x1DFF, "InfraRed Integrated Systems Ltd." }, { 0x1E00, "Jupiter Systems" }, { 0x1E01, "Dynalloy, Inc." }, { 0x1E02, "GLOBEMASTER TECHNOLOGIES CO., LTD." }, { 0x1E03, "OXFORD INSTRUMENTS ANALYTICAL OY" }, { 0x1E04, "Coolsand Technologies (Hong Kong) Ltd." }, { 0x1E05, "Microtronic AG" }, { 0x1E06, "Moore Industries International" }, { 0x1E07, "GETA ELECTRONICS (DONG GUAN) CO., LTD." }, { 0x1E08, "Inventure, Inc." }, { 0x1E09, "Baldwin Boxall Communication Ltd." }, { 0x1E0A, "NOX Medical" }, { 0x1E0B, "TUBITAK UEKAE" }, { 0x1E0C, "NATIONAL HYBRID, INC." }, { 0x1E0D, "NEOWAVE" }, { 0x1E0E, "SHANGHAI BASECOM LTD." }, { 0x1E0F, "mSilica Inc." }, { 0x1E10, "FLIR Integrated Imaging Solutions" }, { 0x1E11, "Hoya Xponent" }, { 0x1E12, "OCTRIAN" }, { 0x1E13, "Burgundy Electric, LLC" }, { 0x1E14, "YANtide Corporation" }, { 0x1E15, "mStation" }, { 0x1E16, "SMARTIO" }, { 0x1E17, "Mirion Technologies Inc." }, { 0x1E18, "MIGHT Co., Ltd." }, { 0x1E19, "Torus Networks Co., Ltd." }, { 0x1E1A, "HITEC RCD KOREA" }, { 0x1E1B, "e-Practical Solutions" }, { 0x1E1C, "CMS PRODUCTS" }, { 0x1E1D, "Kanguru Solutions" }, { 0x1E1E, "Trans New Technology, Inc." }, { 0x1E1F, "INVIA" }, { 0x1E20, "JDSU" }, { 0x1E21, "NEONUMERIC" }, { 0x1E22, "LEDCO" }, { 0x1E23, "Aeronix, Inc." }, { 0x1E24, "Cine-tal Systems, Inc." }, { 0x1E25, "3M Cogent, Inc." }, { 0x1E26, "Multi Channel Systems MCS GmbH" }, { 0x1E27, "NASA / Johnson Space Center / EV2" }, { 0x1E28, "Raptor Innovations International" }, { 0x1E29, "Festo AG & Co. KG" }, { 0x1E2A, "NANOFORTI INC." }, { 0x1E2B, "3M CMD (Communication Markets Division)" }, { 0x1E2C, "KRONIK ELEKTRONIK SANAYI VETICARET LIMITED SIRKETI" }, { 0x1E2D, "Cinterion Wireless Modules GmbH" }, { 0x1E2E, "Syrinx Industrial Electronics b.v." }, { 0x1E2F, "Celrun Co., Ltd." }, { 0x1E30, "Kohler Co." }, { 0x1E31, "Greatbatch" }, { 0x1E32, "Opti-Sciences, Inc." }, { 0x1E33, "KOBIAN CANADA INC." }, { 0x1E34, "Sensory, Inc." }, { 0x1E35, "BELLING Co., Ltd." }, { 0x1E36, "Insulet Corporation" }, { 0x1E37, "Rehoboth Tech. Co., Ltd." }, { 0x1E38, "QRS Music Technologies Inc." }, { 0x1E39, "YIS Corporation" }, { 0x1E3A, "Continental Automotive Systems Inc." }, { 0x1E3B, "MICROBIT 2.0 AB" }, { 0x1E3C, "Vapor Bus Int'l Div of Westinghouse Air Brake Tech Corp" }, { 0x1E3D, "Chipsbrand Technologies (HK) Co., Limited" }, { 0x1E3E, "EMS Aviation" }, { 0x1E3F, "JJ Keller & Associates Inc." }, { 0x1E40, "SciLog, Inc." }, { 0x1E41, "Cleverscope Ltd." }, { 0x1E42, "SSE GmbH" }, { 0x1E43, "Sagem Mobiles" }, { 0x1E44, "SHIMANO INC." }, { 0x1E45, "TADANO LTD." }, { 0x1E46, "Danfoss A/S" }, { 0x1E47, "HUNG TA H.T.ENTERPRISE CO., LTD." }, { 0x1E48, "LABAU Technology" }, { 0x1E49, "FES LLC" }, { 0x1E4A, "CHIRON TECHNOLOGY LTD." }, { 0x1E4B, "exxact GmbH" }, { 0x1E4C, "Stereotaxis, Inc." }, { 0x1E4D, "BST International GmbH" }, { 0x1E4E, "Etron Technology, Inc." }, { 0x1E4F, "SECOM Co., Ltd." }, { 0x1E50, "VILTECHMEDA UAB" }, { 0x1E51, "DiMoto" }, { 0x1E52, "SZ TELSTAR CO., LTD." }, { 0x1E53, "WYPLAY" }, { 0x1E54, "TypeMatrix Inc." }, { 0x1E55, "Memorysolution GmbH" }, { 0x1E56, "EURINTEL" }, { 0x1E57, "Bundesdruckerei GmbH" }, { 0x1E58, "Horner APG" }, { 0x1E59, "inTera Tecnologia" }, { 0x1E5A, "VOXTRONIC TECHNOLOGY" }, { 0x1E5B, "APRICO A/S" }, { 0x1E5C, "Enova Technology Corp." }, { 0x1E5D, "SAT Corporation" }, { 0x1E5E, "Touch International" }, { 0x1E5F, "Relpol SA" }, { 0x1E60, "SEA Signalisation" }, { 0x1E61, "Anoto AB" }, { 0x1E62, "Uriver Inc." }, { 0x1E63, "DRAEGER MEDICAL" }, { 0x1E64, "IMSTORAGE CO., LTD." }, { 0x1E65, "THE BOEING CO." }, { 0x1E66, "KAPSYS" }, { 0x1E67, "Orban/CRL Systems, Inc." }, { 0x1E68, "TrekStor GmbH & Co. KG" }, { 0x1E69, "Hormann Funkwerk Kolleda GmbH" }, { 0x1E6A, "RGB Spectrum" }, { 0x1E6B, "iRex Technologies B.V." }, { 0x1E6C, "Sureshotgps Pty. Ltd." }, { 0x1E6D, "WAN SHIH ELECTRONIC (H.K.) CO., LTD." }, { 0x1E6E, "F&D Feinwerk-Und Drucktechnik GmbH" }, { 0x1E6F, "Images Scientific Instruments Inc." }, { 0x1E70, "POSBRO Inc." }, { 0x1E71, "NZXT Corporation" }, { 0x1E72, "Federal Signal Corporation" }, { 0x1E73, "COMLINK ELECTRONICS CO., LTD." }, { 0x1E74, "COBY COMMUNICATIONS, LIMITED" }, { 0x1E75, "TLS Communication GmbH" }, { 0x1E76, "Proview Technology (Shenzhen) Co., Ltd." }, { 0x1E77, "Core Micro Technology Inc." }, { 0x1E78, "Flextronics R & D (Shenzhen) Co., Ltd." }, { 0x1E79, "ISA Co., Ltd." }, { 0x1E7A, "The Tsurumi-Seiki Company, Limited" }, { 0x1E7B, "Zurich Instruments AG" }, { 0x1E7C, "biostep GmbH" }, { 0x1E7D, "ROCCAT GmbH" }, { 0x1E7E, "Bright Star Engineering Inc." }, { 0x1E7F, "NEXS ELECTRONIC CORP." }, { 0x1E80, "InterDigital Communications LLC" }, { 0x1E81, "KIDS PREFERRED, LLC." }, { 0x1E82, "Nortech Systems" }, { 0x1E83, "AMICUS WIRELESS" }, { 0x1E84, "VIVAX CORPORATION" }, { 0x1E85, "Gigaset Communications GmbH" }, { 0x1E86, "Japan Meditech Co., Ltd." }, { 0x1E87, "W&W Communications Inc." }, { 0x1E88, "GBS Laboratories, LLC" }, { 0x1E89, "Vtion Information Technology (Fujian) Co., Ltd." }, { 0x1E8A, "HIBEST Electronic (DongGuan) Co., Ltd." }, { 0x1E8B, "ImTech, Inc." }, { 0x1E8C, "Data Conversion Systems Ltd." }, { 0x1E8D, "HIGHVOLT Prueftechnik Dresden GmbH" }, { 0x1E8E, "EADS Secure Networks" }, { 0x1E8F, "PublicSolution GmbH" }, { 0x1E90, "Mego Afek" }, { 0x1E91, "Other World Computing" }, { 0x1E92, "Beyond Question Learning Technologies, Inc." }, { 0x1E93, "GSI Group" }, { 0x1E94, "RealD" }, { 0x1E95, "DIRECTV, Inc." }, { 0x1E96, "BlueAnt Wireless" }, { 0x1E97, "TOMMYCA HONG KONG LIMITED" }, { 0x1E98, "COMPASS SYSTEMS CORP." }, { 0x1E99, "General Dynamics C4 Systems" }, { 0x1E9A, "MANTHAN SEMICONDUCTOR PVT. LTD." }, { 0x1E9B, "Netcom Sicherheitstechnik GmbH" }, { 0x1E9C, "FirstPaper, LLC" }, { 0x1E9D, "GEOTEST AG" }, { 0x1E9E, "InnoSys Inc." }, { 0x1E9F, "Chase Peabody and Associates, Inc." }, { 0x1EA0, "DiabloSport, Inc." }, { 0x1EA1, "NANOBASE" }, { 0x1EA2, "N.V. Nederlandsche Apparatenfabriek Nedap" }, { 0x1EA3, "Concraft Holding Co., Ltd." }, { 0x1EA4, "MOBILE SYSTEM TECHNOLOGIES INC." }, { 0x1EA5, "CEN LINK CO., LTD." }, { 0x1EA6, "novero GmbH" }, { 0x1EA7, "SEMITEK INTERNATIONAL (HK) HOLDING LTD." }, { 0x1EA8, "Shenzhen Excelsecu Data Technology Co., Ltd." }, { 0x1EA9, "ANDERS ELECTRONICS PLC" }, { 0x1EAA, "Zeebo, Inc." }, { 0x1EAB, "Fujian Newland Auto-ID Tech. Co., Ltd." }, { 0x1EAC, "Thinkware Systems" }, { 0x1EAD, "Industrial Control Communications, Inc." }, { 0x1EAE, "YESCNC CO., LTD." }, { 0x1EAF, "Continental Trading GmbH" }, { 0x1EB0, "Centers for Disease Control & Prevention (CDC)" }, { 0x1EB1, "Kramer Electronics Ltd." }, { 0x1EB2, "IWAKI CO., LTD." }, { 0x1EB3, "SAE MAGNETICS (HK) LTD." }, { 0x1EB4, "YuhDing Precision Industry (KunShan) Co., Ltd." }, { 0x1EB5, "Diablo Technologies Inc." }, { 0x1EB6, "PHYLINKS LIMITED" }, { 0x1EB7, "WIN WIN PRECISION INDUSTRIAL CO., LTD." }, { 0x1EB8, "MODACOM CO., LTD." }, { 0x1EB9, "Campbell Scientific Inc." }, { 0x1EBA, "HITTITE MICROWAVE CORP." }, { 0x1EBB, "NuCORE Technology, Inc." }, { 0x1EBC, "Beijing Novel-Super Media Investment Co., Ltd." }, { 0x1EBD, "Wireless Matrix Corp." }, { 0x1EBE, "Qwizdom, Inc." }, { 0x1EBF, "Yulong Computer Telecommunication Scientific" }, { 0x1EC0, "VIGORHOOD PHOTOELECTRIC SHENZHEN CO., LTD." }, { 0x1EC1, "PROTEK DEVICES" }, { 0x1EC2, "CHUO ELECTRONICS CO., LTD." }, { 0x1EC3, "ANDREAS STIHL AG & Co. KG" }, { 0x1EC4, "ELTRONIC SOLUTION A/S" }, { 0x1EC5, "SIDSA" }, { 0x1EC6, "PHYWORKS LTD." }, { 0x1EC7, "Gefen Inc." }, { 0x1EC8, "TelePath Technologies Co., Ltd." }, { 0x1EC9, "MOSER BAER INDIA LIMITED" }, { 0x1ECA, "Mintpass Co., Ltd." }, { 0x1ECB, "Advanced Mobile Telecom Co., Ltd." }, { 0x1ECC, "Enfora, Inc." }, { 0x1ECD, "Alverix Inc." }, { 0x1ECE, "MyungMin Systems, Inc." }, { 0x1ECF, "MDR Grup S.R.L." }, { 0x1ED0, "Hirschmann Car Communication GmbH" }, { 0x1ED1, "DIGITAL CHINA NETWORKS (BEIJING) LIMITED" }, { 0x1ED2, "Crevis Co., Ltd." }, { 0x1ED3, "Forsis GmbH" }, { 0x1ED4, "Transwitch (Israel) Ltd." }, { 0x1ED5, "LLC GlobalTest" }, { 0x1ED6, "adidas International" }, { 0x1ED7, "Headplay, Inc." }, { 0x1ED8, "Fender Musical Instruments Corp." }, { 0x1ED9, "ALBUMteam, Ltd." }, { 0x1EDA, "AIRTIES WIRELESS NETWORKS" }, { 0x1EDB, "BLACKMAGIC DESIGN PTY." }, { 0x1EDC, "B-DeltaCom" }, { 0x1EDD, "IRIDIUM SATELLITE LLC" }, { 0x1EDE, "steute Schaltgerate GmbH & Co. KG" }, { 0x1EDF, "Selectwireless Co., Ltd." }, { 0x1EE0, "KYUDEN TECHNOSYSTEMS CORPORATION" }, { 0x1EE1, "Matrix Key Inc." }, { 0x1EE2, "NOVA GAMING" }, { 0x1EE3, "3D INNOVATIONS, LLC" }, { 0x1EE4, "Luff Technology Co., Ltd." }, { 0x1EE5, "Spring Soft K.K." }, { 0x1EE6, "SHENZHEN EVERWIN PRECISION TECHNOLOGY CO., LTD." }, { 0x1EE7, "EPCOS" }, { 0x1EE8, "ONDA COMMUNICATION S.p.a." }, { 0x1EE9, "PC PARTNER LIMITED" }, { 0x1EEA, "Yullin Technologies Co., Ltd." }, { 0x1EEB, "GEOTATE" }, { 0x1EEC, "CTC Analytics AG" }, { 0x1EED, "Helo Oy / Helo Ltd." }, { 0x1EEE, "RigiSystems AG" }, { 0x1EEF, "I.C.Y. B.V." }, { 0x1EF0, "Thunder Tiger Corp." }, { 0x1EF1, "PQ Computing Ltd." }, { 0x1EF2, "Vircion Inc." }, { 0x1EF3, "JIANGXI SHIP ELECTRONICS CO., LTD." }, { 0x1EF4, "TATA ELXSI LTD." }, { 0x1EF5, "Impinj, Inc." }, { 0x1EF6, "EADS Deutschland GmbH" }, { 0x1EF7, "ZiiLABS Ltd." }, { 0x1EF8, "CRITICAL LINK, LLC" }, { 0x1EF9, "US Army Electronic Proving Ground" }, { 0x1EFA, "SEIKO Precision Inc." }, { 0x1EFB, "IMI Hydronic Engineering International SA" }, { 0x1EFC, "IMOGEN STUDIO" }, { 0x1EFD, "ROFIN-SINAR LASER GMBH" }, { 0x1EFE, "Sound Design Technologies" }, { 0x1EFF, "Kinemetrics, Inc." }, { 0x1F00, "YUEQING ZHONGLI COMPUTER ELECTRONICS CO., LTD." }, { 0x1F01, "Geo Studio Technology" }, { 0x1F02, "Australian National University" }, { 0x1F03, "PTW Freiburg GmbH" }, { 0x1F04, "Watlow" }, { 0x1F05, "Kyosai Technos Co., Ltd." }, { 0x1F06, "K.T.E.-Keter Technologies Europe" }, { 0x1F07, "OPTOQUEST Co., Ltd." }, { 0x1F08, "Digital Ally Inc." }, { 0x1F09, "DURAG GmbH" }, { 0x1F0A, "AUROX Ltd." }, { 0x1F0B, "INTRONIX TEST INSTURMENTS, INC." }, { 0x1F0C, "Fourier Systems Ltd." }, { 0x1F0D, "NAMOS" }, { 0x1F0E, "Inflexis Corporation" }, { 0x1F0F, "Action Technology (SZ) Co., Ltd." }, { 0x1F10, "LTW TECHNOLOGY CO., LTD." }, { 0x1F11, "VIRAGE LOGIC" }, { 0x1F12, "Photometrics" }, { 0x1F13, "CENTURY SYSTEMS Co., Ltd." }, { 0x1F14, "Astoria Networks GmbH" }, { 0x1F15, "Schmitt Industries Inc." }, { 0x1F16, "Olidata SpA" }, { 0x1F17, "APIS Device, Inc." }, { 0x1F18, "Teseq GmbH" }, { 0x1F19, "POLATIS INC." }, { 0x1F1A, "Sanden Retail Systems Corporation" }, { 0x1F1B, "NORTHROP GRUMMAN SPERRY MARINE" }, { 0x1F1C, "LXE, INC." }, { 0x1F1D, "How Weih Precision Technology (Shenzhen) Co., Ltd." }, { 0x1F1E, "TSIEN (UK) LTD." }, { 0x1F1F, "RaaX Co., Ltd." }, { 0x1F20, "Shenzhen Tenwei Electronics Co., Ltd." }, { 0x1F21, "Scosche Industries" }, { 0x1F22, "STAr Technologies, Inc." }, { 0x1F23, "KOUEI SYSTEM, LTD." }, { 0x1F24, "EBTRON INC." }, { 0x1F25, "Victron Energy B.V." }, { 0x1F26, "INCAP GmbH" }, { 0x1F27, "KEE Action Sports (Hater Paintball)" }, { 0x1F28, "Cal-Comp Electronics & Communications" }, { 0x1F29, "Analogix Semiconductor, Inc." }, { 0x1F2A, "Scene Double Ltd." }, { 0x1F2B, "JUKI CORPORATION" }, { 0x1F2C, "SELESTA INGEGNERIA SPA" }, { 0x1F2D, "Liteye Systems, Inc." }, { 0x1F2E, "ARMOUR GROUP PLC." }, { 0x1F2F, "UPOS SYSTEM SP. Z O.O." }, { 0x1F30, "RENA GmbH" }, { 0x1F31, "SASKEN COMMUNICATION TECH LTD." }, { 0x1F32, "COCHLEAR TECHNOLOGY CENTRE BELGIUM" }, { 0x1F33, "GrupoPIE Portugal, S.A." }, { 0x1F34, "Dutronics" }, { 0x1F35, "Amphenol ShouhMin Industry (ShenZhen) Co., Ltd" }, { 0x1F36, "ddm hopt + schuler GmbH & Co. KG" }, { 0x1F37, "Next Step Solutions Limited" }, { 0x1F38, "Kesumo, LLC" }, { 0x1F39, "Sumitomo Electric Networks, Inc." }, { 0x1F3A, "Allwinner Technology Co., Ltd." }, { 0x1F3B, "Biocryptodisk Sdn Bhd" }, { 0x1F3C, "Chang Yang Electronics Company Ltd." }, { 0x1F3D, "Advanced Engineering Services Co., Ltd." }, { 0x1F3E, "Telenot Electronic GmbH" }, { 0x1F3F, "SECA GmbH & Co. KG" }, { 0x1F40, "JiangSu Dongda Integrated Circuits Sys. Eng. Tech. Co." }, { 0x1F41, "Nipro Diagnostics, Inc" }, { 0x1F42, "ID2P TECHNOLOGIES, INC." }, { 0x1F43, "RAPID BRIDGE LLC" }, { 0x1F44, "Digital Business Process (dba: The Neat Company)" }, { 0x1F45, "QUALCOMM ENTERPRISE SERVICES" }, { 0x1F46, "Gener8, Inc." }, { 0x1F47, "Orb Networks, Inc." }, { 0x1F48, "H-TRONIC GmbH" }, { 0x1F49, "Exelis, Inc." }, { 0x1F4A, "Key Ingredient Corporation" }, { 0x1F4B, "Precision System Science Co., Ltd." }, { 0x1F4C, "Cyber Sport Pty., Ltd." }, { 0x1F4D, "SHENZHEN GENIATECH INC., LTD." }, { 0x1F4E, "OFF-NET SERVICE LIMITED" }, { 0x1F4F, "EXAR CORPORATION - JAPAN" }, { 0x1F50, "KEMPPI OY" }, { 0x1F51, "Helmut Hund GmbH" }, { 0x1F52, "Systems & Electronic Development FZCO (SEDCO)" }, { 0x1F53, "SK telesys" }, { 0x1F54, "LOEC, INC." }, { 0x1F55, "Fujitsu Electronics Europe GmbH" }, { 0x1F56, "MUT" }, { 0x1F57, "PIGNOLO S.P.A." }, { 0x1F58, "Inmarsat" }, { 0x1F59, "EL.MO. S.P.A." }, { 0x1F5A, "Micronova srl." }, { 0x1F5B, "KYODO COMMUNICATIONS & ELECTRONICS INC." }, { 0x1F5C, "MIDORI ANZEN CO., LTD." }, { 0x1F5D, "Mobii Systems (Pty) Ltd." }, { 0x1F5E, "Johnson Outdoors Marine Electronics, Inc." }, { 0x1F5F, "NETCLEUS SYSTEMS Corporation" }, { 0x1F60, "Young at Heart International Ltd." }, { 0x1F61, "Flexocard GmbH" }, { 0x1F62, "Elquest Corporation" }, { 0x1F63, "IriTech, Inc." }, { 0x1F64, "actionXL, Inc." }, { 0x1F65, "Taylor Technologies, Co., Ltd." }, { 0x1F66, "Hokkaido Electronics Corporation" }, { 0x1F67, "MICRO INNOVATIONS CORP." }, { 0x1F68, "General Dynamics UK Limited" }, { 0x1F69, "NVIS, Inc." }, { 0x1F6A, "AJA VIDEO SYSTEMS INC." }, { 0x1F6B, "Muve, Inc." }, { 0x1F6C, "Cadex Electronics Inc." }, { 0x1F6D, "AMTI" }, { 0x1F6E, "AccuVein LLC" }, { 0x1F6F, "ALIPHCOM, INC." }, { 0x1F70, "MKD Technology Inc." }, { 0x1F71, "Huaya Microelectronics (HK) Ltd." }, { 0x1F72, "GM INSTRUMENTS LTD." }, { 0x1F73, "Record4Free.TV AG" }, { 0x1F74, "UNISTO Ltd." }, { 0x1F75, "Innostor Co., Ltd." }, { 0x1F76, "CYBER-RAIN, INC." }, { 0x1F77, "POSITRON PUBLIC SAFETY SYSTEMS" }, { 0x1F78, "UNION TOOL CO." }, { 0x1F79, "Rosen Technology and Research Center GmbH" }, { 0x1F7A, "WhiteOak Controls Inc." }, { 0x1F7B, "AVMAP SRL" }, { 0x1F7C, "Voltopia e.U." }, { 0x1F7D, "UNICARD S.A." }, { 0x1F7E, "Canon India Private Limited" }, { 0x1F7F, "NOVA Sensors" }, { 0x1F80, "MagicPixel Inc." }, { 0x1F81, "HYB D.O.O." }, { 0x1F82, "TANDBERG TELECOM AS" }, { 0x1F83, "Beauty Up Co., Ltd." }, { 0x1F84, "Inverness Medical Innovations, Inc." }, { 0x1F85, "Netronix Inc." }, { 0x1F86, "Skyworth Overseas Development Limited" }, { 0x1F87, "STANTUM" }, { 0x1F88, "Modu Ltd." }, { 0x1F89, "Dongguan Goldconn Electronics Co., Ltd." }, { 0x1F8A, "Morning Star Industrial Co., Ltd." }, { 0x1F8B, "Rittal GmbH & Co. KG" }, { 0x1F8C, "Reference, LLC." }, { 0x1F8D, "DEVICE FUNCTIONS" }, { 0x1F8E, "SENSE INSIDE GmbH" }, { 0x1F8F, "Narda Safety Test Solutions GmbH" }, { 0x1F90, "PURE TECHNOLOGIES" }, { 0x1F91, "Wilhelm Mikroelektronik GmbH" }, { 0x1F92, "INTERNATIONAL TECHNIDYNE CORP." }, { 0x1F93, "Alcohol Monitoring Systems, Inc." }, { 0x1F94, "Microhard Systems Inc." }, { 0x1F95, "Art of Technology AG" }, { 0x1F96, "Ascend Geo, LLC" }, { 0x1F97, "OZMO, INC. DBA OZMO DEVICES" }, { 0x1F98, "DSP Design Limited" }, { 0x1F99, "TOKAI RIKEN CO., LTD." }, { 0x1F9A, "Barron Associates, Inc." }, { 0x1F9B, "UBIQUITI Networks, Inc." }, { 0x1F9C, "ARVOO Engineering BV" }, { 0x1F9D, "Tri Works" }, { 0x1F9E, "MUTECH LIMITED" }, { 0x1F9F, "CasaTools, LLC" }, { 0x1FA0, "XLNT IDEA, INC." }, { 0x1FA1, "Curtis Instruments, Inc." }, { 0x1FA2, "AMETEK DENMARK A/S" }, { 0x1FA3, "LAIRD TECHNOLOGIES" }, { 0x1FA4, "BRIDGEPORT INSTRUMENTS, LLC" }, { 0x1FA5, "DELTA DORE" }, { 0x1FA6, "Daylight Solutions, Inc." }, { 0x1FA7, "COSMOS WEB CO., LTD." }, { 0x1FA8, "TCL Technoly Electronics (Hui Zhou) Co., Ltd." }, { 0x1FA9, "Digital Information Technologies Corporation" }, { 0x1FAA, "Zhong Shan City Li Tai Electronic Industrial Co., Ltd." }, { 0x1FAB, "SAMSUNG DIGITAL IMAGING CO., LTD." }, { 0x1FAC, "Franklin Technology Inc." }, { 0x1FAD, "Cresta Technology Inc." }, { 0x1FAE, "Lumidigm, Inc." }, { 0x1FAF, "Weintek Labs, Inc." }, { 0x1FB0, "Discera, Inc." }, { 0x1FB1, "Weatronic GmbH" }, { 0x1FB2, "WITHINGS" }, { 0x1FB3, "Matchbeeper AB" }, { 0x1FB4, "Owl Computing Technologies, Inc." }, { 0x1FB5, "Unify Software and Solutions GmbH & Co. KG" }, { 0x1FB6, "SheKel" }, { 0x1FB7, "J & D Tech Co., Ltd." }, { 0x1FB8, "DORMA TIME + ACCESS GmbH" }, { 0x1FB9, "Lake Shore Cryotronics, Inc." }, { 0x1FBA, "DERMALOG Identification Systems GmbH" }, { 0x1FBB, "PC Worth Int'l Co., Ltd." }, { 0x1FBC, "Kurzweil Education Systems, Inc." }, { 0x1FBD, "STACK LTD." }, { 0x1FBE, "CGS" }, { 0x1FBF, "OVAL Corporation" }, { 0x1FC0, "JUNE-ON Co., Ltd." }, { 0x1FC1, "Blue Chip Technology Limited" }, { 0x1FC2, "Poken SA" }, { 0x1FC3, "ICOP Digital, Inc." }, { 0x1FC4, "Alfons Haar Maschinenbau GmbH & Co. KG" }, { 0x1FC5, "Adaxys Solutions AG" }, { 0x1FC6, "LAUREL BANK MACHINES CO., LTD." }, { 0x1FC7, "mrs GmbH" }, { 0x1FC8, "Medis Technologies Ltd." }, { 0x1FC9, "NXP Semiconductors" }, { 0x1FCA, "ON TIM Technologies Ltd." }, { 0x1FCB, "Thermo Process Instruments" }, { 0x1FCC, "Hiro" }, { 0x1FCD, "Aurora Scientific Inc." }, { 0x1FCE, "WEBSCAN Inc." }, { 0x1FCF, "ACK Co., Ltd." }, { 0x1FD0, "GILSON S.A.S." }, { 0x1FD1, "TEKWorx Limited" }, { 0x1FD2, "LG Display Co., Ltd." }, { 0x1FD3, "ASK SA" }, { 0x1FD4, "FINSECUR" }, { 0x1FD5, "Dream Multimedia GmbH" }, { 0x1FD6, "Logitek Electronic Systems, Inc." }, { 0x1FD7, "ASELSAN Elektronik Sanayi ve Ticaret. A.S." }, { 0x1FD8, "Guangzhou Tianhe Changjiang Communication Industrial Co" }, { 0x1FD9, "Knox Company" }, { 0x1FDA, "Beckwith Electric Co., Inc." }, { 0x1FDB, "Delphin Technology AG" }, { 0x1FDC, "HOSA TECHNOLOGY, INC." }, { 0x1FDD, "CHASE GLORY INDUSTRIAL LTD." }, { 0x1FDE, "ILX Lightwave" }, { 0x1FDF, "SEPURA PLC" }, { 0x1FE0, "REALFLEET Co., Ltd." }, { 0x1FE1, "Ubixum, Inc." }, { 0x1FE2, "Aetas Systems Inc." }, { 0x1FE3, "Amaranthine, LLC" }, { 0x1FE4, "HANDY TECH ELEKTRONIK GmbH" }, { 0x1FE5, "KUKA Roboter GmbH" }, { 0x1FE6, "BOOKHAM INC." }, { 0x1FE7, "VERTEX WIRELESS CO., LTD." }, { 0x1FE8, "103mm Tech" }, { 0x1FE9, "Harvard Bioscience" }, { 0x1FEA, "SIMPLO TECHNOLOGY CO., LTD." }, { 0x1FEB, "Tecella" }, { 0x1FEC, "NIAN YEONG ENTERPRISE CO., LTD." }, { 0x1FED, "SYSACOM R&D Plus Inc." }, { 0x1FEE, "GALILEO ENGINEERING SRL" }, { 0x1FEF, "RESOL - Elektronische Regelungen GmbH" }, { 0x1FF0, "Kyoto Electronics Manufacturing Co., Ltd." }, { 0x1FF1, "Remote Operations Solutions" }, { 0x1FF2, "Carl Valentin GmbH" }, { 0x1FF3, "SINTEF Energy Research" }, { 0x1FF4, "HYUNDAI PETATEL INC." }, { 0x1FF5, "Changzhou Wujin BEST Electronic Cables Co., Ltd." }, { 0x1FF6, "ClickTech LLC" }, { 0x1FF7, "Guangzhou Shi Rui Electronics Co., Ltd." }, { 0x1FF8, "Infinite Memories" }, { 0x1FF9, "Schulze Elektronik GmbH" }, { 0x1FFA, "ARYGON Technologies AG" }, { 0x1FFB, "Pololu Corporation" }, { 0x1FFC, "Azimut Production Association JSC" }, { 0x1FFD, "TESSERA, INC." }, { 0x1FFE, "HOST ENGINEERING, INC." }, { 0x1FFF, "Ideofy Inc." }, { 0x2000, "RongTong Info & Tech Co., Ltd." }, { 0x2001, "D-Link Corporation" }, { 0x2002, "DAP Technologies Ltd." }, { 0x2003, "detectomat GmbH" }, { 0x2004, "Shanghai Bellmann Digital Source Co., Ltd." }, { 0x2005, "Balluff GmbH" }, { 0x2006, "Lenovo Mobile Communication Technology Ltd." }, { 0x2007, "LEYIO" }, { 0x2008, "ThingMagic, Inc." }, { 0x2009, "MPEDIA" }, { 0x200A, "ADVANCED RELAY CORP." }, { 0x200B, "TRANSISTOR DEVICES INC." }, { 0x200C, "HANPIN ELECTRON CO., LTD." }, { 0x200D, "Belkin Electronic (Changzhou) Co., Ltd." }, { 0x200E, "DAIICHI PARTS (HK) CO., LTD." }, { 0x200F, "Progind Srl" }, { 0x2010, "Tectonica Australia Pty. Ltd." }, { 0x2011, "SHENZHEN HEXIN COM. TECH. CO., LTD." }, { 0x2012, "Applied Radar, Inc." }, { 0x2013, "PCTV Systems" }, { 0x2014, "ONKEN CORPORATION" }, { 0x2015, "Shenzhen Ephone Communication Technology Co., Ltd." }, { 0x2016, "Norbit AS" }, { 0x2017, "NAL Research Corporation" }, { 0x2018, "SilverPAC, Inc." }, { 0x2019, "Electronics Development Corp." }, { 0x201A, "Vortran Laser Technology, Inc." }, { 0x201B, "1064138 Ontario Ltd. O/A UNI-TEC ELECTRONICS" }, { 0x201C, "Freeport Resources Enterprises Corp." }, { 0x201D, "Dongguan Shunhui Electronic Co., Ltd." }, { 0x201E, "Qingdao Haier Telecom Co., Ltd." }, { 0x201F, "W.E.M. INC." }, { 0x2020, "Shanghai BroadMobi Communication Technology Co., Ltd." }, { 0x2021, "Smartd ltd" }, { 0x2022, "AMICON Ltd." }, { 0x2023, "Berthold Technologies GmbH & Co. KG" }, { 0x2024, "Shoto Technologies LLC" }, { 0x2025, "NANOSENSE" }, { 0x2026, "EASUN REYROLLE LIMITED" }, { 0x2027, "LOAD SYSTEMS INTERNATIONAL, INC." }, { 0x2028, "DETAS TECHNOLOGY LTD." }, { 0x2029, "MYTRAK HEALTH SYSTEM INC." }, { 0x202A, "Fast Forward Video, Inc." }, { 0x202B, "Damalini AB" }, { 0x202C, "Enhanced Vision" }, { 0x202D, "Snowbush IP (a division of Gennum)" }, { 0x202E, "Lumio Inc." }, { 0x202F, "US ARMY RDECOM-ARDEC" }, { 0x2030, "VITEC Multimedia" }, { 0x2031, "Vistec AG" }, { 0x2032, "GFMesstechnik GmbH" }, { 0x2033, "WYMA Tecnologia Ltda." }, { 0x2034, "iSoft Silicon, Inc." }, { 0x2035, "seowonintech" }, { 0x2036, "Eitech Co., Ltd." }, { 0x2037, "Control Devices Australia Pty., Ltd." }, { 0x2038, "Wescor Inc." }, { 0x2039, "SE-Elektronic GmbH" }, { 0x203A, "Parallels, Inc." }, { 0x203B, "EIT, Inc." }, { 0x203C, "Steptechnica Co., Ltd." }, { 0x203D, "Encore Electronics" }, { 0x203E, "Pascher Instruments AB" }, { 0x203F, "WPG System Pte. Ltd." }, { 0x2040, "Hauppauge Computer Works, Inc." }, { 0x2041, "WILL BEST (ELECTRONICS) LTD." }, { 0x2042, "Eberspaecher Electronics GmbH & Co. KG" }, { 0x2043, "Mobius Microsystems" }, { 0x2044, "NOVUS PRODUTOS ELETRONICOS LTDA." }, { 0x2045, "EMH - Energie-Messtechnik GmbH" }, { 0x2046, "AbleNet Inc." }, { 0x2047, "Texas Instruments Incorporated (MSP430 Group)" }, { 0x2048, "Hongtech Electronics Co., Ltd." }, { 0x2049, "APACEWAVE TECHNOLOGIES" }, { 0x204A, "Enclustra GmbH" }, { 0x204B, "HANSHIN INFORMATION TECHNOLOGY INC." }, { 0x204C, "M7Lab., Co., Ltd." }, { 0x204D, "Orthodyne Electronics" }, { 0x204E, "LINO MANFROTTO + CO. S.P.A." }, { 0x204F, "VIDEOTEC SpA" }, { 0x2050, "CBF Systems, Inc." }, { 0x2051, "N.A.T. GmbH" }, { 0x2052, "Movidius Ltd." }, { 0x2053, "HANSHIN TERMINAL CO., LTD." }, { 0x2054, "Source R & D Inc. (DBA WARPIA)" }, { 0x2055, "Opti B. I. Communications, Ltd." }, { 0x2056, "CliniComp International Inc." }, { 0x2057, "DICE ELECTRONICS, LLC" }, { 0x2058, "NANO RIVER TECHNOLOGIES" }, { 0x2059, "SMART Temps LLC" }, { 0x205A, "Hankook Tire" }, { 0x205B, "TRUMPF Medizin Systeme GmbH" }, { 0x205C, "Shenzhen Tronixin Electronics Co., Ltd." }, { 0x205D, "RESMED LTD." }, { 0x205E, "CTI PRODUCTS, Inc." }, { 0x205F, "Capella Microsystems Inc." }, { 0x2060, "U.S. Army Aviation & Missile R & D & Engineering Center" }, { 0x2061, "FIGMENT DESIGN LABORATORIES" }, { 0x2062, "Trulife" }, { 0x2063, "AirMagnet Inc." }, { 0x2064, "Shenzhen AnNet Technology Co., Ltd." }, { 0x2065, "MEASUREMENT SPECIALTIES INC." }, { 0x2066, "Unicorn Electronics Components Co., Ltd." }, { 0x2067, "TSB LAO COMPANY LIMITED" }, { 0x2068, "Seven 45 Studios" }, { 0x2069, "Vanguard Rugged Storage, LLC" }, { 0x206A, "Fujian Star-net Communication Co., Ltd." }, { 0x206B, "CETIM" }, { 0x206C, "Seeker Technology Corp." }, { 0x206D, "Hunan GreatWall Information Financial Equipment Co.Ltd." }, { 0x206E, "ZAO MIRCOM" }, { 0x206F, "JTOUCH Corporation" }, { 0x2070, "Infinite Response, Inc." }, { 0x2071, "SYSTEM S.P.A." }, { 0x2072, "GOOD YEAR ELECTRONIC MFG. CO., LTD." }, { 0x2073, "Shenzhen R-Way Technology Co., Ltd." }, { 0x2074, "UNIVERSAL CHAMPION ELECTROACOUSTIC TECHNOLOGY COMPANY" }, { 0x2075, "SecureKey Technologies Inc." }, { 0x2076, "SHINKAWA Sensor Technology, Inc." }, { 0x2077, "Shenzhen Gongjin Electronics Co., Ltd." }, { 0x2078, "Epsilon Electronics, Inc dba Power Acoustik Electronics" }, { 0x2079, "New Concept Gaming Ltd." }, { 0x207A, "C.E.T.W.I.N System Solutions Sweden AB" }, { 0x207B, "Technetix Group Ltd." }, { 0x207C, "NESA International, Inc." }, { 0x207D, "CESI Technology Co., Ltd." }, { 0x207E, "ENHANCED VIDEO DEVICES, INC." }, { 0x207F, "Profound BV" }, { 0x2080, "Barnes and Noble" }, { 0x2081, "UTRONIX Elektronikutreckling AB" }, { 0x2082, "EKOMINI INC." }, { 0x2083, "XEL SOLUTIONS LTD." }, { 0x2084, "I Zone Technologies Co., Ltd." }, { 0x2085, "SIXENSE ENTERTAINMENT INC." }, { 0x2086, "SHENZHEN CATIC INFORMATION TECHNOLOGY INDUSTRY CO., LTD" }, { 0x2087, "Cando Corporation" }, { 0x2088, "WALTON CHAINTECH CORPORATION" }, { 0x2089, "microdrones GmbH" }, { 0x208A, "TECHNO ROAD Inc." }, { 0x208B, "KONTRON EMBEDDED COMPUTERS GmbH" }, { 0x208C, "Linkbit, Inc." }, { 0x208D, "Attero Tech, LLC" }, { 0x208E, "Luxshare-ICT" }, { 0x208F, "Chi Mei Optoelectronics Corporation" }, { 0x2090, "Transition Networks" }, { 0x2091, "Callpod, Inc." }, { 0x2092, "Logina" }, { 0x2093, "Ambu A/S" }, { 0x2094, "Yoostar Entertainment Group, Inc." }, { 0x2095, "CE LINK LIMITED" }, { 0x2096, "Shenzhen Microconn Investment and Development Co., Ltd." }, { 0x2097, "USBPARTNER" }, { 0x2098, "TouchTable, Inc." }, { 0x2099, "Systematic Development Group, LLC" }, { 0x209A, "Avedis Zildjian Company" }, { 0x209B, "SATEL OY" }, { 0x209C, "iPulse Systems" }, { 0x209D, "Vector Co., Ltd." }, { 0x209E, "GlideTV Inc." }, { 0x209F, "Alcolizer Technology" }, { 0x20A0, "Flirc" }, { 0x20A1, "BRAINZSQUARE CO., LTD." }, { 0x20A2, "SCANMATIK" }, { 0x20A3, "Sterilucent" }, { 0x20A4, "Itron Metering Solutions" }, { 0x20A5, "Cardiorobotics, Inc." }, { 0x20A6, "ZheJiang SEENSUN Communication&Electronic Equipment Co." }, { 0x20A7, "GREAT LUSTRE (SPEEDY) CO., LTD." }, { 0x20A8, "nLighten Technologies (Shanghai) Co., Ltd." }, { 0x20A9, "Autotronic Controls Corp." }, { 0x20AA, "ED-CONTRIVE Co., Ltd." }, { 0x20AB, "Identification International, Inc." }, { 0x20AC, "Wintek Corporation" }, { 0x20AD, "Japan Probe Co., Ltd." }, { 0x20AE, "SoCChip (Wuxi Youxin IC Design Co., Ltd.)" }, { 0x20AF, "Shenzhen CARVE Electronics Co., Ltd." }, { 0x20B0, "ICOMM TELE LIMITED" }, { 0x20B1, "XMOS Ltd." }, { 0x20B2, "Clubbhouse Inventions LLC" }, { 0x20B3, "Hannstouch Solution Inc." }, { 0x20B4, "SANDBRIDGE TECHNOLOGIES, INC." }, { 0x20B5, "ACD Gruppe" }, { 0x20B6, "Bohle AG" }, { 0x20B7, "Qi Hardware, Inc." }, { 0x20B8, "PARA INDUSTRIAL CO., LTD." }, { 0x20B9, "TLAY Technologies Co., Ltd." }, { 0x20BA, "jwin Electronics Corp." }, { 0x20BB, "THALES TRANSPORTATION SYSTEMS" }, { 0x20BC, "Guangzhou Pingzhong Electronic Technology Co., Ltd." }, { 0x20BD, "KETEK" }, { 0x20BE, "BURY GmbH & Co. KG" }, { 0x20BF, "Dwyer Instruments, Inc." }, { 0x20C0, "FENGHUA KINGSUN CO., LTD." }, { 0x20C1, "HARWIN ASIA PTE. LTD." }, { 0x20C2, "Sumitomo Electric Ind., Ltd., Optical Comm. R&D Lab" }, { 0x20C3, "TECNOMOTOR ELETRONICA DO BRASIL S/A" }, { 0x20C4, "Communications Laboratories, Inc. (Comlabs)" }, { 0x20C5, "A.U. Physics Enterprises" }, { 0x20C6, "Mutto Optronics Corporation" }, { 0x20C7, "HMC INTERNATIONAL" }, { 0x20C8, "CEC TELECOM CO., LTD." }, { 0x20C9, "SYSTEMCORP Pty., Ltd." }, { 0x20CA, "TRIPHOS Co., Ltd." }, { 0x20CB, "Dave Smith Instruments" }, { 0x20CC, "TAKARA" }, { 0x20CD, "Schweers Informationstechnologie GmbH" }, { 0x20CE, "Mini-Circuits" }, { 0x20CF, "Gridmark Limited" }, { 0x20D0, "FRESENIUS VIAL" }, { 0x20D1, "Dascom Europe GmbH" }, { 0x20D2, "ROBOTEQ INC." }, { 0x20D3, "Provo Craft" }, { 0x20D4, "SCDi" }, { 0x20D5, "Lenexpo Inc. (dba: Atlona)" }, { 0x20D6, "Bensussen Deutsch & Associates, Inc. (BDA)" }, { 0x20D7, "SHENZHEN ZILI ELECTRONICS CO. LTD." }, { 0x20D8, "Changzhou Xinchao Technologies, Inc." }, { 0x20D9, "ZHEJIANG YONGCHENGGONG DIANSU.CO., LTD." }, { 0x20DA, "LumaSense Technologies A/S" }, { 0x20DB, "KTS GmbH" }, { 0x20DC, "KCS Digital, Inc." }, { 0x20DD, "FORTREND TAIWAN SCIENTIFIC CORP." }, { 0x20DE, "OneSail HK Ltd." }, { 0x20DF, "SIMTEC ELECTRONICS" }, { 0x20E0, "Realway Electronics Technology Limited" }, { 0x20E1, "Daiichi Co., Ltd." }, { 0x20E2, "ASEQ INSTRUMENTS" }, { 0x20E3, "LAUDA DR.R.WOBSER GMBH & CO. KG" }, { 0x20E4, "Onecell Technologies" }, { 0x20E5, "Cardreader, Inc." }, { 0x20E6, "Brooks Automation, Inc." }, { 0x20E7, "Scientific Digital Imaging plc" }, { 0x20E8, "Jow Tong Technology Co., Ltd." }, { 0x20E9, "adp Gauselmann GmbH" }, { 0x20EA, "CACTUS TECHNOLOGIES, LIMITED" }, { 0x20EB, "AOS Technologies AG" }, { 0x20EC, "AMBIR TECHNOLOGY, INC." }, { 0x20ED, "TRANZFINITY, INC." }, { 0x20EE, "Emotiva Audio Corp." }, { 0x20EF, "TIGRIS Elektronik GmbH" }, { 0x20F0, "Insight Technology Incorporated" }, { 0x20F1, "NET GmbH" }, { 0x20F2, "Secured Mobility" }, { 0x20F3, "Flexcore" }, { 0x20F4, "TRENDnet" }, { 0x20F5, "MKS Instruments - Technology for Productivity" }, { 0x20F6, "EXMAN ELECTRIC" }, { 0x20F7, "XIMEA s.r.o." }, { 0x20F8, "Guangzhou Somic Digital & Electronic Technology Co, Ltd" }, { 0x20F9, "Medical Computer Systems, Ltd." }, { 0x20FA, "IC Intracom" }, { 0x20FB, "Aptina Imaging Corporation" }, { 0x20FC, "PIE SOFT LAB CORPORATION" }, { 0x20FD, "NOVO NORDISK A/S" }, { 0x20FE, "Bittium USA Inc." }, { 0x20FF, "PNI Sensor Corp." }, { 0x2100, "RT Systems Inc." }, { 0x2101, "NAS Technologies Corp." }, { 0x2102, "Vitalograph Ltd." }, { 0x2103, "OHMORI ELECTRIC INDUSTRIES CO., LTD." }, { 0x2104, "Tobii AB" }, { 0x2105, "Retail Innovation HTT AB" }, { 0x2106, "Sharp Korea Corporation" }, { 0x2107, "Amstore CD Production Ltd." }, { 0x2108, "NEATO ROBOTICS" }, { 0x2109, "VIA Labs, Inc." }, { 0x210A, "PULSUS TECHNOLOGIES" }, { 0x210B, "Work Microwave GmbH" }, { 0x210C, "DOT HILL SYSTEMS" }, { 0x210D, "Plastoform Industries Ltd." }, { 0x210E, "Commscope" }, { 0x210F, "Tyco / Scott Health & Safety" }, { 0x2110, "carina system co., ltd." }, { 0x2111, "alphaNUCLEAR Inc." }, { 0x2112, "Point Of Pay Pty. Ltd." }, { 0x2113, "Softkinetic" }, { 0x2114, "Innovision Technology Corporation Ltd." }, { 0x2115, "Alliance Material Co., Ltd." }, { 0x2116, "KT Tech Inc." }, { 0x2117, "Frama AG" }, { 0x2118, "RF WINDOW" }, { 0x2119, "MoreDNA Technology Co., Ltd." }, { 0x211A, "PILLKEY HOLDING BV" }, { 0x211B, "MENTOR GmbH & Co. Praezisions-Bauteile KG" }, { 0x211C, "SWENC Technology Co., Ltd." }, { 0x211D, "Mutualink, Inc." }, { 0x211E, "Dongbu HiTek" }, { 0x211F, "XINETWORKS CO., LTD." }, { 0x2120, "Odirrus Limited" }, { 0x2121, "Escort Data Logging Systems Ltd." }, { 0x2122, "ZEDEL" }, { 0x2123, "SYNTEK DEVELOPMENT LTD." }, { 0x2124, "ELSAGDATAMAT S.P.A." }, { 0x2125, "FIBERPRO INC." }, { 0x2126, "SUZA INTERNATIONAL FRANCE" }, { 0x2127, "FutureDial, Inc." }, { 0x2128, "Naval Research Laboratory" }, { 0x2129, "Tokushu Denshi Kairo, Inc." }, { 0x212A, "Kappa optronics GmbH" }, { 0x212B, "GR Telecom Co., Ltd." }, { 0x212C, "Shenzhen Linoya Electronic Co., Ltd." }, { 0x212D, "Dong Guan City Wanhong Electric Co., Ltd." }, { 0x212E, "Amphenol AssembleTech (Xiamen) Co., Ltd." }, { 0x212F, "SUZUKI MUSICAL INST. MFG. CO., LTD." }, { 0x2130, "Sanmu Communication Technology (H.K.) Ltd." }, { 0x2131, "IES Co., Ltd." }, { 0x2132, "EDAS, Inc." }, { 0x2133, "SIGNOTEC GmbH" }, { 0x2134, "CANESTA, INC." }, { 0x2135, "W.O.M. World of Medicine AG" }, { 0x2136, "Compunow Trading Corp." }, { 0x2137, "Beyonics Technology Limited" }, { 0x2138, "iVina, Inc." }, { 0x2139, "Eigenlabs Ltd." }, { 0x213A, "Carlo Gavazzi" }, { 0x213B, "UICO, Inc." }, { 0x213C, "ICON Health & Fitness" }, { 0x213D, "DRS Data & Imaging Systems, Inc." }, { 0x213E, "Phase Matrix, Inc." }, { 0x213F, "Digitron Instrumentation Ltd." }, { 0x2140, "Sichuan Jiuzhou Electric Group Co., Ltd." }, { 0x2141, "ZT Group Int'l, Inc." }, { 0x2142, "Enginuity Communications" }, { 0x2143, "InDevR Inc." }, { 0x2144, "Sea Tel, Inc." }, { 0x2145, "Ballard Technology" }, { 0x2146, "Victorinox AG" }, { 0x2147, "Chin-Ban Electronics (Hong Kong) Co., Ltd." }, { 0x2148, "Visteon Sistemas Automotives Ltda." }, { 0x2149, "MasTouch Optoelectronics Technologies Co., Ltd." }, { 0x214A, "Interlink Electronics" }, { 0x214B, "AMECO TECHNOLOGIES (SHENZHEN) CO., LTD." }, { 0x214C, "Y Soft Corporation" }, { 0x214D, "SyTech Corporation" }, { 0x214E, "Swiftpoint Limited" }, { 0x214F, "Attainment Company, Inc." }, { 0x2150, "AZOTEQ (PTY) LTD." }, { 0x2151, "SeaSpace Corporation" }, { 0x2152, "AD Semiconductor Co., Ltd." }, { 0x2153, "Mastertouch Solutions Electronics Co., Ltd." }, { 0x2154, "Trace Lighting Ltd." }, { 0x2155, "Teledyne Controls" }, { 0x2156, "Weistech Technology Co., Ltd." }, { 0x2157, "Digital Imaging Technology" }, { 0x2158, "TA WEI TECHNOLOGY CO., LTD." }, { 0x2159, "TRIASX Pty Ltd." }, { 0x215A, "Sling Media, Inc." }, { 0x215B, "2D Debus & Diebold Messsysteme GmbH" }, { 0x215C, "OTOVATION, LLC" }, { 0x215D, "GeNUA mbH" }, { 0x215E, "ST Embedded Engineering, LLC" }, { 0x215F, "DECIMATOR DESIGN PTY LTD." }, { 0x2160, "PULOON Technology Inc." }, { 0x2161, "BEA SA" }, { 0x2162, "Prime Audio Inc." }, { 0x2163, "Digital Rapids Corp." }, { 0x2164, "Witek System" }, { 0x2165, "CONTROL SOLUTIONS, INC." }, { 0x2166, "JVC KENWOOD Corporation" }, { 0x2167, "Zhejiang Fousine Science & Technology Co., Ltd." }, { 0x2168, "TZYR HWEY ENTERPRISE CO., LTD." }, { 0x2169, "TIANJIN SHENNAN INFORMATION SECURITY CO., LTD." }, { 0x216A, "Shenzhen San Jing Electronics Co., Ltd." }, { 0x216B, "XceedID Corporation" }, { 0x216C, "UniDisplay Inc." }, { 0x216D, "BENSON MEDICAL INSTRUMENTS" }, { 0x216E, "KHOMP INDUSTRIA E COMERCIO LTDA" }, { 0x216F, "ALTAIR SEMICONDUCTOR" }, { 0x2170, "Wurtec, Inc." }, { 0x2171, "Bokam Engineering, Inc." }, { 0x2172, "Torrey Pines Logic, Inc." }, { 0x2173, "HUIZHOU HUANGJI PRECISIONS FLEX ELECTRONICAL CO., LTD." }, { 0x2174, "Transcend Information, Inc." }, { 0x2175, "Light Blue Optics, Inc." }, { 0x2176, "TMC - Allion Test Labs" }, { 0x2177, "CHAUVIN ARNOUX" }, { 0x2178, "Ion Science" }, { 0x2179, "UGtizer Corp." }, { 0x217A, "Triple Eye" }, { 0x217B, "BDP Semiconductors Ltd." }, { 0x217C, "Sensitech Inc." }, { 0x217D, "Bilcare Technologies Singapore Pte. Ltd." }, { 0x217E, "TP RADIO" }, { 0x217F, "REAL EAR A/S" }, { 0x2180, "Icare Finland Oy" }, { 0x2181, "GLOBAL TRAFFIC TECHNOLOGIES, LLC" }, { 0x2182, "XAC Automation Corp." }, { 0x2183, "Bonutti Research" }, { 0x2184, "GOOD WILL Instrument Co., Ltd." }, { 0x2185, "FUJIWORK Co., Ltd." }, { 0x2186, "Home Server Technologies Inc." }, { 0x2187, "ESPACE SERVICES MULTIMEDIAS" }, { 0x2188, "CalDigit, Inc." }, { 0x2189, "SEMNTECH" }, { 0x218A, "EXELYS LLC" }, { 0x218B, "Blackbird Technologies Inc." }, { 0x218C, "Gammadata Instrument AB" }, { 0x218D, "Adaptive I/O Technologies, Inc." }, { 0x218E, "UNITRO-Fleischmann" }, { 0x218F, "DHEF INC." }, { 0x2190, "esonic Co., Ltd." }, { 0x2191, "SecureAT Co., Ltd." }, { 0x2192, "FlexRadio Systems" }, { 0x2193, "Schnick-Schnack-Systems GmbH" }, { 0x2194, "ROTH + WEBER GmbH" }, { 0x2195, "Hans Eckes Hardware & Software" }, { 0x2196, "XPMOBILE" }, { 0x2197, "W & D, LLC" }, { 0x2198, "Wonde Proud Technology Co., Ltd." }, { 0x2199, "Image and Information Technology" }, { 0x219A, "COSMO ELECTRONICS CO., LTD." }, { 0x219B, "TPK Touch Solutions Inc." }, { 0x219C, "SEAL ONE AG" }, { 0x219D, "BDR Technologies Ltd." }, { 0x219E, "VALKEE OY" }, { 0x219F, "VENTIS" }, { 0x21A0, "AXELSPACE Corporation" }, { 0x21A1, "EMOTIV SYSTEMS INC." }, { 0x21A2, "ABB Low Voltage Products" }, { 0x21A3, "Optcom Co., Ltd." }, { 0x21A4, "ELECTRONIC ARTS" }, { 0x21A5, "Genesis Technology USA, Inc." }, { 0x21A6, "YUPITERU CORPORATION" }, { 0x21A7, "PAYPRINT SRL" }, { 0x21A8, "GE Intelligent Platforms, Inc." }, { 0x21A9, "Saleae LLC" }, { 0x21AA, "TAKASAKI KYODO COMPUTING CENTER CO., LTD." }, { 0x21AB, "Planeta Informatica Ltda." }, { 0x21AC, "infoSense Technology Inc." }, { 0x21AD, "Wobbegong Fitness and Therapy Products Pty. Ltd." }, { 0x21AE, "Philips and Neusoft Medical System Co., Ltd." }, { 0x21AF, "Euro-CB Phils. Inc." }, { 0x21B0, "Grace Industries, Incorporated" }, { 0x21B1, "TATA CONSULTANCY SERVICES" }, { 0x21B2, "Felix Meier GmbH" }, { 0x21B3, "Dongguan Teconn Electronics Technology Co., Ltd." }, { 0x21B4, "Wavelength Audio, Ltd." }, { 0x21B5, "SHENZHEN JASON ELECTRONICS CO., LTD." }, { 0x21B6, "EUROAVIONICS GmbH & Co. KG" }, { 0x21B7, "STAIB INSTRUMENTE GmbH" }, { 0x21B8, "KONTRONIK GmbH" }, { 0x21B9, "ZP ENGINEERING s.r.l." }, { 0x21BA, "SI2 MICROSYSTEMS, Ltd." }, { 0x21BB, "WWPass Corporation" }, { 0x21BC, "Skyhawke Technologies, LLC" }, { 0x21BD, "Code Red Technologies, Ltd." }, { 0x21BE, "KEC Co., Ltd." }, { 0x21BF, "Mayo Clinic" }, { 0x21C0, "PIXTREE, Inc." }, { 0x21C1, "Baumann Electronic Controls, LLC" }, { 0x21C2, "Shenzhen V-Interface Technology Co., Ltd." }, { 0x21C3, "MASIMO LABORATORIES INC." }, { 0x21C4, "Longsys Electronics (HK) Co., Ltd." }, { 0x21C5, "Vukic Computer Instruments GmbH" }, { 0x21C6, "PSS Hong Kong Limited" }, { 0x21C7, "Unisoku Co., Ltd." }, { 0x21C8, "IDONDEMAND INC." }, { 0x21C9, "Innoteletek, Inc." }, { 0x21CA, "RAE Systems Inc." }, { 0x21CB, "Vodafone Ltd." }, { 0x21CC, "ChipsWork Microelectronics Corp." }, { 0x21CD, "Infoxelle Co., Ltd." }, { 0x21CE, "Polostar Technology Corporation" }, { 0x21CF, "HISATOMI ELECTRIC IND. CO., LTD." }, { 0x21D0, "Red Rapids" }, { 0x21D1, "ADDER TECHNOLOGY LTD." }, { 0x21D2, "NeoLAB Convergence" }, { 0x21D3, "Compupack Technology Co., Ltd." }, { 0x21D4, "Eduplayer Co., Ltd." }, { 0x21D5, "M.G.F." }, { 0x21D6, "Agecodagis SARL" }, { 0x21D7, "VINCIAMO, Inc." }, { 0x21D8, "P & A Technologies, Inc." }, { 0x21D9, "Verification Technology, Inc." }, { 0x21DA, "Valor Auto Companion, Inc." }, { 0x21DB, "G-Max Technology Co., Ltd." }, { 0x21DC, "ABB S.p.A., Low Voltage Products Division" }, { 0x21DD, "Looxcie, Inc." }, { 0x21DE, "Cloud Engines, Inc." }, { 0x21DF, "Quanser Consulting Inc." }, { 0x21E0, "OpenPattern" }, { 0x21E1, "CAEN S.P.A." }, { 0x21E2, "Ascension Technology Corp." }, { 0x21E3, "Crest Technology Inc." }, { 0x21E4, "Xcellen Co., Ltd." }, { 0x21E5, "Kruglov Evgeniy Vladimirovich" }, { 0x21E6, "OCZ Technology Group" }, { 0x21E7, "Sagemcom Broadband SAS" }, { 0x21E8, "BOEHNKE + PARTNER GmbH Steuerungssysteme" }, { 0x21E9, "Jiafuh Metal & Plastic (ShenZhen) Co., Ltd." }, { 0x21EA, "JUST MAKE ELECTRONICS CO., LTD." }, { 0x21EB, "KOKORO CO., LTD." }, { 0x21EC, "ApniCure, Inc." }, { 0x21ED, "Accuphase Laboratories, Inc." }, { 0x21EE, "MAVIN TECHNOLOGY INC." }, { 0x21EF, "FEMTO Messtechnik GmbH" }, { 0x21F0, "LivingLab Development Co., Ltd." }, { 0x21F1, "ABS Group AB" }, { 0x21F2, "Palmer Environmental Ltd." }, { 0x21F3, "Inspired Instruments Inc." }, { 0x21F4, "Minebea Technologies Taiwan Co., Ltd." }, { 0x21F5, "Shenzhen Strong Rising Electronics Co., Ltd." }, { 0x21F6, "QSR Automations, Inc." }, { 0x21F7, "Wuerth-Elektronik eiSos GmbH & Co. KG" }, { 0x21F8, "Goeasily Int'l Co., Ltd." }, { 0x21F9, "American Thermal Instruments" }, { 0x21FA, "Pitsco, Inc." }, { 0x21FB, "HELIOS Electronic Design & Manufacture" }, { 0x21FC, "Thum + Mahr GmbH" }, { 0x21FD, "Associated Controls (Australia) Pty., Limited" }, { 0x21FE, "ELAP S.p.A." }, { 0x21FF, "DEIF A/S" }, { 0x2200, "Nuribom" }, { 0x2201, "Elan Digital Systems Ltd." }, { 0x2202, "Walex Electronic (Wu Xi) Co., Ltd." }, { 0x2203, "Shin Shin Co., Ltd." }, { 0x2204, "Innov-X Systems Inc." }, { 0x2205, "3eYamaichi Electronics Co., Ltd." }, { 0x2206, "Wiretek International Investment Ltd." }, { 0x2207, "Fuzhou Rockchip Electronics Co., Ltd." }, { 0x2208, "CONNFLY ELECTRONIC CO., LTD." }, { 0x2209, "SPoT LLC" }, { 0x220A, "Anton Paar GmbH" }, { 0x220B, "IKARIA Holdings, Inc." }, { 0x220C, "Island Technology Co., Ltd." }, { 0x220D, "Humanline Co., Ltd." }, { 0x220E, "NetComm Ltd." }, { 0x220F, "Italdata Ingegneria Dell'Idea s.p.a." }, { 0x2210, "Klavis Technologies" }, { 0x2211, "FLUID COMPONENTS INTERNATIONAL LLC" }, { 0x2212, "Dev-Audio Pty. Ltd. (Dev-Audio)" }, { 0x2213, "Ascon Co., Ltd." }, { 0x2214, "Pollin Electronic GmbH" }, { 0x2215, "InCOMM Technologies Co., Ltd." }, { 0x2216, "Environmental Systems Corporation" }, { 0x2217, "FTS Forest Technology Systems Ltd." }, { 0x2218, "Listen Technologies Corp." }, { 0x2219, "Hogahm Technology" }, { 0x221A, "ZTEX" }, { 0x221B, "Kyodo Denshi Engineering Co., Ltd." }, { 0x221C, "CORTEX TECHNOLOGY APS" }, { 0x221D, "fischertechnik GmbH" }, { 0x221E, "Linktec Technologies Co., Ltd." }, { 0x221F, "Resolution Audio" }, { 0x2220, "FAMAS SYSTEM S.P.A." }, { 0x2221, "EnovateIT Inc." }, { 0x2222, "SOFTMECHA" }, { 0x2223, "Ratioplast-Optoelectronics GmbH" }, { 0x2224, "LM Technologies Ltd." }, { 0x2225, "GETT Geratetechnik GmbH" }, { 0x2226, "PLANAR LLC" }, { 0x2227, "Northtronics Pty., Ltd." }, { 0x2228, "Dantec Dynamics A/S" }, { 0x2229, "Key Technologies, Inc." }, { 0x222A, "ILI TECHNOLOGY CORP." }, { 0x222B, "ALPHAMEDIA CO., LTD." }, { 0x222C, "TOHAN DENSHI KIKI Co., Ltd." }, { 0x222D, "LEIFHEIT AG" }, { 0x222E, "OXYSEC s.r.l." }, { 0x222F, "Tcom Technology Co., Ltd." }, { 0x2230, "Plugable Technologies" }, { 0x2231, "Coregate Inc." }, { 0x2232, "NAMUGA Co., Ltd." }, { 0x2233, "ARGtek Communication Inc." }, { 0x2234, "T-CONN PRECISION CORPORATION" }, { 0x2235, "WoundVision" }, { 0x2236, "ACELLA" }, { 0x2237, "Kobo Inc." }, { 0x2238, "ELMO Motion Control Ltd." }, { 0x2239, "PEIKER acustic GmbH & Co., KG" }, { 0x223A, "BKtel Communications GmbH" }, { 0x223B, "Crystalfontz America, Inc." }, { 0x223C, "Audio Research Corp." }, { 0x223D, "AlfaPlus Semiconductor, Inc." }, { 0x223E, "Home Electronics" }, { 0x223F, "Oga, Inc." }, { 0x2240, "NETTALK.COM INC." }, { 0x2241, "Envision Interface Engineering, LLC" }, { 0x2242, "Zhihe Electronics Technology Co., Ltd." }, { 0x2243, "EMIC CORPORATION" }, { 0x2244, "Kronos" }, { 0x2245, "ASPEED Technology Inc." }, { 0x2246, "Nanjing Frentec Co., Ltd." }, { 0x2247, "CHUNGHWA PICTURE TUBES, LTD." }, { 0x2248, "KAISE CORPORATION" }, { 0x2249, "Long Range Systems, Inc." }, { 0x224A, "ORMEC SYSTEMS CORP." }, { 0x224B, "Sirit Inc." }, { 0x224C, "Datron World Communications, Inc." }, { 0x224D, "Tescom Co., Ltd." }, { 0x224E, "RDH2 Science" }, { 0x224F, "APDM, INC." }, { 0x2250, "Evernew Wire & Cable Co., Ltd." }, { 0x2251, "QuieTek Corp." }, { 0x2252, "TSANSUN TECH. CO., LTD." }, { 0x2253, "Arpage AG" }, { 0x2254, "RPO" }, { 0x2255, "COOPER WIRELESS" }, { 0x2256, "Mathias Fuchss Software - Entwicklung" }, { 0x2257, "On the Go Video, Inc." }, { 0x2258, "D+H Mechatronic AG" }, { 0x2259, "Skypine Electronics (Shenzhen) Co., Ltd." }, { 0x225A, "Vivanco GmbH" }, { 0x225B, "Lineage Power" }, { 0x225C, "Digital Check Corp" }, { 0x225D, "Sagem Securite" }, { 0x225E, "Unholtz-Dickie Corp." }, { 0x225F, "Ace Karaoke Corp." }, { 0x2260, "Multigig, Inc." }, { 0x2261, "DOM-Sicherheitstechnik GmbH & Co. KG" }, { 0x2262, "VIETTEL GROUP" }, { 0x2263, "Nuovations" }, { 0x2264, "Entourage Systems, Inc." }, { 0x2265, "DailyCare BioMedical Inc." }, { 0x2266, "Psychology Software Tools, Inc." }, { 0x2267, "Boreal Genomics" }, { 0x2268, "EXSUSS, Inc." }, { 0x2269, "Schlumberger Ltd." }, { 0x226A, "Ooma, Inc." }, { 0x226B, "Bruker Nano GmbH" }, { 0x226C, "HAL Communications Corp." }, { 0x226D, "Wrenchman, Inc." }, { 0x226E, "DISPLAX" }, { 0x226F, "Koyo Trading Co., Ltd." }, { 0x2270, "XiaMen GaoLuChang Electronics Co. Ltd." }, { 0x2271, "Karl Storz GmbH & Co. KG" }, { 0x2272, "E.E.P.D." }, { 0x2273, "IMAX Corporation" }, { 0x2274, "Morgan Schaffer Inc." }, { 0x2275, "ReliOn Inc." }, { 0x2276, "Pioneer CBC" }, { 0x2277, "Ortho Neuro Technologies, Inc." }, { 0x2278, "Infratec Datentechnik GmbH" }, { 0x2279, "Goossens Engineering" }, { 0x227A, "FLOM Corporation" }, { 0x227B, "CYBELEC SA" }, { 0x227C, "S. & A.S. LTD." }, { 0x227D, "Unitec Co., Ltd." }, { 0x227E, "JSC " }, { 0x227F, "Granite River Labs" }, { 0x2280, "Life Technologies Corp." }, { 0x2281, "GI CORPORATION" }, { 0x2282, "Mamiya Digital Imaging Co., Ltd." }, { 0x2283, "NIHON DEMPA KOGYO Co., Ltd." }, { 0x2284, "SuperSonic Inc." }, { 0x2285, "IRIS ID" }, { 0x2286, "Altierre Corporation" }, { 0x2287, "Shenzhen Oversea Win Technology Co., Ltd." }, { 0x2288, "Dt&C (Digital Technology and Certification)" }, { 0x2289, "Sun Fair Electric Wire & Cable (HK) Co., Ltd." }, { 0x228A, "Hotron Precision Electronic Ind. Corp." }, { 0x228B, "Shenzhen DLK Electronics Technology Co., Ltd." }, { 0x228C, "Analogic Corporation" }, { 0x228D, "8D TECHNOLOGIES INC." }, { 0x228E, "EKO Instruments Co., Ltd." }, { 0x228F, "SIGMATEK GmbH & Co. KG" }, { 0x2290, "Touchplus information Corp." }, { 0x2291, "Vallen Systeme GmbH" }, { 0x2292, "Global Industrial Services, Ltd." }, { 0x2293, "Berger Elektronik GmbH" }, { 0x2294, "KoCo Connector AG" }, { 0x2295, "Sound ID" }, { 0x2296, "Musashi Engineering Company Limited" }, { 0x2297, "Grain Media, Inc." }, { 0x2298, "PULSION Medical Systems AG" }, { 0x2299, "BRAIN VISION SYSTEMS (BVS)" }, { 0x229A, "Control Express Finland OY" }, { 0x229B, "SFC Smart Fuel Cell AG" }, { 0x229C, "Raytheon Company" }, { 0x229D, "Solacia Inc." }, { 0x229E, "JV2R - MacWay" }, { 0x229F, "RRC power solutions GmbH" }, { 0x22A0, "Winpos System Co., Ltd." }, { 0x22A1, "Shenzhen Jiuzhou Electric Co., Ltd." }, { 0x22A2, "Disruptive Ltd." }, { 0x22A3, "DexCom" }, { 0x22A4, "InnoComm Mobile Technology Corp." }, { 0x22A5, "Yu Jeong System Co., Ltd." }, { 0x22A6, "Pie Digital, Inc." }, { 0x22A7, "Fortinet, Inc." }, { 0x22A8, "OTTO" }, { 0x22A9, "Valor Communication, Inc." }, { 0x22AA, "AppliedMicro" }, { 0x22AB, "Trigence Semiconductor, Inc." }, { 0x22AC, "Sensor Switch, Inc." }, { 0x22AD, "DCP Microdevelopments Limited" }, { 0x22AE, "Buerkert Werke GmbH" }, { 0x22AF, "JW Fishers Mfg." }, { 0x22B0, "Business Security OL AB" }, { 0x22B1, "Secret Labs LLC" }, { 0x22B2, "EDGE Tech Corp." }, { 0x22B3, "SOMFY" }, { 0x22B4, "NIPPON ANTENNA Co., Ltd." }, { 0x22B5, "Thyracont Vacuum Instruments GmbH" }, { 0x22B6, "IMTRADEX Hoer-/Sprechsysteme GmbH" }, { 0x22B7, "Unjo AB" }, { 0x22B8, "Motorola Mobility Inc." }, { 0x22B9, "eTurboTouch Technology Inc." }, { 0x22BA, "Technology Innovation Holdings Ltd." }, { 0x22BB, "Saris Cycling Group" }, { 0x22BC, "OPWILL Technologies (Beijing) Co., Ltd." }, { 0x22BD, "Basis Software, Inc." }, { 0x22BE, "Cheetah-Medical Ltd." }, { 0x22BF, "Bit Cauldron Corporation" }, { 0x22C0, "ReLia Diagnostic Systems, Inc." }, { 0x22C1, "ATEK Products, LLC" }, { 0x22C2, "Fast And Safe Technology Co., Ltd." }, { 0x22C3, "Tsinghua Tongfang Co., Ltd." }, { 0x22C4, "Fresenius Medical Care Deutschland GmbH" }, { 0x22C5, "Himax Technologies, Inc." }, { 0x22C6, "Baker Hughes Production Quest" }, { 0x22C7, "MEMUP" }, { 0x22C8, "Shenzhen Xinerchang Electronics Co., Ltd." }, { 0x22C9, "StepOver GmbH" }, { 0x22CA, "Amimon Ltd." }, { 0x22CB, "Forware Spain S.L." }, { 0x22CC, "LAONEX CO., LTD." }, { 0x22CD, "Kinova" }, { 0x22CE, "Metters Industries" }, { 0x22CF, "Marquess Co., Limited" }, { 0x22D0, "Norsonic AS" }, { 0x22D1, "ZeitControl GmbH" }, { 0x22D2, "ZETT OPTICS GmbH" }, { 0x22D3, "FAAC SpA" }, { 0x22D4, "Laview Technology Ltd." }, { 0x22D5, "Yellow Soft Co., Ltd." }, { 0x22D6, "Numatic International Ltd." }, { 0x22D7, "IntelliTech International, Inc." }, { 0x22D8, "Shantery Co., Ltd." }, { 0x22D9, "GuangDong OPPO Mobile Telecommunications Corp., Ltd." }, { 0x22DA, "TXTR GmbH" }, { 0x22DB, "Phase One A/S" }, { 0x22DC, "TILERA CORPORATION" }, { 0x22DD, "Kawasaki Heavy Industries, Ltd." }, { 0x22DE, "WeTelecom" }, { 0x22DF, "Medicom-MTD" }, { 0x22E0, "Secunet Security Networks AG" }, { 0x22E1, "TempoTec Corp" }, { 0x22E2, "IDEA!" }, { 0x22E3, "Escort, Inc." }, { 0x22E4, "Shenyang Tongzhen Precision Electronic Technology Co." }, { 0x22E5, "Mine Safety Appliances Co." }, { 0x22E6, "Labo America, Inc." }, { 0x22E7, "ZAFFER BVBA" }, { 0x22E8, "Audio Partnership" }, { 0x22E9, "Orion Diagnostica OY" }, { 0x22EA, "Bit Trade One, Ltd." }, { 0x22EB, "Vizimax Inc." }, { 0x22EC, "Kozio, Inc." }, { 0x22ED, "HannStar Display Corp." }, { 0x22EE, "Struers A/S" }, { 0x22EF, "Edutor Technologies India Private Limited" }, { 0x22F0, "Allen + Heath Ltd." }, { 0x22F1, "DATEQ BV" }, { 0x22F2, "Quest Payment Systems" }, { 0x22F3, "Zephyr Technology Corporation" }, { 0x22F4, "Olive Global Holding Pvt. Ltd." }, { 0x22F5, "oTHE Technology Inc." }, { 0x22F6, "Clear Pulse Co., Ltd." }, { 0x22F7, "Drivven, Inc." }, { 0x22F8, "Universal Sats Ltd." }, { 0x22F9, "Compass, s.r.l." }, { 0x22FA, "Sifteo Inc." }, { 0x22FB, "Beijing Chiplight IC Design Co., Ltd." }, { 0x22FC, "ModusLink Global Solutions, Inc." }, { 0x22FD, "Miltope Corp." }, { 0x22FE, "Protium Technologies, Inc." }, { 0x22FF, "Avnet" }, { 0x2300, "Nanjing Magon Opto-Electrical Science & Technology Co." }, { 0x2301, "Imaginant Inc." }, { 0x2302, "Rafael Advanced Defense Systems Ltd." }, { 0x2303, "Grosvenor Technology Ltd." }, { 0x2304, "Pinnacle" }, { 0x2305, "Lindemann Audiotechnik GmbH" }, { 0x2306, "Syba Multimedia, Inc." }, { 0x2307, "Madboy Audio International Oy" }, { 0x2308, "UV Networks, Inc." }, { 0x2309, "TimeLink Inc." }, { 0x230A, "Data Locker Inc." }, { 0x230B, "Shanda Interactive Entertainment Limited" }, { 0x230C, "GarTech Enterprises, Inc." }, { 0x230D, "Linktop Technology Co., Ltd." }, { 0x230E, "eDAQ Pty., Ltd." }, { 0x230F, "applause.elfmimi.jp" }, { 0x2310, "WCE, Inc." }, { 0x2311, "Francotyp-Postalia GmbH" }, { 0x2312, "Learning Curve Brands, Inc." }, { 0x2313, "Kunshan Jiahua Electronics Co., Ltd." }, { 0x2314, "INQ Mobile Limited" }, { 0x2315, "Avery Design Systems, Inc." }, { 0x2316, "DongGuan Potec Electric Industrial Co., Ltd." }, { 0x2317, "Huawei Device Co., Ltd." }, { 0x2318, "Solar Components LLC" }, { 0x2319, "Loewe Opta GmbH" }, { 0x231A, "SANWA KAGAKU KENKYUSHO CO., LTD." }, { 0x231B, "winner story Co., Ltd." }, { 0x231C, "SONUUS LIMITED" }, { 0x231D, "Fervian Technologies Limited" }, { 0x231E, "Chongqing CYIT Communication Technologies Co., Ltd." }, { 0x231F, "FandF Co., Ltd." }, { 0x2320, "Redring AB" }, { 0x2321, "iKingdom Corp. (d.b.a. iConnectivity)" }, { 0x2322, "RichWave Technology Corp." }, { 0x2323, "EFI TECHNOLOGY s.r.l." }, { 0x2324, "Ubisense Limited" }, { 0x2325, "Simbex" }, { 0x2326, "CKM Electronics Co., Ltd." }, { 0x2327, "DreamSecurity" }, { 0x2328, "Radio Systems Corporation" }, { 0x2329, "Infinite Technologies JLT" }, { 0x232A, "Skalar Analytical b.v." }, { 0x232B, "Zhuhai Pantum Technology Co., Ltd." }, { 0x232C, "Digital Lumens" }, { 0x232D, "Edinburgh Instruments Ltd." }, { 0x232E, "EA, Elektro-Automatik GmbH & Co. KG" }, { 0x232F, "Motic China Group Co., Ltd." }, { 0x2330, "Tensorcom, Inc." }, { 0x2331, "PUZZLE LOGIC INC." }, { 0x2332, "Coges S.p.A." }, { 0x2333, "Zamzee Co." }, { 0x2334, "Opticos srl" }, { 0x2335, "Personable Inc." }, { 0x2336, "Vix Technology (Aust) Ltd." }, { 0x2337, "linked IP GmbH" }, { 0x2338, "RedE Innovations" }, { 0x2339, "Sierra Nevada Corporation" }, { 0x233A, "Telpar" }, { 0x233B, "taberna pro medicum GmbH" }, { 0x233C, "Julabo" }, { 0x233D, "Microtech System" }, { 0x233E, "Aastra Telecom Inc." }, { 0x233F, "Stage Tec GmbH" }, { 0x2340, "Teleepoch Limited" }, { 0x2341, "Arduino, LLC" }, { 0x2342, "nextEDGE Technology, K.K." }, { 0x2343, "AquaScan A/S" }, { 0x2344, "HAMBURG INDUSTRIES CO., LTD." }, { 0x2345, "ZOWIE GEAR" }, { 0x2346, "Data Transfer & Communications Ltd." }, { 0x2347, "iControl Networks" }, { 0x2348, "Ubisys Technology" }, { 0x2349, "P2 Engineering Group, LLC" }, { 0x234A, "Cypress Technology Co., Ltd." }, { 0x234B, "Free Software Initiative of Japan" }, { 0x234C, "Zenverge Inc." }, { 0x234D, "Skype Inc." }, { 0x234E, "Anewin" }, { 0x234F, "VaniOs Consulting" }, { 0x2350, "ZiiLABS Pte. Ltd." }, { 0x2351, "EmbCodeAB" }, { 0x2352, "SKYTEX Technology Inc." }, { 0x2353, "PHiON Technology Inc." }, { 0x2354, "BirdBrain Technologies LLC" }, { 0x2355, "Pacific Northwest National Laboratory (PNNL)" }, { 0x2356, "Grid Connect Inc." }, { 0x2357, "TP-LINK Technologies Co., Ltd." }, { 0x2358, "Greenconn Corporation" }, { 0x2359, "Shenzhen Autone-Tronic Technology Co., Ltd." }, { 0x235A, "Top Yang Technology Enterprise Co., Ltd." }, { 0x235B, "KangXiang Electronic Co., Ltd." }, { 0x235C, "Neuralieve" }, { 0x235D, "Wavepod Technologies LLC" }, { 0x235E, "Sage Electronic Engineering LLC" }, { 0x235F, "Delux Technology Co., Ltd." }, { 0x2360, "AudioProbe Inc." }, { 0x2361, "Artiza Networks, Inc." }, { 0x2362, "Intuity Medical" }, { 0x2363, "SplitFish Ltd." }, { 0x2364, "Friedrich Leutert GmbH & Co. KG" }, { 0x2365, "Midwest Microwave Solutions" }, { 0x2366, "Bitmanufaktur GmbH" }, { 0x2367, "Teenage Engineering" }, { 0x2368, "Peterson Electro-Musical Products, Inc." }, { 0x2369, "Telspan Data, LLC" }, { 0x236A, "SiBEAM, Inc." }, { 0x236B, "Era Optoelectronics Inc." }, { 0x236C, "ZheJiang Chunsheng Electronics Co., Ltd." }, { 0x236D, "e-supplies Co., Ltd." }, { 0x236E, "Idex ASA" }, { 0x236F, "Risun Electric Information Technology Co., Ltd." }, { 0x2370, "Vlatacom d.o.o." }, { 0x2371, "Zetron, Inc." }, { 0x2372, "Shenzhen Techaser Technologies Co., Ltd." }, { 0x2373, "Pumatronix Equipamentos Eletronicos Ltda." }, { 0x2374, "Codan Limited" }, { 0x2375, "Nexell Co., Ltd." }, { 0x2376, "Realfiction Aps" }, { 0x2377, "Musa srl" }, { 0x2378, "OnLive, INC." }, { 0x2379, "Geotechnical Instruments (UK) Ltd." }, { 0x237A, "Danatronics, Corp." }, { 0x237B, "YUKAI Engineering" }, { 0x237C, "POWERVAR" }, { 0x237D, "CradlePoint, Inc." }, { 0x237E, "Ernie Ball, Inc." }, { 0x237F, "He Shan World Fair Electronics Technology Ltd." }, { 0x2380, "Law Enforcement Associates, Inc." }, { 0x2381, "IPE Music" }, { 0x2382, "Trigaudio, Inc." }, { 0x2383, "Super Pioneer Co., Ltd." }, { 0x2384, "Tamara Electronics Design" }, { 0x2385, "Booyco Electronics (Pty) Ltd." }, { 0x2386, "Raydium Semiconductor Corporation" }, { 0x2387, "N&S Services, Inc. dba XIM Technologies" }, { 0x2388, "High Density Devices" }, { 0x2389, "ShenZhen Handin Tech Co., Ltd." }, { 0x238A, "ASAHI SANGYO CO., LTD." }, { 0x238B, "Hytera Communications Co., Ltd." }, { 0x238C, "Japan Care Net Service Corporation" }, { 0x238D, "OMNIO Corporation" }, { 0x238E, "Xtralis" }, { 0x238F, "TRS Star GmbH" }, { 0x2390, "Triex Technologies, Inc." }, { 0x2391, "FUKUDA CO., LTD." }, { 0x2392, "Deltatee Enterprises Ltd." }, { 0x2393, "WonATech Co., Ltd." }, { 0x2394, "J.MORITA MFG. CORP." }, { 0x2395, "CNOGA MEDICAL LTD." }, { 0x2396, "Advanced Multi Tech Pte. Ltd." }, { 0x2397, "Simaudio Ltd." }, { 0x2398, "Bluetechnix" }, { 0x2399, "Lightwares" }, { 0x239A, "Adafruit Industries LLC" }, { 0x239B, "TZ Medical, Inc." }, { 0x239C, "Braebon Medical Corporation" }, { 0x239D, "Memjet Labels, Inc." }, { 0x239E, "Rubin Informatikai Zrt." }, { 0x239F, "Nikola Engineering Inc." }, { 0x23A0, "BIFIT" }, { 0x23A1, "Pepperl+Fuchs GmbH" }, { 0x23A2, "Mobile Peak Holdings, Ltd." }, { 0x23A3, "Dongguan City ShengJing Electronics Co., Ltd." }, { 0x23A4, "MINGTECH CHINA CO., LTD." }, { 0x23A5, "Instytut Fotonowy Sp. Z o.o." }, { 0x23A6, "Tronical Components GmbH" }, { 0x23A7, "System In Frontier Inc." }, { 0x23A8, "Sagio A/S" }, { 0x23A9, "SiliconGo Microelectronics Inc." }, { 0x23AA, "DOK (HK) Trading Limited" }, { 0x23AB, "SZZT ELECTRONICS CO., LTD" }, { 0x23AC, "Marunix Electron Limited" }, { 0x23AD, "voxeljet technology GmbH" }, { 0x23AE, "DIGITAL DEVICES UG" }, { 0x23AF, "iOWA AB" }, { 0x23B0, "Seniorsoft Development Co., Ltd." }, { 0x23B1, "Riken Keiki Co., Ltd." }, { 0x23B2, "SEER Technology, Inc." }, { 0x23B3, "Straubtec GmbH & Co. KG" }, { 0x23B4, "Dental Wings Inc." }, { 0x23B5, "Crowcon Detection Instruments Limited" }, { 0x23B6, "FULL ELECTRONIC system" }, { 0x23B7, "Isca Networks" }, { 0x23B8, "Daruma Telecomunicacoes e Informatica S/A" }, { 0x23B9, "Green Energy Options Ltd." }, { 0x23BA, "Playback Designs LLC" }, { 0x23BB, "EMI STOP CORP." }, { 0x23BC, "ARIDIAN TECHNOLOGY COMPANY INC." }, { 0x23BD, "Musashi Engineering, Inc." }, { 0x23BE, "Raynet Technologies Pte. Ltd." }, { 0x23BF, "Environics Oy" }, { 0x23C0, "Kotec" }, { 0x23C1, "MakerBot Industries" }, { 0x23C2, "CREALOGIX E-Banking AG" }, { 0x23C3, "Cydle Corp." }, { 0x23C4, "Media Engineering" }, { 0x23C5, "Promega Corporation" }, { 0x23C6, "plawa-feinwerktechnik GmbH & Co. KG" }, { 0x23C7, "GCI Technologies Corp." }, { 0x23C8, "IML Ltd." }, { 0x23C9, "IRM Touch Inc." }, { 0x23CA, "IHP GmbH Innovations for High Performance Microelectro" }, { 0x23CB, "Point Core SARL" }, { 0x23CC, "Avitech International Corp." }, { 0x23CD, "Avconn Precise Connector Co., Ltd." }, { 0x23CE, "Gembird Electronics Ltd." }, { 0x23CF, "Admesy BV" }, { 0x23D0, "Youjie" }, { 0x23D1, "LUFFT Mess-und Regeltechnik GmbH" }, { 0x23D2, "WEAVERSMIND Inc." }, { 0x23D3, "RFTECH SRL" }, { 0x23D4, "ALLTRAX, Inc." }, { 0x23D5, "SerialTek" }, { 0x23D6, "DONGGUAN LICHENG ELECTRONICS CO., LTD." }, { 0x23D7, "PENNYWISE PERIPHERALS PTY. LTD." }, { 0x23D8, "CREATOR (CHINA) TECH CO., LTD." }, { 0x23D9, "SIGLEAD Inc." }, { 0x23DA, "THK Co., Ltd." }, { 0x23DB, "Sonicweld" }, { 0x23DC, "Phonic Ear, Inc. Frontrow Division" }, { 0x23DD, "Ningbo Sunny Opotech Co., Ltd." }, { 0x23DE, "ZAO Papillon" }, { 0x23DF, "WebAthletics BV" }, { 0x23E0, "BitifEye Digital Test Solutions GmbH" }, { 0x23E1, "Vidyo, Inc." }, { 0x23E2, "Shape Medical Systems, Inc." }, { 0x23E3, "Christie Digital Systems Canada Inc." }, { 0x23E4, "General Microsystems Sdn Bhd" }, { 0x23E5, "Antelope Audio" }, { 0x23E6, "DIGIT MOBILE INC." }, { 0x23E7, "ROGER Dariusz Wensker Grzegorz Wensker S.P.j." }, { 0x23E8, "Propellerhead Software AB" }, { 0x23E9, "Peregrine Technology Co., Ltd." }, { 0x23EA, "Inputek" }, { 0x23EB, "TOPPAN FORMS CO., LTD." }, { 0x23EC, "Alacer Biomedica Industria Eletronica Ltda." }, { 0x23ED, "Optomotive, mehatronika d.o.o." }, { 0x23EE, "Sofird, Inc." }, { 0x23EF, "PPHU AWEX RAFAL STANUCH" }, { 0x23F0, "Ecotronics Limited" }, { 0x23F1, "WIMM Labs" }, { 0x23F2, "Northern Digital Inc." }, { 0x23F3, "Funke Digital TV" }, { 0x23F4, "NXT Plc" }, { 0x23F5, "Speed Conn Electronics (Shenzhen) Co., Ltd." }, { 0x23F6, "Gamesman Ltd." }, { 0x23F7, "TechRhythm, Inc." }, { 0x23F8, "Xiangde Electronic Technologies (Shenzhen) Co., Ltd." }, { 0x23F9, "RT Systems (Pty) Ltd." }, { 0x23FA, "DJO, LLC" }, { 0x23FB, "Janich & Klass Computertechnik GmbH" }, { 0x23FC, "SesKion GmbH" }, { 0x23FD, "AWare, Inc." }, { 0x23FE, "Express Way Limited" }, { 0x23FF, "UIworks Electronics" }, { 0x2400, "Shenzhen Chuangyitong Technology Co., Ltd" }, { 0x2401, "Deltronic Labs" }, { 0x2402, "DA FACT" }, { 0x2403, "XTRAMUS TECHNOLOGIES" }, { 0x2404, "GE MDS" }, { 0x2405, "Custom Computer Services, Inc." }, { 0x2406, "WIseKey" }, { 0x2407, "Incasolution Co., Ltd." }, { 0x2408, "Catalyst Enterprises, Inc." }, { 0x2409, "BCInet, Inc." }, { 0x240A, "Infron Teknolojik Sistemleri San. Ve Tic. Ltd. STI" }, { 0x240B, "Kawamura Electric, Inc." }, { 0x240C, "Maples Micro System Corp" }, { 0x240D, "Chinachip Technology Limited" }, { 0x240E, "JEFF ROWLAND DESIGN GROUP, INC" }, { 0x240F, "Trantek Electronics Co., Ltd." }, { 0x2410, "Tenebraex Corp." }, { 0x2411, "Industrial Scientific Oldham SAS" }, { 0x2412, "Invision Biometrics Ltd." }, { 0x2413, "Skyviia Corporation" }, { 0x2414, "Leopold Kostal GmbH & Co. KG" }, { 0x2415, "CipherLab Co., Ltd." }, { 0x2416, "FUTURE DESIGNS, INC." }, { 0x2417, "INIT GmbH" }, { 0x2418, "Irphotonics" }, { 0x2419, "Shenzhen Dnine Technology Co., Ltd." }, { 0x241A, "The Silanna Group Pty. Ltd." }, { 0x241B, "Dongguan City Qirui Electronics Co., Ltd." }, { 0x241C, "ATMOS Medizin Technik GmbH & Co. KG" }, { 0x241D, "Redbird Flight Simulations, Inc." }, { 0x241E, "SHENZHEN FUNDUN TECHNOLOGY CO., LTD." }, { 0x241F, "Global Geo Supplies, Inc." }, { 0x2420, "M Seven System Limited" }, { 0x2421, "Anasphere, Inc." }, { 0x2422, "Tom Communication Industrial Co., Ltd." }, { 0x2423, "Bio-Med Devices Inc." }, { 0x2424, "CREATZ Inc." }, { 0x2425, "PIQX Imaging Pte. Ltd." }, { 0x2426, "Johnson Controls, Inc. - Building Efficiency Business" }, { 0x2427, "Winkelmann UK Ltd." }, { 0x2428, "SANTEC CORPORATION" }, { 0x2429, "IWSCOPE Inc." }, { 0x242A, "HUR OY" }, { 0x242B, "Philips Healthcare" }, { 0x242C, "ARMSTEL, Inc." }, { 0x242D, "Flastar Technology Co., Ltd." }, { 0x242E, "Vossloh-Schwabe Deutschland GmbH" }, { 0x242F, "GPH Co., Ltd." }, { 0x2430, "APE GmbH" }, { 0x2431, "Yamazaki Co., Ltd." }, { 0x2432, "Ceton Corp." }, { 0x2433, "Asetek A/S" }, { 0x2434, "NOVA electronics, Inc." }, { 0x2435, "PAKSENSE, INC." }, { 0x2436, "MediTECH Electronic GmbH" }, { 0x2437, "NIKETECH ELECTRONICS GROUP LIMITED" }, { 0x2438, "Innopower Technology Corporation" }, { 0x2439, "Comex Electronics AB" }, { 0x243A, "Mobile Devices Ingenierie" }, { 0x243B, "OTAX Electronics (ShenZhen) Co., Ltd." }, { 0x243C, "DiZiC Co., Ltd." }, { 0x243D, "emz - Hanauer GmbH & Co KGaA" }, { 0x243E, "Savi Elettronica srl" }, { 0x243F, "Photonic GesmbH & Co. KG" }, { 0x2440, "RB GeneralEkonomik" }, { 0x2441, "TV One" }, { 0x2442, "University of Central Florida" }, { 0x2443, "Aessent Technology Ltd." }, { 0x2444, "NetModule AG" }, { 0x2445, "TOMY Company, Ltd." }, { 0x2446, "Avionics Interface Technologies" }, { 0x2447, "Knick Elektronische Messgerate GmbH & Co. KG" }, { 0x2448, "Winterhalter GmbH" }, { 0x2449, "SHAEFER GmbH" }, { 0x244A, "Onzo Ltd." }, { 0x244B, "Applied Technical Systems" }, { 0x244C, "MinebeaMitsumi Inc." }, { 0x244D, "Pantec Biosolutions AG" }, { 0x244E, "ShopGuard Ltd." }, { 0x244F, "iWall A/S" }, { 0x2450, "Boule Medical AB" }, { 0x2451, "AEM Performance Electronics" }, { 0x2452, "Speeder Electronics Co., Ltd." }, { 0x2453, "BAANTO" }, { 0x2454, "Velosti Technology Limited" }, { 0x2455, "Anton/Bauer, Inc." }, { 0x2456, "CKD NIKKI DENSO CO., LTD" }, { 0x2457, "Alcomp. Inc." }, { 0x2458, "Bluegiga Technologies Oy" }, { 0x2459, "Secure Holdings Limited" }, { 0x245A, "KONDOH SEISAKUSHO Co., Ltd." }, { 0x245B, "Zixsys Inc." }, { 0x245C, "Steinbauer Electronics GmbH" }, { 0x245D, "ID Technologies" }, { 0x245E, "LNT - Automation GmbH" }, { 0x245F, "Chord Electronics Limited" }, { 0x2460, "NELS, Ltd." }, { 0x2461, "Beam Communications" }, { 0x2462, "IDENTICA S.A." }, { 0x2463, "BAP Precision Ltd." }, { 0x2464, "Nestlabs" }, { 0x2465, "Microsoft Surface Hub" }, { 0x2466, "Fractal Audio Systems, LLC" }, { 0x2467, "Nektar Technology, Inc." }, { 0x2468, "New Cosmos Electric Co., Ltd." }, { 0x2469, "Gloria Music Corp." }, { 0x246A, "UNH Interoperability Laboratory" }, { 0x246B, "Perfect Fortune Electric Wire & Cable (ShenZhen) Co. Ltd." }, { 0x246C, "Shanghai Fudan Microelectronics Co., Ltd." }, { 0x246D, "TrackMan A/S" }, { 0x246E, "Movinto Fun AB" }, { 0x246F, "STORK PRINTS AUSTRIA GmbH" }, { 0x2470, "Hale Microsystems" }, { 0x2471, "Bloonn Srl" }, { 0x2472, "Bossa Nova Robotics, Inc." }, { 0x2473, "Trend Control Systems Limited" }, { 0x2474, "Stamps.com" }, { 0x2475, "JCM American Corporation" }, { 0x2476, "Yost Engineering Inc." }, { 0x2477, "UbiVelox" }, { 0x2478, "Sonix Technology (Shenzhen) Co., Ltd." }, { 0x2479, "smartek d.o.o." }, { 0x247A, "Suzhou Jutze Technologies Co., Ltd" }, { 0x247B, "Digibras Industria do Brasil S.A" }, { 0x247C, "Fullconn Industry Inc." }, { 0x247D, "JARGY CO. LTD." }, { 0x247E, "GEWA music GmbH" }, { 0x247F, "Lynx Studio Technology, Inc." }, { 0x2480, "Omniware Inc." }, { 0x2481, "Shenzhen SKY DRAGON Audio-Video Technology Co., Ltd." }, { 0x2482, "SmartRoom LLC" }, { 0x2483, "Valups Corp." }, { 0x2484, "Unipolar Optics-Electrical Technology Co., Ltd." }, { 0x2485, "Dream SAS" }, { 0x2486, "DCG Systems, Inc." }, { 0x2487, "SHANGHAI VEI SHENG AUTO PARTS MANUFACTURING CO., LTD." }, { 0x2488, "SuperD Co., Ltd." }, { 0x2489, "Irvine Sensors Corporation" }, { 0x248A, "TeLink Semiconductor (Shanghai) Co., Ltd." }, { 0x248B, "DONGGUAN SYNCONN PRECISION INDUSTRY CO. LTD." }, { 0x248C, "Avicenna Instruments, LLC" }, { 0x248D, "Digital Matter Pty Ltd." }, { 0x248E, "Pulsar Informatics, Inc." }, { 0x248F, "HMS Industrial Networks AB" }, { 0x2490, "Zealtek electronic Co. Ltd." }, { 0x2491, "OBSERVATOR instruments b.v." }, { 0x2492, "Mofiria Corporation" }, { 0x2493, "Sensolutions Inc." }, { 0x2494, "Invoxia" }, { 0x2495, "Summit Semiconductor LLC" }, { 0x2496, "Dongguan DaTang Industrial Investment Co., Ltd." }, { 0x2497, "HyunWoo Electronics Co., Ltd." }, { 0x2498, "Aurora SFC Systems, Inc." }, { 0x2499, "Governors America Corp." }, { 0x249A, "Anedio, LLC" }, { 0x249B, "Miller Electric Mfg. Co." }, { 0x249C, "M2TECH SRL" }, { 0x249D, "Ken-A-Vision Manufacturing Company, Inc." }, { 0x249E, "Tlab West Systems AB" }, { 0x249F, "ABC PCB Sarl" }, { 0x24A0, "VIMAR SPA" }, { 0x24A1, "AUTONICS Corporation" }, { 0x24A2, "SafeTech Ltd." }, { 0x24A3, "BioTillion, LLC" }, { 0x24A4, "Primare AB" }, { 0x24A5, "OWANDY" }, { 0x24A6, "Shenzhen Pangngai Industrial Co., Ltd." }, { 0x24A7, "PROMAX ELECTRONICA S.A." }, { 0x24A8, "Hermes electronic GmbH" }, { 0x24A9, "ASolid Technology Co., Ltd." }, { 0x24AA, "Wasatch Photonics" }, { 0x24AB, "IMERJ LTD." }, { 0x24AC, "ToMiTec GmbH" }, { 0x24AD, "embedded brains GmbH" }, { 0x24AE, "Shenzhen Rapoo Technology Co., Ltd." }, { 0x24AF, "Integrated Corporation" }, { 0x24B0, "Echometer Company" }, { 0x24B1, "SCR Engineers Ltd." }, { 0x24B2, "DelSys Inc." }, { 0x24B3, "Simbionix Ltd." }, { 0x24B4, "Leema Acoustics" }, { 0x24B5, "3C TEK CORP." }, { 0x24B6, "Shenzhen New-Conn International Co., Ltd." }, { 0x24B7, "Medical Equipment Europe GmbH" }, { 0x24B8, "DongGuan CJ TOUCH Electronic Co., Ltd." }, { 0x24B9, "Hoshin Electronics Co., Ltd." }, { 0x24BA, "PRADOTEC Corporation Sdn. Bhd." }, { 0x24BB, "SHANGHAI LIGHTSURFING INFORMATION TECHNOLOGY CO., LTD." }, { 0x24BC, "Sartorius AG" }, { 0x24BD, "Smart Solution" }, { 0x24BE, "Mutewatch AB" }, { 0x24BF, "NBS Payment Solutions, Inc." }, { 0x24C0, "Chaney Instrument Co." }, { 0x24C1, "Maction Technologies, Inc." }, { 0x24C2, "DiCon Fiberoptics, Inc." }, { 0x24C3, "Covaris, Inc." }, { 0x24C4, "CMITECH Co., Ltd." }, { 0x24C5, "HUINTECH" }, { 0x24C6, "Xbox 3rd Party Partners" }, { 0x24C7, "Laser Technology, Inc." }, { 0x24C8, "CHAPP INC." }, { 0x24C9, "Pilot Electronic (China) Ltd." }, { 0x24CA, "SMARTEH d.o.o." }, { 0x24CB, "Servotronix Motion Control Ltd." }, { 0x24CC, "JSB Tech Pte. Ltd." }, { 0x24CD, "Viking360.com LLC" }, { 0x24CE, "Shenzhen Deren Electronic Co., Ltd." }, { 0x24CF, "Lytro, Inc." }, { 0x24D0, "Smith Micro Software, Inc." }, { 0x24D1, "POS & Solution Company" }, { 0x24D2, "DADT Holdings, LLC" }, { 0x24D3, "Lexking Technology Co., Ltd." }, { 0x24D4, "KOMATSU ELECTRONIC CO., LTD." }, { 0x24D5, "SATEL Ltd." }, { 0x24D6, "Develer S.r.l." }, { 0x24D7, "ACORDE TECHNOLOGIES" }, { 0x24D8, "Pittway Tecnologica Srl" }, { 0x24D9, "Unfors Instruments AB" }, { 0x24DA, "KYOCERA ELCO Korea Co., Ltd." }, { 0x24DB, "DDUSB Technology" }, { 0x24DC, "Aladdin Software Security R.D." }, { 0x24DD, "Kingspan Environmental Ltd." }, { 0x24DE, "Navicron" }, { 0x24DF, "ALGO System. Co" }, { 0x24E0, "Yoctopuce Sarl" }, { 0x24E1, "Paratronic S.A." }, { 0x24E2, "Digital Information Technology Studies (Shenzhen) Ltd." }, { 0x24E3, "Beijing TianYu Communication Equipment Co., Ltd." }, { 0x24E4, "Bytec Group Limited" }, { 0x24E5, "Lanmark Controls Inc." }, { 0x24E6, "ACI Analytical Control Instruments GmbH" }, { 0x24E7, "maxon motor ag" }, { 0x24E8, "ivee" }, { 0x24E9, "Microelectronics Technology Inc." }, { 0x24EA, "ZEBEX INDUSTRIES INC." }, { 0x24EB, "SHENZHEN PCTX TECHNOLOGY DEVELOPMENT CO., LTD." }, { 0x24EC, "CE-Infosys GmbH" }, { 0x24ED, "ZEN FACTORY GROUP (ASIA) LTD." }, { 0x24EE, "A C S Co., Ltd." }, { 0x24EF, "DATONG PLC" }, { 0x24F0, "Das Keyboard - Metadot" }, { 0x24F1, "Silicon Communication Technology" }, { 0x24F2, "Secure Electrans LTD." }, { 0x24F3, "MartinLogan Ltd." }, { 0x24F4, "Mind Media BV" }, { 0x24F5, "QRS Diagnostic" }, { 0x24F6, "Aplix IP Holdings Corporation" }, { 0x24F7, "Seneye Ltd." }, { 0x24F8, "Bang & Olufsen A/S" }, { 0x24F9, "TOSHIBA MITSUBISHI-ELECTRIC INDUSTRIAL SYSTEMS CORP." }, { 0x24FA, "Vectronix AG" }, { 0x24FB, "GTECH Corporation" }, { 0x24FC, "GPEG International" }, { 0x24FD, "Nichiyu Giken Kogyo Co., Ltd." }, { 0x24FE, "GOMETRICS, S.L." }, { 0x24FF, "Acroname Inc." }, { 0x2500, "Ettus Research LLC" }, { 0x2501, "Bridge Publications, Inc." }, { 0x2502, "Canadian Automotive Instruments Ltd." }, { 0x2503, "Kurth Electronic GmbH" }, { 0x2504, "Nemic Lambda Ltd." }, { 0x2505, "Xiroku Accupoint Technology Inc." }, { 0x2506, "Hind Technology Group" }, { 0x2507, "Advion BioSystems" }, { 0x2508, "Symplex Communications, Inc." }, { 0x2509, "Chain-In Electronic Co., Ltd." }, { 0x250A, "H-Squared" }, { 0x250B, "Nautilus Lifeline Ltd." }, { 0x250C, "PHX Inc." }, { 0x250D, "Alstom Grid SAS" }, { 0x250E, "Beijing MOPS Technology Co., Ltd." }, { 0x250F, "itplants ltd." }, { 0x2510, "SE Elektronische Systeme" }, { 0x2511, "Morita Tech Co., Ltd." }, { 0x2512, "RNDPLUS Co., Ltd." }, { 0x2513, "RMI Laser, LLC" }, { 0x2514, "Fullpower Technologies" }, { 0x2515, "AMITEK" }, { 0x2516, "Cooler Master Co., Ltd." }, { 0x2517, "Marel EHF" }, { 0x2518, "Anite Telecoms Inc." }, { 0x2519, "n-gineric gmbh" }, { 0x251A, "Daiichi Electronics" }, { 0x251B, "Stable Imaging Solutions, LLC" }, { 0x251C, "snom technology AG" }, { 0x251D, "Fortebio Inc." }, { 0x251E, "Polara Engineering, Inc." }, { 0x251F, "Golden Emperor International Ltd." }, { 0x2520, "ANA-U GmbH" }, { 0x2521, "Fundacion Tekniker" }, { 0x2522, "Light Harmonic" }, { 0x2523, "Recon Instruments Inc." }, { 0x2524, "CVRx" }, { 0x2525, "Barron McCann Technology Ltd." }, { 0x2526, "Weide Electronics Co., Ltd." }, { 0x2527, "Software Bisque, Inc." }, { 0x2528, "BittWare Inc." }, { 0x2529, "SUZHOU XINYA ELECTRIC COMMUNICATION CO., LTD." }, { 0x252A, "SUZHOU KELI TECHNOLOGY DEVELOPMENT CO., LTD." }, { 0x252B, "TOP Exactitude Industry (ShenZhen) Co., Ltd." }, { 0x252C, "VIGO System S.A." }, { 0x252D, "Nokia Siemens Networks" }, { 0x252E, "Heliox Technologies, Inc." }, { 0x252F, "Pentronic AB" }, { 0x2530, "STT Emtec AB" }, { 0x2531, "Proteus Industries Inc." }, { 0x2532, "C.R.D.E. (Cahors Group)" }, { 0x2533, "Osaka Micro Computer, Inc." }, { 0x2534, "Russia's Institute of Radionavigation and Time" }, { 0x2535, "ShenZhen Hogend Precision Technology Co., Ltd." }, { 0x2536, "Ubisys Technology Co., Ltd." }, { 0x2537, "Norel Systems Ltd." }, { 0x2538, "Cochlear Ltd." }, { 0x2539, "Club Electronics" }, { 0x253A, "System Sacom Industry Corporation" }, { 0x253B, "RCF S.p.a." }, { 0x253C, "Tri-Tech Manufacturing Inc." }, { 0x253D, "Koss Corporation" }, { 0x253E, "Creative Product Design Pty., Ltd." }, { 0x253F, "ORANGE IT INC." }, { 0x2540, "Applied Materials" }, { 0x2541, "Shanghai AisinoChip Electronics Technology Co., Ltd." }, { 0x2542, "Ditron S.R.L." }, { 0x2543, "Spark Dental Technology Limited" }, { 0x2544, "Energy Micro AS" }, { 0x2545, "Digital Foci, Inc." }, { 0x2546, "Ravensburger Spieleverlag GmbH" }, { 0x2547, "YiDu Technology" }, { 0x2548, "Pulse-Eight Limited" }, { 0x2549, "Librestream Technologies" }, { 0x254A, "Enegate Co., Ltd." }, { 0x254B, "Toy Toy Toy Ltd." }, { 0x254C, "X6D Limited" }, { 0x254D, "ICAR VISION SYSTEMS S.L." }, { 0x254E, "SHF Communication Technologies AG" }, { 0x254F, "Jigeon Technologies Co., Ltd." }, { 0x2550, "Teledyne" }, { 0x2551, "A.E.B. Industriale S.r.l." }, { 0x2552, "Striiv, Inc." }, { 0x2553, "C8 MediSensor" }, { 0x2554, "ASSA ABLOY AB" }, { 0x2555, "Pulse Tracer, Inc." }, { 0x2556, "United Radio-Electronic Technologies Co., Ltd." }, { 0x2557, "Robatech AG" }, { 0x2558, "INTECH ELECTRONICS CORP." }, { 0x2559, "Jangus Music, Inc. (dba Wi Digital Systems)" }, { 0x255A, "TaiDoc Technology Corp." }, { 0x255B, "NDI Technologies, Inc." }, { 0x255C, "HOSIWELL TECHNOLOGY CO., LTD." }, { 0x255D, "ATEECS" }, { 0x255E, "Beijing Bonxeon Technology Co., Ltd." }, { 0x255F, "DORNIER-LTF GmbH" }, { 0x2560, "e-con Systems India Private Limited" }, { 0x2561, "Brookhaven Instruments Corp." }, { 0x2562, "SHENGZHEN MAYA ELECTRONICS CREATION CO. LTD." }, { 0x2563, "Shenzhen ShanWan Technology Co., Ltd." }, { 0x2564, "TESSERA TECHNOLOGY INC." }, { 0x2565, "Cyclone Industries Limited" }, { 0x2566, "Cryptera A/S" }, { 0x2567, "DongGuan LongTao Electronic Co., Ltd." }, { 0x2568, "ALL LINK CONN. TECHNOLOGY CORP." }, { 0x2569, "DongGuan City MingJi Electronics Co., Ltd." }, { 0x256A, "TAIAN TECHNOLOGY (WUXI) Co., Ltd." }, { 0x256B, "Perreaux Industries Ltd." }, { 0x256C, "GRAPHICS TECHNOLOGY (HK) CO., LIMITED" }, { 0x256D, "Compal Broadband Networks, Inc." }, { 0x256E, "Valuest Co., Ltd." }, { 0x256F, "3D CONNEXION SAM" }, { 0x2570, "AVID Technologies, Inc." }, { 0x2571, "CHIPMAST TECHNOLOGY CO., LTD." }, { 0x2572, "Vmarker" }, { 0x2573, "ESI Audiotechnik GmbH" }, { 0x2574, "AVer Information Inc." }, { 0x2575, "Weida Hi-Tech Co., Ltd." }, { 0x2576, "AFO Co., Ltd." }, { 0x2577, "LCDVF LLC" }, { 0x2578, "MPEC Technology Limited" }, { 0x2579, "Dongguan Wisechamp Electronic Co., Ltd." }, { 0x257A, "Shanghai Yuga Information Technology Co., Ltd." }, { 0x257B, "shenzhen dcard smart card tech. co., ltd." }, { 0x257C, "Richard Woehr GmbH" }, { 0x257D, "Panovel Technology Corporation" }, { 0x257E, "RFL Electronics Inc." }, { 0x257F, "8devices" }, { 0x2580, "DJ Techtools (Golden Sol Music LLC. Is Holding Co.)" }, { 0x2581, "Plug-up" }, { 0x2582, "Helmholz GmbH & Co. KG" }, { 0x2583, "VECTRUX DISTRIBUTORS LLC" }, { 0x2584, "COSMO CO., LTD." }, { 0x2585, "HomeChip Ltd." }, { 0x2586, "PLANET Technology Corporation" }, { 0x2587, "Ningbo Jiatang Electronic Co., Ltd." }, { 0x2588, "Infinitegra, Inc." }, { 0x2589, "Argon Technology Corporation" }, { 0x258A, "Sino Wealth Electronic Ltd." }, { 0x258B, "KORYO ELECTRONICS CO., LTD." }, { 0x258C, "Fastec Imaging Corporation" }, { 0x258D, "Sequans Communications" }, { 0x258E, "ENJsoft Co., Ltd." }, { 0x258F, "CME" }, { 0x2590, "MuChip Co., Ltd." }, { 0x2591, "Optimus Semiconductor Inc." }, { 0x2592, "Quest International" }, { 0x2593, "CELIZION, Inc." }, { 0x2594, "Acsys Technologies Ltd." }, { 0x2595, "SANYO DENKI CO., LTD." }, { 0x2596, "Twisted Melon Inc." }, { 0x2597, "Diagnostic Systems Associates Inc." }, { 0x2598, "Aerocrine" }, { 0x2599, "Q-tag AG" }, { 0x259A, "TriQuint Semiconductor" }, { 0x259B, "INUVIO" }, { 0x259C, "Immedia Semiconductor Inc." }, { 0x259D, "RCA DA AMAZONIA LTDA" }, { 0x259E, "American Messaging Services LLC" }, { 0x259F, "THERMO KING" }, { 0x25A0, "Ciegus Ltd." }, { 0x25A1, "Suitable Technologies, Inc." }, { 0x25A2, "LEMKE ENG." }, { 0x25A3, "Nanoteq (Pty) Ltd." }, { 0x25A4, "ALGOLTEK, INC." }, { 0x25A5, "Yakel Enterprises LLC" }, { 0x25A6, "AADI AS" }, { 0x25A7, "Beken Corporation" }, { 0x25A8, "Guangzhou Geoelectron Science & Technology Co., Ltd." }, { 0x25A9, "Advanced Bionics" }, { 0x25AA, "Top Victory Investments Ltd. (HK)" }, { 0x25AB, "Carmanah Signs" }, { 0x25AC, "PLIGG" }, { 0x25AD, "Aurora Networks, Inc." }, { 0x25AE, "OXIPULSE" }, { 0x25AF, "C&A Marketing" }, { 0x25B0, "Musical Fidelity" }, { 0x25B1, "Disc Soft Ltd." }, { 0x25B2, "DRS-RSTA, Inc." }, { 0x25B3, "DongGuan Elinke Industrial Co., Ltd." }, { 0x25B4, "Fairhaven Health" }, { 0x25B5, "FlatFrog Laboratories AB" }, { 0x25B6, "Fructel AB" }, { 0x25B7, "Neomitic Technologies S.A. de C.V." }, { 0x25B8, "Neutronics Inc." }, { 0x25B9, "Nujira Ltd." }, { 0x25BA, "WITec Wissenschaftliche Instrumente & Technologie GmbH" }, { 0x25BB, "Brunner Elektronik AG" }, { 0x25BC, "CETRTA POT" }, { 0x25BD, "TECHEYE SYSTEMS INC." }, { 0x25BE, "Infinite Z" }, { 0x25BF, "Elegant Invention" }, { 0x25C0, "Beyond Music Industrial Co., Ltd." }, { 0x25C1, "Vaddio" }, { 0x25C2, "Smith + Nephew Inc." }, { 0x25C3, "Phorus" }, { 0x25C4, "A & R Cambridge Ltd." }, { 0x25C5, "Securetec Detektions Systeme AG" }, { 0x25C6, "AVA Group A/S" }, { 0x25C7, "MEGATRON Elektronik AG & Co." }, { 0x25C8, "Visualplanet Ltd." }, { 0x25C9, "Proximiant" }, { 0x25CA, "Hovding Sverige AB" }, { 0x25CB, "ELZET80 Mikrocomputer Giesler & Danne GmbH & Co. KG" }, { 0x25CC, "NKC Co., Ltd." }, { 0x25CD, "Edwards Ltd." }, { 0x25CE, "MYTEK DIGITAL" }, { 0x25CF, "Corning Optical Communications LLC" }, { 0x25D0, "AeVee Laboratories LLC" }, { 0x25D1, "TOKAI-DENSHI Inc." }, { 0x25D2, "MRA Tek LLC" }, { 0x25D3, "Zhe Jiang Huasheng Technology Co., Ltd." }, { 0x25D4, "LOOPCOMM TECHNOLOGY, INC." }, { 0x25D5, "DATATON AB" }, { 0x25D6, "KOUZIRO Co., Ltd." }, { 0x25D7, "Audiomatica srl" }, { 0x25D8, "Serious Integrated, Inc." }, { 0x25D9, "Monarch Innovative Technologies Pvt. Ltd." }, { 0x25DA, "NETATMO" }, { 0x25DB, "Merrick Industries, Inc." }, { 0x25DC, "Cobolt AB" }, { 0x25DD, "bit4id srl" }, { 0x25DE, "Gasmet Technologies OY" }, { 0x25DF, "TTE Systems Ltd." }, { 0x25E0, "MULTIPLEX Modellsport GmbH & Co. KG" }, { 0x25E1, "Daimler AG" }, { 0x25E2, "Domain Surgical" }, { 0x25E3, "SCI Innovations Ltd." }, { 0x25E4, "AnaJet" }, { 0x25E5, "ALLFLEX EUROPE" }, { 0x25E6, "Digital Drilling Data Systems, LLC" }, { 0x25E7, "EIFELWERK Butler Systeme GmbH" }, { 0x25E8, "ATOLL Electronique" }, { 0x25E9, "Leybold Vacuum" }, { 0x25EA, "Aeroflex Weinschel" }, { 0x25EB, "Medical Intubation Technology Corp." }, { 0x25EC, "VELUX A/S" }, { 0x25ED, "Logic PD" }, { 0x25EE, "Mimoco" }, { 0x25EF, "BLITZ Co., Ltd." }, { 0x25F0, "GOODBETTERBEST Ltd." }, { 0x25F1, "Eden Innovations" }, { 0x25F2, "Dongguan Jinyue Electronics Co., Ltd." }, { 0x25F3, "Kicker" }, { 0x25F4, "ADVANSEE" }, { 0x25F5, "Lucas Holding bv" }, { 0x25F6, "SaferZone Co., Ltd." }, { 0x25F7, "Engineea Remote Technologies S.L." }, { 0x25F8, "Keypair Co., Ltd." }, { 0x25F9, "Donbass Soft Ltd. & Co. KG" }, { 0x25FA, "SoftEther Corporation" }, { 0x25FB, "RICOH IMAGING COMPANY, LTD." }, { 0x25FC, "RWA (Hong Kong) Limited" }, { 0x25FD, "Neuromonics Inc." }, { 0x25FE, "Providence Enterprise Limited" }, { 0x25FF, "Watermark Medical, Inc." }, { 0x2600, "SMARTCORE Inc." }, { 0x2601, "OFI Testing Equipment, Inc." }, { 0x2602, "Magenta Research Ltd." }, { 0x2603, "Swyx Solutions AG" }, { 0x2604, "Shenzhen Tenda Technology, Ltd." }, { 0x2605, "OSRAM SYLVANIA" }, { 0x2606, "O-Network Engineering AB" }, { 0x2607, "Prox Dynamics AS" }, { 0x2608, "OLHO tronic GmbH" }, { 0x2609, "FICOSA" }, { 0x260A, "SPEMOT AG" }, { 0x260B, "Schneider Electric Canada Inc. - Division of PCT" }, { 0x260C, "Saiko Systems Ltd." }, { 0x260D, "DongGuan Togran Electronic Co., Ltd." }, { 0x260E, "DongGuan HYX Industrial Co., Ltd." }, { 0x260F, "VITY" }, { 0x2610, "Egan Teamboard Inc." }, { 0x2611, "I.C.E. Co., Ltd." }, { 0x2612, "Crave Innovations" }, { 0x2613, "Gerd Bar GmbH" }, { 0x2614, "VMC Consulting Corporation" }, { 0x2615, "Gammaflux L.P." }, { 0x2616, "PS Audio" }, { 0x2617, "Front-End Technology, Inc." }, { 0x2618, "MicroGate Systems Ltd." }, { 0x2619, "Advanced Silicon SA" }, { 0x261A, "Shandong Synthesis Electronic Technology Co., Ltd." }, { 0x261B, "INTELLIGENT ENERGY, LTD." }, { 0x261C, "EISST Limited" }, { 0x261D, "Arkham Technology" }, { 0x261E, "IFAM GmbH Erfurt" }, { 0x261F, "Cooper Industries" }, { 0x2620, "SUE unicon.uz Scientific, Engineering & Marketing RC" }, { 0x2621, "CLIXUP LLC" }, { 0x2622, "IAG Group Limited" }, { 0x2623, "SGR Audio Pty Ltd." }, { 0x2624, "L-3 Communications - Communications Systems West" }, { 0x2625, "MilDef AB" }, { 0x2626, "Aruba Networks" }, { 0x2627, "Vectron Systems AG" }, { 0x2628, "TEN-TEC, INC." }, { 0x2629, "Winstars Technology Limited" }, { 0x262A, "SAVITECH CORP." }, { 0x262B, "YTOP Electronics Technical (Kunshan) Co., Ltd." }, { 0x262C, "Scannx" }, { 0x262D, "Fujian Witsi Microelectronics Technology Co., Ltd." }, { 0x262E, "UNITEX Corporation" }, { 0x262F, "MELAG Medizintechnik oHG" }, { 0x2630, "ifm electronic gmbh" }, { 0x2631, "NEOPROT TECNOLOGIA EM INFORMATICA LTDA." }, { 0x2632, "ENSPERT Inc." }, { 0x2633, "Inno Audio & Video (HK) Limited" }, { 0x2634, "E.M.S. S.R.L." }, { 0x2635, "uHDevice Technology Ltd." }, { 0x2636, "MED-EL Medical Electronics" }, { 0x2637, "TAEWOONG MEDICAL. CO., LTD." }, { 0x2638, "Becker-Antriebe GmbH" }, { 0x2639, "Xsens Technologies B.V." }, { 0x263A, "Maury Microwave" }, { 0x263B, "Time & Data Systems International Ltd." }, { 0x263C, "Schultes Microcomputer-Vertriebs-GmbH & Co KG" }, { 0x263D, "pls Programmierbare Logik & Systeme GmbH" }, { 0x263E, "Odin TeleSystems Inc." }, { 0x263F, "ES-Experts, Ltd." }, { 0x2640, "Banner Engineering" }, { 0x2641, "PRO TUNE ELECTRONIC SYSTEMS" }, { 0x2642, "NPP ELIKS America Inc. DBA T&M Atlantic" }, { 0x2643, "COMVOX AUDIO CO., LTD." }, { 0x2644, "Sioux Electronics B.V." }, { 0x2645, "Lead Data Inc." }, { 0x2646, "Bel Canto Design, Ltd." }, { 0x2647, "FORMER ENGINEERING SERVICE CO., LTD." }, { 0x2648, "Telongo LLC" }, { 0x2649, "Soundspring Audio, Inc" }, { 0x264A, "THERMALTAKE Technology Co., Ltd." }, { 0x264B, "Industrial Indexing Systems" }, { 0x264C, "Si14 SpA" }, { 0x264D, "Wolfrum Elektronik & Avionik" }, { 0x264E, "3i Corporation" }, { 0x264F, "RF Controls, LLC" }, { 0x2650, "Electronics For Imaging, Inc." }, { 0x2651, "Otis Instruments Inc." }, { 0x2652, "Fallbrook Technologies, Inc." }, { 0x2653, "AutoHotBox" }, { 0x2654, "DarklingX, LLC" }, { 0x2655, "Moog Inc." }, { 0x2656, "Ashcroft Inc." }, { 0x2657, "Embedia Technologies Corporation" }, { 0x2658, "Sintermask GmbH" }, { 0x2659, "Sundtek" }, { 0x265A, "3Brain GmbH" }, { 0x265B, "D-tect Systems" }, { 0x265C, "IDEX Health + Science LLC" }, { 0x265D, "H. Schomaecker GmbH" }, { 0x265E, "JSC Engineering Centre Energoservice" }, { 0x265F, "Azatrax" }, { 0x2660, "YEONG DER (SUM-EM) Enterprises Co., Ltd." }, { 0x2661, "WorldCast Systems" }, { 0x2662, "MOOG Music Inc." }, { 0x2663, "JOMESA Messsysteme GmbH" }, { 0x2664, "NOHMI BOSAI Ltd." }, { 0x2665, "Yamaki Electric Corporation" }, { 0x2666, "BLX IC Design Corp., Ltd." }, { 0x2667, "SuZhou ZhongXingLian Precision Industrial Co., Ltd." }, { 0x2668, "Shenzhen Yuwenfa Electronic Technology Co., Ltd." }, { 0x2669, "ME4SURE, Inc." }, { 0x266A, "Linear LLC" }, { 0x266B, "ProSys Development Services" }, { 0x266C, "Brightsight BV" }, { 0x266D, "Ergotest Innovation A.S." }, { 0x266E, "Multimedia Link, Inc." }, { 0x266F, "Shanghai Zhengyuan Technologies Co., Ltd." }, { 0x2670, "Zhengzhou Xin Da Jie An Information Technology Co., Ltd" }, { 0x2671, "Innovative Logic" }, { 0x2672, "GoPro" }, { 0x2673, "Wadia Digital" }, { 0x2674, "Hoyt Monitor Technologies, LLC" }, { 0x2675, "Peter Huber Kaeltemaschinenbau GmbH" }, { 0x2676, "Basler AG" }, { 0x2677, "Winegard Company" }, { 0x2678, "Sky Deutschland GmbH & Co. KG" }, { 0x2679, "BESTMEDIA CD-Recordable GmbH & Co. KG" }, { 0x267A, "Xi'an YEP Telecommunication Technology Co., Ltd." }, { 0x267B, "Palpilot International Corp." }, { 0x267C, "OptiGene Limited" }, { 0x267D, "KOHZU Precision Co., Ltd." }, { 0x267E, "E.D. Bullard Company" }, { 0x267F, "Acromag Inc." }, { 0x2680, "DIGICO UK Limited" }, { 0x2681, "MYLAPS B.V." }, { 0x2682, "ROBOX S.P.A." }, { 0x2683, "Gazogiken Co., Ltd." }, { 0x2684, "Funkwerk Security Communications GmbH" }, { 0x2685, "Cardo Systems Inc." }, { 0x2686, "IP LABS Inc." }, { 0x2687, "FITBIT" }, { 0x2688, "Stratasys Inc." }, { 0x2689, "StepOver Inc." }, { 0x268A, "QEES" }, { 0x268B, "Dimension Engineering LLC" }, { 0x268C, "AMS-TAOS" }, { 0x268D, "WEISS ENGINEERING LTD." }, { 0x268E, "xyzmo Software GmbH" }, { 0x268F, "LETech Co., Ltd." }, { 0x2690, "K.K. Rabbit" }, { 0x2691, "ZINK Imaging, Inc." }, { 0x2692, "CELLIENT CO., LTD." }, { 0x2693, "Silvershore Technology Partners" }, { 0x2694, "RoboteX Inc." }, { 0x2695, "DynaGen Technologies Inc." }, { 0x2696, "Sensovation AG" }, { 0x2697, "Anfatec Instruments" }, { 0x2698, "EVTD Inc." }, { 0x2699, "ECOUS Corp." }, { 0x269A, "BETTER MANAGE INVESTMENTS LIMITED" }, { 0x269B, "Novel Data Solutions (Suzhou) Corporation" }, { 0x269C, "ECTRON CORPORATION" }, { 0x269D, "Accessible Technologies, Inc." }, { 0x269E, "Astro Gaming" }, { 0x269F, "DKL TECHNOLOGY (SHENZHEN) CO., LTD." }, { 0x26A0, "MIDAS" }, { 0x26A1, "Miris AB" }, { 0x26A2, "Eppendorf AG" }, { 0x26A3, "EMKO ELEKTRONIK SAN. VE TIC. AS" }, { 0x26A4, "Blue Goji" }, { 0x26A5, "CAL TEST ELECTRONICS, INC." }, { 0x26A6, "Radio Design Group, Inc." }, { 0x26A7, "LOG-IN, Inc." }, { 0x26A8, "UNIREX CORPORATION" }, { 0x26A9, "Research Industrial Systems IT-Engineering (RISE) GmbH" }, { 0x26AA, "YAESU MUSEN CO., LTD." }, { 0x26AB, "Motion Control Systems, Inc." }, { 0x26AC, "3D Robotics Inc." }, { 0x26AD, "Global Distribution GmbH" }, { 0x26AE, "Oscium" }, { 0x26AF, "Bombardier Transportation GmbH, TCMS Development Ctr 2" }, { 0x26B0, "Zhejiang Senda Electronics Co., Ltd." }, { 0x26B1, "Bassett Electronic Systems Limited" }, { 0x26B2, "RST Instruments Ltd." }, { 0x26B3, "Global Inkjet Systems" }, { 0x26B4, "Sensor Technology Limited" }, { 0x26B5, "ELECTROCOMPANIET AS" }, { 0x26B6, "Pacom Systems Pty. Ltd." }, { 0x26B7, "Azusatekuno" }, { 0x26B8, "InkControl, LLC" }, { 0x26B9, "Satlantic LP" }, { 0x26BA, "Freetronics Pty Ltd." }, { 0x26BB, "Omega Elektronik Sanayi ve Ticaret A.S." }, { 0x26BC, "CARDIN ELETTRONICA S.p.A." }, { 0x26BD, "Integral Memory Plc." }, { 0x26BE, "AKASA (ASIA) CORP." }, { 0x26BF, "Broadway System, Inc." }, { 0x26C0, "RADIODETECTION LTD." }, { 0x26C1, "Viola Audio Laboratories" }, { 0x26C2, "FUTURE UNIVERSITY HAKODATE" }, { 0x26C3, "HARLEY-DAVIDSON MOTOR COMPANY" }, { 0x26C4, "Logic Way GmbH" }, { 0x26C5, "TOKAI RUBBER INDUSTRIES, LTD." }, { 0x26C6, "GRAF-SYTECO GmbH & Co. KG" }, { 0x26C7, "Beijing Stone New Technology Industry Co., Ltd." }, { 0x26C8, "SCHMID mme - electronic product engineering" }, { 0x26C9, "SPM INSTRUMENT AB" }, { 0x26CA, "MSY Inc." }, { 0x26CB, "Sung Kyung Precision Co., Ltd." }, { 0x26CC, "Hunting Titan" }, { 0x26CD, "Blendology Limited" }, { 0x26CE, "ASRock Inc." }, { 0x26CF, "The Gate Technologies" }, { 0x26D0, "ZK Celltest, Inc." }, { 0x26D1, "THORLABS LTD." }, { 0x26D2, "Jiangsu Yinhe Electronics Co., Ltd." }, { 0x26D3, "VIBRATION INSTRUMENTS CO., LTD." }, { 0x26D4, "Truesense Imaging" }, { 0x26D5, "Equinox Payments, LLC" }, { 0x26D6, "Sistemi Elettronici Di Addonizio Luisa" }, { 0x26D7, "POPSPA (HK) LTD." }, { 0x26D8, "APR, LLC" }, { 0x26D9, "ATC-NY" }, { 0x26DA, "Dabi Atlante" }, { 0x26DB, "American DJ Supply" }, { 0x26DC, "Gato Audio" }, { 0x26DD, "Monnit Corp." }, { 0x26DE, "Velocity Micro, Inc." }, { 0x26DF, "University of Cambridge" }, { 0x26E0, "Shenzhen Shixin Digital Co., Ltd." }, { 0x26E1, "CrucialTec Co., Ltd." }, { 0x26E2, "Ingenieurbuero Dietzsch und Thiele PartG" }, { 0x26E3, "SHENZHEN EXCEL DIGITAL TECHNOLOGY CO., LTD." }, { 0x26E4, "VIZIO, Inc." }, { 0x26E5, "Shaghal Ltd." }, { 0x26E6, "ORC Manufacturing Co., Ltd." }, { 0x26E7, "Fishman" }, { 0x26E8, "Camgian Microsystems" }, { 0x26E9, "Lumenergi Inc." }, { 0x26EA, "OPTOVUE INC." }, { 0x26EB, "emtrion GmbH" }, { 0x26EC, "SLE quality engineering GmbH & Co. KG" }, { 0x26ED, "a.tron3d GmbH" }, { 0x26EE, "Grimm Audio" }, { 0x26EF, "TAKEBISHI CORPORATION" }, { 0x26F0, "EDM Corporation" }, { 0x26F1, "Fujian LANDI Commercial Equipment Co., Ltd." }, { 0x26F2, "AUDIS SARL" }, { 0x26F3, "Raven Systems Design, Inc." }, { 0x26F4, "RTW GmbH & Co. KG" }, { 0x26F5, "Morning Star Digital Connector Co., Ltd." }, { 0x26F6, "Sea-Bird Electronics" }, { 0x26F7, "BFFT GmbH" }, { 0x26F8, "Salon Transcripts, Inc." }, { 0x26F9, "Outstanding Technology Co., Ltd." }, { 0x26FA, "DAQ SYSTEM Co., Ltd." }, { 0x26FB, "FLIR Advanced Imaging Systems" }, { 0x26FC, "Raven Industries" }, { 0x26FD, "Foot Levelers, Inc." }, { 0x26FE, "ESPROS Photonics AG" }, { 0x26FF, "MIA Corporation" }, { 0x2700, "MITACHI CO., LTD." }, { 0x2701, "Pro Design Electronic GmbH" }, { 0x2702, "Hobart GmbH" }, { 0x2703, "Greenwave Reality Pte. Ltd." }, { 0x2704, "Unisun Innovation Incorporated" }, { 0x2705, "CardioGrip Corporation" }, { 0x2706, "iKey, Ltd." }, { 0x2707, "Bardac Corporation" }, { 0x2708, "Audient Limited" }, { 0x2709, "ZEON CORPORATION" }, { 0x270A, "Channel Islands Audio" }, { 0x270B, "MSHeli Srl" }, { 0x270C, "Inhon Computer Co., Ltd." }, { 0x270D, "ROSAND Technologies" }, { 0x270E, "Applied Security Inc." }, { 0x270F, "Western Digital, HGST" }, { 0x2710, "Kontron America, Inc." }, { 0x2711, "ASD Inc." }, { 0x2712, "US Army Benet Laboratories" }, { 0x2713, "Datalink Electronics Ltd." }, { 0x2714, "i'm S.p.A." }, { 0x2715, "Photron Limited" }, { 0x2716, "YUEN DA ELECTRONIC PRODUCTS FACTORY" }, { 0x2717, "Xiaomi Communications Co., Ltd." }, { 0x2718, "Tamaggo" }, { 0x2719, "4iiii Innovations Inc." }, { 0x271A, "KONE Industrial Ltd." }, { 0x271B, "Tec.to" }, { 0x271C, "KDDI Technology Corporation" }, { 0x271D, "Gionee Communication Equipment Co., Ltd. ShenZhen" }, { 0x271E, "Changzhou Traful Electronic Co., Ltd." }, { 0x271F, "Shanghai Nufront Electronic Technology Co., Ltd." }, { 0x2720, "motrona GmbH" }, { 0x2721, "Germaneers GmbH" }, { 0x2722, "TRANIT" }, { 0x2723, "KUK Electronic AG" }, { 0x2724, "XS Technology, Inc." }, { 0x2725, "L-3 Applied Signal & Image Technology" }, { 0x2726, "Universal Electronics Inc. (dba: TVIEW)" }, { 0x2727, "ANM OPTO LIMITED" }, { 0x2728, "STX-Med SPRL" }, { 0x2729, "Regenersis (Glenrothes) Ltd." }, { 0x272A, "StarLeaf Limited" }, { 0x272B, "VAT Vakuumventile AG" }, { 0x272C, "IAR Systems" }, { 0x272D, "AKAR GAME LTD." }, { 0x272E, "Teratronik elektronische Systeme GmbH" }, { 0x272F, "tommis gmbh, Ingenieurburo f. Nachrichtentechnik u. Aut" }, { 0x2730, "Camozzi spa" }, { 0x2731, "Pebble Audio Oy" }, { 0x2732, "Samsung Medison Co., Ltd." }, { 0x2733, "ShenZhen SunSonny Electronic Technology Co., Ltd." }, { 0x2734, "Wuhan XinAn LuoJia Technologies Co., Ltd." }, { 0x2735, "Wilk Elektronik S.A." }, { 0x2736, "Silver Palm Technologies LLC" }, { 0x2737, "Blu Controls" }, { 0x2738, "Bad Rabby Designs" }, { 0x2739, "BluePacket Communications Co., Ltd." }, { 0x273A, "Singular Technology Co., Ltd." }, { 0x273B, "TecScan Systems Inc." }, { 0x273C, "Etherstack Limited" }, { 0x273D, "Thrimona Corporation" }, { 0x273E, "LIFODAS" }, { 0x273F, "Hughski Limited" }, { 0x2740, "Apparent Corporation" }, { 0x2741, "N2 Imaging Systems" }, { 0x2742, "Organ Recovery Systems, Inc." }, { 0x2743, "XS Embedded GmbH" }, { 0x2744, "RIKEN KEIKI NARA MFG. Co., Ltd." }, { 0x2745, "Unitech Electronics Co., Ltd." }, { 0x2746, "Shenzhen YishunTai Metal Factory" }, { 0x2747, "AHA INC. Co., Ltd." }, { 0x2748, "Stresstech Oy" }, { 0x2749, "GMV SISTEMAS" }, { 0x274A, "Qdac Inc." }, { 0x274B, "Automotive Data Solutions, Inc." }, { 0x274C, "Atos Worldline" }, { 0x274D, "FXI Technologies AS" }, { 0x274E, "VECTRONIC Aerospace GmbH" }, { 0x274F, "Dacuda AG" }, { 0x2750, "SafeLine Sweden AB" }, { 0x2751, "AMI International, Inc." }, { 0x2752, "miniDSP Ltd." }, { 0x2753, "Danville Signal Processing, Inc." }, { 0x2754, "Trapeze Software Group, Inc." }, { 0x2755, "Cosmic Circuits Pvt. Ltd." }, { 0x2756, "Victor Hasselblad AB" }, { 0x2757, "HiteVision Digital Media Technology Co., Ltd." }, { 0x2758, "MobileEco Co., Ltd." }, { 0x2759, "Philip Morris Products S.A." }, { 0x275A, "Vertex Aquaristik GmbH" }, { 0x275B, "PROPACK" }, { 0x275C, "NITA, LLC" }, { 0x275D, "NewSoc Tech Limited" }, { 0x275E, "Scent Sciences Corporation" }, { 0x275F, "Vishay Measurements Group, Inc." }, { 0x2760, "Oxigraf, Inc." }, { 0x2761, "CAST Navigation LLC" }, { 0x2762, "FERMAX ELECTRONICA S.A.U." }, { 0x2763, "PRIMES GmbH" }, { 0x2764, "Ouman Oy" }, { 0x2765, "Firstbeat Technologies Ltd." }, { 0x2766, "LifeScan" }, { 0x2767, "Cheetah Hi-Tech, Inc." }, { 0x2768, "DongGuan City Lian Zhi Electronic Technology Co. Ltd." }, { 0x2769, "SPI ENGINEERING Co., Ltd." }, { 0x276A, "SUGIYAMA ELECTRIC SYSTEM INC." }, { 0x276B, "CTI INFORMATION CENTER CO., LTD." }, { 0x276C, "PROTEI" }, { 0x276D, "YSTEK Technology Company" }, { 0x276E, "RGB Lasersysteme GmbH" }, { 0x276F, "Lightware Visual Engineering" }, { 0x2771, "TTE Corporation" }, { 0x2772, "Audio Tuning Vertriebs GmbH" }, { 0x2773, "HILTI AG" }, { 0x2774, "Novasina AG" }, { 0x2775, "Sonardyne International Ltd." }, { 0x2776, "KFI Trading s.r.l." }, { 0x2777, "SingTrix LLC" }, { 0x2778, "Cypher Labs LLC" }, { 0x2779, "Qualnetics Corporation" }, { 0x277A, "Occipital, Inc." }, { 0x277B, "Moxtek, Inc" }, { 0x277C, "SignalCore, Inc." }, { 0x277D, "Microcom Corporation" }, { 0x277E, "Sportable Scoreboards, Inc." }, { 0x277F, "DongGuan City Shangjie Electronic Co., Ltd." }, { 0x2780, "M31 Technology Corp." }, { 0x2781, "Liteconn Co., Ltd." }, { 0x2782, "TTS Inc." }, { 0x2783, "Aktina Medical Corp." }, { 0x2784, "A-One Co., Ltd." }, { 0x2785, "Mayekawa Mfg. Co., Ltd." }, { 0x2786, "Switch Science, Incorporation" }, { 0x2787, "AVTECH Corporation" }, { 0x2788, "Sanwin (HK) Electronic Technology Co., Ltd." }, { 0x2789, "Suzhou WEIJU Electronics Technology Co., Ltd." }, { 0x278A, "MARSHAL Corporation" }, { 0x278B, "The Rotel Co., Ltd." }, { 0x278C, "NAGATA ELECTRIC CO., LTD." }, { 0x278D, "GPSports Systems Pty., Ltd." }, { 0x278E, "TSS AB" }, { 0x278F, "Bosch Sicherheitssysteme Engineering GmbH" }, { 0x2790, "Cobalt Digital, Inc." }, { 0x2791, "SunTech Medical, Inc." }, { 0x2792, "SYSTEC Co., Limited" }, { 0x2793, "i-KAIST" }, { 0x2794, "SilverPlus, Inc." }, { 0x2795, "QuantaScope Biotech" }, { 0x2796, "Zhejiang Wellcom Technology Co., Ltd." }, { 0x2797, "EUROIMMUN AG" }, { 0x2798, "Turning Technologies" }, { 0x2799, "Colorimetry Research, Inc." }, { 0x279A, "Naim Audio Limited" }, { 0x279B, "Bluefish Technologies Pty Ltd." }, { 0x279C, "Advanced Anaesthesia Specialists" }, { 0x279D, "Towa Electronics Co., Ltd." }, { 0x279E, "Syntronix Corporation" }, { 0x279F, "Hiragawa Electronics Industry Co., Ltd." }, { 0x27A0, "Mondokey Limited" }, { 0x27A1, "Autoliv Romania S.R.L." }, { 0x27A2, "T.I.T. ENG CO., LTD." }, { 0x27A3, "AU Optronics Corporation" }, { 0x27A4, "Digital Act Inc." }, { 0x27A5, "Advantest Corporation" }, { 0x27A6, "iRobot Corporation" }, { 0x27A7, "Delta Computer Systems, Inc." }, { 0x27A8, "Square Inc." }, { 0x27A9, "Global Mixed-mode Technology Inc." }, { 0x27AA, "Just Connector Kunshan Co., Ltd." }, { 0x27AB, "Shenzhen Maxmade Technology Co., Ltd." }, { 0x27AC, "GP Electronics (HK) Limited" }, { 0x27AD, "PAUL HARTMANN AG" }, { 0x27AE, "TeleOrbit GmbH" }, { 0x27AF, "HANNA Instruments, Inc." }, { 0x27B0, "FOXPRO Inc." }, { 0x27B1, "UltiMachine" }, { 0x27B2, "OrthoAccel Technologies, Inc." }, { 0x27B3, "Secure Systems Limited" }, { 0x27B4, "Duerkopp Adler AG" }, { 0x27B5, "J-MEX Inc." }, { 0x27B6, "TechnoKom Ltd." }, { 0x27B7, "Fraunhofer IMS" }, { 0x27B8, "ThingM Corporation" }, { 0x27B9, "Ziotech Corp" }, { 0x27BA, "Aoptix Technologies, Inc." }, { 0x27BB, "Plenom A/S" }, { 0x27BC, "KeyView" }, { 0x27BD, "Codethink Limited" }, { 0x27BE, "InHand Electronics, Inc." }, { 0x27BF, "Dongguan CPO Electronic Co., Ltd." }, { 0x27C0, "Cadwell Laboratories, Inc." }, { 0x27C1, "ARKAMI" }, { 0x27C2, "ArcBotics LLC" }, { 0x27C3, "Danfoss Turbocor Compressors Inc." }, { 0x27C4, "KRYPTUS" }, { 0x27C5, "SRT Marine Technology Limited" }, { 0x27C6, "Shenzhen Huiding Technology Co. Ltd." }, { 0x27C7, "TransluSense, LLC" }, { 0x27C8, "Rigaku Corporation" }, { 0x27C9, "ElaraTek LTD." }, { 0x27CA, "JayBird LLC" }, { 0x27CB, "ANXA Limited Hong Kong" }, { 0x27CC, "GHL Matthias Gross GmbH & Co. KG" }, { 0x27CD, "GHEO SA" }, { 0x27CE, "Double Power Technology Inc." }, { 0x27CF, "Weidmueller Interface GmbH & Co. KG" }, { 0x27D0, "Traxon Technologies Europe GmbH" }, { 0x27D1, "Angelbird Technologies GmbH" }, { 0x27D2, "EURONOVATE SA" }, { 0x27D3, "PRECIA MOLEN" }, { 0x27D4, "Blackstar Amplification Ltd." }, { 0x27D5, "BSkyB LTD." }, { 0x27D6, "T3 Innovation" }, { 0x27D7, "Senova Systems, Inc." }, { 0x27D8, "Patriot Memory" }, { 0x27D9, "Gallagher Group Limited" }, { 0x27DA, "S Net Media Inc." }, { 0x27DB, "Hiitop Technology Limited" }, { 0x27DC, "Tennant Company" }, { 0x27DD, "Shenzhen MinDe Electronics Technology Ltd." }, { 0x27DE, "Newtec Cy" }, { 0x27DF, "Charles Novacroft Direct Limited" }, { 0x27E0, "Stelulu Technology" }, { 0x27E1, "TRX Systems, Inc." }, { 0x27E2, "Natus Medical Incorproated" }, { 0x27E3, "Chemyx Inc." }, { 0x27E4, "Easybotics LLC" }, { 0x27E5, "Shiroshita Industrial Co., Ltd." }, { 0x27E6, "SENECA srl" }, { 0x27E7, "AVIWEST" }, { 0x27E8, "takwak GmbH" }, { 0x27E9, "Soeks Limited" }, { 0x27EA, "Goldmund International" }, { 0x27EB, "ACCUCOMM, INC." }, { 0x27EC, "SEETECH CO., LTD." }, { 0x27ED, "Tescom-Emerson Process Management" }, { 0x27EE, "DashLogic Inc." }, { 0x27EF, "TAIYO SEIKI CO., LTD." }, { 0x27F0, "DITECT Corporation" }, { 0x27F1, "VERTU Corporation Limited" }, { 0x27F2, "Softnautics Private Limited" }, { 0x27F3, "Indutherm Erwaermungsanlagen GmbH" }, { 0x27F4, "LEGIC Identsystems Ltd." }, { 0x27F5, "Relume Technologies, Inc." }, { 0x27F6, "Advanced Simulation Technology Inc." }, { 0x27F7, "Wyred 4 Sound" }, { 0x27F8, "Wikipad, Inc." }, { 0x27F9, "MIDAS Elektronik GmbH" }, { 0x27FA, "Afag Automation AG" }, { 0x27FB, "Barclays" }, { 0x27FC, "CAREL SPA" }, { 0x27FD, "GI Therapies Pty Ltd." }, { 0x27FE, "DONGGUAN Rakecorp Co., Ltd." }, { 0x27FF, "Cashway Technology Co., Ltd." }, { 0x2800, "iluminage, Inc." }, { 0x2801, "Pear Sports LLC" }, { 0x2802, "Moixa Technology" }, { 0x2803, "StarLine LLC" }, { 0x2804, "4MOD Technology" }, { 0x2805, "Shenzhen N-Pass Mobile Technology, Ltd." }, { 0x2806, "RF DataTech" }, { 0x2807, "Elliptic Laboratories AS" }, { 0x2808, "FocalTech Systems, Ltd." }, { 0x2809, "Sept Co., Ltd." }, { 0x280A, "Culti Co., Ltd." }, { 0x280B, "Dukane Corporation" }, { 0x280C, "Linera" }, { 0x280D, "Ai Electronic Industry Co., Ltd." }, { 0x280E, "Leaf Imaging Ltd." }, { 0x280F, "MBit Wireless, Inc." }, { 0x2810, "Aphex, LLC" }, { 0x2811, "DigiTalks INC." }, { 0x2812, "Bridge Semiconductor Corp." }, { 0x2813, "Brookfield Engineering Laboratories Inc." }, { 0x2814, "OOO SMS-Soft" }, { 0x2815, "KING TSUSHIN KOGYO CO., LTD." }, { 0x2816, "Harvard Photonix" }, { 0x2817, "Test Equipment Plus" }, { 0x2818, "Codex Digital Limited" }, { 0x2819, "MESSRING Systembau MSG GmbH" }, { 0x281A, "SWAC Automation Consult GmbH" }, { 0x281B, "HiES Tech s.r.o." }, { 0x281C, "Presidium Instruments Pte. Ltd." }, { 0x281D, "AISIN AW CO., LTD." }, { 0x281E, "Symphodia Phil" }, { 0x281F, "Motion Control, Inc." }, { 0x2820, "Sanovas" }, { 0x2821, "Aclima Inc." }, { 0x2822, "REFLEXdigital" }, { 0x2823, "Dongguan Jiumutong Industry Co., Ltd." }, { 0x2824, "Vollsun Ltd." }, { 0x2825, "Baumer Optronic GmbH" }, { 0x2826, "BSH Bosch und Siemens Hausgerate GmbH" }, { 0x2827, "DIGITTRADE GmbH" }, { 0x2828, "SAPHYMO" }, { 0x2829, "Scanomat A/S" }, { 0x282A, "REDL GmbH" }, { 0x282B, "Aevoe Inc." }, { 0x282C, "Reichert, Inc." }, { 0x282D, "Aeromax Technology Co., Ltd." }, { 0x282E, "Vectawave Technology Ltd." }, { 0x282F, "SANKEN ELECTRIC CO., LTD." }, { 0x2830, "GD-Broadband" }, { 0x2831, "Power Integrations" }, { 0x2832, "Applied Research Associates" }, { 0x2833, "Oculus VR LLC" }, { 0x2834, "JM Concept" }, { 0x2835, "SEIDENSHA ELECTRONICS Co., Ltd." }, { 0x2836, "OUYA Inc." }, { 0x2837, "Tunstall Healthcare (UK) Ltd." }, { 0x2838, "Ontorix GmbH" }, { 0x2839, "Grass Elektronik" }, { 0x283A, "HIKe Mobile Co., Ltd." }, { 0x283B, "Cellon Communications Technology (Shenzhen) Co., Ltd." }, { 0x283C, "HIGH TEK HARNESS ENTERPRISE CO., LTD." }, { 0x283D, "SigNET (AC) Ltd." }, { 0x283E, "DECATHLON SA" }, { 0x283F, "Elprosys Sp. Z.o.o." }, { 0x2840, "Taiwan Carol Electronics Co., Ltd." }, { 0x2841, "Artvision Technologies Inc." }, { 0x2842, "RobotGroup" }, { 0x2843, "SyncMOS Technologies International, Inc." }, { 0x2844, "ELSIST Srl" }, { 0x2845, "Systec Designs BV" }, { 0x2846, "ATRON electronic GmbH" }, { 0x2847, "TMG TE GmbH" }, { 0x2848, "Sentons USA, Inc." }, { 0x2849, "Astronics Advanced Electronic Systems Corp." }, { 0x284A, "Yangtze Optical Fibre and Cable Company Ltd." }, { 0x284B, "Leadingui Co., Ltd." }, { 0x284C, "Full in Hope Co., Ltd." }, { 0x284D, "Qltouch Tech Co., Ltd." }, { 0x284E, "Flysky RC Model Co., Ltd." }, { 0x284F, "ANTLIA SA" }, { 0x2850, "Intellectual Property Group SA" }, { 0x2851, "RETIA, a.s." }, { 0x2852, "Virtual Console, LLC" }, { 0x2853, "Ralston Instruments" }, { 0x2854, "Great River Technology" }, { 0x2855, "System Dimensions, Inc." }, { 0x2856, "Thales Alenia Space - Italia" }, { 0x2857, "Skardin Industrial Corporation" }, { 0x2858, "PT Doo Won Precision Indonesia" }, { 0x2859, "Viconn Technology (HK) Co., Ltd." }, { 0x285A, "AiM Touch Technology Co., Ltd." }, { 0x285B, "HARDWARE & SOFTWARE TECHNOLOGY CO., LTD." }, { 0x285C, "URMET S.p.a." }, { 0x285D, "Alarm.com, Inc." }, { 0x285E, "Occam Robotics" }, { 0x285F, "CyWee Group Limited" }, { 0x2860, "WISYCOM UNIPERSONALE s.r.l." }, { 0x2861, "Pacific Image Electronics Co., Ltd." }, { 0x2862, "DeVilbiss Healthcare LLC" }, { 0x2863, "BIOMATIQUES IDENTIFICATION SOLUTIONS PRIVATE LIMITED" }, { 0x2864, "Wenngo Inc." }, { 0x2865, "VIKING GmbH" }, { 0x2866, "SLOW CONTROL" }, { 0x2867, "DASCOM" }, { 0x2868, "Chakra Energetics Ltd." }, { 0x2869, "Comfort Audio AB" }, { 0x286A, "Dipl. - Ing. H. Horstmann GmbH" }, { 0x286B, "STANEO SAS" }, { 0x286C, "Atest-Gaz A. M. Pachole sp. j." }, { 0x286D, "Production Resource Group, LLC" }, { 0x286E, "Geosense Inc." }, { 0x286F, "Bretford Manufacturing Inc." }, { 0x2870, "Typhoon HIL, Inc." }, { 0x2871, "BYK-Gardner GmbH" }, { 0x2872, "Brite Semiconductor (Shanghai) Corporation" }, { 0x2873, "Spire Payments Holdings S.a.r.l." }, { 0x2874, "Dexter Research Center, Inc." }, { 0x2875, "nVideon, Inc." }, { 0x2876, "Safety Innovations, Inc." }, { 0x2877, "BrightSign LLC" }, { 0x2878, "Cabletech Electronics (Hong Kong) Co., Ltd." }, { 0x2879, "Rancore Technologies Private Limited" }, { 0x287A, "Shenzhen Bojuxing Industrial Development Co., Ltd." }, { 0x287B, "Pro-Tech" }, { 0x287C, "Special Recording Systems Ltd." }, { 0x287D, "Pettersson Elektronik AB" }, { 0x287E, "Silicon Designs, Inc." }, { 0x287F, "Beijing Jinke XinAn Technology Co., Ltd." }, { 0x2880, "Black Diamond Video" }, { 0x2881, "DX Antenna Co., Ltd." }, { 0x2882, "GCOMM CORPORATION" }, { 0x2883, "abatec group AG" }, { 0x2884, "Bor" }, { 0x2885, "Quantec SA" }, { 0x2886, "Seeed Technology Co., Ltd." }, { 0x2887, "Specwerkz" }, { 0x2888, "VEX Robotics, Inc." }, { 0x2889, "TrueVision Systems, Inc." }, { 0x288A, "LEXIBOOK LIMITED" }, { 0x288B, "Hierstar (Suzhou)" }, { 0x288C, "Moswell Co., Ltd." }, { 0x288D, "Centre for Development of Advanced Computing (C-DAC)" }, { 0x288E, "mce-systems Ltd." }, { 0x288F, "Voxx Accessories Corp." }, { 0x2890, "Teknic, Inc." }, { 0x2891, "Flytec AG" }, { 0x2892, "NAVIgard" }, { 0x2893, "LEVEL Ltd." }, { 0x2894, "Hovercam" }, { 0x2895, "INIM Electronics s.r.l." }, { 0x2896, "TTAF Elektronik Sanayi ve Ticaret Ltd. Sti." }, { 0x2897, "SDJ Technologies, Inc." }, { 0x2898, "Accumetrics Associates, Inc." }, { 0x2899, "Toptronic Industrial Co., Ltd." }, { 0x289A, "Scan-Sense A.S." }, { 0x289B, "DRACAL Technologies Inc." }, { 0x289C, "TLS Corp." }, { 0x289D, "Tyrian Systems, Inc." }, { 0x289E, "Esselte Leitz GmbH & Co. KG" }, { 0x289F, "inoage GmbH" }, { 0x28A0, "I-CUBE TECHNOLOGY Co., Ltd." }, { 0x28A1, "AVEST-SYSTEMS Private Unitary Enterprise" }, { 0x28A2, "Meadowlark Optics Incorporated" }, { 0x28A3, "SensoMotoric Instruments GmbH" }, { 0x28A4, "Objective Solutions Sweden AB" }, { 0x28A5, "TCS John Huxley" }, { 0x28A6, "E-SEEK Inc." }, { 0x28A7, "Hugo Brennenstuhl GmbH & Co. KG" }, { 0x28A8, "AT Sciences, LLC" }, { 0x28A9, "Alpha Technologies" }, { 0x28AA, "Realta Entertainment Group" }, { 0x28AB, "Navigil Ltd." }, { 0x28AC, "euroBRAILLE" }, { 0x28AD, "iDTRONIC GmbH" }, { 0x28AE, "Zynaptic Limited" }, { 0x28AF, "Sharkbay Technologies Pte. Ltd." }, { 0x28B0, "PMC - Sierra" }, { 0x28B1, "EcoTech, Inc." }, { 0x28B2, "Siemens Infrastructure & Cities" }, { 0x28B3, "Profoto AB" }, { 0x28B4, "TOACK Corporation" }, { 0x28B5, "Solacom Inc." }, { 0x28B6, "Alcohol Countermeasure Systems Corp." }, { 0x28B7, "Pleora Technologies Inc." }, { 0x28B8, "Swiss Authentication Research & Development AG" }, { 0x28B9, "Kapsch TrafficCom AB" }, { 0x28BA, "RSscan International NV" }, { 0x28BB, "ICP Systems b.v." }, { 0x28BC, "Cyplex Corporation" }, { 0x28BD, "GuangZhou Ugee Computer Technology Co., Ltd." }, { 0x28BE, "GMG TECH. Co., Ltd." }, { 0x28BF, "Vitetech Int'l Co., Ltd." }, { 0x28C0, "SCVNGR, Inc." }, { 0x28C1, "DOMMEL GmbH" }, { 0x28C2, "Tapko Technologies GmbH" }, { 0x28C3, "MITSUBISHI ELECTRIC SYSTEM & SERVICE CO., LTD." }, { 0x28C4, "GALA, Inc." }, { 0x28C5, "ShenZhen Innovate-link Precision Hardware Co., Ltd." }, { 0x28C6, "FASTLITE" }, { 0x28C7, "Ultimaker BV" }, { 0x28C8, "ULTRACHIP Inc." }, { 0x28C9, "DongGuan City DHE Wire & Cable Co., Ltd." }, { 0x28CA, "NUMATA Corporation" }, { 0x28CB, "GO engineering GmbH" }, { 0x28CC, "MIWA ELECTRIC CO., LTD." }, { 0x28CD, "SMARTMATIC INTERNATIONAL CORP." }, { 0x28CE, "Changzhou Shi Wujin Miqi East Electronic Co., Ltd." }, { 0x28CF, "Asiatelco Technologies Co." }, { 0x28D0, "Stryker Corporation" }, { 0x28D1, "Technomedica Co., Ltd." }, { 0x28D2, "FTK Corporation" }, { 0x28D3, "Golden Transmart International Co., Ltd." }, { 0x28D4, "DEVIALET SAS" }, { 0x28D5, "Vicor Corporation" }, { 0x28D6, "Electrogamez USA Inc." }, { 0x28D7, "Tekron International" }, { 0x28D8, "Panda Ocean Inc." }, { 0x28D9, "Shenzhen Yoshuo Precision Components Co., Ltd." }, { 0x28DA, "G.SKILL Int'l Enterprice Co., Ltd." }, { 0x28DB, "Konftel AB" }, { 0x28DC, "Power Electronics International, Inc." }, { 0x28DD, "AIWA COMPANY LTD. - Love Harmony (LH)" }, { 0x28DE, "Valve Corporation" }, { 0x28DF, "EMBED-IT" }, { 0x28E0, "PRASIMAX" }, { 0x28E1, "Shenzhen iSolution Technologies Co., Ltd." }, { 0x28E2, "Surplus Electronic Technology Co., Ltd." }, { 0x28E3, "Apollo Electrical Technology Co., Ltd." }, { 0x28E4, "RKS, Inc." }, { 0x28E5, "MEP TECH" }, { 0x28E6, "BIAMP SYSTEMS" }, { 0x28E7, "Glyph Production Technologies" }, { 0x28E8, "Jefferson Audio Video Systems, Inc." }, { 0x28E9, "GigaDevice Semiconductor (Beijing) Inc." }, { 0x28EA, "Dongguan Vast Electronics Co.,Ltd" }, { 0x28EB, "SHEN ZHEN SHI YUAN AI HARDWARE ELECTRONIC CO., LTD." }, { 0x28EC, "Transcom Instruments Co., Ltd." }, { 0x28ED, "Shenzhen AraTek Biometrics Technology Co., Ltd." }, { 0x28EE, "China Mobile Group Device Co., Ltd." }, { 0x28EF, "SEEFRONT GmbH" }, { 0x28F0, "Elcus Electronic Company JSC" }, { 0x28F1, "Leddartech Inc." }, { 0x28F2, "Applied Vision Corporation" }, { 0x28F3, "Clover Network" }, { 0x28F4, "Sonoma Wire Works" }, { 0x28F5, "Electrolux Laundry Systems Sweden AB" }, { 0x28F6, "SERVOMEX Group Ltd." }, { 0x28F7, "ANYWIRE CORPORATION" }, { 0x28F8, "VTECH Technology Corp." }, { 0x28F9, "Comcraft" }, { 0x28FA, "iProtoXi Oy" }, { 0x28FB, "Shin Hwa Contech Co., Ltd." }, { 0x28FC, "Shandong Sinochiptp Electronic Technology Co., Ltd." }, { 0x28FD, "Wolfson Microelectronics Plc." }, { 0x28FE, "Marquardt Mechatronik GmbH" }, { 0x28FF, "MIRAENANOTECH" }, { 0x2900, "Labsphere" }, { 0x2901, "Tolomatic Inc." }, { 0x2902, "Woodward Inc." }, { 0x2903, "Lightspeed Aviation" }, { 0x2904, "Charon Technologies LLC" }, { 0x2905, "iDea USA Products Inc." }, { 0x2906, "Masimo Corporation" }, { 0x2907, "Mimetics Inc." }, { 0x2908, "Shenzhen Sen5 Technology Co., Ltd." }, { 0x2909, "Active Mind Technology" }, { 0x290A, "Electronic Systems Technology, Inc." }, { 0x290B, "Beats Electronics LLC" }, { 0x290C, "R. Hamilton & Co. Ltd." }, { 0x290D, "IBCONN Technologies (Shenzhen) Co., Ltd." }, { 0x290E, "Fugoo Inc." }, { 0x290F, "AFL Noyes" }, { 0x2910, "Cree, Inc." }, { 0x2911, "Penetek, Inc." }, { 0x2912, "Management Company ATOL Ltd." }, { 0x2913, "Teladin Co., Ltd." }, { 0x2914, "Kent Displays Inc." }, { 0x2915, "Sage Microelectronics Corp." }, { 0x2916, "Yota Devices Ltd." }, { 0x2917, "Pan Xin Precision Electronics Co., Ltd." }, { 0x2918, "Gigatronik Ingolstadt GmbH" }, { 0x2919, "GE Analytical Instruments" }, { 0x291A, "Anker Technology Co., Limited" }, { 0x291B, "LONTEX PIOTR LONDZIN" }, { 0x291C, "KEISOKUKI CENTER CO., LTD." }, { 0x291D, "Research & Development Center ELVEES OJSC" }, { 0x291E, "Shanghai DynamiCode Company Ltd." }, { 0x291F, "CBN Inc." }, { 0x2920, "Fiberplex Technologies, LLC" }, { 0x2921, "BiovenTus, LLC" }, { 0x2922, "Dongguan Digi-in Digital Technology Co., Ltd." }, { 0x2923, "Vprime" }, { 0x2924, "Chinon Corporation" }, { 0x2925, "Flight System Consulting Inc." }, { 0x2926, "Wildlife Acoustics, Inc." }, { 0x2927, "BF1 Systems Ltd." }, { 0x2928, "Dongguan Sineng Electronic Technology Co., Ltd." }, { 0x2929, "Shenzhen Taishan Online Technology Co., Ltd." }, { 0x292A, "T1Visions, Inc." }, { 0x292B, "Precision Audio Device Lab Limited" }, { 0x292C, "GENUSION, Inc." }, { 0x292D, "Wellitec Development Limited" }, { 0x292E, "HOYA Service Corporation" }, { 0x292F, "Nanotec Electronic GmbH & Co. KG" }, { 0x2930, "Ineda Systems Inc." }, { 0x2931, "Jolla Ltd." }, { 0x2932, "Peraso Technologies, Inc." }, { 0x2933, "IEI Integration Corp." }, { 0x2934, "CETA Testsysteme GmbH" }, { 0x2935, "Nanjing Magewell Electronics Co., Ltd." }, { 0x2936, "LEAP Motion" }, { 0x2937, "Tmax Digital Inc." }, { 0x2938, "Aides Technology Co., Ltd." }, { 0x2939, "Zaber Technologies Inc." }, { 0x293A, "The SmarTV Company" }, { 0x293B, "Lucent Medical Systems, Inc." }, { 0x293C, "Comcast" }, { 0x293D, "Medicatec Inc." }, { 0x293E, "EIDEN Co., Ltd." }, { 0x293F, "Gan Zhou DPT-Technology Co., Ltd." }, { 0x2940, "Shenzhen Yiwanda Electronics Co., Ltd." }, { 0x2941, "Sanofi-Aventis Deutschland GmbH" }, { 0x2942, "SoftLab - NSK" }, { 0x2943, "ZAGG Inc." }, { 0x2944, "RailComm" }, { 0x2945, "Matrix Design Group, LLC" }, { 0x2946, "OnAsset Intelligence Inc." }, { 0x2947, "KAPELSE" }, { 0x2948, "Access Network Technology Limited" }, { 0x2949, "Shenzhen JSR Technology Co., Ltd." }, { 0x294A, "Shenzhen Xinguodu Technology Co., Ltd." }, { 0x294B, "snakebyte Asia Ltd." }, { 0x294C, "Terminus Circuits Pvt Ltd." }, { 0x294D, "Cellwise Holding Co., Ltd." }, { 0x294E, "SHIH HUA TECHNOLOGY LTD." }, { 0x294F, "Dollar Connection Ltd." }, { 0x2950, "Resource One Inc." }, { 0x2951, "Raytrix GmbH" }, { 0x2952, "Seba Dynatronic GmbH" }, { 0x2953, "Axes System sp. Z.o.o." }, { 0x2954, "Human Design Medical, LLC" }, { 0x2955, "Baidu Online Network Technology (Beijing) Co., Ltd." }, { 0x2956, "Alfatest Ind. e Com. Produtos Eletronicos S/A" }, { 0x2957, "OBSIDIAN RESEARCH CORPORATION" }, { 0x2958, "Eleven Engineering Inc." }, { 0x2959, "Inuitive" }, { 0x295A, "ENERMAX TECHNOLOGY CORPORATION" }, { 0x295B, "eflow Inc." }, { 0x295C, "MediaNet M. Hermsen" }, { 0x295D, "Positive Grid" }, { 0x295E, "Britelite Enterprises" }, { 0x295F, "Tecvox Connectivity, LLC" }, { 0x2960, "Power Probe, Inc." }, { 0x2961, "Miselu Inc." }, { 0x2962, "Wilocity Ltd." }, { 0x2963, "BIO-key International, Inc." }, { 0x2964, "Kintech Co., Ltd." }, { 0x2965, "Kortek" }, { 0x2966, "Schatz AG" }, { 0x2967, "St. Andrews Instrumentation Ltd." }, { 0x2968, "Phoenix Avionics Systems, LLC" }, { 0x2969, "Sumix" }, { 0x296A, "Nitero, Inc." }, { 0x296B, "Xacti Corporation" }, { 0x296C, "KNC ONE GmbH - Research & Development" }, { 0x296D, "Azuri Technologies Ltd" }, { 0x296E, "LG CNS Co., Ltd." }, { 0x296F, "Broadsound Corporation" }, { 0x2970, "MERIDIAN SOFTWARE SYSTEMS LIMITED" }, { 0x2971, "Ory Laboratory Ltd." }, { 0x2972, "FiiO Electronics Technology Co., Ltd." }, { 0x2973, "Wild Elektronik & Kunststoff GmbH & Co. KG" }, { 0x2974, "Printrbot, Inc." }, { 0x2975, "MPC Research Ltd." }, { 0x2976, "COMOTA Co., Ltd." }, { 0x2977, "Shenzhen Zowee Technology Co., Ltd." }, { 0x2978, "Imaging Solutions Group of NY, Inc." }, { 0x2979, "Williams Sound, LLC" }, { 0x297A, "Innovative Developments LLC" }, { 0x297B, "ALKERIA s.r.l." }, { 0x297C, "HashFast Technologies LLC" }, { 0x297D, "Krypton Solutions" }, { 0x297E, "Shenzhen DTEC Electronic Technology Co., Ltd." }, { 0x297F, "Emerging Technology (Holdings) Ltd." }, { 0x2980, "CiDELEC" }, { 0x2981, "Elektron Technology UK Limited" }, { 0x2982, "Ableton AG" }, { 0x2983, "Coyote System" }, { 0x2984, "Glensound Electronics Ltd." }, { 0x2985, "DUALO" }, { 0x2986, "Rapt Touch (Ireland) Ltd." }, { 0x2987, "Lyve Minds, Inc." }, { 0x2988, "3D Systems Corporation" }, { 0x2989, "Nanjing Fujitsu Electronics Information Technology Co., Ltd" }, { 0x298A, "Singeen Electronics Technologies (Dongguan) Co., Ltd." }, { 0x298B, "Hanil ProTech" }, { 0x298C, "GL Solutions Inc." }, { 0x298D, "NEXT Biometrics" }, { 0x298E, "Delta Controls" }, { 0x298F, "NIHON DENON CO., LTD." }, { 0x2990, "SHIGA MEC Company Limited" }, { 0x2991, "Orbitsound Ltd" }, { 0x2992, "Lantos Technologies, Inc." }, { 0x2993, "ADPlaus Technology Limited" }, { 0x2995, "Resodyn Corporation" }, { 0x2996, "Delphi Data Connectivity" }, { 0x2997, "Inogeni Inc." }, { 0x2998, "EOS S.r.l." }, { 0x2999, "Fourtec Technologies Ltd." }, { 0x299A, "Ogi Systems Ltd. by A.A. Lab Systems" }, { 0x299B, "Ohio Semitronics, Inc." }, { 0x299C, "WINTOUCH Co., Ltd." }, { 0x299D, "Horst Platz Beratungs und Vertriebs GmbH" }, { 0x299E, "TRE INNOVATORER AB" }, { 0x299F, "MESTEC Technologies" }, { 0x29A0, "Bang & Olufsen Medicom A/S" }, { 0x29A1, "Union Electric Plug & Connector Corp." }, { 0x29A2, "MUTEC GmbH" }, { 0x29A3, "Cista System Corporation" }, { 0x29A4, "Source Audio LLC" }, { 0x29A5, "Harbo Entertainment LLC" }, { 0x29A6, "Chiyoda Electronics Co., Ltd." }, { 0x29A7, "Tekinvest Holding Ltd." }, { 0x29A8, "Lester Electrical" }, { 0x29A9, "Smartisan Technology Co., Ltd." }, { 0x29AA, "Zivix, LLC" }, { 0x29AB, "The Eye Tribe" }, { 0x29AC, "Cool Control (S.D.) Ltd." }, { 0x29AD, "Quest Engineering & Development, Inc." }, { 0x29AE, "Japan Lifeline Co., Ltd." }, { 0x29AF, "Zhongshan K-Mate General Electronics Co., Ltd." }, { 0x29B0, "Diebold Financial Equipment Co., Ltd." }, { 0x29B1, "Dongguan Haitai Precision Electronic Technology Co Ltd" }, { 0x29B2, "Canova Tech" }, { 0x29B3, "Dowling Software" }, { 0x29B4, "Shenzhen Carbetter Technology Co., Ltd." }, { 0x29B5, "PN Devices Int'l Limited" }, { 0x29B6, "Gowin Technology International Holdings Limited" }, { 0x29B7, "X.O.Ware, Inc." }, { 0x29B8, "Hawk-Owl Systems" }, { 0x29B9, "S.I.C.E.S. S.r.l." }, { 0x29BA, "TOPTICA Photonics AG" }, { 0x29BB, "SMUFS Biometric Solutions" }, { 0x29BC, "IMBEL - Industria de Material Belico do Brasil" }, { 0x29BD, "Silicon Works" }, { 0x29BE, "Mamiya-OP NEQUOS Co., Ltd." }, { 0x29BF, "BalanceMaster, Inc." }, { 0x29C0, "Canopy Co." }, { 0x29C1, "TazTag" }, { 0x29C2, "Lewitt GmbH" }, { 0x29C3, "Noviga" }, { 0x29C4, "SoundHawk Corporation" }, { 0x29C5, "Peachtree Audio" }, { 0x29C6, "Shenzhen Jiali Asia Industry Co., Ltd." }, { 0x29C7, "HANRICO ANFU ELECTRONICS CO., LTD." }, { 0x29C8, "Samil CTS Co., Ltd." }, { 0x29C9, "BEEVC-Electronic Systems, LDA" }, { 0x29CA, "Cross the Road Electronics, LLC" }, { 0x29CB, "Xima Software" }, { 0x29CC, "Kodak Alaris" }, { 0x29CD, "Carotron, Inc." }, { 0x29CE, "JGR Optics Inc." }, { 0x29CF, "Richtek Technology Corporation" }, { 0x29D0, "ShenZhen Synergy Digital Co., Ltd." }, { 0x29D1, "Binatone Electronics Int. Ltd." }, { 0x29D2, "Crypto Control Limited" }, { 0x29D3, "HESS Cash Systems GmbH & Co. KG" }, { 0x29D4, "Twin Development S.A." }, { 0x29D5, "Alibaba Cloud Computing Ltd." }, { 0x29D6, "Ara Hub Design Inc." }, { 0x29D7, "Suritel" }, { 0x29D8, "Vigor Electric Corporation" }, { 0x29D9, "San-Eisha, Ltd." }, { 0x29DA, "The Modal Shop" }, { 0x29DB, "Shenzhen iBoard Technology Co., Ltd." }, { 0x29DC, "TOHO Electronics Inc." }, { 0x29DD, "Embedded Micro" }, { 0x29DE, "Korea Electric Terminal Co., Ltd." }, { 0x29DF, "SMIT(HK) Limited" }, { 0x29E0, "ARCCRA Technology Co., Ltd." }, { 0x29E1, "TOSEI ENGINEERING CORP." }, { 0x29E2, "Huatune Technology (Shanghai) Co., Ltd." }, { 0x29E3, "Bio-Medical Research" }, { 0x29E4, "Prestigio Plaza Ltd." }, { 0x29E5, "Dongguan Kechenda Electronic Technology Co., Ltd." }, { 0x29E6, "Fengshun Peiying Electro-Acoustic Co., Ltd." }, { 0x29E7, "Brunel University" }, { 0x29E8, "4Links Limited" }, { 0x29E9, "Quanttus, Inc." }, { 0x29EA, "Kinesis Corporation" }, { 0x29EB, "Virtuix Inc." }, { 0x29EC, "R. Stahl" }, { 0x29ED, "CERA" }, { 0x29EE, "Pinnacle Response Ltd." }, { 0x29EF, "GamePop Inc." }, { 0x29F0, "WirePath Home Systems dba Snap AV" }, { 0x29F1, "0XF8 Limited" }, { 0x29F2, "RECO Gesellschaft fur Industriefilterregelung mbH" }, { 0x29F3, "Resonessence Labs" }, { 0x29F4, "NeuroSky, Inc." }, { 0x29F5, "AirNetix, LLC" }, { 0x29F6, "Evoko Unlimited AB" }, { 0x29F7, "Matica Technologies AG" }, { 0x29F8, "MD ELEKTRONIK GmbH" }, { 0x29F9, "EnerLab, LLC" }, { 0x29FA, "LogTag Recorders Ltd." }, { 0x29FB, "JSK Co., Ltd." }, { 0x29FC, "Namsung Corporation" }, { 0x29FD, "Bad Elf, LLC" }, { 0x29FE, "GEO Semiconductor Inc." }, { 0x29FF, "Thalmic Labs Inc." }, { 0x2A00, "NTLab" }, { 0x2A01, "Amuseway Korea Co., Ltd." }, { 0x2A02, "OJI LTD." }, { 0x2A03, "dog hunter AG" }, { 0x2A04, "Microtech Laboratory Inc." }, { 0x2A05, "EXO LABS INC." }, { 0x2A06, "HiFiMAN Electronics" }, { 0x2A07, "ise GmbH" }, { 0x2A08, "Marshall Amplification PLC" }, { 0x2A09, "cytonome" }, { 0x2A0A, "All Star International Trading" }, { 0x2A0B, "Leopard Imaging Inc." }, { 0x2A0C, "MultiSoft Systems Ltd." }, { 0x2A0D, "ADVANCE Co., Ltd." }, { 0x2A0E, "Shenzhen DreamSource Technology Co., Ltd." }, { 0x2A0F, "Shenzhen Giec Electronics Co., Ltd." }, { 0x2A10, "Powerway Electronics Co., Ltd." }, { 0x2A11, "P3 Ingenieurgesellschaft mbH" }, { 0x2A12, "Vreo Limited" }, { 0x2A13, "Grabba International" }, { 0x2A14, "Kanex" }, { 0x2A15, "navAero AB" }, { 0x2A16, "Hella Gutmann Solutions" }, { 0x2A17, "UDEA Electronic Ltd." }, { 0x2A18, "King Abdulaziz City for Science and Technology" }, { 0x2A19, "Numato Systems Pvt. Ltd." }, { 0x2A1A, "ASCOT GmbH" }, { 0x2A1B, "DRS Power & Control Technologies, Inc." }, { 0x2A1C, "ThinkWrite" }, { 0x2A1D, "Oxford Nanopore Technologies" }, { 0x2A1E, "Obsidian Technology" }, { 0x2A1F, "Lucent Trans Electronics Co., Ltd." }, { 0x2A20, "GUOGUANG GROUP CO., LTD." }, { 0x2A21, "ROL Ergo AB" }, { 0x2A22, "CDEX CORP." }, { 0x2A23, "Artec Design" }, { 0x2A24, "CNPLUS" }, { 0x2A25, "Fourstar Group" }, { 0x2A26, "Tragant International Co., Ltd." }, { 0x2A27, "DongGuan LianGang Optoelectronic Technology Co., Ltd." }, { 0x2A28, "Higbie, LLC dba kinetuex" }, { 0x2A29, "PayPal, Inc." }, { 0x2A2A, "TARGAMITE LLC" }, { 0x2A2B, "NooElec Inc." }, { 0x2A2C, "Bkav Corporation" }, { 0x2A2D, "Atrust Computer Corp." }, { 0x2A2E, "VIA Alliance Semiconductor Co., Ltd." }, { 0x2A2F, "BSUN Electronics Co., Ltd." }, { 0x2A30, "KORR Medical Technologies" }, { 0x2A31, "Sandia National Laboratories" }, { 0x2A32, "Centre for Advanced Transport Engineering and Research" }, { 0x2A33, "NTT R&D Laboratories" }, { 0x2A34, "KT System, Inc." }, { 0x2A35, "Quatius Limited" }, { 0x2A36, "MOS Co., Ltd." }, { 0x2A37, "RTD Embedded Technologies, Inc." }, { 0x2A38, "Electronic Design Inc." }, { 0x2A39, "RME GmbH" }, { 0x2A3A, "K'NEX Limited Partnership Group" }, { 0x2A3B, "Eschenbach Optik GmbH" }, { 0x2A3C, "TRINAMIC Motion Control GmbH & Co. KG" }, { 0x2A3D, "FIME" }, { 0x2A3E, "Atlas Copco" }, { 0x2A3F, "Yasunaga Corporation" }, { 0x2A40, "Shenzhen Choseal Industrial Co., Ltd." }, { 0x2A41, "Canyon Semiconductor" }, { 0x2A42, "Spectra7 Microsystems Corp." }, { 0x2A43, "Ekosur S.A." }, { 0x2A44, "FUEL3D Technologies Limited" }, { 0x2A45, "Meizu Technology Co., Ltd." }, { 0x2A46, "Hubei Yingtong Telecommunication Cable Inc." }, { 0x2A47, "Mundo Reader SL" }, { 0x2A48, "Pointmobile" }, { 0x2A49, "UNOWHY" }, { 0x2A4A, "threeRivers 3D, Inc." }, { 0x2A4B, "EMULEX Corporation" }, { 0x2A4C, "Tianjin SharpNow Technology Co., Ltd." }, { 0x2A4D, "Wilder Technologies" }, { 0x2A4E, "Henge Docks, LLC" }, { 0x2A4F, "L-3 Communications Avionics Systems" }, { 0x2A50, "Akizuki Denshi Tsusho Co., Ltd." }, { 0x2A51, "Multiclet Corp." }, { 0x2A52, "L CARD Ltd." }, { 0x2A53, "x-odos GmbH" }, { 0x2A54, "Black Diamond Advanced Technology, LLC" }, { 0x2A56, "eemagine Medical Imaging Solutions GmbH" }, { 0x2A57, "Bellingham + Stanley Limited" }, { 0x2A58, "ALIGN Corporation Limited" }, { 0x2A59, "The Whistler Group" }, { 0x2A5A, "Kromek Group Plc." }, { 0x2A5B, "Integrity Applications Ltd." }, { 0x2A5C, "Dalian Zonewin Electronics Co., Ltd." }, { 0x2A5D, "Zhejiang Wanli Jo Ju Automation Technonolgy Co., Ltd." }, { 0x2A5E, "The Chemours Company" }, { 0x2A5F, "Tencent Technology (Shenzhen) Company Limited" }, { 0x2A60, "Oscadi SAS" }, { 0x2A61, "Ellex Medical Pty Ltd." }, { 0x2A62, "Flymaster Avionics, LDA" }, { 0x2A63, "Postek Electronics Co., Ltd." }, { 0x2A64, "Zhejiang Songcheng Electronics Co., Ltd." }, { 0x2A65, "FreeWave Technologies, Inc." }, { 0x2A66, "JoyLabz LLC" }, { 0x2A67, "Chart Industries" }, { 0x2A68, "CheckSum, LLC" }, { 0x2A69, "EDIC Systems Inc." }, { 0x2A6A, "PINTSCH TIEFENBACH GmbH" }, { 0x2A6B, "VSN Mobil" }, { 0x2A6C, "Silego Technology" }, { 0x2A6D, "SAsync, LLC" }, { 0x2A6E, "Bare Conductive Ltd." }, { 0x2A6F, "Shenzhen Justtide Tech Co., Ltd." }, { 0x2A70, "Shenzhen Oneplus Science and Technology Co., Inc." }, { 0x2A71, "Eyelock, Inc." }, { 0x2A72, "Omega Engineering" }, { 0x2A73, "IMAC Co., Ltd." }, { 0x2A74, "Innoflight Tech., Ltd." }, { 0x2A75, "Delta Dansk Elektronik, Lys & Akustik" }, { 0x2A76, "Microsemi Corporation (Phoenix)" }, { 0x2A77, "American Printing House for the Blind" }, { 0x2A78, "mySkin, Inc." }, { 0x2A79, "S.E. Technologies Limited" }, { 0x2A7A, "Beijing Casue Technology Co., Ltd." }, { 0x2A7B, "Bellwether Electronic Corp." }, { 0x2A7C, "Acute Technology Inc." }, { 0x2A7D, "ParTech, Inc." }, { 0x2A7E, "VAIO Corporation" }, { 0x2A7F, "Perixx Computer GmbH" }, { 0x2A80, "Smart Start Inc." }, { 0x2A81, "Hale Products, Inc." }, { 0x2A82, "Printek, Inc." }, { 0x2A83, "Autodesk Inc." }, { 0x2A84, "ATE Systems" }, { 0x2A85, "HANK ELECTRONICS CO., LTD" }, { 0x2A86, "KITRIS AG" }, { 0x2A87, "Kummler + Matter AG" }, { 0x2A88, "DFU Technology Ltd." }, { 0x2A89, "Robert Bosch Tool Corporation" }, { 0x2A8A, "Benchmark Drives GmbH & Co. KG" }, { 0x2A8B, "I.C. Lercher GmbH & Co. KG" }, { 0x2A8C, "Sonnet Technologies, Inc." }, { 0x2A8D, "Keysight Technologies Inc." }, { 0x2A8E, "Starlink Electronics Corp." }, { 0x2A8F, "Manutronics Vietnam Joint Stock Company" }, { 0x2A90, "NowComputing, LLC" }, { 0x2A91, "Seed Industrial Designing Co., Ltd." }, { 0x2A92, "Woosim Systems Inc." }, { 0x2A93, "Enblink Co., Ltd." }, { 0x2A94, "G2 Touch Co., Ltd." }, { 0x2A95, "Flipkart Internet Pvt. Ltd." }, { 0x2A96, "Micromax Informatics Ltd" }, { 0x2A97, "Broadway Semiconductor, Inc." }, { 0x2A98, "Calix" }, { 0x2A99, "Humanistic Robotics, Inc." }, { 0x2A9A, "SRAM, LLC" }, { 0x2A9B, "Doblet Inc." }, { 0x2A9C, "Olorin AB" }, { 0x2A9D, "LawMate International Co., Ltd." }, { 0x2A9E, "SEIKO SOLUTIONS Inc." }, { 0x2A9F, "Mobelisk LLC" }, { 0x2AA0, "Casco Products Corp." }, { 0x2AA1, "Ivanhoe (DE), Inc." }, { 0x2AA2, "GTI Spindle Technology, Inc." }, { 0x2AA3, "Strike Technologies a Division of Penbro Kelnick (Pty) Ltd" }, { 0x2AA4, "Voim Technologies Inc." }, { 0x2AA5, "Pen Generations, Inc." }, { 0x2AA6, "ChengFong International Limited" }, { 0x2AA7, "MJC Techno Co., Ltd." }, { 0x2AA8, "Resus Industries NV" }, { 0x2AA9, "Infrared Cameras Inc." }, { 0x2AAA, "Virtium Technology, Inc." }, { 0x2AAB, "Field and Company LLC, dba Leef USA" }, { 0x2AAC, "Elinchrom S.A." }, { 0x2AAD, "iCatch Technology, Inc." }, { 0x2AAE, "Chipone Technology (Beijing) Co., Ltd." }, { 0x2AAF, "Xiamen Hanin Electronic Technology Co., Ltd." }, { 0x2AB0, "GM Global Technology Operations LLC" }, { 0x2AB1, "Tesco Stores Ltd." }, { 0x2AB2, "Maktar, Inc." }, { 0x2AB3, "Key Asic Inc." }, { 0x2AB4, "Line Seiki Co., Ltd." }, { 0x2AB5, "Micro-Technica Co., Ltd." }, { 0x2AB6, "T+A Elektroakustik GmbH + Co. KG" }, { 0x2AB7, "foc.us" }, { 0x2AB8, "Meggitt (Orange County), Inc." }, { 0x2AB9, "Monsoon Solutions, Inc." }, { 0x2ABA, "MagneMotion Inc." }, { 0x2ABB, "HiDeep Inc." }, { 0x2ABC, "Beijing Kingrich Medical Technology Co., Ltd." }, { 0x2ABD, "Meeteasy Technology Limited" }, { 0x2ABE, "Bluink Ltd" }, { 0x2ABF, "Revolabs, Inc." }, { 0x2AC0, "POWA Technologies Ltd." }, { 0x2AC1, "Lattice Semiconductor Corp" }, { 0x2AC2, "Toreck Co., Ltd." }, { 0x2AC3, "Foshan Nanhai Saga Audio Equipment Co., Ltd." }, { 0x2AC4, "BlackBox Biometrics, Inc." }, { 0x2AC5, "PhotoFast Co., Ltd." }, { 0x2AC6, "HAKKO Corporation" }, { 0x2AC7, "Ultrahaptics Limited" }, { 0x2AC8, "SimonsVoss Technologies GmbH" }, { 0x2AC9, "TELPA Telekomunikasyon Tic. A.S. Brand: General Mobile" }, { 0x2ACA, "Toledo do Brasil Industria de Balancas Ltda." }, { 0x2ACB, "Pole/Zero Acquisition, Inc." }, { 0x2ACC, "illunis LLC" }, { 0x2ACD, "Silergy Corp." }, { 0x2ACE, "Tonetron Electronic Ltd." }, { 0x2ACF, "Ruffy Controls Inc." }, { 0x2AD0, "Holley Performance Products (CANADA) Inc." }, { 0x2AD1, "Pictronic GmbH" }, { 0x2AD2, "Allnic Audio" }, { 0x2AD3, "Shenzhen Hali-Power Industrial Co., Ltd." }, { 0x2AD4, "L&F Corporation" }, { 0x2AD5, "Baikal Electronics JSC" }, { 0x2AD6, "Cozumo, Inc." }, { 0x2AD7, "RHENAC Systems GmbH" }, { 0x2AD8, "i2s" }, { 0x2AD9, "Zound Industries International AB" }, { 0x2ADA, "McCarthy Music Corp." }, { 0x2ADB, "I-PEX (Dai-ichi Seiko)" }, { 0x2ADC, "Absolute USA" }, { 0x2ADD, "SEE-PLUS INDUSTRIAL LTD." }, { 0x2ADE, "Orga BV" }, { 0x2ADF, "Noiseless Security A/S" }, { 0x2AE0, "Auma Riester GmbH & Co. KG" }, { 0x2AE1, "EDEC PROGRESS CO., LTD." }, { 0x2AE2, "VXi Corporation" }, { 0x2AE3, "Jiuzhou Digital (Hong Kong) Limited" }, { 0x2AE4, "Next! s.c. Slawomir Piela, Bartlomiej Dryja" }, { 0x2AE5, "Fairphone B.V." }, { 0x2AE6, "e-distribuzione Spa" }, { 0x2AE7, "Advanced Media, Inc." }, { 0x2AE8, "Quintic Microelectronics (Wuxi) Co., Ltd." }, { 0x2AE9, "Regal Beloit Canada ULC. dba Thomson Power Systems" }, { 0x2AEA, "Protonex Technology Corporation" }, { 0x2AEB, "NovaTech, LLC" }, { 0x2AEC, "Ambiq Micro, Inc." }, { 0x2AED, "Technology Launch, LLC" }, { 0x2AEE, "Adapt-IP Company" }, { 0x2AEF, "Coronado Electronics, Inc." }, { 0x2AF0, "Zhejiang Yuesui Electron Stock Co., Ltd." }, { 0x2AF1, "Innovation Spring Tech, Inc." }, { 0x2AF2, "CIS Corporation" }, { 0x2AF3, "Rehan Electronics Ltd." }, { 0x2AF4, "ROLI Ltd." }, { 0x2AF5, "Libratone A/S" }, { 0x2AF6, "Nix Sensor Ltd." }, { 0x2AF7, "Shenzhen Hazens Automotive Electronics (SZ) Co., Ltd." }, { 0x2AF8, "Jiangsu Toppower Automotive Electronics Co., Ltd." }, { 0x2AF9, "Drapho Electronics Technology Co., Ltd." }, { 0x2AFA, "Yokogawa Digital Computer Corporation" }, { 0x2AFB, "EMC, Electronic Music Components" }, { 0x2AFC, "Savox Communications OY AB" }, { 0x2AFD, "McIntosh Laboratory, Inc." }, { 0x2AFE, "IntriCon" }, { 0x2AFF, "ARP Corporation" }, { 0x2B00, "Novitec Co., Ltd." }, { 0x2B01, "Zimi Corporation" }, { 0x2B02, "AMGOO Telecom Co., Ltd." }, { 0x2B03, "STEREOLABS" }, { 0x2B04, "Spark Labs, Inc." }, { 0x2B05, "Warn Industries" }, { 0x2B06, "TEControl" }, { 0x2B07, "ESA Elektroschaltanlagen Grimma GmbH" }, { 0x2B08, "KYOEI ENGINEERING Co., Ltd." }, { 0x2B09, "Shenzhen Lidacheng Technology Co., Ltd." }, { 0x2B0A, "AMICCOM Electronics Corporation" }, { 0x2B0B, "Qtul Enterprises" }, { 0x2B0C, "Goclever Sp z o.o." }, { 0x2B0D, "Dongguan Yulian Electronic Industrial Co., Ltd." }, { 0x2B0E, "Le Shi Zhi Xin Electronic Technology (Tian Jin) Limited" }, { 0x2B0F, "Best Integration Technology Co., Ltd." }, { 0x2B10, "Cardiac Insight, Inc." }, { 0x2B11, "Europe Net Srl" }, { 0x2B12, "DeepSpar" }, { 0x2B13, "Lightcomm Technology Co., Ltd." }, { 0x2B14, "EverPro Technologies Company, Ltd." }, { 0x2B15, "Rosenberger Hochfrequenztechnik" }, { 0x2B16, "Spirometrix, Inc." }, { 0x2B17, "Jaguar Land Rover" }, { 0x2B18, "ProSign GmbH" }, { 0x2B19, "JBSignal Co." }, { 0x2B1A, "Fortune Ship Technology (HK) Limited" }, { 0x2B1B, "Dongguan City Sanji Electronics Co., Ltd." }, { 0x2B1C, "Shenzhen Virtual Reality Technology Company Limited" }, { 0x2B1D, "Lintes Technology Co., Ltd." }, { 0x2B1E, "NFUZD Technology Inc" }, { 0x2B1F, "KinnexA, Inc." }, { 0x2B20, "WaveLynx Technologies Corporation" }, { 0x2B21, "Project Florida" }, { 0x2B22, "Metra Electronics Corp." }, { 0x2B23, "Red Hat, Inc." }, { 0x2B24, "KeepKey, LLC" }, { 0x2B25, "Logos Biosystems, Inc." }, { 0x2B26, "Oltrade LLC" }, { 0x2B27, "FluxData Incorporated" }, { 0x2B28, "Enovation Controls, LLC" }, { 0x2B29, "Lezyne" }, { 0x2B2A, "BDX" }, { 0x2B2B, "BITwave PTE LTD." }, { 0x2B2C, "S1nn GmbH & Co. KG" }, { 0x2B2D, "AEG Power Solutions GmbH" }, { 0x2B2E, "pei tel Communications GmbH" }, { 0x2B2F, "UL TS B.V." }, { 0x2B30, "Neratec Solutions AG" }, { 0x2B31, "JVIS USA, LLC" }, { 0x2B32, "NVS Technologies AG" }, { 0x2B33, "Commend International GmbH" }, { 0x2B34, "Seemahale Telecoms" }, { 0x2B35, "Assem Technology Co., Ltd." }, { 0x2B36, "Dongguan City Jianghan Electronics Co., Ltd." }, { 0x2B37, "Huizhou Desay SV Automotive Co., Ltd." }, { 0x2B38, "Ningbo Rixing Electronics Co., Ltd." }, { 0x2B39, "KANAI ELECTRONIC APPLIANCE Co., Ltd." }, { 0x2B3A, "Cirrus Research plc" }, { 0x2B3B, "ScriptPro, LLC" }, { 0x2B3C, "Technikos Sports Inc." }, { 0x2B3D, "GuangDong YuanFeng Automotive Electroics Co., Ltd." }, { 0x2B3E, "NewAE Technology Inc." }, { 0x2B3F, "ATL-SD Co., Ltd." }, { 0x2B40, "Matsumura Engineering Co., Ltd." }, { 0x2B41, "Image Match Design Inc." }, { 0x2B42, "NEXO S.A." }, { 0x2B43, "Doro AB" }, { 0x2B44, "Wildfire, Inc." }, { 0x2B45, "PRA Audio Systems, Inc." }, { 0x2B46, "Centerm Information Co., Ltd." }, { 0x2B47, "Huizhou Aorora Science & Technology Co., Ltd." }, { 0x2B48, "Sounding Audio Industrial Limited" }, { 0x2B49, "GECO Incorporated" }, { 0x2B4A, "Yueqing Huaxin Electronic Co., Ltd." }, { 0x2B4B, "China Hualu Group Co., Ltd." }, { 0x2B4C, "Beijing SHENQI Technology Co., Ltd." }, { 0x2B4D, "SMC Corporation" }, { 0x2B4E, "Microcabin Inc." }, { 0x2B4F, "Aeroscout Ltd. (Stanley Healthcare)" }, { 0x2B50, "Denchi Power Ltd." }, { 0x2B51, "Pax Instruments" }, { 0x2B52, "Dongguan Evermax Electronics Technology Co., Ltd." }, { 0x2B53, "Shenzhen Supernature Multimedia Co., Ltd." }, { 0x2B54, "AMPAK Technology Inc." }, { 0x2B55, "FUJIFILM Imaging Systems Co., Ltd." }, { 0x2B56, "The Crypto Group" }, { 0x2B57, "GIROPTIC" }, { 0x2B58, "DJ Sound Electronics, LLC / BiZi Inc." }, { 0x2B59, "ESI Motion" }, { 0x2B5A, "Universal Audio, Inc." }, { 0x2B5B, "Xiamen Home Meitu Technology Co., Ltd." }, { 0x2B5C, "B&B Exporting Limited" }, { 0x2B5D, "GSL Solutions, Inc." }, { 0x2B5E, "Audio Alchemy" }, { 0x2B5F, "b-plus GmbH" }, { 0x2B60, "Viking Technology" }, { 0x2B61, "Universal Biosensors, Inc." }, { 0x2B62, "ICP Entwicklungs GmbH" }, { 0x2B63, "Inora Technologies, Inc." }, { 0x2B64, "Cyanogen Inc." }, { 0x2B65, "Atelier Vision Corporation" }, { 0x2B66, "Clinton Instrument Company" }, { 0x2B67, "Lifesize, Inc." }, { 0x2B68, "FLEXIM - Flexible Industriemesstechnik GmbH" }, { 0x2B69, "Humax Automotive Co., Ltd." }, { 0x2B6A, "FUJI TECOM INC." }, { 0x2B6B, "Colorix SA" }, { 0x2B6C, "Transbit Sp. z o.o." }, { 0x2B6D, "SATORI ELECTRIC CO., LTD." }, { 0x2B6E, "Airviz Inc." }, { 0x2B6F, "Revolution Education Ltd." }, { 0x2B70, "Micran, Research & Production Company" }, { 0x2B71, "Zhejiang Flashforge 3D Technology Co., Ltd." }, { 0x2B72, "RT Corporation" }, { 0x2B73, "Pioneer DJ Corporation" }, { 0x2B74, "Embedded Intelligence, Inc." }, { 0x2B75, "New Matter" }, { 0x2B76, "Shanghai Wingtech Electronic Technology Co., Ltd." }, { 0x2B77, "Epiphan Systems Inc." }, { 0x2B78, "Elyctis" }, { 0x2B79, "Radio Sound, Inc." }, { 0x2B7A, "Spin Master Far East Ltd." }, { 0x2B7B, "Gigaset Digital Technology (Shenzhen) Co., Ltd." }, { 0x2B7C, "Noveltek Semiconductor Corp." }, { 0x2B7D, "ZEITEC Semiconductor Co., Ltd." }, { 0x2B7E, "Shenzhen Kingcome Optoelectronic Co., Ltd." }, { 0x2B7F, "NanoTS Co., Ltd." }, { 0x2B80, "Miyuki Giken Co., Ltd." }, { 0x2B81, "PULAX Corporation" }, { 0x2B82, "TELE RADIO AB" }, { 0x2B83, "Silicon Line GmbH" }, { 0x2B84, "Ever Win International Corp." }, { 0x2B85, "YICHUN YILIAN PRINT TECH CO., LTD." }, { 0x2B86, "MITSUBISHI HITACHI POWER SYSTEMS ENGINEERING CO., LTD." }, { 0x2B87, "ATP Industries Group Ltd." }, { 0x2B88, "Socionext Inc." }, { 0x2B89, "Ugreen Group Limited" }, { 0x2B8A, "Shanghai Pateo Electronic Equipment Mfg. Co., Ltd." }, { 0x2B8B, "Inner Mongolia Yinan Science & Technology Dev. Co., Ltd" }, { 0x2B8C, "EDGE I&D" }, { 0x2B8D, "Dr. Fritz Faulhaber GmbH & Co. KG" }, { 0x2B8E, "Pentair PLC" }, { 0x2B8F, "DxO Labs Corp." }, { 0x2B90, "ACR Braendli & Voegeli AG" }, { 0x2B91, "The Fredericks Company" }, { 0x2B92, "i-BLADES, Inc." }, { 0x2B93, "Altia Systems Inc." }, { 0x2B94, "ShenZhen Baoyuanda Electronics Co., Ltd." }, { 0x2B95, "iST - Integrated Service Technology Inc." }, { 0x2B96, "HYUNDAI MOBIS Co., Ltd." }, { 0x2B97, "Digen Co., Ltd." }, { 0x2B98, "Glenair, Inc." }, { 0x2B99, "360fly, Inc." }, { 0x2B9A, "HUIZHOU CHENG SHUO HARDWARE PLASTIC CO., LTD." }, { 0x2B9B, "Zhongshan Aute Electronics Technology Co., Ltd." }, { 0x2B9C, "Guangdong King Link Industrial Co., Ltd." }, { 0x2B9D, "HARTING Electric GmbH & Co. KG" }, { 0x2B9E, "ZPower LLC" }, { 0x2B9F, "Scietera Technologies, Inc." }, { 0x2BA0, "InVue Security Products" }, { 0x2BA1, "I-Sheng Electric Wire & Cable Co., Ltd." }, { 0x2BA2, "China Daheng Group Inc Beijing Image Vision Tech Branch" }, { 0x2BA3, "Shenzhen FeiTianXia Technology Ltd." }, { 0x2BA4, "Shenzhen HengJia New Energy Auto Part Co., Ltd." }, { 0x2BA5, "Yueguan Network Technology (Shanghai) Co., Ltd." }, { 0x2BA6, "Cyberith GmbH" }, { 0x2BA7, "77 Elektronika Kft." }, { 0x2BA8, "YUDU EASON ELECTRONIC CO., LTD." }, { 0x2BA9, "YanFeng Visteon Automotive Electronics Co., Ltd." }, { 0x2BAA, "New World Technologies Inc." }, { 0x2BAB, "Grandstream Networks, Inc." }, { 0x2BAC, "Polyera Corporation" }, { 0x2BAD, "XinJi Technologies Ltd." }, { 0x2BAE, "Holinail H.K. Limited" }, { 0x2BAF, "Getac Technology Corp." }, { 0x2BB0, "ITES Co., Ltd." }, { 0x2BB1, "Validata LLC" }, { 0x2BB2, "HIDEX OY" }, { 0x2BB3, "Elcoa Industria e Comercio Ltda" }, { 0x2BB4, "PRINK Srl" }, { 0x2BB5, "Silk ID Systems" }, { 0x2BB6, "3D Imaging & Simulations Corp. (3DISC)" }, { 0x2BB7, "Dongguan ChengXiang Industrial Co., Ltd." }, { 0x2BB8, "OCC (Zhuhai) Electronic Co., Ltd." }, { 0x2BB9, "ARGUS-SPECTRUM" }, { 0x2BBA, "Sinseader Electronic Co., Ltd." }, { 0x2BBB, "DONGGUAN YELLOW KNIFE Industrial Co., Ltd." }, { 0x2BBC, "Guided Ultrasonics Ltd" }, { 0x2BBD, "RF Creations Ltd." }, { 0x2BBE, "Chengyi Semiconductors (Shanghai) Co., Ltd." }, { 0x2BBF, "Shenzhen Shinning Electronic Co., Ltd." }, { 0x2BC0, "Shenzhen WFD Electronics Co., Ltd." }, { 0x2BC1, "Dongguan Sino Syncs Industrial Co., Ltd." }, { 0x2BC2, "JNTC Co., Ltd." }, { 0x2BC3, "Nihon Mechatronics Co., Ltd." }, { 0x2BC4, "SR Research Ltd." }, { 0x2BC5, "Orbbec 3D Tech. Int'l Inc." }, { 0x2BC6, "Server Technology, Inc." }, { 0x2BC7, "Zounds Hearing Inc." }, { 0x2BC8, "DONGGUAN POLIXIN ELECTRIC CO., LTD." }, { 0x2BC9, "Tama Electric (Suzhou) Co., Ltd." }, { 0x2BCA, "Exvision, Inc." }, { 0x2BCB, "Tanaka Electric Industry Co., Ltd." }, { 0x2BCC, "InoTec GmbH Organisationssysteme" }, { 0x2BCD, "Keyprocessor BV" }, { 0x2BCE, "UV Partners" }, { 0x2BCF, "Magtrol, Inc." }, { 0x2BD0, "mophie, LLC" }, { 0x2BD1, "Spectran LLC" }, { 0x2BD2, "Nabtesco Corporation" }, { 0x2BD3, "Dongguan ULT-unite electronic technology co., LTD" }, { 0x2BD4, "JL Audio, Inc." }, { 0x2BD5, "Cable Matters Inc." }, { 0x2BD6, "CoroWare, Inc." }, { 0x2BD7, "EcuTek International Ltd." }, { 0x2BD8, "ROPEX Industrie-Elektronik GmbH" }, { 0x2BD9, "Huddly" }, { 0x2BDA, "Panono GmbH" }, { 0x2BDB, "LOVEOX CO., LTD." }, { 0x2BDC, "Automation Electronics Inc." }, { 0x2BDD, "Charm Sciences Inc." }, { 0x2BDE, "Pickering Interfaces Limited" }, { 0x2BDF, "Hangzhou Hikvision Digital Technology Co., Ltd." }, { 0x2BE0, "Fullink Technology Co., Ltd" }, { 0x2BE1, "AutoChips Inc." }, { 0x2BE2, "Electric Connector Technology Co., Ltd." }, { 0x2BE3, "Hydac Electronic GmbH" }, { 0x2BE4, "Cojali S.L. ES-B13210489" }, { 0x2BE5, "LELTEK" }, { 0x2BE6, "Dongguan KaiWin Electronics Co., Ltd." }, { 0x2BE7, "BEFS Co., Ltd." }, { 0x2BE8, "Archisite, Inc." }, { 0x2BE9, "Magneti Marelli S.p.A Electr BL" }, { 0x2BEA, "Inspire Medical Systems" }, { 0x2BEB, "Gateworks Corporation" }, { 0x2BEC, "Lumantek Co., Ltd." }, { 0x2BED, "Econoburn LLC" }, { 0x2BEE, "Ventev Mobile" }, { 0x2BEF, "Quanta Storage Inc." }, { 0x2BF0, "Tech-Top Technology Limited" }, { 0x2BF1, "Murakami Color Research Laboratory" }, { 0x2BF2, "ABB India Limited" }, { 0x2BF3, "Photek Ltd." }, { 0x2BF4, "Thunderbird International DBA Spectec" }, { 0x2BF5, "Shenzhen YOOBAO Technology Co., Ltd." }, { 0x2BF6, "Shenzhen Sinotek Technology Co., Ltd." }, { 0x2BF7, "KEYW" }, { 0x2BF8, "Visual Land Inc." }, { 0x2BF9, "Poynt Co." }, { 0x2BFA, "High Country Tek" }, { 0x2BFB, "Strattec Advanced Logic, LLC" }, { 0x2BFC, "Sulon Technologies Inc." }, { 0x2BFD, "Kinematics GmbH" }, { 0x2BFE, "Novexx Solutions GmbH" }, { 0x2BFF, "Shindengen Electric Mfg. Co., Ltd." }, { 0x2C00, "MEEM SL Ltd" }, { 0x2C01, "Dongguan Arin Electronics Technology Co., Ltd." }, { 0x2C02, "DongGuan City JianNuo Electronics Co., Ltd." }, { 0x2C03, "Barrett Communications Pty. Ltd." }, { 0x2C04, "Shenzhen XOX Electronics Co., Ltd." }, { 0x2C05, "Protop International Inc." }, { 0x2C06, "Microsemi Semiconductor (US) Inc." }, { 0x2C07, "Webcloak LLC" }, { 0x2C08, "INVECAS INC." }, { 0x2C09, "Prediktor Medical AS" }, { 0x2C0A, "ATANS Technology Inc." }, { 0x2C0B, "Triple Win Precision Technology Co., Ltd." }, { 0x2C0C, "IC Realtech" }, { 0x2C0D, "Embrava Pty Ltd" }, { 0x2C0E, "Unity Scientific" }, { 0x2C0F, "Mantra Softech (India) Pvt Ltd" }, { 0x2C10, "Sinotronics Co., Ltd." }, { 0x2C11, "ALLBEST ELECTRONICS TECHNOLOGY CO., LTD." }, { 0x2C12, "Shenzhen Xin Kai Feng Electronics Factory" }, { 0x2C13, "MOST WELL Technology Corp." }, { 0x2C14, "Buffalo Memory Co., Ltd." }, { 0x2C15, "Xentris Wireless" }, { 0x2C16, "Priferential Accessories Ltd" }, { 0x2C17, "SVS-VISTEK GmbH" }, { 0x2C18, "Euclideon Pty. Ltd." }, { 0x2C19, "Sunlike Technology Co., Ltd." }, { 0x2C1A, "Young Fast Optoelectronics Co., Ltd." }, { 0x2C1B, "ISAW Camera Inc" }, { 0x2C1C, "Daesung Eltec., Ltd" }, { 0x2C1D, "Makita Corporation" }, { 0x2C1E, "Global Fire Equipment S.A." }, { 0x2C1F, "Cashmaster International Limited" }, { 0x2C20, "Pulsar Instruments Plc." }, { 0x2C21, "Prynt Corp." }, { 0x2C22, "Qanba USA, LLC" }, { 0x2C23, "Super Micro Computer Inc." }, { 0x2C24, "SONOTEC Ultraschallsensorik Halle GmbH" }, { 0x2C25, "Shanghai TAIDU INTELLIGENT TECHNOLOGY CO., LTD." }, { 0x2C26, "Micromax International Corporation" }, { 0x2C27, "YAWATA Electric Industrial Co., Ltd." }, { 0x2C28, "Granite River Labs Japan Ltd." }, { 0x2C29, "Coagent Enterprise Limited" }, { 0x2C2A, "LEIA Inc." }, { 0x2C2B, "NetScout Systems, Inc." }, { 0x2C2C, "Fortify Technologies, LLC" }, { 0x2C2D, "Shenzhen Ebull Technology Limited" }, { 0x2C2E, "Hualun Technology Co., Ltd." }, { 0x2C2F, "Sensel, Inc." }, { 0x2C30, "Ariadne's Thread (USA), Inc. dba Immerex" }, { 0x2C31, "tinnos" }, { 0x2C32, "MCS Micronic Computer Systeme GmbH" }, { 0x2C33, "Shinobiya.com Co., Ltd." }, { 0x2C34, "Xerox Business Services (Switzerland) AG" }, { 0x2C35, "Decto, Inc." }, { 0x2C36, "Bonsai Lab, Inc." }, { 0x2C37, "Shenzhen Adition Audio Science & Technology Co., Ltd." }, { 0x2C38, "Goldenconn Electronics Technology (Suzhou) Co., Ltd." }, { 0x2C39, "JIB Electronics Technology Co., Ltd." }, { 0x2C3A, "Changzhou Shinco Automotive Electronics Co., Ltd." }, { 0x2C3B, "Shenzhen Hangsheng Electronics Corp., Ltd." }, { 0x2C3C, "Beartooth Radio, Inc." }, { 0x2C3D, "Audience, A Knowles Company" }, { 0x2C3E, "Verizon Telematics, Inc." }, { 0x2C3F, "Nextbit Systems, Inc." }, { 0x2C40, "Leadtrend" }, { 0x2C41, "Adaptertek Technology Co., Ltd." }, { 0x2C42, "Feature Integration Technology Inc." }, { 0x2C43, "Avegant Corporation" }, { 0x2C44, "Digital Design Corporation" }, { 0x2C45, "Reid Heath Ltd." }, { 0x2C46, "Soehnle Industrial Solutions GmbH" }, { 0x2C47, "Chunghsin International Electronics Co., Ltd." }, { 0x2C48, "Delphi Electrical Centers (Shanghai) Co., Ltd." }, { 0x2C49, "Chikuma Seiki Co., Ltd." }, { 0x2C4A, "System Industrie Electronic GmbH" }, { 0x2C4B, "Huntleigh Healthcare Ltd." }, { 0x2C4C, "Double Robotics, Inc." }, { 0x2C4D, "VVETEK DOO" }, { 0x2C4E, "Mercusys Technologies Co., Limited" }, { 0x2C4F, "Canon Electronic Business Machines (H.K.) Co., Ltd." }, { 0x2C50, "Vinghog AS" }, { 0x2C51, "Lambda Acoustic" }, { 0x2C52, "Comio Communication Co., Ltd." }, { 0x2C53, "Huizhou Foryou General Electronics Co., Ltd." }, { 0x2C54, "LifeWatch Technologies Ltd." }, { 0x2C55, "Magicleap" }, { 0x2C56, "Pocket Radar Inc." }, { 0x2C57, "BMT Messtechnik GmbH" }, { 0x2C58, "Dyden Corporation" }, { 0x2C59, "EBARA CORPORATION" }, { 0x2C5A, "Mobilus Automotive Inc" }, { 0x2C5B, "Shenglan Technology Co. Ltd" }, { 0x2C5C, "Neusoft Corporation" }, { 0x2C5D, "SIP Simya Electronics Technology Co., Ltd." }, { 0x2C5E, "ELVES Automotive Co., Ltd" }, { 0x2C5F, "YOODS Co., Ltd." }, { 0x2C60, "Sirin LABS AG" }, { 0x2C61, "Jadmam Corporation dba: Boytone" }, { 0x2C62, "Trice Medical" }, { 0x2C63, "Electronica Steren, S.A. de C.V." }, { 0x2C64, "Creaform Inc. (Ametek Ultra Precision Technologies)" }, { 0x2C65, "Nokia Technologies" }, { 0x2C66, "EMOTIQ srl" }, { 0x2C67, "VentureCraft, Ltd." }, { 0x2C68, "EMRight Technology Co., Ltd." }, { 0x2C69, "BBPOS Limited" }, { 0x2C6A, "Joint Stock Company Research Centre Module" }, { 0x2C6B, "System JD Co., Ltd" }, { 0x2C6C, "Nano TouchSystems co., Ltd." }, { 0x2C6D, "Gibson Innovations" }, { 0x2C6E, "Shen Zhen Xian Shuo Technology Co. Ltd." }, { 0x2C6F, "PST Eletronica LTDA" }, { 0x2C70, "PERI, Inc." }, { 0x2C71, "Bozhou BoTong Information Technology Co., Ltd." }, { 0x2C72, "BlueberryE GmbH" }, { 0x2C73, "Qiku Internet Network Scientific (Shenzhen) Co., Ltd." }, { 0x2C74, "CJSC Nordavind" }, { 0x2C75, "Net And Print Inc." }, { 0x2C76, "DATAPATH LTD" }, { 0x2C77, "Profindustry GmbH" }, { 0x2C78, "BRAGI GmbH" }, { 0x2C79, "WAWGD, Inc. (DBA: Foresight Sports)" }, { 0x2C7A, "AutoNavi Software Co., Ltd." }, { 0x2C7B, "Beijing ASU Tech Co., Ltd." }, { 0x2C7C, "Anysmart Technologies Co., Ltd." }, { 0x2C7D, "Shenzhen Protruly Electronic Co., Ltd." }, { 0x2C7E, "Dongguan Allpass Electronic Co., Ltd." }, { 0x2C7F, "SHENZHEN D-VITEC INDUSTRIAL CO., LTD." }, { 0x2C80, "motomobile AG" }, { 0x2C81, "Indie Semiconductor" }, { 0x2C82, "Cloud9 Technologies LLC" }, { 0x2C83, "LRP electronic GmbH" }, { 0x2C84, "Innodezign MauRitius Limited" }, { 0x2C85, "Audientes" }, { 0x2C86, "Ultraflux" }, { 0x2C87, "ISKN" }, { 0x2C88, "K-Tronic SRL" }, { 0x2C89, "Younes Medical Technologies" }, { 0x2C8A, "Advanced Casino Electronics" }, { 0x2C8B, "Huizhou Dehong Technology Co., Ltd." }, { 0x2C8C, "PowerCenter Technology Limited" }, { 0x2C8D, "Mizco International, Inc." }, { 0x2C8E, "Unique Secure Limited" }, { 0x2C8F, "Regulus Company Ltd." }, { 0x2C90, "I. AM. PLUS, LLC" }, { 0x2C91, "Corigine, Inc." }, { 0x2C92, "Ningbo Yinzhou Shengke Electronics Co., Ltd." }, { 0x2C93, "SWFL Inc. dba: Filament" }, { 0x2C94, "HIRATSUKA Engineering Co., Ltd." }, { 0x2C95, "TOSHIBA MACHINE CO., LTD." }, { 0x2C96, "KBS Industrieelektronik GmbH" }, { 0x2C97, "LEDGER" }, { 0x2C98, "Fosfomatic Technology LLC" }, { 0x2C99, "Prusa Research s.r.o." }, { 0x2C9A, "Lawo AG" }, { 0x2C9B, "SPECIM, Spectral Imaging Ltd." }, { 0x2C9C, "Vayyar Imaging LTD." }, { 0x2C9D, "Nod Inc." }, { 0x2C9E, "Shanghai Linguo Technology Co.,Ltd." }, { 0x2C9F, "e-Smart Systems Pvt. Ltd." }, { 0x2CA0, "Leagtech Jiangxi Electronic Co., Ltd." }, { 0x2CA1, "Veetone Technologies Limited" }, { 0x2CA2, "GuangZhou MingPing Electronics Technology" }, { 0x2CA3, "DJI Technology Co., Ltd." }, { 0x2CA4, "Shenzhen Alex Technology Co., Ltd." }, { 0x2CA5, "Fussen Technology Co., Ltd." }, { 0x2CA6, "Dai-ichi Dentsu Ltd." }, { 0x2CA7, "Heptagon Advanced Micro Optics" }, { 0x2CA8, "STATSports" }, { 0x2CA9, "JITS TECHNOLOGY CO., LIMITED" }, { 0x2CAA, "LIVV Brand llc" }, { 0x2CAB, "AppWorld S. de R.L. de C.V." }, { 0x2CAC, "MGF Sviesos Konversija, UAB" }, { 0x2CAD, "EMS Security Group Ltd." }, { 0x2CAE, "Clyde Broadcast Products Ltd." }, { 0x2CAF, "IDS GmbH" }, { 0x2CB0, "Creative bits Solutions" }, { 0x2CB1, "Avista Corporation" }, { 0x2CB2, "NAGANO KEIKI CO., LTD." }, { 0x2CB3, "Shenzhen Bolin Image Science Technology Co., Ltd." }, { 0x2CB4, "Ava Enterprises, Inc. dba Boss Audio Systems" }, { 0x2CB5, "SUS Corp." }, { 0x2CB6, "Borqs Hong Kong Limited" }, { 0x2CB7, "Fibocom Wireless Inc." }, { 0x2CB8, "Shenzhen Sydixon Electronic Technology Co., Ltd." }, { 0x2CB9, "On-Bright Electronics (Shanghai) Co., Ltd." }, { 0x2CBA, "Dongguan Puxu Industrial Co., Ltd." }, { 0x2CBB, "Shenzhen Soling Indusrtial Co., Ltd." }, { 0x2CBD, "EGGCYTE, INC." }, { 0x2CBE, "uQontrol" }, { 0x2CBF, "Donggguan Yuhua Electronic Co., Ltd." }, { 0x2CC0, "Hangzhou Zero Zero Technology Co., Ltd." }, { 0x2CC1, "SIGFOX" }, { 0x2CC2, "Lautsprecher Teufel GmbH" }, { 0x2CC3, "A-VEKT K.K." }, { 0x2CC4, "Sanden Advanced Technology Corporation" }, { 0x2CC5, "Metatronics" }, { 0x2CC6, "Prodigy Technovations Pvt Ltd" }, { 0x2CC7, "EmergiTech, Inc" }, { 0x2CC8, "Hewlett Packard Enterprise" }, { 0x2CC9, "Monolithic Power Systems Inc." }, { 0x2CCA, "Amphenol Advanced Sensors" }, { 0x2CCB, "USB Memory Direct" }, { 0x2CCC, "Silicon Mitus Inc." }, { 0x2CCD, "ITOS Inc." }, { 0x2CCE, "SMARTY Performance King SA" }, { 0x2CCF, "Hypersecu Information Systems, Inc." }, { 0x2CD0, "Technics Global Electronics & JCE Co., Ltd." }, { 0x2CD1, "Tamron Co., Ltd." }, { 0x2CD2, "Mikrotikls S/A" }, { 0x2CD3, "Life Robotics Inc." }, { 0x2CD4, "NGK SPARK PLUG CO., LTD." }, { 0x2CD5, "Institut Dr. Foerster GmbH & Co. KG" }, { 0x2CD6, "Immersive Media" }, { 0x2CD7, "Cosemi Technologies Inc." }, { 0x2CD8, "Nanoport Technology, Inc." }, { 0x2CD9, "Cambrionix Ltd" }, { 0x2CDA, "CXUN Co. Ltd." }, { 0x2CDB, "China Tsp Inc" }, { 0x2CDC, "Sea & Sun Technology GmbH" }, { 0x2CDD, "IAI Corporation" }, { 0x2CDE, "RTI International" }, { 0x2CDF, "Tecno Alarm S.R.L." }, { 0x2CE0, "iClassmate Educational Technologies Co., Ltd." }, { 0x2CE1, "Gradus Group" }, { 0x2CE2, "Yanfeng Visteon (Chongqing) Automotive Electronics Co" }, { 0x2CE3, "Alcorlink Corp." }, { 0x2CE4, "ISBC Ltd." }, { 0x2CE5, "InX8 Inc dba AKiTiO" }, { 0x2CE6, "SDAN Tecchnology Co., Ltd." }, { 0x2CE7, "Lemobile Information Technology (Beijing) Co., Ltd." }, { 0x2CE8, "DongGuan Hongweixiang Electronic Technology Co., Ltd." }, { 0x2CE9, "Suzhu Jingshi Electronic Technology Co., Ltd." }, { 0x2CEA, "Zhong Shan City Richsound Electronic Industrial Ltd." }, { 0x2CEB, "Dongguang Kangbang Electronics Co., Ltd." }, { 0x2CEC, "Ascon Tecnologic" }, { 0x2CED, "KMC Controls, Inc." }, { 0x2CEE, "Winpower Qmadix Technology Co., Ltd." }, { 0x2CEF, "Toptest Technologies Co., Ltd." }, { 0x2CF0, "Nuand, LLC" }, { 0x2CF1, "DTS, Inc." }, { 0x2CF2, "KUNSHAN DLK Electronics Technology Co., Ltd." }, { 0x2CF3, "Konekt, Inc." }, { 0x2CF4, "CAM2 Technologies, LLC dba: Czitek" }, { 0x2CF5, "EBARA REFRIGERATION EQUIPMENT & SYSTEMS CO., LTD." }, { 0x2CF6, "Eye-Fi, Inc." }, { 0x2CF7, "PPST, Inc." }, { 0x2CF8, "Itron" }, { 0x2CF9, "Terrafix Ltd." }, { 0x2CFA, "Meta Company" }, { 0x2CFB, "Nanchang Haozhun Electronics Co., Ltd." }, { 0x2CFC, "DeLaval International AB" }, { 0x2CFD, "GoerTek Inc." }, { 0x2CFE, "Alpha Data Parallel Systems" }, { 0x2CFF, "ITHAKi" }, { 0x2D00, "VDO Cyclecomputing, Cycle Parts GmbH" }, { 0x2D01, "Gopod Group Limited" }, { 0x2D02, "Zhi Sheng Electronics Technology Co., Ltd." }, { 0x2D03, "ECCO Safety Group" }, { 0x2D05, "Technology Solutions (UK) Limited" }, { 0x2D06, "Jireh Industries Ltd." }, { 0x2D07, "MSI.TOKYO, Inc." }, { 0x2D08, "ZIT Ltd." }, { 0x2D09, "Dongguan Evervictory Electronic Co., Ltd." }, { 0x2D0A, "Kingsignal Technology Co., Ltd." }, { 0x2D0B, "IPD CO., LTD" }, { 0x2D0C, "B & P Automation Dynamics Ltd" }, { 0x2D0D, "Star Vision Electronics Limited" }, { 0x2D0E, "Linxee (Beijing) Technology LTD." }, { 0x2D0F, "M8TRIX TECH LLC" }, { 0x2D10, "Shenzhen San Guan Si Yuan Technology Limited" }, { 0x2D11, "Servelec Technologies" }, { 0x2D12, "SICPA Security Solutions SA" }, { 0x2D13, "DONG GUAN EBEN ELECTRONIC CO., LTD" }, { 0x2D14, "Palit Microsystems Ltd" }, { 0x2D15, "Si-Ware Systems" }, { 0x2D16, "DONGGUAN WELLINK ELECTRONIC CO., LTD." }, { 0x2D17, "TECHVIWIN INTERNATIONAL (HONGKONG) LIMITED" }, { 0x2D18, "Hui Zhou Kai Yue Electronics Co., Ltd" }, { 0x2D19, "Churchill Navigation" }, { 0x2D1A, "Phononic" }, { 0x2D1B, "Suzhou Yourfriend Electronic Co., Ltd." }, { 0x2D1C, "Club 3D BV" }, { 0x2D1D, "Design Pool Limited" }, { 0x2D1E, "Excalibur" }, { 0x2D1F, "Wacom Taiwan Information Co. Ltd." }, { 0x2D20, "UL LLC" }, { 0x2D21, "Koozyt, Inc." }, { 0x2D22, "SEIKOSHA Co., Ltd." }, { 0x2D23, "Shenzhen Microtest Automation Co., Ltd." }, { 0x2D24, "Warwick Audio Technologies Ltd" }, { 0x2D25, "Kronegger GmbH" }, { 0x2D26, "Greenfield Technology" }, { 0x2D27, "Global Optics Limited" }, { 0x2D28, "Beijing ANTVR Technology Co., LTD" }, { 0x2D29, "Beijing Baofengmojing Technologies Co. Ltd" }, { 0x2D2A, "Shenzhen ZDT Technology Co., LTD" }, { 0x2D2B, "STYL Solutions Pte Ltd" }, { 0x2D2C, "Tankya Developing Co., Limited" }, { 0x2D2D, "Guangzhou Botao Information Technology Co., Ltd" }, { 0x2D2E, "Hieyoung International (Hong Kong) Limited" }, { 0x2D2F, "PT Phototechnics AG" }, { 0x2D30, "Addasound Denmark A/S" }, { 0x2D31, "Synox Tech Co., Ltd." }, { 0x2D32, "JR Technik Co., Ltd." }, { 0x2D33, "Elysia-raytest GmbH" }, { 0x2D34, "Nureva Inc." }, { 0x2D35, "SIGMA TECH. CO., LTD" }, { 0x2D36, "Blu5 View Pte. Ltd." }, { 0x2D37, "Xprinter Co., Ltd" }, { 0x2D38, "Shanghai OXi Technology Co., Ltd" }, { 0x2D39, "Roofer Technology (Shenzhen) Co. Ltd" }, { 0x2D3A, "Le Touch (Shenzhen) Electronics Co., Ltd." }, { 0x2D3B, "Lencheng Electronics Co., Ltd" }, { 0x2D3C, "FOVE, Inc." }, { 0x2D3D, "Battlespace Simulations, Inc." }, { 0x2D3E, "Technica Del Arte BV" }, { 0x2D3F, "ViCentra B.V." }, { 0x2D40, "Beijing Pico Technology Co., Ltd." }, { 0x2D41, "Dongguan Mankind Plastic Electronics Co., Ltd" }, { 0x2D42, "Protech Electronics & Technology Limited" }, { 0x2D43, "OSSIC Corporation" }, { 0x2D44, "FAMAR FUEGUINA S.A." }, { 0x2D45, "JSC TION SMART MICROCLIMATE" }, { 0x2D46, "JSC Yukon Advanced Optics Worldwide" }, { 0x2D47, "INVENCO GROUP LIMITED" }, { 0x2D48, "StarBridge, Inc." }, { 0x2D49, "Shanghai Deepoon Technology Co., Ltd." }, { 0x2D4A, "Helioway Enterprises Co., Ltd" }, { 0x2D4B, "Dongguan Hongwei Electronics Co.,Ltd" }, { 0x2D4C, "Ixtra Tech Inc" }, { 0x2D4D, "Razer Inc" }, { 0x2D4E, "Electronic Equipment BV" }, { 0x2D4F, "Dongguan Hanker Electronic Technology Co., Ltd." }, { 0x2D50, "CryLaS - Crystal Laser Systems GmbH" }, { 0x2D51, "NITTA Corporation" }, { 0x2D52, "YiQin Electronics Co.,Ltd" }, { 0x2D53, "OWOW Products B.V." }, { 0x2D54, "C-Smartlink Information Technology Co., Ltd." }, { 0x2D55, "Nagravision SA" }, { 0x2D56, "DongGuan Kelta Electro Mechanical Products CO, LTD" }, { 0x2D58, "Lyra Semiconductor Incorporated" }, { 0x2D59, "Sunyking Technology Co., Ltd" }, { 0x2D5A, "Shenzhen YAAN Precision Connector Co., Ltd." }, { 0x2D5B, "SunTo Technology (Shen Zhen) Corporation Limited" }, { 0x2D5C, "Daiwoo Electronics Lo., LTD" }, { 0x2D5D, "Loctek Ergonomic Technology Corp." }, { 0x2D5E, "Sky UK Limited" }, { 0x2D5F, "Shanghai Yuewen information technology Co., Ltd." }, { 0x2D60, "Comarch S.A." }, { 0x2D61, "Shenzhen Hongjixin Plastic & Electronics Co., Ltd" }, { 0x2D62, "Weifang Genius Electronics Co.,Ltd." }, { 0x2D63, "Cable Technology Corp." }, { 0x2D64, "H.D.T. S.R.L" }, { 0x2D65, "DPA Microphones" }, { 0x2D66, "Oley Company Limited" }, { 0x2D67, "Fengfan (Suzhou) Audio Technology Co., Ltd." }, { 0x2D68, "Lumulabs d.o.o." }, { 0x2D6A, "AIPHONE Co., LTD" }, { 0x2D6B, "NetUP Inc." }, { 0x2D6C, "Sphericam Inc." }, { 0x2D6D, "Shenzhen HaiWei Technology Co., LTD" }, { 0x2D6E, "Jiangsu Jing Lian Electronic Technology Co., Ltd" }, { 0x2D6F, "Tobii Dynavox" }, { 0x2D70, "Zhongshan Winner Electronic Technology CO., LTD" }, { 0x2D71, "OVERKIZ" }, { 0x2D72, "DOGAWIST - Investment GmbH" }, { 0x2D73, "XtremeMac Sarl" }, { 0x2D74, "CMO America; dba ZipKord Solutions" }, { 0x2D75, "Shenzhen Taiji Electronics Co., Ltd." }, { 0x2D76, "SiliConch Systems Private Limited" }, { 0x2D77, "SweDeltaco AB" }, { 0x2D78, "Dental Imaging Technology Corporation" }, { 0x2D79, "Shenzhen Legendary Technologies Co., LTD." }, { 0x2D7A, "Dongguan JingFeng Electronics Technology Co., Ltd" }, { 0x2D7B, "Panasonic Lighting Americas, Inc." }, { 0x2D7C, "Dongguan City Qingda Electronic Co., Ltd." }, { 0x2D7D, "Televes S.A." }, { 0x2D7E, "NISSIN ELECTRIC Corporation" }, { 0x2D7F, "Sinar Photography AG" }, { 0x2D80, "Pendo Technology China Corporation" }, { 0x2D81, "Evollve Inc." }, { 0x2D82, "boud" }, { 0x2D84, "Zhuhai J-Speed Technology Co., Ltd." }, { 0x2D85, "Asahi Electronics Laboratory" }, { 0x2D86, "Dongguan Team Force Electronic Co., Ltd" }, { 0x2D87, "Zhuhai Spark Electronic Equipment Co., Ltd" }, { 0x2D88, "Prinics Co., Ltd." }, { 0x2D89, "Ekahau" }, { 0x2D8A, "I-O Conn (GuangDong) Technologies Co., Ltd" }, { 0x2D8B, "Eclatkey Semiconductor Technology Company Limited" }, { 0x2D8C, "Hongrida Electronic Technology Co. LTD" }, { 0x2D8D, "MISUMI Corporation" }, { 0x2D8E, "Color Sentinel Systems, LLC" }, { 0x2D8F, "Shenzhen Bing Chuang Wei Technology Co., Ltd." }, { 0x2D90, "Humanplus" }, { 0x2D91, "SDI Technologies Inc." }, { 0x2D92, "Shanghai Fengtian Electronic Co., LTD." }, { 0x2D93, "STK TECHNOLOGY CO., LTD." }, { 0x2D94, "TokenWorks Inc." }, { 0x2D95, "Vivo Mobile Communication Co., Ltd." }, { 0x2D96, "SHENZHEN WAMAXLINK ELECTRONIC TECHNOLOGY CO., LTD" }, { 0x2D97, "Dong Guan JingHe Electronics Technology Co., Ltd" }, { 0x2D98, "Shenzhen Ruiming Technology Co., Ltd." }, { 0x2D99, "Edifier International Limited" }, { 0x2D9A, "Jiangsu GuoGuang Electronic Information Technology Co.," }, { 0x2D9B, "iStorage Limited" }, { 0x2D9C, "Global Connector Technology" }, { 0x2D9D, "Dongguan Suntes Electronics Technology Co., Ltd." }, { 0x2D9E, "Sivantos GmbH" }, { 0x2D9F, "SABRENT" }, { 0x2DA0, "IN-VISION Digital Imaging Optics GmbH" }, { 0x2DA1, "Koden Electronics Co., Ltd" }, { 0x2DA2, "CIMA SPA con socio unico" }, { 0x2DA3, "Superior Communications" }, { 0x2DA4, "GE Multilin" }, { 0x2DA5, "Tokai Rika Create Corporation" }, { 0x2DA6, "SiChuan Rui Thai Electronic Technology Co., Ltd." }, { 0x2DA7, "Topland Corporation" }, { 0x2DA8, "Harmonic Drive Systems Inc." }, { 0x2DA9, "ELECTRONIC ASSEMBLY GmbH" }, { 0x2DAA, "Shenzhen Jing Tuo Jin Electronics Co., Ltd." }, { 0x2DAB, "CYD Electronics (Shenzhen) Co., Ltd." }, { 0x2DAC, "Shenzhen YZB Electronics Technology Co., Ltd" }, { 0x2DAD, "GoerTek Dynaudio Co., Ltd" }, { 0x2DAE, "Hex Technology Limited" }, { 0x2DAF, "IF Link Electronics Co Limited" }, { 0x2DB0, "Shenzhen Welltech Cable Co., Ltd" }, { 0x2DB1, "DongGuan Greatek Electronics Technology Co., LTD" }, { 0x2DB2, "Imperx, Inc" }, { 0x2DB3, "i Digital Galaxy Ltd." }, { 0x2DB4, "Dongguan Changtuo Hardware Technology Co., Ltd." }, { 0x2DB5, "Fuji Ceramics Corporation" }, { 0x2DB6, "Kunshan 3e Electronics Co., Ltd." }, { 0x2DB7, "Premium Sound Solutions Sdn. Bhd." }, { 0x2DB8, "Foshan Yami Electric Ltd." }, { 0x2DB9, "Danelec Marine A/S" }, { 0x2DBA, "Houwa System Design, k.k" }, { 0x2DBB, "Huajie IMI Technology Co., Ltd." }, { 0x2DBC, "Mikroelektronika d.o.o" }, { 0x2DBD, "Shanghai Xiaoyi Technology Co., Ltd" }, { 0x2DBE, "MA Lighting Technology GmbH" }, { 0x2DBF, "Tul Corporation" }, { 0x2DC0, "Chipsea Technologies (Shenzhen) Corp" }, { 0x2DC1, "littleBits" }, { 0x2DC2, "MintWave Co., Ltd." }, { 0x2DC3, "Action Industries (M) SDN BHD" }, { 0x2DC4, "Six 15 Technologies" }, { 0x2DC5, "Cytek Biosciences, Inc." }, { 0x2DC6, "Dongguan Kingtron Electronics Technology Co., Ltd." }, { 0x2DC7, "Lacroix Sofrel" }, { 0x2DC8, "8BITDO TECHNOLOGY HK LIMITED" }, { 0x2DC9, "3T B.V." }, { 0x2DCA, "OEM Systems Co., Ltd." }, { 0x2DCB, "i-Money Technology Co., Ltd." }, { 0x2DCC, "Suzhou Keda Technology Co., Ltd." }, { 0x2DCD, "Yeonho Electronics" }, { 0x2DCE, "Shen Zhen Farmer Technology Co., Limited" }, { 0x2DCF, "Dialog Semiconductor (UK) Ltd" }, { 0x2DD0, "iBaby Labs, Inc" }, { 0x2DD1, "Empathy Co., Ltd." }, { 0x2DD2, "HARNICS Co., LTD." }, { 0x2DD3, "Viscell, LLC" }, { 0x2DD5, "Gingy Technology Inc." }, { 0x2DD6, "Suzhou SuperMax Smart System Co., Ltd." }, { 0x2DD7, "enRoute Co., Ltd." }, { 0x2DD8, "Perception Sensors and Instrumentation Ltd" }, { 0x2DD9, "Dong Guan Fei Tai Electronics CO., LTD." }, { 0x2DDA, "Miura Systems Ltd" }, { 0x2DDB, "Shenzhen DAK Technology Co., Ltd" }, { 0x2DDC, "Audiolink Co., Ltd" }, { 0x2DDD, "Princeton Infrared Technologies, Inc." }, { 0x2DDE, "The Chamberlain Group, Inc." }, { 0x2DDF, "BOMTECH ELECTRONICS CO., LTD." }, { 0x2DE0, "Active-semi, Inc" }, { 0x2DE1, "Jiang Su Denseting Precision Technology Co., Ltd." }, { 0x2DE2, "PathPartner Technology Pvt. Ltd" }, { 0x2DE3, "Shanghai Yitu Technology Co., Ltd." }, { 0x2DE4, "Best Case and Accessories, Inc." }, { 0x2DE5, "KaiJet Technology International Limited, Inc. dba j5create" }, { 0x2DE6, "Amazon Fulfillment Services, Inc." }, { 0x2DE7, "The LightCo, Inc." }, { 0x2DE8, "Shenzhen City Xiaoduan Electrical Co., LTD." }, { 0x2DE9, "CAR MATE MFG. CO., LTD." }, { 0x2DEA, "LightFactor" }, { 0x2DEB, "Hold-Key Electric Wire & Cable Co Ltd" }, { 0x2DEC, "ZNi Technology Co., Ltd" }, { 0x2DED, "Aquil Star Precision Industrial (Shenzhen) Co., Ltd" }, { 0x2DEE, "Shenzhen MeiG Smart Technology Co., Ltd" }, { 0x2DEF, "Kirale Technologies SL" }, { 0x2DF0, "CANVASBIO CO., LTD" }, { 0x2DF1, "Inovonics Corp" }, { 0x2DF2, "LIPS Corporation" }, { 0x2DF3, "LongSung Technology (Shanghai) Co., Ltd." }, { 0x2DF4, "Jumplux Technology Co., Ltd." }, { 0x2DF5, "Helium Systems Inc." }, { 0x2DF6, "Greektown Casino-Hotel, LLC" }, { 0x2DF7, "Fastwel Group Ltd." }, { 0x2DF8, "ITEST" }, { 0x2DF9, "EZQuest, Inc." }, { 0x2DFA, "3DRUDDER" }, { 0x2DFB, "Bren-Tronics, Inc." }, { 0x2DFC, "Graphic Products" }, { 0x2DFD, "Ubisoft Entertainment SA" }, { 0x2DFE, "Next Thing Co." }, { 0x2DFF, "Unicept GmbH" }, { 0x2E00, "CIB Security Inc" }, { 0x2E01, "Symetrix, Inc." }, { 0x2E02, "Softiron" }, { 0x2E03, "Zhejiang Dahua Technology Co., Ltd." }, { 0x2E04, "HMD Global Oy" }, { 0x2E05, "CKD Corporation" }, { 0x2E06, "Shenzhen Junlan Electronic Ltd" }, { 0x2E07, "Lafayette Instrument Company" }, { 0x2E08, "Zhongshan Dumei Weite Electronics Co., Ltd" }, { 0x2E09, "Beijing LLVision Technology Co. LTD" }, { 0x2E0A, "Dytran Instruments" }, { 0x2E0B, "Datafield Industries (HK) Ltd" }, { 0x2E0C, "Shenzhen Mek Intellisys PTE Ltd" }, { 0x2E0D, "Suzhou FanglinTechnology Co., Ltd" }, { 0x2E0E, "Hatteland Display AS" }, { 0x2E0F, "Institute for Defense Analyses / Center for Computing Sciences" }, { 0x2E10, "LinkMTech Inc." }, { 0x2E11, "ShenZhen ShenTai WeiXiang Electronics Co., Ltd" }, { 0x2E12, "Hongkong Chenyang Electronic Co., Limited" }, { 0x2E13, "Intelligent Automation (Zhuhai) Co., Ltd" }, { 0x2E14, "Expressive" }, { 0x2E15, "Now Technologies" }, { 0x2E16, "Glosys Inc." }, { 0x2E17, "Essential Products, Inc." }, { 0x2E18, "NorthStar Battery Company, LLC" }, { 0x2E19, "Additel Corporation" }, { 0x2E1A, "Shenzhen Arashi Vision Company Limited" }, { 0x2E1B, "BeiJie Electronics Technology Co., Ltd" }, { 0x2E1C, "Shenzhen Auto-Link World Information Technology Co., Ltd." }, { 0x2E1D, "Clarion (Malaysia) Sdn. Bhd." }, { 0x2E1E, "Sound Technology (C.Q.) Co., Ltd" }, { 0x2E1F, "BrainScope Company, Inc." }, { 0x2E20, "Guangzhou Long Do Co.,Ltd" }, { 0x2E21, "DOSCH&AMAND Research GmbH&CoKG" }, { 0x2E22, "DongGuan LinSong precision electronics CO., LTD" }, { 0x2E23, "Shenzhen Baojia Battery Technology Co., Ltd." }, { 0x2E24, "Hyperkin Inc." }, { 0x2E25, "Gold Cable (Zhongshan) Electronic Co., Ltd." }, { 0x2E26, "Monoprice, Inc." }, { 0x2E27, "Lion Semiconductor" }, { 0x2E28, "VOLTRONIC POWER TECHNOLOGY CORP." }, { 0x2E29, "Clas Ohlson AB" }, { 0x2E2B, "Shenzhen Qinps Technology Co Limited" }, { 0x2E2C, "Dashine Electronics Co, Ltd" }, { 0x2E2D, "Anaren Inc." }, { 0x2E2E, "First Design System Inc." }, { 0x2E2F, "Gulden Ophthalmics, Inc." }, { 0x2E30, "Andon Health Co., Ltd." }, { 0x2E31, "Thine Electronics, Inc." }, { 0x2E32, "Shenzhen Red Star Electronics Co., Ltd." }, { 0x2E33, "Squarehead Technology" }, { 0x2E34, "ALLDATA LLC" }, { 0x2E35, "Shenzhen PYS Industrial Co., LTD" }, { 0x2E36, "Depo Electronics Limited" }, { 0x2E37, "IRISO ELECTRONICS CO., LTD" }, { 0x2E38, "OHM ELECTRONIC INC." }, { 0x2E39, "Epic Tech, LLC" }, { 0x2E3A, "Nanaboshi Electric Mfg. Co., Ltd." }, { 0x2E3B, "uSens Inc" }, { 0x2E3C, "ARTERY Technology Co., Ltd." }, { 0x2E3D, "ASWAN ELEC. SALES CO., LTD." }, { 0x2E3E, "Karma Automotive" }, { 0x2E3F, "Poly-Planar Group LLC" }, { 0x2E40, "Mobile Technologies Inc" }, { 0x2E41, "DONGGUAN RONGDEKANG ELECTRONIC TECHNOLOGY CO., LTD." }, { 0x2E42, "Hunan Ronghe Microelectronics Co., Ltd." }, { 0x2E43, "Owl Labs, Inc" }, { 0x2E44, "Idealens Technology (Chengdu) Co., Ltd." }, { 0x2E45, "Widex A/S" }, { 0x2E46, "Mobileconn Technology Co., Ltd." }, { 0x2E47, "X-Media Tech, Inc." }, { 0x2E48, "Andromium Inc." }, { 0x2E49, "A&T Corporation" }, { 0x2E4A, "Xiamen Jinhaode Electronic Co., Ltd" }, { 0x2E4B, "ART SPA" }, { 0x2E4C, "Carter Duncan Corp." }, { 0x2E4D, "Vinpower, Inc." }, { 0x2E4E, "METER Group, Inc" }, { 0x2E4F, "Audiotec Fischer GmbH" }, { 0x2E50, "beyerdynamic GmbH & Co. KG" }, { 0x2E51, "EVER Sp. Z.o.o." }, { 0x2E52, "Toughbuilt Industries Inc" }, { 0x2E53, "Shenzhen East-Toptech Electronic Technology Co., Ltd" }, { 0x2E54, "Yin Run Precise Metal Products CO., LTD." }, { 0x2E55, "FIP Formatura Iniezione Polimeri an Aliaxis Company" }, { 0x2E56, "Juchin Technology (JIANGXI) Co., Ltd" }, { 0x2E57, "MEGWARE Computer Vertrieb und Service GmbH" }, { 0x2E58, "GONGNIU GROUP CO., LTD." }, { 0x2E59, "Maui Imaging, Inc." }, { 0x2E5A, "Mysher Technology Co., Ltd." }, { 0x2E5B, "Fitipower Integrated Technology Inc." }, { 0x2E5C, "Y.H.S. Co., Ltd" }, { 0x2E5D, "Dong Guan LM-Link Precise Electronic Co., Ltd." }, { 0x2E5E, "Mei Shun He Electronic Limited" }, { 0x2E5F, "Shenzhen BTC Technology Co., Ltd." }, { 0x2E60, "castAR, Inc." }, { 0x2E61, "NetBurner, Inc." }, { 0x2E62, "Will Semiconductor Co., LTD" }, { 0x2E63, "Polaris-Labs Shenzhen Co., Ltd" }, { 0x2E64, "Shenzhen Kaibao Technology Co., Ltd." }, { 0x2E65, "Kunshan Xintaili Precision Components Co., Ltd." }, { 0x2E66, "SALICRU, S.A." }, { 0x2E67, "Elevation Lab, Inc." }, { 0x2E68, "Tessonics Inc." }, { 0x2E69, "Swift Navigation Inc" }, { 0x2E6A, "Wilderness Labs Inc." }, { 0x2E6B, "DMX, LLC dba Mood Media" }, { 0x2E6C, "Uwatec AG" }, { 0x2E6D, "Laser Argentina S.A." }, { 0x2E6E, "E4D Technologies LLC" }, { 0x2E6F, "Areca Technology Corporation" }, { 0x2E70, "Revision Electronics & Power Systems Inc." }, { 0x2E71, "Futurepath Electronics Technology (Dongguan) Co., Ltd." }, { 0x2E72, "DongGuan YongHao Electronics Co., LTD" }, { 0x2E73, "Backyard Brains" }, { 0x2E74, "Magenta Labs Inc." }, { 0x2E75, "Shanghai Hinge Electronic Technologies Co., Ltd." }, { 0x2E76, "Guangdong Jinrun Electronics Co., Ltd." }, { 0x2E77, "LOGICDATA Electronics & Software Entwicklungs GmbH" }, { 0x2E78, "ES Gear Ltd." }, { 0x2E79, "NP System Development Co., Ltd." }, { 0x2E7A, "Jiangsu BDSTAR Navigation Electronic Co., Ltd." }, { 0x2E7B, "Terrada Music Score CO., Ltd." }, { 0x2E7C, "Pyramid Solutions" }, { 0x2E7D, "Shenzhen Xin Yong Yang Technology Co., Ltd." }, { 0x2E7E, "ValueHD Corporation" }, { 0x2E7F, "Aries Manufacturing - a division of Boss Tech Products Inc." }, { 0x2E80, "Join Tek Corporation Co., Ltd." }, { 0x2E81, "Zodiac Inflight Innovations" }, { 0x2E82, "Sapphire Technology Limited" }, { 0x2E83, "Ocean Tek Enterprise Co., Ltd." }, { 0x2E84, "Sheng San Electronics (Shen Zhen) Co., Ltd." }, { 0x2E85, "Verizon" }, { 0x2E86, "SBO HEARING A/S" }, { 0x2E87, "Shenzhen Injoinic Technology Co., Ltd." }, { 0x2E88, "Huada Semiconductor Corporation Limited" }, { 0x2E89, "Group Dekko, Inc." }, { 0x2E8A, "Raspberry Pi (Trading) Limited" }, { 0x2E8B, "Asia Optical International Ltd." }, { 0x2E8C, "Aisino Wincor Manufacturing (Shanghai) Co., Ltd." }, { 0x2E8D, "YSC Science Technique Electron (Yi Chun) Co., Ltd" }, { 0x2E8E, "Bitatek CO., LTD" }, { 0x2E8F, "Shenzhen Weiduli Technology Co., Ltd." }, { 0x2E90, "Wireless Media Tech CO., Limited" }, { 0x2E91, "Shenzhen Suprint Smart Technology Co., Ltd." }, { 0x2E92, "bioMerieux, Inc." }, { 0x2E93, "Shenzhen Huikeyuan Electronic Technology Co., Ltd." }, { 0x2E94, "Graviton Inc." }, { 0x2E95, "Scuf Gaming International, LLC" }, { 0x2E96, "Aspect Microsystems Corp." }, { 0x2E97, "Aerocool Advanced Technologies Corporation" }, { 0x2E98, "Nekteck, Inc." }, { 0x2E99, "Hynetek Semiconductor Co., Ltd" }, { 0x2E9A, "MS Solutions Co., Ltd." }, { 0x2E9B, "New Imaging Technologies" }, { 0x2E9C, "Shenzhen Silkway Technology Co., Ltd." }, { 0x2E9D, "Resolved Instruments Inc." }, { 0x2E9E, "SoundAI Technology Co., Ltd." }, { 0x2E9F, "EyeTech Digital Systems, Inc." }, { 0x2EA0, "Magnescale Co., Ltd." }, { 0x2EA1, "DASANELECTRON CO., LTD" }, { 0x2EA2, "Ningbo Kangda Electronic Co., Ltd." }, { 0x2EA3, "POSLAB Technology Corporation" }, { 0x2EA4, "Hubbell Incorporated (Delaware), Wiring Device Kellems Division" }, { 0x2EA5, "Dongguanshi Qitaiprecision Moulds Co., Ltd." }, { 0x2EA6, "Foreign Trade Corporation dba. Technocel" }, { 0x2EA7, "Muhanbit" }, { 0x2EA8, "Changsha JingJia Microelectronics Co., LTD." }, { 0x2EA9, "Yuneec International (China) Co., Ltd." }, { 0x2EAA, "TSUME S.A." }, { 0x2EAB, "Zong Cable Technology Co., Ltd." }, { 0x2EAC, "Jia Yang Electronics (Dongguan) Co., Ltd." }, { 0x2EAD, "Align Technology Inc." }, { 0x2EAE, "Shenzhen TOMTOP Technology Co., Ltd." }, { 0x2EAF, "microsonic co., ltd." }, { 0x2EB0, "Commtech, Inc." }, { 0x2EB1, "Samsung SmartThings" }, { 0x2EB2, "Markus Klotz GmbH" }, { 0x2EB3, "Shenzhen Tokwa Precision Technology Co., Ltd." }, { 0x2EB4, "Beijer Automotive BV" }, { 0x2EB5, "Dongguan HengYue Communication Technology Co., Ltd." }, { 0x2EB6, "The Vehicle Group LTD" }, { 0x2EB7, "Digital Divide Systems Ltd." }, { 0x2EB8, "Yueqing Nuode Electronic Technology Co., Ltd." }, { 0x2EB9, "SSI Computer Corp." }, { 0x2EBA, "Shenzhen E&C Smart Link Technology Co., Ltd." }, { 0x2EBB, "Shanghai Tuzheng Information Technology Co., Ltd." }, { 0x2EBC, "RAIDON Technology Inc." }, { 0x2EBD, "Netstor Technology Co., Ltd." }, { 0x2EBE, "Delphi Automotive Systems, LLC" }, { 0x2EBF, "Shenzhen D&D Technology Co., Ltd" }, { 0x2EC0, "GuideTech" }, { 0x2EC1, "Avid Identification Systems, Inc." }, { 0x2EC2, "Loupedeck Oy" }, { 0x2EC3, "Shenzhen Huntkey Electric Co., Ltd." }, { 0x2EC4, "tetralux S.a.r.l." }, { 0x2EC5, "Ariba Technology Co., LTD." }, { 0x2EC6, "Facebook, Inc." }, { 0x2EC7, "ITECH Electronic Co., Ltd." }, { 0x2EC8, "Ningbo Prime Electronic Co., Ltd." }, { 0x2EC9, "Shenzhou Rongan Technology (Beijing) Limited" }, { 0x2ECA, "AQuantia Corp" }, { 0x2ECB, "Zhejiang Quzhou Gelinte Wire and Cable Co., Ltd." }, { 0x2ECC, "ASR Microelectronics (Shanghai) Co., Ltd." }, { 0x2ECD, "EUROICC" }, { 0x2ECE, "E-Lead Electronic Co., Ltd." }, { 0x2ECF, "Fluo Technology Ltd." }, { 0x2ED0, "Mind Alive Inc." }, { 0x2ED1, "QBit Semiconductor LTD" }, { 0x2ED2, "APOLLO GIKEN Co., Ltd." }, { 0x2ED3, "Shenzhen Xinhongya Electronics Corporation" }, { 0x2ED4, "Butterfly Network Inc." }, { 0x2ED5, "QSAN Technology, Inc." }, { 0x2ED6, "Shenzhen Xinliyang Co., Ltd." }, { 0x2ED7, "Libratel Inc" }, { 0x2ED8, "Dongguan Lontion Industrial Co., Ltd." }, { 0x2ED9, "Microscopes International, LLC" }, { 0x2EDA, "Wenzhou Haitong Communication Electronics Co., Ltd." }, { 0x2EDB, "NeuroHabilitation Corporation" }, { 0x2EDC, "Nippon Techno Lab., Inc." }, { 0x2EDD, "reMarkable AS" }, { 0x2EDE, "Technik Industrial Company Limited" }, { 0x2EDF, "Huizhou Wealth Metal Micro Control Limited" }, { 0x2EE0, "Pogotec Inc." }, { 0x2EE1, "Safetrust Inc" }, { 0x2EE2, "Kashimura Co., Ltd." }, { 0x2EE3, "Kin Keung Electrical Mfg. Ltd." }, { 0x2EE4, "Osprey Video, Inc." }, { 0x2EE6, "NEURODIGITAL TECHNOLOGIES, S.L." }, { 0x2EE7, "GOOGFIT TECH LIMITED" }, { 0x2EE8, "Zunidata Systems, Inc." }, { 0x2EE9, "Adigal LLC" }, { 0x2EEA, "Loma Systems" }, { 0x2EEB, "Jianduan Technology (Shenzhen) Co., Ltd." }, { 0x2EEC, "Sensor Industries Limited" }, { 0x2EED, "Shenzhen Panhui Technologies Co., Ltd." }, { 0x2EEE, "Beijing Qunli Tiancheng Network Technology Company" }, { 0x2EEF, "Booz Allen Hamilton" }, { 0x2EF0, "Zhongshan Auxus Electronic Technology Co., Ltd." }, { 0x2EF1, "Tatvik Biosystems Private Limited" }, { 0x2EF2, "Shenzhen Goodwin Technology Co., Ltd." }, { 0x2FB2, "Fujitsu Limited" }, { 0x3176, "WHANAM ELECTRONICS CO., Ltd. MS division" }, { 0x3552, "BD Consumer Healthcare" }, { 0x3636, "INVIBRO" }, { 0x3884, "Nicolet Biomedical Inc., a Viasys Healthcare Co." }, { 0x3923, "National Instruments" }, { 0x4102, "iRiver" }, { 0x413C, "Dell Inc." }, { 0x4234, "Powervar Inc. (UPS Products)" }, { 0x4242, "USB Design By Example" }, { 0x4317, "Broadcom WLAN" }, { 0x4426, "TANITA Corporation" }, { 0x4745, "Beijing Tiertime Technology Co., Ltd." }, { 0x4791, "Western Digital, G-Tech" }, { 0x4909, "GE Healthcare Bio-Sciences AB" }, { 0x4971, "HITACHI GLOBAL STORAGE TECHNOLOGIES" }, { 0x4B53, "Key Soft Service" }, { 0x4C46, "DSPecialists GmbH" }, { 0x4DDC, "Data Device Corporation" }, { 0x5058, "ProXense, LLC" }, { 0x5245, "RESPIRONICS, INC." }, { 0x544D, "Transmeta Corporation" }, { 0x5543, "UC-Logic Technology Corp." }, { 0x5555, "Number Five, Software" }, { 0x55AA, "OnSpec Electronic Inc." }, { 0x5986, "BISON ELECTRONICS INC." }, { 0x6000, "TRIDENT MICROSYSTEMS (Far East) Ltd." }, { 0x630F, "Leapfrog Schoolhouse" }, { 0x636C, "CoreLogic, Inc." }, { 0x6400, "Springer Design, Inc." }, { 0x6A75, "Shanghai Jujo Electronics Co., Ltd." }, { 0x735F, "Beijing Techshino Technology Co., Ltd." }, { 0x8020, "Trinity, Inc." }, { 0x8086, "Intel Corporation" }, { 0x8087, "Intel" }, { 0x8829, "Beijing Daming Wuzhou Science & Technology Co., Ltd." }, { 0x8873, "Dengineer Co., Ltd." }, { 0x9696, "Digital Arts, Inc." }, { 0x9710, "Moschip Semiconductor Technology" }, { 0xA600, "ASIX s.r.o." }, { 0xA625, "Wuhan Tianyu Information Industry Co., Ltd." }, { 0xBEE5, "BEE SYSTEMS LLC" }, { 0xC0B8, "Corbett Life Science" }, { 0xC10C, "Given Imaging" }, { 0xCACE, "CACE Technologies" }, { 0xCC42, "Cardio Control NV" }, { 0xEA01, "Eagle Technology" }, { 0xEB1A, "Empia Technology, Inc." }, { 0xFF01, "DisplayPort (VESA)" }, { 0xFF02, "MHL, LLC" }, { 0xFF03, "MIPI Debug" }, { 0xFF04, "HDMI" }, { 0x0000, "Vendor ID not listed with USB.org" } }; #endif /* __VNDRLIST_H__ */ ================================================ FILE: tests/projects/windows/winsdk/usbview/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("usbview") add_rules("win.sdk.application") add_files("*.c", "*.rc") add_files("xmlhelper.cpp", {rules = "win.sdk.dotnet"}) set_exceptions("none") ================================================ FILE: tests/projects/windows/winsdk/usbview/xmlhelper.cpp ================================================ /*++ Copyright (c) 1997-2011 Microsoft Corporation Module Name: XMLHELPER.CPP Abstract: This source file contains helper APIs for reading writing XML Environment: user mode Revision History: 05-05-11 : created --*/ /***************************************************************************** I N C L U D E S *****************************************************************************/ #include "uvcview.h" #include "h264.h" #include "xmlhelper.h" // usbschema.hpp is autogenerated from schema during build PASS0 #include "usbschema.hpp" // Include code analysis suppressions #include "codeanalysis.h" /***************************************************************************** D E F I N E S *****************************************************************************/ #define COBJMACROS #define PACHAR_TO_STRING(X) ((X != NULL)? gcnew String(Marshal::PtrToStringAnsi((IntPtr) X )):nullptr) #define PWCHAR_TO_STRING(X) ((X != NULL)? gcnew String(Marshal::PtrToStringUni((IntPtr) X )):nullptr) #define MAX_STRING_DESCRIPTOR_LENGTH 512 #define STRING_DESCRIPTOR_EN_LANGUAGE_ID 0x0409 #define DEVICE_DESCRIPTOR_LENGTH 18 #define SERVICE_EHCI "usbehci" #define SERVICE_XHCI "usbxhci" #define SERVICE_OHCI "usbohci" #define SERVICE_UHCI "usbuhci" #define USB_1_1 "USB 1.1" #define USB_2_0 "USB 2.0" #define USB_3_0 "USB 3.0" #define USB_GENERIC "USB GENERIC (UNKNOWN)" /***************************************************************************** N A M E S P A C E S *****************************************************************************/ using namespace System; using namespace System::IO; using namespace System::Runtime::InteropServices; using namespace System::Collections; using namespace Microsoft::Kits::Samples::Usb; /***************************************************************************** G L O B A L S *****************************************************************************/ namespace Microsoft { namespace Kits { namespace Samples { namespace Usb { public ref class XmlGlobal sealed { private: static XmlGlobal ^ pInstance = gcnew XmlGlobal(); // Empty private constructor XmlGlobal() { } public: // // Globals for XML view // property UvcViewAll ^ ViewAll; property bool XmlViewInitialized; // // Stack of parents of a given node. This is used for finding // where a given object should be added // #if CODE_ANALYSIS // ParentStack need not be constant since we will only have one instance of this object [SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")] #endif static Stack ^ ParentStack = gcnew Stack(); static XmlGlobal ^ Instance() { return pInstance; } }; }; }; }; }; #define gXmlView ((XmlGlobal::Instance())->ViewAll->UvcView) #define gXmlViewInitialized ((XmlGlobal::Instance())->XmlViewInitialized) #define gXmlStack ((XmlGlobal::Instance())->ParentStack) /***************************************************************************** D E C L A R A T I O N S *****************************************************************************/ String ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly); void XmlAddHostControllerPowerMapping( UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo); String ^ XmlGetDeviceClassString(UCHAR deviceClass); void XmlAddHostControllerPowerMapping(UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo); void XmlAddHub30Descriptor(Hub30DescriptorType ^hub30Desc, PUSB_30_HUB_DESCRIPTOR hub30Descriptor); void XmlAddHubDescriptor(HubDescriptorType ^hubDesc, PUSB_HUB_DESCRIPTOR hubDescriptor); void XmlAddPortConnectorProps(PortConnectorType ^portXmlProps, PUSB_PORT_CONNECTOR_PROPERTIES portProps); void XmlAddHubCharacteristics(HubInformationType ^hubI, WORD hubChar); HRESULT XmlAddHubNodeInformation(HubNodeInformationType ^ni, PUSB_NODE_INFORMATION nodeInfo); HRESULT XmlAddHubInformationEx(HubInformationExType ^ex, PUSB_HUB_INFORMATION_EX hubInfoEx); HRESULT XmlAddHubCapabilitiesEx(HubCapabilitiesExType ^ex, USB_HUB_CAPABILITIES_EX hubCapEx); ExternalHubType ^ AddExternalHub(Object ^parent); NoDeviceType ^ AddDisconnectedPort(Object ^parent); UsbDeviceType ^ AddUsbDevice(Object ^parent); void XmlAddEndpointDescriptor( EndpointDescriptorType ^usbXmlEndpointDescriptor, PUSB_ENDPOINT_DESCRIPTOR endPointDescriptor, UCHAR connectionSpeed); void XmlAddPipeInformation( array< UsbPipeInfoType ^> ^ usbXmlPipeInfoList, PUSB_PIPE_INFO pipeInfo, ULONG numPipes, UCHAR connectionSpeed); void XmlAddUsbDeviceDescriptor( UsbDeviceDescriptorType ^usbXmlDeviceDescriptor, PUSB_DEVICE_DESCRIPTOR usbDeviceDescriptor); void XmlAddConfigurationDescriptor( UsbConfigurationDescriptorType ^ confXmlDesc, PUSBDEVICEINFO deviceInfo, PUSB_CONFIGURATION_DESCRIPTOR configDesc, PSTRING_DESCRIPTOR_NODE stringDesc); void XmlAddDeviceQualDescriptor( UsbDeviceQualifierDescriptorType ^ qualXmlDesc, PUSB_DEVICE_QUALIFIER_DESCRIPTOR qualDesc); void XmlAddDeviceConfiguration( UsbDeviceConfigurationType ^ confXmlDesc, PUSBDEVICEINFO deviceInfo, PUSB_CONFIGURATION_DESCRIPTOR configDesc, PSTRING_DESCRIPTOR_NODE stringDesc, int numInterfaces); void XmlAddConnectionInfoSt( NodeConnectionInfoExStructType ^xmlConnectionInfoSt, PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, PDEVICE_INFO_NODE pNode); String ^ XmlGetLangIdString(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc); String ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly); String ^ XmlGetDeviceClassString(UCHAR deviceClass); bool XmlAddDeviceClassDetails( UsbDeviceClassDetailsType ^ deviceDetails, PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, PUSBDEVICEINFO deviceInfo); void XmlAddConnectionInfo( NodeConnectionInfoExType ^xmlConnectionInfo, PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, PUSBDEVICEINFO deviceInfo, PSTRING_DESCRIPTOR_NODE stringDesc, PDEVICE_INFO_NODE pNode); void XmlAddHidDescriptor( UsbDeviceHidDescriptorType ^ hidXmlDesc, PUSB_HID_DESCRIPTOR hidDesc); void XmlAddDeviceInterfaceDescriptor( UsbDeviceInterfaceDescriptorType ^ ifXmlDesc, PUSB_INTERFACE_DESCRIPTOR ifDesc, PSTRING_DESCRIPTOR_NODE stringDesc); void XmlAddOTGDescriptor( UsbDeviceOTGDescriptorType ^ otgXmlDesc, PUSB_OTG_DESCRIPTOR otgDesc); void XmlAddIADDescriptor( UsbDeviceIADDescriptorType ^ iadXmlDesc, PUSB_IAD_DESCRIPTOR iadDesc, PSTRING_DESCRIPTOR_NODE stringDesc, int nInterfaces); array < UsbDeviceConfigurationType ^> ^ XmlGetConfigDescriptors( PUSBDEVICEINFO deviceInfo, PUSB_CONFIGURATION_DESCRIPTOR configDescs, PSTRING_DESCRIPTOR_NODE stringDesc); UsbBosDescriptorType ^ XmlGetBosDescriptor( PUSB_BOS_DESCRIPTOR bosDesc, PSTRING_DESCRIPTOR_NODE stringDesc ); UsbDeviceClassType ^ XmlGetDeviceClass(UCHAR deviceClass, UCHAR deviceSubClass, UCHAR deviceProtocol); UsbDeviceUnknownDescriptorType ^ XmlGetUnknownDescriptor( PUSB_COMMON_DESCRIPTOR unknownDesc ); UsbUsb20ExtensionDescriptorType ^ XmlGetUsb20CapabilityExtensionDescriptor( PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR capDesc ); UsbSuperSpeedExtensionDescriptorType ^ XmlGetSuperSpeedCapabilityExtensionDescriptor( PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR capDesc ); UsbDispContIdCapExtDescriptorType ^ XmlGetContainerIdCapabilityExtensionDescriptor( PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR capDesc ); UsbBillboardCapabilityDescriptorType ^ XmlGetBillboardCapabilityDescriptor( PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR capDesc, PSTRING_DESCRIPTOR_NODE stringDesc ); /***************************************************************************** D E F I N I T I O N S *****************************************************************************/ /***************************************************************************** XmlNotifyEndOfNodeList This function is called back by WalkTreeTopDown() function to notify us that there are no more children to add for the current parent *****************************************************************************/ VOID XmlNotifyEndOfNodeList(PVOID pContext) { UNREFERENCED_PARAMETER(pContext); if (gXmlStack != nullptr && gXmlStack->Count > 0) { // Remove the last parent on the stack gXmlStack->Pop(); } } /***************************************************************************** XmlAddHostControllerPowerMapping() add power info to xml structure *****************************************************************************/ void XmlAddHostControllerPowerMapping(UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo) { int i, powerState; PUSB_POWER_INFO pUPI = usbHCPowerInfo; UsbHCPowerStateType ^ pwrState = nullptr; xmlPwrInfo->PowerMap = gcnew array (WdmUsbPowerSystemShutdown); for(i = 0, powerState = WdmUsbPowerSystemWorking; powerState < WdmUsbPowerSystemShutdown; i++, powerState++, pUPI++) { xmlPwrInfo->PowerMap[i] = gcnew UsbHCPowerStateType(); pwrState = xmlPwrInfo->PowerMap[i]; pwrState->SystemState = PACHAR_TO_STRING(GetPowerStateString(pUPI->SystemState)); pwrState->HostControllerState = PACHAR_TO_STRING(GetPowerStateString(pUPI->HcDevicePowerState)); pwrState->HubState = PACHAR_TO_STRING(GetPowerStateString(pUPI->RhDevicePowerState)); pwrState->CanWakeUp = pUPI->CanWakeup? true:false; pwrState->IsPowered = pUPI->IsPowered? true:false; } xmlPwrInfo->LastSleepState = PACHAR_TO_STRING(GetPowerStateString(pUPI->LastSystemSleepState)); return; } /***************************************************************************** XmlAddHostController() Add an host controller to XML view *****************************************************************************/ HRESULT XmlAddHostController(PSTR hcName, PUSBHOSTCONTROLLERINFO hcInfo) { HRESULT hr = S_OK; UNREFERENCED_PARAMETER(hcName); HostControllerType ^ hc = nullptr; // // Check if the USB Tree array has been initialized // It would have been great if XSD had a way of generating a list instead of array, but it does not // So we have to do array.Resize everytime // if (gXmlView->UsbTree == nullptr) { // This is the first time we are being called, initialize the array with 1 element gXmlView->UsbTree = gcnew array(1); gXmlView->UsbTree[0] = gcnew HostControllerType(); hc = gXmlView->UsbTree[0]; } else { // Create a new array every time as Array.Resize does not seem to work in our case (CLI) // We do this using ArrayList. ArrayList ^hcList = gcnew ArrayList; hcList->AddRange(gXmlView->UsbTree); hc = gcnew HostControllerType(); hcList->Add(hc); gXmlView->UsbTree = reinterpret_cast^> (hcList->ToArray(HostControllerType::typeid)); } if (hc != nullptr) { ULONG debugPort = 0; UsbHCDeviceInfoType ^ ci = nullptr; UsbHCPowerStateMappingType ^ pm = nullptr; if (NULL != hcInfo->UsbDeviceProperties) { hc->HwId = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->HwId); hc->DeviceId = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceId); hc->ServiceName = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->Service); hc->DeviceName = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceDesc); hc->DeviceClass = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceClass); bool foundUsbProtocol = false; if (hcInfo->UsbDeviceProperties->Service != NULL) { foundUsbProtocol = true; if (_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_OHCI) == 0) { hc->UsbProtocol = gcnew String(USB_1_1); } else if(_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_EHCI) == 0 || _stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_UHCI) == 0) { hc->UsbProtocol = gcnew String(USB_2_0); } else if (_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_XHCI) == 0) { hc->UsbProtocol = gcnew String(USB_3_0); } else { foundUsbProtocol = false; } } if (!foundUsbProtocol) { // If protocol lookup failed based on service name, try Controller flavor if(NULL != hcInfo->ControllerInfo) { USB_CONTROLLER_FLAVOR flavor = hcInfo->ControllerInfo->ControllerFlavor; if(flavor == USB_HcGeneric) { hc->UsbProtocol = gcnew String(USB_GENERIC); } else if(flavor >= OHCI_Generic && flavor < UHCI_Generic) { hc->UsbProtocol = gcnew String(USB_1_1); } else if(flavor >= UHCI_Generic && flavor <= EHCI_Generic) { hc->UsbProtocol = gcnew String(USB_2_0); } else if(flavor > EHCI_Generic) { hc->UsbProtocol = gcnew String(USB_3_0); } } } } hc->ControllerInfo = gcnew UsbHCDeviceInfoType(); hc->PowerMapping = gcnew UsbHCPowerStateMappingType(); ci = hc->ControllerInfo; pm = hc->PowerMapping; ci->VendorId = hcInfo->VendorID; ci->DeviceId = hcInfo->DeviceID; ci->DriverKey = PACHAR_TO_STRING(hcInfo->DriverKey); ci->SubSysId = hcInfo->SubSysID; ci->Revision = hcInfo->Revision; if(NULL != hcInfo->ControllerInfo) { ci->NumberOfRootPorts = hcInfo->ControllerInfo->NumberOfRootPorts; ci->ControllerFlavor = hcInfo->ControllerInfo->ControllerFlavor; ci->PortSwitchingEnabled = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_FLAG_PORT_POWER_SWITCHING)? true: false; ci->SelectiveSuspendEnabled = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_FLAG_SEL_SUSPEND)? true: false; ci->LegacyBios = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_LEGACY_BIOS)? true: false; ci->ControllerFlavorString = PACHAR_TO_STRING(GetControllerFlavorString(hcInfo->ControllerInfo->ControllerFlavor)); } // Add power mappings XmlAddHostControllerPowerMapping(pm, (PUSB_POWER_INFO) (&(hcInfo->USBPowerInfo[0]))); // Add debug port debugPort = GetEhciDebugPort(hcInfo->VendorID, hcInfo->DeviceID); if (debugPort > 0) { ci->DebugPort = debugPort; } gXmlStack->Push(hc); } else { hr = E_FAIL; } return hr; } /***************************************************************************** XmlAddHub30Descriptor() Adds the hub 3.0 descriptor to the given hub object *****************************************************************************/ void XmlAddHub30Descriptor(Hub30DescriptorType ^hub30Desc, PUSB_30_HUB_DESCRIPTOR hub30Descriptor) { if (nullptr != hub30Desc && NULL != hub30Descriptor) { hub30Desc->Length = hub30Descriptor->bLength; hub30Desc->DescriptorType = hub30Descriptor->bDescriptorType; hub30Desc->NumberOfPorts = hub30Descriptor->bNumberOfPorts; hub30Desc->HubCharacteristics = hub30Descriptor->wHubCharacteristics; hub30Desc->PowerOntoPowerGood = hub30Descriptor->bPowerOnToPowerGood; hub30Desc->HubControlCurrent = hub30Descriptor->bHubControlCurrent; hub30Desc->HubHdrDecLat = hub30Descriptor->bHubHdrDecLat; hub30Desc->DeviceRemovable = hub30Descriptor->DeviceRemovable; } } /***************************************************************************** XmlAddHubDescriptor() Adds the hub descriptor to the given hub object *****************************************************************************/ void XmlAddHubDescriptor(HubDescriptorType ^hubDesc, PUSB_HUB_DESCRIPTOR hubDescriptor) { if (nullptr != hubDesc && NULL != hubDescriptor) { hubDesc->DescriptorLength = hubDescriptor->bDescriptorLength; hubDesc->DescriptorType = hubDescriptor->bDescriptorType; hubDesc->NumberOfPorts = hubDescriptor->bNumberOfPorts; hubDesc->PowerOntoPowerGood = hubDescriptor->bPowerOnToPowerGood; hubDesc->HubControlCurrent = hubDescriptor->bHubControlCurrent; } } /***************************************************************************** XmlAddPortConnectorProps() Adds the port connector properties to XML file *****************************************************************************/ void XmlAddPortConnectorProps(PortConnectorType ^portXmlProps, PUSB_PORT_CONNECTOR_PROPERTIES portProps) { if (NULL != portProps) { portXmlProps->UsbPortProperties = gcnew UsbPortPropertiesType(); portXmlProps->ConnectionIndex = portProps->ConnectionIndex; portXmlProps->ActualLength = portProps->ActualLength; portXmlProps->CompanionIndex = portProps->CompanionIndex; portXmlProps->CompanionPortNumber = portProps->CompanionPortNumber; portXmlProps->CompanionHubSymbolicLinkName = PWCHAR_TO_STRING(portProps->CompanionHubSymbolicLinkName); portXmlProps->UsbPortProperties->PortIsUserConnectable = portProps->UsbPortProperties.PortIsUserConnectable? true:false; portXmlProps->UsbPortProperties->PortIsDebugCapable = portProps->UsbPortProperties.PortIsDebugCapable? true:false; } return; } /***************************************************************************** XmlAddConnectionInfoV2() Adds the V2 connection info structure *****************************************************************************/ void XmlAddConnectionInfoV2(NodeConnectionInfoExV2Type ^ connectionXmlInfo, PUSB_NODE_CONNECTION_INFORMATION_EX_V2 connectionInfo) { if (NULL != connectionInfo) { connectionXmlInfo->ConnectionIndex = connectionInfo->ConnectionIndex; connectionXmlInfo->Length = connectionInfo->Length; connectionXmlInfo->Usb110Supported = connectionInfo->SupportedUsbProtocols.Usb110? true:false; connectionXmlInfo->Usb200Supported = connectionInfo->SupportedUsbProtocols.Usb200? true:false; connectionXmlInfo->Usb300Supported = connectionInfo->SupportedUsbProtocols.Usb300? true:false; connectionXmlInfo->DeviceIsOperatingAtSuperSpeedOrHigher = connectionInfo->Flags.DeviceIsOperatingAtSuperSpeedOrHigher; connectionXmlInfo->DeviceIsSuperSpeedCapableOrHigher = connectionInfo->Flags.DeviceIsSuperSpeedCapableOrHigher; connectionXmlInfo->DeviceIsOperatingAtSuperSpeedPlusOrHigher = connectionInfo->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher; connectionXmlInfo->DeviceIsSuperSpeedPlusCapableOrHigher = connectionInfo->Flags.DeviceIsSuperSpeedPlusCapableOrHigher; } return; } /***************************************************************************** XmlAddHubCharacteristics() Adds the hub characteristics to the given hub object *****************************************************************************/ void XmlAddHubCharacteristics(HubInformationType ^hubI, WORD hubChar) { HubCharacteristicsType ^hubC = nullptr; hubI->HubCharacteristics = gcnew HubCharacteristicsType(); hubC = hubI->HubCharacteristics; hubC->HubCharacteristicsValue = hubChar; switch(hubChar & 0x3) { case 0x0: hubC->PowerSwitching = gcnew String("Ganged"); break; case 0x1: hubC->PowerSwitching = gcnew String("Individual"); break; case 0x2: case 0x3: hubC->PowerSwitching = gcnew String("None"); break; default: hubC->PowerSwitching = gcnew String("Unknown"); } hubC->CompoundDevice = (hubChar & 0x4)? true:false; switch(hubChar & 0x18) { case 0x0: hubC->OverCurrentProtection = gcnew String("Global"); break; case 0x8: hubC->OverCurrentProtection = gcnew String("Individual"); break; case 0x10: case 0x18: hubC->OverCurrentProtection = gcnew String("No protection, bus power only"); break; default: hubC->OverCurrentProtection = gcnew String("Unknown"); } } /***************************************************************************** XmlAddHubNodeInformation() Adds the node information to the hub object *****************************************************************************/ HRESULT XmlAddHubNodeInformation(HubNodeInformationType ^ni, PUSB_NODE_INFORMATION nodeInfo) { PUSB_HUB_INFORMATION hubInfo = NULL; if (NULL == nodeInfo) { return E_FAIL; } hubInfo = &(nodeInfo->u.HubInformation); ni->HubNode = static_cast (nodeInfo->NodeType); ni->HubInformation = gcnew HubInformationType(); ni->HubInformation->IsRootHub = true; ni->HubInformation->IsBusPowered = hubInfo->HubIsBusPowered? true:false; // Add hub characteristics XmlAddHubCharacteristics(ni->HubInformation, hubInfo->HubDescriptor.wHubCharacteristics); // Add descriptor ni->HubInformation->HubDescriptor = gcnew HubDescriptorType(); XmlAddHubDescriptor(ni->HubInformation->HubDescriptor, &(hubInfo->HubDescriptor)); return S_OK; } /***************************************************************************** XmlAddHubInformation() Adds the node information to the hub object *****************************************************************************/ HRESULT XmlAddHubInformationEx(HubInformationExType ^ex, PUSB_HUB_INFORMATION_EX hubInfoEx) { HubDescriptorType ^hubDesc = nullptr; Hub30DescriptorType ^hub30Desc = nullptr; if (NULL == hubInfoEx) { return E_FAIL; } ex->HubType = static_cast (hubInfoEx->HubType); ex->HighestPortNumber = hubInfoEx->HighestPortNumber; switch(hubInfoEx->HubType) { case UsbRootHub: case Usb20Hub: ex->HubDescriptor = hubDesc = gcnew HubDescriptorType(); XmlAddHubDescriptor(hubDesc, &(hubInfoEx->u.UsbHubDescriptor)); break; case Usb30Hub: ex->Hub30Descriptor = hub30Desc = gcnew Hub30DescriptorType(); XmlAddHub30Descriptor(hub30Desc, &(hubInfoEx->u.Usb30HubDescriptor)); break; } return S_OK; } /***************************************************************************** XmlAddHubCapabilitiesEx() Adds the hub capabilities information to the hub object *****************************************************************************/ HRESULT XmlAddHubCapabilitiesEx(HubCapabilitiesExType ^ex, PUSB_HUB_CAPABILITIES_EX hubCapEx) { if(NULL != hubCapEx) { ex->HubIsHighSpeedCapable = hubCapEx->CapabilityFlags.HubIsHighSpeedCapable?true:false; ex->HubIsHighSpeed = hubCapEx->CapabilityFlags.HubIsHighSpeed?true:false; ex->HubIsMultiTtCapable = hubCapEx->CapabilityFlags.HubIsMultiTtCapable?true:false; ex->HubIsMultiTt = hubCapEx->CapabilityFlags.HubIsMultiTt?true:false; ex->HubIsRoot = hubCapEx->CapabilityFlags.HubIsRoot?true:false; ex->HubIsArmedWakeOnConnect = hubCapEx->CapabilityFlags.HubIsArmedWakeOnConnect?true:false; ex->HubIsBusPowered = hubCapEx->CapabilityFlags.HubIsBusPowered?true:false; } return S_OK; } /***************************************************************************** ExternalHubType ^ AddExternalHub(Object ^parent) This routine finds the type of the parent and adds an external hub object to the parent's list of external hubs. The newly created object is returned We are using arrays insted of better types of collections becaused the code generated by xsd.exe does not support other types. *****************************************************************************/ ExternalHubType ^ AddExternalHub(Object ^parent) { RootHubType ^ rhParent = nullptr; ExternalHubType ^ ehParent = nullptr; array ^ exHubArray = nullptr; ExternalHubType ^ exHub = nullptr; boolean arrayCreated = false; // An external hub can be connected to a Root Hub or another External Hub // We need to determine the type of the object. // Try root hub first rhParent = dynamic_cast (parent); if (rhParent == nullptr) { // RootHub cast was not successfult, try external hub ehParent = dynamic_cast (parent); if (ehParent != nullptr) { // External hub parent if (ehParent->ExternalHub == nullptr) { // First hub in the list of external hubs ehParent->ExternalHub = gcnew array (1); arrayCreated = true; } exHubArray = ehParent->ExternalHub; } } else { // Parent is a root hub if (rhParent->ExternalHub == nullptr) { // First hub in root hub list rhParent->ExternalHub = gcnew array(1); arrayCreated = true; } exHubArray = rhParent->ExternalHub; } if (exHubArray != nullptr) { if (arrayCreated) { // We created the array in this function, so we use offset 0 exHubArray[0] = gcnew ExternalHubType(); exHub = exHubArray[0]; } else { // The array was already present, we need to do elaborate things // as array.resize does not work. ArrayList ^exList = gcnew ArrayList(); exList->AddRange(exHubArray); exHub = gcnew ExternalHubType(); exList->Add(exHub); if (rhParent != nullptr) { rhParent->ExternalHub = reinterpret_cast^> (exList->ToArray(ExternalHubType::typeid)); } else { ehParent->ExternalHub = reinterpret_cast^> (exList->ToArray(ExternalHubType::typeid)); } } } return exHub; } /***************************************************************************** NoDeviceType ^ AddDisconnectedPort(Object ^parent) This routine finds the type of the parent and adds a empty port connection object to the parent's list of devices. The newly created object is returned We are using arrays insted of better types of collections becaused the code generated by xsd.exe does not support other types. *****************************************************************************/ NoDeviceType ^ AddDisconnectedPort(Object ^parent) { RootHubType ^ rhParent = nullptr; ExternalHubType ^ ehParent = nullptr; array ^ devicesArray = nullptr; NoDeviceType ^ noD = nullptr; boolean arrayCreated = false; // An external hub can be connected to a Root Hub or another External Hub // We need to determine the type of the object. // Try RH first rhParent = dynamic_cast (parent); if (rhParent == nullptr) { // RootHub cast was not successfult, try external hub ehParent = dynamic_cast (parent); if (ehParent != nullptr) { // External hub parent if (ehParent->NoDevice == nullptr) { // First hub in the list of external hubs ehParent->NoDevice = gcnew array (1); arrayCreated = true; } devicesArray = ehParent->NoDevice; } } else { // Parent is a root hub if (rhParent->NoDevice == nullptr) { // First hub in root hub list rhParent->NoDevice = gcnew array(1); arrayCreated = true; } devicesArray = rhParent->NoDevice; } if (devicesArray != nullptr) { if (arrayCreated) { // We created the array in this function, so we use offset 0 devicesArray[0] = gcnew NoDeviceType(); noD = devicesArray[0]; } else { // The array was already present, we need to do elaborate things // as array.resize does not work. ArrayList ^exList = gcnew ArrayList(); exList->AddRange(devicesArray); noD = gcnew NoDeviceType(); exList->Add(noD); if (rhParent != nullptr) { rhParent->NoDevice = reinterpret_cast^> (exList->ToArray(NoDeviceType::typeid)); } else { ehParent->NoDevice = reinterpret_cast^> (exList->ToArray(NoDeviceType::typeid)); } } } return noD; } /***************************************************************************** UsbDeviceType ^ AddUsbDevice(Object ^parent) This routine finds the type of the parent and adds a port connection object to the parent's list of port connectors. The newly created object is returned We are using arrays insted of better types of collections becaused the code generated by xsd.exe does not support other types. *****************************************************************************/ UsbDeviceType ^ AddUsbDevice(Object ^parent) { RootHubType ^ rhParent = nullptr; ExternalHubType ^ ehParent = nullptr; array ^ devicesArray = nullptr; UsbDeviceType ^ usbD = nullptr; boolean arrayCreated = false; // An external hub can be connected to a Root Hub or another External Hub // We need to determine the type of the object. // Try RH first rhParent = dynamic_cast (parent); if (rhParent == nullptr) { // RootHub cast was not successfult, try external hub ehParent = dynamic_cast (parent); if (ehParent != nullptr) { // External hub parent if (ehParent->UsbDevice == nullptr) { // First hub in the list of external hubs ehParent->UsbDevice = gcnew array (1); arrayCreated = true; } devicesArray = ehParent->UsbDevice; } } else { // Parent is a root hub if (rhParent->UsbDevice == nullptr) { // First hub in root hub list rhParent->UsbDevice = gcnew array(1); arrayCreated = true; } devicesArray = rhParent->UsbDevice; } if (devicesArray != nullptr) { if (arrayCreated) { // We created the array in this function, so we use offset 0 devicesArray[0] = gcnew UsbDeviceType(); usbD = devicesArray[0]; } else { // The array was already present, we need to do elaborate things // as array.resize does not work. ArrayList ^exList = gcnew ArrayList(); exList->AddRange(devicesArray); usbD = gcnew UsbDeviceType(); exList->Add(usbD); if (rhParent != nullptr) { rhParent->UsbDevice = reinterpret_cast^> (exList->ToArray(UsbDeviceType::typeid)); } else { ehParent->UsbDevice = reinterpret_cast^> (exList->ToArray(UsbDeviceType::typeid)); } } } return usbD; } /***************************************************************************** XmlAddIADDescriptor() This routine adds usb IAD descriptor *****************************************************************************/ void XmlAddIADDescriptor( UsbDeviceIADDescriptorType ^ iadXmlDesc, PUSB_IAD_DESCRIPTOR iadDesc, PSTRING_DESCRIPTOR_NODE stringDesc, int nInterfaces) { if (NULL == iadDesc || NULL == stringDesc) { return; } // Update structure fields iadXmlDesc->BLength = iadDesc->bLength; iadXmlDesc->BDescriptorType = iadDesc->bDescriptorType; iadXmlDesc->BFirstInterface = iadDesc->bFirstInterface; iadXmlDesc->BInterfaceCount = iadDesc->bInterfaceCount; iadXmlDesc->BFunctionClass = iadDesc->bFunctionClass; iadXmlDesc->BFunctionSubclass = iadDesc->bFunctionSubClass; iadXmlDesc->BFunctionProtocol = iadDesc->bFunctionProtocol; iadXmlDesc->IFunction = iadDesc->iFunction; // Validate fields if (iadDesc->bInterfaceCount == 1) { iadXmlDesc->InterfaceError = gcnew String("ERROR: bInterfaceCount must be greater than 1"); } if (nInterfaces < iadDesc->bFirstInterface + iadDesc->bInterfaceCount) { iadXmlDesc->InterfaceError = gcnew String("ERROR: The total number of interfaces"); iadXmlDesc->InterfaceError += nInterfaces; iadXmlDesc->InterfaceError += " must be greater than or equal to the highest linked interface number (base "; iadXmlDesc->InterfaceError += iadDesc->bFirstInterface; iadXmlDesc->InterfaceError += " + count "; iadXmlDesc->InterfaceError += iadDesc->bInterfaceCount; iadXmlDesc->InterfaceError += " = "; iadXmlDesc->InterfaceError += (iadDesc->bFirstInterface + iadDesc->bInterfaceCount); iadXmlDesc->InterfaceError += " )"; } if (iadDesc->bFunctionClass == 0) { iadXmlDesc->FunctionClassError = gcnew String("ERROR: bFunctionClass contains an illegal value 0"); } iadXmlDesc->FunctionDetails = XmlGetDeviceClass( iadDesc->bFunctionClass, iadDesc->bFunctionSubClass, iadDesc->bFunctionProtocol); // Protocol check if (iadDesc->bFunctionClass == USB_DEVICE_CLASS_VIDEO) { if (iadDesc->bFunctionProtocol != PC_PROTOCOL_UNDEFINED) { iadXmlDesc->Protocol= gcnew String("WARNING: Protocol must be set to PC_PROTOCOL_UNDEFINED"); iadXmlDesc->Protocol+= " for this class but is set to: "; iadXmlDesc->Protocol+= iadDesc->bFunctionProtocol; } else { iadXmlDesc->Protocol = gcnew String("PC_PROTOCOL_UNDEFINED protocol"); } } if (iadDesc->iFunction) { // Add String descriptor iadXmlDesc->StringDesc = XmlGetStringDescriptor( iadDesc->iFunction, stringDesc, false); } return; } /***************************************************************************** XmlAddOTGDescriptor() This routine adds usb OTG descriptor *****************************************************************************/ void XmlAddOTGDescriptor( UsbDeviceOTGDescriptorType ^ otgXmlDesc, PUSB_OTG_DESCRIPTOR otgDesc) { if (NULL == otgDesc) { return; } otgXmlDesc->BLength = otgDesc->bLength; otgXmlDesc->BDescriptorType = otgDesc->bDescriptorType; otgXmlDesc->BmAttributes = otgDesc->bmAttributes; // Add descriptive fields switch (otgDesc->bmAttributes) { case 0: break; case 1: otgXmlDesc->AttributesString = gcnew String("SRP support"); break; case 2: otgXmlDesc->AttributesString = gcnew String("HNP support"); break; case 3: otgXmlDesc->AttributesString = gcnew String("SRP and HNP support"); break; default: otgXmlDesc->AttributesString = gcnew String("ERROR: bmAttributes bits 2-7 are reserved should be 0)"); break; } return; } /***************************************************************************** XmlAddHidDescriptor() This routine adds usb HID descriptor *****************************************************************************/ void XmlAddHidDescriptor( UsbDeviceHidDescriptorType ^ hidXmlDesc, PUSB_HID_DESCRIPTOR hidDesc ) { int i = 0; if (NULL == hidDesc) { return; } hidXmlDesc->BLength = hidDesc->bLength; hidXmlDesc->BDescriptorType = hidDesc->bDescriptorType; hidXmlDesc->BcdHID = hidDesc->bcdHID; hidXmlDesc->BCountryCode = hidDesc->bCountryCode; hidXmlDesc->BNumDescriptors = hidDesc->bNumDescriptors; // Add optional descriptors if (hidDesc->bNumDescriptors > 0) { hidXmlDesc->OptionalDescriptor = gcnew array (hidDesc->bNumDescriptors); for(i=0; i < hidDesc->bNumDescriptors; i++) { hidXmlDesc->OptionalDescriptor[i] = gcnew UsbDeviceHidOptionalDescriptorsType(); hidXmlDesc->OptionalDescriptor[i]->BDescriptorType = hidDesc->OptionalDescriptors[i].bDescriptorType; hidXmlDesc->OptionalDescriptor[i]->WDescriptorLength = hidDesc->OptionalDescriptors[i].wDescriptorLength; } } return; } /***************************************************************************** XmlGetUnknownDescriptor() This routine gets a usb unknown descriptor object form unknown descriptor *****************************************************************************/ UsbDeviceUnknownDescriptorType ^ XmlGetUnknownDescriptor( PUSB_COMMON_DESCRIPTOR unknownDesc ) { int i = 0; UsbDeviceUnknownDescriptorType ^ unknownXmlDesc = nullptr; if (NULL == unknownDesc) { return nullptr; } unknownXmlDesc = gcnew UsbDeviceUnknownDescriptorType(); unknownXmlDesc->BLength = unknownDesc->bLength; unknownXmlDesc->BDescriptorType = unknownDesc->bDescriptorType; // Add optional descriptors if (unknownDesc->bLength > 0) { unknownXmlDesc->UnknownDescriptor = gcnew String("Unknown descriptor->"); for(i=0; i < unknownDesc->bLength; i++) { unknownXmlDesc->UnknownDescriptor += String::Format("0x{0:X} ", ((PUCHAR) unknownDesc)[i]); } } return unknownXmlDesc; } /***************************************************************************** XmlAddEndpointDescriptor() This routine adds usb endpoint descriptor and verbose fields *****************************************************************************/ void XmlAddEndpointDescriptor( EndpointDescriptorType ^usbXmlEndpointDescriptor, PUSB_ENDPOINT_DESCRIPTOR endPointDescriptor, UCHAR connectionSpeed ) { EndpointDescriptorType ^ue = usbXmlEndpointDescriptor; ULONG maxBytes = endPointDescriptor->wMaxPacketSize & 0x7FF; // Add structure values ue->Length = endPointDescriptor->bLength; ue->DescriptorType = endPointDescriptor->bDescriptorType; ue->EndpointAddress = endPointDescriptor->bEndpointAddress; ue->Attributes = endPointDescriptor->bmAttributes; ue->MaxPacketSize = endPointDescriptor->wMaxPacketSize; // Add verbose fields ue->EndpointId = endPointDescriptor->bEndpointAddress & 0x0F; // Add endpoint direction if (USB_ENDPOINT_DIRECTION_OUT(endPointDescriptor->bEndpointAddress)) { ue->EndpointDirection = gcnew String("Out"); } else if (USB_ENDPOINT_DIRECTION_IN(endPointDescriptor->bEndpointAddress)) { ue->EndpointDirection = gcnew String("In"); } // Add endpoint type switch (endPointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) { case USB_ENDPOINT_TYPE_CONTROL: ue->EndpointType = gcnew String("Control Transfer Type"); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: switch (endPointDescriptor->bmAttributes & 0x0C) { case 0x00: ue->EndpointType = gcnew String("Ischronous Transfer Type - No Synchronization"); break; case 0x04: ue->EndpointType = gcnew String("Ischronous Transfer Type - Asynchronous"); break; case 0x08: ue->EndpointType = gcnew String("Ischronous Transfer Type - Adaptive"); break; case 0x0C: ue->EndpointType = gcnew String("Ischronous Transfer Type - Synchronous"); break; } break; case USB_ENDPOINT_TYPE_BULK: ue->EndpointType = gcnew String("Bulk Transfer Type"); break; case USB_ENDPOINT_TYPE_INTERRUPT: ue->EndpointType = gcnew String("Interrupt Transfer Type"); break; } // Add packet info switch (connectionSpeed) { case UsbHighSpeed: if (endPointDescriptor->bmAttributes & 1) { ULONG transactions = ((endPointDescriptor->wMaxPacketSize & 0x1800) >> 11) + 1; // Isoc or Interrupt endpoint ue->EndpointPacketInfo = gcnew String( transactions + " transactions per microframe, " + maxBytes + " max bytes"); } else { // Bulk endpoint ue->EndpointPacketInfo = gcnew String(maxBytes + " max bytes"); } break; case UsbFullSpeed: ue->EndpointPacketInfo = gcnew String(maxBytes + " max bytes"); break; default: // Low or Invalid speed ue->EndpointPacketInfo = gcnew String("Invalid bus speed"); break; } // Add validation if (endPointDescriptor->wMaxPacketSize & 0xE000) { ue->EndpointPacketSizeValidation = gcnew String("ERROR: wMaxPacketSize bits 15-13 should be 0"); } else if (connectionSpeed==UsbHighSpeed) { USHORT hsMux; hsMux = (endPointDescriptor->wMaxPacketSize >> 11) & 0x03; switch (endPointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) { case USB_ENDPOINT_TYPE_ISOCHRONOUS: case USB_ENDPOINT_TYPE_INTERRUPT: switch (hsMux) { case 0: if ((maxBytes < 1) || (maxBytes > 1024)) { ue->EndpointPacketSizeValidation = gcnew String("ERROR: Invalid maximum packet size, should be between 1 and 1024"); } break; case 1: if ((maxBytes < 513) || (maxBytes > 1024)) { ue->EndpointPacketSizeValidation = gcnew String("ERROR: Invalid maximum packet size, should be between 513 and 1024"); } break; case 2: if ((maxBytes < 683) || (maxBytes > 1024)) { ue->EndpointPacketSizeValidation = gcnew String("ERROR: Invalid maximum packet size, should be between 683 and 1024"); } break; case 3: ue->EndpointPacketSizeValidation = gcnew String("ERROR: Bits 12-11 set to reserved value\r\n"); break; } } } // Add interval if (endPointDescriptor->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR)) { ue->Interval = endPointDescriptor->bInterval; } else { PUSB_ENDPOINT_DESCRIPTOR2 endpointDesc2 = (PUSB_ENDPOINT_DESCRIPTOR2) endPointDescriptor; ue->WInterval = endpointDesc2->wInterval; ue->SyncAddress = endpointDesc2->bSyncAddress; } return; } /***************************************************************************** XmlAddPipeInformation() This routine adds all the pipe information for device *****************************************************************************/ void XmlAddPipeInformation( array< UsbPipeInfoType ^> ^ usbXmlPipeInfoList, PUSB_PIPE_INFO pipeInfo, ULONG numPipes, UCHAR connectionSpeed ) { ULONG i = 0; for(i = 0; i< numPipes; i++) { // Add all pipe in the list usbXmlPipeInfoList[i] = gcnew UsbPipeInfoType(); usbXmlPipeInfoList[i]->EndpointDescriptor = gcnew EndpointDescriptorType(); XmlAddEndpointDescriptor( usbXmlPipeInfoList[i]->EndpointDescriptor, &pipeInfo[i].EndpointDescriptor, connectionSpeed); usbXmlPipeInfoList[i]->ScheduleOffset = pipeInfo->ScheduleOffset; } return; } /***************************************************************************** XmlAddUsbDeviceDescriptor() This routine adds usb device descriptor *****************************************************************************/ void XmlAddUsbDeviceDescriptor( UsbDeviceDescriptorType ^usbXmlDeviceDescriptor, PUSB_DEVICE_DESCRIPTOR usbDeviceDescriptor) { UsbDeviceDescriptorType ^ud = usbXmlDeviceDescriptor; // Map all fields explicitly ud->Length = usbDeviceDescriptor->bLength; ud->DescriptorType = usbDeviceDescriptor->bDescriptorType; ud->CdUSB= usbDeviceDescriptor->bcdUSB; ud->DeviceClass = usbDeviceDescriptor->bDeviceClass; ud->DeviceSubclass = usbDeviceDescriptor->bDeviceSubClass; ud->DeviceProtocol = usbDeviceDescriptor->bDeviceProtocol; ud->MaxPacketSize0 = usbDeviceDescriptor->bMaxPacketSize0; ud->IdVendor = usbDeviceDescriptor->idVendor; ud->IdProduct = usbDeviceDescriptor->idProduct ; ud->CdDevice = usbDeviceDescriptor->bcdDevice; ud->IManufacturer = usbDeviceDescriptor->iManufacturer; ud->IProduct = usbDeviceDescriptor->iProduct; ud->ISerialNumber = usbDeviceDescriptor->iSerialNumber; ud->NumConfigurations = usbDeviceDescriptor->bNumConfigurations; return; } /***************************************************************************** XmlAddConfigurationDescriptor() This routine adds the configuration descriptor *****************************************************************************/ void XmlAddConfigurationDescriptor( UsbConfigurationDescriptorType ^ confXmlDesc, PUSBDEVICEINFO deviceInfo, PUSB_CONFIGURATION_DESCRIPTOR configDesc, PSTRING_DESCRIPTOR_NODE stringDesc ) { UINT uCount = 0; BOOL isSuperSpeed = FALSE; if (NULL == configDesc || NULL == deviceInfo) { return; } if(deviceInfo->ConnectionInfoV2 && (deviceInfo->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher || deviceInfo->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher)) { isSuperSpeed = TRUE; } confXmlDesc->BLength = configDesc->bLength; confXmlDesc->BDescriptorType = configDesc->bDescriptorType; confXmlDesc->WTotalLength = configDesc->wTotalLength; confXmlDesc->BNumInterfaces = configDesc->bNumInterfaces; confXmlDesc->BConfigurationValue = configDesc->bConfigurationValue; confXmlDesc->IConfiguration = configDesc->iConfiguration; confXmlDesc->BmAttributes = configDesc->bmAttributes; confXmlDesc->MaxPower = configDesc->MaxPower; uCount = GetConfigurationSize(deviceInfo); if (uCount != configDesc->wTotalLength) { confXmlDesc->ConfigDescError = gcnew String("ERROR: Invalid total configuration size " + configDesc->wTotalLength + ", should be " + uCount); } if (configDesc->bConfigurationValue != 1) { confXmlDesc->ConfValueError = gcnew String("CAUTION: Most host controllers will only work with one configuration per speed"); } if (configDesc->iConfiguration) { confXmlDesc->ConfStringDesc = XmlGetStringDescriptor( configDesc->iConfiguration, stringDesc, false); } if (configDesc->bmAttributes & USB_CONFIG_BUS_POWERED) { confXmlDesc->AttributesStr = gcnew String("Bus Powered"); } else if (configDesc->bmAttributes & USB_CONFIG_SELF_POWERED) { confXmlDesc->AttributesStr = gcnew String("Self Powered"); } else if (configDesc->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) { confXmlDesc->AttributesStr = gcnew String("Remote Wakeup"); } else { confXmlDesc->AttributesStr = gcnew String("WARNING: bmAttributes is using reserved space"); } confXmlDesc->MaxCurrent = gcnew String(""); confXmlDesc->MaxCurrent += (isSuperSpeed?configDesc->MaxPower * 8:configDesc->MaxPower * 2); confXmlDesc->MaxCurrent += " mA"; return; } /***************************************************************************** XmlGetDeviceClass() This routine returns the interface class and subclass for given interface descriptor *****************************************************************************/ UsbDeviceClassType ^ XmlGetDeviceClass(UCHAR bInterfaceClass, UCHAR bInterfaceSubclass, UCHAR bInterfaceProtocol) { String ^ deviceClass = nullptr; String ^ deviceSubclass = nullptr; UsbDeviceClassType ^ deviceDetails = gcnew UsbDeviceClassType(); switch (bInterfaceClass) { case USB_DEVICE_CLASS_AUDIO: deviceClass = gcnew String("Audio Interface"); switch (bInterfaceSubclass) { case USB_AUDIO_SUBCLASS_AUDIOCONTROL: deviceSubclass = gcnew String("Audio Control Interface"); break; case USB_AUDIO_SUBCLASS_AUDIOSTREAMING: deviceSubclass = gcnew String("Audio Streaming Interface"); break; case USB_AUDIO_SUBCLASS_MIDISTREAMING: deviceSubclass = gcnew String("MIDI Streaming Interface"); break; default: deviceSubclass = gcnew String("CAUTION: This appears to be an invalid bInterfaceSubclass : "); deviceSubclass += bInterfaceSubclass; break; } break; case USB_DEVICE_CLASS_VIDEO: deviceClass = gcnew String("Video Interface"); switch(bInterfaceSubclass) { case VIDEO_SUBCLASS_CONTROL: deviceSubclass = gcnew String("Video Control"); break; case VIDEO_SUBCLASS_STREAMING: deviceSubclass = gcnew String("Video Streaming"); break; default: deviceSubclass = gcnew String("CAUTION: This appears to be an invalid bInterfaceSubclass : "); deviceSubclass += bInterfaceSubclass; break; } break; case USB_DEVICE_CLASS_VENDOR_SPECIFIC: deviceClass = gcnew String("Vendor Specific Device"); break; case USB_DEVICE_CLASS_HUMAN_INTERFACE: deviceClass = gcnew String("HID Interface"); break; case USB_DEVICE_CLASS_HUB: deviceClass = gcnew String("HUB Interface"); break; case USB_DEVICE_CLASS_RESERVED: deviceClass = gcnew String("CAUTION: Reserved USB Device Interface Class"); break; case USB_DEVICE_CLASS_COMMUNICATIONS: deviceClass = gcnew String("Communications (CDC Control) USB Device\r\n"); break; case USB_DEVICE_CLASS_MONITOR: deviceClass = gcnew String("Monitor USB Device Interface Class*** (This may be obsolete)"); break; case USB_DEVICE_CLASS_PHYSICAL_INTERFACE: deviceClass = gcnew String("Physical Interface USB Device"); break; case USB_DEVICE_CLASS_POWER: if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1) { deviceClass = gcnew String("Image USB Device"); } else { deviceClass = gcnew String("Power USB Device (This may be obsolete)"); } break; case USB_DEVICE_CLASS_PRINTER: deviceClass = gcnew String("Printer USB Device"); break; case USB_DEVICE_CLASS_STORAGE: deviceClass = gcnew String("Mass Storage USB Device"); break; case USB_CDC_DATA_INTERFACE: deviceClass = gcnew String("CDC Data USB Device"); break; case USB_CHIP_SMART_CARD_INTERFACE: deviceClass = gcnew String("Chip/Smart Card USB Device"); break; case USB_CONTENT_SECURITY_INTERFACE: deviceClass = gcnew String("Content Security USB Device"); break; case USB_DIAGNOSTIC_DEVICE_INTERFACE: if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1) { deviceClass = gcnew String("Reprogrammable USB2 Compliance Diagnostic Device USB Device"); } else { deviceClass = gcnew String("CAUTION: This appears to be an invalid device class: "); deviceClass += bInterfaceClass; } break; case USB_WIRELESS_CONTROLLER_INTERFACE: if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1) { deviceClass = gcnew String("Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface"); } else { deviceClass = gcnew String("CAUTION: This appears to be an invalid device class: "); deviceClass += bInterfaceClass; } break; case USB_APPLICATION_SPECIFIC_INTERFACE: deviceClass = gcnew String("Application Specific USB Device"); switch(bInterfaceSubclass) { case 1: deviceSubclass = gcnew String("Device Firmware Application Specific USB Device"); break; case 2: deviceSubclass = gcnew String("IrDA Bridge Application Specific USB Device"); break; case 3: deviceSubclass = gcnew String("Test & Measurement Class (USBTMC) Application Specific USB Device"); break; default: deviceSubclass = gcnew String("CAUTION: This appears to be an invalid bInterfaceSubclass : "); deviceSubclass += bInterfaceSubclass; } break; case USB_DEVICE_CLASS_BILLBOARD: deviceClass = gcnew String("Billboard Class"); switch (bInterfaceSubclass) { case 0: deviceSubclass = gcnew String("Billboard Subclass"); break; default: deviceSubclass = gcnew String("CAUTION: This appears to be an invalid bInterfaceSubClass"); break; } break; default: deviceClass = gcnew String("Interface Class unknown : "); deviceClass += bInterfaceClass; break; } // Return class and subclass deviceDetails->DeviceClass = deviceClass; deviceDetails->DeviceSubclass = deviceSubclass; return deviceDetails; } /***************************************************************************** XmlAddInterfaceDescriptor() This routine adds the device interface descriptor *****************************************************************************/ void XmlAddDeviceInterfaceDescriptor( UsbDeviceInterfaceDescriptorType ^ ifXmlDesc, PUSB_INTERFACE_DESCRIPTOR ifDesc, PSTRING_DESCRIPTOR_NODE stringDesc) { if (NULL == ifDesc || NULL == stringDesc) { return; } // Update structure fields ifXmlDesc->BLength = ifDesc->bLength; ifXmlDesc->BDescriptorType = ifDesc->bDescriptorType; ifXmlDesc->BInterfaceNumber = ifDesc->bInterfaceNumber; ifXmlDesc->BAlternateSetting = ifDesc->bAlternateSetting; ifXmlDesc->BNumEndpoints = ifDesc->bNumEndpoints; ifXmlDesc->BInterfaceClass = ifDesc->bInterfaceClass; ifXmlDesc->BInterfaceSubclass = ifDesc->bInterfaceSubClass; ifXmlDesc->BInterfaceProtocol = ifDesc->bInterfaceProtocol; ifXmlDesc->IInterface = ifDesc->iInterface; // Update class and sub class ifXmlDesc->InterfaceDetails = XmlGetDeviceClass( ifDesc->bInterfaceClass, ifDesc->bInterfaceSubClass, ifDesc->bInterfaceProtocol); //This is basically the check for PC_PROTOCOL_UNDEFINED if ((ifDesc->bInterfaceClass == USB_DEVICE_CLASS_VIDEO) || (ifDesc->bInterfaceClass == USB_DEVICE_CLASS_AUDIO)) { if (ifDesc->bInterfaceProtocol != PC_PROTOCOL_UNDEFINED) { ifXmlDesc->ProtocolError = gcnew String("WARNING: Protocol must be set to PC_PROTOCOL_UNDEFINED"); ifXmlDesc->ProtocolError += " for this class but is set to: "; ifXmlDesc->ProtocolError += ifDesc->bInterfaceProtocol; } } if (ifDesc->iInterface) { // Add String descriptor ifXmlDesc->StringDesc = XmlGetStringDescriptor( ifDesc->iInterface, stringDesc, false); } if (ifDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR2)) { PUSB_INTERFACE_DESCRIPTOR2 interfaceDesc2; interfaceDesc2 = (PUSB_INTERFACE_DESCRIPTOR2)ifDesc; ifXmlDesc->WNumClasses = interfaceDesc2->wNumClasses; } return; } /***************************************************************************** XmlAddDeviceQualDescriptor() This routine adds the device qualifier descriptor *****************************************************************************/ void XmlAddDeviceQualDescriptor( UsbDeviceQualifierDescriptorType ^ qualXmlDesc, PUSB_DEVICE_QUALIFIER_DESCRIPTOR qualDesc) { if (NULL == qualDesc) { return; } // Add structure fields qualXmlDesc->BLength = qualDesc->bLength; qualXmlDesc->BDescriptorType = qualDesc->bDescriptorType; qualXmlDesc->BcdUSB = qualDesc->bcdUSB; qualXmlDesc->BDeviceClass = qualDesc->bDeviceClass; qualXmlDesc->BDeviceSubclass = qualDesc->bDeviceSubClass; qualXmlDesc->BDeviceProtocol = qualDesc->bDeviceProtocol; qualXmlDesc->BMaxPacketSize0 = qualDesc->bMaxPacketSize0; qualXmlDesc->NumConfigurations = qualDesc->bNumConfigurations; // Get device class string qualXmlDesc->DeviceClass = XmlGetDeviceClassString(qualDesc->bDeviceClass); if (qualDesc->bDeviceSubClass > 0x00 && qualDesc->bDeviceSubClass < 0xFF) { qualXmlDesc->DeviceSubclassError = gcnew String("ERROR: bDeviceSubClass is invalid : "); qualXmlDesc->DeviceSubclassError += qualDesc->bDeviceSubClass; } if (qualDesc->bDeviceProtocol > 0x00 && qualDesc->bDeviceProtocol < 0xFF) { qualXmlDesc->DeviceProtocolError = gcnew String("ERROR: bDeviceProtocol is invalid : "); qualXmlDesc->DeviceProtocolError += qualDesc->bDeviceProtocol; } qualXmlDesc->MaxPacketSizeInBytes = qualDesc->bMaxPacketSize0; if (qualDesc->bNumConfigurations != 1) { qualXmlDesc->DeviceNumConfigError = gcnew String( "CAUTION: Most host controllers will only work with one configuration per speed"); } if (qualDesc->bReserved != 0) { qualXmlDesc->ReservedError = gcnew String("WARNING: bReserved needs to be set to 0 to be valid - " + qualDesc->bReserved); } return; } /***************************************************************************** XmlAddAddConfigDescriptors() This routine adds the all the config descriptors *****************************************************************************/ array < UsbDeviceConfigurationType ^> ^ XmlGetConfigDescriptors( PUSBDEVICEINFO deviceInfo, PUSB_CONFIGURATION_DESCRIPTOR configDescs, PSTRING_DESCRIPTOR_NODE stringDesc ) { array < UsbDeviceConfigurationType ^> ^ confXmlDescs = nullptr; PUSB_COMMON_DESCRIPTOR commonDesc = NULL; PUCHAR descEnd = NULL; ArrayList ^confList = gcnew ArrayList; UsbDeviceConfigurationType ^ deviceConf = nullptr; commonDesc = (PUSB_COMMON_DESCRIPTOR) configDescs; descEnd = (PUCHAR) configDescs + configDescs->wTotalLength; while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) { // Add the config descriptor deviceConf = gcnew UsbDeviceConfigurationType(); XmlAddDeviceConfiguration( deviceConf, deviceInfo, (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc, stringDesc, configDescs->bNumInterfaces ); confList->Add(deviceConf); commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); } confXmlDescs = reinterpret_cast^> (confList->ToArray(UsbDeviceConfigurationType::typeid)); return confXmlDescs; } /***************************************************************************** XmlAddDeviceConfiguration() This routine adds the device configuration *****************************************************************************/ void XmlAddDeviceConfiguration( UsbDeviceConfigurationType ^ confXmlDesc, PUSBDEVICEINFO deviceInfo, PUSB_CONFIGURATION_DESCRIPTOR configDesc, PSTRING_DESCRIPTOR_NODE stringDesc, int numInterfaces ) { PUSB_COMMON_DESCRIPTOR commonDesc = NULL; UCHAR bInterfaceClass = 0; UCHAR bInterfaceSubclass = 0; UCHAR bInterfaceProtocol = 0; BOOL displayUnknown = FALSE; if (NULL == deviceInfo || NULL == configDesc || NULL == stringDesc) { return; } commonDesc = (PUSB_COMMON_DESCRIPTOR)configDesc; displayUnknown = FALSE; switch (commonDesc->bDescriptorType) { case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE: if (commonDesc->bLength != sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)) { // Validate descriptor confXmlDesc->DeviceQualifierError = String::Format( "ERROR: Device Qualifier bLength value incorrect Obtained: {0} Expected {1}", commonDesc->bLength, sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)); displayUnknown = TRUE; break; } // Add device Qual descriptor confXmlDesc->DeviceQualifierDescriptor = gcnew UsbDeviceQualifierDescriptorType(); XmlAddDeviceQualDescriptor( confXmlDesc->DeviceQualifierDescriptor, (PUSB_DEVICE_QUALIFIER_DESCRIPTOR) commonDesc); break; case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE: if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) { // Validate descriptor confXmlDesc->SpeedConfigurationError = String::Format( "ERROR: Other speed configuration bLength value incorrect Obtained: {0} Expected {1}", commonDesc->bLength, sizeof(USB_CONFIGURATION_DESCRIPTOR)); displayUnknown = TRUE; } // Add configuration desc confXmlDesc->ConfigurationDescriptor = gcnew UsbConfigurationDescriptorType(); XmlAddConfigurationDescriptor( confXmlDesc->ConfigurationDescriptor, deviceInfo, (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc, stringDesc); break; case USB_CONFIGURATION_DESCRIPTOR_TYPE: if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) { // Validate descriptor confXmlDesc->SpeedConfigurationError = String::Format( "ERROR: Configuration bLength value incorrect Obtained: {0} Expected {1}", commonDesc->bLength, sizeof(USB_CONFIGURATION_DESCRIPTOR)); displayUnknown = TRUE; break; } // Add configuration desc confXmlDesc->ConfigurationDescriptor = gcnew UsbConfigurationDescriptorType(); XmlAddConfigurationDescriptor( confXmlDesc->ConfigurationDescriptor, deviceInfo, (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc, stringDesc); break; case USB_INTERFACE_DESCRIPTOR_TYPE: if ((commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR)) && (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))) { // Validate descriptor confXmlDesc->InterfaceError = String::Format( "ERROR: Interface bLength value incorrect Obtained: {0} Expected: {1} or {2}", commonDesc->bLength, sizeof(USB_INTERFACE_DESCRIPTOR), sizeof(USB_INTERFACE_DESCRIPTOR2)); displayUnknown = TRUE; break; } // Add interface descriptor bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass; bInterfaceSubclass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceSubClass; bInterfaceProtocol = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceProtocol; confXmlDesc->InterfaceDescriptor = gcnew UsbDeviceInterfaceDescriptorType(); XmlAddDeviceInterfaceDescriptor( confXmlDesc->InterfaceDescriptor, (PUSB_INTERFACE_DESCRIPTOR) commonDesc, stringDesc ); case USB_ENDPOINT_DESCRIPTOR_TYPE: if ((commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR)) && (commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR2))) { // Validate endpoint descriptor confXmlDesc->EndpointError = String::Format( "ERROR: Endpoint bLength value incorrect Obtained: {0} Expected: {1} or {2}", commonDesc->bLength, sizeof(USB_ENDPOINT_DESCRIPTOR), sizeof(USB_ENDPOINT_DESCRIPTOR2)); displayUnknown = TRUE; break; } confXmlDesc->EndpointDescriptor = gcnew EndpointDescriptorType(); if (NULL != deviceInfo->ConnectionInfo) { // Add endpoint descriptor XmlAddEndpointDescriptor( confXmlDesc->EndpointDescriptor, (PUSB_ENDPOINT_DESCRIPTOR) commonDesc, deviceInfo->ConnectionInfo->Speed); } break; case USB_HID_DESCRIPTOR_TYPE: if (commonDesc->bLength < sizeof(USB_HID_DESCRIPTOR)) { // Validate HID confXmlDesc->HidError = String::Format( "ERROR: HID bLength value incorrect Obtained: {0} Expected: {1}", commonDesc->bLength, sizeof(USB_HID_DESCRIPTOR)); displayUnknown = TRUE; break; } // Add HID descriptor confXmlDesc->HidDescriptor = gcnew UsbDeviceHidDescriptorType(); XmlAddHidDescriptor( confXmlDesc->HidDescriptor, (PUSB_HID_DESCRIPTOR) commonDesc ); break; case USB_OTG_DESCRIPTOR_TYPE: if (commonDesc->bLength < sizeof(USB_OTG_DESCRIPTOR)) { // Validate length confXmlDesc->HidError = String::Format( "ERROR: OTG bLength value incorrect Obtained: {0} Expected: {1}", commonDesc->bLength, sizeof(USB_OTG_DESCRIPTOR)); displayUnknown = TRUE; break; } // Add OTG descriptor confXmlDesc->OtgDescriptor = gcnew UsbDeviceOTGDescriptorType(); XmlAddOTGDescriptor( confXmlDesc->OtgDescriptor, (PUSB_OTG_DESCRIPTOR) commonDesc ); break; case USB_IAD_DESCRIPTOR_TYPE: if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR)) { // Validate length confXmlDesc->IadError = String::Format( "ERROR: IAD bLength value incorrect", commonDesc->bLength, sizeof(USB_OTG_DESCRIPTOR)); displayUnknown = TRUE; } // Add IAD descriptor confXmlDesc->IadDescriptor = gcnew UsbDeviceIADDescriptorType(); XmlAddIADDescriptor( confXmlDesc->IadDescriptor, (PUSB_IAD_DESCRIPTOR) commonDesc, stringDesc, numInterfaces ); break; default: // Interface class device (?) confXmlDesc->DeviceDetails = XmlGetDeviceClass( ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceClass, ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceSubClass, ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceProtocol ); break; } if (displayUnknown) { // Add unknown descriptor confXmlDesc->UnknownDescriptor = XmlGetUnknownDescriptor(commonDesc); } return; } /***************************************************************************** XmlAddConnectionInfoSt() This routine adds connection information structures for the device *****************************************************************************/ void XmlAddConnectionInfoSt( NodeConnectionInfoExStructType ^xmlConnectionInfoSt, PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, PDEVICE_INFO_NODE pNode) { NodeConnectionInfoExStructType ^nS = xmlConnectionInfoSt; nS->ConnectionIndex = connectionInfo->ConnectionIndex; nS->DeviceDescriptor = gcnew UsbDeviceDescriptorType(); XmlAddUsbDeviceDescriptor(nS->DeviceDescriptor, &(connectionInfo->DeviceDescriptor)); nS->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue; nS->Speed = connectionInfo->Speed; nS->SpeedStr = static_cast (connectionInfo->Speed); nS->DeviceIsHub = connectionInfo->DeviceIsHub? true: false; nS->NumOfOpenPipes = connectionInfo->NumberOfOpenPipes; nS->UsbConnectionStatus = static_cast (connectionInfo->ConnectionStatus); if(NULL != pNode) { nS->DevicePowerState = static_cast(pNode->LatestDevicePowerState); } else { nS->DevicePowerState = static_cast(PowerDeviceUnspecified); } // Add the pipe list if (connectionInfo->NumberOfOpenPipes > 0) { nS->Pipe = gcnew array (connectionInfo->NumberOfOpenPipes); XmlAddPipeInformation( nS->Pipe, connectionInfo->PipeList, connectionInfo->NumberOfOpenPipes, connectionInfo->Speed ); } return; } /***************************************************************************** XmlGetLangIdString() Obtains the language string for given string descriptor index *****************************************************************************/ String ^ XmlGetLangIdString(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc) { String ^langIdStr = nullptr; bool foundDescriptor = false; while(stringDesc) { if (stringDesc->DescriptorIndex == index) { langIdStr = PACHAR_TO_STRING(GetLangIDString(stringDesc->LanguageID)); if (langIdStr == nullptr) { langIdStr = gcnew String("WARNING: Invalid language ID: " + stringDesc->LanguageID); } foundDescriptor = true; break; } stringDesc = stringDesc->Next; } if (foundDescriptor == false) { // If no descriptor was found, return error message in field langIdStr = gcnew String("ERROR: No String descriptor for index " + index); } return langIdStr; } /***************************************************************************** XmlGetStringDescriptor() Obtains the string descriptor for given string descriptor index *****************************************************************************/ String ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly) { ULONG nBytes = 0; CHAR pString[MAX_STRING_DESCRIPTOR_LENGTH]; String ^desc = nullptr; bool foundDescriptor = false; bool foundNonEnglishDescriptor = false; ZeroMemory(pString, MAX_STRING_DESCRIPTOR_LENGTH); while(stringDesc) { if (stringDesc->DescriptorIndex == index) { if (enOnly && stringDesc->LanguageID != STRING_DESCRIPTOR_EN_LANGUAGE_ID) { // If we are required to return only english descriptor, continue foundNonEnglishDescriptor = true; continue; } nBytes = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, stringDesc->StringDescriptor->bString, (stringDesc->StringDescriptor->bLength -2)/2, pString, MAX_STRING_DESCRIPTOR_LENGTH, NULL, NULL ); if (nBytes) { foundDescriptor = true; desc = PACHAR_TO_STRING(pString); } break; } stringDesc = stringDesc->Next; } if ((foundDescriptor == false) && (foundNonEnglishDescriptor == false)) { // If no descriptor was found, return error message in field desc = gcnew String("ERROR: No String descriptor for index " + index); } else if ((foundDescriptor == false) && (foundNonEnglishDescriptor == true) && (enOnly)) { desc = gcnew String("ERROR: The index " + index + " does not support English(US)"); } return desc; } /***************************************************************************** XmlGetDeviceClassString() Returns the device class string for given device class ID *****************************************************************************/ String ^ XmlGetDeviceClassString(UCHAR deviceClass) { String ^ deviceClassStr = nullptr; // Not an IAD device switch (deviceClass) { case USB_INTERFACE_CLASS_DEVICE: deviceClassStr = gcnew String("Interface Class Defined Device"); break; case USB_COMMUNICATION_DEVICE: deviceClassStr = gcnew String("Communication Device"); break; case USB_HUB_DEVICE: deviceClassStr = gcnew String("Hub Device"); break; case USB_DIAGNOSTIC_DEVICE: deviceClassStr = gcnew String("Diagnostic Device"); break; case USB_WIRELESS_CONTROLLER_DEVICE: deviceClassStr = gcnew String("Wireless Controller(Bluetooth) Device"); break; case USB_VENDOR_SPECIFIC_DEVICE: deviceClassStr = gcnew String("Vendor specific device"); break; case USB_DEVICE_CLASS_BILLBOARD: deviceClassStr = gcnew String("Billboard class device"); break; default: deviceClassStr= gcnew String("ERROR: unknown bDeviceClass" + deviceClass); break; } return deviceClassStr; } /***************************************************************************** XmlAddDeviceClassDetails() This routine adds device class details *****************************************************************************/ bool XmlAddDeviceClassDetails( UsbDeviceClassDetailsType ^ deviceDetails, PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, PUSBDEVICEINFO deviceInfo) { UINT uIADcount = 0; bool tog = true; uIADcount = IsIADDevice((PUSBDEVICEINFO) deviceInfo); if (uIADcount) { // IAD device, check validity of device class if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE) { tog = false; deviceDetails->DeviceType = gcnew String("Multi-interface Function Code Device"); } else { deviceDetails->DeviceTypeError = gcnew String("ERROR: device class should be Multi-interface Function " + USB_MISCELLANEOUS_DEVICE + "is used"); } deviceDetails->UvcVersion = IsUVCDevice((PUSBDEVICEINFO) deviceInfo); // This device configuration has 1 or more IAD descriptors if (connectionInfo->DeviceDescriptor.bDeviceSubClass == USB_COMMON_SUB_CLASS) { deviceDetails->SubclassType = gcnew String("Common Class Sub Class"); } else { deviceDetails->SubclassTypeError = gcnew String("ERROR: device SubClass should be USB Common Sub Class" + USB_COMMON_SUB_CLASS + " when IAD descriptor is used"); } // Check device protocol if (connectionInfo->DeviceDescriptor.bDeviceProtocol == USB_IAD_PROTOCOL) { deviceDetails->DeviceProtocol = gcnew String("Interface Association Descriptor protocol"); } else { deviceDetails->DeviceProtocolError = gcnew String("ERROR: device Protocol should be USB IAD Protocol " + USB_IAD_PROTOCOL + " when IAD descriptor is used"); } } else { deviceDetails->DeviceType = XmlGetDeviceClassString(connectionInfo->DeviceDescriptor.bDeviceClass); if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_BILLBOARD && (connectionInfo->DeviceDescriptor.bDeviceSubClass != 0x0 || connectionInfo->DeviceDescriptor.bDeviceProtocol != 0x0)) { deviceDetails->DeviceTypeError = gcnew String("ERROR: Billboard device has invalid bDeviceSubclass/bDeviceProtocol"); } if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE) { deviceDetails->DeviceTypeError = gcnew String("ERROR: Multi-interface Function code " + connectionInfo->DeviceDescriptor.bDeviceClass + " used for device with no IAD descriptors"); } if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_COMMUNICATION_DEVICE || connectionInfo->DeviceDescriptor.bDeviceClass == USB_HUB_DEVICE || connectionInfo->DeviceDescriptor.bDeviceClass == USB_DIAGNOSTIC_DEVICE || connectionInfo->DeviceDescriptor.bDeviceClass == USB_WIRELESS_CONTROLLER_DEVICE || connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE || connectionInfo->DeviceDescriptor.bDeviceClass == USB_VENDOR_SPECIFIC_DEVICE) { tog = false; } // Not an IAD device, so all subclass values are invalid if (connectionInfo->DeviceDescriptor.bDeviceSubClass > 0x00 && connectionInfo->DeviceDescriptor.bDeviceSubClass < 0xFF) { deviceDetails->SubclassTypeError = gcnew String("ERROR: bDeviceSubClass is invalid - " + connectionInfo->DeviceDescriptor.bDeviceSubClass); } // Not an IAD device, so all subclass values are invalid, check protocol if (connectionInfo->DeviceDescriptor.bDeviceProtocol > 0x00 && connectionInfo->DeviceDescriptor.bDeviceProtocol < 0xFF && tog==1) { deviceDetails->DeviceProtocolError = gcnew String("ERROR: bDeviceProtocol is invalid - " + connectionInfo->DeviceDescriptor.bDeviceProtocol); } } return tog; } /***************************************************************************** XmlAddConnectionInfo() This routine adds connection information for the device *****************************************************************************/ void XmlAddConnectionInfo( NodeConnectionInfoExType ^xmlConnectionInfo, PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, PUSBDEVICEINFO deviceInfo, PSTRING_DESCRIPTOR_NODE stringDesc, PDEVICE_INFO_NODE pNode) { NodeConnectionInfoExType ^ nc = xmlConnectionInfo; bool tog = true; nc->ConnectionInfoStruct = gcnew NodeConnectionInfoExStructType(); // Update the structure XmlAddConnectionInfoSt(nc->ConnectionInfoStruct, connectionInfo, pNode); // Add verbose fields if (connectionInfo->ConnectionStatus == NoDeviceConnected) { // No device connected, nothing to do return; } if (connectionInfo->DeviceDescriptor.iProduct) { // Add EN version of string descriptor nc->IProductStringDescEn = XmlGetStringDescriptor( connectionInfo->DeviceDescriptor.iProduct, stringDesc, true); } // Check open pipes count if (connectionInfo->NumberOfOpenPipes == 0) { nc->PipeInfoError = gcnew String("ERROR: No open pipes"); } // Check device descriptor length if (connectionInfo->DeviceDescriptor.bLength != DEVICE_DESCRIPTOR_LENGTH) { nc->LengthError = gcnew String("ERROR: bLength " + connectionInfo->DeviceDescriptor.bLength + " incorrect, should be " + DEVICE_DESCRIPTOR_LENGTH ); } // Check for device error if ((connectionInfo->ConnectionStatus == DeviceFailedEnumeration) || (connectionInfo->ConnectionStatus == DeviceGeneralFailure)) { nc->DeviceError = gcnew String("ERROR: Device enumeration failure"); } else { nc->DeviceClassDetails = gcnew UsbDeviceClassDetailsType(); // Add device class details tog = XmlAddDeviceClassDetails( nc->DeviceClassDetails, connectionInfo, deviceInfo); nc->MaxPacketSizeInBytes = connectionInfo->DeviceDescriptor.bMaxPacketSize0; // Validate speed switch (connectionInfo->Speed) { case UsbLowSpeed: if (connectionInfo->DeviceDescriptor.bMaxPacketSize0 != 8) { nc->PacketSizeError = gcnew String("ERROR: Low Speed Devices require bMaxPacketSize0 = 8"); } break; case UsbFullSpeed: if (!(connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 8 || connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 16 || connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 32 || connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 64)) { nc->PacketSizeError = gcnew String("ERROR: Full Speed Devices require bMaxPacketSize0 = 8, 16, 32, or 64"); } break; case UsbHighSpeed: if (connectionInfo->DeviceDescriptor.bMaxPacketSize0 != 64) { nc->PacketSizeError = gcnew String("ERROR: High Speed Devices require bMaxPacketSize0 = 64"); } break; } // Get string descriptors nc->VendorString = PACHAR_TO_STRING(GetVendorString(connectionInfo->DeviceDescriptor.idVendor)); nc->ManufacturerString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iManufacturer, stringDesc, false); nc->ProductString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iProduct, stringDesc, false); nc->LangIdString = XmlGetLangIdString(connectionInfo->DeviceDescriptor.iProduct, stringDesc); nc->SerialString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iSerialNumber, stringDesc, false); // Validate configuration if (connectionInfo->DeviceDescriptor.bNumConfigurations != 1) { nc->ConfigurationCountError = gcnew String("WARNING: Most host controllers will only work with "\ "one configuration per speed"); } } return; } /***************************************************************************** XmlAddExternalHub() Add a external to the parent Host Controller or hub. This is determined by the last object pushed on the stack *****************************************************************************/ HRESULT XmlAddExternalHub(PSTR ehName, PUSBEXTERNALHUBINFO ehInfo) { HRESULT hr = S_OK; Object ^ parent = gXmlStack->Peek(); ExternalHubType ^exHub = nullptr; UNREFERENCED_PARAMETER(ehName); if (NULL == ehInfo) { return E_FAIL; } exHub = AddExternalHub(parent); if (exHub != nullptr) { exHub->HubName = PACHAR_TO_STRING(ehInfo->HubName); if (NULL != ehInfo->UsbDeviceProperties) { exHub->HwId = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->HwId); exHub->DeviceId = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceId); exHub->ServiceName = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->Service); exHub->DeviceName = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceDesc); exHub->DeviceClass = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceClass); } exHub->HubNodeInformation = gcnew HubNodeInformationType(); XmlAddHubNodeInformation(exHub->HubNodeInformation, ehInfo->HubInfo); exHub->HubInformationEx = gcnew HubInformationExType(); XmlAddHubInformationEx(exHub->HubInformationEx, ehInfo->HubInfoEx); exHub->HubCapabilityEx = gcnew HubCapabilitiesExType(); XmlAddHubCapabilitiesEx(exHub->HubCapabilityEx, ehInfo->HubCapabilityEx); exHub->ConnectionInfo = gcnew NodeConnectionInfoExType(); // Update protocol if (NULL != ehInfo->ConnectionInfo) { switch(ehInfo->ConnectionInfo->Speed) { case UsbLowSpeed: case UsbFullSpeed: exHub->UsbProtocol = gcnew String(USB_1_1); break; case UsbHighSpeed: exHub->UsbProtocol = gcnew String(USB_2_0); break; case UsbSuperSpeed: exHub->UsbProtocol = gcnew String(USB_3_0); break; } } // Add connection info XmlAddConnectionInfo( exHub->ConnectionInfo, ehInfo->ConnectionInfo, (PUSBDEVICEINFO) ehInfo, ehInfo->StringDescs, ehInfo->DeviceInfoNode ); // Add port connectors if (NULL != ehInfo->PortConnectorProps) { exHub->PortConnector = gcnew PortConnectorType(); XmlAddPortConnectorProps( exHub->PortConnector, ehInfo->PortConnectorProps ); } // Add connection info V2 exHub->ConnectionInfoV2 = gcnew NodeConnectionInfoExV2Type(); XmlAddConnectionInfoV2( exHub->ConnectionInfoV2, ehInfo->ConnectionInfoV2 ); // Add configuration descriptor if (NULL != ehInfo->ConfigDesc) { exHub->DeviceConfiguration = XmlGetConfigDescriptors( (PUSBDEVICEINFO) ehInfo, (PUSB_CONFIGURATION_DESCRIPTOR) (ehInfo->ConfigDesc + 1), ehInfo->StringDescs ); } // Add BOS descriptor if (NULL != ehInfo->BosDesc) { exHub->BosDescriptor = XmlGetBosDescriptor((PUSB_BOS_DESCRIPTOR) (ehInfo->BosDesc + 1), ehInfo->StringDescs); } gXmlStack->Push(exHub); } else { hr = E_FAIL; } return hr; } /***************************************************************************** XmlGetBosDescriptor() Gets the Bos descriptor object for given BOS descriptor *****************************************************************************/ UsbBosDescriptorType ^ XmlGetBosDescriptor( PUSB_BOS_DESCRIPTOR bosDesc, PSTRING_DESCRIPTOR_NODE stringDesc ) { PUSB_COMMON_DESCRIPTOR commonDesc = NULL; PUSB_DEVICE_CAPABILITY_DESCRIPTOR capDesc = NULL; UsbBosDescriptorType ^ bosXmlDesc = nullptr; ArrayList ^usb20CapExtDescList = gcnew ArrayList(); ArrayList ^usbSuperSpeedExtDescList = gcnew ArrayList(); ArrayList ^usbContIdCapExtDescList = gcnew ArrayList(); ArrayList ^usbUnknownDescList = gcnew ArrayList(); ArrayList ^usbBillboardDescList = gcnew ArrayList(); if(NULL == bosDesc) { return nullptr; } // Initialize attributes bosXmlDesc = gcnew UsbBosDescriptorType(); bosXmlDesc->BLength = bosDesc->bLength; bosXmlDesc->BDescriptorType = bosDesc->bDescriptorType; bosXmlDesc->WTotalLength = bosDesc->wTotalLength; bosXmlDesc->BNumDeviceCaps = bosDesc->bNumDeviceCaps; commonDesc = (PUSB_COMMON_DESCRIPTOR) bosDesc; while ((commonDesc = GetNextDescriptor((PUSB_COMMON_DESCRIPTOR) bosDesc, bosDesc->wTotalLength, commonDesc, -1)) != NULL) { switch (commonDesc->bDescriptorType) { case USB_DEVICE_CAPABILITY_DESCRIPTOR_TYPE: capDesc = (PUSB_DEVICE_CAPABILITY_DESCRIPTOR)commonDesc; switch (capDesc->bDevCapabilityType) { case USB_DEVICE_CAPABILITY_USB20_EXTENSION: usb20CapExtDescList->Add( XmlGetUsb20CapabilityExtensionDescriptor( (PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR)capDesc ) ); break; case USB_DEVICE_CAPABILITY_SUPERSPEED_USB: usbSuperSpeedExtDescList->Add( XmlGetSuperSpeedCapabilityExtensionDescriptor( (PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR)capDesc ) ); break; case USB_DEVICE_CAPABILITY_CONTAINER_ID: usbContIdCapExtDescList->Add( XmlGetContainerIdCapabilityExtensionDescriptor( (PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR)capDesc ) ); break; case USB_DEVICE_CAPABILITY_BILLBOARD: usbBillboardDescList->Add( XmlGetBillboardCapabilityDescriptor( (PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) capDesc, stringDesc ) ); break; default: usbUnknownDescList->Add( XmlGetUnknownDescriptor( (PUSB_COMMON_DESCRIPTOR) capDesc ) ); break; } break; default: usbUnknownDescList->Add(XmlGetUnknownDescriptor(commonDesc)); break; } } // Convert lists to arrays for and add to Bos Descriptor bosXmlDesc->UnknownDescriptor = reinterpret_cast^> ( usbUnknownDescList->ToArray(UsbDeviceUnknownDescriptorType::typeid) ); bosXmlDesc->UsbSuperSpeedExtensionDescriptor = reinterpret_cast^> ( usbSuperSpeedExtDescList->ToArray(UsbSuperSpeedExtensionDescriptorType::typeid) ); bosXmlDesc->UsbUsb20ExtensionDescriptor = reinterpret_cast^> ( usb20CapExtDescList->ToArray(UsbUsb20ExtensionDescriptorType::typeid) ); bosXmlDesc->UsbDispContIdCapExtDescriptor = reinterpret_cast^> ( usbContIdCapExtDescList->ToArray(UsbDispContIdCapExtDescriptorType::typeid) ); bosXmlDesc->UsbBillboardCapabilityDescriptor = reinterpret_cast^> ( usbBillboardDescList->ToArray(UsbBillboardCapabilityDescriptorType::typeid) ); return bosXmlDesc; } /***************************************************************************** XmlGetUsb20CapabilityExtensionDescriptor() Gets a Usb20Capability extension descriptor object from the given descriptor *****************************************************************************/ UsbUsb20ExtensionDescriptorType ^ XmlGetUsb20CapabilityExtensionDescriptor( PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR capDesc ) { UsbUsb20ExtensionDescriptorType ^ capXmlDesc = nullptr; if(NULL == capDesc) { return nullptr; } capXmlDesc = gcnew UsbUsb20ExtensionDescriptorType(); capXmlDesc->BLength = capDesc->bLength; capXmlDesc->BDescriptorType = capDesc->bDescriptorType; capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType; capXmlDesc->BmAttributes = capDesc->bmAttributes.AsUlong; if (capDesc->bmAttributes.AsUlong & USB_DEVICE_CAPABILITY_USB20_EXTENSION_BMATTRIBUTES_RESERVED_MASK) { capXmlDesc->ReservedBitError = gcnew String("ERROR: bits 31..2 and bit 0 are reserved and must be 0"); } if (capDesc->bmAttributes.LPMCapable == 1) { capXmlDesc->SupportsLinkPowerManagement = true; } return capXmlDesc; } /***************************************************************************** XmlGetSuperSpeedCapabilityExtensionDescriptor() Gets a Super speed capability extension descriptor object from the given descriptor *****************************************************************************/ UsbSuperSpeedExtensionDescriptorType ^ XmlGetSuperSpeedCapabilityExtensionDescriptor( PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR capDesc ) { UsbSuperSpeedExtensionDescriptorType ^ capXmlDesc = nullptr; if(NULL == capDesc) { return nullptr; } capXmlDesc = gcnew UsbSuperSpeedExtensionDescriptorType(); capXmlDesc->BLength = capDesc->bLength; capXmlDesc->BDescriptorType = capDesc->bDescriptorType; capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType; capXmlDesc->BmAttributes = capDesc->bmAttributes; capXmlDesc->BU1DevExitLat = capDesc->bU1DevExitLat; capXmlDesc->WSpeedsSupported = capDesc->wSpeedsSupported; capXmlDesc->WU2DevExitLat = capDesc->wU2DevExitLat; capXmlDesc->BFunctionalitySupport = capDesc->bFunctionalitySupport; // Add descriptive fields if (capDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_RESERVED_MASK) { capXmlDesc->ReservedAttributesBitError = gcnew String("ERROR: bits 7:2 and bit 0 are reserved"); } if (capDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_LTM_CAPABLE) { capXmlDesc->LatencyToleranceMsgCapable = true; } if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_LOW) { capXmlDesc->SupportsLowSpeed = true; } if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_FULL) { capXmlDesc->SupportsFullSpeed = true; } if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_HIGH) { capXmlDesc->SupportsHighSpeed = true; } if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_SUPER) { capXmlDesc->SupportsSuperSpeed = true; } if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_RESERVED_MASK) { capXmlDesc->ReservedSpeedError = gcnew String("ERROR: bits 15:4 are reserved"); } switch (capDesc->bFunctionalitySupport) { case UsbLowSpeed: capXmlDesc->LowestSpeed = gcnew String("low-speed"); break; case UsbFullSpeed: capXmlDesc->LowestSpeed = gcnew String("full-speed"); break; case UsbHighSpeed: capXmlDesc->LowestSpeed = gcnew String("high-speed"); break; case UsbSuperSpeed: capXmlDesc->LowestSpeed = gcnew String("SuperSpeed"); break; default: capXmlDesc->LowestSpeed = gcnew String("ERROR: Invalid value"); break; } if (capDesc->bU1DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U1_DEVICE_EXIT_MAX_VALUE) { capXmlDesc->U1DevExitLatencyString = String::Format("Less than {0} micro-seconds", capDesc->bU1DevExitLat); } else { capXmlDesc->U1DevExitLatencyString = gcnew String("ERROR: Invalid value"); } if (capDesc->wU2DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U2_DEVICE_EXIT_MAX_VALUE) { capXmlDesc->U2DevExitLatencyString = String::Format("Less than {0} micro-seconds", capDesc->wU2DevExitLat); } else { capXmlDesc->U2DevExitLatencyString = gcnew String("ERROR: Invalid value"); } return capXmlDesc; } /***************************************************************************** XmlGetContainerIdCapabilityExtensionDescriptor() Gets a Usb20Capability extension descriptor object from the given descriptor *****************************************************************************/ UsbDispContIdCapExtDescriptorType ^ XmlGetContainerIdCapabilityExtensionDescriptor( PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR capDesc ) { UsbDispContIdCapExtDescriptorType ^ capXmlDesc = nullptr; LPGUID pGuid = NULL; if(NULL == capDesc) { return nullptr; } capXmlDesc = gcnew UsbDispContIdCapExtDescriptorType(); capXmlDesc->BLength = capDesc->bLength; capXmlDesc->BDescriptorType = capDesc->bDescriptorType; capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType; capXmlDesc->BReserved = capDesc->bReserved; if (capDesc->bReserved != 0) { capXmlDesc->ReservedBitError = gcnew String("ERROR: field is reserved and should be zero"); } pGuid = (LPGUID) capDesc->ContainerID; capXmlDesc->ContainerIdStr = String::Format("{0:X}-{1:X}-{2:X}-{3:X}{4:X}-{5:X}{6:X}{7:X}{8:X}{9:X}{10:X}", pGuid->Data1, pGuid->Data2, pGuid->Data3, pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]); return capXmlDesc; } /***************************************************************************** XmlGetBillboardCapabilityDescriptor() Gets a billboard capability descriptor from a given descriptor *****************************************************************************/ UsbBillboardCapabilityDescriptorType ^ XmlGetBillboardCapabilityDescriptor( PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR capDesc, PSTRING_DESCRIPTOR_NODE stringDesc ) { UCHAR i = 0; UCHAR bNumAlternateModes = 0; UCHAR alternateModeConfiguration = 0; UsbBillboardCapabilityDescriptorType ^ capXmlDesc = nullptr; UsbBillboardSVIDType ^ svidXmlDesc = nullptr; ArrayList ^ usbSVIDDescList = gcnew ArrayList(); if (NULL == capDesc) { return nullptr; } capXmlDesc = gcnew UsbBillboardCapabilityDescriptorType(); capXmlDesc->BLength = capDesc->bLength; capXmlDesc->BDescriptorType = capDesc->bDescriptorType; capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType; capXmlDesc->IAddtionalInfoURL = capDesc->iAddtionalInfoURL; capXmlDesc->BNumberOfAlternateModes = capDesc->bNumberOfAlternateModes; capXmlDesc->BPreferredAlternateMode = capDesc->bPreferredAlternateMode; capXmlDesc->CalculatedBLength = sizeof(USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) + sizeof(capDesc->AlternateMode[0]) * (capDesc->bNumberOfAlternateModes - 1); capXmlDesc->BillboardDescriptorErrors = gcnew String(""); capXmlDesc->AddtionalInfoURL = XmlGetStringDescriptor( capDesc->iAddtionalInfoURL, stringDesc, false ); if (capDesc->VconnPower.NoVconnPowerRequired) { capXmlDesc->VConnPower = gcnew String("The adapter does not require Vconn Power. Bits 2..0 ignored"); } else { switch (capDesc->VconnPower.VConnPowerNeededForFullFunctionality) { case 0: capXmlDesc->VConnPower = gcnew String("1W needed by adapter for full functionality"); break; case 1: capXmlDesc->VConnPower = gcnew String("1.5W needed by adapter for full functionality"); break; case 7: capXmlDesc->BillboardDescriptorErrors += "ERROR: VConnPowerNeededForFullFunctionality - Reserved value being used"; break; default: capXmlDesc->VConnPower = gcnew String(String::Format("{0} W needed by adapter for full functionality", capDesc->VconnPower.VConnPowerNeededForFullFunctionality)); } } if (capDesc->bNumberOfAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE) { capXmlDesc->BillboardDescriptorErrors += "ERROR: Invalid bNumberofAlternateModes; "; } if (capDesc->VconnPower.Reserved) { capXmlDesc->BillboardDescriptorErrors += "ERROR: Reserved bits in VCONN Power being used; "; } if (capDesc->bReserved) { capXmlDesc->BillboardDescriptorErrors += "ERROR: bReserved being used; "; } bNumAlternateModes = capDesc->bNumberOfAlternateModes; if (bNumAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE) { bNumAlternateModes = BILLBOARD_MAX_NUM_ALT_MODE; } for (i = 0; i < bNumAlternateModes; i++) { svidXmlDesc = gcnew UsbBillboardSVIDType(); alternateModeConfiguration = ((capDesc->bmConfigured[i / 4]) >> ((i % 4) * 2)) & 0x3; svidXmlDesc->WSVID = capDesc->AlternateMode[i].wSVID; svidXmlDesc->BAlternateMode = capDesc->AlternateMode[i].bAlternateMode; svidXmlDesc->IAlternateModeString = capDesc->AlternateMode[i].iAlternateModeSetting; svidXmlDesc->AlternateModeString = XmlGetStringDescriptor( capDesc->AlternateMode[i].iAlternateModeSetting, stringDesc, false ); switch (alternateModeConfiguration) { case 0: svidXmlDesc->Description = gcnew String("Unspecified Error"); break; case 1: svidXmlDesc->Description = gcnew String("Alternate Mode configuration not attempted"); break; case 2: svidXmlDesc->Description = gcnew String("Alternate Mode configuration attempted but unsuccessful"); break; case 3: svidXmlDesc->Description = gcnew String("Alternate Mode configuration successful"); break; } usbSVIDDescList->Add(svidXmlDesc); } capXmlDesc->UsbBillboardSVID = reinterpret_cast^> ( usbSVIDDescList->ToArray(UsbBillboardSVIDType::typeid)); return capXmlDesc; } /***************************************************************************** XmlAddUsbDevice() Add a external to the parent Host Controller or hub. This is determined by the last object pushed on the stack *****************************************************************************/ HRESULT XmlAddUsbDevice(PSTR devName, PUSBDEVICEINFO deviceInfo) { HRESULT hr = S_OK; Object ^ parent = gXmlStack->Peek(); UsbDeviceType ^usbDevice = nullptr; NoDeviceType ^noDevice = nullptr; if (NULL == deviceInfo) { return E_FAIL; } if (deviceInfo->ConfigDesc == NULL) { // There is no USB device on this port, add a NoDevice type here instead of USB device noDevice = AddDisconnectedPort(parent); if (nullptr != noDevice) { noDevice->UsbPortNumber = gcnew String(""); noDevice->UsbPortNumber += deviceInfo->ConnectionInfo->ConnectionIndex; noDevice->Name = PACHAR_TO_STRING(devName); } else { hr = E_FAIL; } } else { usbDevice = AddUsbDevice(parent); if (nullptr != usbDevice) { // Update device information if (NULL != deviceInfo->UsbDeviceProperties) { usbDevice->HwId = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->HwId); usbDevice->DeviceId = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceId); usbDevice->ServiceName = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->Service); usbDevice->DeviceName = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceDesc); usbDevice->DeviceClass = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceClass); } // Update port number usbDevice->UsbPortNumber = gcnew String(""); usbDevice->UsbPortNumber += deviceInfo->ConnectionInfo->ConnectionIndex; usbDevice->ConnectionInfo = gcnew NodeConnectionInfoExType(); // Update protocol if (NULL != deviceInfo->ConnectionInfo) { switch(deviceInfo->ConnectionInfo->Speed) { case UsbLowSpeed: case UsbFullSpeed: usbDevice->UsbProtocol = gcnew String(USB_1_1); break; case UsbHighSpeed: usbDevice->UsbProtocol = gcnew String(USB_2_0); break; case UsbSuperSpeed: usbDevice->UsbProtocol = gcnew String(USB_3_0); break; } } // Add connection info XmlAddConnectionInfo( usbDevice->ConnectionInfo, deviceInfo->ConnectionInfo, (PUSBDEVICEINFO) deviceInfo, deviceInfo->StringDescs, deviceInfo->DeviceInfoNode ); // Add port connector if (NULL != deviceInfo->PortConnectorProps) { usbDevice->PortConnector = gcnew PortConnectorType(); XmlAddPortConnectorProps( usbDevice->PortConnector, deviceInfo->PortConnectorProps ); } // Add connectiontion info V2 if (NULL != deviceInfo->ConnectionInfoV2) { usbDevice->ConnectionInfoV2 = gcnew NodeConnectionInfoExV2Type(); XmlAddConnectionInfoV2( usbDevice->ConnectionInfoV2, deviceInfo->ConnectionInfoV2 ); } // Add configuration descriptor if (NULL != deviceInfo->ConfigDesc) { // The device configuration is allocated by XmlGetConfigDescriptors() usbDevice->DeviceConfiguration = XmlGetConfigDescriptors( (PUSBDEVICEINFO) deviceInfo, (PUSB_CONFIGURATION_DESCRIPTOR) (deviceInfo->ConfigDesc + 1), deviceInfo->StringDescs ); } // Add BOS descriptor if (NULL != deviceInfo->BosDesc) { usbDevice->BosDescriptor = XmlGetBosDescriptor( (PUSB_BOS_DESCRIPTOR) (deviceInfo->BosDesc + 1), deviceInfo->StringDescs ); } } else { hr = E_FAIL; } } return hr; } /***************************************************************************** XmlAddRootHub() Add a root hub to the parent Host Controller *****************************************************************************/ HRESULT XmlAddRootHub(PSTR rhName, PUSBROOTHUBINFO rhInfo) { HRESULT hr = S_OK; Object ^ parent = gXmlStack->Peek(); HostControllerType ^ hcParent = nullptr; PSTR rootHubName = rhInfo->HubName; UNREFERENCED_PARAMETER(rhName); hcParent = dynamic_cast (parent); if (hcParent != nullptr) { RootHubType ^ rh = nullptr; hcParent = (HostControllerType ^) parent; hcParent->RootHub = gcnew RootHubType(); rh = hcParent->RootHub; rh->HubName = PACHAR_TO_STRING(rootHubName); if (NULL != rhInfo->UsbDeviceProperties) { rh->HwId = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->HwId); rh->DeviceId = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceId); rh->ServiceName = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->Service); rh->DeviceName = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceDesc); rh->DeviceClass = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceClass); // Roothub protocol is same as HC protocol rh->UsbProtocol = hcParent->UsbProtocol; } rh->HubNodeInformation = gcnew HubNodeInformationType(); XmlAddHubNodeInformation(rh->HubNodeInformation, rhInfo->HubInfo); rh->HubInformationEx = gcnew HubInformationExType(); XmlAddHubInformationEx(rh->HubInformationEx, rhInfo->HubInfoEx); rh->HubCapabilityEx = gcnew HubCapabilitiesExType(); XmlAddHubCapabilitiesEx(rh->HubCapabilityEx, rhInfo->HubCapabilityEx); // Push root hub on to stack gXmlStack->Push(rh); } else { // Root hub should be connected to a host controller hr = E_FAIL; } return S_OK; } /***************************************************************************** XmlSetVersion() Set version information in XML tree *****************************************************************************/ VOID XmlSetVersion( UCHAR uvcMajorVersion, UCHAR uvcMinorVersion, UCHAR uvcMajorSpecVersion, UCHAR uvcMinorSpecVersion ) { MachineInfoType ^ mInfo; gXmlView->MachineInfo = gcnew MachineInfoType(); mInfo = gXmlView->MachineInfo; mInfo->UvcMajorVersion = uvcMajorVersion; mInfo->UvcMinorVersion = uvcMinorVersion; mInfo->UvcMajorSpecVersion = uvcMajorSpecVersion; mInfo->UvcMinorSpecVersion = uvcMinorSpecVersion; } /***************************************************************************** InitXmlHelper() Initialize XML helper *****************************************************************************/ HRESULT InitXmlHelper() { HRESULT hr = S_OK; (XmlGlobal::Instance())->ViewAll = gcnew UvcViewAll(); (XmlGlobal::Instance())->ViewAll->UvcView = gcnew UvcViewType(); // // Initialize fields to null so we can check against them for allocation // (XmlGlobal::Instance())->ViewAll->UvcView->MachineInfo = nullptr; (XmlGlobal::Instance())->ViewAll->UvcView->UsbTree = nullptr; XmlSetVersion( UVC_SPEC_MAJOR_VERSION, UVC_SPEC_MINOR_VERSION, USBVIEW_MAJOR_VERSION, USBVIEW_MINOR_VERSION ); gXmlStack->Push(gXmlView); gXmlViewInitialized = TRUE; return hr; } /***************************************************************************** SaveXml() Saves the inmemory USB view as XML file *****************************************************************************/ HRESULT SaveXml(LPTSTR szfileName, DWORD dwCreationDisposition) { HRESULT hr = S_OK; if (gXmlViewInitialized) { try { String ^fileName = PACHAR_TO_STRING(szfileName); XmlSerializer ^ serializer = gcnew XmlSerializer(UvcViewAll::typeid); TextWriter ^ writer = nullptr; if (dwCreationDisposition != CREATE_ALWAYS) { // Check if file exits and return failure if it does if (File::Exists(fileName)) { hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS); } } // Check if file name is NULL if (String::IsNullOrEmpty(fileName)) { hr = E_INVALIDARG; } if (SUCCEEDED(hr)) { writer = gcnew StreamWriter(fileName); serializer->Serialize(writer, (XmlGlobal::Instance())->ViewAll); writer->Close(); } // Release and reinit XML View for next iteration if requested ReleaseXmlWriter(); InitXmlHelper(); } catch(Exception ^ ex) { hr = (HRESULT) Marshal::GetHRForException(ex); } } else { hr = E_FAIL; } return hr; } /***************************************************************************** ReleaseXmlWriter() *****************************************************************************/ HRESULT ReleaseXmlWriter() { HRESULT hr = S_OK; if (gXmlViewInitialized) { gXmlViewInitialized = FALSE; delete XmlGlobal::Instance(); } return hr; } ================================================ FILE: tests/projects/windows/winsdk/usbview/xmlhelper.h ================================================ /*++ Copyright (c) 1997-2011 Microsoft Corporation Module Name: XMLHELPER.H Abstract: This helper file declaration for XML helper APIs Environment: user mode Revision History: 05-05-11 : created --*/ #pragma once /***************************************************************************** I N C L U D E S *****************************************************************************/ #include "uvcview.h" EXTERN_C HRESULT InitXmlHelper(); EXTERN_C HRESULT ReleaseXmlWriter(); EXTERN_C HRESULT SaveXml(LPTSTR szfileName, DWORD dwCreationDisposition); EXTERN_C HRESULT XmlAddHostController( PSTR hcName, PUSBHOSTCONTROLLERINFO hcInfo ); EXTERN_C HRESULT XmlAddRootHub(PSTR rhName, PUSBROOTHUBINFO rhInfo); EXTERN_C HRESULT XmlAddExternalHub(PSTR ehName, PUSBEXTERNALHUBINFO ehInfo); EXTERN_C HRESULT XmlAddUsbDevice(PSTR devName, PUSBDEVICEINFO deviceInfo); EXTERN_C VOID XmlNotifyEndOfNodeList(PVOID pContext); ================================================ FILE: tests/projects/windows/winsdk/windemo/main.cpp ================================================ // testw.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "test.h" #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. MSG msg; HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_TESTW, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTW)); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // // COMMENTS: // // This function and its usage are only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this function // so that the application will get 'well formed' small icons associated // with it. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTW)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TESTW); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // FUNCTION: InitInstance(HINSTANCE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // Message handler for about box. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } ================================================ FILE: tests/projects/windows/winsdk/windemo/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by test.rc // #define IDS_APP_TITLE 103 #define IDR_MAINFRAME 128 #define IDD_TESTW_DIALOG 102 #define IDD_ABOUTBOX 103 #define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDI_TESTW 107 #define IDI_SMALL 108 #define IDC_TESTW 109 #define IDC_MYICON 2 #ifndef IDC_STATIC #define IDC_STATIC -1 #endif // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 130 #define _APS_NEXT_RESOURCE_VALUE 129 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif ================================================ FILE: tests/projects/windows/winsdk/windemo/stdafx.cpp ================================================ // stdafx.cpp : source file that includes just the standard includes // testw.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H // and not in this file ================================================ FILE: tests/projects/windows/winsdk/windemo/stdafx.h ================================================ // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #pragma once #include "targetver.h" #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files: #include // C RunTime Header Files #include #include #include #include // TODO: reference additional headers your program requires here ================================================ FILE: tests/projects/windows/winsdk/windemo/targetver.h ================================================ #pragma once // The following macros define the minimum required platform. The minimum required platform // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run // your application. The macros work by enabling all features available on platform versions up to and // including the version specified. // Modify the following defines if you have to target a platform prior to the ones specified below. // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef WINVER // Specifies that the minimum required platform is Windows Vista. #define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. #endif #ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. #define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. #endif ================================================ FILE: tests/projects/windows/winsdk/windemo/test ================================================ //Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #ifndef APSTUDIO_INVOKED #include "targetver.h" #endif #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE 9, 1 #pragma code_page(936) ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_TESTW ICON "testw.ico" IDI_SMALL ICON "small.ico" ///////////////////////////////////////////////////////////////////////////// // // Menu // IDC_TESTW MENU BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", IDM_EXIT END POPUP "&Help" BEGIN MENUITEM "&About ...", IDM_ABOUT END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_TESTW ACCELERATORS BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About testw" FONT 8, "MS Shell Dlg" BEGIN ICON IDR_MAINFRAME,IDC_STATIC,14,14,21,20 LTEXT "testw, Version 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX LTEXT "Copyright (C) 2020",IDC_STATIC,42,26,114,8 DEFPUSHBUTTON "OK",IDOK,113,41,50,14,WS_GROUP END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_ABOUTBOX, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 163 TOPMARGIN, 7 BOTTOMMARGIN, 55 END END #endif // APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#ifndef APSTUDIO_INVOKED\r\n" "#include ""targetver.h""\r\n" "#endif\r\n" "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""windows.h""\r\n" "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDC_TESTW "TESTW" IDS_APP_TITLE "testw" END #endif ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: tests/projects/windows/winsdk/windemo/test.h ================================================ #pragma once #include "resource.h" ================================================ FILE: tests/projects/windows/winsdk/windemo/test.rc ================================================ //Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #ifndef APSTUDIO_INVOKED #include "targetver.h" #endif #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE 9, 1 #pragma code_page(936) ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_TESTW ICON "test.ico" IDI_SMALL ICON "small.ico" ///////////////////////////////////////////////////////////////////////////// // // Menu // IDC_TESTW MENU BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", IDM_EXIT END POPUP "&Help" BEGIN MENUITEM "&About ...", IDM_ABOUT END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_TESTW ACCELERATORS BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About testw" FONT 8, "MS Shell Dlg" BEGIN ICON IDR_MAINFRAME,IDC_STATIC,14,14,21,20 LTEXT "testw, Version 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX LTEXT "Copyright (C) 2020",IDC_STATIC,42,26,114,8 DEFPUSHBUTTON "OK",IDOK,113,41,50,14,WS_GROUP END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_ABOUTBOX, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 163 TOPMARGIN, 7 BOTTOMMARGIN, 55 END END #endif // APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#ifndef APSTUDIO_INVOKED\r\n" "#include ""targetver.h""\r\n" "#endif\r\n" "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""windows.h""\r\n" "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDC_TESTW "TESTW" IDS_APP_TITLE "testw" END #endif ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: tests/projects/windows/winsdk/windemo/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") add_rules("win.sdk.application") add_files("*.rc", "*.cpp") ================================================ FILE: tests/projects/xmake_cli/hello/src/lni/main.c ================================================ #include static tb_byte_t const g_luafiles_data[] = { #include "luafiles.xmz.h" }; static tb_int_t lni_test_hello(lua_State* lua) { lua_pushliteral(lua, "hello xmake!"); return 1; } static tb_void_t lni_initalizer(xm_engine_ref_t engine, lua_State* lua) { static luaL_Reg const lni_test_funcs[] = { {"hello", lni_test_hello} , {tb_null, tb_null} }; xm_engine_register(engine, "test", lni_test_funcs); xm_engine_add_embedfiles(engine, g_luafiles_data, sizeof(g_luafiles_data)); } tb_int_t main(tb_int_t argc, tb_char_t** argv) { tb_char_t* taskargv[] = {"lua", "-D", "lua.main", tb_null}; return xm_engine_run("hello", argc, argv, taskargv, lni_initalizer); } ================================================ FILE: tests/projects/xmake_cli/hello/src/lua/main.lua ================================================ import("core.base.option") import("lib.lni.test") function main () print(test.hello()) local argv = option.get("arguments") if argv then print(argv) end end ================================================ FILE: tests/projects/xmake_cli/hello/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("libxmake") target("hello") add_rules("xmake.cli") add_files("src/lni/*.c") add_files("src/lua/*.lua", {rootdir = "src"}) add_packages("libxmake") ================================================ FILE: tests/projects/xmake_cli/ide_integration/assets/targetpath.lua ================================================ import("core.project.config") import("core.project.project") import("lib.lni") function main (targetname) config.load() if not os.isfile(os.projectfile()) then return end local target = nil if targetname then target = project.target(targetname) end if not target then for _, t in pairs(project.targets()) do local default = t:get("default") if (default == nil or default == true) and t:get("kind") == "binary" then target = t break end end end if target then local targetfile = target:targetfile() if not path.is_absolute(targetfile) then targetfile = path.absolute(targetfile, os.projectdir()) end lni.result = targetfile end end ================================================ FILE: tests/projects/xmake_cli/ide_integration/assets/targets.lua ================================================ import("core.project.config") import("core.project.project") import("core.base.json") import("lib.lni") function main () config.load() local names = {} for name, _ in pairs((project.targets())) do table.insert(names, name) end table.sort(names) if json.mark_as_array then json.mark_as_array(names) end lni.result = json.encode(names) end ================================================ FILE: tests/projects/xmake_cli/ide_integration/src/main.c ================================================ #include static lua_State* g_lua = tb_null; static tb_void_t lni_initalizer(xm_engine_ref_t engine, lua_State* lua) { g_lua = lua; } static tb_char_t const* load_scriptfile(xm_engine_ref_t engine, tb_char_t const* filepath, tb_char_t const* arg1) { // reset result first lua_getglobal(g_lua, "_lni"); lua_pushnil(g_lua); lua_setfield(g_lua, -2, "result"); lua_pop(g_lua, 1); // load script and get result (string) tb_char_t* argv[] = {"xmake"}; tb_char_t* taskargv[] = {"lua", "-D", (tb_char_t*)filepath, (tb_char_t*)arg1, tb_null}; tb_char_t const* result = tb_null; if (xm_engine_main(engine, 1, argv, taskargv) == 0) { lua_getglobal(g_lua, "_lni"); lua_getfield(g_lua, -1, "result"); if (lua_isstring(g_lua, -1)) { result = tb_strdup(lua_tostring(g_lua, -1)); } lua_pop(g_lua, 2); } return result; } static tb_void_t dump_targets(xm_engine_ref_t engine) { tb_trace_i("------------------------- targets -------------------------"); tb_char_t const* result = load_scriptfile(engine, "assets/targets.lua", tb_null); if (result) { tb_trace_i("result: %s", result); tb_free(result); } } static tb_void_t dump_targetpath(xm_engine_ref_t engine) { tb_trace_i("------------------------- targetpath -------------------------"); tb_char_t const* result = load_scriptfile(engine, "assets/targetpath.lua", "ide"); if (result) { tb_trace_i("result: %s", result); tb_free(result); } } tb_int_t main(tb_int_t argc, tb_char_t** argv) { if (xm_init()) { xm_engine_ref_t engine = xm_engine_init("xmake", lni_initalizer); if (engine) { dump_targets(engine); dump_targetpath(engine); xm_engine_exit(engine); } xm_exit(); } return 0; } ================================================ FILE: tests/projects/xmake_cli/ide_integration/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("libxmake") target("ide") add_files("src/*.c") add_packages("libxmake") set_rundir(".") ================================================ FILE: tests/projects/xmake_cli/xmake/src/main.c ================================================ #include tb_int_t main(tb_int_t argc, tb_char_t** argv) { return xm_engine_run("xmake", argc, argv, tb_null, tb_null); } ================================================ FILE: tests/projects/xmake_cli/xmake/src/xmake.rc ================================================ #include "xmake.config.h" #include "winres.h" #define _STR(x) #x #define STR(x) _STR(x) VS_VERSION_INFO VERSIONINFO FILEVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0 PRODUCTVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "000004B0" BEGIN VALUE "Comments", "A cross-platform build utility based on Lua\nwebsite: https://xmake.io" VALUE "CompanyName", "The Xmake Open Source Community" VALUE "FileDescription", "XMake build utility" VALUE "FileVersion", XM_CONFIG_VERSION "+" STR(XM_CONFIG_VERSION_BUILD) VALUE "InternalName", "xmake" VALUE "LegalCopyright", "Copyright (C) 2015-present Ruki Wang, https://xmake.io" VALUE "LegalTrademarks", "" VALUE "OriginalFilename", "xmake.exe" VALUE "ProductName", "XMake" VALUE "ProductVersion", XM_CONFIG_VERSION "+" STR(XM_CONFIG_VERSION_BUILD) END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0, 1200 END END IDI_APP ICON DISCARDABLE "xmake.ico" ================================================ FILE: tests/projects/xmake_cli/xmake/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("libxmake") target("xmake") add_files("src/*.c") if is_plat("windows") then add_files("src/*.rc") end add_packages("libxmake") ================================================ FILE: tests/projects/zig/console/src/main.zig ================================================ const std = @import("std"); pub fn main() !void { std.debug.print("Hello, {s}!\n", .{"world"}); } ================================================ FILE: tests/projects/zig/console/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/*.zig") ================================================ FILE: tests/projects/zig/console_c_call_zig/src/main.c ================================================ #include int add(int a, int b); int main(int argc, char **argv) { int result = add(42, 1337); printf("%d\n", result); return 0; } ================================================ FILE: tests/projects/zig/console_c_call_zig/src/test.zig ================================================ export fn add(a: i32, b: i32) i32 { return a + b; } ================================================ FILE: tests/projects/zig/console_c_call_zig/xmake.lua ================================================ add_rules("mode.debug", "mode.release") add_requires("zig >=0.10") target("demo") set_kind("binary") add_files("src/*.c") add_files("src/*.zig") set_toolchains("@zig") ================================================ FILE: tests/projects/zig/shared_library/src/main.zig ================================================ const std = @import("std"); extern fn add(a: i32, b: i32) i32; pub fn main() !void { std.debug.print("Hello, {s} - {d}!\n", .{"world", add(1, 1)}); } ================================================ FILE: tests/projects/zig/shared_library/src/test.zig ================================================ export fn add(a: i32, b: i32) i32 { return a + b; } ================================================ FILE: tests/projects/zig/shared_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("testlib") set_kind("shared") add_files("src/test.zig") target("test") set_kind("binary") add_deps("testlib") add_files("src/main.zig") ================================================ FILE: tests/projects/zig/static_library/src/main.zig ================================================ const std = @import("std"); extern fn add(a: i32, b: i32) i32; pub fn main() !void { std.debug.print("Hello, {s} - {d}!\n", .{"world", add(1, 1)}); } ================================================ FILE: tests/projects/zig/static_library/src/test.zig ================================================ export fn add(a: i32, b: i32) i32 { return a + b; } ================================================ FILE: tests/projects/zig/static_library/xmake.lua ================================================ add_rules("mode.debug", "mode.release") target("testlib") set_kind("static") add_files("src/test.zig") target("test") set_kind("binary") add_deps("testlib") add_files("src/main.zig") ================================================ FILE: tests/run.lua ================================================ -- imports import("core.base.task") import("core.base.option") import("runner", {rootdir = os.scriptdir()}) function _run_test(script, opt) runner(script, opt) end -- run test with the given name function _run_test_filter(name) local tests = {} local root = path.absolute(os.scriptdir()) for _, script in ipairs(os.files(path.join(root, "**", name, "**", "test.lua"))) do if not script:find(".xmake", 1, true) then table.insert(tests, path.absolute(script)) end end for _, script in ipairs(os.files(path.join(root, name, "**", "test.lua"))) do if not script:find(".xmake", 1, true) then table.insert(tests, path.absolute(script)) end end for _, script in ipairs(os.files(path.join(root, "**", name, "test.lua"))) do table.insert(tests, path.absolute(script)) end for _, script in ipairs(os.files(path.join(root, name, "test.lua"))) do table.insert(tests, path.absolute(script)) end tests = table.unique(tests) if #tests == 0 then utils.warning("no test have run, please check your filter .. (%s)", name) else cprint("> %d test(s) found", #tests) if option.get("diagnosis") then for _, v in ipairs(tests) do cprint("> %s", v) end end for i, v in ipairs(tests) do _run_test(v, {index = i, total = #tests}) end cprint("> %d test(s) succeed", #tests) end end function main(name) return _run_test_filter(name or "/") end ================================================ FILE: tests/runner.lua ================================================ import("core.base.option") import("test_utils.context", { alias = "test_context" }) function main(script, opt) opt = opt or {} if os.isdir(script) then script = path.join(script, "test.lua") end script = path.absolute(script) assert(path.filename(script) == "test.lua", "file(%s) should named `test.lua`", script) assert(os.isfile(script), "should be a file") -- disable statistics os.setenv("XMAKE_STATS", "false") -- init test context local context = test_context(script) local root = path.directory(script) local verbose = option.get("verbose") or option.get("diagnosis") -- trace cprint(">> [%d/%d]: testing %s ...", opt.index, opt.total, path.relative(root)) -- get test functions local data = import("test", { rootdir = root, anonymous = true }) if data.main then -- ignore everthing when we found a main function data = { test_main = data.main } end -- enter script directory local old_dir = os.cd(root) -- run test local succeed_count = 0 local start_time = os.mclock() for k, v in pairs(data) do if k:startswith("test") and type(v) == "function" then if verbose then print(">> running %s ...", k) end context.func = v context.funcname = k local result = try { function () -- set workdir for each test os.cd(root) return v(context) end, catch { function (errors) if errors then errors = tostring(errors) end if errors and not errors:find("aborting because of ") then context:print_error(errors, v, "unhandled error") else raise(errors) end end } } if context:is_skipped(result) then print(">> skipped %s : %s", k, result.reason) end succeed_count = succeed_count + 1 end end if verbose then print(">> finished %d test method(s), spent %0.02fs", succeed_count, (os.mclock() - start_time) / 1000) end -- leave script directory os.cd(old_dir) end ================================================ FILE: tests/test/test.lua ================================================ function test_are_same(t) t:are_same(1, 1) t:are_same("1", "1") t:are_same(nil, nil) t:are_same(true, true) t:are_same(1.34, 1.34) t:are_same(test_are_same, test_are_same) t:are_not_same({}, {}) t:are_not_same(1, "1") end function test_are_equal(t) t:are_equal(1, 1) t:are_equal("1", "1") t:are_equal(nil, nil) t:are_equal(true, true) t:are_equal(1.34, 1.34) t:are_equal(test_are_same, test_are_same) t:are_equal({}, {}) t:are_equal({ a = 1 }, { a = 1 }) t:are_equal({ a = { a= 1}}, { a = {a=1} }) t:are_not_equal(1, "1") t:are_not_equal({ a = 1 }, { a = 1, b = 2 }) t:are_not_equal({ a = 1, c = 3 }, { a = 1, b = 2 }) t:are_not_equal({ a = 1}, { a = 1, b = 2 }) t:are_not_equal({ a = { a= 1}}, { a = {a=2} }) end function test_require(t) t:require(true) t:require({}) t:require(0) t:require("") t:require_not(false) t:require_not(nil) end function test_will_raise(t) t:will_raise(function () raise("error: xxx") end, "error") t:will_raise(function () raise(" ") end, "%s") t:will_raise(function () raise("") end) t:will_raise(function () print("A test failed message will be printed") t:will_raise(function() end) end, "aborting because of ${red}failed assertion${reset}") end ================================================ FILE: tests/test_utils/check.lua ================================================ function _tablelength(table) local count = 0 for _ in pairs(table) do count = count + 1 end return count end function _get_rep(value) if type(value) == "nil" then return "(nil)" end if type(value) == "string" then return "`" .. value .. "`" end return tostring(value) end function same(actual, expected) if actual ~= actual and expected ~= expected then return true, _get_rep(actual), _get_rep(expected) end return actual == expected, _get_rep(actual), _get_rep(expected) end function equal(actual, expected) local same, ap, ep = same(actual, expected) if same then return true, ap, ep end if type(expected) == "table" and type(actual) == "table" then local al = _tablelength(actual) local el = _tablelength(expected) if al ~= el then return false, vformat("{...(%d elements)}", al), vformat("{...(%d elements)}", el) end for k, v in pairs(expected) do local av = actual[k] local eq, app, epp = equal(av, v) if not eq then return false, vformat("{[%s] = %s, ...}", k, app), vformat("{[%s] = %s, ...}", k, epp) end end return true, "{...}", "{...}" end return false, ap, ep end ================================================ FILE: tests/test_utils/context.lua ================================================ import("test_build") import("test_skip") import("test_assert") function main(filename) local context = { filename = filename } table.join2(context, test_build()) table.join2(context, test_skip()) table.join2(context, test_assert()) return context end ================================================ FILE: tests/test_utils/print_error.lua ================================================ function _getinfo(v) local info = debug.getinfo(v) if info == nil then return end if info and info.source:startswith("@") then info.fullpath = path.absolute(vformat(info.source:sub(2)), os.workingdir()) info.path = path.relative(info.fullpath, os.workingdir()) end return info end function _getfuncs(funcs_or_filename) local funcs = nil if type(funcs_or_filename) == "function" then funcs = { _getinfo(funcs_or_filename) } elseif type(funcs_or_filename) == "table" then funcs = {} for _, v in ipairs(funcs_or_filename) do table.join2(funcs, _getfuncs(v)) end else assert(type(funcs_or_filename) == "string") funcs_or_filename = path.absolute(funcs_or_filename) funcs = {} local uplevel = 2 local func = nil repeat func = _getinfo(uplevel) if func and func.fullpath == funcs_or_filename then table.insert(funcs, func) end uplevel = uplevel + 1 until func == nil end return funcs end function main(t, message, funcs_or_filename, abort_reason) local funcs = _getfuncs(funcs_or_filename) cprint(">> ${red}test failed:${reset} %s", message) for _, func in ipairs(funcs) do local line = (func.currentline >= 0) and func.currentline or func.linedefined local name = (func.func == t.func) and t.funcname or func.name or "(anonymous)" cprint(">> function %s ${underline}%s${reset}:${bright}%d${reset}", name, func.path, line) end raise("aborting because of ${red}%s${reset} ...", abort_reason or "failed assertion") end ================================================ FILE: tests/test_utils/test_assert.lua ================================================ import("check") local test_assert = { print_error = import("print_error", { anonymous = true }).main } function test_assert:require(value) if not value then self:print_error(vformat("require ${green}true${reset} but got ${red}%s${reset}", value), self.filename) end end function test_assert:require_not(value) if value then self:print_error(vformat("require ${green}false${reset} but got ${red}%s${reset}", value), self.filename) end end function test_assert:are_same(actual, expected) local r, ap, ep = check.same(actual, expected) if not r then self:print_error(format("expected: ${green}%s${reset}, actual ${red}%s${reset}", ep, ap), self.filename) end end function test_assert:are_not_same(actual, expected) local r, ap, ep = check.same(actual, expected) if r then self:print_error(format("expected: ${green}%s${reset}, actual ${red}%s${reset}", ep, ap), self.filename) end end function test_assert:are_equal(actual, expected) local r, ap, ep = check.equal(actual, expected) if not r then self:print_error(format("expected: ${green}%s${reset}, actual ${red}%s${reset}", ep, ap), self.filename) end end function test_assert:are_not_equal(actual, expected) local r, ap, ep = check.equal(actual, expected) if r then self:print_error(format("expected: ${green}%s${reset}, actual ${red}%s${reset}", ep, ap), self.filename) end end test_assert._will_raise_stack = {} function test_assert:will_raise(func, message_pattern) table.insert(self._will_raise_stack, 1, debug.getinfo(2).func) try { func, finally { function (ok, error) local funcs = { func, unpack(self._will_raise_stack) } if ok then self:print_error("expected raise but finished successfully", funcs) elseif message_pattern and not error:find(message_pattern, 1, true) and not error:find(message_pattern) then self:print_error(format("expected raise with message ${green}%s${reset} but got ${red}%s${reset}", message_pattern, error), funcs) end end } } table.remove(self._will_raise_stack, 1) end function main() return test_assert end ================================================ FILE: tests/test_utils/test_build.lua ================================================ local test_build = {} function test_build:build(argv) os.exec("xmake f -c -D -y") os.exec("xmake -D") end function main() return test_build end ================================================ FILE: tests/test_utils/test_skip.lua ================================================ local test_skip = { _is_skipped_tag = {true} } function test_skip:skip(reason) return { is_skipped = self._is_skipped_tag, reason = reason, context = self } end function test_skip:is_skipped(result) return result and result.context and result.context._is_skipped_tag == result.is_skipped end function main() return test_skip end ================================================ FILE: tests/ui/desktop.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-2020, Xmake Open Source Community. -- -- @author ruki -- @file desktop.lua -- -- imports import("core.ui.log") import("core.ui.rect") import("core.ui.view") import("core.ui.label") import("core.ui.event") import("core.ui.button") import("core.ui.application") -- the demo application local demo = application() -- init demo function demo:init() -- init name application.init(self, "demo") -- show desktop, menubar and statusbar self:insert(self:desktop()) self:insert(self:menubar()) self:insert(self:statusbar()) -- init title self:menubar():title():text_set("Menu Bar (Hello)") -- add title label self:desktop():insert(label:new("title", rect {0, 0, 12, 1}, "hello ltui!"):textattr_set("white"), {centerx = true}) -- add yes button self:desktop():insert(button:new("yes", rect {0, 1, 7, 2}, "< Yes >"):textattr_set("white"), {centerx = true}) -- add no button self:desktop():insert(button:new("no", rect {0, 2, 6, 3}, "< No >"):textattr_set("white"), {centerx = true}) end -- on event function demo:on_event(e) if application.on_event(self, e) then return true end if e.type == event.ev_keyboard then self:statusbar():info():text_set(e.key_name) if e.key_name == "s" then self:statusbar():show(not self:statusbar():state("visible")) elseif e.key_name == "m" then self:menubar():show(not self:menubar():state("visible")) elseif e.key_name == "d" then self:desktop():show(not self:desktop():state("visible")) end end end -- on resize function demo:on_resize() for v in self:desktop():views() do self:center(v, {centerx = true}) end application.on_resize(self) end -- main entry function main(...) demo:run(...) end ================================================ FILE: tests/ui/dialog.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-2020, Xmake Open Source Community. -- -- @author ruki -- @file dialog.lua -- -- imports import("core.ui.log") import("core.ui.rect") import("core.ui.view") import("core.ui.label") import("core.ui.event") import("core.ui.boxdialog") import("core.ui.textdialog") import("core.ui.inputdialog") import("core.ui.application") -- the demo application local demo = application() -- init demo function demo:init() -- init name application.init(self, "demo") -- init background self:background_set("blue") -- init main dialog self:insert(self:dialog_main()) -- init input dialog self:insert(self:dialog_input(), {centerx = true, centery = true}) -- init tips dialog self:insert(self:dialog_tips(), {centerx = true, centery = true}) end -- main dialog function demo:dialog_main() local dialog_main = self._DIALOG_MAIN if not dialog_main then dialog_main = boxdialog:new("dialog.main", rect {1, 1, self:width() - 1, self:height() - 1}, "main dialog") dialog_main:text():text_set("The project focuses on making development and building easier and provides many features (.e.g package, install, plugin, macro, action, option, task ...), so that any developer can quickly pick it up and enjoy the productivity boost when developing and building project.") dialog_main:button_add("tips", "< Tips >", function (v) self:view("dialog.tips"):show(true, {focused = true}) end) dialog_main:button_add("input", "< Input >", function (v) self:view("dialog.input"):show(true, {focused = true}) end) dialog_main:button_add("help", "< Help >", function (v) self:insert(self:dialog_help()) end) dialog_main:button_add("quit", "< Quit >", "cm_quit") self._DIALOG_MAIN = dialog_main end return dialog_main end -- help dialog function demo:dialog_help() local dialog_help = self._DIALOG_HELP if not dialog_help then dialog_help = textdialog:new("dialog.help", rect {1, 1, self:width() - 1, self:height() - 1}, "README") dialog_help:option_set("scrollable", true) local helptext = nil local file = io.open("./LICENSE.md", 'r') if file then helptext = file:read("*a") file:close() end if helptext then dialog_help:text():text_set(helptext) end dialog_help:button_add("exit", "< Exit >", function (v) self:remove(dialog_help) end) self._DIALOG_HELP = dialog_help end return dialog_help end -- input dialog function demo:dialog_input() local dialog_input = self._DIALOG_INPUT if not dialog_input then dialog_input = inputdialog:new("dialog.input", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background()) dialog_input:frame():background_set("cyan") dialog_input:text():text_set("please input text:"):textattr_set("red") dialog_input:button_add("no", "< No >", function (v) dialog_input:show(false) end) dialog_input:button_add("yes", "< Yes >", function (v) self:dialog_main():text():text_set(dialog_input:textedit():text()) dialog_input:show(false) end) dialog_input:show(false) self._DIALOG_INPUT = dialog_input end return dialog_input end -- tips dialog function demo:dialog_tips() local dialog_tips = self._DIALOG_TIPS if not dialog_tips then dialog_tips = textdialog:new("dialog.tips", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background()) dialog_tips:frame():background_set("cyan") dialog_tips:text():text_set("hello ltui! (https://tboox.org)\nA cross-platform terminal ui library based on Lua"):textattr_set("red") dialog_tips:button_add("yes", "< Yes >", function (v) dialog_tips:show(false) end) dialog_tips:button_add("no", "< No >", function (v) dialog_tips:show(false) end) self._DIALOG_TIPS = dialog_tips end return dialog_tips end -- on resize function demo:on_resize() self:dialog_main():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) self:dialog_help():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) self:center(self:dialog_input(), {centerx = true, centery = true}) self:center(self:dialog_tips(), {centerx = true, centery = true}) application.on_resize(self) end -- main entry function main(...) demo:run(...) end ================================================ FILE: tests/ui/events.lua ================================================ --!A cross-platform terminal ui library based on Lua -- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2020, Xmake Open Source Community. -- -- @author ruki -- @file events.lua -- -- imports import("core.ui.rect") import("core.ui.label") import("core.ui.event") import("core.ui.window") import("core.ui.application") -- the demo application local demo = application() -- init demo function demo:init() -- init name application.init(self, "demo") -- init background self:background_set("black") -- init body window self:insert(self:body_window()) -- init teste self:body_window():panel():insert(self:teste()) end -- get body window function demo:body_window() if not self._BODY_WINDOW then self._BODY_WINDOW = window:new("window.body", rect {1, 1, self:width() - 1, self:height() - 1}, "main window") end return self._BODY_WINDOW end -- get teste label function demo:teste() if not self._TESTE then self._TESTE = label:new('demo.label', rect {0, 0, 40, 5}, 'this is a test') end return self._TESTE end -- on resize function demo:on_resize() self:body_window():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) application.on_resize(self) end -- on event function demo:on_event(e) if e.type < event.ev_max then self:teste():text_set('type: ' .. tostring(e.type) .. '; name: ' .. tostring(e.key_name or e.btn_name) .. '; code: ' .. tostring(e.key_code or e.x) .. '; meta: ' .. tostring(e.key_code or e.y)) end application.on_event(self, e) end -- main entry function main(...) demo:run(...) end ================================================ FILE: tests/ui/inputdialog.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-2020, Xmake Open Source Community. -- -- @author ruki -- @file inputdialog.lua -- -- imports import("core.ui.log") import("core.ui.rect") import("core.ui.view") import("core.ui.label") import("core.ui.event") import("core.ui.inputdialog") import("core.ui.application") -- the demo application local demo = application() -- init demo function demo:init() -- init name application.init(self, "demo") -- init background self:background_set("blue") -- init input dialog self:insert(self:dialog_input(), {centerx = true, centery = true}) end -- input dialog function demo:dialog_input() local dialog_input = self._DIALOG_INPUT if not dialog_input then dialog_input = inputdialog:new("dialog.input", rect{0, 0, math.floor(self:width() / 2), math.floor(self:height() / 3)}) dialog_input:text():text_set("please input text:") dialog_input:button_add("no", "< No >", function (v) dialog_input:quit() end) dialog_input:button_add("yes", "< Yes >", function (v) dialog_input:quit() end) self._DIALOG_INPUT = dialog_input end return dialog_input end -- on resize function demo:on_resize() self:dialog_input():bounds_set(rect{0, 0, math.floor(self:width() / 2), math.floor(self:height() / 3)}) self:center(self:dialog_input(), {centerx = true, centery = true}) application.on_resize(self) end -- main entry function main(...) demo:run(...) end ================================================ FILE: tests/ui/mconfdialog.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-2020, Xmake Open Source Community. -- -- @author ruki -- @file mconfdialog.lua -- -- imports import("core.ui.log") import("core.ui.rect") import("core.ui.view") import("core.ui.label") import("core.ui.event") import("core.ui.action") import("core.ui.menuconf") import("core.ui.mconfdialog") import("core.ui.application") -- the demo application local demo = application() -- init demo function demo:init() -- init name application.init(self, "demo") -- init background self:background_set("blue") -- init configs local configs_sub2 = {} table.insert(configs_sub2, menuconf.boolean {description = "boolean config sub-item2"}) table.insert(configs_sub2, menuconf.number {value = 10, default = 10, description = "number config sub-item2"}) table.insert(configs_sub2, menuconf.string {value = "armv7", description = "string config sub-item2"}) table.insert(configs_sub2, menuconf.menu {description = "menu config sub-item2"}) local configs_sub = {} table.insert(configs_sub, menuconf.boolean {description = "boolean config sub-item"}) table.insert(configs_sub, menuconf.number {value = 90, default = 10, description = "number config sub-item"}) table.insert(configs_sub, menuconf.string {value = "arm64", description = "string config sub-item"}) table.insert(configs_sub, menuconf.menu {description = "menu config sub-item", configs = configs_sub2}) table.insert(configs_sub, menuconf.choice {value = 2, values = {2, 5, 16, 87}, description = "choice config sub-item"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item1"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item2"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item3"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item4"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item5"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item6"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item7"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item8"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item9"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item10"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item11"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item12"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item13"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item14"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item15"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item16"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item17"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item18"}) table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = "number config item19"}) local configs = {} table.insert(configs, menuconf.boolean {description = "boolean config item"}) table.insert(configs, menuconf.boolean {default = true, new = false, description = {"boolean config item2", " - more description info", " - more description info", " - more description info"}}) table.insert(configs, menuconf.number {value = 6, default = 10, description = "number config item"}) table.insert(configs, menuconf.string {value = "x86_64", description = "string config item"}) table.insert(configs, menuconf.menu {description = "menu config item", configs = configs_sub}) table.insert(configs, menuconf.choice {value = 3, values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, default = 2, description = "choice config item"}) -- init menu config dialog self:dialog_mconf():load(configs) self:insert(self:dialog_mconf()) end -- get mconfdialog function demo:dialog_mconf() local dialog_mconf = self._DIALOG_MCONF if not dialog_mconf then dialog_mconf = mconfdialog:new("mconfdialog.main", rect{1, 1, self:width() - 1, self:height() - 1}, "menu config") dialog_mconf:action_set(action.ac_on_exit, function (v) self:quit() end) dialog_mconf:action_set(action.ac_on_save, function (v) -- TODO save configs dialog_mconf:quit() end) self._DIALOG_MCONF = dialog_mconf end return dialog_mconf end -- on resize function demo:on_resize() self:dialog_mconf():bounds_set(rect{1, 1, self:width() - 1, self:height() - 1}) application.on_resize(self) end -- main entry function main(...) demo:run(...) end ================================================ FILE: tests/ui/utf8dialog.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-2020, Xmake Open Source Community. -- -- @author ruki, laelnasan -- @file inputdialog.lua -- -- imports import("core.ui.log") import("core.ui.rect") import("core.ui.view") import("core.ui.label") import("core.ui.event") import("core.ui.button") import("core.ui.boxdialog") import("core.ui.textdialog") import("core.ui.inputdialog") import("core.ui.application") -- the demo application local demo = application() -- init demo function demo:init() -- init name application.init(self, "demo") -- init background self:background_set("blue") -- init main dialog self:insert(self:dialog_main()) -- init input dialog self:insert(self:dialog_input(), {centerx = true, centery = true}) -- init tips dialog self:insert(self:dialog_tips(), {centerx = true, centery = true}) end -- main dialog function demo:dialog_main() local dialog_main = self._DIALOG_MAIN if not dialog_main then dialog_main = boxdialog:new("dialog.main", rect {1, 1, self:width() - 1, self:height() - 1}, "main dialog") dialog_main:text():text_set([[LTUI是一个基于lua的跨平台字符终端UI界面库。 此框架源于xmake中图形化菜单配置的需求,类似linux kernel的menuconf去配置编译参数,因此基于curses和lua实现了一整套跨平台的字符终端ui库。 而样式风格基本上完全参照的kconfig-frontends,当然用户也可以自己定制不同的ui风格。]]) dialog_main:button_add("tips", "< ☝ Tips >", function (v) self:view("dialog.tips"):show(true, {focused = true}) end) dialog_main:button_add("input", "< ☺ Input >", function (v) self:view("dialog.input"):show(true, {focused = true}) end) dialog_main:button_add("help", "< ☕Help >", function (v) self:insert(self:dialog_help()) end) dialog_main:button_add("quit", "< ☠ Quit >", "cm_quit") self._DIALOG_MAIN = dialog_main end return dialog_main end -- help dialog function demo:dialog_help() local dialog_help = self._DIALOG_HELP if not dialog_help then dialog_help = textdialog:new("dialog.help", rect {1, 1, self:width() - 1, self:height() - 1}, "README") dialog_help:option_set("scrollable", true) local helptext = nil local file = io.open("./LICENSE.md", 'r') if file then helptext = file:read("*a") file:close() end if helptext then dialog_help:text():text_set(helptext) end dialog_help:button_add("exit", "< Exit >", function (v) self:remove(dialog_help) end) self._DIALOG_HELP = dialog_help end return dialog_help end -- input dialog function demo:dialog_input() local dialog_input = self._DIALOG_INPUT if not dialog_input then dialog_input = inputdialog:new("dialog.input", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background()) dialog_input:frame():background_set("cyan") dialog_input:text():text_set("please input text:"):textattr_set("red") dialog_input:button_add("no", "< No >", function (v) dialog_input:show(false) end) dialog_input:button_add("yes", "< Yes >", function (v) self:dialog_main():text():text_set(dialog_input:textedit():text()) dialog_input:show(false) end) dialog_input:show(false) self._DIALOG_INPUT = dialog_input end return dialog_input end -- tips dialog function demo:dialog_tips() local dialog_tips = self._DIALOG_TIPS if not dialog_tips then dialog_tips = textdialog:new("dialog.tips", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background()) dialog_tips:frame():background_set("cyan") dialog_tips:text():text_set("hello ltui! (https://tboox.org)\nA cross-platform terminal ui library based on Lua"):textattr_set("red") dialog_tips:button_add("yes", "< Yes >", function (v) dialog_tips:show(false) end) dialog_tips:button_add("no", "< No >", function (v) dialog_tips:show(false) end) self._DIALOG_TIPS = dialog_tips end return dialog_tips end -- on resize function demo:on_resize() self:dialog_main():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) self:dialog_help():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) self:center(self:dialog_input(), {centerx = true, centery = true}) self:center(self:dialog_tips(), {centerx = true, centery = true}) application.on_resize(self) end -- main entry function main(...) demo:run(...) end ================================================ FILE: tests/ui/window.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-2020, Xmake Open Source Community. -- -- @author ruki -- @file window.lua -- -- imports import("core.ui.log") import("core.ui.rect") import("core.ui.view") import("core.ui.label") import("core.ui.event") import("core.ui.window") import("core.ui.application") -- the demo application local demo = application() -- init demo function demo:init() -- init name application.init(self, "demo") -- init background self:background_set("blue") -- init body window self:insert(self:body_window()) end -- get body window function demo:body_window() if not self._BODY_WINDOW then self._BODY_WINDOW = window:new("window.body", rect {1, 1, self:width() - 1, self:height() - 1}, "main window", true) end return self._BODY_WINDOW end -- on resize function demo:on_resize() self:body_window():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) application.on_resize(self) end -- main entry function main(...) demo:run(...) end ================================================ FILE: xmake/actions/build/build.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file build.lua -- -- imports import("core.base.option") import("core.project.config") import("core.project.project") import("private.service.distcc_build.client", {alias = "distcc_build_client"}) import("private.action.build.target", {alias = "target_buildutils"}) import("deprecated.build", {alias = "deprecated_build"}) -- run prepare jobs function _prepare(targets_root, opt) opt = opt or {} opt.job_kind = "prepare" opt.progress_factor = 0.05 target_buildutils.run_targetjobs(targets_root, opt) end -- run build jobs function _build(targets_root, opt) opt = opt or {} opt.job_kind = "build" opt.progress_factor = 0.95 if distcc_build_client.is_connected() then opt.distcc = distcc_build_client.singleton() if project.policy("build.distcc.remote_only") then opt.remote_only = true end end target_buildutils.run_targetjobs(targets_root, opt) end function main(targetnames, opt) -- get root targets local targets_root = target_buildutils.get_root_targets(targetnames, opt) -- prepare to build _prepare(targets_root, opt) -- do build if project.policy("build.jobgraph") then _build(targets_root, opt) else deprecated_build(targets_root, opt) end end ================================================ FILE: xmake/actions/build/build_files.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file build_files.lua -- -- imports import("core.base.option") import("core.base.hashset") import("core.project.config") import("core.project.project") import("private.service.distcc_build.client", {alias = "distcc_build_client"}) import("private.action.build.target", {alias = "target_buildutils"}) import("deprecated.build_files", {alias = "deprecated_build_files"}) -- convert all sourcefiles to lua pattern function _get_file_patterns(sourcefiles) local patterns = {} if not sourcefiles then return patterns end for _, sourcefile in ipairs(path.splitenv(sourcefiles)) do -- get the excludes local pattern = sourcefile:trim() local excludes = pattern:match("|.*$") if excludes then excludes = excludes:split("|", {plain = true}) end -- translate excludes if excludes then local _excludes = {} for _, exclude in ipairs(excludes) do exclude = path.translate(exclude) exclude = path.pattern(exclude) table.insert(_excludes, exclude) end excludes = _excludes end -- translate path and remove some repeat separators pattern = path.translate(pattern:gsub("|.*$", "")) -- remove "./" or '.\\' prefix if pattern:sub(1, 2):find('%.[/\\]') then pattern = pattern:sub(3) end -- get the root directory local rootdir = pattern local startpos = pattern:find("*", 1, true) if startpos then rootdir = rootdir:sub(1, startpos - 1) end rootdir = path.directory(rootdir) -- convert to lua path pattern pattern = path.pattern(pattern) table.insert(patterns, {pattern = pattern, excludes = excludes, rootdir = rootdir}) end return patterns end -- run prepare files jobs function _prepare_files(targets_root, opt) opt = opt or {} opt.job_kind = "prepare" opt.progress_factor = 0.05 opt.filepatterns = _get_file_patterns(opt.sourcefiles) target_buildutils.run_filejobs(targets_root, opt) end -- run build files jobs function _build_files(targets_root, opt) opt = opt or {} opt.job_kind = "build" opt.progress_factor = 0.95 opt.filepatterns = _get_file_patterns(opt.sourcefiles) if distcc_build_client.is_connected() then opt.distcc = distcc_build_client.singleton() end if not target_buildutils.run_filejobs(targets_root, opt) then if opt.sourcefiles then wprint("%s not found!", opt.sourcefiles) else wprint("no files found!") end end end function main(targetnames, opt) -- get root targets local targets_root = target_buildutils.get_root_targets(targetnames, opt) -- prepare to build files _prepare_files(targets_root, opt) -- do build files if project.policy("build.jobgraph") then _build_files(targets_root, opt) else deprecated_build_files(targets_root, opt) end end ================================================ FILE: xmake/actions/build/check.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file check_targets.lua -- -- imports import("core.base.option") import("core.project.project") import("private.check.checker") import("private.check.show") function main(targetnames, opt) opt = opt or {} -- get targets local targets = {} if targetnames then for _, targetname in ipairs(table.wrap(targetnames)) do table.insert(targets, project.target(targetname)) end else for _, target in pairs(project.targets()) do if target:is_enabled() then local group = target:get("group") if (target:is_default() and not group_pattern) or option.get("all") or (group_pattern and group and group:match(group_pattern)) then table.insert(targets, target) end end end end -- do check local checkers = checker.checkers() for name, info in table.orderpairs(checkers) do if (info.build and opt.build) or (info.build_failure and opt.build_failure) then local check = import("private.check.checkers." .. name, {anonymous = true}) for _, target in ipairs(targets) do check({target = target, show = show.wshow}) end end end end ================================================ FILE: xmake/actions/build/cleaner.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file cleaner.lua -- -- imports import("core.base.option") import("core.base.global") import("core.base.process") import("core.project.config") import("core.project.project") import("core.package.package") import("core.platform.platform") -- clean up temporary files once a day function cleanup() -- has been cleaned up today? local markfile = path.join(os.tmpdir(), "cleanup", os.date("%y%m%d") .. ".mark") if os.isfile(markfile) then return end -- mark as posted first, avoid posting it repeatly io.writefile(markfile, "ok") -- init argument list local argv = {"lua", path.join(os.scriptdir(), "cleaner.lua")} for _, name in ipairs({"root", "file", "project", "diagnosis", "verbose", "quiet", "yes", "confirm"}) do local value = option.get(name) if type(value) == "string" then table.insert(argv, "--" .. name .. "=" .. value) elseif value then table.insert(argv, "--" .. name) end end -- try to post it in background try { function () process.openv(os.programfile(), argv, {stdout = path.join(os.tmpdir(), "cleaner.log"), detach = true}):close() end } end -- the main function function main() -- clean up the temporary files at last 30 days, @see os.tmpdir() local parentdir = path.directory(os.tmpdir()) for day = 1, 30 do local tmpdir = path.join(parentdir, os.date("%y%m%d", os.time() - day * 24 * 3600)) if os.isdir(tmpdir) then print("cleanup %s ..", tmpdir) os.tryrm(tmpdir) end end -- clean up the temporary files of project at last 30 days, @see project.tmpdir() if os.isfile(os.projectfile()) then local parentdir = path.directory(project.tmpdir()) for day = 1, 30 do local tmpdir = path.join(parentdir, os.date("%y%m%d", os.time() - day * 24 * 3600)) if os.isdir(tmpdir) then print("cleanup %s ..", tmpdir) os.tryrm(tmpdir) end end end -- clean up the previous month package cache files, @see package.cachedir() local cachedir = path.join(package.cachedir({rootonly = true}), os.date("%y%m", os.time() - 31 * 24 * 3600)) if os.isdir(cachedir) and cachedir ~= package.cachedir() then print("cleanup %s ..", cachedir) os.tryrm(cachedir) end end ================================================ FILE: xmake/actions/build/deprecated/build.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file build.lua -- -- imports import("core.base.option") import("core.project.config") import("core.project.project") import("private.async.jobpool") import("async.runjobs") import("private.utils.batchcmds") import("core.base.hashset") import("private.service.distcc_build.client", {alias = "distcc_build_client"}) -- clean target for rebuilding function _clean_target(target) if target:targetfile() then os.tryrm(target:symbolfile()) os.tryrm(target:targetfile()) end end -- add builtin batch jobs function _add_batchjobs_builtin(batchjobs, rootjob, target) -- uses the rules script? local job, job_leaf for _, r in irpairs(target:orderules()) do -- reverse rules order for batchjobs:addjob() local script = r:script("build") if script then if r:extraconf("build", "batch") then job, job_leaf = assert(script(target, batchjobs, {rootjob = job or rootjob}), "rule(%s):on_build(): no returned job!", r:name()) elseif r:extraconf("build", "jobgraph") then wprint("rule(%s) with jobgraph found, please enable `build.jobgraph` policy first!", r:name()) else job = batchjobs:addjob("rule/" .. r:name() .. "/build", function (index, total, opt) script(target, {progress = opt.progress}) end, {rootjob = job or rootjob}) end else local buildcmd = r:script("buildcmd") if buildcmd then job = batchjobs:addjob("rule/" .. r:name() .. "/build", function (index, total, opt) local batchcmds_ = batchcmds.new({target = target}) buildcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end, {rootjob = job or rootjob}) end end end -- uses the builtin target script if not job and (target:is_static() or target:is_binary() or target:is_shared() or target:is_object() or target:is_moduleonly()) then job, job_leaf = import("kinds." .. target:kind(), {anonymous = true})(batchjobs, rootjob, target) end job = job or rootjob return job, job_leaf or job end -- add batch jobs function _add_batchjobs(batchjobs, rootjob, target) local job, job_leaf local script = target:script("build") if not script then -- do builtin batch jobs job, job_leaf = _add_batchjobs_builtin(batchjobs, rootjob, target) elseif target:extraconf("build", "batch") then -- do custom batch script -- e.g. -- target("test") -- on_build(function (target, batchjobs, opt) -- return batchjobs:addjob("test", function (idx, total) -- print("build it") -- end, {rootjob = opt.rootjob}) -- end, {batch = true}) -- job, job_leaf = assert(script(target, batchjobs, {rootjob = rootjob}), "target(%s):on_build(): no returned job!", target:name()) else -- do custom script directly -- e.g. -- -- target("test") -- on_build(function (target, opt) -- print("build it") -- end) -- job = batchjobs:addjob(target:name() .. "/build", function (index, total, opt) script(target, {progress = opt.progress}) end, {rootjob = rootjob}) end return job, job_leaf or job end -- add batch jobs for the given target function _add_batchjobs_for_target(batchjobs, rootjob, target) -- has been disabled? if not target:is_enabled() then return end -- add after_build job for target local pkgenvs = _g.pkgenvs or {} _g.pkgenvs = pkgenvs local job_build_after = batchjobs:addjob(target:name() .. "/after_build", function (index, total, opt) -- do after_build local progress = opt.progress local after_build = target:script("build_after") if after_build then after_build(target, {progress = progress}) end for _, r in ipairs(target:orderules()) do local after_build = r:script("build_after") if after_build then after_build(target, {progress = progress}) else local after_buildcmd = r:script("buildcmd_after") if after_buildcmd then local batchcmds_ = batchcmds.new({target = target}) after_buildcmd(target, batchcmds_, {progress = progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end end end -- restore environments if target:pkgenvs() then pkgenvs.oldenvs = pkgenvs.oldenvs or os.getenvs() pkgenvs.newenvs = pkgenvs.newenvs or {} pkgenvs.newenvs[target] = nil local newenvs = pkgenvs.oldenvs for _, envs in pairs(pkgenvs.newenvs) do newenvs = os.joinenvs(envs, newenvs) end os.setenvs(newenvs) end end, {rootjob = rootjob}) -- add batch jobs for target, @note only on_build script support batch jobs local job_build, job_build_leaf = _add_batchjobs(batchjobs, job_build_after, target) -- add before_build job for target local job_build_before = batchjobs:addjob(target:name() .. "/before_build", function (index, total, opt) -- enter package environments -- https://github.com/xmake-io/xmake/issues/4033 -- -- maybe mixing envs isn't a great solution, -- but it's the most efficient compromise compared to setting envs in every on_build_file. -- if target:pkgenvs() then pkgenvs.oldenvs = pkgenvs.oldenvs or os.getenvs() pkgenvs.newenvs = pkgenvs.newenvs or {} pkgenvs.newenvs[target] = target:pkgenvs() local newenvs = pkgenvs.oldenvs for _, envs in pairs(pkgenvs.newenvs) do newenvs = os.joinenvs(envs, newenvs) end os.setenvs(newenvs) end -- clean target if rebuild if target:is_rebuilt() and not option.get("dry-run") then _clean_target(target) end -- do before_build -- we cannot add batchjobs for this rule scripts, @see https://github.com/xmake-io/xmake/issues/2684 local progress = opt.progress local before_build = target:script("build_before") if before_build then before_build(target, {progress = progress}) end for _, r in ipairs(target:orderules()) do local before_build = r:script("build_before") if before_build then before_build(target, {progress = progress}) else local before_buildcmd = r:script("buildcmd_before") if before_buildcmd then local batchcmds_ = batchcmds.new({target = target}) before_buildcmd(target, batchcmds_, {progress = progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end end end end, {rootjob = job_build_leaf}) return job_build_before, job_build, job_build_after end -- add batch jobs for the given target and deps function _add_batchjobs_for_target_and_deps(batchjobs, rootjob, target, jobrefs, jobrefs_before) local targetjob_ref = jobrefs[target:name()] if targetjob_ref then batchjobs:add(targetjob_ref, rootjob) else local job_build_before, job_build, job_build_after = _add_batchjobs_for_target(batchjobs, rootjob, target) if job_build_before and job_build and job_build_after then jobrefs[target:name()] = job_build_after jobrefs_before[target:name()] = job_build_before for _, depname in ipairs(target:get("deps")) do local dep = project.target(depname, {namespace = target:namespace()}) local targetjob = job_build -- @see https://github.com/xmake-io/xmake/discussions/2500 if dep:policy("build.across_targets_in_parallel") == false then targetjob = job_build_before end _add_batchjobs_for_target_and_deps(batchjobs, targetjob, dep, jobrefs, jobrefs_before) end end end end -- get batch jobs function _get_batchjobs(targets_root, opt) -- generate batch jobs for default or all targets local jobrefs = {} local jobrefs_before = {} local batchjobs = jobpool.new() for _, target in ipairs(targets_root) do _add_batchjobs_for_target_and_deps(batchjobs, batchjobs:rootjob(), target, jobrefs, jobrefs_before) end -- add fence jobs, @see https://github.com/xmake-io/xmake/issues/5003 for _, target in ipairs(project.ordertargets()) do local target_job_before = jobrefs_before[target:name()] if target_job_before then for _, dep in ipairs(target:orderdeps()) do if dep:policy("build.fence") then local fence_job = jobrefs[dep:name()] if fence_job then batchjobs:add(fence_job, target_job_before) end end end end end return batchjobs end function main(targets_root, opt) -- enable distcc? local distcc if distcc_build_client.is_connected() then distcc = distcc_build_client.singleton() end -- build all jobs local batchjobs = _get_batchjobs(targets_root, opt) if batchjobs and batchjobs:size() > 0 then local curdir = os.curdir() runjobs("build", batchjobs, {on_exit = function (errors) import("utils.progress") if errors then progress.show_output("") end end, comax = option.get("jobs") or 1, curdir = curdir, distcc = distcc}) os.cd(curdir) end end ================================================ FILE: xmake/actions/build/deprecated/build_files.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file build_files.lua -- -- imports import("core.base.option") import("core.base.hashset") import("core.project.config") import("core.project.project") import("private.async.jobpool") import("async.runjobs") import("kinds.object") -- match source files function _match_sourcefiles(sourcefile, filepatterns) for _, filepattern in ipairs(filepatterns) do if sourcefile:match(filepattern.pattern) == sourcefile then if filepattern.excludes then if filepattern.rootdir and sourcefile:startswith(filepattern.rootdir) then sourcefile = sourcefile:sub(#filepattern.rootdir + 2) end for _, exclude in ipairs(filepattern.excludes) do if sourcefile:match(exclude) == sourcefile then return false end end end return true end end end -- add batch jobs function _add_batchjobs(batchjobs, rootjob, target, filepatterns) local newbatches = {} local sourcecount = 0 for rulename, sourcebatch in pairs(target:sourcebatches()) do local objectfiles = sourcebatch.objectfiles local dependfiles = sourcebatch.dependfiles local sourcekind = sourcebatch.sourcekind for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do if _match_sourcefiles(sourcefile, filepatterns) then local newbatch = newbatches[rulename] if not newbatch then newbatch = {} newbatch.sourcekind = sourcekind newbatch.rulename = rulename newbatch.sourcefiles = {} end table.insert(newbatch.sourcefiles, sourcefile) if objectfiles then newbatch.objectfiles = newbatch.objectfiles or {} table.insert(newbatch.objectfiles, objectfiles[idx]) end if dependfiles then newbatch.dependfiles = newbatch.dependfiles or {} table.insert(newbatch.dependfiles, dependfiles[idx]) end newbatches[rulename] = newbatch sourcecount = sourcecount + 1 end end end if sourcecount > 0 then return object.add_batchjobs_for_sourcefiles(batchjobs, rootjob, target, newbatches) end end -- add batch jobs for the given target function _add_batchjobs_for_target(batchjobs, rootjob, target, filepatterns) -- has been disabled? if not target:is_enabled() then return end -- add batch jobs for target return _add_batchjobs(batchjobs, rootjob, target, filepatterns) end -- add batch jobs for the given target and deps function _add_batchjobs_for_target_and_deps(batchjobs, rootjob, jobrefs, target, filepatterns) local targetjob_ref = jobrefs[target:name()] if targetjob_ref then batchjobs:add(targetjob_ref, rootjob) else local targetjob, targetjob_root = _add_batchjobs_for_target(batchjobs, rootjob, target, filepatterns) if targetjob and targetjob_root then jobrefs[target:name()] = targetjob_root if not option.get("shallow") then for _, depname in ipairs(target:get("deps")) do _add_batchjobs_for_target_and_deps(batchjobs, targetjob, jobrefs, project.target(depname, {namespace = target:namespace()}), filepatterns) end end end end end -- get batch jobs function _get_batchjobs(targets_root, opt) -- convert all sourcefiles to lua pattern local filepatterns = _get_file_patterns(opt.sourcefiles) -- generate batch jobs for default or all targets local jobrefs = {} local batchjobs = jobpool.new() for _, target in pairs(targets_root) do _add_batchjobs_for_target_and_deps(batchjobs, batchjobs:rootjob(), jobrefs, target, filepatterns) end return batchjobs end -- convert all sourcefiles to lua pattern function _get_file_patterns(sourcefiles) local patterns = {} for _, sourcefile in ipairs(path.splitenv(sourcefiles)) do -- get the excludes local pattern = sourcefile:trim() local excludes = pattern:match("|.*$") if excludes then excludes = excludes:split("|", {plain = true}) end -- translate excludes if excludes then local _excludes = {} for _, exclude in ipairs(excludes) do exclude = path.translate(exclude) exclude = path.pattern(exclude) table.insert(_excludes, exclude) end excludes = _excludes end -- translate path and remove some repeat separators pattern = path.translate(pattern:gsub("|.*$", "")) -- remove "./" or '.\\' prefix if pattern:sub(1, 2):find('%.[/\\]') then pattern = pattern:sub(3) end -- get the root directory local rootdir = pattern local startpos = pattern:find("*", 1, true) if startpos then rootdir = rootdir:sub(1, startpos - 1) end rootdir = path.directory(rootdir) -- convert to lua path pattern pattern = path.pattern(pattern) table.insert(patterns, {pattern = pattern, excludes = excludes, rootdir = rootdir}) end return patterns end function main(targets_root, opt) -- build all jobs local batchjobs = _get_batchjobs(targets_root, opt) if batchjobs and batchjobs:size() > 0 then local curdir = os.curdir() runjobs("build_files", batchjobs, {comax = option.get("jobs") or 1, curdir = curdir}) os.cd(curdir) else wprint("%s not found!", opt.sourcefiles) end end ================================================ FILE: xmake/actions/build/deprecated/kinds/binary.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file binary.lua -- -- imports import("core.base.option") import("core.theme.theme") import("core.tool.linker") import("core.tool.compiler") import("core.project.depend") import("utils.progress") import("private.utils.batchcmds") import("object", {alias = "object_target"}) import("private.action.build.target", {alias = "target_buildutils"}) -- do link target function _do_link_target(target, opt) local linkinst = linker.load(target:kind(), target:sourcekinds(), {target = target}) local linkflags = linkinst:linkflags({target = target}) -- need build this target? local depfiles = target_buildutils.get_linkdepfiles(target) local dryrun = option.get("dry-run") local depvalues = {linkinst:program(), linkflags} depend.on_changed(function () local filename = target:filename() if target:namespace() then filename = target:namespace() .. "::" .. filename end progress.show(opt.progress, "${color.build.target}linking.$(mode) %s", filename) local targetfile = target:targetfile() local objectfiles = target:objectfiles() local verbose = option.get("verbose") if verbose then -- show the full link command with raw arguments, it will expand @xxx.args for msvc/link on windows print(linkinst:linkcmd(objectfiles, targetfile, {linkflags = linkflags, rawargs = true})) end if not dryrun then assert(linkinst:link(objectfiles, targetfile, {linkflags = linkflags})) end end, {dependfile = target:dependfile(), lastmtime = os.mtime(target:targetfile()), changed = target:is_rebuilt() or option.get("linkonly"), values = depvalues, files = depfiles, dryrun = dryrun}) end -- on link the given target function _on_link_target(target, opt) -- link target with rules local done = false for _, r in ipairs(target:orderules()) do local on_link = r:script("link") if on_link then on_link(target, opt) done = true end local on_linkcmd = r:script("linkcmd") if on_linkcmd then local batchcmds_ = batchcmds.new({target = target}) on_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) done = true end end if done then return end -- do link _do_link_target(target, opt) end -- link target function _link_target(target, opt) -- do before link for target local before_link = target:script("link_before") if before_link then before_link(target, opt) end -- do before link for rules for _, r in ipairs(target:orderules()) do local before_link = r:script("link_before") if before_link then before_link(target, opt) end local before_linkcmd = r:script("linkcmd_before") if before_linkcmd then local batchcmds_ = batchcmds.new({target = target}) before_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end end -- on link target:script("link", _on_link_target)(target, opt) -- do after link for target local after_link = target:script("link_after") if after_link then after_link(target, opt) end -- do after link for rules for _, r in ipairs(target:orderules()) do local after_link = r:script("link_after") if after_link then after_link(target, opt) end local after_linkcmd = r:script("linkcmd_after") if after_linkcmd then local batchcmds_ = batchcmds.new({target = target}) after_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end end end -- add batch jobs for building binary target function main(batchjobs, rootjob, target) -- add link job local job_link = batchjobs:addjob(target:name() .. "/link", function (index, total, opt) _link_target(target, {progress = opt.progress}) end, {rootjob = rootjob}) -- we only need to return and depend the link job for each target, -- so we can compile the source files for each target in parallel -- -- unless call set_policy("build.across_targets_in_parallel", false) to disable to build across targets in parallel. -- local job_objects = object_target.add_batchjobs_for_object(batchjobs, job_link, target) return target:policy("build.across_targets_in_parallel") == false and job_objects or job_link, job_objects end ================================================ FILE: xmake/actions/build/deprecated/kinds/moduleonly.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki, Arthapz -- @file moduleonly.lua -- -- imports inherit("object") ================================================ FILE: xmake/actions/build/deprecated/kinds/object.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file object.lua -- -- imports import("core.base.option") import("core.project.rule") import("core.project.config") import("core.project.project") import("async.runjobs") import("private.utils.batchcmds") import("rule_groups") -- has scripts for the custom rule function _has_scripts_for_rule(ruleinst, suffix) -- add batch jobs for xx_build_files local scriptname = "build_files" .. (suffix and ("_" .. suffix) or "") local script = ruleinst:script(scriptname) if script then return true end -- add batch jobs for xx_build_file scriptname = "build_file" .. (suffix and ("_" .. suffix) or "") script = ruleinst:script(scriptname) if script then return true end -- add batch jobs for xx_buildcmd_files scriptname = "buildcmd_files" .. (suffix and ("_" .. suffix) or "") script = ruleinst:script(scriptname) if script then return true end -- add batch jobs for xx_buildcmd_file scriptname = "buildcmd_file" .. (suffix and ("_" .. suffix) or "") script = ruleinst:script(scriptname) if script then return true end end -- has scripts for target function _has_scripts_for_target(target, suffix) local scriptname = "build_files" .. (suffix and ("_" .. suffix) or "") local script = target:script(scriptname) if script then return true else scriptname = "build_file" .. (suffix and ("_" .. suffix) or "") script = target:script(scriptname) if script then return true end end end -- has scripts for group function _has_scripts_for_group(group, suffix) for _, item in pairs(group) do if item.target and _has_scripts_for_target(item.target, suffix) then return true end if item.rule and _has_scripts_for_rule(item.rule, suffix) then return true end end end -- add batch jobs for the custom rule function _add_batchjobs_for_rule(batchjobs, rootjob, target, sourcebatch, suffix) -- get rule local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!") local ruleinst = rule_groups.get_rule(target, rulename) -- add batch jobs for xx_build_files local scriptname = "build_files" .. (suffix and ("_" .. suffix) or "") local script = ruleinst:script(scriptname) if script then if ruleinst:extraconf(scriptname, "batch") then script(target, batchjobs, sourcebatch, {rootjob = rootjob, distcc = ruleinst:extraconf(scriptname, "distcc")}) else batchjobs:addjob("rule/" .. rulename .. "/" .. scriptname, function (index, total, opt) script(target, sourcebatch, {progress = opt.progress}) end, {rootjob = rootjob}) end end -- add batch jobs for xx_build_file if not script then scriptname = "build_file" .. (suffix and ("_" .. suffix) or "") script = ruleinst:script(scriptname) if script then local sourcekind = sourcebatch.sourcekind for _, sourcefile in ipairs(sourcebatch.sourcefiles) do batchjobs:addjob(sourcefile, function (index, total, opt) script(target, sourcefile, {sourcekind = sourcekind, progress = opt.progress}) end, {rootjob = rootjob, distcc = ruleinst:extraconf(scriptname, "distcc")}) end end end -- add batch jobs for xx_buildcmd_files if not script then scriptname = "buildcmd_files" .. (suffix and ("_" .. suffix) or "") script = ruleinst:script(scriptname) if script then batchjobs:addjob("rule/" .. rulename .. "/" .. scriptname, function (index, total, opt) local batchcmds_ = batchcmds.new({target = target}) local distcc = ruleinst:extraconf(scriptname, "distcc") script(target, batchcmds_, sourcebatch, {progress = opt.progress, distcc = distcc}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end, {rootjob = rootjob}) end end -- add batch jobs for xx_buildcmd_file if not script then scriptname = "buildcmd_file" .. (suffix and ("_" .. suffix) or "") script = ruleinst:script(scriptname) if script then local sourcekind = sourcebatch.sourcekind for _, sourcefile in ipairs(sourcebatch.sourcefiles) do batchjobs:addjob(sourcefile, function (index, total, opt) local batchcmds_ = batchcmds.new({target = target}) script(target, batchcmds_, sourcefile, {sourcekind = sourcekind, progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end, {rootjob = rootjob, distcc = ruleinst:extraconf(scriptname, "distcc")}) end end end end -- add batch jobs for target function _add_batchjobs_for_target(batchjobs, rootjob, target, sourcebatch, suffix) -- we just build sourcebatch with on_build_files scripts -- -- for example, c++.build and c++.build.modules.builder rules have same sourcefiles, -- but we just build it for c++.build -- -- @see https://github.com/xmake-io/xmake/issues/3171 -- local rulename = sourcebatch.rulename if rulename then local ruleinst = rule_groups.get_rule(target, rulename) if not ruleinst:script("build_file") and not ruleinst:script("build_files") then return end end -- add batch jobs local scriptname = "build_files" .. (suffix and ("_" .. suffix) or "") local script = target:script(scriptname) if script then if target:extraconf(scriptname, "batch") then script(target, batchjobs, sourcebatch, {rootjob = rootjob, distcc = target:extraconf(scriptname, "distcc")}) else batchjobs:addjob(target:name() .. "/" .. scriptname, function (index, total, opt) script(target, sourcebatch, {progress = opt.progress}) end, {rootjob = rootjob}) end return true else scriptname = "build_file" .. (suffix and ("_" .. suffix) or "") script = target:script(scriptname) if script then local sourcekind = sourcebatch.sourcekind for _, sourcefile in ipairs(sourcebatch.sourcefiles) do batchjobs:addjob(sourcefile, function (index, total, opt) script(target, sourcefile, {sourcekind = sourcekind, progress = opt.progress}) end, {rootjob = rootjob, distcc = target:extraconf(scriptname, "distcc")}) end return true end end end -- add batch jobs for group function _add_batchjobs_for_group(batchjobs, rootjob, target, group, suffix) for _, item in pairs(group) do local sourcebatch = item.sourcebatch if item.target then _add_batchjobs_for_target(batchjobs, rootjob, target, sourcebatch, suffix) end -- override on_xxx script in target? we need to ignore rule scripts if item.rule and (suffix or not _has_scripts_for_target(target, suffix)) then _add_batchjobs_for_rule(batchjobs, rootjob, target, sourcebatch, suffix) end end end -- add batch jobs for building source files function add_batchjobs_for_sourcefiles(batchjobs, rootjob, target, sourcebatches) -- build sourcebatch groups first local groups = rule_groups.build_sourcebatch_groups(target, sourcebatches) -- add batch jobs for build_after local groups_root local groups_leaf = rootjob for idx, group in ipairs(groups) do if _has_scripts_for_group(group, "after") then batchjobs:group_enter(target:name() .. "/after_build_files" .. idx) _add_batchjobs_for_group(batchjobs, groups_leaf, target, group, "after") groups_leaf = batchjobs:group_leave() or groups_leaf groups_root = groups_root or groups_leaf end end -- add batch jobs for build for idx, group in ipairs(groups) do if _has_scripts_for_group(group) then batchjobs:group_enter(target:name() .. "/build_files" .. idx) _add_batchjobs_for_group(batchjobs, groups_leaf, target, group) groups_leaf = batchjobs:group_leave() or groups_leaf groups_root = groups_root or groups_leaf end end -- add batch jobs for build_before for idx, group in ipairs(groups) do if _has_scripts_for_group(group, "before") then batchjobs:group_enter(target:name() .. "/before_build_files" .. idx) _add_batchjobs_for_group(batchjobs, groups_leaf, target, group, "before") groups_leaf = batchjobs:group_leave() or groups_leaf groups_root = groups_root or groups_leaf end end return groups_leaf, groups_root or groups_leaf end -- add batch jobs for building object files function add_batchjobs_for_object(batchjobs, rootjob, target) return add_batchjobs_for_sourcefiles(batchjobs, rootjob, target, target:sourcebatches()) end -- add batch jobs for building object target function main(batchjobs, rootjob, target) -- add a fake link job local job_link = batchjobs:addjob(target:name() .. "/fakelink", function (index, total, opt) end, {rootjob = rootjob}) -- we only need to return and depend the link job for each target, -- so we can compile the source files for each target in parallel -- -- unless call set_policy("build.across_targets_in_parallel", false) to disable to build across targets in parallel. -- local job_objects = add_batchjobs_for_object(batchjobs, job_link, target) return target:policy("build.across_targets_in_parallel") == false and job_objects or job_link, job_objects end ================================================ FILE: xmake/actions/build/deprecated/kinds/rule_groups.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file rule_groups.lua -- -- imports import("core.base.option") import("core.project.rule") import("core.project.config") import("core.project.project") -- get rule -- @note we need to get rule from target first, because we maybe will inject and replace builtin rule in target function get_rule(target, rulename) local ruleinst = assert(target:rule(rulename) or project.rule(rulename, {namespace = target:namespace()}) or rule.rule(rulename), "unknown rule: %s", rulename) return ruleinst end -- get max depth of rule function _get_rule_max_depth(target, ruleinst, depth) local max_depth = depth for _, depname in ipairs(ruleinst:get("deps")) do local dep = get_rule(target, depname) local dep_depth = depth if ruleinst:extraconf("deps", depname, "order") then dep_depth = dep_depth + 1 end local cur_depth = _get_rule_max_depth(target, dep, dep_depth) if cur_depth > max_depth then max_depth = cur_depth end end return max_depth end -- build sourcebatch groups for target function _build_sourcebatch_groups_for_target(groups, target, sourcebatches) local group = groups[1] for _, sourcebatch in pairs(sourcebatches) do local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!") local item = group[rulename] or {} item.target = target item.sourcebatch = sourcebatch group[rulename] = item end end -- build sourcebatch groups for rules function _build_sourcebatch_groups_for_rules(groups, target, sourcebatches) for _, sourcebatch in pairs(sourcebatches) do local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!") local ruleinst = get_rule(target, rulename) local depth = _get_rule_max_depth(target, ruleinst, 1) local group = groups[depth] if group == nil then group = {} groups[depth] = group end local item = group[rulename] or {} item.rule = ruleinst item.sourcebatch = sourcebatch group[rulename] = item end end -- build sourcebatch groups by rule dependencies order, e.g. `add_deps("qt.ui", {order = true})` -- -- @see https://github.com/xmake-io/xmake/issues/2814 -- function build_sourcebatch_groups(target, sourcebatches) local groups = {{}} _build_sourcebatch_groups_for_target(groups, target, sourcebatches) _build_sourcebatch_groups_for_rules(groups, target, sourcebatches) if #groups > 0 then groups = table.reverse(groups) end return groups end ================================================ FILE: xmake/actions/build/deprecated/kinds/shared.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file shared.lua -- -- imports import("core.base.option") import("core.theme.theme") import("core.tool.linker") import("core.tool.compiler") import("core.project.depend") import("utils.progress") import("private.utils.batchcmds") import("object", {alias = "object_target"}) import("private.action.build.target", {alias = "target_buildutils"}) -- do link target function _do_link_target(target, opt) local linkinst = linker.load(target:kind(), target:sourcekinds(), {target = target}) local linkflags = linkinst:linkflags({target = target}) -- need build this target? local depfiles = target_buildutils.get_linkdepfiles(target) local dryrun = option.get("dry-run") local depvalues = {linkinst:program(), linkflags} depend.on_changed(function () local filename = target:filename() if target:namespace() then filename = target:namespace() .. "::" .. filename end progress.show(opt.progress, "${color.build.target}linking.$(mode) %s", filename) local targetfile = target:targetfile() local objectfiles = target:objectfiles() local verbose = option.get("verbose") if verbose then -- show the full link command with raw arguments, it will expand @xxx.args for msvc/link on windows print(linkinst:linkcmd(objectfiles, targetfile, {linkflags = linkflags, rawargs = true})) end if not dryrun then assert(linkinst:link(objectfiles, targetfile, {linkflags = linkflags})) end end, {dependfile = target:dependfile(), lastmtime = os.mtime(target:targetfile()), changed = target:is_rebuilt() or option.get("linkonly"), values = depvalues, files = depfiles, dryrun = dryrun}) end -- on link the given target function _on_link_target(target, opt) -- link target with rules local done = false for _, r in ipairs(target:orderules()) do local on_link = r:script("link") if on_link then on_link(target, opt) done = true end local on_linkcmd = r:script("linkcmd") if on_linkcmd then local batchcmds_ = batchcmds.new({target = target}) on_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) done = true end end if done then return end -- do link _do_link_target(target, opt) end -- link target function _link_target(target, opt) -- do before link for target local before_link = target:script("link_before") if before_link then before_link(target, opt) end -- do before link for rules for _, r in ipairs(target:orderules()) do local before_link = r:script("link_before") if before_link then before_link(target, opt) end local before_linkcmd = r:script("linkcmd_before") if before_linkcmd then local batchcmds_ = batchcmds.new({target = target}) before_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end end -- on link target:script("link", _on_link_target)(target, opt) -- do after link for target local after_link = target:script("link_after") if after_link then after_link(target, opt) end -- do after link for rules for _, r in ipairs(target:orderules()) do local after_link = r:script("link_after") if after_link then after_link(target, opt) end local after_linkcmd = r:script("linkcmd_after") if after_linkcmd then local batchcmds_ = batchcmds.new({target = target}) after_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end end end -- add batch jobs for building shared target function main(batchjobs, rootjob, target) -- add link job local job_link = batchjobs:addjob(target:name() .. "/link", function (index, total, opt) _link_target(target, {progress = opt.progress}) end, {rootjob = rootjob}) -- we only need to return and depend the link job for each target, -- so we can compile the source files for each target in parallel -- -- unless call set_policy("build.across_targets_in_parallel", false) to disable to build across targets in parallel. -- local job_objects = object_target.add_batchjobs_for_object(batchjobs, job_link, target) return target:policy("build.across_targets_in_parallel") == false and job_objects or job_link, job_objects end ================================================ FILE: xmake/actions/build/deprecated/kinds/static.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file static.lua -- -- imports import("core.base.option") import("core.theme.theme") import("core.tool.linker") import("core.tool.compiler") import("core.project.depend") import("utils.progress") import("private.utils.batchcmds") import("object", {alias = "object_target"}) import("private.action.build.target", {alias = "target_buildutils"}) -- do link target function _do_link_target(target, opt) local linkinst = linker.load(target:kind(), target:sourcekinds(), {target = target}) local linkflags = linkinst:linkflags({target = target}) -- need build this target? local depfiles = target_buildutils.get_linkdepfiles(target) local dryrun = option.get("dry-run") local depvalues = {linkinst:program(), linkflags} depend.on_changed(function () local filename = target:filename() if target:namespace() then filename = target:namespace() .. "::" .. filename end progress.show(opt.progress, "${color.build.target}archiving.$(mode) %s", filename) local targetfile = target:targetfile() local objectfiles = target:objectfiles() local verbose = option.get("verbose") if verbose then -- show the full link command with raw arguments, it will expand @xxx.args for msvc/link on windows print(linkinst:linkcmd(objectfiles, targetfile, {linkflags = linkflags, rawargs = true})) end if not dryrun then assert(linkinst:link(objectfiles, targetfile, {linkflags = linkflags})) end end, {dependfile = target:dependfile(), lastmtime = os.mtime(target:targetfile()), changed = target:is_rebuilt() or option.get("linkonly"), values = depvalues, files = depfiles, dryrun = dryrun}) end -- on link the given target function _on_link_target(target, opt) -- link target with rules local done = false for _, r in ipairs(target:orderules()) do local on_link = r:script("link") if on_link then on_link(target, opt) done = true end local on_linkcmd = r:script("linkcmd") if on_linkcmd then local batchcmds_ = batchcmds.new({target = target}) on_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) done = true end end if done then return end -- do link _do_link_target(target, opt) end -- link target function _link_target(target, opt) -- do before link for target local before_link = target:script("link_before") if before_link then before_link(target, opt) end -- do before link for rules for _, r in ipairs(target:orderules()) do local before_link = r:script("link_before") if before_link then before_link(target, opt) end local before_linkcmd = r:script("linkcmd_before") if before_linkcmd then local batchcmds_ = batchcmds.new({target = target}) before_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end end -- on link target:script("link", _on_link_target)(target, opt) -- do after link for target local after_link = target:script("link_after") if after_link then after_link(target, opt) end -- do after link for rules for _, r in ipairs(target:orderules()) do local after_link = r:script("link_after") if after_link then after_link(target, opt) end local after_linkcmd = r:script("linkcmd_after") if after_linkcmd then local batchcmds_ = batchcmds.new({target = target}) after_linkcmd(target, batchcmds_, {progress = opt.progress}) batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get("dry-run")}) end end end -- add batch jobs for building static target function main(batchjobs, rootjob, target) -- add link job local job_link = batchjobs:addjob(target:name() .. "/link", function (index, total, opt) _link_target(target, {progress = opt.progress}) end, {rootjob = rootjob}) -- we only need to return and depend the link job for each target, -- so we can compile the source files for each target in parallel -- -- unless call set_policy("build.across_targets_in_parallel", false) to disable to build across targets in parallel. -- local job_objects = object_target.add_batchjobs_for_object(batchjobs, job_link, target) return target:policy("build.across_targets_in_parallel") == false and job_objects or job_link, job_objects end ================================================ FILE: xmake/actions/build/main.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file main.lua -- -- imports import("core.base.option") import("core.base.global") import("core.base.task") import("core.tool.toolchain") import("core.cache.detectcache") import("core.project.rule") import("core.project.config") import("core.project.project") import("core.platform.platform") import("core.theme.theme") import("utils.progress") import("build") import("build_files") import("cleaner") import("check", {alias = "check_targets"}) import("private.cache.build_cache") import("private.service.remote_build.action", {alias = "remote_build_action"}) import("private.utils.statistics") import("private.action.utils", {alias = "action_utils"}) import("private.detect.check_targetname") -- try building it function _do_try_build(configfile, tool, trybuild, trybuild_detected, targetname) if configfile and tool and (trybuild or utils.confirm({default = true, description = "${bright}" .. path.filename(configfile) .. "${clear} found, try building it or you can run `${bright}xmake f --trybuild=${clear}` to set buildsystem"})) then if not trybuild then task.run("config", {trybuild = trybuild_detected}) end tool.build() return true end end -- do build for the third-party buildsystem function _try_build() -- load config config.load() -- rebuild it? do clean first local targetname = option.get("target") if option.get("rebuild") then task.run("clean", {target = targetname}) end -- get the buildsystem tool local configfile = nil local tool = nil local trybuild = config.get("trybuild") local trybuild_detected = nil if trybuild then tool = import("private.action.trybuild." .. trybuild, {try = true, anonymous = true}) if tool then configfile = tool.detect() else raise("unknown build tool: %s", trybuild) end return _do_try_build(configfile, tool, trybuild, trybuild_detected, targetname) else for _, name in ipairs({"xrepo", "autoconf", "cmake", "meson", "scons", "bazel", "msbuild", "xcodebuild", "make", "ninja", "ndkbuild"}) do tool = import("private.action.trybuild." .. name, {anonymous = true}) configfile = tool.detect() if configfile then trybuild_detected = name if _do_try_build(configfile, tool, trybuild, trybuild_detected, targetname) then return true end end end end end -- do global project rules function _do_project_rules(scriptname, opt) for _, rulename in ipairs(project.get("target.rules")) do local r = project.rule(rulename) or rule.rule(rulename) if r and r:kind() == "project" then local buildscript = r:script(scriptname) if buildscript then buildscript(opt) end end end end -- do build function _do_build(targetname, opt) local sourcefiles = option.get("files") if sourcefiles then build_files(targetname, {group_pattern = opt.group_pattern, sourcefiles = sourcefiles}) else build(targetname, {group_pattern = opt.group_pattern}) end end -- build targets function build_targets(targetnames, opt) opt = opt or {} try { function () -- do rules before building _do_project_rules("build_before") -- do build _do_build(targetnames, opt) -- do check check_targets(targetnames, {build = true}) -- save toolchain configs toolchain.save() -- save detect cache detectcache:save() -- dump cache stats if option.get("diagnosis") then build_cache.dump_stats() end end, catch { function (errors) -- @see https://github.com/xmake-io/xmake/issues/3401 check_targets(targetnames, {build_failure = true}) -- do rules after building _do_project_rules("build_after", {errors = errors}) -- save toolchain configs toolchain.save() -- save detect cache detectcache:save() -- raise if errors then raise(errors) elseif opt.group_pattern then raise("build targets with group(%s) failed!", opt.group_pattern) elseif targetnames then targetnames = table.wrap(targetnames) raise("build target: %s failed!", table.concat(targetnames, ", ")) else raise("build target failed!") end end } } -- do rules after building _do_project_rules("build_after") end function main(opt) opt = opt or {} -- try building it using third-party buildsystem if xmake.lua not exists if not os.isfile(project.rootfile()) and _try_build() then return end -- post statistics before locking project statistics.post() -- do action for remote? if remote_build_action.enabled() then return remote_build_action() end -- lock the whole project project.lock() -- config it first local targetname, group_pattern = action_utils.get_target_and_group() task.run("config", {}, {disable_dump = true}) -- check target name if targetname then assert(check_targetname(targetname)) end -- enter project directory local oldir = os.cd(project.directory()) -- clean up temporary files once a day cleaner.cleanup() -- build targets local build_time = os.mclock() build_targets(targetname, {group_pattern = group_pattern}) build_time = os.mclock() - build_time -- leave project directory os.cd(oldir) -- unlock the whole project project.unlock() -- trace if not opt.disable_dump then local str = "" if build_time then str = string.format(", spent %ss", build_time / 1000) end progress.show(100, "${color.success}build ok%s", str) end end ================================================ FILE: xmake/actions/build/xmake.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file xmake.lua -- task("build") set_category("main") on_run("main") set_menu { usage = "xmake [task] [options] [target]" , description = "Build targets if no given tasks." , shortname = 'b' , options = { {nil, "version", "k", nil , "Print the version number and exit." } , {'b', "build", "k", nil , "Build target. This is default building mode and optional." } , {'r', "rebuild", "k", nil , "Rebuild the target." } , {'a', "all", "k", nil , "Build all targets." } , {nil, "shallow", "k", nil , "Only re-build the given targets without dependencies." } , {'g', "group", "kv", nil , "Build all targets of the given group. It support path pattern matching.", "e.g.", " xmake -g test", " xmake -g test_*", " xmake --group=benchmark/*" } , {nil, "dry-run", "k", nil , "Dry run to build target." } , {} , {'j', "jobs", "kv", tostring(os.default_njob()), "Set the number of parallel compilation jobs." } , {nil, "linkjobs", "kv", nil, "Set the number of parallel link jobs." } , {'w', "warning", "k", false , "Enable the warnings output. (deprecated)" } , {nil, "linkonly", "k", false , "Only link targets if object files have been compiled." } , {nil, "files", "kv", nil , "Build the given source files.", "e.g. ", " - xmake --files=src/main.c", " - xmake --files='src/*.c' [target]", " - xmake --files='src/**.c|excluded_file.c'", " - xmake --files='src/main.c" .. path.envsep() .. "src/test.c'" } , {} , {nil, "target", "v", nil , "The target name. It will build all default targets if this parameter is not specified." , values = function (complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) end } } } ================================================ FILE: xmake/actions/clean/main.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file main.lua -- -- imports import("core.base.option") import("core.base.task") import("core.project.rule") import("core.project.config") import("core.base.global") import("core.project.project") import("core.platform.platform") import("private.action.clean.remove_files") import("target.action.clean", {alias = "_do_clean_target"}) import("private.service.remote_build.action", {alias = "remote_build_action"}) import("private.detect.check_targetname") -- on clean target function _on_clean_target(target) -- build target with rules local done = false for _, r in ipairs(target:orderules()) do local on_clean = r:script("clean") if on_clean then on_clean(target) done = true end end if done then return end -- do clean _do_clean_target(target) end -- clean the given target files function _clean_target(target) -- has been disabled? if not target:is_enabled() then return end -- enter the environments of the target packages local oldenvs = os.addenvs(target:pkgenvs()) -- the target scripts local scripts = { target:script("clean_before") , function (target) for _, r in ipairs(target:orderules()) do local before_clean = r:script("clean_before") if before_clean then before_clean(target) end end end , target:script("clean", _on_clean_target) , function (target) for _, r in ipairs(target:orderules()) do local after_clean = r:script("clean_after") if after_clean then after_clean(target) end end end , target:script("clean_after") } -- run the target scripts for i = 1, 5 do local script = scripts[i] if script ~= nil then script(target) end end -- leave the environments of the target packages os.setenvs(oldenvs) end -- clean the given targets function _clean_targets(targets) for _, target in ipairs(targets) do _clean_target(target) end end -- clean target function _clean(targetname) if targetname then local target = assert(check_targetname(targetname)) _clean_target(target) else _clean_targets(project.ordertargets()) end end -- clean configuration cache function _clean_configs() if option.get("all") then -- we need to close it first after removing file lock project.filelock():close() remove_files(config.directory()) end end -- do clean for the third-party buildsystem function _try_clean() -- load config config.load() -- get the buildsystem tool local configfile = nil local tool = nil local trybuild = config.get("trybuild") if trybuild then tool = import("private.action.trybuild." .. trybuild, {try = true, anonymous = true}) if tool then configfile = tool.detect() end end -- try cleaning it if configfile and tool and trybuild then tool.clean() end end function main() -- try cleaning it using third-party buildsystem if xmake.lua not exists if not os.isfile(project.rootfile()) then return _try_clean() end -- do action for remote? if remote_build_action.enabled() then return remote_build_action() end -- load config first task.run("config", {require = false}, {disable_dump = true}) -- lock the whole project project.lock() -- get the target name local targetname = option.get("target") -- enter project directory local oldir = os.cd(project.directory()) -- clean target _clean(targetname) -- unlock the whole project project.unlock() -- we must call it after unlocking project because it will remove project lockfile _clean_configs() -- leave project directory os.cd(oldir) end ================================================ FILE: xmake/actions/clean/xmake.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file xmake.lua -- task("clean") set_category("action") on_run("main") set_menu { usage = "xmake clean|c [options] [target]" , description = "Remove all binary and temporary files." , shortname = 'c' , options = { {'a', "all", "k", nil , "Clean all auto-generated files by xmake." } , {} , {nil, "target", "v", nil , "The target name. It will clean all default targets if this parameter is not specified." , values = function (complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) end } } } ================================================ FILE: xmake/actions/config/configfiles.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file configfiles.lua -- -- imports import("core.base.option") import("core.base.semver") import("core.project.config") import("core.project.depend") import("core.project.project") import("core.platform.platform") import("lib.detect.find_tool") -- get all configuration files function _get_configfiles() local configfiles = {} for _, target in table.orderpairs(project.targets()) do if target:is_enabled() then -- get configuration files for target local srcfiles, dstfiles, fileinfos = target:configfiles() for idx, srcfile in ipairs(srcfiles) do -- get destinate file and file info local dstfile = dstfiles[idx] local fileinfo = fileinfos[idx] -- get source info local srcinfo = configfiles[dstfile] if not srcinfo then srcinfo = {} configfiles[dstfile] = srcinfo end -- save source file if srcinfo.srcfile then assert(path.absolute(srcinfo.srcfile) == path.absolute(srcfile), "file(%s) and file(%s) are writing a same file(%s)", srcfile, srcinfo.srcfile, dstfile) else srcinfo.srcfile = srcfile srcinfo.fileinfo = fileinfo end -- we use first target to get dependfile path -- @see https://github.com/xmake-io/xmake/issues/3321 if not srcinfo.dependfile then srcinfo.dependfile = target:dependfile(srcfile) end -- always update? local always_update = target:policy("build.always_update_configfiles") if always_update == nil then always_update = project.policy("build.always_update_configfiles") end srcinfo.always_update = always_update -- save targets srcinfo.targets = srcinfo.targets or {} table.insert(srcinfo.targets, target) -- save preprocessors local preprocessor = fileinfo and fileinfo.preprocessor if preprocessor then srcinfo.preprocessors = srcinfo.preprocessors or {} table.insert(srcinfo.preprocessors, preprocessor) end end end end return configfiles end -- get the builtin variables function _get_builtinvars_target(target) -- get version variables local builtinvars = {} local version, version_build = target:version() if version then builtinvars.VERSION = version try {function () local v = semver.new(version) if v then builtinvars.VERSION_MAJOR = v:major() builtinvars.VERSION_MINOR = v:minor() builtinvars.VERSION_ALTER = v:patch() end end} if version_build then builtinvars.VERSION_BUILD = version_build end end return builtinvars end -- get the git builtin variables function _get_builtinvars_git(builtinvars) local cmds = { GIT_TAG = {"describe", "--tags"}, GIT_TAG_LONG = {"describe", "--tags", "--long"}, GIT_BRANCH = {"rev-parse", "--abbrev-ref", "HEAD"}, GIT_COMMIT = {"rev-parse", "--short", "HEAD"}, GIT_COMMIT_LONG = {"rev-parse", "HEAD"}, GIT_COMMIT_DATE = {"log", "-1", "--date=format:%Y%m%d%H%M%S", "--format=%ad"} } for name, argv in pairs(cmds) do builtinvars[name] = function () local result local git = find_tool("git") if git then result = try {function () return os.iorunv(git.program, argv) end} end if not result then result = "none" end return result:trim() end end end -- get the global builtin variables function _get_builtinvars_global() local builtinvars = _g.builtinvars_global if builtinvars == nil then builtinvars = { arch = config.get("arch") or os.arch() , plat = config.get("plat") or os.host() , host = os.host() , mode = config.get("mode") or "release" , debug = is_mode("debug") and 1 or 0 , os = platform.os() } local builtinvars_upper = {} for name, value in pairs(builtinvars) do builtinvars_upper[name:upper()] = type(value) == "string" and value:upper() or value end table.join2(builtinvars, builtinvars_upper) _get_builtinvars_git(builtinvars) _g.builtinvars_global = builtinvars end return builtinvars end function _preprocess_define_value(name, value, opt) opt = opt or {} local extraconf = opt.extraconf if value == nil then value = ("/* #undef %s */"):format(name) elseif type(value) == "boolean" then if value then value = ("#define %s 1"):format(name) else value = ("/* #define %s 0 */"):format(name) end elseif type(value) == "number" then value = ("#define %s %d"):format(name, value) elseif type(value) == "string" then local quote = true local escape = false if extraconf then -- disable to wrap quote, @see https://github.com/xmake-io/xmake/issues/1694 if extraconf.quote == false then quote = false end -- escape path seperator when with quote, @see https://github.com/xmake-io/xmake/issues/1872 if quote and extraconf.escape then escape = true end end if quote then if escape then value = value:gsub("\\", "\\\\") end value = ("#define %s \"%s\""):format(name, value) else value = ("#define %s %s"):format(name, value) end else raise("unknown variable(%s) type: %s", name, type(value)) end return value end function _preprocess_default_value(name, value, opt) opt = opt or {} local default = table.unpack(opt.argv or {}) assert(default ~= nil, "please set default value for variable(%s)", variable) if value == nil then value = default else value = tostring(value) end return value end function _preprocess_define_export_value(name, value, opt) value = ([[#ifdef %s_STATIC # define %s_EXPORT #else # if defined(_WIN32) # define %s_EXPORT __declspec(dllexport) # elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) # define %s_EXPORT __attribute__((visibility("default"))) # else # define %s_EXPORT # endif #endif ]]):format(name, name, name, name, name) return value end -- get variable value function _get_variable_value(variables, name, opt) opt = opt or {} local preprocessor_name = opt.preprocessor_name local preprocessor_argv = opt.preprocessor_argv local configfile = opt.configfile local value = variables[name] local extraconf = variables["__extraconf_" .. name] if preprocessor_name then local preprocessed = false if opt.preprocessors then for _, preprocessor in ipairs(opt.preprocessors) do value = preprocessor(preprocessor_name, name, value, {argv = preprocessor_argv, extraconf = extraconf}) if value ~= nil then preprocessed = true break end end end if not preprocessed then local preprocessors = _g._preprocessors if preprocessors == nil then preprocessors = { define = _preprocess_define_value, default = _preprocess_default_value, define_export = _preprocess_define_export_value } _g._preprocessors = preprocessors end local preprocessor = preprocessors[preprocessor_name] if preprocessor == nil then raise("unknown variable keyword, ${%s %s}", preprocessor_name, name) end value = preprocessor(name, value, {argv = preprocessor_argv, extraconf = extraconf}) end assert(value ~= nil, "cannot get variable(%s %s) in %s.", preprocessor_name, name, configfile) else assert(value ~= nil, "cannot get variable(%s) in %s.", name, configfile) end dprint(" > replace %s -> %s", name, value) if type(value) == "table" then dprint("invalid variable value", value) end return value end -- generate the configuration file function _generate_configfile(srcfile, dstfile, fileinfo, targets, preprocessors) -- trace if option.get("verbose") then cprint("${dim}generating %s to %s ..", srcfile, dstfile) end -- only copy it? if fileinfo.onlycopy then if os.mtime(srcfile) > os.mtime(dstfile) then os.cp(srcfile, dstfile) end else -- generate to the temporary file first local dstfile_tmp = os.tmpfile(srcfile) os.tryrm(dstfile_tmp) os.cp(srcfile, dstfile_tmp) -- get all variables local variables = fileinfo.variables or {} for _, target in ipairs(targets) do -- get variables from the target for name, value in pairs(target:get("configvar")) do if variables[name] == nil then value = table.unwrap(value) variables[name] = value variables["__extraconf_" .. name] = target:extraconf("configvar." .. name, value) end end -- get variables from the target.options for _, opt in ipairs(target:orderopts()) do for name, value in pairs(opt:get("configvar")) do if variables[name] == nil then variables[name] = table.unwrap(value) variables["__extraconf_" .. name] = opt:extraconf("configvar." .. name, value) end end end -- get the builtin variables from the target for name, value in pairs(_get_builtinvars_target(target)) do if type(value) == "function" then value = value() end if variables[name] == nil then variables[name] = value end end end -- get the global builtin variables for name, value in pairs(_get_builtinvars_global()) do if type(value) == "function" then value = value() end if variables[name] == nil then variables[name] = value end end -- replace all variables local pattern = fileinfo.pattern or "%${([^\n]-)}" io.gsub(dstfile_tmp, "(" .. pattern .. ")", function(_, variable) variable = variable:trim() local preprocessor_argv local preprocessor_name local parts = variable:split("%s") if #parts > 1 then preprocessor_name = parts[1] variable = parts[2] preprocessor_argv = table.slice(parts, 3) end return _get_variable_value(variables, variable, {preprocessor_name = preprocessor_name, preprocessor_argv = preprocessor_argv, configfile = srcfile, preprocessors = preprocessors}) end) -- update file if the content is changed if os.isfile(dstfile_tmp) then os.cp(dstfile_tmp, dstfile, {copy_if_different = true}) end end -- trace cprint("generating %s ... ${color.success}${text.success}", srcfile) end -- the main entry function function main(opt) -- enter project directory opt = opt or {} local oldir = os.cd(project.directory()) -- generate all configuration files local configfiles = _get_configfiles() for dstfile, srcinfo in pairs(configfiles) do depend.on_changed(function () _generate_configfile(srcinfo.srcfile, dstfile, srcinfo.fileinfo, srcinfo.targets, srcinfo.preprocessors) end, {files = srcinfo.srcfile, lastmtime = os.mtime(dstfile), dependfile = srcinfo.dependfile, changed = opt.force or srcinfo.always_update}) end -- leave project directory os.cd(oldir) end ================================================ FILE: xmake/actions/config/main.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file main.lua -- -- imports import("core.base.option") import("core.base.global") import("core.base.hashset") import("core.tool.toolchain") import("core.project.config") import("core.project.project") import("core.platform.platform") import("private.detect.find_platform") import("core.cache.localcache") import("core.cache.detectcache") import("scangen") import("menuconf", {alias = "menuconf_show"}) import("configfiles", {alias = "generate_configfiles"}) import("private.action.require.register", {alias = "register_packages"}) import("private.action.require.install", {alias = "install_packages"}) import("private.service.remote_build.action", {alias = "remote_build_action"}) import("private.utils.target", {alias = "target_utils"}) -- filter option function _option_filter(name) local options = { target = true , file = true , root = true , yes = true , quiet = true , confirm = true , project = true , verbose = true , diagnosis = true , require = true , export = true , import = true , check = true , menu = true } return not options[name] end -- host changed? function _host_changed() return os.host() ~= config.read("host") end -- need check function _need_check(changed) -- clean? if not changed then changed = option.get("clean") or option.get("check") end -- check for all project files local mtimes = project.mtimes() if not changed then local mtimes_prev = localcache.get("config", "mtimes") if mtimes_prev then for file, mtime in pairs(mtimes) do -- modified? reconfig and rebuild it local mtime_prev = mtimes_prev[file] if not mtime_prev or mtime > mtime_prev then changed = true break end end end end -- unfinished config/recheck if not changed and localcache.get("config", "recheck") then changed = true end -- Has xmake been updated? force to check config again -- we need to clean the dirty config cache of the old version if not changed then if os.mtime(path.join(os.programdir(), "core", "main.lua")) > os.mtime(config.filepath()) then changed = true os.touch(config.filepath(), {mtime = os.time()}) end end return changed end -- check target function _check_target(target, checked_targets) if not checked_targets[target:fullname()] then checked_targets[target:fullname()] = target for _, depname in ipairs(target:get("deps")) do local deptarget = project.target(depname, {namespace = target:namespace()}) assert(deptarget, "unknown target(%s) for %s.deps!", depname, target:fullname()) _check_target(deptarget, checked_targets) end end end -- check targets function _check_targets() assert(not project.is_loaded(), "project and targets may have been loaded early!") local checked_targets = {} for _, target in pairs(project.targets()) do _check_target(target, checked_targets) end end -- find default mode function _find_default_mode() local mode = config.mode() if not mode then mode = project.get("defaultmode") if not mode then mode = "release" end config.set("mode", mode) end return mode end -- check configs function _check_configs() -- check allowed modes local mode = config.mode() local allowed_modes = project.allowed_modes() if allowed_modes then if not allowed_modes:has(mode) then local allowed_modes_str = table.concat(allowed_modes:to_array(), ", ") raise("`%s` is not a valid complation mode for this project, please use one of %s", mode, allowed_modes_str) end end -- check allowed plats local plat = config.plat() local allowed_plats = project.allowed_plats() if allowed_plats then if not allowed_plats:has(plat) then local allowed_plats_str = table.concat(allowed_plats:to_array(), ", ") raise("`%s` is not a valid platform for this project, please use one of %s", plat, allowed_plats_str) end end -- check allowed archs local arch = config.arch() local allowed_archs = project.allowed_archs(config.plat()) if allowed_archs then if not allowed_archs:has(arch) then local allowed_archs_str = table.concat(allowed_archs:to_array(), ", ") raise("`%s` is not a valid complation arch for this project, please use one of %s", arch, allowed_archs_str) end end end -- export configs function _export_configs() local exportfile = option.get("export") if exportfile then config.save(exportfile, {public = true}) end end function main(opt) -- do action for remote? if remote_build_action.enabled() then return remote_build_action() end -- avoid running this task repeatly opt = opt or {} if _g.configured then return end _g.configured = true -- scan project and generate it if xmake.lua not exists local autogen = false local trybuild = option.get("trybuild") if not os.isfile(project.rootfile()) and not trybuild then autogen = utils.confirm({default = false, description = "xmake.lua not found, try generating it"}) if autogen then scangen() else os.exit() end end -- check the working directory if not option.get("project") and not option.get("file") and -- no given project path not localcache.get("project", "projectdir") and -- no cached project path not localcache.get("project", "projectfile") and os.isdir(os.projectdir()) then if path.translate(os.projectdir()) ~= path.translate(os.workingdir()) then wprint([[You are working in the project directory(%s) and you can also force to build in current directory via run `xmake -P .`]], os.projectdir()) end end -- lock the whole project project.lock() -- enter menu config local options_changed = false if option.get("menu") then options_changed = menuconf_show() end -- load the project configuration -- -- priority: option > option_cache > global > option_default > config_check > project_check > config_cache -- -- get the options local options = nil for name, value in pairs(option.options()) do if _option_filter(name) then options = options or {} options[name] = value end end -- merge options from the given import file local importfile = option.get("import") if importfile then assert(os.isfile(importfile), "%s not found!", importfile) -- we need to use readonly, @see https://github.com/xmake-io/xmake/issues/2278 local import_configs = io.load(importfile) if import_configs then for name, value in pairs(import_configs) do options = options or {} if options[name] == nil then options[name] = value end end end end -- override configuration from the options or cache local options_history = {} if not option.get("clean") and not autogen then options_history = localcache.get("config", "options") or {} options = options or options_history end for name, value in pairs(options) do -- Is options changed by argument options? options_changed = options_changed or options_history[name] ~= value -- @note override it and mark as readonly (highest priority) config.set(name, value, {readonly = true}) end -- merge the cached configuration -- -- @note we cannot load cache config when switching platform, arch .. -- so we need known whether options have been changed -- local configcache_loaded = false if not options_changed and not option.get("clean") and not _host_changed() then configcache_loaded = config.load() end -- merge the global configuration for name, value in pairs(global.options()) do if config.get(name) == nil then config.set(name, value) end end -- merge the default options for name, value in pairs(option.defaults()) do if _option_filter(name) and config.get(name) == nil then config.set(name, value) end end -- merge the project options after default options for name, value in pairs(project.get("config")) do value = table.unwrap(value) assert(type(value) == "string" or type(value) == "boolean" or type(value) == "number", "set_config(%s): unsupported value type(%s)", name, type(value)) if not config.readonly(name) then config.set(name, value) end end -- find default mode local mode = _find_default_mode() assert(mode == config.mode()) -- find default platform and save to configuration local plat, arch = find_platform({global = true}) assert(plat == config.plat()) assert(arch == config.arch()) -- load platform instance local instance_plat = platform.load(plat, arch) -- merge the checked configuration local recheck = _need_check(options_changed or not configcache_loaded or autogen) if recheck then -- clear cached configuration if option.get("clean") then localcache.clear("config") end -- clear some local caches localcache.clear("detect") localcache.clear("option") localcache.clear("package") localcache.clear("toolchain") localcache.set("config", "recheck", true) if not opt.loadonly then localcache.save() end -- check platform instance_plat:check() -- check project options if not trybuild then project.check_options() end end -- translate the build directory local builddir = config.get("builddir") if config.get("buildir") then wprint("`xmake f --buildir=` has been deprecated, please use `xmake f -o/--builddir=`") builddir = config.get("buildir") config.set("builddir", builddir, {readonly = true, force = true}) end if builddir and path.is_absolute(builddir) then config.set("builddir", path.relative(builddir, project.directory()), {readonly = true, force = true}) end -- only config for building project using third-party buildsystem if not trybuild then -- check configs _check_configs() -- install and register packages local require_enable = option.boolean(option.get("require")) if (recheck or require_enable) then if require_enable ~= false then install_packages() else register_packages() end end -- check target and ensure to load all targets, @note we must load targets after installing required packages, -- otherwise has_package() will be invalid. _check_targets() -- check target toolchains if recheck then target_utils.check_target_toolchains() end -- load targets project.load_targets({recheck = recheck}) -- update the config files generate_configfiles({force = recheck}) end -- dump config if option.get("verbose") and not opt.disable_dump then config.dump() end -- export configs if option.get("export") then _export_configs() end -- save configs and caches if not opt.loadonly then -- we need to save it and enable external working mode -- if we configure the given project directory -- -- @see https://github.com/xmake-io/xmake/issues/3342 -- local projectdir = option.get("project") local projectfile = option.get("file") if projectdir or projectfile then localcache.set("project", "projectdir", projectdir) localcache.set("project", "projectfile", projectfile) localcache.save("project") end -- save options and config cache localcache.set("config", "recheck", false) localcache.set("config", "mtimes", project.mtimes()) config.save() localcache.set("config", "options", options) localcache.save("config") -- save toolchain cache toolchain.save() -- save detect cache detectcache:save() end -- unlock the whole project project.unlock() end ================================================ FILE: xmake/actions/config/menuconf.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file menuconf.lua -- -- imports import("core.base.option") import("core.project.config") import("core.project.project") import("core.ui.log") import("core.ui.rect") import("core.ui.view") import("core.ui.label") import("core.ui.event") import("core.ui.action") import("core.ui.menuconf") import("core.ui.mconfdialog") import("core.ui.application") import("private.detect.find_platform") -- the app application local app = application() -- init app function app:init() -- init name application.init(self, "app.config") -- init background self:background_set("blue") -- insert menu config dialog self:insert(self:mconfdialog()) -- load configs self:load(not option.get("clean")) end -- get menu config dialog function app:mconfdialog() if not self._MCONFDIALOG then local mconfdialog = mconfdialog:new("app.config.mconfdialog", rect{1, 1, self:width() - 1, self:height() - 1}, "menu config") mconfdialog:action_set(action.ac_on_exit, function (v) self:quit() os.exit() end) mconfdialog:action_set(action.ac_on_save, function (v) self:save() self:quit() end) self._MCONFDIALOG = mconfdialog end return self._MCONFDIALOG end -- on resize function app:on_resize() self:mconfdialog():bounds_set(rect{1, 1, self:width() - 1, self:height() - 1}) application.on_resize(self) end -- filter option function app:_filter_option(name) local options = { target = true , file = true , root = true , yes = true , quiet = true , confirm = true , project = true , verbose = true , diagnosis = true , require = true , version = true , help = true , clean = true , menu = true , import = true , export = true , check = true } return not options[name] and not project.option(name) end -- get or make menu by category function app:_menu_by_category(root, configs, menus, category) -- is root? if category == "." or category == "" then return end -- attempt to get menu first local menu = menus[category] if not menu then -- get config path local parentdir = path.directory(category) local config_path = path.join(root, parentdir == "." and "" or parentdir) -- make a new menu menu = menuconf.menu {name = category, path = config_path, description = path.basename(category), configs = {}} menus[category] = menu -- insert to the parent or root configs local parent = self:_menu_by_category(root, configs, menus, parentdir) table.insert(parent and parent.configs or configs, menu) end return menu end -- make configs by category function app:_make_configs_by_category(root, options_by_category, cache, get_option_info) -- make configs category -- -- root category: "." -- category path: "a", "a/b", "a/b/c" ... -- local menus = {} local configs = {} local categories = table.orderkeys(options_by_category) for _, category in ipairs(categories) do -- get or make menu by category local options = options_by_category[category] local menu = self:_menu_by_category(root, configs, menus, category) -- get sub-configs local subconfigs = menu and menu.configs or configs -- insert options to sub-configs for _, opt in ipairs(options) do -- get option info local info = get_option_info(opt) -- new value? local newvalue = true -- load value local value = nil if cache then value = config.get(info.name) if value ~= nil and info.kind == "choice" and info.values then for idx, val in ipairs(info.values) do if value == val then value = idx break end end end if value ~= nil then newvalue = false end end -- find the menu index in subconfigs local menu_index = #subconfigs + 1 for idx, subconfig in ipairs(subconfigs) do if subconfig.kind == "menu" then menu_index = idx break end end -- get config path local config_path = path.join(root, category == "." and "" or category) -- insert config before all sub-menus if info.kind == "string" then table.insert(subconfigs, menu_index, menuconf.string {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, description = info.description, sourceinfo = info.sourceinfo}) elseif info.kind == "boolean" then table.insert(subconfigs, menu_index, menuconf.boolean {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, description = info.description, sourceinfo = info.sourceinfo}) elseif info.kind == "choice" then table.insert(subconfigs, menu_index, menuconf.choice {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, values = info.values, description = info.description, sourceinfo = info.sourceinfo}) end end end -- done return configs end -- get basic configs function app:_basic_configs(cache) -- get configs from the cache first local configs = self._BASIC_CONFIGS if configs then return configs end -- get config menu local menu = option.taskmenu("config") -- merge options by category local category = "." local options = menu and menu.options or {} local options_by_category = {} local keys = table.orderkeys(options) for _, key in ipairs(keys) do local opt = options[key] local name = opt[2] or opt[1] if name and self:_filter_option(name) then options_by_category[category] = options_by_category[category] or {} table.insert(options_by_category[category], opt) elseif opt.category then category = opt.category end end -- make configs by category self._BASIC_CONFIGS = self:_make_configs_by_category("Basic Configuration", options_by_category, cache, function (opt) -- get option local name = opt[2] or opt[1] local default = opt[4] local kind = (opt[3] == "k" or type(default) == "boolean") and "boolean" or "string" -- get default values if name == "plat" then default = find_platform() elseif name == "arch" then _, default = find_platform() elseif name == "mode" then default = project.get("defaultmode") if not default then default = "release" end end -- choice option? local values = opt.values if values then if type(values) == "function" then values = values(false, {menuconf = true}) end values = table.wrap(values) for idx, value in ipairs(values) do if default == value then default = idx break end end end if values then kind = "choice" end -- get description local description = {} for i = 5, 64 do local desc = opt[i] if type(desc) == "function" then desc = desc() end if type(desc) == "string" then table.insert(description, desc) elseif type(desc) == "table" then table.join2(description, desc) else break end end -- make option info return {name = name, kind = kind, default = default, values = values, description = description} end) return self._BASIC_CONFIGS end -- get project configs function app:_project_configs(cache) -- get configs from the cache first local configs = self._PROJECT_CONFIGS if configs then return configs end -- merge options by category local options = project.options() local options_by_category = {} local keys = table.orderkeys(options) for _, key in ipairs(keys) do local opt = options[key] if opt:showmenu() ~= false then local category = "." if opt:get("category") then category = table.unwrap(opt:get("category")) end options_by_category[category] = options_by_category[category] or {} table.insert(options_by_category[category], opt) end end -- make configs by category self._PROJECT_CONFIGS = self:_make_configs_by_category("Project Configuration", options_by_category, cache, function (opt) -- the default value local default = "auto" if opt:get("default") ~= nil then default = opt:get("default") end -- get kind local kind = (type(default) == "string") and "string" or "boolean" -- get description local description = opt:description() -- get source info local sourceinfo = (opt:get("__sourceinfo_description") or {})[type(description) == "table" and description[1] or description] -- choice option? local values = opt:get("values") if values then kind = "choice" values = table.wrap(values) for idx, value in ipairs(values) do if default == value then default = idx break end end end return {name = opt:name(), kind = kind, default = default, values = values, description = description, sourceinfo = sourceinfo} end) return self._PROJECT_CONFIGS end -- save the given configs function app:_save_configs(configs) local options = option.options() for _, conf in pairs(configs) do if conf.kind == "menu" then self:_save_configs(conf.configs) elseif not conf.new and (conf.kind == "boolean" or conf.kind == "string") then options[conf.name] = conf.value elseif not conf.new and (conf.kind == "choice") then options[conf.name] = conf.values[conf.value] end end end -- Have configs been changed? function app:_configs_changed() return self._CONFIGS_CHANGED end -- load configs from options function app:load(cache) -- merge configuration from the given import file or cache local loaded = false local importfile = option.get("import") if importfile and os.isfile(importfile) then loaded = config.load(importfile) elseif cache then loaded = config.load() end -- clear configs first self._BASIC_CONFIGS = nil self._PROJECT_CONFIGS = nil -- load configs local configs = {} table.insert(configs, menuconf.menu {description = "Basic Configuration", configs = self:_basic_configs(cache)}) table.insert(configs, menuconf.menu {description = "Project Configuration", configs = self:_project_configs(cache)}) self:mconfdialog():load(configs) -- the previous config is only for loading menuconf, so clear config now if loaded then config.clear() end end -- save configs to options function app:save() self:_save_configs(self:_basic_configs()) self:_save_configs(self:_project_configs()) self._CONFIGS_CHANGED = true end -- main entry function main(...) app:run(...) return app:_configs_changed() end ================================================ FILE: xmake/actions/config/scangen.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file scangen.lua -- -- imports import("core.project.config") import("core.project.project") import("core.language.language") -- scan project and generate xmake.lua automaticlly if the project codes exist function main() -- trace cprint("${color.warning}xmake.lua not found, scanning files ..") -- scan source files for the current directory local targetkinds = {} local sourcefiles = {} local sourcefiles_main = {} for extension, sourcekind in pairs(language.extensions()) do -- load language instance local instance = language.load_sk(sourcekind) -- get check main() script local check_main = instance:get("check_main") -- scan source files local filecount = 0 for _, sourcefile in ipairs(os.files("*" .. extension)) do if check_main and check_main(sourcefile) then table.insert(sourcefiles_main, sourcefile) else table.insert(sourcefiles, sourcefile) end filecount = filecount + 1 end -- add targetkinds if filecount > 0 then for targetkind, _ in pairs(instance:kinds()) do targetkinds[targetkind] = true end end end sourcefiles = table.unique(sourcefiles) sourcefiles_main = table.unique(sourcefiles_main) -- project not found if #sourcefiles == 0 and #sourcefiles_main == 0 then raise("project not found!") end -- generate xmake.lua local file = io.open("xmake.lua", "w") if file then -- get target name local targetname = path.basename(os.curdir()) -- define static/binary target if #sourcefiles > 0 then -- get targetkind local targetkind = nil if targetkinds["static"] then targetkind = "static" elseif targetkinds["binary"] then targetkind = "binary" end assert(targetkind, "unknown target kind!") -- trace cprint("target(${magenta}%s${clear}): %s", targetname, targetkind) -- add rules file:print("add_rules(\"mode.debug\", \"mode.release\")") file:print("") -- add target file:print("target(\"%s\")", targetname) file:print(" set_kind(\"%s\")", targetkind) for _, sourcefile in ipairs(sourcefiles) do cprint(" ${green}[+]: ${clear}%s", sourcefile) file:print(" add_files(\"%s\")", sourcefile) end file:print("") end -- define binary targets for _, sourcefile in ipairs(sourcefiles_main) do -- trace local name = path.basename(sourcefile) if name == targetname then name = name .. "1" end cprint("target(${magenta}%s${clear}): binary", name) cprint(" ${green}[+]: ${clear}%s", sourcefile) -- add target file:print("target(\"%s\")", name) file:print(" set_kind(\"binary\")") file:print(" add_files(\"%s\")", sourcefile) file:print("") -- add deps if #sourcefiles > 0 then file:print(" add_deps(\"%s\")", targetname) file:print("") end end -- add FAQ file:print(io.readfile(path.join(os.programdir(), "scripts", "faq.lua"))) -- exit file file:close() end -- generate .gitignore if not exists if not os.isfile(".gitignore") then os.cp("$(programdir)/scripts/gitignore", ".gitignore") end -- trace cprint("${color.success}xmake.lua generated, scan ok!") end ================================================ FILE: xmake/actions/config/xmake.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file xmake.lua -- function _plat_values(complete, opt) import("core.platform.platform") import("core.base.hashset") import("core.project.project") if not complete or not opt.arch then local plats = try {function () return project.allowed_plats() end} if plats then return plats:to_array() end return platform.plats() end -- arch has given, find all supported platforms local plats = {} for _, plat in ipairs(platform.plats()) do local archs = hashset.from(platform.archs(plat)) if archs:has(opt.arch) then table.insert(plats, plat) end end return plats end function _arch_values(complete, opt) opt = opt or {} if opt.helpmenu then return end -- imports import("core.project.project") import("core.platform.platform") import("core.base.hashset") -- get all platforms local plats = try {function () return project.allowed_plats() end} if plats then plats = plats:to_array() end plats = plats or platform.plats() -- get all architectures local archset = hashset.new() for _, plat in ipairs(opt.plat and { opt.plat } or plats) do local archs = try {function () return project.allowed_archs(plat) end} if archs then archs = archs:to_array() end if not archs then archs = platform.archs(plat) end if archs then for _, arch in ipairs(archs) do archset:insert(arch) end end end return archset:to_array() end function _arch_description() import("core.project.project") import("core.platform.platform") -- get all platforms local plats = try {function () return project.allowed_plats() end} if plats then plats = plats:to_array() end plats = plats or platform.plats() -- get all architectures local description = {} for i, plat in ipairs(plats) do local archs = try {function () return project.allowed_archs(plat) end} if archs then archs = archs:to_array() end if not archs then archs = platform.archs(plat) end if archs and #archs > 0 then local desc = " - " .. plat .. ":" for _, arch in ipairs(archs) do desc = desc .. " " .. arch end table.insert(description, desc) end end return description end function _mode_values(complete, opt) import("core.project.project") opt = opt or {} local modes = try {function() if opt.menuconf then -- we cannot load target.mode in menuconf local allowed_modes = project.allowed_modes() if allowed_modes then return allowed_modes:to_array() end else return project.modes() end end} if not modes then modes = {"debug", "release"} end return modes end function _target_values(complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) end -- the toolchains is too much, so we just show all for menuconf and auto-complete mode. -- @see https://github.com/xmake-io/xmake/issues/3436 -- function _toolchain_values(complete, opt) opt = opt or {} if complete or opt.menuconf then import("core.tool.toolchain") return toolchain.list() end end function _project_menu_options() import("core.project.menu") return menu.options() end function _language_menu_options() import("core.language.menu") return menu.options("config") end function _platform_menu_options() import("core.platform.menu") return menu.options("config") end task("config") set_category("action") on_run("main") set_menu { usage = "xmake config|f [options]", description = "Configure the project.", shortname = 'f', options = { {'c', "clean", "k", nil , "Clean the cached user configs and detection cache."}, {nil, "check", "k", nil , "Just ignore detection cache and force to check all, it will reserve the cached user configs."}, {nil, "export", "kv", nil , "Export the current configuration to the given file." , " e.g." , " - xmake f -m debug -xxx=y --export=build/config.txt"}, {nil, "import", "kv", nil , "Import configs from the given file." , " e.g." , " - xmake f -import=build/config.txt"}, {nil, "menu", "k", nil , "Configure project with a menu-driven user interface."}, {category = "."}, {'p', "plat", "kv", "auto" , "Compile for the given platform.", values = _plat_values}, {'a', "arch", "kv", "auto" , "Compile for the given architecture.", _arch_description, values = _arch_values}, {'m', "mode", "kv", "auto" , "Compile for the given mode.", values = _mode_values}, {'k', "kind", "kv", "static" , "Compile for the given target kind.", values = {"static", "shared", "binary"}}, {nil, "host", "kv", "$(host)" , "Set the current host environment."}, {nil, "policies", "kv", nil , "Set the project policies.", " e.g.", " - xmake f --policies=package.fetch_only", " - xmake f --policies=package.precompiled:n,package.install_only"}, {category = "Package Configuration"}, {nil, "require", "kv", nil , "Require all dependent packages?", values = {"yes", "no"}}, {nil, "pkg_searchdirs", "kv", nil , "The search directories of the remote package." , " e.g." , " - xmake f --pkg_searchdirs=/dir1" .. path.envsep() .. "/dir2"}, {category = "Cross Complation Configuration"}, {nil, "cross", "kv", nil, "Set cross toolchains prefix" , "e.g." , " - i386-mingw32-" , " - arm-linux-androideabi-"}, {nil, "target_os", "kv", nil, "Set target os only for cross-complation"}, {nil, "bin", "kv", nil, "Set cross toolchains bin directory" , "e.g." , " - sdk/bin (/arm-linux-gcc ..)"}, {nil, "sdk", "kv", nil, "Set cross SDK directory" , "e.g." , " - sdk/bin" , " - sdk/lib" , " - sdk/include"}, {nil, "toolchain", "kv", nil, "Set toolchain name" , "e.g. " , " - xmake f --toolchain=clang" , " - xmake f --toolchain=[cross|llvm|sdcc ..] --sdk=/xxx" , " - run `xmake show -l toolchains` to get all toolchains" , values = _toolchain_values}, {nil, "toolchain_host", "kv", nil, "Set host toolchain name, it's only for building packages on host machine." , "e.g. " , " - xmake f --toolchain_host=clang" , " - xmake f --toolchain_host=[cross|llvm|sdcc ..] --sdk=/xxx" , " - run `xmake show -l toolchains` to get all toolchains" , values = _toolchain_values}, {nil, "runtimes", "kv", nil, "Set the compiler runtime library." , "e.g. " , " - xmake f --runtimes=MTd" , " - xmake f --runtimes=MT,c++_static" , values = {"MT", "MTd", "MD", "MDd", -- only for msvc "c++_static", "c++_shared", -- gcc/clang/android ndk "stdc++_static", "stdc++_shared", -- gcc/clang "gnustl_static", "gnustl_shared", -- only for old android ndk "stlport_static", "stlport_shared"}}, -- only for old android ndk _language_menu_options, _platform_menu_options, {category = "Other Configuration"}, {nil, "debugger", "kv", "auto" , "Set debugger"}, {nil, "ccache", "kv", true , "Enable or disable the c/c++ compiler cache."}, {nil, "ccachedir", "kv", nil , "Set the ccache directory."}, {nil, "trybuild", "kv", nil , "Enable try-build mode and set the third-party buildsystem tool.", "e.g.", " - xmake f --trybuild=auto; xmake", " - xmake f --trybuild=autoconf -p android --ndk=xxx; xmake", "", "the third-party buildsystems:" , values = {"auto", "make", "autoconf", "cmake", "scons", "meson", "bazel", "ninja", "msbuild", "xcodebuild", "ndkbuild", "xrepo"}}, {nil, "tryconfigs", "kv", nil , "Set the extra configurations of the third-party buildsystem for the try-build mode.", "e.g.", " - xmake f --trybuild=autoconf --tryconfigs='--enable-shared=no'"}, {'o', "builddir", "kv", "build" , "Set build directory."}, {nil, "buildir", "kv", nil , "Set build directory. (deprecated)"}, {}, {category = "Project Configuration"}, _project_menu_options}} ================================================ FILE: xmake/actions/create/main.lua ================================================ --!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file main.lua -- -- imports import("core.base.option") import("core.project.project") import("actions.create.template", {rootdir = os.programdir()}) -- validate template component against path traversal function _validate_template_component(name, value) if #value == 0 or value == "." or value == ".." or value:find("/", 1, true) or value:find("\\", 1, true) or value:find(":", 1, true) or value:find("\0", 1, true) then raise("invalid %s: %s!", name, value) end end -- get template language from template id function _get_language_from_template(templateid) local lang = option.get("language") if lang then _validate_template_component("language", lang) end if not templateid or not lang or template.templatedir(lang, templateid) then return lang end local langs = template.languages_for_template(templateid) if #langs == 1 then return langs[1] elseif #langs > 1 then raise("template(%s): please pass -l/--language, supported languages: %s", templateid, table.concat(langs, ", ")) end return lang end -- get template id from command line options function _get_templateid() local templateid = option.get("template") _validate_template_component("template id", templateid) return templateid end -- get target name from command line options function _get_targetname() return option.get("target") or path.basename(project.directory()) or "demo" end -- list all supported templates for each language -- -- output is in tree format: -- -- --