--- /dev/null
+# Cscope/Tags
+/cscope.files
+/cscope.out
+/tags
+
+# Output
+/xenvkbd
--- /dev/null
+Building the XenVkbd Package
+============================
+
+First you'll need a device driver build environment for Windows 8, Windows
+8.1, or Windows 10.
+For Windows 8 this means:
+
+* Visual Studio 2012 (Professional or Ultimate)
+* Windows Driver Kit 8
+
+For Windows 8.1 this means:
+
+* Visual Studio 2013 (Any SKU, including Express)
+* Windows Driver Kit 8.1
+
+For Windows 10 this means:
+
+* Visual Studio 2015 (Any SKU, including Express or Community)
+* Windows Driver Kit 10
+
+(See http://msdn.microsoft.com/en-us/windows/hardware/hh852365.aspx). You
+may find it useful to install VirtualCloneDrive from http://www.slysoft.com
+as Visual Studio is generally supplied in ISO form.
+
+Install Visual Studio first (you only need install MFC for C++) and then
+the WDK. Set an environment variable called VS to the base of the Visual
+Studio Installation (e.g. C:\Program Files\Microsoft Visual Studio 12.0) and
+a variable called KIT to the base of the WDK
+(e.g. C:\Program Files\Windows Kits\8.1). Also set an environment variable
+called SYMBOL\_SERVER to point at a location where driver symbols can be
+stored. This can be local directory e.g. C:\Symbols.
+
+NOTE: If you are using WDK 10 then you will need to acquire the DIFx
+ re-distributable package from one of the other WDKs, so that the
+ driver build can copy dpinst.exe into the output.
+ Set the environment variable DPINST_REDIST to the base dpinst
+ directory (i.e. the directory under which the x86 and x64 sub-
+ directories containing dpinst.exe can be found).
+
+Next you'll need a 3.x version of python (which you can get from
+http://www.python.org). Make sure python.exe is somewhere on your default
+path.
+
+Now fire up a Command Prompt and navigate to the base of your git repository.
+At the prompt type:
+
+ build.py checked
+
+This will create a debug build of the driver. To create a non-debug build
+type:
+
+ build.py free
+
+Note that Static Driver Verifier is run by default as part of the build
+process. This can be very time consuming. If you don't want to run the
+verifier then you can add the 'nosdv' keyword to the end of your command
+e.g.:
+
+ build.py free nosdv
--- /dev/null
+Installing XenVkbd
+==================
+
+It's important to note that the build scripts generate a driver which is
+*test signed*. This means that when the driver is installed on a 64-bit
+version of Windows you must enabled testsigning mode otherwise your system
+will fail signature verification checked on the next reboot.
+If you wish to install the test certificate on the target system then copy
+xenvkbd.pfx (which you'll find in he proj subdirectory) onto your system and
+use certmgr to install it. (It is not password protected).
+
+xenvkbd.sys binds to one of three devices which may be created by XenBus:
+
+1. XENBUS\\VEN_XSC000&DEV_VKBD&REV_00000001
+2. XENBUS\\VEN_XS0001&DEV_VKBD&REV_00000001
+3. XENBUS\\VEN_XS0002&DEV_VKBD&REV_00000001
+
+The particular device present in your VM will be determined by the binding
+of the XenBus driver. The DeviceID of the PCI device to which it is bound is
+echoed in the VEN_ substring of the devices it creates. Hence only one of the
+above three variants will be present.
+
+To install the driver on your target system, copy the contents of the xenvkbd
+subdirectory onto the system, then navigate into the copy, to either the x86
+or x64 subdirectory (whichever is appropriate), and execute the copy of
+dpinst.exe you find there with Administrator privilege.
--- /dev/null
+Interface Versions and PDO Revisions\r
+====================================\r
+\r
+It is important that introduction of a new API, introduction of a new\r
+version of an existing API or retirement of an old version of an API is\r
+managed carefully to avoid incompatibilities between clients and\r
+providers. The general API versioning policy is described below:\r
+\r
+Each distinct set of API versions exported by a bus driver maps to a PDO\r
+revision. The DeviceID of each PDO created will specify the latest\r
+revision supported and all others will be contained within the\r
+HardwareIDs and CompatibleIDs. When a new version of an API is added,\r
+a new PDO revision must be added. When a version of an API is removed\r
+then ALL revisions that API version maps to must be removed. The mapping\r
+of interface versions to PDO revisions is specified in the header file\r
+include/revision.h in the bus driver source repository.\r
+\r
+Whe introducing a new version of an interface in a bus driver it is good\r
+practice to continue to support the previous version so it is not\r
+necessary to simultaneously introduce a new PDO revision and retire a\r
+previous one that child drivers may still be binding to.\r
+Child drivers should, of course, always be built to use the latest\r
+interface versions (which can be copied from the include directory in the\r
+source repository of the bus driver providing them) but it may take\r
+some time to make the necessary changes and deploy new builds of child\r
+drivers and so some overlap is desirable.\r
+\r
+To try to avoid installation of a version of a bus driver that is\r
+incompatible with child drivers installed on a system. There is a check\r
+in the pre-install phase in the co-intaller which compares the\r
+MatchingDeviceId values for each child driver against the table in\r
+include/revision.h in the bus driver source to make sure that the\r
+matching revision number is present.\r
--- /dev/null
+Copyright (c) Citrix Systems Inc.
+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.
+
+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.
+
--- /dev/null
+List of maintainers and how to submit changes
+=============================================
+
+If you wish to submit code, we recommend first reaching out to the maintainers,
+who will advise you on the precise procedure they wish to use.
+
+We also request you follow these basic guidelines:
+
+1. Make sure you test your changes on both a 32- and 64-bit version of Windows.
+ (The more versions of Windows you can test on the better).
+
+2. Make sure your changes do not introduce any new prefast warnings.
+
+3. Make a patch available to the relevant maintainer in the list. Use 'diff -u'
+ to make the patch easy to merge. Be prepared to get your changes sent back
+ with seemingly silly requests about formatting and variable names. These
+ aren't as silly as they seem. One job the maintainers do is to keep things
+ looking the same.
+
+ NOTE that all source should have Unix line endings.
+
+ PLEASE see http://wiki.xen.org/wiki/Submitting_Xen_Patches for hints on how
+ to submit a patch in a suitable form. Whilst the PV driver source
+ repositories are distinct from the Xen Project hypervisor source, we will
+ follow the same general patch submission and review process.
+
+ PLEASE try to include any credit lines you want added with the patch. It
+ avoids people being missed off by mistake and makes it easier to know who
+ wants adding and who doesn't.
+
+ PLEASE document known bugs. If it doesn't work for everything or does
+ something very odd once a month document it.
+
+ PLEASE remember that submissions must be made under the terms of the
+ "Developer's Certificate of Origin" (DCO) and should include a
+ Signed-off-by: line.
+
+4. Make sure you have the right to submit any changes you make. If you do
+ changes at work you may find your employer owns the patches instead of
+ you.
+
+
+Maintainers List
+----------------
+
+* Paul Durrant <paul.durrant@citrix.com>
+
+* Ben Chalmers <ben.chalmers@citrix.com>
+
+* Owen Smith <owen.smith@citrix.com>
+
--- /dev/null
+XenVkbd - The Xen Paravitual Keyboard/Mouse Driver for Windows
+==============================================================
+
+The XenVkbd package consists of a single device driver:
+
+* xenvkbd.sys is a bus driver which attaches to a virtual device created
+ by XenBus and creates a child device for each VKBD for XenHid to attach
+ to.
+ It is also a protocol driver for the kbdif wire protocol (see
+ include\\xen\\io\\kbdif.h).
+
+Quick Start Guide
+=================
+
+Building the driver
+-------------------
+
+See BUILD.md
+
+Installing the driver
+---------------------
+
+See INSTALL.md
+
+Driver Interfaces
+=================
+
+See INTERFACES.md
+
+Miscellaneous
+=============
+
+For convenience the source repository includes some other scripts:
+
+kdfiles.py
+----------
+
+This generates two files called kdfiles32.txt and kdfiles64.txt which can
+be used as map files for the .kdfiles WinDBG command.
+
+sdv.py
+------
+
+This runs Static Driver Verifier on the source.
+
+clean.py
+--------
+
+This removes any files not checked into the repository and not covered by
+the .gitignore file.
+
+get_xen_headers.py
+------------------
+
+This will import any necessary headers from a given tag of that Xen
+repository at git://xenbits.xen.org/xen.git.
--- /dev/null
+#!python -u
+
+import os, sys
+import datetime
+import re
+import glob
+import tarfile
+import subprocess
+import shutil
+import time
+
+def next_build_number():
+ try:
+ file = open('.build_number', 'r')
+ build_number = file.read()
+ file.close()
+ except IOError:
+ build_number = '0'
+
+ file = open('.build_number', 'w')
+ file.write(str(int(build_number) + 1))
+ file.close()
+
+ return build_number
+
+
+def make_header():
+ now = datetime.datetime.now()
+
+ file = open('include\\version.h', 'w')
+
+ file.write('#define VENDOR_NAME_STR\t\t"' + os.environ['VENDOR_NAME'] + '"\n')
+ file.write('#define VENDOR_PREFIX_STR\t"' + os.environ['VENDOR_PREFIX'] + '"\n')
+
+ if 'VENDOR_DEVICE_ID' in os.environ.keys():
+ file.write('#define VENDOR_DEVICE_ID_STR\t"' + os.environ['VENDOR_DEVICE_ID'] + '"\n')
+
+ file.write('#define PRODUCT_NAME_STR\t"' + os.environ['PRODUCT_NAME'] + '"\n')
+ file.write('\n')
+
+ file.write('#define MAJOR_VERSION\t\t' + os.environ['MAJOR_VERSION'] + '\n')
+ file.write('#define MAJOR_VERSION_STR\t"' + os.environ['MAJOR_VERSION'] + '"\n')
+ file.write('\n')
+
+ file.write('#define MINOR_VERSION\t\t' + os.environ['MINOR_VERSION'] + '\n')
+ file.write('#define MINOR_VERSION_STR\t"' + os.environ['MINOR_VERSION'] + '"\n')
+ file.write('\n')
+
+ file.write('#define MICRO_VERSION\t\t' + os.environ['MICRO_VERSION'] + '\n')
+ file.write('#define MICRO_VERSION_STR\t"' + os.environ['MICRO_VERSION'] + '"\n')
+ file.write('\n')
+
+ file.write('#define BUILD_NUMBER\t\t' + os.environ['BUILD_NUMBER'] + '\n')
+ file.write('#define BUILD_NUMBER_STR\t"' + os.environ['BUILD_NUMBER'] + '"\n')
+ file.write('\n')
+
+ file.write('#define YEAR\t\t\t' + str(now.year) + '\n')
+ file.write('#define YEAR_STR\t\t"' + str(now.year) + '"\n')
+ file.write('\n')
+
+ file.write('#define MONTH\t\t\t' + str(now.month) + '\n')
+ file.write('#define MONTH_STR\t\t"' + str(now.month) + '"\n')
+ file.write('\n')
+
+ file.write('#define DAY\t\t\t' + str(now.day) + '\n')
+ file.write('#define DAY_STR\t\t\t"' + str(now.day) + '"\n')
+ file.write('\n')
+
+ file.close()
+
+
+def copy_inf(vs, name):
+ src = open('src\\%s.inf' % name, 'r')
+ dst = open('%s\\%s.inf' % (vs, name), 'w')
+
+ for line in src:
+ line = re.sub('@MAJOR_VERSION@', os.environ['MAJOR_VERSION'], line)
+ line = re.sub('@MINOR_VERSION@', os.environ['MINOR_VERSION'], line)
+ line = re.sub('@MICRO_VERSION@', os.environ['MICRO_VERSION'], line)
+ line = re.sub('@BUILD_NUMBER@', os.environ['BUILD_NUMBER'], line)
+ line = re.sub('@VENDOR_NAME@', os.environ['VENDOR_NAME'], line)
+ line = re.sub('@VENDOR_PREFIX@', os.environ['VENDOR_PREFIX'], line)
+ line = re.sub('@PRODUCT_NAME@', os.environ['PRODUCT_NAME'], line)
+
+ if re.search('@VENDOR_DEVICE_ID@', line):
+ if 'VENDOR_DEVICE_ID' not in os.environ.keys():
+ continue
+ line = re.sub('@VENDOR_DEVICE_ID@', os.environ['VENDOR_DEVICE_ID'], line)
+
+ dst.write(line)
+
+ dst.close()
+ src.close()
+
+
+def get_expired_symbols(name, age = 30):
+ path = os.path.join(os.environ['SYMBOL_SERVER'], '000Admin\\history.txt')
+
+ try:
+ file = open(path, 'r')
+ except IOError:
+ return []
+
+ threshold = datetime.datetime.utcnow() - datetime.timedelta(days = age)
+
+ expired = []
+
+ for line in file:
+ item = line.split(',')
+
+ if (re.match('add', item[1])):
+ id = item[0]
+ date = item[3].split('/')
+ time = item[4].split(':')
+ tag = item[5].strip('"')
+
+ age = datetime.datetime(year = int(date[2]),
+ month = int(date[0]),
+ day = int(date[1]),
+ hour = int(time[0]),
+ minute = int(time[1]),
+ second = int(time[2]))
+ if (tag == name and age < threshold):
+ expired.append(id)
+
+ elif (re.match('del', item[1])):
+ id = item[2].rstrip()
+ try:
+ expired.remove(id)
+ except ValueError:
+ pass
+
+ file.close()
+
+ return expired
+
+
+def get_configuration(release, debug):
+ configuration = release
+
+ if debug:
+ configuration += ' Debug'
+ else:
+ configuration += ' Release'
+
+ return configuration
+
+
+def get_target_path(release, arch, debug, vs):
+ configuration = get_configuration(release, debug)
+ name = ''.join(configuration.split(' '))
+ target = { 'x86': os.sep.join([name, 'Win32']), 'x64': os.sep.join([name, 'x64']) }
+ target_path = os.sep.join([vs, target[arch]])
+
+ return target_path
+
+
+def shell(command, dir):
+ print(dir)
+ print(command)
+ sys.stdout.flush()
+
+ sub = subprocess.Popen(' '.join(command), cwd=dir,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ for line in sub.stdout:
+ print(line.decode(sys.getdefaultencoding()).rstrip())
+
+ sub.wait()
+
+ return sub.returncode
+
+
+class msbuild_failure(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+def msbuild(platform, configuration, target, file, args, dir):
+ os.environ['PLATFORM'] = platform
+ os.environ['CONFIGURATION'] = configuration
+ os.environ['TARGET'] = target
+ os.environ['FILE'] = file
+ os.environ['EXTRA'] = args
+
+ bin = os.path.join(os.getcwd(), 'msbuild.bat')
+
+ status = shell([bin], dir)
+
+ if (status != 0):
+ raise msbuild_failure(configuration)
+
+
+def build_sln(name, release, arch, debug, vs):
+ configuration = get_configuration(release, debug)
+
+ if arch == 'x86':
+ platform = 'Win32'
+ elif arch == 'x64':
+ platform = 'x64'
+
+ cwd = os.getcwd()
+
+ msbuild(platform, configuration, 'Build', name + '.sln', '', vs)
+
+
+def remove_timestamps(path):
+ try:
+ os.unlink(path + '.orig')
+ except OSError:
+ pass
+
+ os.rename(path, path + '.orig')
+
+ src = open(path + '.orig', 'r')
+ dst = open(path, 'w')
+
+ for line in src:
+ if line.find('TimeStamp') == -1:
+ dst.write(line)
+
+ dst.close()
+ src.close()
+
+def run_sdv(name, dir, vs):
+ release = { 'vs2012':'Windows 8',
+ 'vs2013':'Windows 8',
+ 'vs2015':'Windows 10' }
+
+ configuration = get_configuration(release[vs], False)
+ platform = 'x64'
+
+ msbuild(platform, configuration, 'Build', name + '.vcxproj',
+ '', os.path.join(vs, name))
+
+ msbuild(platform, configuration, 'sdv', name + '.vcxproj',
+ '/p:Inputs="/clean"', os.path.join(vs, name))
+
+ msbuild(platform, configuration, 'sdv', name + '.vcxproj',
+ '/p:Inputs="/check:default.sdv"', os.path.join(vs, name))
+
+ path = [vs, name, 'sdv', 'SDV.DVL.xml']
+ remove_timestamps(os.path.join(*path))
+
+ msbuild(platform, configuration, 'dvl', name + '.vcxproj',
+ '', os.path.join(vs, name))
+
+ path = [vs, name, name + '.DVL.XML']
+ shutil.copy(os.path.join(*path), dir)
+
+ path = [vs, name, 'refine.sdv']
+ if os.path.isfile(os.path.join(*path)):
+ msbuild(platform, configuration, 'sdv', name + '.vcxproj',
+ '/p:Inputs=/refine', os.path.join(vs, name))
+
+
+def symstore_del(name, age):
+ symstore_path = [os.environ['KIT'], 'Debuggers']
+ if os.environ['PROCESSOR_ARCHITECTURE'] == 'x86':
+ symstore_path.append('x86')
+ else:
+ symstore_path.append('x64')
+ symstore_path.append('symstore.exe')
+
+ symstore = os.path.join(*symstore_path)
+
+ for id in get_expired_symbols(name, age):
+ command=['"' + symstore + '"']
+ command.append('del')
+ command.append('/i')
+ command.append(str(id))
+ command.append('/s')
+ command.append(os.environ['SYMBOL_SERVER'])
+
+ shell(command, None)
+
+
+def symstore_add(name, release, arch, debug, vs):
+ target_path = get_target_path(release, arch, debug, vs)
+
+ symstore_path = [os.environ['KIT'], 'Debuggers']
+ if os.environ['PROCESSOR_ARCHITECTURE'] == 'x86':
+ symstore_path.append('x86')
+ else:
+ symstore_path.append('x64')
+ symstore_path.append('symstore.exe')
+
+ symstore = os.path.join(*symstore_path)
+
+ version = '.'.join([os.environ['MAJOR_VERSION'],
+ os.environ['MINOR_VERSION'],
+ os.environ['MICRO_VERSION'],
+ os.environ['BUILD_NUMBER']])
+
+ command=['"' + symstore + '"']
+ command.append('add')
+ command.append('/s')
+ command.append(os.environ['SYMBOL_SERVER'])
+ command.append('/r')
+ command.append('/f')
+ command.append('*.pdb')
+ command.append('/t')
+ command.append(name)
+ command.append('/v')
+ command.append(version)
+
+ shell(command, target_path)
+
+
+def manifest():
+ cmd = ['git', 'ls-tree', '-r', '--name-only', 'HEAD']
+
+ sub = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ output = sub.communicate()[0]
+ ret = sub.returncode
+
+ if ret != 0:
+ raise(Exception("Error %d in : %s" % (ret, cmd)))
+
+ return output.decode('utf-8')
+
+
+def archive(filename, files, tgz=False):
+ access='w'
+ if tgz:
+ access='w:gz'
+ tar = tarfile.open(filename, access)
+ for name in files :
+ try:
+ tar.add(name)
+ except:
+ pass
+ tar.close()
+
+
+def getVsVersion():
+ vsenv ={}
+ vars = subprocess.check_output([os.environ['VS']+'\\VC\\vcvarsall.bat',
+ '&&', 'set'],
+ shell=True)
+ for var in vars.splitlines():
+ k, _, v = map(str.strip, var.strip().decode('utf-8').partition('='))
+ if k.startswith('?'):
+ continue
+ vsenv[k] = v
+
+ mapping = { '11.0':'vs2012',
+ '12.0':'vs2013',
+ '14.0':'vs2015' }
+
+ return mapping[vsenv['VisualStudioVersion']]
+
+
+if __name__ == '__main__':
+ debug = { 'checked': True, 'free': False }
+ sdv = { 'nosdv': False, None: True }
+ driver = 'xenvkbd'
+ vs = getVsVersion()
+
+ if 'VENDOR_NAME' not in os.environ.keys():
+ os.environ['VENDOR_NAME'] = 'Xen Project'
+
+ if 'VENDOR_PREFIX' not in os.environ.keys():
+ os.environ['VENDOR_PREFIX'] = 'XP'
+
+ if 'PRODUCT_NAME' not in os.environ.keys():
+ os.environ['PRODUCT_NAME'] = 'Xen'
+
+ os.environ['MAJOR_VERSION'] = '9'
+ os.environ['MINOR_VERSION'] = '0'
+ os.environ['MICRO_VERSION'] = '0'
+
+ if 'BUILD_NUMBER' not in os.environ.keys():
+ os.environ['BUILD_NUMBER'] = next_build_number()
+
+ if 'GIT_REVISION' in os.environ.keys():
+ revision = open('revision', 'w')
+ print(os.environ['GIT_REVISION'], file=revision)
+ revision.close()
+
+ print("VENDOR_NAME\t\t'%s'" % os.environ['VENDOR_NAME'])
+ print("VENDOR_PREFIX\t\t'%s'" % os.environ['VENDOR_PREFIX'])
+ print("PRODUCT_NAME\t\t'%s'" % os.environ['PRODUCT_NAME'])
+ print("MAJOR_VERSION\t\t%s" % os.environ['MAJOR_VERSION'])
+ print("MINOR_VERSION\t\t%s" % os.environ['MINOR_VERSION'])
+ print("MICRO_VERSION\t\t%s" % os.environ['MICRO_VERSION'])
+ print("BUILD_NUMBER\t\t%s" % os.environ['BUILD_NUMBER'])
+ print()
+
+ make_header()
+ copy_inf(vs, driver)
+
+ symstore_del(driver, 30)
+
+ release = { 'vs2012':'Windows Vista',
+ 'vs2013':'Windows 7',
+ 'vs2015':'Windows 8' }
+
+ build_sln(driver, release[vs], 'x86', debug[sys.argv[1]], vs)
+ build_sln(driver, release[vs], 'x64', debug[sys.argv[1]], vs)
+
+ symstore_add(driver, release[vs], 'x86', debug[sys.argv[1]], vs)
+ symstore_add(driver, release[vs], 'x64', debug[sys.argv[1]], vs)
+
+ if len(sys.argv) <= 2 or sdv[sys.argv[2]]:
+ run_sdv('xenvkbd', driver, vs)
+
+ archive(driver + '\\source.tgz', manifest().splitlines(), tgz=True)
+ archive(driver + '.tar', [driver,'revision'])
+
--- /dev/null
+#!/usr/bin/env python
+
+import os, sys, shutil
+
+if __name__ == '__main__':
+ file = os.popen('git status -u --porcelain')
+
+ for line in file:
+ item = line.split(' ')
+ if item[0] == '??':
+ path = ' '.join(item[1:]).rstrip()
+ print(path)
+ try:
+ if os.path.isfile(path):
+ os.remove(path)
+ if os.path.isdir(path):
+ shutil.rmtree(path)
+ except OSError:
+ None
+
+ file.close()
--- /dev/null
+#!python -u
+
+import os, sys
+import shutil
+import subprocess
+import re
+
+def shell(command, dir = '.'):
+ print("in '%s' execute '%s'" % (dir, ' '.join(command)))
+ sys.stdout.flush()
+
+ sub = subprocess.Popen(' '.join(command), cwd=dir,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ for line in sub.stdout:
+ print(line.decode(sys.getdefaultencoding()).rstrip())
+
+ sub.wait()
+
+ return sub.returncode
+
+def get_repo(url, working):
+ shell(['git', 'clone', '--no-checkout', url, working])
+
+def get_branch(tag, working):
+ shell(['git', 'checkout', '-b', 'tmp', tag], working)
+
+def put_branch(working):
+ shell(['git', 'checkout', 'master'], working)
+ shell(['git', 'branch', '-d', 'tmp'], working)
+
+def copy_file(working, dir, name):
+ try:
+ os.makedirs('include\\xen\\%s' % dir)
+ except OSError:
+ None
+
+ src = open('%s\\xen\\include\\%s\\%s' % (working, dir, name), 'r')
+ dst = open('include\\xen\\%s\\%s' % (dir, name), 'w', newline='\n')
+
+ print(name)
+
+ for line in src:
+ line = re.sub(' unsigned long', ' ULONG_PTR', line)
+ line = re.sub('\(unsigned long', '(ULONG_PTR', line)
+ line = re.sub(' long', ' LONG_PTR', line)
+ line = re.sub('\(long', '(LONG_PTR', line)
+ dst.write(line)
+
+ dst.close()
+ src.close()
+
+if __name__ == '__main__':
+ tag = sys.argv[1]
+ working = sys.argv[2]
+
+ get_repo('git://xenbits.xen.org/xen.git', working)
+ get_branch(tag, working)
+
+ shell(['git', 'rm', '-r', '-f', 'xen'], 'include')
+
+ copy_file(working, 'public', 'xen.h')
+ copy_file(working, 'public', 'xen-compat.h')
+ copy_file(working, 'public', 'trace.h')
+ copy_file(working, 'public', 'grant_table.h')
+ copy_file(working, 'public', 'errno.h')
+
+ copy_file(working, 'xen', 'errno.h')
+
+ copy_file(working, 'public\\arch-x86', 'xen.h')
+ copy_file(working, 'public\\arch-x86', 'xen-x86_32.h')
+ copy_file(working, 'public\\arch-x86', 'xen-x86_64.h')
+
+ copy_file(working, 'public\\io', 'ring.h')
+ copy_file(working, 'public\\io', 'kbdif.h')
+ copy_file(working, 'public\\io', 'xenbus.h')
+
+ put_branch(working)
+
+ shell(['git', 'add', 'xen'], 'include')
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 cache_interface.h
+ \brief XENBUS CACHE Interface
+
+ This interface provides access to XENBUS's object cache
+ implementation.
+*/
+
+#ifndef _XENBUS_CACHE_INTERFACE_H
+#define _XENBUS_CACHE_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_CACHE
+ \brief Cache handle
+*/
+typedef struct _XENBUS_CACHE XENBUS_CACHE, *PXENBUS_CACHE;
+
+/*! \typedef XENBUS_CACHE_ACQUIRE
+ \brief Acquire a reference to the CACHE interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_CACHE_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_CACHE_RELEASE
+ \brief Release a reference to the CACHE interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_CACHE_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_CACHE_CTOR
+ \brief Object creator callback
+
+ \param Argument Context \a Argument supplied to \a XENBUS_CACHE_CREATE
+ \param Object Newly allocated object
+
+ This callback is invoked just after a new object is allocated and may
+ be used to initialize any object data prior to its insertion into the
+ cache.
+*/
+typedef NTSTATUS
+(*XENBUS_CACHE_CTOR)(
+ IN PVOID Argument,
+ IN PVOID Object
+ );
+
+/*! \typedef XENBUS_CACHE_DTOR
+ \brief Object destructor callback
+
+ \param Argument Context \a Argument supplied to \a XENBUS_CACHE_CREATE
+ \param Object Object about to be freed
+
+ This callback is invoked just after an object is removed from the
+ cache and before it is freed and may be used to tear down any object data.
+*/
+typedef VOID
+(*XENBUS_CACHE_DTOR)(
+ IN PVOID Argument,
+ IN PVOID Object
+ );
+
+/*! \typedef XENBUS_CACHE_ACQUIRE_LOCK
+ \brief Cache lock callback
+
+ \param Argument Context \a Argument supplied to \a XENBUS_CACHE_CREATE
+
+ This callback is invoked if the cache implementation requires mutual
+ exclusion.
+*/
+typedef VOID
+(*XENBUS_CACHE_ACQUIRE_LOCK)(
+ IN PVOID Argument
+ );
+
+/*! \typedef XENBUS_CACHE_RELEASE_LOCK
+ \brief Cache unlock callback
+
+ \param Argument Context \a Argument supplied to \a XENBUS_CACHE_CREATE
+
+ This callback is invoked to release the mutual exclusion lock acquired
+ by a previous invocation of \a XENBUS_CACHE_ACQUIRE_LOCK.
+*/
+typedef VOID
+(*XENBUS_CACHE_RELEASE_LOCK)(
+ IN PVOID Argument
+ );
+
+/*! \typedef XENBUS_CACHE_CREATE
+ \brief Create a cache of objects of the given \a Size
+
+ \param Interface The interface header
+ \param Name A name for the cache which will be used in debug output
+ \param Size The size of each object in bytes
+ \param Reservation The target minimum population of the cache
+ \param Ctor A callback which is invoked when a new object created
+ \param Dtor A callback which is invoked when an object is destroyed
+ \param AcquireLock A callback invoked to acquire a spinlock
+ \param ReleaseLock A callback invoked to release the spinlock
+ \param Argument An optional context argument passed to the callbacks
+ \param Cache A pointer to a cache handle to be initialized
+
+ If a non-zero \a Reservation is specified then this method will fail
+ unless that number of objects can be immediately created.
+*/
+typedef NTSTATUS
+(*XENBUS_CACHE_CREATE)(
+ IN PINTERFACE Interface,
+ IN const CHAR *Name,
+ IN ULONG Size,
+ IN ULONG Reservation,
+ IN XENBUS_CACHE_CTOR Ctor,
+ IN XENBUS_CACHE_DTOR Dtor,
+ IN XENBUS_CACHE_ACQUIRE_LOCK AcquireLock,
+ IN XENBUS_CACHE_RELEASE_LOCK ReleaseLock,
+ IN PVOID Argument OPTIONAL,
+ OUT PXENBUS_CACHE *Cache
+ );
+
+/*! \typedef XENBUS_CACHE_GET
+ \brief Get an object from a \a Cache
+
+ \param Interface The interface header
+ \param Cache The cache handle
+ \param Locked If mutually exclusive access to the cache is already
+ guaranteed then set this to TRUE
+*/
+typedef PVOID
+(*XENBUS_CACHE_GET)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_CACHE Cache,
+ IN BOOLEAN Locked
+ );
+
+/*! \typedef XENBUS_CACHE_PUT
+ \brief Return an object to a \a Cache
+
+ \param Interface The interface header
+ \param Cache The cache handle
+ \param Locked If mutually exclusive access to the cache is already
+ guaranteed then set this to TRUE
+*/
+typedef VOID
+(*XENBUS_CACHE_PUT)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_CACHE Cache,
+ IN PVOID Object,
+ IN BOOLEAN Locked
+ );
+
+/*! \typedef XENBUS_CACHE_DESTROY
+ \brief Destroy a \a Cache
+
+ \param Interface The interface header
+ \param Cache The cache handle
+
+ All objects must have been returned to the cache prior to destruction
+*/
+typedef VOID
+(*XENBUS_CACHE_DESTROY)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_CACHE Cache
+ );
+
+// {A98DFD78-416A-4949-92A5-E084F2F4B44E}
+DEFINE_GUID(GUID_XENBUS_CACHE_INTERFACE,
+0xa98dfd78, 0x416a, 0x4949, 0x92, 0xa5, 0xe0, 0x84, 0xf2, 0xf4, 0xb4, 0x4e);
+
+/*! \struct _XENBUS_CACHE_INTERFACE_V1
+ \brief CACHE interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_CACHE_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_CACHE_ACQUIRE CacheAcquire;
+ XENBUS_CACHE_RELEASE CacheRelease;
+ XENBUS_CACHE_CREATE CacheCreate;
+ XENBUS_CACHE_GET CacheGet;
+ XENBUS_CACHE_PUT CachePut;
+ XENBUS_CACHE_DESTROY CacheDestroy;
+};
+
+typedef struct _XENBUS_CACHE_INTERFACE_V1 XENBUS_CACHE_INTERFACE, *PXENBUS_CACHE_INTERFACE;
+
+/*! \def XENBUS_CACHE
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_CACHE(_Method, _Interface, ...) \
+ (_Interface)->Cache ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_CACHE_INTERFACE_VERSION_MIN 1
+#define XENBUS_CACHE_INTERFACE_VERSION_MAX 1
+
+#endif // _XENBUS_CACHE_INTERFACE_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 debug_interface.h
+ \brief XENBUS DEBUG Interface
+
+ This interface provides to register and invoke debug callbacks
+*/
+
+#ifndef _XENBUS_DEBUG_INTERFACE_H
+#define _XENBUS_DEBUG_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_DEBUG_CALLBACK
+ \brief Debug callback handle
+*/
+typedef struct _XENBUS_DEBUG_CALLBACK XENBUS_DEBUG_CALLBACK, *PXENBUS_DEBUG_CALLBACK;
+
+/*! \typedef XENBUS_DEBUG_ACQUIRE
+ \brief Acquire a reference to the DEBUG interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_DEBUG_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_DEBUG_RELEASE
+ \brief Release a reference to the DEBUG interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_DEBUG_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_DEBUG_FUNCTION
+ \brief Debug callback function
+
+ \param Argument Context \a Argument supplied to \a XENBUS_DEBUG_REGISTER
+ \param Crashing This is set to TRUE if the function is invoked as
+ part of pre-crash logging
+
+ Debug callback functions are always invoked with IRQL == HIGH_LEVEL
+*/
+typedef VOID
+(*XENBUS_DEBUG_FUNCTION)(
+ IN PVOID Argument,
+ IN BOOLEAN Crashing
+ );
+
+/*! \typedef XENBUS_DEBUG_REGISTER
+ \brief Register a debug callback function
+
+ \param Interface The interface header
+ \param Prefix A prefix applied to each line logged by \a XENBUS_DEBUG_PRINTF
+ \param Function The callback function
+ \param Argument An optional context argument passed to the callback
+ \param Callback A pointer to a callback handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_DEBUG_REGISTER)(
+ IN PINTERFACE Interface,
+ IN PCHAR Prefix,
+ IN XENBUS_DEBUG_FUNCTION Function,
+ IN PVOID Argument OPTIONAL,
+ OUT PXENBUS_DEBUG_CALLBACK *Callback
+ );
+
+/*! \typedef XENBUS_DEBUG_PRINTF
+ \brief Print a debug message in to the log
+
+ \param Interface The interface header
+ \param Format A format specifier
+ \param ... Additional parameters required by \a Format
+
+ This method must only be invoked from the context of a debug
+ callback
+*/
+typedef VOID
+(*XENBUS_DEBUG_PRINTF)(
+ IN PINTERFACE Interface,
+ IN const CHAR *Format,
+ ...
+ );
+
+/*! \typedef XENBUS_DEBUG_DEREGISTER
+ \brief Deregister a debug callback function
+
+ \param Interface The interface header
+ \param Callback The callback handle
+*/
+typedef VOID
+(*XENBUS_DEBUG_DEREGISTER)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_DEBUG_CALLBACK Callback
+ );
+
+/*! \typedef XENBUS_DEBUG_TRIGGER
+ \brief Invoke debug callback functions
+
+ \param Interface The interface header
+ \param Callback Optional argument to restrict invocation to a singe
+ debug callback (NULL invokes all debug callbacks)
+*/
+typedef VOID
+(*XENBUS_DEBUG_TRIGGER)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_DEBUG_CALLBACK Callback OPTIONAL
+ );
+
+// {0DF600AE-6B20-4227-BF94-03DA9A26A114}
+DEFINE_GUID(GUID_XENBUS_DEBUG_INTERFACE,
+0xdf600ae, 0x6b20, 0x4227, 0xbf, 0x94, 0x3, 0xda, 0x9a, 0x26, 0xa1, 0x14);
+
+/*! \struct _XENBUS_DEBUG_INTERFACE_V1
+ \brief DEBUG interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_DEBUG_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_DEBUG_ACQUIRE DebugAcquire;
+ XENBUS_DEBUG_RELEASE DebugRelease;
+ XENBUS_DEBUG_REGISTER DebugRegister;
+ XENBUS_DEBUG_PRINTF DebugPrintf;
+ XENBUS_DEBUG_TRIGGER DebugTrigger;
+ XENBUS_DEBUG_DEREGISTER DebugDeregister;
+};
+
+typedef struct _XENBUS_DEBUG_INTERFACE_V1 XENBUS_DEBUG_INTERFACE, *PXENBUS_DEBUG_INTERFACE;
+
+/*! \def XENBUS_DEBUG
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_DEBUG(_Method, _Interface, ...) \
+ (_Interface)->Debug ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_DEBUG_INTERFACE_VERSION_MIN 1
+#define XENBUS_DEBUG_INTERFACE_VERSION_MAX 1
+
+#endif // _XENBUS_DEBUG_INTERFACE_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 evtchn_interface.h
+ \brief XENBUS EVTCHN Interface
+
+ This interface provides access to hypervisor event channels
+*/
+
+#ifndef _XENBUS_EVTCHN_INTERFACE_H
+#define _XENBUS_EVTCHN_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \enum _XENBUS_EVTCHN_TYPE
+ \brief Event channel type to be opened
+*/
+typedef enum _XENBUS_EVTCHN_TYPE {
+ XENBUS_EVTCHN_TYPE_INVALID = 0,
+ XENBUS_EVTCHN_TYPE_FIXED, /*!< Fixed */
+ XENBUS_EVTCHN_TYPE_UNBOUND, /*!< Unbound */
+ XENBUS_EVTCHN_TYPE_INTER_DOMAIN, /*!< Interdomain */
+ XENBUS_EVTCHN_TYPE_VIRQ /*!< VIRQ */
+} XENBUS_EVTCHN_TYPE, *PXENBUS_EVTCHN_TYPE;
+
+/*! \typedef XENBUS_EVTCHN_CHANNEL
+ \brief Event channel handle
+*/
+typedef struct _XENBUS_EVTCHN_CHANNEL XENBUS_EVTCHN_CHANNEL, *PXENBUS_EVTCHN_CHANNEL;
+
+/*! \typedef XENBUS_EVTCHN_ACQUIRE
+ \brief Acquire a reference to the EVTCHN interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_EVTCHN_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_EVTCHN_RELEASE
+ \brief Release a reference to the EVTCHN interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_EVTCHN_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_EVTCHN_OPEN
+ \brief Open an event channel
+
+ \param Interface The interface header
+ \param Type The type of event channel to open
+ \param Function The callback function
+ \param Argument An optional context argument passed to the callback
+ \param ... Additional parameters required by \a Type
+
+ \b Fixed:
+ \param LocalPort The local port number of the (already bound) channel
+ \param Mask Set to TRUE if the channel should be automatically masked before invoking the callback
+
+ \b Unbound:
+ \param RemoteDomain The domid of the remote domain which will bind the channel
+ \param Mask Set to TRUE if the channel should be automatically masked before invoking the callback
+
+ \b Interdomain:
+ \param RemoteDomain The domid of the remote domain which has already bound the channel
+ \param RemotePort The port number bound to the channel in the remote domain
+ \param Mask Set to TRUE if the channel should be automatically masked before invoking the callback
+
+ \b VIRQ:
+ \param Index The index number of the VIRQ
+
+ \return Event channel handle
+*/
+typedef PXENBUS_EVTCHN_CHANNEL
+(*XENBUS_EVTCHN_OPEN)(
+ IN PINTERFACE Interface,
+ IN XENBUS_EVTCHN_TYPE Type,
+ IN PKSERVICE_ROUTINE Function,
+ IN PVOID Argument OPTIONAL,
+ ...
+ );
+
+typedef NTSTATUS
+(*XENBUS_EVTCHN_BIND_V2)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel,
+ IN ULONG Cpu
+ );
+
+/*! \typedef XENBUS_EVTCHN_BIND
+ \brief Bind an event channel to a specific CPU
+
+ \param Interface The interface header
+ \param Channel The channel handle
+ \param Group The group number of the CPU that should handle events
+ \param Number The relative number of the CPU that should handle events
+*/
+typedef NTSTATUS
+(*XENBUS_EVTCHN_BIND)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel,
+ IN USHORT Group,
+ IN UCHAR Number
+ );
+
+typedef BOOLEAN
+(*XENBUS_EVTCHN_UNMASK_V1)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel,
+ IN BOOLEAN InCallback
+ );
+
+/*! \typedef XENBUS_EVTCHN_UNMASK
+ \brief Unmask an event channel
+
+ \param Interface The interface header
+ \param Channel The channel handle
+ \param InCallback Set to TRUE if this method is invoked in context of the channel callback
+*/
+typedef VOID
+(*XENBUS_EVTCHN_UNMASK)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel,
+ IN BOOLEAN InCallback
+ );
+
+/*! \typedef XENBUS_EVTCHN_SEND
+ \brief Send an event to the remote end of the channel
+
+ \param Interface The interface header
+ \param Channel The channel handle
+*/
+typedef VOID
+(*XENBUS_EVTCHN_SEND)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel
+ );
+
+/*! \typedef XENBUS_EVTCHN_TRIGGER
+ \brief Send an event to the local end of the channel
+
+ \param Interface The interface header
+ \param Channel The channel handle
+*/
+typedef VOID
+(*XENBUS_EVTCHN_TRIGGER)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel
+ );
+
+/*! \typedef XENBUS_EVTCHN_WAIT
+ \brief Wait for an event to the local end of the channel
+
+ \param Interface The interface header
+ \param Channel The channel handle
+ \param Timeout An optional timeout value (similar to KeWaitForSingleObject(), but non-zero values are allowed at DISPATCH_LEVEL).
+*/
+typedef NTSTATUS
+(*XENBUS_EVTCHN_WAIT)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel,
+ IN PLARGE_INTEGER Timeout OPTIONAL
+ );
+
+/*! \typedef XENBUS_EVTCHN_GET_PORT
+ \brief Get the local port number bound to the channel
+
+ \param Interface The interface header
+ \param Channel The channel handle
+ \return The port number
+*/
+typedef ULONG
+(*XENBUS_EVTCHN_GET_PORT)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel
+ );
+
+/*! \typedef XENBUS_EVTCHN_CLOSE
+ \brief Close an event channel
+
+ \param Interface The interface header
+ \param Channel The channel handle
+*/
+typedef VOID
+(*XENBUS_EVTCHN_CLOSE)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel
+ );
+
+// {BE2440AC-1098-4150-AF4D-452FADCEF923}
+DEFINE_GUID(GUID_XENBUS_EVTCHN_INTERFACE,
+0xbe2440ac, 0x1098, 0x4150, 0xaf, 0x4d, 0x45, 0x2f, 0xad, 0xce, 0xf9, 0x23);
+
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V1
+ \brief EVTCHN interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_EVTCHN_ACQUIRE EvtchnAcquire;
+ XENBUS_EVTCHN_RELEASE EvtchnRelease;
+ XENBUS_EVTCHN_OPEN EvtchnOpen;
+ XENBUS_EVTCHN_UNMASK_V1 EvtchnUnmaskVersion1;
+ XENBUS_EVTCHN_SEND EvtchnSend;
+ XENBUS_EVTCHN_TRIGGER EvtchnTrigger;
+ XENBUS_EVTCHN_GET_PORT EvtchnGetPort;
+ XENBUS_EVTCHN_CLOSE EvtchnClose;
+};
+
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V2
+ \brief EVTCHN interface version 2
+ \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V2 {
+ INTERFACE Interface;
+ XENBUS_EVTCHN_ACQUIRE EvtchnAcquire;
+ XENBUS_EVTCHN_RELEASE EvtchnRelease;
+ XENBUS_EVTCHN_OPEN EvtchnOpen;
+ XENBUS_EVTCHN_BIND_V2 EvtchnBindVersion2;
+ XENBUS_EVTCHN_UNMASK_V1 EvtchnUnmaskVersion1;
+ XENBUS_EVTCHN_SEND EvtchnSend;
+ XENBUS_EVTCHN_TRIGGER EvtchnTrigger;
+ XENBUS_EVTCHN_GET_PORT EvtchnGetPort;
+ XENBUS_EVTCHN_CLOSE EvtchnClose;
+};
+
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V3
+ \brief EVTCHN interface version 3
+ \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V3 {
+ INTERFACE Interface;
+ XENBUS_EVTCHN_ACQUIRE EvtchnAcquire;
+ XENBUS_EVTCHN_RELEASE EvtchnRelease;
+ XENBUS_EVTCHN_OPEN EvtchnOpen;
+ XENBUS_EVTCHN_BIND_V2 EvtchnBindVersion2;
+ XENBUS_EVTCHN_UNMASK EvtchnUnmask;
+ XENBUS_EVTCHN_SEND EvtchnSend;
+ XENBUS_EVTCHN_TRIGGER EvtchnTrigger;
+ XENBUS_EVTCHN_GET_PORT EvtchnGetPort;
+ XENBUS_EVTCHN_CLOSE EvtchnClose;
+};
+
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V4
+ \brief EVTCHN interface version 4
+ \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V4 {
+ INTERFACE Interface;
+ XENBUS_EVTCHN_ACQUIRE EvtchnAcquire;
+ XENBUS_EVTCHN_RELEASE EvtchnRelease;
+ XENBUS_EVTCHN_OPEN EvtchnOpen;
+ XENBUS_EVTCHN_BIND EvtchnBind;
+ XENBUS_EVTCHN_UNMASK EvtchnUnmask;
+ XENBUS_EVTCHN_SEND EvtchnSend;
+ XENBUS_EVTCHN_TRIGGER EvtchnTrigger;
+ XENBUS_EVTCHN_GET_PORT EvtchnGetPort;
+ XENBUS_EVTCHN_CLOSE EvtchnClose;
+};
+
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V5
+ \brief EVTCHN interface version 5
+ \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V5 {
+ INTERFACE Interface;
+ XENBUS_EVTCHN_ACQUIRE EvtchnAcquire;
+ XENBUS_EVTCHN_RELEASE EvtchnRelease;
+ XENBUS_EVTCHN_OPEN EvtchnOpen;
+ XENBUS_EVTCHN_BIND EvtchnBind;
+ XENBUS_EVTCHN_UNMASK EvtchnUnmask;
+ XENBUS_EVTCHN_SEND EvtchnSend;
+ XENBUS_EVTCHN_TRIGGER EvtchnTrigger;
+ XENBUS_EVTCHN_WAIT EvtchnWait;
+ XENBUS_EVTCHN_GET_PORT EvtchnGetPort;
+ XENBUS_EVTCHN_CLOSE EvtchnClose;
+};
+
+typedef struct _XENBUS_EVTCHN_INTERFACE_V5 XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVTCHN_INTERFACE;
+
+/*! \def XENBUS_EVTCHN
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_EVTCHN(_Method, _Interface, ...) \
+ (_Interface)->Evtchn ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_EVTCHN_INTERFACE_VERSION_MIN 1
+#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 5
+
+#endif // _XENBUS_EVTCHN_INTERFACE_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 gnttab_interface.h
+ \brief XENBUS GNTTAB Interface
+
+ This interface provides access to the hypervisor grant table
+*/
+
+#ifndef _XENBUS_GNTTAB_INTERFACE_H
+#define _XENBUS_GNTTAB_INTERFACE_H
+
+#include <cache_interface.h>
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_GNTTAB_ENTRY
+ \brief Grant table entry handle
+*/
+typedef struct _XENBUS_GNTTAB_ENTRY XENBUS_GNTTAB_ENTRY, *PXENBUS_GNTTAB_ENTRY;
+
+/*! \typedef XENBUS_GNTTAB_CACHE
+ \brief Grant table cache handle
+*/
+typedef struct _XENBUS_GNTTAB_CACHE XENBUS_GNTTAB_CACHE, *PXENBUS_GNTTAB_CACHE;
+
+/*! \typedef XENBUS_GNTTAB_ACQUIRE
+ \brief Acquire a reference to the GNTTAB interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_GNTTAB_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_GNTTAB_RELEASE
+ \brief Release a reference to the GNTTAB interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_GNTTAB_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_GNTTAB_CREATE_CACHE
+ \brief Create a cache of grant table entries
+
+ \param Interface The interface header
+ \param Name A name for the cache which will be used in debug output
+ \param Reservation The target minimum population of the cache
+ \param AcquireLock A callback invoked to acquire a spinlock
+ \param ReleaseLock A callback invoked to release the spinlock
+ \param Argument An optional context argument passed to the callbacks
+ \param Cache A pointer to a grant table cache handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_GNTTAB_CREATE_CACHE)(
+ IN PINTERFACE Interface,
+ IN const CHAR *Name,
+ IN ULONG Reservation,
+ IN XENBUS_CACHE_ACQUIRE_LOCK AcquireLock,
+ IN XENBUS_CACHE_RELEASE_LOCK ReleaseLock,
+ IN PVOID Argument OPTIONAL,
+ OUT PXENBUS_GNTTAB_CACHE *Cache
+ );
+
+/*! \typedef XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS
+ \brief Get a table entry from the \a Cache permitting access to a given \a Pfn
+
+ \param Interface The interface header
+ \param Cache The grant table cache handle
+ \param Locked If mutually exclusive access to the cache is already
+ guaranteed then set this to TRUE
+ \param Domain The domid of the domain being granted access
+ \param Pfn The frame number of the page that we are granting access to
+ \param ReadOnly Set to TRUE if the foreign domain is only being granted
+ read access
+ \param Entry A pointer to a grant table entry handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_GNTTAB_CACHE Cache,
+ IN BOOLEAN Locked,
+ IN USHORT Domain,
+ IN PFN_NUMBER Pfn,
+ IN BOOLEAN ReadOnly,
+ OUT PXENBUS_GNTTAB_ENTRY *Entry
+ );
+
+/*! \typedef XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS
+ \brief Revoke foreign access and return the \a Entry to the \a Cache
+
+ \param Interface The interface header
+ \param Cache The grant table cache handle
+ \param Locked If mutually exclusive access to the cache is already
+ guaranteed then set this to TRUE
+ \param Entry The grant table entry handle
+*/
+typedef NTSTATUS
+(*XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_GNTTAB_CACHE Cache,
+ IN BOOLEAN Locked,
+ IN PXENBUS_GNTTAB_ENTRY Entry
+ );
+
+/*! \typedef XENBUS_GNTTAB_GET_REFERENCE
+ \brief Get the reference number of the entry
+
+ \param Interface The interface header
+ \param Entry The grant table entry handle
+ \return The reference number
+*/
+typedef ULONG
+(*XENBUS_GNTTAB_GET_REFERENCE)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_GNTTAB_ENTRY Entry
+ );
+
+/*! \typedef XENBUS_GNTTAB_DESTROY_CACHE
+ \brief Destroy a cache of grant table entries
+
+ \param Interface The interface header
+ \param Cache The grant table cache handle
+
+ All grant table entries must have been revoked prior to destruction
+ of the cache
+*/
+typedef VOID
+(*XENBUS_GNTTAB_DESTROY_CACHE)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_GNTTAB_CACHE Cache
+ );
+
+// {763679C5-E5C2-4A6D-8B88-6BB02EC42D8E}
+DEFINE_GUID(GUID_XENBUS_GNTTAB_INTERFACE,
+0x763679c5, 0xe5c2, 0x4a6d, 0x8b, 0x88, 0x6b, 0xb0, 0x2e, 0xc4, 0x2d, 0x8e);
+
+/*! \struct _XENBUS_GNTTAB_INTERFACE_V1
+ \brief GNTTAB interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_GNTTAB_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_GNTTAB_ACQUIRE GnttabAcquire;
+ XENBUS_GNTTAB_RELEASE GnttabRelease;
+ XENBUS_GNTTAB_CREATE_CACHE GnttabCreateCache;
+ XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS GnttabPermitForeignAccess;
+ XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS GnttabRevokeForeignAccess;
+ XENBUS_GNTTAB_GET_REFERENCE GnttabGetReference;
+ XENBUS_GNTTAB_DESTROY_CACHE GnttabDestroyCache;
+};
+
+typedef struct _XENBUS_GNTTAB_INTERFACE_V1 XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;
+
+/*! \def XENBUS_GNTTAB
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_GNTTAB(_Method, _Interface, ...) \
+ (_Interface)->Gnttab ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_GNTTAB_INTERFACE_VERSION_MIN 1
+#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 1
+
+#endif // _XENBUS_GNTTAB_INTERFACE_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 hid_interface.h
+ \brief XENHID HID Interface
+
+ This interface provides access to the PV network frontend
+*/
+
+#ifndef _XENHID_HID_INTERFACE_H
+#define _XENHID_HID_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENHID_HID_ACQUIRE
+ \brief Acquire a reference to the HID interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENHID_HID_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENHID_HID_RELEASE
+ \brief Release a reference to the HID interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENHID_HID_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENHID_HID_CALLBACK
+ \brief Provider to subscriber callback function
+
+ \param Argument An optional context argument passed to the callback
+ \param Buffer A HID report buffer to complete
+ \param Length The length of the \a Buffer
+*/
+typedef BOOLEAN
+(*XENHID_HID_CALLBACK)(
+ IN PVOID Argument OPTIONAL,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+/*! \typedef XENHID_HID_ENABLE
+ \brief Enable the HID interface
+
+ All packets queued for transmit will be rejected and no packets will
+ be queued for receive until this method completes.
+
+ \param Interface The interface header
+ \param Callback The subscriber's callback function
+ \param Argument An optional context argument passed to the callback
+*/
+typedef NTSTATUS
+(*XENHID_HID_ENABLE)(
+ IN PINTERFACE Interface,
+ IN XENHID_HID_CALLBACK Callback,
+ IN PVOID Argument OPTIONAL
+ );
+
+/*! \typedef XENHID_HID_DISABLE
+ \brief Disable the HID interface
+
+ This method will not complete until any packets queued for receive
+ have been returned. Any packets queued for transmit may be aborted.
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENHID_HID_DISABLE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENHID_HID_GET_DEVICE_ATTRIBUTES
+ \brief Get the HID Device Attributes structure
+
+*/
+typedef NTSTATUS
+(*XENHID_HID_GET_DEVICE_ATTRIBUTES)(
+ IN PINTERFACE Interface,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ );
+
+/*! \typedef XENHID_HID_GET_DEVICE_DESCRIPTOR
+ \brief Get the HID Device Descriptor structure
+
+ \param Interface The interface header
+ \param Buffer The buffer to fill
+ \param Length The length of the buffer
+ \param Returned The number of bytes returned
+*/
+typedef NTSTATUS
+(*XENHID_HID_GET_DEVICE_DESCRIPTOR)(
+ IN PINTERFACE Interface,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ );
+
+/*! \typedef XENHID_HID_GET_REPORT_DESCRIPTOR
+ \brief Get the HID Report Descriptor structure
+
+ \param Interface The interface header
+ \param Buffer The buffer to fill
+ \param Length The length of the buffer
+ \param Returned The number of bytes returned
+*/
+typedef NTSTATUS
+(*XENHID_HID_GET_REPORT_DESCRIPTOR)(
+ IN PINTERFACE Interface,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ );
+
+/*! \typedef XENHID_HID_GET_STRING
+ \brief Get the HID Device Descriptor structure
+
+ \param Interface The interface header
+ \param Identifier The string identifier
+ \param Buffer The buffer to fill
+ \param Length The length of the buffer
+ \param Returned The number of bytes returned
+*/
+typedef NTSTATUS
+(*XENHID_HID_GET_STRING)(
+ IN PINTERFACE Interface,
+ IN ULONG Identifier,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ );
+
+/*! \typedef XENHID_HID_GET_INDEXED_STRING
+ \brief Set the HID Device Descriptor structure
+
+ \param Interface The interface header
+ \param Index The index of the string
+ \param Buffer The buffer to fill
+ \param Length The length of the buffer
+ \param Returned The number of bytes returned
+*/
+typedef NTSTATUS
+(*XENHID_HID_GET_INDEXED_STRING)(
+ IN PINTERFACE Interface,
+ IN ULONG Index,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ );
+
+/*! \typedef XENHID_HID_GET_FEATURE
+ \brief Get the feature
+
+ \param Interface The interface header
+ \param ReportId The report id to set
+ \param Buffer The report buffer
+ \param Length The length of the buffer
+ \param Returned The number of bytes returned
+*/
+typedef NTSTATUS
+(*XENHID_HID_GET_FEATURE)(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ );
+
+/*! \typedef XENHID_HID_SET_FEATURE
+ \brief Set the feature report
+
+ \param Interface The interface header
+ \param ReportId The report id to set
+ \param Buffer The report buffer
+ \param Length The length of the buffer
+*/
+typedef NTSTATUS
+(*XENHID_HID_SET_FEATURE)(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+/*! \typedef XENHID_HID_GET_INPUT_REPORT
+ \brief Get the input report
+
+ \param Interface The interface header
+ \param ReportId The report id to set
+ \param Buffer The report buffer
+ \param Length The length of the buffer
+ \param Returned The number of bytes returned
+*/
+typedef NTSTATUS
+(*XENHID_HID_GET_INPUT_REPORT)(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ );
+
+/*! \typedef XENHID_HID_SET_OUTPUT_REPORT
+ \brief Set the output report
+
+ \param Interface The interface header
+ \param ReportId The report id to set
+ \param Buffer The write report buffer
+ \param Length The length of the buffer
+*/
+typedef NTSTATUS
+(*XENHID_HID_SET_OUTPUT_REPORT)(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+/*! \typedef XENHID_HID_READ_REPORT
+ \brief Checks to see if any pending read reports
+ need completing. A single read report will be
+ completed by calling the callback
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENHID_HID_READ_REPORT)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENHID_HID_WRITE_REPORT
+ \brief Set the output report
+
+ \param Interface The interface header
+ \param ReportId The report id to set
+ \param Buffer The write report buffer
+ \param Length The length of the buffer
+*/
+typedef NTSTATUS
+(*XENHID_HID_WRITE_REPORT)(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+// {D215E1B5-8C38-420A-AEA6-02520DF3A621}\r
+DEFINE_GUID(GUID_XENHID_HID_INTERFACE,\r
+0xd215e1b5, 0x8c38, 0x420a, 0xae, 0xa6, 0x2, 0x52, 0xd, 0xf3, 0xa6, 0x21);\r
+
+/*! \struct _XENHID_HID_INTERFACE_V1
+ \brief HID interface version 1
+ \ingroup interfaces
+*/
+struct _XENHID_HID_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENHID_HID_ACQUIRE Acquire;
+ XENHID_HID_RELEASE Release;
+ XENHID_HID_ENABLE Enable;
+ XENHID_HID_DISABLE Disable;
+ XENHID_HID_GET_DEVICE_ATTRIBUTES GetDeviceAttributes;
+ XENHID_HID_GET_DEVICE_DESCRIPTOR GetDeviceDescriptor;
+ XENHID_HID_GET_REPORT_DESCRIPTOR GetReportDescriptor;
+ XENHID_HID_GET_STRING GetString;
+ XENHID_HID_GET_INDEXED_STRING GetIndexedString;
+ XENHID_HID_GET_FEATURE GetFeature;
+ XENHID_HID_SET_FEATURE SetFeature;
+ XENHID_HID_GET_INPUT_REPORT GetInputReport;
+ XENHID_HID_SET_OUTPUT_REPORT SetOutputReport;
+ XENHID_HID_READ_REPORT ReadReport;
+ XENHID_HID_WRITE_REPORT WriteReport;
+};
+
+typedef struct _XENHID_HID_INTERFACE_V1 XENHID_HID_INTERFACE, *PXENHID_HID_INTERFACE;
+
+/*! \def XENHID_HID
+ \brief Macro at assist in method invocation
+*/
+#define XENHID_HID(_Method, _Interface, ...) \
+ (_Interface)-> ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENHID_HID_INTERFACE_VERSION_MIN 1
+#define XENHID_HID_INTERFACE_VERSION_MAX 1
+
+#endif // _XENHID_INTERFACE_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 range_set_interface.h
+ \brief XENBUS RANGE_SET Interface
+
+ This interface provides access to XENBUS's range-set
+ implementation.
+*/
+
+#ifndef _XENBUS_RANGE_SET_INTERFACE_H
+#define _XENBUS_RANGE_SET_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_RANGE_SET
+ \brief Range-set handle
+*/
+typedef struct _XENBUS_RANGE_SET XENBUS_RANGE_SET, *PXENBUS_RANGE_SET;
+
+/*! \typedef XENBUS_RANGE_SET_ACQUIRE
+ \brief Acquire a reference to the RANGE_SET interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_RANGE_SET_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_RANGE_SET_RELEASE
+ \brief Release a reference to the RANGE_SET interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_RANGE_SET_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_RANGE_SET_CREATE
+ \brief Create a new empty range-set
+
+ \param Interface The interface header
+ \param Name A name for the ramge-set which will be used in debug output
+ \param RangeSet A pointer to a range-set handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_RANGE_SET_CREATE)(
+ IN PINTERFACE Interface,
+ IN const CHAR *Name,
+ OUT PXENBUS_RANGE_SET *RangeSet
+ );
+
+/*! \typedef XENBUS_RANGE_SET_PUT
+ \brief Put a range into a range-set
+
+ \param Interface The interface header
+ \param RangeSet The range-set handle
+ \param Start The base of the range
+ \param Count The number of items of the range
+*/
+typedef NTSTATUS
+(*XENBUS_RANGE_SET_PUT)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_RANGE_SET RangeSet,
+ IN LONGLONG Start,
+ IN ULONGLONG Count
+ );
+
+/*! \typedef XENBUS_RANGE_SET_POP
+ \brief Pop a range out of a range-set
+
+ \param Interface The interface header
+ \param RangeSet The range-set handle
+ \param Count The number of items required
+ \param Start A pointer to a value which will be set to the base of
+ a suitable range
+*/
+typedef NTSTATUS
+(*XENBUS_RANGE_SET_POP)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_RANGE_SET RangeSet,
+ IN ULONGLONG Count,
+ OUT PLONGLONG Start
+ );
+
+/*! \typedef XENBUS_RANGE_SET_GET
+ \brief Get a specific range out of a range-set
+
+ \param Interface The interface header
+ \param RangeSet The range-set handle
+ \param Start The base of the range
+ \param Count The number of items in the range
+*/
+typedef NTSTATUS
+(*XENBUS_RANGE_SET_GET)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_RANGE_SET RangeSet,
+ IN LONGLONG Start,
+ IN ULONGLONG Count
+ );
+
+/*! \typedef XENBUS_RANGE_SET_DESTROY
+ \brief Destroy a range-set
+
+ \param Interface The interface header
+ \param RangeSet The range-set handle
+
+ The range-set must be empty when it is destroyed
+*/
+typedef VOID
+(*XENBUS_RANGE_SET_DESTROY)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_RANGE_SET RangeSet
+ );
+
+// {EE7E78A2-6847-48C5-B123-BB012F0EABF4}
+DEFINE_GUID(GUID_XENBUS_RANGE_SET_INTERFACE,
+0xee7e78a2, 0x6847, 0x48c5, 0xb1, 0x23, 0xbb, 0x1, 0x2f, 0xe, 0xab, 0xf4);
+
+/*! \struct _XENBUS_RANGE_SET_INTERFACE_V1
+ \brief RANGE_SET interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_RANGE_SET_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_RANGE_SET_ACQUIRE RangeSetAcquire;
+ XENBUS_RANGE_SET_RELEASE RangeSetRelease;
+ XENBUS_RANGE_SET_CREATE RangeSetCreate;
+ XENBUS_RANGE_SET_PUT RangeSetPut;
+ XENBUS_RANGE_SET_POP RangeSetPop;
+ XENBUS_RANGE_SET_GET RangeSetGet;
+ XENBUS_RANGE_SET_DESTROY RangeSetDestroy;
+};
+
+typedef struct _XENBUS_RANGE_SET_INTERFACE_V1 XENBUS_RANGE_SET_INTERFACE, *PXENBUS_RANGE_SET_INTERFACE;
+
+/*! \def XENBUS_RANGE_SET
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_RANGE_SET(_Method, _Interface, ...) \
+ (_Interface)->RangeSet ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_RANGE_SET_INTERFACE_VERSION_MIN 1
+#define XENBUS_RANGE_SET_INTERFACE_VERSION_MAX 1
+
+#endif // _XENBUS_RANGE_SET_INTERFACE_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _REVISION_H
+#define _REVISION_H
+
+// Key:
+// H - XENHID_HID_INTERFACE
+
+// REVISION H
+#define DEFINE_REVISION_TABLE \
+ DEFINE_REVISION(0x0800000B, 1), \
+ DEFINE_REVISION(0x0800000C, 1), \
+ DEFINE_REVISION(0x0800000D, 1), \
+ DEFINE_REVISION(0x09000000, 1)
+
+#endif // _REVISION_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 store_interface.h
+ \brief XENBUS STORE Interface
+
+ This interface provides access to XenStore
+*/
+
+#ifndef _XENBUS_STORE_INTERFACE_H
+#define _XENBUS_STORE_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_STORE_TRANSACTION
+ \brief XenStore transaction handle
+*/
+typedef struct _XENBUS_STORE_TRANSACTION XENBUS_STORE_TRANSACTION, *PXENBUS_STORE_TRANSACTION;
+
+/*! \typedef XENBUS_STORE_WATCH
+ \brief XenStore watch handle
+*/
+typedef struct _XENBUS_STORE_WATCH XENBUS_STORE_WATCH, *PXENBUS_STORE_WATCH;
+
+/*! \typedef XENBUS_STORE_PERMISSION_MASK
+ \brief Bitmask of XenStore key permissions
+*/
+typedef enum _XENBUS_STORE_PERMISSION_MASK {
+ XENBUS_STORE_PERM_NONE = 0,
+ XENBUS_STORE_PERM_READ = 1,
+ XENBUS_STORE_PERM_WRITE = 2,
+} XENBUS_STORE_PERMISSION_MASK;
+
+/*! \typedef XENBUS_STORE_PERMISSION
+ \brief XenStore key permissions entry for a single domain
+*/
+typedef struct _XENBUS_STORE_PERMISSION {
+ USHORT Domain;
+ XENBUS_STORE_PERMISSION_MASK Mask;
+} XENBUS_STORE_PERMISSION, *PXENBUS_STORE_PERMISSION;
+
+/*! \typedef XENBUS_STORE_ACQUIRE
+ \brief Acquire a reference to the STORE interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_STORE_RELEASE
+ \brief Release a reference to the STORE interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_STORE_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_STORE_FREE
+ \brief Free a memory buffer allocated by the STORE interface
+
+ \param Interface The interface header
+ \param Buffer Pointer to the memory buffer
+*/
+typedef VOID
+(*XENBUS_STORE_FREE)(
+ IN PINTERFACE Interface,
+ IN PCHAR Buffer
+ );
+
+/*! \typedef XENBUS_STORE_READ
+ \brief Read a value from XenStore
+
+ \param Interface The interface header
+ \param Transaction The transaction handle (NULL if this read is not
+ part of a transaction)
+ \param Prefix An optional prefix for the \a Node
+ \param Node The concatenation of the \a Prefix and this value specifies
+ the XenStore key to read
+ \param A pointer to a pointer that will be initialized with a memory
+ buffer containing the value read
+
+ The \a Buffer should be freed using \a XENBUS_STORE_FREE
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_READ)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL,
+ IN PCHAR Prefix OPTIONAL,
+ IN PCHAR Node,
+ OUT PCHAR *Buffer
+ );
+
+/*! \typedef XENBUS_STORE_PRINTF
+ \brief Write a value to XenStore
+
+ \param Interface The interface header
+ \param Transaction The transaction handle (NULL if this write is not
+ part of a transaction)
+ \param Prefix An optional prefix for the \a Node
+ \param Node The concatenation of the \a Prefix and this value specifies
+ the XenStore key to write
+ \param Format A format specifier
+ \param ... Additional parameters required by \a Format
+
+ If the \a Node does not exist then it is created
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_PRINTF)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL,
+ IN PCHAR Prefix OPTIONAL,
+ IN PCHAR Node,
+ IN const CHAR *Format,
+ ...
+ );
+
+/*! \typedef XENBUS_STORE_REMOVE
+ \brief Remove a key from XenStore
+
+ \param Interface The interface header
+ \param Transaction The transaction handle (NULL if this removal is not
+ part of a transaction)
+ \param Prefix An optional prefix for the \a Node
+ \param Node The concatenation of the \a Prefix and this value specifies
+ the XenStore key to remove
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_REMOVE)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL,
+ IN PCHAR Prefix OPTIONAL,
+ IN PCHAR Node
+ );
+
+/*! \typedef XENBUS_STORE_DIRECTORY
+ \brief Enumerate all immediate child keys of a XenStore key
+
+ \param Interface The interface header
+ \param Transaction The transaction handle (NULL if this removal is not
+ part of a transaction)
+ \param Prefix An optional prefix for the \a Node
+ \param Node The concatenation of the \a Prefix and this value specifies
+ the XenStore key to enumerate
+ \param A pointer to a pointer that will be initialized with a memory
+ buffer containing a NUL separated list of key names
+
+ The \a Buffer should be freed using \a XENBUS_STORE_FREE
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_DIRECTORY)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL,
+ IN PCHAR Prefix OPTIONAL,
+ IN PCHAR Node,
+ OUT PCHAR *Buffer
+ );
+
+/*! \typedef XENBUS_STORE_TRANSACTION_START
+ \brief Start a XenStore transaction
+
+ \param Interface The interface header
+ \param Transaction Pointer to a transaction handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_TRANSACTION_START)(
+ IN PINTERFACE Interface,
+ OUT PXENBUS_STORE_TRANSACTION *Transaction
+ );
+
+/*! \typedef XENBUS_STORE_TRANSACTION_END
+ \brief End a XenStore transaction
+
+ \param Interface The interface header
+ \param Transaction The transaction handle
+ \param Commit Set to TRUE if actions performed within the transaction should
+ be made visible, or FALSE if they should not be
+
+ If \a Commit is TRUE and the transaction to found to clash then
+ STATUS_RETRY will be returned
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_TRANSACTION_END)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_STORE_TRANSACTION Transaction,
+ IN BOOLEAN Commit
+ );
+
+/*! \typedef XENBUS_STORE_WATCH_ADD
+ \brief Add a XenStore watch
+
+ \param Interface The interface header
+ \param Prefix An optional prefix for the \a Node
+ \param Node The concatenation of the \a Prefix and this value specifies
+ the XenStore key to watch
+ \param Event A pointer to an event object to be signalled when the
+ watch fires
+ \param Watch A pointer to a watch handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_WATCH_ADD)(
+ IN PINTERFACE Interface,
+ IN PCHAR Prefix OPTIONAL,
+ IN PCHAR Node,
+ IN PKEVENT Event,
+ OUT PXENBUS_STORE_WATCH *Watch
+ );
+
+/*! \typedef XENBUS_STORE_WATCH_REMOVE
+ \brief Remove a XenStore watch
+
+ \param Interface The interface header
+ \param Watch The watch handle
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_WATCH_REMOVE)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_STORE_WATCH Watch
+ );
+
+/*! \typedef XENBUS_STORE_POLL
+ \brief Poll for XenStore activity
+
+ \param Interface The interface header
+
+ If it is necessary to spin at DISPATCH_LEVEL waiting for XenStore
+ activity then this will block the normal STORE interface DPC so this
+ method must be regularly invoked during the spin loop to check for
+ XenStore activity
+*/
+typedef VOID
+(*XENBUS_STORE_POLL)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_STORE_PERMISSIONS_SET
+ \brief Set permissions for a XenStore key
+
+ \param Interface The interface header
+ \param Transaction The transaction handle (NULL if this is not
+ part of a transaction)
+ \param Prefix An optional prefix for the \a Node
+ \param Node The concatenation of the \a Prefix and this value specifies
+ the XenStore key to set permissions of
+ \param Permissions An array of permissions to set
+ \param NumberPermissions Number of elements in the \a Permissions array
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_PERMISSIONS_SET)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL,
+ IN PCHAR Prefix OPTIONAL,
+ IN PCHAR Node,
+ IN PXENBUS_STORE_PERMISSION Permissions,
+ IN ULONG NumberPermissions
+ );
+
+// {86824C3B-D34E-4753-B281-2F1E3AD214D7}
+DEFINE_GUID(GUID_XENBUS_STORE_INTERFACE,
+0x86824c3b, 0xd34e, 0x4753, 0xb2, 0x81, 0x2f, 0x1e, 0x3a, 0xd2, 0x14, 0xd7);
+
+/*! \struct _XENBUS_STORE_INTERFACE_V1
+ \brief STORE interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_STORE_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_STORE_ACQUIRE StoreAcquire;
+ XENBUS_STORE_RELEASE StoreRelease;
+ XENBUS_STORE_FREE StoreFree;
+ XENBUS_STORE_READ StoreRead;
+ XENBUS_STORE_PRINTF StorePrintf;
+ XENBUS_STORE_REMOVE StoreRemove;
+ XENBUS_STORE_DIRECTORY StoreDirectory;
+ XENBUS_STORE_TRANSACTION_START StoreTransactionStart;
+ XENBUS_STORE_TRANSACTION_END StoreTransactionEnd;
+ XENBUS_STORE_WATCH_ADD StoreWatchAdd;
+ XENBUS_STORE_WATCH_REMOVE StoreWatchRemove;
+ XENBUS_STORE_POLL StorePoll;
+};
+
+/*! \struct _XENBUS_STORE_INTERFACE_V2
+ \brief STORE interface version 2
+ \ingroup interfaces
+*/
+struct _XENBUS_STORE_INTERFACE_V2 {
+ INTERFACE Interface;
+ XENBUS_STORE_ACQUIRE StoreAcquire;
+ XENBUS_STORE_RELEASE StoreRelease;
+ XENBUS_STORE_FREE StoreFree;
+ XENBUS_STORE_READ StoreRead;
+ XENBUS_STORE_PRINTF StorePrintf;
+ XENBUS_STORE_PERMISSIONS_SET StorePermissionsSet;
+ XENBUS_STORE_REMOVE StoreRemove;
+ XENBUS_STORE_DIRECTORY StoreDirectory;
+ XENBUS_STORE_TRANSACTION_START StoreTransactionStart;
+ XENBUS_STORE_TRANSACTION_END StoreTransactionEnd;
+ XENBUS_STORE_WATCH_ADD StoreWatchAdd;
+ XENBUS_STORE_WATCH_REMOVE StoreWatchRemove;
+ XENBUS_STORE_POLL StorePoll;
+};
+
+typedef struct _XENBUS_STORE_INTERFACE_V2 XENBUS_STORE_INTERFACE, *PXENBUS_STORE_INTERFACE;
+
+/*! \def XENBUS_STORE
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_STORE(_Method, _Interface, ...) \
+ (_Interface)->Store ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_STORE_INTERFACE_VERSION_MIN 1
+#define XENBUS_STORE_INTERFACE_VERSION_MAX 2
+
+#endif // _XENBUS_STORE_INTERFACE_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 suspend_interface.h
+ \brief XENBUS SUSPEND Interface
+
+ This interface provides primitives to handle VM suspend/resume
+*/
+
+#ifndef _XENBUS_SUSPEND_INTERFACE_H
+#define _XENBUS_SUSPEND_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \enum _XENBUS_SUSPEND_CALLBACK_TYPE
+ \brief Suspend callback type to be registered
+*/
+typedef enum _XENBUS_SUSPEND_CALLBACK_TYPE {
+ SUSPEND_CALLBACK_TYPE_INVALID = 0,
+ SUSPEND_CALLBACK_EARLY, /*!< Early */
+ SUSPEND_CALLBACK_LATE /*!< Late */
+} XENBUS_SUSPEND_CALLBACK_TYPE, *PXENBUS_SUSPEND_CALLBACK_TYPE;
+
+/*! \typedef XENBUS_SUSPEND_CALLBACK
+ \brief Suspend callback handle
+*/
+typedef struct _XENBUS_SUSPEND_CALLBACK XENBUS_SUSPEND_CALLBACK, *PXENBUS_SUSPEND_CALLBACK;
+
+/*! \typedef XENBUS_SUSPEND_ACQUIRE
+ \brief Acquire a reference to the SUSPEND interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_SUSPEND_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_SUSPEND_RELEASE
+ \brief Release a reference to the SUSPEND interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_SUSPEND_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_SUSPEND_FUNCTION
+ \brief Suspend callback function
+
+ \param Argument Context \a Argument supplied to \a XENBUS_SUSPEND_REGISTER
+
+ Suspend callback functions are always invoked on one vCPU with all other
+ vCPUs corralled at the same IRQL as the callback. \a Early callback
+ functions are always invoked with IRQL == HIGH_LEVEL and \a Late callback
+ functions are always invoked with IRQL == DISPATCH_LEVEL
+*/
+typedef VOID
+(*XENBUS_SUSPEND_FUNCTION)(
+ IN PVOID Argument
+ );
+
+/*! \typedef XENBUS_SUSPEND_REGISTER
+ \brief Register a suspend callback function
+
+ \param Interface The interface header
+ \param Type The type of callback function to register
+ \param Function The callback function
+ \param Argument An optional context argument passed to the callback
+ \param Callback A pointer to a callback handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_SUSPEND_REGISTER)(
+ IN PINTERFACE Interface,
+ IN XENBUS_SUSPEND_CALLBACK_TYPE Type,
+ IN XENBUS_SUSPEND_FUNCTION Function,
+ IN PVOID Argument OPTIONAL,
+ OUT PXENBUS_SUSPEND_CALLBACK *Callback
+ );
+
+/*! \typedef XENBUS_SUSPEND_DEREGISTER
+ \brief Deregister a suspend callback function
+
+ \param Interface The interface header
+ \param Callback The callback handle
+*/
+typedef VOID
+(*XENBUS_SUSPEND_DEREGISTER)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_SUSPEND_CALLBACK Callback
+ );
+
+/*! \typedef XENBUS_SUSPEND_TRIGGER
+ \brief Trigger a VM suspend
+
+ \param Interface The interface header
+
+ This method must always be invoked with IRQL == PASSIVE_LEVEL
+*/
+typedef NTSTATUS
+(*XENBUS_SUSPEND_TRIGGER)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_SUSPEND_GET_COUNT
+ \brief Get the number of VM suspends that have occurred since boot
+
+ \param Interface The interface header
+ \return The number of VM suspends
+*/
+typedef ULONG
+(*XENBUS_SUSPEND_GET_COUNT)(
+ IN PINTERFACE Interface
+ );
+
+// {0554F2AF-B510-4C71-AC03-1C503E394238}
+DEFINE_GUID(GUID_XENBUS_SUSPEND_INTERFACE,
+0x554f2af, 0xb510, 0x4c71, 0xac, 0x3, 0x1c, 0x50, 0x3e, 0x39, 0x42, 0x38);
+
+/*! \struct _XENBUS_SUSPEND_INTERFACE_V1
+ \brief SUSPEND interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_SUSPEND_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_SUSPEND_ACQUIRE Acquire;
+ XENBUS_SUSPEND_RELEASE Release;
+ XENBUS_SUSPEND_REGISTER Register;
+ XENBUS_SUSPEND_DEREGISTER Deregister;
+ XENBUS_SUSPEND_TRIGGER Trigger;
+ XENBUS_SUSPEND_GET_COUNT GetCount;
+};
+
+typedef struct _XENBUS_SUSPEND_INTERFACE_V1 XENBUS_SUSPEND_INTERFACE, *PXENBUS_SUSPEND_INTERFACE;
+
+/*! \def XENBUS_SUSPEND
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_SUSPEND(_Method, _Interface, ...) \
+ (_Interface)-> ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_SUSPEND_INTERFACE_VERSION_MIN 1
+#define XENBUS_SUSPEND_INTERFACE_VERSION_MAX 1
+
+#endif // _XENBUS_SUSPEND_INTERFACE_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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 unplug_interface.h
+ \brief XENBUS UNPLUG Interface
+
+ This interface provides a method to request emulated device unplug
+*/
+
+#ifndef _XENBUS_UNPLUG_INTERFACE_H
+#define _XENBUS_UNPLUG_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_UNPLUG_ACQUIRE
+ \brief Acquire a reference to the UNPLUG interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_UNPLUG_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_UNPLUG_RELEASE
+ \brief Release a reference to the UNPLUG interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_UNPLUG_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \enum _XENBUS_UNPLUG_DEVICE_TYPE
+ \brief Type of device to be unplugged
+*/
+typedef enum _XENBUS_UNPLUG_DEVICE_TYPE {
+ XENBUS_UNPLUG_DEVICE_TYPE_INVALID = 0,
+ XENBUS_UNPLUG_DEVICE_TYPE_NICS, /*!< NICs */
+ XENBUS_UNPLUG_DEVICE_TYPE_DISKS, /*!< Disks */
+} XENBUS_UNPLUG_DEVICE_TYPE, *PXENBUS_UNPLUG_DEVICE_TYPE;
+
+/*! \typedef XENBUS_UNPLUG_REQUEST
+ \brief Request unplug of a type of emulated device
+
+ \param Interface The interface header
+ \param Type The type of device
+ \param Make Set to TRUE if the request is being made, FALSE if it is
+ being revoked.
+*/
+typedef VOID
+(*XENBUS_UNPLUG_REQUEST)(
+ IN PINTERFACE Interface,
+ IN XENBUS_UNPLUG_DEVICE_TYPE Type,
+ IN BOOLEAN Make
+ );
+
+// {73db6517-3d06-4937-989f-199b7501e229}
+DEFINE_GUID(GUID_XENBUS_UNPLUG_INTERFACE,
+0x73db6517, 0x3d06, 0x4937, 0x98, 0x9f, 0x19, 0x9b, 0x75, 0x01, 0xe2, 0x29);
+
+/*! \struct _XENBUS_UNPLUG_INTERFACE_V1
+ \brief UNPLUG interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_UNPLUG_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_UNPLUG_ACQUIRE UnplugAcquire;
+ XENBUS_UNPLUG_RELEASE UnplugRelease;
+ XENBUS_UNPLUG_REQUEST UnplugRequest;
+};
+
+typedef struct _XENBUS_UNPLUG_INTERFACE_V1 XENBUS_UNPLUG_INTERFACE, *PXENBUS_UNPLUG_INTERFACE;
+
+/*! \def XENBUS_UNPLUG
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_UNPLUG(_Method, _Interface, ...) \
+ (_Interface)->Unplug ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_UNPLUG_INTERFACE_VERSION_MIN 1
+#define XENBUS_UNPLUG_INTERFACE_VERSION_MAX 1
+
+#endif // _XENBUS_UNPLUG_INTERFACE_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XEN_TYPES_H
+#define _XEN_TYPES_H
+
+#include <ntddk.h>
+
+// Define types necessary to include xen headers
+
+typedef CHAR int8_t;
+typedef SHORT int16_t;
+typedef LONG int32_t;
+typedef LONG64 int64_t;
+
+typedef UCHAR uint8_t;
+typedef USHORT uint16_t;
+typedef ULONG uint32_t;
+typedef ULONG64 uint64_t;
+
+#define offsetof(_type, _field) FIELD_OFFSET(_type, _field)
+
+#define xen_mb() KeMemoryBarrier()
+#define xen_wmb() KeMemoryBarrier()
+#define xen_rmb() KememoryBarrier()
+
+#endif // _XEN_TYPES_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XEN_VERSION_H
+#define _XEN_VERSION_H
+
+#define __XEN_INTERFACE_VERSION__ __XEN_LATEST_INTERFACE_VERSION__
+
+#endif // _XEN_VERSION_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XEN_WARNINGS_H
+#define _XEN_WARNINGS_H
+
+#include <ntddk.h>
+
+// Disable warnings necessary to include xen headers
+
+# pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
+# pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union
+
+#endif // _XEN_WARNINGS_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XEN_H
+#define _XEN_H
+
+#include <ntddk.h>
+
+#include <xen-version.h>
+#include <xen-types.h>
+#include <xen-warnings.h>
+
+#include <public/io/ring.h>
+#include <public/io/kbdif.h>
+#include <public/io/xenbus.h>
+
+#endif // _XEN_H
--- /dev/null
+/******************************************************************************
+ * xen-x86_32.h
+ *
+ * Guest OS interface to x86 32-bit Xen.
+ *
+ * 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.
+ *
+ * Copyright (c) 2004-2007, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__
+#define __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__
+
+/*
+ * Hypercall interface:
+ * Input: %ebx, %ecx, %edx, %esi, %edi, %ebp (arguments 1-6)
+ * Output: %eax
+ * Access is via hypercall page (set up by guest loader or via a Xen MSR):
+ * call hypercall_page + hypercall-number * 32
+ * Clobbered: Argument registers (e.g., 2-arg hypercall clobbers %ebx,%ecx)
+ */
+
+/*
+ * These flat segments are in the Xen-private section of every GDT. Since these
+ * are also present in the initial GDT, many OSes will be able to avoid
+ * installing their own GDT.
+ */
+#define FLAT_RING1_CS 0xe019 /* GDT index 259 */
+#define FLAT_RING1_DS 0xe021 /* GDT index 260 */
+#define FLAT_RING1_SS 0xe021 /* GDT index 260 */
+#define FLAT_RING3_CS 0xe02b /* GDT index 261 */
+#define FLAT_RING3_DS 0xe033 /* GDT index 262 */
+#define FLAT_RING3_SS 0xe033 /* GDT index 262 */
+
+#define FLAT_KERNEL_CS FLAT_RING1_CS
+#define FLAT_KERNEL_DS FLAT_RING1_DS
+#define FLAT_KERNEL_SS FLAT_RING1_SS
+#define FLAT_USER_CS FLAT_RING3_CS
+#define FLAT_USER_DS FLAT_RING3_DS
+#define FLAT_USER_SS FLAT_RING3_SS
+
+#define __HYPERVISOR_VIRT_START_PAE 0xF5800000
+#define __MACH2PHYS_VIRT_START_PAE 0xF5800000
+#define __MACH2PHYS_VIRT_END_PAE 0xF6800000
+#define HYPERVISOR_VIRT_START_PAE xen_mk_ulong(__HYPERVISOR_VIRT_START_PAE)
+#define MACH2PHYS_VIRT_START_PAE xen_mk_ulong(__MACH2PHYS_VIRT_START_PAE)
+#define MACH2PHYS_VIRT_END_PAE xen_mk_ulong(__MACH2PHYS_VIRT_END_PAE)
+
+/* Non-PAE bounds are obsolete. */
+#define __HYPERVISOR_VIRT_START_NONPAE 0xFC000000
+#define __MACH2PHYS_VIRT_START_NONPAE 0xFC000000
+#define __MACH2PHYS_VIRT_END_NONPAE 0xFC400000
+#define HYPERVISOR_VIRT_START_NONPAE \
+ xen_mk_ulong(__HYPERVISOR_VIRT_START_NONPAE)
+#define MACH2PHYS_VIRT_START_NONPAE \
+ xen_mk_ulong(__MACH2PHYS_VIRT_START_NONPAE)
+#define MACH2PHYS_VIRT_END_NONPAE \
+ xen_mk_ulong(__MACH2PHYS_VIRT_END_NONPAE)
+
+#define __HYPERVISOR_VIRT_START __HYPERVISOR_VIRT_START_PAE
+#define __MACH2PHYS_VIRT_START __MACH2PHYS_VIRT_START_PAE
+#define __MACH2PHYS_VIRT_END __MACH2PHYS_VIRT_END_PAE
+
+#ifndef HYPERVISOR_VIRT_START
+#define HYPERVISOR_VIRT_START xen_mk_ulong(__HYPERVISOR_VIRT_START)
+#endif
+
+#define MACH2PHYS_VIRT_START xen_mk_ulong(__MACH2PHYS_VIRT_START)
+#define MACH2PHYS_VIRT_END xen_mk_ulong(__MACH2PHYS_VIRT_END)
+#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>2)
+#ifndef machine_to_phys_mapping
+#define machine_to_phys_mapping ((ULONG_PTR *)MACH2PHYS_VIRT_START)
+#endif
+
+/* 32-/64-bit invariability for control interfaces (domctl/sysctl). */
+#if defined(__XEN__) || defined(__XEN_TOOLS__)
+#undef ___DEFINE_XEN_GUEST_HANDLE
+#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \
+ typedef struct { type *p; } \
+ __guest_handle_ ## name; \
+ typedef struct { union { type *p; uint64_aligned_t q; }; } \
+ __guest_handle_64_ ## name
+#undef set_xen_guest_handle_raw
+#define set_xen_guest_handle_raw(hnd, val) \
+ do { if ( sizeof(hnd) == 8 ) *(uint64_t *)&(hnd) = 0; \
+ (hnd).p = val; \
+ } while ( 0 )
+#define int64_aligned_t int64_t __attribute__((aligned(8)))
+#define uint64_aligned_t uint64_t __attribute__((aligned(8)))
+#define __XEN_GUEST_HANDLE_64(name) __guest_handle_64_ ## name
+#define XEN_GUEST_HANDLE_64(name) __XEN_GUEST_HANDLE_64(name)
+#endif
+
+#ifndef __ASSEMBLY__
+
+struct cpu_user_regs {
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t eax;
+ uint16_t error_code; /* private */
+ uint16_t entry_vector; /* private */
+ uint32_t eip;
+ uint16_t cs;
+ uint8_t saved_upcall_mask;
+ uint8_t _pad0;
+ uint32_t eflags; /* eflags.IF == !saved_upcall_mask */
+ uint32_t esp;
+ uint16_t ss, _pad1;
+ uint16_t es, _pad2;
+ uint16_t ds, _pad3;
+ uint16_t fs, _pad4;
+ uint16_t gs, _pad5;
+};
+typedef struct cpu_user_regs cpu_user_regs_t;
+DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t);
+
+/*
+ * Page-directory addresses above 4GB do not fit into architectural %cr3.
+ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
+ * must use the following accessor macros to pack/unpack valid MFNs.
+ */
+#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
+#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
+
+struct arch_vcpu_info {
+ ULONG_PTR cr2;
+ ULONG_PTR pad[5]; /* sizeof(vcpu_info_t) == 64 */
+};
+typedef struct arch_vcpu_info arch_vcpu_info_t;
+
+struct xen_callback {
+ ULONG_PTR cs;
+ ULONG_PTR eip;
+};
+typedef struct xen_callback xen_callback_t;
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+/******************************************************************************
+ * xen-x86_64.h
+ *
+ * Guest OS interface to x86 64-bit Xen.
+ *
+ * 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.
+ *
+ * Copyright (c) 2004-2006, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__
+#define __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__
+
+/*
+ * Hypercall interface:
+ * Input: %rdi, %rsi, %rdx, %r10, %r8, %r9 (arguments 1-6)
+ * Output: %rax
+ * Access is via hypercall page (set up by guest loader or via a Xen MSR):
+ * call hypercall_page + hypercall-number * 32
+ * Clobbered: argument registers (e.g., 2-arg hypercall clobbers %rdi,%rsi)
+ */
+
+/*
+ * 64-bit segment selectors
+ * These flat segments are in the Xen-private section of every GDT. Since these
+ * are also present in the initial GDT, many OSes will be able to avoid
+ * installing their own GDT.
+ */
+
+#define FLAT_RING3_CS32 0xe023 /* GDT index 260 */
+#define FLAT_RING3_CS64 0xe033 /* GDT index 261 */
+#define FLAT_RING3_DS32 0xe02b /* GDT index 262 */
+#define FLAT_RING3_DS64 0x0000 /* NULL selector */
+#define FLAT_RING3_SS32 0xe02b /* GDT index 262 */
+#define FLAT_RING3_SS64 0xe02b /* GDT index 262 */
+
+#define FLAT_KERNEL_DS64 FLAT_RING3_DS64
+#define FLAT_KERNEL_DS32 FLAT_RING3_DS32
+#define FLAT_KERNEL_DS FLAT_KERNEL_DS64
+#define FLAT_KERNEL_CS64 FLAT_RING3_CS64
+#define FLAT_KERNEL_CS32 FLAT_RING3_CS32
+#define FLAT_KERNEL_CS FLAT_KERNEL_CS64
+#define FLAT_KERNEL_SS64 FLAT_RING3_SS64
+#define FLAT_KERNEL_SS32 FLAT_RING3_SS32
+#define FLAT_KERNEL_SS FLAT_KERNEL_SS64
+
+#define FLAT_USER_DS64 FLAT_RING3_DS64
+#define FLAT_USER_DS32 FLAT_RING3_DS32
+#define FLAT_USER_DS FLAT_USER_DS64
+#define FLAT_USER_CS64 FLAT_RING3_CS64
+#define FLAT_USER_CS32 FLAT_RING3_CS32
+#define FLAT_USER_CS FLAT_USER_CS64
+#define FLAT_USER_SS64 FLAT_RING3_SS64
+#define FLAT_USER_SS32 FLAT_RING3_SS32
+#define FLAT_USER_SS FLAT_USER_SS64
+
+#define __HYPERVISOR_VIRT_START 0xFFFF800000000000
+#define __HYPERVISOR_VIRT_END 0xFFFF880000000000
+#define __MACH2PHYS_VIRT_START 0xFFFF800000000000
+#define __MACH2PHYS_VIRT_END 0xFFFF804000000000
+
+#ifndef HYPERVISOR_VIRT_START
+#define HYPERVISOR_VIRT_START xen_mk_ulong(__HYPERVISOR_VIRT_START)
+#define HYPERVISOR_VIRT_END xen_mk_ulong(__HYPERVISOR_VIRT_END)
+#endif
+
+#define MACH2PHYS_VIRT_START xen_mk_ulong(__MACH2PHYS_VIRT_START)
+#define MACH2PHYS_VIRT_END xen_mk_ulong(__MACH2PHYS_VIRT_END)
+#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3)
+#ifndef machine_to_phys_mapping
+#define machine_to_phys_mapping ((ULONG_PTR *)HYPERVISOR_VIRT_START)
+#endif
+
+/*
+ * int HYPERVISOR_set_segment_base(unsigned int which, ULONG_PTR base)
+ * @which == SEGBASE_* ; @base == 64-bit base address
+ * Returns 0 on success.
+ */
+#define SEGBASE_FS 0
+#define SEGBASE_GS_USER 1
+#define SEGBASE_GS_KERNEL 2
+#define SEGBASE_GS_USER_SEL 3 /* Set user %gs specified in base[15:0] */
+
+/*
+ * int HYPERVISOR_iret(void)
+ * All arguments are on the kernel stack, in the following format.
+ * Never returns if successful. Current kernel context is lost.
+ * The saved CS is mapped as follows:
+ * RING0 -> RING3 kernel mode.
+ * RING1 -> RING3 kernel mode.
+ * RING2 -> RING3 kernel mode.
+ * RING3 -> RING3 user mode.
+ * However RING0 indicates that the guest kernel should return to iteself
+ * directly with
+ * orb $3,1*8(%rsp)
+ * iretq
+ * If flags contains VGCF_in_syscall:
+ * Restore RAX, RIP, RFLAGS, RSP.
+ * Discard R11, RCX, CS, SS.
+ * Otherwise:
+ * Restore RAX, R11, RCX, CS:RIP, RFLAGS, SS:RSP.
+ * All other registers are saved on hypercall entry and restored to user.
+ */
+/* Guest exited in SYSCALL context? Return to guest with SYSRET? */
+#define _VGCF_in_syscall 8
+#define VGCF_in_syscall (1<<_VGCF_in_syscall)
+#define VGCF_IN_SYSCALL VGCF_in_syscall
+
+#ifndef __ASSEMBLY__
+
+struct iret_context {
+ /* Top of stack (%rsp at point of hypercall). */
+ uint64_t rax, r11, rcx, flags, rip, cs, rflags, rsp, ss;
+ /* Bottom of iret stack frame. */
+};
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+/* Anonymous union includes both 32- and 64-bit names (e.g., eax/rax). */
+#define __DECL_REG(name) union { \
+ uint64_t r ## name, e ## name; \
+ uint32_t _e ## name; \
+}
+#else
+/* Non-gcc sources must always use the proper 64-bit name (e.g., rax). */
+#define __DECL_REG(name) uint64_t r ## name
+#endif
+
+struct cpu_user_regs {
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ __DECL_REG(bp);
+ __DECL_REG(bx);
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ __DECL_REG(ax);
+ __DECL_REG(cx);
+ __DECL_REG(dx);
+ __DECL_REG(si);
+ __DECL_REG(di);
+ uint32_t error_code; /* private */
+ uint32_t entry_vector; /* private */
+ __DECL_REG(ip);
+ uint16_t cs, _pad0[1];
+ uint8_t saved_upcall_mask;
+ uint8_t _pad1[3];
+ __DECL_REG(flags); /* rflags.IF == !saved_upcall_mask */
+ __DECL_REG(sp);
+ uint16_t ss, _pad2[3];
+ uint16_t es, _pad3[3];
+ uint16_t ds, _pad4[3];
+ uint16_t fs, _pad5[3]; /* Non-zero => takes precedence over fs_base. */
+ uint16_t gs, _pad6[3]; /* Non-zero => takes precedence over gs_base_usr. */
+};
+typedef struct cpu_user_regs cpu_user_regs_t;
+DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t);
+
+#undef __DECL_REG
+
+#define xen_pfn_to_cr3(pfn) ((ULONG_PTR)(pfn) << 12)
+#define xen_cr3_to_pfn(cr3) ((ULONG_PTR)(cr3) >> 12)
+
+struct arch_vcpu_info {
+ ULONG_PTR cr2;
+ ULONG_PTR pad; /* sizeof(vcpu_info_t) == 64 */
+};
+typedef struct arch_vcpu_info arch_vcpu_info_t;
+
+typedef ULONG_PTR xen_callback_t;
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+/******************************************************************************
+ * arch-x86/xen.h
+ *
+ * Guest OS interface to x86 Xen.
+ *
+ * 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.
+ *
+ * Copyright (c) 2004-2006, K A Fraser
+ */
+
+#include "../xen.h"
+
+#ifndef __XEN_PUBLIC_ARCH_X86_XEN_H__
+#define __XEN_PUBLIC_ARCH_X86_XEN_H__
+
+/* Structural guest handles introduced in 0x00030201. */
+#if __XEN_INTERFACE_VERSION__ >= 0x00030201
+#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \
+ typedef struct { type *p; } __guest_handle_ ## name
+#else
+#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \
+ typedef type * __guest_handle_ ## name
+#endif
+
+/*
+ * XEN_GUEST_HANDLE represents a guest pointer, when passed as a field
+ * in a struct in memory.
+ * XEN_GUEST_HANDLE_PARAM represent a guest pointer, when passed as an
+ * hypercall argument.
+ * XEN_GUEST_HANDLE_PARAM and XEN_GUEST_HANDLE are the same on X86 but
+ * they might not be on other architectures.
+ */
+#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
+ ___DEFINE_XEN_GUEST_HANDLE(name, type); \
+ ___DEFINE_XEN_GUEST_HANDLE(const_##name, const type)
+#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name)
+#define __XEN_GUEST_HANDLE(name) __guest_handle_ ## name
+#define XEN_GUEST_HANDLE(name) __XEN_GUEST_HANDLE(name)
+#define XEN_GUEST_HANDLE_PARAM(name) XEN_GUEST_HANDLE(name)
+#define set_xen_guest_handle_raw(hnd, val) do { (hnd).p = val; } while (0)
+#define set_xen_guest_handle(hnd, val) set_xen_guest_handle_raw(hnd, val)
+
+#if defined(__i386__)
+#include "xen-x86_32.h"
+#elif defined(__x86_64__)
+#include "xen-x86_64.h"
+#endif
+
+#ifndef __ASSEMBLY__
+typedef ULONG_PTR xen_pfn_t;
+#define PRI_xen_pfn "lx"
+#endif
+
+#define XEN_HAVE_PV_GUEST_ENTRY 1
+
+#define XEN_HAVE_PV_UPCALL_MASK 1
+
+/*
+ * `incontents 200 segdesc Segment Descriptor Tables
+ */
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_set_gdt(const xen_pfn_t frames[], unsigned int entries);
+ * `
+ */
+/*
+ * A number of GDT entries are reserved by Xen. These are not situated at the
+ * start of the GDT because some stupid OSes export hard-coded selector values
+ * in their ABI. These hard-coded values are always near the start of the GDT,
+ * so Xen places itself out of the way, at the far end of the GDT.
+ *
+ * NB The LDT is set using the MMUEXT_SET_LDT op of HYPERVISOR_mmuext_op
+ */
+#define FIRST_RESERVED_GDT_PAGE 14
+#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096)
+#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
+
+
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_update_descriptor(u64 pa, u64 desc);
+ * `
+ * ` @pa The machine physical address of the descriptor to
+ * ` update. Must be either a descriptor page or writable.
+ * ` @desc The descriptor value to update, in the same format as a
+ * ` native descriptor table entry.
+ */
+
+/* Maximum number of virtual CPUs in legacy multi-processor guests. */
+#define XEN_LEGACY_MAX_VCPUS 32
+
+#ifndef __ASSEMBLY__
+
+typedef ULONG_PTR xen_ulong_t;
+#define PRI_xen_ulong "lx"
+
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_stack_switch(ULONG_PTR ss, ULONG_PTR esp);
+ * `
+ * Sets the stack segment and pointer for the current vcpu.
+ */
+
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_set_trap_table(const struct trap_info traps[]);
+ * `
+ */
+/*
+ * Send an array of these to HYPERVISOR_set_trap_table().
+ * Terminate the array with a sentinel entry, with traps[].address==0.
+ * The privilege level specifies which modes may enter a trap via a software
+ * interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate
+ * privilege levels as follows:
+ * Level == 0: Noone may enter
+ * Level == 1: Kernel may enter
+ * Level == 2: Kernel may enter
+ * Level == 3: Everyone may enter
+ */
+#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
+#define TI_GET_IF(_ti) ((_ti)->flags & 4)
+#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl))
+#define TI_SET_IF(_ti,_if) ((_ti)->flags |= ((!!(_if))<<2))
+struct trap_info {
+ uint8_t vector; /* exception vector */
+ uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */
+ uint16_t cs; /* code selector */
+ ULONG_PTR address; /* code offset */
+};
+typedef struct trap_info trap_info_t;
+DEFINE_XEN_GUEST_HANDLE(trap_info_t);
+
+typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
+
+/*
+ * The following is all CPU context. Note that the fpu_ctxt block is filled
+ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
+ *
+ * Also note that when calling DOMCTL_setvcpucontext and VCPU_initialise
+ * for HVM and PVH guests, not all information in this structure is updated:
+ *
+ * - For HVM guests, the structures read include: fpu_ctxt (if
+ * VGCT_I387_VALID is set), flags, user_regs, debugreg[*]
+ *
+ * - PVH guests are the same as HVM guests, but additionally use ctrlreg[3] to
+ * set cr3. All other fields not used should be set to 0.
+ */
+struct vcpu_guest_context {
+ /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
+ struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */
+#define VGCF_I387_VALID (1<<0)
+#define VGCF_IN_KERNEL (1<<2)
+#define _VGCF_i387_valid 0
+#define VGCF_i387_valid (1<<_VGCF_i387_valid)
+#define _VGCF_in_kernel 2
+#define VGCF_in_kernel (1<<_VGCF_in_kernel)
+#define _VGCF_failsafe_disables_events 3
+#define VGCF_failsafe_disables_events (1<<_VGCF_failsafe_disables_events)
+#define _VGCF_syscall_disables_events 4
+#define VGCF_syscall_disables_events (1<<_VGCF_syscall_disables_events)
+#define _VGCF_online 5
+#define VGCF_online (1<<_VGCF_online)
+ ULONG_PTR flags; /* VGCF_* flags */
+ struct cpu_user_regs user_regs; /* User-level CPU registers */
+ struct trap_info trap_ctxt[256]; /* Virtual IDT */
+ ULONG_PTR ldt_base, ldt_ents; /* LDT (linear address, # ents) */
+ ULONG_PTR gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
+ ULONG_PTR kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */
+ /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */
+ ULONG_PTR ctrlreg[8]; /* CR0-CR7 (control registers) */
+ ULONG_PTR debugreg[8]; /* DB0-DB7 (debug registers) */
+#ifdef __i386__
+ ULONG_PTR event_callback_cs; /* CS:EIP of event callback */
+ ULONG_PTR event_callback_eip;
+ ULONG_PTR failsafe_callback_cs; /* CS:EIP of failsafe callback */
+ ULONG_PTR failsafe_callback_eip;
+#else
+ ULONG_PTR event_callback_eip;
+ ULONG_PTR failsafe_callback_eip;
+#ifdef __XEN__
+ union {
+ ULONG_PTR syscall_callback_eip;
+ struct {
+ unsigned int event_callback_cs; /* compat CS of event cb */
+ unsigned int failsafe_callback_cs; /* compat CS of failsafe cb */
+ };
+ };
+#else
+ ULONG_PTR syscall_callback_eip;
+#endif
+#endif
+ ULONG_PTR vm_assist; /* VMASST_TYPE_* bitmap */
+#ifdef __x86_64__
+ /* Segment base addresses. */
+ uint64_t fs_base;
+ uint64_t gs_base_kernel;
+ uint64_t gs_base_user;
+#endif
+};
+typedef struct vcpu_guest_context vcpu_guest_context_t;
+DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
+
+struct arch_shared_info {
+ /*
+ * Number of valid entries in the p2m table(s) anchored at
+ * pfn_to_mfn_frame_list_list and/or p2m_vaddr.
+ */
+ ULONG_PTR max_pfn;
+ /*
+ * Frame containing list of mfns containing list of mfns containing p2m.
+ * A value of 0 indicates it has not yet been set up, ~0 indicates it has
+ * been set to invalid e.g. due to the p2m being too large for the 3-level
+ * p2m tree. In this case the linear mapper p2m list anchored at p2m_vaddr
+ * is to be used.
+ */
+ xen_pfn_t pfn_to_mfn_frame_list_list;
+ ULONG_PTR nmi_reason;
+ /*
+ * Following three fields are valid if p2m_cr3 contains a value different
+ * from 0.
+ * p2m_cr3 is the root of the address space where p2m_vaddr is valid.
+ * p2m_cr3 is in the same format as a cr3 value in the vcpu register state
+ * and holds the folded machine frame number (via xen_pfn_to_cr3) of a
+ * L3 or L4 page table.
+ * p2m_vaddr holds the virtual address of the linear p2m list. All entries
+ * in the range [0...max_pfn[ are accessible via this pointer.
+ * p2m_generation will be incremented by the guest before and after each
+ * change of the mappings of the p2m list. p2m_generation starts at 0 and
+ * a value with the least significant bit set indicates that a mapping
+ * update is in progress. This allows guest external software (e.g. in Dom0)
+ * to verify that read mappings are consistent and whether they have changed
+ * since the last check.
+ * Modifying a p2m element in the linear p2m list is allowed via an atomic
+ * write only.
+ */
+ ULONG_PTR p2m_cr3; /* cr3 value of the p2m address space */
+ ULONG_PTR p2m_vaddr; /* virtual address of the p2m list */
+ ULONG_PTR p2m_generation; /* generation count of p2m mapping */
+#ifdef __i386__
+ /* There's no room for this field in the generic structure. */
+ uint32_t wc_sec_hi;
+#endif
+};
+typedef struct arch_shared_info arch_shared_info_t;
+
+#if defined(__XEN__) || defined(__XEN_TOOLS__)
+/*
+ * struct xen_arch_domainconfig's ABI is covered by
+ * XEN_DOMCTL_INTERFACE_VERSION.
+ */
+struct xen_arch_domainconfig {
+#define _XEN_X86_EMU_LAPIC 0
+#define XEN_X86_EMU_LAPIC (1U<<_XEN_X86_EMU_LAPIC)
+#define _XEN_X86_EMU_HPET 1
+#define XEN_X86_EMU_HPET (1U<<_XEN_X86_EMU_HPET)
+#define _XEN_X86_EMU_PM 2
+#define XEN_X86_EMU_PM (1U<<_XEN_X86_EMU_PM)
+#define _XEN_X86_EMU_RTC 3
+#define XEN_X86_EMU_RTC (1U<<_XEN_X86_EMU_RTC)
+#define _XEN_X86_EMU_IOAPIC 4
+#define XEN_X86_EMU_IOAPIC (1U<<_XEN_X86_EMU_IOAPIC)
+#define _XEN_X86_EMU_PIC 5
+#define XEN_X86_EMU_PIC (1U<<_XEN_X86_EMU_PIC)
+#define _XEN_X86_EMU_VGA 6
+#define XEN_X86_EMU_VGA (1U<<_XEN_X86_EMU_VGA)
+#define _XEN_X86_EMU_IOMMU 7
+#define XEN_X86_EMU_IOMMU (1U<<_XEN_X86_EMU_IOMMU)
+#define _XEN_X86_EMU_PIT 8
+#define XEN_X86_EMU_PIT (1U<<_XEN_X86_EMU_PIT)
+
+#define XEN_X86_EMU_ALL (XEN_X86_EMU_LAPIC | XEN_X86_EMU_HPET | \
+ XEN_X86_EMU_PM | XEN_X86_EMU_RTC | \
+ XEN_X86_EMU_IOAPIC | XEN_X86_EMU_PIC | \
+ XEN_X86_EMU_VGA | XEN_X86_EMU_IOMMU | \
+ XEN_X86_EMU_PIT)
+ uint32_t emulation_flags;
+};
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_fpu_taskswitch(int set);
+ * `
+ * Sets (if set!=0) or clears (if set==0) CR0.TS.
+ */
+
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_set_debugreg(int regno, ULONG_PTR value);
+ *
+ * ` ULONG_PTR
+ * ` HYPERVISOR_get_debugreg(int regno);
+ * For 0<=reg<=7, returns the debug register value.
+ * For other values of reg, returns ((ULONG_PTR)-EINVAL).
+ * (Unfortunately, this interface is defective.)
+ */
+
+/*
+ * Prefix forces emulation of some non-trapping instructions.
+ * Currently only CPUID.
+ */
+#ifdef __ASSEMBLY__
+#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
+#define XEN_CPUID XEN_EMULATE_PREFIX cpuid
+#else
+#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
+#define XEN_CPUID XEN_EMULATE_PREFIX "cpuid"
+#endif
+
+#endif /* __XEN_PUBLIC_ARCH_X86_XEN_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+/*
+ * There are two expected ways of including this header.
+ *
+ * 1) The "default" case (expected from tools etc).
+ *
+ * Simply #include <public/errno.h>
+ *
+ * In this circumstance, normal header guards apply and the includer shall get
+ * an enumeration in the XEN_xxx namespace, appropriate for C or assembly.
+ *
+ * 2) The special case where the includer provides a XEN_ERRNO() in scope.
+ *
+ * In this case, no inclusion guards apply and the caller is responsible for
+ * their XEN_ERRNO() being appropriate in the included context. The header
+ * will unilaterally #undef XEN_ERRNO().
+ */
+
+#ifndef XEN_ERRNO
+
+/*
+ * Includer has not provided a custom XEN_ERRNO(). Arrange for normal header
+ * guards, an automatic enum (for C code) and constants in the XEN_xxx
+ * namespace.
+ */
+#ifndef __XEN_PUBLIC_ERRNO_H__
+#define __XEN_PUBLIC_ERRNO_H__
+
+#define XEN_ERRNO_DEFAULT_INCLUDE
+
+#ifndef __ASSEMBLY__
+
+#define XEN_ERRNO(name, value) XEN_##name = value,
+enum xen_errno {
+
+#elif __XEN_INTERFACE_VERSION__ < 0x00040700
+
+#define XEN_ERRNO(name, value) .equ XEN_##name, value
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __XEN_PUBLIC_ERRNO_H__ */
+#endif /* !XEN_ERRNO */
+
+/* ` enum neg_errnoval { [ -Efoo for each Efoo in the list below ] } */
+/* ` enum errnoval { */
+
+#ifdef XEN_ERRNO
+
+/*
+ * Values originating from x86 Linux. Please consider using respective
+ * values when adding new definitions here.
+ *
+ * The set of identifiers to be added here shouldn't extend beyond what
+ * POSIX mandates (see e.g.
+ * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html)
+ * with the exception that we support some optional (XSR) values
+ * specified there (but no new ones should be added).
+ */
+
+XEN_ERRNO(EPERM, 1) /* Operation not permitted */
+XEN_ERRNO(ENOENT, 2) /* No such file or directory */
+XEN_ERRNO(ESRCH, 3) /* No such process */
+#ifdef __XEN__ /* Internal only, should never be exposed to the guest. */
+XEN_ERRNO(EINTR, 4) /* Interrupted system call */
+#endif
+XEN_ERRNO(EIO, 5) /* I/O error */
+XEN_ERRNO(ENXIO, 6) /* No such device or address */
+XEN_ERRNO(E2BIG, 7) /* Arg list too LONG_PTR */
+XEN_ERRNO(ENOEXEC, 8) /* Exec format error */
+XEN_ERRNO(EBADF, 9) /* Bad file number */
+XEN_ERRNO(ECHILD, 10) /* No child processes */
+XEN_ERRNO(EAGAIN, 11) /* Try again */
+XEN_ERRNO(EWOULDBLOCK, 11) /* Operation would block. Aliases EAGAIN */
+XEN_ERRNO(ENOMEM, 12) /* Out of memory */
+XEN_ERRNO(EACCES, 13) /* Permission denied */
+XEN_ERRNO(EFAULT, 14) /* Bad address */
+XEN_ERRNO(EBUSY, 16) /* Device or resource busy */
+XEN_ERRNO(EEXIST, 17) /* File exists */
+XEN_ERRNO(EXDEV, 18) /* Cross-device link */
+XEN_ERRNO(ENODEV, 19) /* No such device */
+XEN_ERRNO(EISDIR, 21) /* Is a directory */
+XEN_ERRNO(EINVAL, 22) /* Invalid argument */
+XEN_ERRNO(ENFILE, 23) /* File table overflow */
+XEN_ERRNO(EMFILE, 24) /* Too many open files */
+XEN_ERRNO(ENOSPC, 28) /* No space left on device */
+XEN_ERRNO(EROFS, 30) /* Read-only file system */
+XEN_ERRNO(EMLINK, 31) /* Too many links */
+XEN_ERRNO(EDOM, 33) /* Math argument out of domain of func */
+XEN_ERRNO(ERANGE, 34) /* Math result not representable */
+XEN_ERRNO(EDEADLK, 35) /* Resource deadlock would occur */
+XEN_ERRNO(EDEADLOCK, 35) /* Resource deadlock would occur. Aliases EDEADLK */
+XEN_ERRNO(ENAMETOOLONG, 36) /* File name too LONG_PTR */
+XEN_ERRNO(ENOLCK, 37) /* No record locks available */
+XEN_ERRNO(ENOTEMPTY, 39) /* Directory not empty */
+XEN_ERRNO(ENOSYS, 38) /* Function not implemented */
+XEN_ERRNO(ENODATA, 61) /* No data available */
+XEN_ERRNO(ETIME, 62) /* Timer expired */
+XEN_ERRNO(EBADMSG, 74) /* Not a data message */
+XEN_ERRNO(EOVERFLOW, 75) /* Value too large for defined data type */
+XEN_ERRNO(EILSEQ, 84) /* Illegal byte sequence */
+#ifdef __XEN__ /* Internal only, should never be exposed to the guest. */
+XEN_ERRNO(ERESTART, 85) /* Interrupted system call should be restarted */
+#endif
+XEN_ERRNO(ENOTSOCK, 88) /* Socket operation on non-socket */
+XEN_ERRNO(EOPNOTSUPP, 95) /* Operation not supported on transport endpoint */
+XEN_ERRNO(EADDRINUSE, 98) /* Address already in use */
+XEN_ERRNO(EADDRNOTAVAIL, 99) /* Cannot assign requested address */
+XEN_ERRNO(ENOBUFS, 105) /* No buffer space available */
+XEN_ERRNO(EISCONN, 106) /* Transport endpoint is already connected */
+XEN_ERRNO(ENOTCONN, 107) /* Transport endpoint is not connected */
+XEN_ERRNO(ETIMEDOUT, 110) /* Connection timed out */
+
+#undef XEN_ERRNO
+#endif /* XEN_ERRNO */
+/* ` } */
+
+/* Clean up from a default include. Close the enum (for C). */
+#ifdef XEN_ERRNO_DEFAULT_INCLUDE
+#undef XEN_ERRNO_DEFAULT_INCLUDE
+#ifndef __ASSEMBLY__
+};
+#endif
+
+#endif /* XEN_ERRNO_DEFAULT_INCLUDE */
--- /dev/null
+/******************************************************************************
+ * grant_table.h
+ *
+ * Interface for granting foreign access to page frames, and receiving
+ * page-ownership transfers.
+ *
+ * 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.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_GRANT_TABLE_H__
+#define __XEN_PUBLIC_GRANT_TABLE_H__
+
+#include "xen.h"
+
+/*
+ * `incontents 150 gnttab Grant Tables
+ *
+ * Xen's grant tables provide a generic mechanism to memory sharing
+ * between domains. This shared memory interface underpins the split
+ * device drivers for block and network IO.
+ *
+ * Each domain has its own grant table. This is a data structure that
+ * is shared with Xen; it allows the domain to tell Xen what kind of
+ * permissions other domains have on its pages. Entries in the grant
+ * table are identified by grant references. A grant reference is an
+ * integer, which indexes into the grant table. It acts as a
+ * capability which the grantee can use to perform operations on the
+ * granter's memory.
+ *
+ * This capability-based system allows shared-memory communications
+ * between unprivileged domains. A grant reference also encapsulates
+ * the details of a shared page, removing the need for a domain to
+ * know the real machine address of a page it is sharing. This makes
+ * it possible to share memory correctly with domains running in
+ * fully virtualised memory.
+ */
+
+/***********************************
+ * GRANT TABLE REPRESENTATION
+ */
+
+/* Some rough guidelines on accessing and updating grant-table entries
+ * in a concurrency-safe manner. For more information, Linux contains a
+ * reference implementation for guest OSes (drivers/xen/grant_table.c, see
+ * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=drivers/xen/grant-table.c;hb=HEAD
+ *
+ * NB. WMB is a no-op on current-generation x86 processors. However, a
+ * compiler barrier will still be required.
+ *
+ * Introducing a valid entry into the grant table:
+ * 1. Write ent->domid.
+ * 2. Write ent->frame:
+ * GTF_permit_access: Frame to which access is permitted.
+ * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+ * frame, or zero if none.
+ * 3. Write memory barrier (WMB).
+ * 4. Write ent->flags, inc. valid type.
+ *
+ * Invalidating an unused GTF_permit_access entry:
+ * 1. flags = ent->flags.
+ * 2. Observe that !(flags & (GTF_reading|GTF_writing)).
+ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ * NB. No need for WMB as reuse of entry is control-dependent on success of
+ * step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ *
+ * Invalidating an in-use GTF_permit_access entry:
+ * This cannot be done directly. Request assistance from the domain controller
+ * which can set a timeout on the use of a grant entry and take necessary
+ * action. (NB. This is not yet implemented!).
+ *
+ * Invalidating an unused GTF_accept_transfer entry:
+ * 1. flags = ent->flags.
+ * 2. Observe that !(flags & GTF_transfer_committed). [*]
+ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ * NB. No need for WMB as reuse of entry is control-dependent on success of
+ * step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ * [*] If GTF_transfer_committed is set then the grant entry is 'committed'.
+ * The guest must /not/ modify the grant entry until the address of the
+ * transferred frame is written. It is safe for the guest to spin waiting
+ * for this to occur (detect by observing GTF_transfer_completed in
+ * ent->flags).
+ *
+ * Invalidating a committed GTF_accept_transfer entry:
+ * 1. Wait for (ent->flags & GTF_transfer_completed).
+ *
+ * Changing a GTF_permit_access from writable to read-only:
+ * Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing.
+ *
+ * Changing a GTF_permit_access from read-only to writable:
+ * Use SMP-safe bit-setting instruction.
+ */
+
+/*
+ * Reference to a grant entry in a specified domain's grant table.
+ */
+typedef uint32_t grant_ref_t;
+
+/*
+ * A grant table comprises a packed array of grant entries in one or more
+ * page frames shared between Xen and a guest.
+ * [XEN]: This field is written by Xen and read by the sharing guest.
+ * [GST]: This field is written by the guest and read by Xen.
+ */
+
+/*
+ * Version 1 of the grant table entry structure is maintained purely
+ * for backwards compatibility. New guests should use version 2.
+ */
+#if __XEN_INTERFACE_VERSION__ < 0x0003020a
+#define grant_entry_v1 grant_entry
+#define grant_entry_v1_t grant_entry_t
+#endif
+struct grant_entry_v1 {
+ /* GTF_xxx: various type and flag information. [XEN,GST] */
+ uint16_t flags;
+ /* The domain being granted foreign privileges. [GST] */
+ domid_t domid;
+ /*
+ * GTF_permit_access: GFN that @domid is allowed to map and access. [GST]
+ * GTF_accept_transfer: GFN that @domid is allowed to transfer into. [GST]
+ * GTF_transfer_completed: MFN whose ownership transferred by @domid
+ * (non-translated guests only). [XEN]
+ */
+ uint32_t frame;
+};
+typedef struct grant_entry_v1 grant_entry_v1_t;
+
+/* The first few grant table entries will be preserved across grant table
+ * version changes and may be pre-populated at domain creation by tools.
+ */
+#define GNTTAB_NR_RESERVED_ENTRIES 8
+#define GNTTAB_RESERVED_CONSOLE 0
+#define GNTTAB_RESERVED_XENSTORE 1
+
+/*
+ * Type of grant entry.
+ * GTF_invalid: This grant entry grants no privileges.
+ * GTF_permit_access: Allow @domid to map/access @frame.
+ * GTF_accept_transfer: Allow @domid to transfer ownership of one page frame
+ * to this guest. Xen writes the page number to @frame.
+ * GTF_transitive: Allow @domid to transitively access a subrange of
+ * @trans_grant in @trans_domid. No mappings are allowed.
+ */
+#define GTF_invalid (0U<<0)
+#define GTF_permit_access (1U<<0)
+#define GTF_accept_transfer (2U<<0)
+#define GTF_transitive (3U<<0)
+#define GTF_type_mask (3U<<0)
+
+/*
+ * Subflags for GTF_permit_access.
+ * GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
+ * GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
+ * GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
+ * GTF_PAT, GTF_PWT, GTF_PCD: (x86) cache attribute flags for the grant [GST]
+ * GTF_sub_page: Grant access to only a subrange of the page. @domid
+ * will only be allowed to copy from the grant, and not
+ * map it. [GST]
+ */
+#define _GTF_readonly (2)
+#define GTF_readonly (1U<<_GTF_readonly)
+#define _GTF_reading (3)
+#define GTF_reading (1U<<_GTF_reading)
+#define _GTF_writing (4)
+#define GTF_writing (1U<<_GTF_writing)
+#define _GTF_PWT (5)
+#define GTF_PWT (1U<<_GTF_PWT)
+#define _GTF_PCD (6)
+#define GTF_PCD (1U<<_GTF_PCD)
+#define _GTF_PAT (7)
+#define GTF_PAT (1U<<_GTF_PAT)
+#define _GTF_sub_page (8)
+#define GTF_sub_page (1U<<_GTF_sub_page)
+
+/*
+ * Subflags for GTF_accept_transfer:
+ * GTF_transfer_committed: Xen sets this flag to indicate that it is committed
+ * to transferring ownership of a page frame. When a guest sees this flag
+ * it must /not/ modify the grant entry until GTF_transfer_completed is
+ * set by Xen.
+ * GTF_transfer_completed: It is safe for the guest to spin-wait on this flag
+ * after reading GTF_transfer_committed. Xen will always write the frame
+ * address, followed by ORing this flag, in a timely manner.
+ */
+#define _GTF_transfer_committed (2)
+#define GTF_transfer_committed (1U<<_GTF_transfer_committed)
+#define _GTF_transfer_completed (3)
+#define GTF_transfer_completed (1U<<_GTF_transfer_completed)
+
+/*
+ * Version 2 grant table entries. These fulfil the same role as
+ * version 1 entries, but can represent more complicated operations.
+ * Any given domain will have either a version 1 or a version 2 table,
+ * and every entry in the table will be the same version.
+ *
+ * The interface by which domains use grant references does not depend
+ * on the grant table version in use by the other domain.
+ */
+#if __XEN_INTERFACE_VERSION__ >= 0x0003020a
+/*
+ * Version 1 and version 2 grant entries share a common prefix. The
+ * fields of the prefix are documented as part of struct
+ * grant_entry_v1.
+ */
+struct grant_entry_header {
+ uint16_t flags;
+ domid_t domid;
+};
+typedef struct grant_entry_header grant_entry_header_t;
+
+/*
+ * Version 2 of the grant entry structure.
+ */
+union grant_entry_v2 {
+ grant_entry_header_t hdr;
+
+ /*
+ * This member is used for V1-style full page grants, where either:
+ *
+ * -- hdr.type is GTF_accept_transfer, or
+ * -- hdr.type is GTF_permit_access and GTF_sub_page is not set.
+ *
+ * In that case, the frame field has the same semantics as the
+ * field of the same name in the V1 entry structure.
+ */
+ struct {
+ grant_entry_header_t hdr;
+ uint32_t pad0;
+ uint64_t frame;
+ } full_page;
+
+ /*
+ * If the grant type is GTF_grant_access and GTF_sub_page is set,
+ * @domid is allowed to access bytes [@page_off,@page_off+@length)
+ * in frame @frame.
+ */
+ struct {
+ grant_entry_header_t hdr;
+ uint16_t page_off;
+ uint16_t length;
+ uint64_t frame;
+ } sub_page;
+
+ /*
+ * If the grant is GTF_transitive, @domid is allowed to use the
+ * grant @gref in domain @trans_domid, as if it was the local
+ * domain. Obviously, the transitive access must be compatible
+ * with the original grant.
+ *
+ * The current version of Xen does not allow transitive grants
+ * to be mapped.
+ */
+ struct {
+ grant_entry_header_t hdr;
+ domid_t trans_domid;
+ uint16_t pad0;
+ grant_ref_t gref;
+ } transitive;
+
+ uint32_t __spacer[4]; /* Pad to a power of two */
+};
+typedef union grant_entry_v2 grant_entry_v2_t;
+
+typedef uint16_t grant_status_t;
+
+#endif /* __XEN_INTERFACE_VERSION__ */
+
+/***********************************
+ * GRANT TABLE QUERIES AND USES
+ */
+
+/* ` enum neg_errnoval
+ * ` HYPERVISOR_grant_table_op(enum grant_table_op cmd,
+ * ` void *args,
+ * ` unsigned int count)
+ * `
+ *
+ * @args points to an array of a per-command data structure. The array
+ * has @count members
+ */
+
+/* ` enum grant_table_op { // GNTTABOP_* => struct gnttab_* */
+#define GNTTABOP_map_grant_ref 0
+#define GNTTABOP_unmap_grant_ref 1
+#define GNTTABOP_setup_table 2
+#define GNTTABOP_dump_table 3
+#define GNTTABOP_transfer 4
+#define GNTTABOP_copy 5
+#define GNTTABOP_query_size 6
+#define GNTTABOP_unmap_and_replace 7
+#if __XEN_INTERFACE_VERSION__ >= 0x0003020a
+#define GNTTABOP_set_version 8
+#define GNTTABOP_get_status_frames 9
+#define GNTTABOP_get_version 10
+#define GNTTABOP_swap_grant_ref 11
+#define GNTTABOP_cache_flush 12
+#endif /* __XEN_INTERFACE_VERSION__ */
+/* ` } */
+
+/*
+ * Handle to track a mapping created via a grant reference.
+ */
+typedef uint32_t grant_handle_t;
+
+/*
+ * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
+ * by devices and/or host CPUs. If successful, <handle> is a tracking number
+ * that must be presented later to destroy the mapping(s). On error, <status>
+ * is a negative status code.
+ * NOTES:
+ * 1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address
+ * via which I/O devices may access the granted frame.
+ * 2. If GNTMAP_host_map is specified then a mapping will be added at
+ * either a host virtual address in the current address space, or at
+ * a PTE at the specified machine address. The type of mapping to
+ * perform is selected through the GNTMAP_contains_pte flag, and the
+ * address is specified in <host_addr>.
+ * 3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a
+ * host mapping is destroyed by other means then it is *NOT* guaranteed
+ * to be accounted to the correct grant reference!
+ */
+struct gnttab_map_grant_ref {
+ /* IN parameters. */
+ uint64_t host_addr;
+ uint32_t flags; /* GNTMAP_* */
+ grant_ref_t ref;
+ domid_t dom;
+ /* OUT parameters. */
+ int16_t status; /* => enum grant_status */
+ grant_handle_t handle;
+ uint64_t dev_bus_addr;
+};
+typedef struct gnttab_map_grant_ref gnttab_map_grant_ref_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_map_grant_ref_t);
+
+/*
+ * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
+ * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that
+ * field is ignored. If non-zero, they must refer to a device/host mapping
+ * that is tracked by <handle>
+ * NOTES:
+ * 1. The call may fail in an undefined manner if either mapping is not
+ * tracked by <handle>.
+ * 3. After executing a batch of unmaps, it is guaranteed that no stale
+ * mappings will remain in the device or host TLBs.
+ */
+struct gnttab_unmap_grant_ref {
+ /* IN parameters. */
+ uint64_t host_addr;
+ uint64_t dev_bus_addr;
+ grant_handle_t handle;
+ /* OUT parameters. */
+ int16_t status; /* => enum grant_status */
+};
+typedef struct gnttab_unmap_grant_ref gnttab_unmap_grant_ref_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t);
+
+/*
+ * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
+ * <nr_frames> pages. The frame addresses are written to the <frame_list>.
+ * Only <nr_frames> addresses are written, even if the table is larger.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ * 3. Xen may not support more than a single grant-table page per domain.
+ */
+struct gnttab_setup_table {
+ /* IN parameters. */
+ domid_t dom;
+ uint32_t nr_frames;
+ /* OUT parameters. */
+ int16_t status; /* => enum grant_status */
+#if __XEN_INTERFACE_VERSION__ < 0x00040300
+ XEN_GUEST_HANDLE(ulong) frame_list;
+#else
+ XEN_GUEST_HANDLE(xen_pfn_t) frame_list;
+#endif
+};
+typedef struct gnttab_setup_table gnttab_setup_table_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_t);
+
+/*
+ * GNTTABOP_dump_table: Dump the contents of the grant table to the
+ * xen console. Debugging use only.
+ */
+struct gnttab_dump_table {
+ /* IN parameters. */
+ domid_t dom;
+ /* OUT parameters. */
+ int16_t status; /* => enum grant_status */
+};
+typedef struct gnttab_dump_table gnttab_dump_table_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_dump_table_t);
+
+/*
+ * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The
+ * foreign domain has previously registered its interest in the transfer via
+ * <domid, ref>.
+ *
+ * Note that, even if the transfer fails, the specified page no LONG_PTRer belongs
+ * to the calling domain *unless* the error is GNTST_bad_page.
+ */
+struct gnttab_transfer {
+ /* IN parameters. */
+ xen_pfn_t mfn;
+ domid_t domid;
+ grant_ref_t ref;
+ /* OUT parameters. */
+ int16_t status;
+};
+typedef struct gnttab_transfer gnttab_transfer_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_t);
+
+
+/*
+ * GNTTABOP_copy: Hypervisor based copy
+ * source and destinations can be eithers MFNs or, for foreign domains,
+ * grant references. the foreign domain has to grant read/write access
+ * in its grant table.
+ *
+ * The flags specify what type source and destinations are (either MFN
+ * or grant reference).
+ *
+ * Note that this can also be used to copy data between two domains
+ * via a third party if the source and destination domains had previously
+ * grant appropriate access to their pages to the third party.
+ *
+ * source_offset specifies an offset in the source frame, dest_offset
+ * the offset in the target frame and len specifies the number of
+ * bytes to be copied.
+ */
+
+#define _GNTCOPY_source_gref (0)
+#define GNTCOPY_source_gref (1<<_GNTCOPY_source_gref)
+#define _GNTCOPY_dest_gref (1)
+#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref)
+
+struct gnttab_copy {
+ /* IN parameters. */
+ struct gnttab_copy_ptr {
+ union {
+ grant_ref_t ref;
+ xen_pfn_t gmfn;
+ } u;
+ domid_t domid;
+ uint16_t offset;
+ } source, dest;
+ uint16_t len;
+ uint16_t flags; /* GNTCOPY_* */
+ /* OUT parameters. */
+ int16_t status;
+};
+typedef struct gnttab_copy gnttab_copy_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t);
+
+/*
+ * GNTTABOP_query_size: Query the current and maximum sizes of the shared
+ * grant table.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ */
+struct gnttab_query_size {
+ /* IN parameters. */
+ domid_t dom;
+ /* OUT parameters. */
+ uint32_t nr_frames;
+ uint32_t max_nr_frames;
+ int16_t status; /* => enum grant_status */
+};
+typedef struct gnttab_query_size gnttab_query_size_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_query_size_t);
+
+/*
+ * GNTTABOP_unmap_and_replace: Destroy one or more grant-reference mappings
+ * tracked by <handle> but atomically replace the page table entry with one
+ * pointing to the machine address under <new_addr>. <new_addr> will be
+ * redirected to the null entry.
+ * NOTES:
+ * 1. The call may fail in an undefined manner if either mapping is not
+ * tracked by <handle>.
+ * 2. After executing a batch of unmaps, it is guaranteed that no stale
+ * mappings will remain in the device or host TLBs.
+ */
+struct gnttab_unmap_and_replace {
+ /* IN parameters. */
+ uint64_t host_addr;
+ uint64_t new_addr;
+ grant_handle_t handle;
+ /* OUT parameters. */
+ int16_t status; /* => enum grant_status */
+};
+typedef struct gnttab_unmap_and_replace gnttab_unmap_and_replace_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t);
+
+#if __XEN_INTERFACE_VERSION__ >= 0x0003020a
+/*
+ * GNTTABOP_set_version: Request a particular version of the grant
+ * table shared table structure. This operation can only be performed
+ * once in any given domain. It must be performed before any grants
+ * are activated; otherwise, the domain will be stuck with version 1.
+ * The only defined versions are 1 and 2.
+ */
+struct gnttab_set_version {
+ /* IN/OUT parameters */
+ uint32_t version;
+};
+typedef struct gnttab_set_version gnttab_set_version_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_set_version_t);
+
+
+/*
+ * GNTTABOP_get_status_frames: Get the list of frames used to store grant
+ * status for <dom>. In grant format version 2, the status is separated
+ * from the other shared grant fields to allow more efficient synchronization
+ * using barriers instead of atomic cmpexch operations.
+ * <nr_frames> specify the size of vector <frame_list>.
+ * The frame addresses are returned in the <frame_list>.
+ * Only <nr_frames> addresses are returned, even if the table is larger.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ */
+struct gnttab_get_status_frames {
+ /* IN parameters. */
+ uint32_t nr_frames;
+ domid_t dom;
+ /* OUT parameters. */
+ int16_t status; /* => enum grant_status */
+ XEN_GUEST_HANDLE(uint64_t) frame_list;
+};
+typedef struct gnttab_get_status_frames gnttab_get_status_frames_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_t);
+
+/*
+ * GNTTABOP_get_version: Get the grant table version which is in
+ * effect for domain <dom>.
+ */
+struct gnttab_get_version {
+ /* IN parameters */
+ domid_t dom;
+ uint16_t pad;
+ /* OUT parameters */
+ uint32_t version;
+};
+typedef struct gnttab_get_version gnttab_get_version_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_get_version_t);
+
+/*
+ * GNTTABOP_swap_grant_ref: Swap the contents of two grant entries.
+ */
+struct gnttab_swap_grant_ref {
+ /* IN parameters */
+ grant_ref_t ref_a;
+ grant_ref_t ref_b;
+ /* OUT parameters */
+ int16_t status; /* => enum grant_status */
+};
+typedef struct gnttab_swap_grant_ref gnttab_swap_grant_ref_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_swap_grant_ref_t);
+
+/*
+ * Issue one or more cache maintenance operations on a portion of a
+ * page granted to the calling domain by a foreign domain.
+ */
+struct gnttab_cache_flush {
+ union {
+ uint64_t dev_bus_addr;
+ grant_ref_t ref;
+ } a;
+ uint16_t offset; /* offset from start of grant */
+ uint16_t length; /* size within the grant */
+#define GNTTAB_CACHE_CLEAN (1<<0)
+#define GNTTAB_CACHE_INVAL (1<<1)
+#define GNTTAB_CACHE_SOURCE_GREF (1<<31)
+ uint32_t op;
+};
+typedef struct gnttab_cache_flush gnttab_cache_flush_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_cache_flush_t);
+
+#endif /* __XEN_INTERFACE_VERSION__ */
+
+/*
+ * Bitfield values for gnttab_map_grant_ref.flags.
+ */
+ /* Map the grant entry for access by I/O devices. */
+#define _GNTMAP_device_map (0)
+#define GNTMAP_device_map (1<<_GNTMAP_device_map)
+ /* Map the grant entry for access by host CPUs. */
+#define _GNTMAP_host_map (1)
+#define GNTMAP_host_map (1<<_GNTMAP_host_map)
+ /* Accesses to the granted frame will be restricted to read-only access. */
+#define _GNTMAP_readonly (2)
+#define GNTMAP_readonly (1<<_GNTMAP_readonly)
+ /*
+ * GNTMAP_host_map subflag:
+ * 0 => The host mapping is usable only by the guest OS.
+ * 1 => The host mapping is usable by guest OS + current application.
+ */
+#define _GNTMAP_application_map (3)
+#define GNTMAP_application_map (1<<_GNTMAP_application_map)
+
+ /*
+ * GNTMAP_contains_pte subflag:
+ * 0 => This map request contains a host virtual address.
+ * 1 => This map request contains the machine addess of the PTE to update.
+ */
+#define _GNTMAP_contains_pte (4)
+#define GNTMAP_contains_pte (1<<_GNTMAP_contains_pte)
+
+#define _GNTMAP_can_fail (5)
+#define GNTMAP_can_fail (1<<_GNTMAP_can_fail)
+
+/*
+ * Bits to be placed in guest kernel available PTE bits (architecture
+ * dependent; only supported when XENFEAT_gnttab_map_avail_bits is set).
+ */
+#define _GNTMAP_guest_avail0 (16)
+#define GNTMAP_guest_avail_mask ((uint32_t)~0 << _GNTMAP_guest_avail0)
+
+/*
+ * Values for error status returns. All errors are -ve.
+ */
+/* ` enum grant_status { */
+#define GNTST_okay (0) /* Normal return. */
+#define GNTST_general_error (-1) /* General undefined error. */
+#define GNTST_bad_domain (-2) /* Unrecognsed domain id. */
+#define GNTST_bad_gntref (-3) /* Unrecognised or inappropriate gntref. */
+#define GNTST_bad_handle (-4) /* Unrecognised or inappropriate handle. */
+#define GNTST_bad_virt_addr (-5) /* Inappropriate virtual address to map. */
+#define GNTST_bad_dev_addr (-6) /* Inappropriate device address to unmap.*/
+#define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */
+#define GNTST_permission_denied (-8) /* Not enough privilege for operation. */
+#define GNTST_bad_page (-9) /* Specified page was invalid for op. */
+#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary. */
+#define GNTST_address_too_big (-11) /* transfer page address too large. */
+#define GNTST_eagain (-12) /* Operation not done; try again. */
+/* ` } */
+
+#define GNTTABOP_error_msgs { \
+ "okay", \
+ "undefined error", \
+ "unrecognised domain id", \
+ "invalid grant reference", \
+ "invalid mapping handle", \
+ "invalid virtual address", \
+ "invalid device address", \
+ "no spare translation slot in the I/O MMU", \
+ "permission denied", \
+ "bad page", \
+ "copy arguments cross page boundary", \
+ "page address size too large", \
+ "operation not done; try again" \
+}
+
+#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+/*
+ * kbdif.h -- Xen virtual keyboard/mouse
+ *
+ * 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.
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ */
+
+#ifndef __XEN_PUBLIC_IO_KBDIF_H__
+#define __XEN_PUBLIC_IO_KBDIF_H__
+
+/*
+ *****************************************************************************
+ * Feature and Parameter Negotiation
+ *****************************************************************************
+ *
+ * The two halves of a para-virtual driver utilize nodes within
+ * XenStore to communicate capabilities and to negotiate operating parameters.
+ * This section enumerates these nodes which reside in the respective front and
+ * backend portions of XenStore, following XenBus convention.
+ *
+ * All data in XenStore is stored as strings. Nodes specifying numeric
+ * values are encoded in decimal. Integer value ranges listed below are
+ * expressed as fixed sized integer types capable of storing the conversion
+ * of a properly formated node string, without loss of information.
+ *
+ *****************************************************************************
+ * Backend XenBus Nodes
+ *****************************************************************************
+ *
+ *---------------------------- Features supported ----------------------------
+ *
+ * Capable backend advertises supported features by publishing
+ * corresponding entries in XenStore and puts 1 as the value of the entry.
+ * If a feature is not supported then 0 must be set or feature entry omitted.
+ *
+ * feature-abs-pointer
+ * Values: <uint>
+ *
+ * Backends, which support reporting of absolute coordinates for pointer
+ * device should set this to 1.
+ *
+ * feature-multi-touch
+ * Values: <uint>
+ *
+ * Backends, which support reporting of multi-touch events
+ * should set this to 1.
+ *
+ *------------------------- Pointer Device Parameters ------------------------
+ *
+ * width
+ * Values: <uint>
+ *
+ * Maximum X coordinate (width) to be used by the frontend
+ * while reporting input events, pixels, [0; UINT32_MAX].
+ *
+ * height
+ * Values: <uint>
+ *
+ * Maximum Y coordinate (height) to be used by the frontend
+ * while reporting input events, pixels, [0; UINT32_MAX].
+ *
+ *****************************************************************************
+ * Frontend XenBus Nodes
+ *****************************************************************************
+ *
+ *------------------------------ Feature request -----------------------------
+ *
+ * Capable frontend requests features from backend via setting corresponding
+ * entries to 1 in XenStore. Requests for features not advertised as supported
+ * by the backend have no effect.
+ *
+ * request-abs-pointer
+ * Values: <uint>
+ *
+ * Request backend to report absolute pointer coordinates
+ * (XENKBD_TYPE_POS) instead of relative ones (XENKBD_TYPE_MOTION).
+ *
+ * request-multi-touch
+ * Values: <uint>
+ *
+ * Request backend to report multi-touch events.
+ *
+ *----------------------- Request Transport Parameters -----------------------
+ *
+ * event-channel
+ * Values: <uint>
+ *
+ * The identifier of the Xen event channel used to signal activity
+ * in the ring buffer.
+ *
+ * page-gref
+ * Values: <uint>
+ *
+ * The Xen grant reference granting permission for the backend to map
+ * a sole page in a single page sized event ring buffer.
+ *
+ * page-ref
+ * Values: <uint>
+ *
+ * OBSOLETE, not recommended for use.
+ * PFN of the shared page.
+ *
+ *----------------------- Multi-touch Device Parameters -----------------------
+ *
+ * multi-touch-num-contacts
+ * Values: <uint>
+ *
+ * Number of simultaneous touches reported.
+ *
+ * multi-touch-width
+ * Values: <uint>
+ *
+ * Width of the touch area to be used by the frontend
+ * while reporting input events, pixels, [0; UINT32_MAX].
+ *
+ * multi-touch-height
+ * Values: <uint>
+ *
+ * Height of the touch area to be used by the frontend
+ * while reporting input events, pixels, [0; UINT32_MAX].
+ */
+
+/*
+ * EVENT CODES.
+ */
+
+#define XENKBD_TYPE_MOTION 1
+#define XENKBD_TYPE_RESERVED 2
+#define XENKBD_TYPE_KEY 3
+#define XENKBD_TYPE_POS 4
+#define XENKBD_TYPE_MTOUCH 5
+
+/* Multi-touch event sub-codes */
+
+#define XENKBD_MT_EV_DOWN 0
+#define XENKBD_MT_EV_UP 1
+#define XENKBD_MT_EV_MOTION 2
+#define XENKBD_MT_EV_SYN 3
+#define XENKBD_MT_EV_SHAPE 4
+#define XENKBD_MT_EV_ORIENT 5
+
+/*
+ * CONSTANTS, XENSTORE FIELD AND PATH NAME STRINGS, HELPERS.
+ */
+
+#define XENKBD_DRIVER_NAME "vkbd"
+
+#define XENKBD_FIELD_FEAT_ABS_POINTER "feature-abs-pointer"
+#define XENKBD_FIELD_FEAT_MTOUCH "feature-multi-touch"
+#define XENKBD_FIELD_REQ_ABS_POINTER "request-abs-pointer"
+#define XENKBD_FIELD_REQ_MTOUCH "request-multi-touch"
+#define XENKBD_FIELD_RING_GREF "page-gref"
+#define XENKBD_FIELD_EVT_CHANNEL "event-channel"
+#define XENKBD_FIELD_WIDTH "width"
+#define XENKBD_FIELD_HEIGHT "height"
+#define XENKBD_FIELD_MT_WIDTH "multi-touch-width"
+#define XENKBD_FIELD_MT_HEIGHT "multi-touch-height"
+#define XENKBD_FIELD_MT_NUM_CONTACTS "multi-touch-num-contacts"
+
+/* OBSOLETE, not recommended for use */
+#define XENKBD_FIELD_RING_REF "page-ref"
+
+/*
+ *****************************************************************************
+ * Description of the protocol between frontend and backend driver.
+ *****************************************************************************
+ *
+ * The two halves of a Para-virtual driver communicate with
+ * each other using a shared page and an event channel.
+ * Shared page contains a ring with event structures.
+ *
+ * All reserved fields in the structures below must be 0.
+ *
+ *****************************************************************************
+ * Backend to frontend events
+ *****************************************************************************
+ *
+ * Frontends should ignore unknown in events.
+ * All event packets have the same length (40 octets)
+ * All event packets have common header:
+ *
+ * 0 octet
+ * +-----------------+
+ * | type |
+ * +-----------------+
+ * type - uint8_t, event code, XENKBD_TYPE_???
+ *
+ *
+ * Pointer relative movement event
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_MOTION | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | rel_x | 8
+ * +----------------+----------------+----------------+----------------+
+ * | rel_y | 12
+ * +----------------+----------------+----------------+----------------+
+ * | rel_z | 16
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 20
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * rel_x - int32_t, relative X motion
+ * rel_y - int32_t, relative Y motion
+ * rel_z - int32_t, relative Z motion (wheel)
+ */
+
+struct xenkbd_motion
+{
+ uint8_t type;
+ int32_t rel_x;
+ int32_t rel_y;
+ int32_t rel_z;
+};
+
+/*
+ * Key event (includes pointer buttons)
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_KEY | pressed | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | keycode | 8
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 12
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * pressed - uint8_t, 1 if pressed; 0 otherwise
+ * keycode - uint32_t, KEY_* from linux/input.h
+ */
+
+struct xenkbd_key
+{
+ uint8_t type;
+ uint8_t pressed;
+ uint32_t keycode;
+};
+
+/*
+ * Pointer absolute position event
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_POS | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | abs_x | 8
+ * +----------------+----------------+----------------+----------------+
+ * | abs_y | 12
+ * +----------------+----------------+----------------+----------------+
+ * | rel_z | 16
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 20
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * abs_x - int32_t, absolute X position (in FB pixels)
+ * abs_y - int32_t, absolute Y position (in FB pixels)
+ * rel_z - int32_t, relative Z motion (wheel)
+ */
+
+struct xenkbd_position
+{
+ uint8_t type;
+ int32_t abs_x;
+ int32_t abs_y;
+ int32_t rel_z;
+};
+
+/*
+ * Multi-touch event and its sub-types
+ *
+ * All multi-touch event packets have common header:
+ *
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_MTOUCH | event_type | contact_id | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 8
+ * +----------------+----------------+----------------+----------------+
+ *
+ * event_type - unt8_t, multi-touch event sub-type, XENKBD_MT_EV_???
+ * contact_id - unt8_t, ID of the contact
+ *
+ * Touch interactions can consist of one or more contacts.
+ * For each contact, a series of events is generated, starting
+ * with a down event, followed by zero or more motion events,
+ * and ending with an up event. Events relating to the same
+ * contact point can be identified by the ID of the sequence: contact ID.
+ * Contact ID may be reused after XENKBD_MT_EV_UP event and
+ * is in the [0; XENKBD_FIELD_NUM_CONTACTS - 1] range.
+ *
+ * For further information please refer to documentation on Wayland [1],
+ * Linux [2] and Windows [3] multi-touch support.
+ *
+ * [1] https://cgit.freedesktop.org/wayland/wayland/tree/protocol/wayland.xml
+ * [2] https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
+ * [3] https://msdn.microsoft.com/en-us/library/jj151564(v=vs.85).aspx
+ *
+ *
+ * Multi-touch down event - sent when a new touch is made: touch is assigned
+ * a unique contact ID, sent with this and consequent events related
+ * to this touch.
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_MTOUCH | _MT_EV_DOWN | contact_id | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 8
+ * +----------------+----------------+----------------+----------------+
+ * | abs_x | 12
+ * +----------------+----------------+----------------+----------------+
+ * | abs_y | 16
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 20
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * abs_x - int32_t, absolute X position, in pixels
+ * abs_y - int32_t, absolute Y position, in pixels
+ *
+ * Multi-touch contact release event
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_MTOUCH | _MT_EV_UP | contact_id | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 8
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * Multi-touch motion event
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_MTOUCH | _MT_EV_MOTION | contact_id | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 8
+ * +----------------+----------------+----------------+----------------+
+ * | abs_x | 12
+ * +----------------+----------------+----------------+----------------+
+ * | abs_y | 16
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 20
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * abs_x - int32_t, absolute X position, in pixels,
+ * abs_y - int32_t, absolute Y position, in pixels,
+ *
+ * Multi-touch input synchronization event - shows end of a set of events
+ * which logically belong together.
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_MTOUCH | _MT_EV_SYN | contact_id | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 8
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * Multi-touch shape event - touch point's shape has changed its shape.
+ * Shape is approximated by an ellipse through the major and minor axis
+ * lengths: major is the longer diameter of the ellipse and minor is the
+ * shorter one. Center of the ellipse is reported via
+ * XENKBD_MT_EV_DOWN/XENKBD_MT_EV_MOTION events.
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_MTOUCH | _MT_EV_SHAPE | contact_id | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 8
+ * +----------------+----------------+----------------+----------------+
+ * | major | 12
+ * +----------------+----------------+----------------+----------------+
+ * | minor | 16
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 20
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * major - unt32_t, length of the major axis, pixels
+ * minor - unt32_t, length of the minor axis, pixels
+ *
+ * Multi-touch orientation event - touch point's shape has changed
+ * its orientation: calculated as a clockwise angle between the major axis
+ * of the ellipse and positive Y axis in degrees, [-180; +180].
+ * 0 1 2 3 octet
+ * +----------------+----------------+----------------+----------------+
+ * | _TYPE_MTOUCH | _MT_EV_ORIENT | contact_id | reserved | 4
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 8
+ * +----------------+----------------+----------------+----------------+
+ * | orientation | reserved | 12
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 16
+ * +----------------+----------------+----------------+----------------+
+ * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
+ * +----------------+----------------+----------------+----------------+
+ * | reserved | 40
+ * +----------------+----------------+----------------+----------------+
+ *
+ * orientation - int16_t, clockwise angle of the major axis
+ */
+
+struct xenkbd_mtouch {
+ uint8_t type; /* XENKBD_TYPE_MTOUCH */
+ uint8_t event_type; /* XENKBD_MT_EV_??? */
+ uint8_t contact_id;
+ uint8_t reserved[5]; /* reserved for the future use */
+ union {
+ struct {
+ int32_t abs_x; /* absolute X position, pixels */
+ int32_t abs_y; /* absolute Y position, pixels */
+ } pos;
+ struct {
+ uint32_t major; /* length of the major axis, pixels */
+ uint32_t minor; /* length of the minor axis, pixels */
+ } shape;
+ int16_t orientation; /* clockwise angle of the major axis */
+ } u;
+};
+
+#define XENKBD_IN_EVENT_SIZE 40
+
+union xenkbd_in_event
+{
+ uint8_t type;
+ struct xenkbd_motion motion;
+ struct xenkbd_key key;
+ struct xenkbd_position pos;
+ struct xenkbd_mtouch mtouch;
+ char pad[XENKBD_IN_EVENT_SIZE];
+};
+
+/*
+ *****************************************************************************
+ * Frontend to backend events
+ *****************************************************************************
+ *
+ * Out events may be sent only when requested by backend, and receipt
+ * of an unknown out event is an error.
+ * No out events currently defined.
+
+ * All event packets have the same length (40 octets)
+ * All event packets have common header:
+ * 0 octet
+ * +-----------------+
+ * | type |
+ * +-----------------+
+ * type - uint8_t, event code
+ */
+
+#define XENKBD_OUT_EVENT_SIZE 40
+
+union xenkbd_out_event
+{
+ uint8_t type;
+ char pad[XENKBD_OUT_EVENT_SIZE];
+};
+
+/*
+ *****************************************************************************
+ * Shared page
+ *****************************************************************************
+ */
+
+#define XENKBD_IN_RING_SIZE 2048
+#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE)
+#define XENKBD_IN_RING_OFFS 1024
+#define XENKBD_IN_RING(page) \
+ ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS))
+#define XENKBD_IN_RING_REF(page, idx) \
+ (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN])
+
+#define XENKBD_OUT_RING_SIZE 1024
+#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE)
+#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE)
+#define XENKBD_OUT_RING(page) \
+ ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS))
+#define XENKBD_OUT_RING_REF(page, idx) \
+ (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN])
+
+struct xenkbd_page
+{
+ uint32_t in_cons, in_prod;
+ uint32_t out_cons, out_prod;
+};
+
+#endif /* __XEN_PUBLIC_IO_KBDIF_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+/******************************************************************************
+ * ring.h
+ *
+ * Shared producer-consumer ring macros.
+ *
+ * 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.
+ *
+ * Tim Deegan and Andrew Warfield November 2004.
+ */
+
+#ifndef __XEN_PUBLIC_IO_RING_H__
+#define __XEN_PUBLIC_IO_RING_H__
+
+#include "../xen-compat.h"
+
+#if __XEN_INTERFACE_VERSION__ < 0x00030208
+#define xen_mb() mb()
+#define xen_rmb() rmb()
+#define xen_wmb() wmb()
+#endif
+
+typedef unsigned int RING_IDX;
+
+/* Round a 32-bit unsigned constant down to the nearest power of two. */
+#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1))
+#define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x))
+#define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x))
+#define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x))
+#define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x))
+
+/*
+ * Calculate size of a shared ring, given the total available space for the
+ * ring and indexes (_sz), and the name tag of the request/response structure.
+ * A ring contains as many entries as will fit, rounded down to the nearest
+ * power of two (so we can mask with (size-1) to loop around).
+ */
+#define __CONST_RING_SIZE(_s, _sz) \
+ (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \
+ sizeof(((struct _s##_sring *)0)->ring[0])))
+/*
+ * The same for passing in an actual pointer instead of a name tag.
+ */
+#define __RING_SIZE(_s, _sz) \
+ (__RD32(((_sz) - (LONG_PTR)(_s)->ring + (LONG_PTR)(_s)) / sizeof((_s)->ring[0])))
+
+/*
+ * Macros to make the correct C datatypes for a new kind of ring.
+ *
+ * To make a new ring datatype, you need to have two message structures,
+ * let's say request_t, and response_t already defined.
+ *
+ * In a header where you want the ring datatype declared, you then do:
+ *
+ * DEFINE_RING_TYPES(mytag, request_t, response_t);
+ *
+ * These expand out to give you a set of types, as you can see below.
+ * The most important of these are:
+ *
+ * mytag_sring_t - The shared ring.
+ * mytag_front_ring_t - The 'front' half of the ring.
+ * mytag_back_ring_t - The 'back' half of the ring.
+ *
+ * To initialize a ring in your code you need to know the location and size
+ * of the shared memory area (PAGE_SIZE, for instance). To initialise
+ * the front half:
+ *
+ * mytag_front_ring_t front_ring;
+ * SHARED_RING_INIT((mytag_sring_t *)shared_page);
+ * FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
+ *
+ * Initializing the back follows similarly (note that only the front
+ * initializes the shared ring):
+ *
+ * mytag_back_ring_t back_ring;
+ * BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
+ */
+
+#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \
+ \
+/* Shared ring entry */ \
+union __name##_sring_entry { \
+ __req_t req; \
+ __rsp_t rsp; \
+}; \
+ \
+/* Shared ring page */ \
+struct __name##_sring { \
+ RING_IDX req_prod, req_event; \
+ RING_IDX rsp_prod, rsp_event; \
+ union { \
+ struct { \
+ uint8_t smartpoll_active; \
+ } netif; \
+ struct { \
+ uint8_t msg; \
+ } tapif_user; \
+ uint8_t pvt_pad[4]; \
+ } pvt; \
+ uint8_t __pad[44]; \
+ union __name##_sring_entry ring[1]; /* variable-length */ \
+}; \
+ \
+/* "Front" end's private variables */ \
+struct __name##_front_ring { \
+ RING_IDX req_prod_pvt; \
+ RING_IDX rsp_cons; \
+ unsigned int nr_ents; \
+ struct __name##_sring *sring; \
+}; \
+ \
+/* "Back" end's private variables */ \
+struct __name##_back_ring { \
+ RING_IDX rsp_prod_pvt; \
+ RING_IDX req_cons; \
+ unsigned int nr_ents; \
+ struct __name##_sring *sring; \
+}; \
+ \
+/* Syntactic sugar */ \
+typedef struct __name##_sring __name##_sring_t; \
+typedef struct __name##_front_ring __name##_front_ring_t; \
+typedef struct __name##_back_ring __name##_back_ring_t
+
+/*
+ * Macros for manipulating rings.
+ *
+ * FRONT_RING_whatever works on the "front end" of a ring: here
+ * requests are pushed on to the ring and responses taken off it.
+ *
+ * BACK_RING_whatever works on the "back end" of a ring: here
+ * requests are taken off the ring and responses put on.
+ *
+ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
+ * This is OK in 1-for-1 request-response situations where the
+ * requestor (front end) never has more than RING_SIZE()-1
+ * outstanding requests.
+ */
+
+/* Initialising empty rings */
+#define SHARED_RING_INIT(_s) do { \
+ (_s)->req_prod = (_s)->rsp_prod = 0; \
+ (_s)->req_event = (_s)->rsp_event = 1; \
+ (void)memset((_s)->pvt.pvt_pad, 0, sizeof((_s)->pvt.pvt_pad)); \
+ (void)memset((_s)->__pad, 0, sizeof((_s)->__pad)); \
+} while(0)
+
+#define FRONT_RING_INIT(_r, _s, __size) do { \
+ (_r)->req_prod_pvt = 0; \
+ (_r)->rsp_cons = 0; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+ (_r)->sring = (_s); \
+} while (0)
+
+#define BACK_RING_INIT(_r, _s, __size) do { \
+ (_r)->rsp_prod_pvt = 0; \
+ (_r)->req_cons = 0; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+ (_r)->sring = (_s); \
+} while (0)
+
+/* How big is this ring? */
+#define RING_SIZE(_r) \
+ ((_r)->nr_ents)
+
+/* Number of free requests (for use on front side only). */
+#define RING_FREE_REQUESTS(_r) \
+ (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons))
+
+/* Test if there is an empty slot available on the front ring.
+ * (This is only meaningful from the front. )
+ */
+#define RING_FULL(_r) \
+ (RING_FREE_REQUESTS(_r) == 0)
+
+/* Test if there are outstanding messages to be processed on a ring. */
+#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
+ ((_r)->sring->rsp_prod - (_r)->rsp_cons)
+
+#ifdef __GNUC__
+#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \
+ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
+ unsigned int rsp = RING_SIZE(_r) - \
+ ((_r)->req_cons - (_r)->rsp_prod_pvt); \
+ req < rsp ? req : rsp; \
+})
+#else
+/* Same as above, but without the nice GCC ({ ... }) syntax. */
+#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
+ ((((_r)->sring->req_prod - (_r)->req_cons) < \
+ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \
+ ((_r)->sring->req_prod - (_r)->req_cons) : \
+ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt)))
+#endif
+
+/* Direct access to individual ring elements, by index. */
+#define RING_GET_REQUEST(_r, _idx) \
+ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
+
+/*
+ * Get a local copy of a request.
+ *
+ * Use this in preference to RING_GET_REQUEST() so all processing is
+ * done on a local copy that cannot be modified by the other end.
+ *
+ * Note that https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 may cause this
+ * to be ineffective where _req is a struct which consists of only bitfields.
+ */
+#define RING_COPY_REQUEST(_r, _idx, _req) do { \
+ /* Use volatile to force the copy into _req. */ \
+ *(_req) = *(volatile typeof(_req))RING_GET_REQUEST(_r, _idx); \
+} while (0)
+
+#define RING_GET_RESPONSE(_r, _idx) \
+ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
+
+/* Loop termination condition: Would the specified index overflow the ring? */
+#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \
+ (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
+
+/* Ill-behaved frontend determination: Can there be this many requests? */
+#define RING_REQUEST_PROD_OVERFLOW(_r, _prod) \
+ (((_prod) - (_r)->rsp_prod_pvt) > RING_SIZE(_r))
+
+#define RING_PUSH_REQUESTS(_r) do { \
+ xen_wmb(); /* back sees requests /before/ updated producer index */ \
+ (_r)->sring->req_prod = (_r)->req_prod_pvt; \
+} while (0)
+
+#define RING_PUSH_RESPONSES(_r) do { \
+ xen_wmb(); /* front sees resps /before/ updated producer index */ \
+ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \
+} while (0)
+
+/*
+ * Notification hold-off (req_event and rsp_event):
+ *
+ * When queueing requests or responses on a shared ring, it may not always be
+ * necessary to notify the remote end. For example, if requests are in flight
+ * in a backend, the front may be able to queue further requests without
+ * notifying the back (if the back checks for new requests when it queues
+ * responses).
+ *
+ * When enqueuing requests or responses:
+ *
+ * Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument
+ * is a boolean return value. True indicates that the receiver requires an
+ * asynchronous notification.
+ *
+ * After dequeuing requests or responses (before sleeping the connection):
+ *
+ * Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES().
+ * The second argument is a boolean return value. True indicates that there
+ * are pending messages on the ring (i.e., the connection should not be put
+ * to sleep).
+ *
+ * These macros will set the req_event/rsp_event field to trigger a
+ * notification on the very next message that is enqueued. If you want to
+ * create batches of work (i.e., only receive a notification after several
+ * messages have been enqueued) then you will need to create a customised
+ * version of the FINAL_CHECK macro in your own code, which sets the event
+ * field appropriately.
+ */
+
+#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \
+ RING_IDX __old = (_r)->sring->req_prod; \
+ RING_IDX __new = (_r)->req_prod_pvt; \
+ xen_wmb(); /* back sees requests /before/ updated producer index */ \
+ (_r)->sring->req_prod = __new; \
+ xen_mb(); /* back sees new requests /before/ we check req_event */ \
+ (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \
+ (RING_IDX)(__new - __old)); \
+} while (0)
+
+#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \
+ RING_IDX __old = (_r)->sring->rsp_prod; \
+ RING_IDX __new = (_r)->rsp_prod_pvt; \
+ xen_wmb(); /* front sees resps /before/ updated producer index */ \
+ (_r)->sring->rsp_prod = __new; \
+ xen_mb(); /* front sees new resps /before/ we check rsp_event */ \
+ (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \
+ (RING_IDX)(__new - __old)); \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \
+ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
+ if (_work_to_do) break; \
+ (_r)->sring->req_event = (_r)->req_cons + 1; \
+ xen_mb(); \
+ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \
+ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
+ if (_work_to_do) break; \
+ (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \
+ xen_mb(); \
+ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
+} while (0)
+
+#endif /* __XEN_PUBLIC_IO_RING_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+/*****************************************************************************
+ * xenbus.h
+ *
+ * Xenbus protocol details.
+ *
+ * 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.
+ *
+ * Copyright (C) 2005 XenSource Ltd.
+ */
+
+#ifndef _XEN_PUBLIC_IO_XENBUS_H
+#define _XEN_PUBLIC_IO_XENBUS_H
+
+/*
+ * The state of either end of the Xenbus, i.e. the current communication
+ * status of initialisation across the bus. States here imply nothing about
+ * the state of the connection between the driver and the kernel's device
+ * layers.
+ */
+enum xenbus_state {
+ XenbusStateUnknown = 0,
+
+ XenbusStateInitialising = 1,
+
+ /*
+ * InitWait: Finished early initialisation but waiting for information
+ * from the peer or hotplug scripts.
+ */
+ XenbusStateInitWait = 2,
+
+ /*
+ * Initialised: Waiting for a connection from the peer.
+ */
+ XenbusStateInitialised = 3,
+
+ XenbusStateConnected = 4,
+
+ /*
+ * Closing: The device is being closed due to an error or an unplug event.
+ */
+ XenbusStateClosing = 5,
+
+ XenbusStateClosed = 6,
+
+ /*
+ * Reconfiguring: The device is being reconfigured.
+ */
+ XenbusStateReconfiguring = 7,
+
+ XenbusStateReconfigured = 8
+};
+typedef enum xenbus_state XenbusState;
+
+#endif /* _XEN_PUBLIC_IO_XENBUS_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+/******************************************************************************
+ * include/public/trace.h
+ *
+ * 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.
+ *
+ * Mark Williamson, (C) 2004 Intel Research Cambridge
+ * Copyright (C) 2005 Bin Ren
+ */
+
+#ifndef __XEN_PUBLIC_TRACE_H__
+#define __XEN_PUBLIC_TRACE_H__
+
+#define TRACE_EXTRA_MAX 7
+#define TRACE_EXTRA_SHIFT 28
+
+/* Trace classes */
+#define TRC_CLS_SHIFT 16
+#define TRC_GEN 0x0001f000 /* General trace */
+#define TRC_SCHED 0x0002f000 /* Xen Scheduler trace */
+#define TRC_DOM0OP 0x0004f000 /* Xen DOM0 operation trace */
+#define TRC_HVM 0x0008f000 /* Xen HVM trace */
+#define TRC_MEM 0x0010f000 /* Xen memory trace */
+#define TRC_PV 0x0020f000 /* Xen PV traces */
+#define TRC_SHADOW 0x0040f000 /* Xen shadow tracing */
+#define TRC_HW 0x0080f000 /* Xen hardware-related traces */
+#define TRC_GUEST 0x0800f000 /* Guest-generated traces */
+#define TRC_ALL 0x0ffff000
+#define TRC_HD_TO_EVENT(x) ((x)&0x0fffffff)
+#define TRC_HD_CYCLE_FLAG (1UL<<31)
+#define TRC_HD_INCLUDES_CYCLE_COUNT(x) ( !!( (x) & TRC_HD_CYCLE_FLAG ) )
+#define TRC_HD_EXTRA(x) (((x)>>TRACE_EXTRA_SHIFT)&TRACE_EXTRA_MAX)
+
+/* Trace subclasses */
+#define TRC_SUBCLS_SHIFT 12
+
+/* trace subclasses for SVM */
+#define TRC_HVM_ENTRYEXIT 0x00081000 /* VMENTRY and #VMEXIT */
+#define TRC_HVM_HANDLER 0x00082000 /* various HVM handlers */
+#define TRC_HVM_EMUL 0x00084000 /* emulated devices */
+
+#define TRC_SCHED_MIN 0x00021000 /* Just runstate changes */
+#define TRC_SCHED_CLASS 0x00022000 /* Scheduler-specific */
+#define TRC_SCHED_VERBOSE 0x00028000 /* More inclusive scheduling */
+
+/*
+ * The highest 3 bits of the last 12 bits of TRC_SCHED_CLASS above are
+ * reserved for encoding what scheduler produced the information. The
+ * actual event is encoded in the last 9 bits.
+ *
+ * This means we have 8 scheduling IDs available (which means at most 8
+ * schedulers generating events) and, in each scheduler, up to 512
+ * different events.
+ */
+#define TRC_SCHED_ID_BITS 3
+#define TRC_SCHED_ID_SHIFT (TRC_SUBCLS_SHIFT - TRC_SCHED_ID_BITS)
+#define TRC_SCHED_ID_MASK (((1UL<<TRC_SCHED_ID_BITS) - 1) << TRC_SCHED_ID_SHIFT)
+#define TRC_SCHED_EVT_MASK (~(TRC_SCHED_ID_MASK))
+
+/* Per-scheduler IDs, to identify scheduler specific events */
+#define TRC_SCHED_CSCHED 0
+#define TRC_SCHED_CSCHED2 1
+/* #define XEN_SCHEDULER_SEDF 2 (Removed) */
+#define TRC_SCHED_ARINC653 3
+#define TRC_SCHED_RTDS 4
+
+/* Per-scheduler tracing */
+#define TRC_SCHED_CLASS_EVT(_c, _e) \
+ ( ( TRC_SCHED_CLASS | \
+ ((TRC_SCHED_##_c << TRC_SCHED_ID_SHIFT) & TRC_SCHED_ID_MASK) ) + \
+ (_e & TRC_SCHED_EVT_MASK) )
+
+/* Trace classes for DOM0 operations */
+#define TRC_DOM0_DOMOPS 0x00041000 /* Domains manipulations */
+
+/* Trace classes for Hardware */
+#define TRC_HW_PM 0x00801000 /* Power management traces */
+#define TRC_HW_IRQ 0x00802000 /* Traces relating to the handling of IRQs */
+
+/* Trace events per class */
+#define TRC_LOST_RECORDS (TRC_GEN + 1)
+#define TRC_TRACE_WRAP_BUFFER (TRC_GEN + 2)
+#define TRC_TRACE_CPU_CHANGE (TRC_GEN + 3)
+
+#define TRC_SCHED_RUNSTATE_CHANGE (TRC_SCHED_MIN + 1)
+#define TRC_SCHED_CONTINUE_RUNNING (TRC_SCHED_MIN + 2)
+#define TRC_SCHED_DOM_ADD (TRC_SCHED_VERBOSE + 1)
+#define TRC_SCHED_DOM_REM (TRC_SCHED_VERBOSE + 2)
+#define TRC_SCHED_SLEEP (TRC_SCHED_VERBOSE + 3)
+#define TRC_SCHED_WAKE (TRC_SCHED_VERBOSE + 4)
+#define TRC_SCHED_YIELD (TRC_SCHED_VERBOSE + 5)
+#define TRC_SCHED_BLOCK (TRC_SCHED_VERBOSE + 6)
+#define TRC_SCHED_SHUTDOWN (TRC_SCHED_VERBOSE + 7)
+#define TRC_SCHED_CTL (TRC_SCHED_VERBOSE + 8)
+#define TRC_SCHED_ADJDOM (TRC_SCHED_VERBOSE + 9)
+#define TRC_SCHED_SWITCH (TRC_SCHED_VERBOSE + 10)
+#define TRC_SCHED_S_TIMER_FN (TRC_SCHED_VERBOSE + 11)
+#define TRC_SCHED_T_TIMER_FN (TRC_SCHED_VERBOSE + 12)
+#define TRC_SCHED_DOM_TIMER_FN (TRC_SCHED_VERBOSE + 13)
+#define TRC_SCHED_SWITCH_INFPREV (TRC_SCHED_VERBOSE + 14)
+#define TRC_SCHED_SWITCH_INFNEXT (TRC_SCHED_VERBOSE + 15)
+#define TRC_SCHED_SHUTDOWN_CODE (TRC_SCHED_VERBOSE + 16)
+
+#define TRC_DOM0_DOM_ADD (TRC_DOM0_DOMOPS + 1)
+#define TRC_DOM0_DOM_REM (TRC_DOM0_DOMOPS + 2)
+
+#define TRC_MEM_PAGE_GRANT_MAP (TRC_MEM + 1)
+#define TRC_MEM_PAGE_GRANT_UNMAP (TRC_MEM + 2)
+#define TRC_MEM_PAGE_GRANT_TRANSFER (TRC_MEM + 3)
+#define TRC_MEM_SET_P2M_ENTRY (TRC_MEM + 4)
+#define TRC_MEM_DECREASE_RESERVATION (TRC_MEM + 5)
+#define TRC_MEM_POD_POPULATE (TRC_MEM + 16)
+#define TRC_MEM_POD_ZERO_RECLAIM (TRC_MEM + 17)
+#define TRC_MEM_POD_SUPERPAGE_SPLINTER (TRC_MEM + 18)
+
+#define TRC_PV_ENTRY 0x00201000 /* Hypervisor entry points for PV guests. */
+#define TRC_PV_SUBCALL 0x00202000 /* Sub-call in a multicall hypercall */
+
+#define TRC_PV_HYPERCALL (TRC_PV_ENTRY + 1)
+#define TRC_PV_TRAP (TRC_PV_ENTRY + 3)
+#define TRC_PV_PAGE_FAULT (TRC_PV_ENTRY + 4)
+#define TRC_PV_FORCED_INVALID_OP (TRC_PV_ENTRY + 5)
+#define TRC_PV_EMULATE_PRIVOP (TRC_PV_ENTRY + 6)
+#define TRC_PV_EMULATE_4GB (TRC_PV_ENTRY + 7)
+#define TRC_PV_MATH_STATE_RESTORE (TRC_PV_ENTRY + 8)
+#define TRC_PV_PAGING_FIXUP (TRC_PV_ENTRY + 9)
+#define TRC_PV_GDT_LDT_MAPPING_FAULT (TRC_PV_ENTRY + 10)
+#define TRC_PV_PTWR_EMULATION (TRC_PV_ENTRY + 11)
+#define TRC_PV_PTWR_EMULATION_PAE (TRC_PV_ENTRY + 12)
+#define TRC_PV_HYPERCALL_V2 (TRC_PV_ENTRY + 13)
+#define TRC_PV_HYPERCALL_SUBCALL (TRC_PV_SUBCALL + 14)
+
+/*
+ * TRC_PV_HYPERCALL_V2 format
+ *
+ * Only some of the hypercall argument are recorded. Bit fields A0 to
+ * A5 in the first extra word are set if the argument is present and
+ * the arguments themselves are packed sequentially in the following
+ * words.
+ *
+ * The TRC_64_FLAG bit is not set for these events (even if there are
+ * 64-bit arguments in the record).
+ *
+ * Word
+ * 0 bit 31 30|29 28|27 26|25 24|23 22|21 20|19 ... 0
+ * A5 |A4 |A3 |A2 |A1 |A0 |Hypercall op
+ * 1 First 32 bit (or low word of first 64 bit) arg in record
+ * 2 Second 32 bit (or high word of first 64 bit) arg in record
+ * ...
+ *
+ * A0-A5 bitfield values:
+ *
+ * 00b Argument not present
+ * 01b 32-bit argument present
+ * 10b 64-bit argument present
+ * 11b Reserved
+ */
+#define TRC_PV_HYPERCALL_V2_ARG_32(i) (0x1 << (20 + 2*(i)))
+#define TRC_PV_HYPERCALL_V2_ARG_64(i) (0x2 << (20 + 2*(i)))
+#define TRC_PV_HYPERCALL_V2_ARG_MASK (0xfff00000)
+
+#define TRC_SHADOW_NOT_SHADOW (TRC_SHADOW + 1)
+#define TRC_SHADOW_FAST_PROPAGATE (TRC_SHADOW + 2)
+#define TRC_SHADOW_FAST_MMIO (TRC_SHADOW + 3)
+#define TRC_SHADOW_FALSE_FAST_PATH (TRC_SHADOW + 4)
+#define TRC_SHADOW_MMIO (TRC_SHADOW + 5)
+#define TRC_SHADOW_FIXUP (TRC_SHADOW + 6)
+#define TRC_SHADOW_DOMF_DYING (TRC_SHADOW + 7)
+#define TRC_SHADOW_EMULATE (TRC_SHADOW + 8)
+#define TRC_SHADOW_EMULATE_UNSHADOW_USER (TRC_SHADOW + 9)
+#define TRC_SHADOW_EMULATE_UNSHADOW_EVTINJ (TRC_SHADOW + 10)
+#define TRC_SHADOW_EMULATE_UNSHADOW_UNHANDLED (TRC_SHADOW + 11)
+#define TRC_SHADOW_WRMAP_BF (TRC_SHADOW + 12)
+#define TRC_SHADOW_PREALLOC_UNPIN (TRC_SHADOW + 13)
+#define TRC_SHADOW_RESYNC_FULL (TRC_SHADOW + 14)
+#define TRC_SHADOW_RESYNC_ONLY (TRC_SHADOW + 15)
+
+/* trace events per subclass */
+#define TRC_HVM_NESTEDFLAG (0x400)
+#define TRC_HVM_VMENTRY (TRC_HVM_ENTRYEXIT + 0x01)
+#define TRC_HVM_VMEXIT (TRC_HVM_ENTRYEXIT + 0x02)
+#define TRC_HVM_VMEXIT64 (TRC_HVM_ENTRYEXIT + TRC_64_FLAG + 0x02)
+#define TRC_HVM_PF_XEN (TRC_HVM_HANDLER + 0x01)
+#define TRC_HVM_PF_XEN64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x01)
+#define TRC_HVM_PF_INJECT (TRC_HVM_HANDLER + 0x02)
+#define TRC_HVM_PF_INJECT64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x02)
+#define TRC_HVM_INJ_EXC (TRC_HVM_HANDLER + 0x03)
+#define TRC_HVM_INJ_VIRQ (TRC_HVM_HANDLER + 0x04)
+#define TRC_HVM_REINJ_VIRQ (TRC_HVM_HANDLER + 0x05)
+#define TRC_HVM_IO_READ (TRC_HVM_HANDLER + 0x06)
+#define TRC_HVM_IO_WRITE (TRC_HVM_HANDLER + 0x07)
+#define TRC_HVM_CR_READ (TRC_HVM_HANDLER + 0x08)
+#define TRC_HVM_CR_READ64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x08)
+#define TRC_HVM_CR_WRITE (TRC_HVM_HANDLER + 0x09)
+#define TRC_HVM_CR_WRITE64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x09)
+#define TRC_HVM_DR_READ (TRC_HVM_HANDLER + 0x0A)
+#define TRC_HVM_DR_WRITE (TRC_HVM_HANDLER + 0x0B)
+#define TRC_HVM_MSR_READ (TRC_HVM_HANDLER + 0x0C)
+#define TRC_HVM_MSR_WRITE (TRC_HVM_HANDLER + 0x0D)
+#define TRC_HVM_CPUID (TRC_HVM_HANDLER + 0x0E)
+#define TRC_HVM_INTR (TRC_HVM_HANDLER + 0x0F)
+#define TRC_HVM_NMI (TRC_HVM_HANDLER + 0x10)
+#define TRC_HVM_SMI (TRC_HVM_HANDLER + 0x11)
+#define TRC_HVM_VMMCALL (TRC_HVM_HANDLER + 0x12)
+#define TRC_HVM_HLT (TRC_HVM_HANDLER + 0x13)
+#define TRC_HVM_INVLPG (TRC_HVM_HANDLER + 0x14)
+#define TRC_HVM_INVLPG64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x14)
+#define TRC_HVM_MCE (TRC_HVM_HANDLER + 0x15)
+#define TRC_HVM_IOPORT_READ (TRC_HVM_HANDLER + 0x16)
+#define TRC_HVM_IOMEM_READ (TRC_HVM_HANDLER + 0x17)
+#define TRC_HVM_CLTS (TRC_HVM_HANDLER + 0x18)
+#define TRC_HVM_LMSW (TRC_HVM_HANDLER + 0x19)
+#define TRC_HVM_LMSW64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x19)
+#define TRC_HVM_RDTSC (TRC_HVM_HANDLER + 0x1a)
+#define TRC_HVM_INTR_WINDOW (TRC_HVM_HANDLER + 0x20)
+#define TRC_HVM_NPF (TRC_HVM_HANDLER + 0x21)
+#define TRC_HVM_REALMODE_EMULATE (TRC_HVM_HANDLER + 0x22)
+#define TRC_HVM_TRAP (TRC_HVM_HANDLER + 0x23)
+#define TRC_HVM_TRAP_DEBUG (TRC_HVM_HANDLER + 0x24)
+#define TRC_HVM_VLAPIC (TRC_HVM_HANDLER + 0x25)
+
+#define TRC_HVM_IOPORT_WRITE (TRC_HVM_HANDLER + 0x216)
+#define TRC_HVM_IOMEM_WRITE (TRC_HVM_HANDLER + 0x217)
+
+/* Trace events for emulated devices */
+#define TRC_HVM_EMUL_HPET_START_TIMER (TRC_HVM_EMUL + 0x1)
+#define TRC_HVM_EMUL_PIT_START_TIMER (TRC_HVM_EMUL + 0x2)
+#define TRC_HVM_EMUL_RTC_START_TIMER (TRC_HVM_EMUL + 0x3)
+#define TRC_HVM_EMUL_LAPIC_START_TIMER (TRC_HVM_EMUL + 0x4)
+#define TRC_HVM_EMUL_HPET_STOP_TIMER (TRC_HVM_EMUL + 0x5)
+#define TRC_HVM_EMUL_PIT_STOP_TIMER (TRC_HVM_EMUL + 0x6)
+#define TRC_HVM_EMUL_RTC_STOP_TIMER (TRC_HVM_EMUL + 0x7)
+#define TRC_HVM_EMUL_LAPIC_STOP_TIMER (TRC_HVM_EMUL + 0x8)
+#define TRC_HVM_EMUL_PIT_TIMER_CB (TRC_HVM_EMUL + 0x9)
+#define TRC_HVM_EMUL_LAPIC_TIMER_CB (TRC_HVM_EMUL + 0xA)
+#define TRC_HVM_EMUL_PIC_INT_OUTPUT (TRC_HVM_EMUL + 0xB)
+#define TRC_HVM_EMUL_PIC_KICK (TRC_HVM_EMUL + 0xC)
+#define TRC_HVM_EMUL_PIC_INTACK (TRC_HVM_EMUL + 0xD)
+#define TRC_HVM_EMUL_PIC_POSEDGE (TRC_HVM_EMUL + 0xE)
+#define TRC_HVM_EMUL_PIC_NEGEDGE (TRC_HVM_EMUL + 0xF)
+#define TRC_HVM_EMUL_PIC_PEND_IRQ_CALL (TRC_HVM_EMUL + 0x10)
+#define TRC_HVM_EMUL_LAPIC_PIC_INTR (TRC_HVM_EMUL + 0x11)
+
+/* trace events for per class */
+#define TRC_PM_FREQ_CHANGE (TRC_HW_PM + 0x01)
+#define TRC_PM_IDLE_ENTRY (TRC_HW_PM + 0x02)
+#define TRC_PM_IDLE_EXIT (TRC_HW_PM + 0x03)
+
+/* Trace events for IRQs */
+#define TRC_HW_IRQ_MOVE_CLEANUP_DELAY (TRC_HW_IRQ + 0x1)
+#define TRC_HW_IRQ_MOVE_CLEANUP (TRC_HW_IRQ + 0x2)
+#define TRC_HW_IRQ_BIND_VECTOR (TRC_HW_IRQ + 0x3)
+#define TRC_HW_IRQ_CLEAR_VECTOR (TRC_HW_IRQ + 0x4)
+#define TRC_HW_IRQ_MOVE_FINISH (TRC_HW_IRQ + 0x5)
+#define TRC_HW_IRQ_ASSIGN_VECTOR (TRC_HW_IRQ + 0x6)
+#define TRC_HW_IRQ_UNMAPPED_VECTOR (TRC_HW_IRQ + 0x7)
+#define TRC_HW_IRQ_HANDLED (TRC_HW_IRQ + 0x8)
+
+/*
+ * Event Flags
+ *
+ * Some events (e.g, TRC_PV_TRAP and TRC_HVM_IOMEM_READ) have multiple
+ * record formats. These event flags distinguish between the
+ * different formats.
+ */
+#define TRC_64_FLAG 0x100 /* Addresses are 64 bits (instead of 32 bits) */
+
+/* This structure represents a single trace buffer record. */
+struct t_rec {
+ uint32_t event:28;
+ uint32_t extra_u32:3; /* # entries in trailing extra_u32[] array */
+ uint32_t cycles_included:1; /* u.cycles or u.no_cycles? */
+ union {
+ struct {
+ uint32_t cycles_lo, cycles_hi; /* cycle counter timestamp */
+ uint32_t extra_u32[7]; /* event data items */
+ } cycles;
+ struct {
+ uint32_t extra_u32[7]; /* event data items */
+ } nocycles;
+ } u;
+};
+
+/*
+ * This structure contains the metadata for a single trace buffer. The head
+ * field, indexes into an array of struct t_rec's.
+ */
+struct t_buf {
+ /* Assume the data buffer size is X. X is generally not a power of 2.
+ * CONS and PROD are incremented modulo (2*X):
+ * 0 <= cons < 2*X
+ * 0 <= prod < 2*X
+ * This is done because addition modulo X breaks at 2^32 when X is not a
+ * power of 2:
+ * (((2^32 - 1) % X) + 1) % X != (2^32) % X
+ */
+ uint32_t cons; /* Offset of next item to be consumed by control tools. */
+ uint32_t prod; /* Offset of next item to be produced by Xen. */
+ /* Records follow immediately after the meta-data header. */
+};
+
+/* Structure used to pass MFNs to the trace buffers back to trace consumers.
+ * Offset is an offset into the mapped structure where the mfn list will be held.
+ * MFNs will be at ((ULONG_PTR *)(t_info))+(t_info->cpu_offset[cpu]).
+ */
+struct t_info {
+ uint16_t tbuf_size; /* Size in pages of each trace buffer */
+ uint16_t mfn_offset[]; /* Offset within t_info structure of the page list per cpu */
+ /* MFN lists immediately after the header */
+};
+
+#endif /* __XEN_PUBLIC_TRACE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+/******************************************************************************
+ * xen-compat.h
+ *
+ * Guest OS interface to Xen. Compatibility layer.
+ *
+ * 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.
+ *
+ * Copyright (c) 2006, Christian Limpach
+ */
+
+#ifndef __XEN_PUBLIC_XEN_COMPAT_H__
+#define __XEN_PUBLIC_XEN_COMPAT_H__
+
+#define __XEN_LATEST_INTERFACE_VERSION__ 0x00040700
+
+#if defined(__XEN__) || defined(__XEN_TOOLS__)
+/* Xen is built with matching headers and implements the latest interface. */
+#define __XEN_INTERFACE_VERSION__ __XEN_LATEST_INTERFACE_VERSION__
+#elif !defined(__XEN_INTERFACE_VERSION__)
+/* Guests which do not specify a version get the legacy interface. */
+#define __XEN_INTERFACE_VERSION__ 0x00000000
+#endif
+
+#if __XEN_INTERFACE_VERSION__ > __XEN_LATEST_INTERFACE_VERSION__
+#error "These header files do not support the requested interface version."
+#endif
+
+#endif /* __XEN_PUBLIC_XEN_COMPAT_H__ */
--- /dev/null
+/******************************************************************************
+ * xen.h
+ *
+ * Guest OS interface to Xen.
+ *
+ * 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.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_XEN_H__
+#define __XEN_PUBLIC_XEN_H__
+
+#include "xen-compat.h"
+
+#if defined(__i386__) || defined(__x86_64__)
+#include "arch-x86/xen.h"
+#elif defined(__arm__) || defined (__aarch64__)
+#include "arch-arm.h"
+#else
+#error "Unsupported architecture"
+#endif
+
+#ifndef __ASSEMBLY__
+/* Guest handles for primitive C types. */
+DEFINE_XEN_GUEST_HANDLE(char);
+__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
+DEFINE_XEN_GUEST_HANDLE(int);
+__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int);
+#if __XEN_INTERFACE_VERSION__ < 0x00040300
+DEFINE_XEN_GUEST_HANDLE(LONG_PTR);
+__DEFINE_XEN_GUEST_HANDLE(ulong, ULONG_PTR);
+#endif
+DEFINE_XEN_GUEST_HANDLE(void);
+
+DEFINE_XEN_GUEST_HANDLE(uint64_t);
+DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
+DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
+
+/* Turn a plain number into a C unsigned (LONG_PTR) constant. */
+#define __xen_mk_uint(x) x ## U
+#define __xen_mk_ulong(x) x ## UL
+#define xen_mk_uint(x) __xen_mk_uint(x)
+#define xen_mk_ulong(x) __xen_mk_ulong(x)
+
+#else
+
+/* In assembly code we cannot use C numeric constant suffixes. */
+#define xen_mk_uint(x) x
+#define xen_mk_ulong(x) x
+
+#endif
+
+/*
+ * HYPERCALLS
+ */
+
+/* `incontents 100 hcalls List of hypercalls
+ * ` enum hypercall_num { // __HYPERVISOR_* => HYPERVISOR_*()
+ */
+
+#define __HYPERVISOR_set_trap_table 0
+#define __HYPERVISOR_mmu_update 1
+#define __HYPERVISOR_set_gdt 2
+#define __HYPERVISOR_stack_switch 3
+#define __HYPERVISOR_set_callbacks 4
+#define __HYPERVISOR_fpu_taskswitch 5
+#define __HYPERVISOR_sched_op_compat 6 /* compat since 0x00030101 */
+#define __HYPERVISOR_platform_op 7
+#define __HYPERVISOR_set_debugreg 8
+#define __HYPERVISOR_get_debugreg 9
+#define __HYPERVISOR_update_descriptor 10
+#define __HYPERVISOR_memory_op 12
+#define __HYPERVISOR_multicall 13
+#define __HYPERVISOR_update_va_mapping 14
+#define __HYPERVISOR_set_timer_op 15
+#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */
+#define __HYPERVISOR_xen_version 17
+#define __HYPERVISOR_console_io 18
+#define __HYPERVISOR_physdev_op_compat 19 /* compat since 0x00030202 */
+#define __HYPERVISOR_grant_table_op 20
+#define __HYPERVISOR_vm_assist 21
+#define __HYPERVISOR_update_va_mapping_otherdomain 22
+#define __HYPERVISOR_iret 23 /* x86 only */
+#define __HYPERVISOR_vcpu_op 24
+#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
+#define __HYPERVISOR_mmuext_op 26
+#define __HYPERVISOR_xsm_op 27
+#define __HYPERVISOR_nmi_op 28
+#define __HYPERVISOR_sched_op 29
+#define __HYPERVISOR_callback_op 30
+#define __HYPERVISOR_xenoprof_op 31
+#define __HYPERVISOR_event_channel_op 32
+#define __HYPERVISOR_physdev_op 33
+#define __HYPERVISOR_hvm_op 34
+#define __HYPERVISOR_sysctl 35
+#define __HYPERVISOR_domctl 36
+#define __HYPERVISOR_kexec_op 37
+#define __HYPERVISOR_tmem_op 38
+#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */
+#define __HYPERVISOR_xenpmu_op 40
+
+/* Architecture-specific hypercall definitions. */
+#define __HYPERVISOR_arch_0 48
+#define __HYPERVISOR_arch_1 49
+#define __HYPERVISOR_arch_2 50
+#define __HYPERVISOR_arch_3 51
+#define __HYPERVISOR_arch_4 52
+#define __HYPERVISOR_arch_5 53
+#define __HYPERVISOR_arch_6 54
+#define __HYPERVISOR_arch_7 55
+
+/* ` } */
+
+/*
+ * HYPERCALL COMPATIBILITY.
+ */
+
+/* New sched_op hypercall introduced in 0x00030101. */
+#if __XEN_INTERFACE_VERSION__ < 0x00030101
+#undef __HYPERVISOR_sched_op
+#define __HYPERVISOR_sched_op __HYPERVISOR_sched_op_compat
+#endif
+
+/* New event-channel and physdev hypercalls introduced in 0x00030202. */
+#if __XEN_INTERFACE_VERSION__ < 0x00030202
+#undef __HYPERVISOR_event_channel_op
+#define __HYPERVISOR_event_channel_op __HYPERVISOR_event_channel_op_compat
+#undef __HYPERVISOR_physdev_op
+#define __HYPERVISOR_physdev_op __HYPERVISOR_physdev_op_compat
+#endif
+
+/* New platform_op hypercall introduced in 0x00030204. */
+#if __XEN_INTERFACE_VERSION__ < 0x00030204
+#define __HYPERVISOR_dom0_op __HYPERVISOR_platform_op
+#endif
+
+/*
+ * VIRTUAL INTERRUPTS
+ *
+ * Virtual interrupts that a guest OS may receive from Xen.
+ *
+ * In the side comments, 'V.' denotes a per-VCPU VIRQ while 'G.' denotes a
+ * global VIRQ. The former can be bound once per VCPU and cannot be re-bound.
+ * The latter can be allocated only once per guest: they must initially be
+ * allocated to VCPU0 but can subsequently be re-bound.
+ */
+/* ` enum virq { */
+#define VIRQ_TIMER 0 /* V. Timebase update, and/or requested timeout. */
+#define VIRQ_DEBUG 1 /* V. Request guest to dump debug info. */
+#define VIRQ_CONSOLE 2 /* G. (DOM0) Bytes received on emergency console. */
+#define VIRQ_DOM_EXC 3 /* G. (DOM0) Exceptional event for some domain. */
+#define VIRQ_TBUF 4 /* G. (DOM0) Trace buffer has records available. */
+#define VIRQ_DEBUGGER 6 /* G. (DOM0) A domain has paused for debugging. */
+#define VIRQ_XENOPROF 7 /* V. XenOprofile interrupt: new sample available */
+#define VIRQ_CON_RING 8 /* G. (DOM0) Bytes received on console */
+#define VIRQ_PCPU_STATE 9 /* G. (DOM0) PCPU state changed */
+#define VIRQ_MEM_EVENT 10 /* G. (DOM0) A memory event has occured */
+#define VIRQ_XC_RESERVED 11 /* G. Reserved for XenClient */
+#define VIRQ_ENOMEM 12 /* G. (DOM0) Low on heap memory */
+#define VIRQ_XENPMU 13 /* V. PMC interrupt */
+
+/* Architecture-specific VIRQ definitions. */
+#define VIRQ_ARCH_0 16
+#define VIRQ_ARCH_1 17
+#define VIRQ_ARCH_2 18
+#define VIRQ_ARCH_3 19
+#define VIRQ_ARCH_4 20
+#define VIRQ_ARCH_5 21
+#define VIRQ_ARCH_6 22
+#define VIRQ_ARCH_7 23
+/* ` } */
+
+#define NR_VIRQS 24
+
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_mmu_update(const struct mmu_update reqs[],
+ * ` unsigned count, unsigned *done_out,
+ * ` unsigned foreigndom)
+ * `
+ * @reqs is an array of mmu_update_t structures ((ptr, val) pairs).
+ * @count is the length of the above array.
+ * @pdone is an output parameter indicating number of completed operations
+ * @foreigndom[15:0]: FD, the expected owner of data pages referenced in this
+ * hypercall invocation. Can be DOMID_SELF.
+ * @foreigndom[31:16]: PFD, the expected owner of pagetable pages referenced
+ * in this hypercall invocation. The value of this field
+ * (x) encodes the PFD as follows:
+ * x == 0 => PFD == DOMID_SELF
+ * x != 0 => PFD == x - 1
+ *
+ * Sub-commands: ptr[1:0] specifies the appropriate MMU_* command.
+ * -------------
+ * ptr[1:0] == MMU_NORMAL_PT_UPDATE:
+ * Updates an entry in a page table belonging to PFD. If updating an L1 table,
+ * and the new table entry is valid/present, the mapped frame must belong to
+ * FD. If attempting to map an I/O page then the caller assumes the privilege
+ * of the FD.
+ * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller.
+ * FD == DOMID_XEN: Map restricted areas of Xen's heap space.
+ * ptr[:2] -- Machine address of the page-table entry to modify.
+ * val -- Value to write.
+ *
+ * There also certain implicit requirements when using this hypercall. The
+ * pages that make up a pagetable must be mapped read-only in the guest.
+ * This prevents uncontrolled guest updates to the pagetable. Xen strictly
+ * enforces this, and will disallow any pagetable update which will end up
+ * mapping pagetable page RW, and will disallow using any writable page as a
+ * pagetable. In practice it means that when constructing a page table for a
+ * process, thread, etc, we MUST be very dilligient in following these rules:
+ * 1). Start with top-level page (PGD or in Xen language: L4). Fill out
+ * the entries.
+ * 2). Keep on going, filling out the upper (PUD or L3), and middle (PMD
+ * or L2).
+ * 3). Start filling out the PTE table (L1) with the PTE entries. Once
+ * done, make sure to set each of those entries to RO (so writeable bit
+ * is unset). Once that has been completed, set the PMD (L2) for this
+ * PTE table as RO.
+ * 4). When completed with all of the PMD (L2) entries, and all of them have
+ * been set to RO, make sure to set RO the PUD (L3). Do the same
+ * operation on PGD (L4) pagetable entries that have a PUD (L3) entry.
+ * 5). Now before you can use those pages (so setting the cr3), you MUST also
+ * pin them so that the hypervisor can verify the entries. This is done
+ * via the HYPERVISOR_mmuext_op(MMUEXT_PIN_L4_TABLE, guest physical frame
+ * number of the PGD (L4)). And this point the HYPERVISOR_mmuext_op(
+ * MMUEXT_NEW_BASEPTR, guest physical frame number of the PGD (L4)) can be
+ * issued.
+ * For 32-bit guests, the L4 is not used (as there is less pagetables), so
+ * instead use L3.
+ * At this point the pagetables can be modified using the MMU_NORMAL_PT_UPDATE
+ * hypercall. Also if so desired the OS can also try to write to the PTE
+ * and be trapped by the hypervisor (as the PTE entry is RO).
+ *
+ * To deallocate the pages, the operations are the reverse of the steps
+ * mentioned above. The argument is MMUEXT_UNPIN_TABLE for all levels and the
+ * pagetable MUST not be in use (meaning that the cr3 is not set to it).
+ *
+ * ptr[1:0] == MMU_MACHPHYS_UPDATE:
+ * Updates an entry in the machine->pseudo-physical mapping table.
+ * ptr[:2] -- Machine address within the frame whose mapping to modify.
+ * The frame must belong to the FD, if one is specified.
+ * val -- Value to write into the mapping entry.
+ *
+ * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD:
+ * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed
+ * with those in @val.
+ *
+ * @val is usually the machine frame number along with some attributes.
+ * The attributes by default follow the architecture defined bits. Meaning that
+ * if this is a X86_64 machine and four page table layout is used, the layout
+ * of val is:
+ * - 63 if set means No execute (NX)
+ * - 46-13 the machine frame number
+ * - 12 available for guest
+ * - 11 available for guest
+ * - 10 available for guest
+ * - 9 available for guest
+ * - 8 global
+ * - 7 PAT (PSE is disabled, must use hypercall to make 4MB or 2MB pages)
+ * - 6 dirty
+ * - 5 accessed
+ * - 4 page cached disabled
+ * - 3 page write through
+ * - 2 userspace accessible
+ * - 1 writeable
+ * - 0 present
+ *
+ * The one bits that does not fit with the default layout is the PAGE_PSE
+ * also called PAGE_PAT). The MMUEXT_[UN]MARK_SUPER arguments to the
+ * HYPERVISOR_mmuext_op serve as mechanism to set a pagetable to be 4MB
+ * (or 2MB) instead of using the PAGE_PSE bit.
+ *
+ * The reason that the PAGE_PSE (bit 7) is not being utilized is due to Xen
+ * using it as the Page Attribute Table (PAT) bit - for details on it please
+ * refer to Intel SDM 10.12. The PAT allows to set the caching attributes of
+ * pages instead of using MTRRs.
+ *
+ * The PAT MSR is as follows (it is a 64-bit value, each entry is 8 bits):
+ * PAT4 PAT0
+ * +-----+-----+----+----+----+-----+----+----+
+ * | UC | UC- | WC | WB | UC | UC- | WC | WB | <= Linux
+ * +-----+-----+----+----+----+-----+----+----+
+ * | UC | UC- | WT | WB | UC | UC- | WT | WB | <= BIOS (default when machine boots)
+ * +-----+-----+----+----+----+-----+----+----+
+ * | rsv | rsv | WP | WC | UC | UC- | WT | WB | <= Xen
+ * +-----+-----+----+----+----+-----+----+----+
+ *
+ * The lookup of this index table translates to looking up
+ * Bit 7, Bit 4, and Bit 3 of val entry:
+ *
+ * PAT/PSE (bit 7) ... PCD (bit 4) .. PWT (bit 3).
+ *
+ * If all bits are off, then we are using PAT0. If bit 3 turned on,
+ * then we are using PAT1, if bit 3 and bit 4, then PAT2..
+ *
+ * As you can see, the Linux PAT1 translates to PAT4 under Xen. Which means
+ * that if a guest that follows Linux's PAT setup and would like to set Write
+ * Combined on pages it MUST use PAT4 entry. Meaning that Bit 7 (PAGE_PAT) is
+ * set. For example, under Linux it only uses PAT0, PAT1, and PAT2 for the
+ * caching as:
+ *
+ * WB = none (so PAT0)
+ * WC = PWT (bit 3 on)
+ * UC = PWT | PCD (bit 3 and 4 are on).
+ *
+ * To make it work with Xen, it needs to translate the WC bit as so:
+ *
+ * PWT (so bit 3 on) --> PAT (so bit 7 is on) and clear bit 3
+ *
+ * And to translate back it would:
+ *
+ * PAT (bit 7 on) --> PWT (bit 3 on) and clear bit 7.
+ */
+#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
+#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */
+#define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */
+
+/*
+ * MMU EXTENDED OPERATIONS
+ *
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_mmuext_op(mmuext_op_t uops[],
+ * ` unsigned int count,
+ * ` unsigned int *pdone,
+ * ` unsigned int foreigndom)
+ */
+/* HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ *
+ * cmd: MMUEXT_(UN)PIN_*_TABLE
+ * mfn: Machine frame number to be (un)pinned as a p.t. page.
+ * The frame must belong to the FD, if one is specified.
+ *
+ * cmd: MMUEXT_NEW_BASEPTR
+ * mfn: Machine frame number of new page-table base to install in MMU.
+ *
+ * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only]
+ * mfn: Machine frame number of new page-table base to install in MMU
+ * when in user space.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_LOCAL
+ * No additional arguments. Flushes local TLB.
+ *
+ * cmd: MMUEXT_INVLPG_LOCAL
+ * linear_addr: Linear address to be flushed from the local TLB.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_MULTI
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_INVLPG_MULTI
+ * linear_addr: Linear address to be flushed.
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_ALL
+ * No additional arguments. Flushes all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_INVLPG_ALL
+ * linear_addr: Linear address to be flushed from all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_FLUSH_CACHE
+ * No additional arguments. Writes back and flushes cache contents.
+ *
+ * cmd: MMUEXT_FLUSH_CACHE_GLOBAL
+ * No additional arguments. Writes back and flushes cache contents
+ * on all CPUs in the system.
+ *
+ * cmd: MMUEXT_SET_LDT
+ * linear_addr: Linear address of LDT base (NB. must be page-aligned).
+ * nr_ents: Number of entries in LDT.
+ *
+ * cmd: MMUEXT_CLEAR_PAGE
+ * mfn: Machine frame number to be cleared.
+ *
+ * cmd: MMUEXT_COPY_PAGE
+ * mfn: Machine frame number of the destination page.
+ * src_mfn: Machine frame number of the source page.
+ *
+ * cmd: MMUEXT_[UN]MARK_SUPER
+ * mfn: Machine frame number of head of superpage to be [un]marked.
+ */
+/* ` enum mmuext_cmd { */
+#define MMUEXT_PIN_L1_TABLE 0
+#define MMUEXT_PIN_L2_TABLE 1
+#define MMUEXT_PIN_L3_TABLE 2
+#define MMUEXT_PIN_L4_TABLE 3
+#define MMUEXT_UNPIN_TABLE 4
+#define MMUEXT_NEW_BASEPTR 5
+#define MMUEXT_TLB_FLUSH_LOCAL 6
+#define MMUEXT_INVLPG_LOCAL 7
+#define MMUEXT_TLB_FLUSH_MULTI 8
+#define MMUEXT_INVLPG_MULTI 9
+#define MMUEXT_TLB_FLUSH_ALL 10
+#define MMUEXT_INVLPG_ALL 11
+#define MMUEXT_FLUSH_CACHE 12
+#define MMUEXT_SET_LDT 13
+#define MMUEXT_NEW_USER_BASEPTR 15
+#define MMUEXT_CLEAR_PAGE 16
+#define MMUEXT_COPY_PAGE 17
+#define MMUEXT_FLUSH_CACHE_GLOBAL 18
+#define MMUEXT_MARK_SUPER 19
+#define MMUEXT_UNMARK_SUPER 20
+/* ` } */
+
+#ifndef __ASSEMBLY__
+struct mmuext_op {
+ unsigned int cmd; /* => enum mmuext_cmd */
+ union {
+ /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR
+ * CLEAR_PAGE, COPY_PAGE, [UN]MARK_SUPER */
+ xen_pfn_t mfn;
+ /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
+ ULONG_PTR linear_addr;
+ } arg1;
+ union {
+ /* SET_LDT */
+ unsigned int nr_ents;
+ /* TLB_FLUSH_MULTI, INVLPG_MULTI */
+#if __XEN_INTERFACE_VERSION__ >= 0x00030205
+ XEN_GUEST_HANDLE(const_void) vcpumask;
+#else
+ const void *vcpumask;
+#endif
+ /* COPY_PAGE */
+ xen_pfn_t src_mfn;
+ } arg2;
+};
+typedef struct mmuext_op mmuext_op_t;
+DEFINE_XEN_GUEST_HANDLE(mmuext_op_t);
+#endif
+
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_update_va_mapping(ULONG_PTR va, u64 val,
+ * ` enum uvm_flags flags)
+ * `
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_update_va_mapping_otherdomain(ULONG_PTR va, u64 val,
+ * ` enum uvm_flags flags,
+ * ` domid_t domid)
+ * `
+ * ` @va: The virtual address whose mapping we want to change
+ * ` @val: The new page table entry, must contain a machine address
+ * ` @flags: Control TLB flushes
+ */
+/* These are passed as 'flags' to update_va_mapping. They can be ORed. */
+/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap. */
+/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer. */
+/* ` enum uvm_flags { */
+#define UVMF_NONE (xen_mk_ulong(0)<<0) /* No flushing at all. */
+#define UVMF_TLB_FLUSH (xen_mk_ulong(1)<<0) /* Flush entire TLB(s). */
+#define UVMF_INVLPG (xen_mk_ulong(2)<<0) /* Flush only one entry. */
+#define UVMF_FLUSHTYPE_MASK (xen_mk_ulong(3)<<0)
+#define UVMF_MULTI (xen_mk_ulong(0)<<2) /* Flush subset of TLBs. */
+#define UVMF_LOCAL (xen_mk_ulong(0)<<2) /* Flush local TLB. */
+#define UVMF_ALL (xen_mk_ulong(1)<<2) /* Flush all TLBs. */
+/* ` } */
+
+/*
+ * Commands to HYPERVISOR_console_io().
+ */
+#define CONSOLEIO_write 0
+#define CONSOLEIO_read 1
+
+/*
+ * Commands to HYPERVISOR_vm_assist().
+ */
+#define VMASST_CMD_enable 0
+#define VMASST_CMD_disable 1
+
+/* x86/32 guests: simulate full 4GB segment limits. */
+#define VMASST_TYPE_4gb_segments 0
+
+/* x86/32 guests: trap (vector 15) whenever above vmassist is used. */
+#define VMASST_TYPE_4gb_segments_notify 1
+
+/*
+ * x86 guests: support writes to bottom-level PTEs.
+ * NB1. Page-directory entries cannot be written.
+ * NB2. Guest must continue to remove all writable mappings of PTEs.
+ */
+#define VMASST_TYPE_writable_pagetables 2
+
+/* x86/PAE guests: support PDPTs above 4GB. */
+#define VMASST_TYPE_pae_extended_cr3 3
+
+/*
+ * x86 guests: Sane behaviour for virtual iopl
+ * - virtual iopl updated from do_iret() hypercalls.
+ * - virtual iopl reported in bounce frames.
+ * - guest kernels assumed to be level 0 for the purpose of iopl checks.
+ */
+#define VMASST_TYPE_architectural_iopl 4
+
+/*
+ * x86/64 guests: strictly hide M2P from user mode.
+ * This allows the guest to control respective hypervisor behavior:
+ * - when not set, L4 tables get created with the respective slot blank,
+ * and whenever the L4 table gets used as a kernel one the missing
+ * mapping gets inserted,
+ * - when set, L4 tables get created with the respective slot initialized
+ * as before, and whenever the L4 table gets used as a user one the
+ * mapping gets zapped.
+ */
+#define VMASST_TYPE_m2p_strict 32
+
+#if __XEN_INTERFACE_VERSION__ < 0x00040600
+#define MAX_VMASST_TYPE 3
+#endif
+
+/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */
+#define DOMID_FIRST_RESERVED xen_mk_uint(0x7FF0)
+
+/* DOMID_SELF is used in certain contexts to refer to oneself. */
+#define DOMID_SELF xen_mk_uint(0x7FF0)
+
+/*
+ * DOMID_IO is used to restrict page-table updates to mapping I/O memory.
+ * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO
+ * is useful to ensure that no mappings to the OS's own heap are accidentally
+ * installed. (e.g., in Linux this could cause havoc as reference counts
+ * aren't adjusted on the I/O-mapping code path).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can
+ * be specified by any calling domain.
+ */
+#define DOMID_IO xen_mk_uint(0x7FF1)
+
+/*
+ * DOMID_XEN is used to allow privileged domains to map restricted parts of
+ * Xen's heap space (e.g., the machine_to_phys table).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if
+ * the caller is privileged.
+ */
+#define DOMID_XEN xen_mk_uint(0x7FF2)
+
+/*
+ * DOMID_COW is used as the owner of sharable pages */
+#define DOMID_COW xen_mk_uint(0x7FF3)
+
+/* DOMID_INVALID is used to identify pages with unknown owner. */
+#define DOMID_INVALID xen_mk_uint(0x7FF4)
+
+/* Idle domain. */
+#define DOMID_IDLE xen_mk_uint(0x7FFF)
+
+#ifndef __ASSEMBLY__
+
+typedef uint16_t domid_t;
+
+/*
+ * Send an array of these to HYPERVISOR_mmu_update().
+ * NB. The fields are natural pointer/address size for this architecture.
+ */
+struct mmu_update {
+ uint64_t ptr; /* Machine address of PTE. */
+ uint64_t val; /* New contents of PTE. */
+};
+typedef struct mmu_update mmu_update_t;
+DEFINE_XEN_GUEST_HANDLE(mmu_update_t);
+
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_multicall(multicall_entry_t call_list[],
+ * ` uint32_t nr_calls);
+ *
+ * NB. The fields are logically the natural register size for this
+ * architecture. In cases where xen_ulong_t is larger than this then
+ * any unused bits in the upper portion must be zero.
+ */
+struct multicall_entry {
+ xen_ulong_t op, result;
+ xen_ulong_t args[6];
+};
+typedef struct multicall_entry multicall_entry_t;
+DEFINE_XEN_GUEST_HANDLE(multicall_entry_t);
+
+#if __XEN_INTERFACE_VERSION__ < 0x00040400
+/*
+ * Event channel endpoints per domain (when using the 2-level ABI):
+ * 1024 if a LONG_PTR is 32 bits; 4096 if a LONG_PTR is 64 bits.
+ */
+#define NR_EVENT_CHANNELS EVTCHN_2L_NR_CHANNELS
+#endif
+
+struct vcpu_time_info {
+ /*
+ * Updates to the following values are preceded and followed by an
+ * increment of 'version'. The guest can therefore detect updates by
+ * looking for changes to 'version'. If the least-significant bit of
+ * the version number is set then an update is in progress and the guest
+ * must wait to read a consistent set of values.
+ * The correct way to interact with the version number is similar to
+ * Linux's seqlock: see the implementations of read_seqbegin/read_seqretry.
+ */
+ uint32_t version;
+ uint32_t pad0;
+ uint64_t tsc_timestamp; /* TSC at last update of time vals. */
+ uint64_t system_time; /* Time, in nanosecs, since boot. */
+ /*
+ * Current system time:
+ * system_time +
+ * ((((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul) >> 32)
+ * CPU frequency (Hz):
+ * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift
+ */
+ uint32_t tsc_to_system_mul;
+ int8_t tsc_shift;
+#if __XEN_INTERFACE_VERSION__ > 0x040600
+ uint8_t flags;
+ uint8_t pad1[2];
+#else
+ int8_t pad1[3];
+#endif
+}; /* 32 bytes */
+typedef struct vcpu_time_info vcpu_time_info_t;
+
+#define XEN_PVCLOCK_TSC_STABLE_BIT (1 << 0)
+#define XEN_PVCLOCK_GUEST_STOPPED (1 << 1)
+
+struct vcpu_info {
+ /*
+ * 'evtchn_upcall_pending' is written non-zero by Xen to indicate
+ * a pending notification for a particular VCPU. It is then cleared
+ * by the guest OS /before/ checking for pending work, thus avoiding
+ * a set-and-check race. Note that the mask is only accessed by Xen
+ * on the CPU that is currently hosting the VCPU. This means that the
+ * pending and mask flags can be updated by the guest without special
+ * synchronisation (i.e., no need for the x86 LOCK prefix).
+ * This may seem suboptimal because if the pending flag is set by
+ * a different CPU then an IPI may be scheduled even when the mask
+ * is set. However, note:
+ * 1. The task of 'interrupt holdoff' is covered by the per-event-
+ * channel mask bits. A 'noisy' event that is continually being
+ * triggered can be masked at source at this very precise
+ * granularity.
+ * 2. The main purpose of the per-VCPU mask is therefore to restrict
+ * reentrant execution: whether for concurrency control, or to
+ * prevent unbounded stack usage. Whatever the purpose, we expect
+ * that the mask will be asserted only for short periods at a time,
+ * and so the likelihood of a 'spurious' IPI is suitably small.
+ * The mask is read before making an event upcall to the guest: a
+ * non-zero mask therefore guarantees that the VCPU will not receive
+ * an upcall activation. The mask is cleared when the VCPU requests
+ * to block: this avoids wakeup-waiting races.
+ */
+ uint8_t evtchn_upcall_pending;
+#ifdef XEN_HAVE_PV_UPCALL_MASK
+ uint8_t evtchn_upcall_mask;
+#else /* XEN_HAVE_PV_UPCALL_MASK */
+ uint8_t pad0;
+#endif /* XEN_HAVE_PV_UPCALL_MASK */
+ xen_ulong_t evtchn_pending_sel;
+ struct arch_vcpu_info arch;
+ struct vcpu_time_info time;
+}; /* 64 bytes (x86) */
+#ifndef __XEN__
+typedef struct vcpu_info vcpu_info_t;
+#endif
+
+/*
+ * `incontents 200 startofday_shared Start-of-day shared data structure
+ * Xen/kernel shared data -- pointer provided in start_info.
+ *
+ * This structure is defined to be both smaller than a page, and the
+ * only data on the shared page, but may vary in actual size even within
+ * compatible Xen versions; guests should not rely on the size
+ * of this structure remaining constant.
+ */
+struct shared_info {
+ struct vcpu_info vcpu_info[XEN_LEGACY_MAX_VCPUS];
+
+ /*
+ * A domain can create "event channels" on which it can send and receive
+ * asynchronous event notifications. There are three classes of event that
+ * are delivered by this mechanism:
+ * 1. Bi-directional inter- and intra-domain connections. Domains must
+ * arrange out-of-band to set up a connection (usually by allocating
+ * an unbound 'listener' port and avertising that via a storage service
+ * such as xenstore).
+ * 2. Physical interrupts. A domain with suitable hardware-access
+ * privileges can bind an event-channel port to a physical interrupt
+ * source.
+ * 3. Virtual interrupts ('events'). A domain can bind an event-channel
+ * port to a virtual interrupt source, such as the virtual-timer
+ * device or the emergency console.
+ *
+ * Event channels are addressed by a "port index". Each channel is
+ * associated with two bits of information:
+ * 1. PENDING -- notifies the domain that there is a pending notification
+ * to be processed. This bit is cleared by the guest.
+ * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING
+ * will cause an asynchronous upcall to be scheduled. This bit is only
+ * updated by the guest. It is read-only within Xen. If a channel
+ * becomes pending while the channel is masked then the 'edge' is lost
+ * (i.e., when the channel is unmasked, the guest must manually handle
+ * pending notifications as no upcall will be scheduled by Xen).
+ *
+ * To expedite scanning of pending notifications, any 0->1 pending
+ * transition on an unmasked channel causes a corresponding bit in a
+ * per-vcpu selector word to be set. Each bit in the selector covers a
+ * 'C LONG_PTR' in the PENDING bitfield array.
+ */
+ xen_ulong_t evtchn_pending[sizeof(xen_ulong_t) * 8];
+ xen_ulong_t evtchn_mask[sizeof(xen_ulong_t) * 8];
+
+ /*
+ * Wallclock time: updated only by control software. Guests should base
+ * their gettimeofday() syscall on this wallclock-base value.
+ */
+ uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */
+ uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
+ uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
+#if !defined(__i386__)
+ uint32_t wc_sec_hi;
+# define xen_wc_sec_hi wc_sec_hi
+#elif !defined(__XEN__) && !defined(__XEN_TOOLS__)
+# define xen_wc_sec_hi arch.wc_sec_hi
+#endif
+
+ struct arch_shared_info arch;
+
+};
+#ifndef __XEN__
+typedef struct shared_info shared_info_t;
+#endif
+
+/*
+ * `incontents 200 startofday Start-of-day memory layout
+ *
+ * 1. The domain is started within contiguous virtual-memory region.
+ * 2. The contiguous region ends on an aligned 4MB boundary.
+ * 3. This the order of bootstrap elements in the initial virtual region:
+ * a. relocated kernel image
+ * b. initial ram disk [mod_start, mod_len]
+ * (may be omitted)
+ * c. list of allocated page frames [mfn_list, nr_pages]
+ * (unless relocated due to XEN_ELFNOTE_INIT_P2M)
+ * d. start_info_t structure [register ESI (x86)]
+ * in case of dom0 this page contains the console info, too
+ * e. unless dom0: xenstore ring page
+ * f. unless dom0: console ring page
+ * g. bootstrap page tables [pt_base and CR3 (x86)]
+ * h. bootstrap stack [register ESP (x86)]
+ * 4. Bootstrap elements are packed together, but each is 4kB-aligned.
+ * 5. The list of page frames forms a contiguous 'pseudo-physical' memory
+ * layout for the domain. In particular, the bootstrap virtual-memory
+ * region is a 1:1 mapping to the first section of the pseudo-physical map.
+ * 6. All bootstrap elements are mapped read-writable for the guest OS. The
+ * only exception is the bootstrap page table, which is mapped read-only.
+ * 7. There is guaranteed to be at least 512kB padding after the final
+ * bootstrap element. If necessary, the bootstrap virtual region is
+ * extended by an extra 4MB to ensure this.
+ *
+ * Note: Prior to 25833:bb85bbccb1c9. ("x86/32-on-64 adjust Dom0 initial page
+ * table layout") a bug caused the pt_base (3.g above) and cr3 to not point
+ * to the start of the guest page tables (it was offset by two pages).
+ * This only manifested itself on 32-on-64 dom0 kernels and not 32-on-64 domU
+ * or 64-bit kernels of any colour. The page tables for a 32-on-64 dom0 got
+ * allocated in the order: 'first L1','first L2', 'first L3', so the offset
+ * to the page table base is by two pages back. The initial domain if it is
+ * 32-bit and runs under a 64-bit hypervisor should _NOT_ use two of the
+ * pages preceding pt_base and mark them as reserved/unused.
+ */
+#ifdef XEN_HAVE_PV_GUEST_ENTRY
+struct start_info {
+ /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */
+ char magic[32]; /* "xen-<version>-<platform>". */
+ ULONG_PTR nr_pages; /* Total pages allocated to this domain. */
+ ULONG_PTR shared_info; /* MACHINE address of shared info struct. */
+ uint32_t flags; /* SIF_xxx flags. */
+ xen_pfn_t store_mfn; /* MACHINE page number of shared page. */
+ uint32_t store_evtchn; /* Event channel for store communication. */
+ union {
+ struct {
+ xen_pfn_t mfn; /* MACHINE page number of console page. */
+ uint32_t evtchn; /* Event channel for console page. */
+ } domU;
+ struct {
+ uint32_t info_off; /* Offset of console_info struct. */
+ uint32_t info_size; /* Size of console_info struct from start.*/
+ } dom0;
+ } console;
+ /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */
+ ULONG_PTR pt_base; /* VIRTUAL address of page directory. */
+ ULONG_PTR nr_pt_frames; /* Number of bootstrap p.t. frames. */
+ ULONG_PTR mfn_list; /* VIRTUAL address of page-frame list. */
+ ULONG_PTR mod_start; /* VIRTUAL address of pre-loaded module */
+ /* (PFN of pre-loaded module if */
+ /* SIF_MOD_START_PFN set in flags). */
+ ULONG_PTR mod_len; /* Size (bytes) of pre-loaded module. */
+#define MAX_GUEST_CMDLINE 1024
+ int8_t cmd_line[MAX_GUEST_CMDLINE];
+ /* The pfn range here covers both page table and p->m table frames. */
+ ULONG_PTR first_p2m_pfn;/* 1st pfn forming initial P->M table. */
+ ULONG_PTR nr_p2m_frames;/* # of pfns forming initial P->M table. */
+};
+typedef struct start_info start_info_t;
+
+/*
+ * Start of day structure passed to PVH guests in %ebx.
+ *
+ * NOTE: nothing will be loaded at physical address 0, so a 0 value in any
+ * of the address fields should be treated as not present.
+ *
+ * 0 +----------------+
+ * | magic | Contains the magic value XEN_HVM_START_MAGIC_VALUE
+ * | | ("xEn3" with the 0x80 bit of the "E" set).
+ * 4 +----------------+
+ * | version | Version of this structure. Current version is 0. New
+ * | | versions are guaranteed to be backwards-compatible.
+ * 8 +----------------+
+ * | flags | SIF_xxx flags.
+ * 12 +----------------+
+ * | nr_modules | Number of modules passed to the kernel.
+ * 16 +----------------+
+ * | modlist_paddr | Physical address of an array of modules
+ * | | (layout of the structure below).
+ * 24 +----------------+
+ * | cmdline_paddr | Physical address of the command line,
+ * | | a zero-terminated ASCII string.
+ * 32 +----------------+
+ * | rsdp_paddr | Physical address of the RSDP ACPI data structure.
+ * 40 +----------------+
+ *
+ * The layout of each entry in the module structure is the following:
+ *
+ * 0 +----------------+
+ * | paddr | Physical address of the module.
+ * 8 +----------------+
+ * | size | Size of the module in bytes.
+ * 16 +----------------+
+ * | cmdline_paddr | Physical address of the command line,
+ * | | a zero-terminated ASCII string.
+ * 24 +----------------+
+ * | reserved |
+ * 32 +----------------+
+ *
+ * The address and sizes are always a 64bit little endian unsigned integer.
+ *
+ * NB: Xen on x86 will always try to place all the data below the 4GiB
+ * boundary.
+ */
+#define XEN_HVM_START_MAGIC_VALUE 0x336ec578
+
+/* New console union for dom0 introduced in 0x00030203. */
+#if __XEN_INTERFACE_VERSION__ < 0x00030203
+#define console_mfn console.domU.mfn
+#define console_evtchn console.domU.evtchn
+#endif
+#endif /* XEN_HAVE_PV_GUEST_ENTRY */
+
+/* These flags are passed in the 'flags' field of start_info_t. */
+#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */
+#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
+#define SIF_MULTIBOOT_MOD (1<<2) /* Is mod_start a multiboot module? */
+#define SIF_MOD_START_PFN (1<<3) /* Is mod_start a PFN? */
+#define SIF_VIRT_P2M_4TOOLS (1<<4) /* Do Xen tools understand a virt. mapped */
+ /* P->M making the 3 level tree obsolete? */
+#define SIF_PM_MASK (0xFF<<8) /* reserve 1 byte for xen-pm options */
+
+/*
+ * A multiboot module is a package containing modules very similar to a
+ * multiboot module array. The only differences are:
+ * - the array of module descriptors is by convention simply at the beginning
+ * of the multiboot module,
+ * - addresses in the module descriptors are based on the beginning of the
+ * multiboot module,
+ * - the number of modules is determined by a termination descriptor that has
+ * mod_start == 0.
+ *
+ * This permits to both build it statically and reference it in a configuration
+ * file, and let the PV guest easily rebase the addresses to virtual addresses
+ * and at the same time count the number of modules.
+ */
+struct xen_multiboot_mod_list
+{
+ /* Address of first byte of the module */
+ uint32_t mod_start;
+ /* Address of last byte of the module (inclusive) */
+ uint32_t mod_end;
+ /* Address of zero-terminated command line */
+ uint32_t cmdline;
+ /* Unused, must be zero */
+ uint32_t pad;
+};
+/*
+ * `incontents 200 startofday_dom0_console Dom0_console
+ *
+ * The console structure in start_info.console.dom0
+ *
+ * This structure includes a variety of information required to
+ * have a working VGA/VESA console.
+ */
+typedef struct dom0_vga_console_info {
+ uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */
+#define XEN_VGATYPE_TEXT_MODE_3 0x03
+#define XEN_VGATYPE_VESA_LFB 0x23
+#define XEN_VGATYPE_EFI_LFB 0x70
+
+ union {
+ struct {
+ /* Font height, in pixels. */
+ uint16_t font_height;
+ /* Cursor location (column, row). */
+ uint16_t cursor_x, cursor_y;
+ /* Number of rows and columns (dimensions in characters). */
+ uint16_t rows, columns;
+ } text_mode_3;
+
+ struct {
+ /* Width and height, in pixels. */
+ uint16_t width, height;
+ /* Bytes per scan line. */
+ uint16_t bytes_per_line;
+ /* Bits per pixel. */
+ uint16_t bits_per_pixel;
+ /* LFB physical address, and size (in units of 64kB). */
+ uint32_t lfb_base;
+ uint32_t lfb_size;
+ /* RGB mask offsets and sizes, as defined by VBE 1.2+ */
+ uint8_t red_pos, red_size;
+ uint8_t green_pos, green_size;
+ uint8_t blue_pos, blue_size;
+ uint8_t rsvd_pos, rsvd_size;
+#if __XEN_INTERFACE_VERSION__ >= 0x00030206
+ /* VESA capabilities (offset 0xa, VESA command 0x4f00). */
+ uint32_t gbl_caps;
+ /* Mode attributes (offset 0x0, VESA command 0x4f01). */
+ uint16_t mode_attrs;
+#endif
+ } vesa_lfb;
+ } u;
+} dom0_vga_console_info_t;
+#define xen_vga_console_info dom0_vga_console_info
+#define xen_vga_console_info_t dom0_vga_console_info_t
+
+typedef uint8_t xen_domain_handle_t[16];
+
+__DEFINE_XEN_GUEST_HANDLE(uint8, uint8_t);
+__DEFINE_XEN_GUEST_HANDLE(uint16, uint16_t);
+__DEFINE_XEN_GUEST_HANDLE(uint32, uint32_t);
+__DEFINE_XEN_GUEST_HANDLE(uint64, uint64_t);
+
+#endif /* !__ASSEMBLY__ */
+
+/* Default definitions for macros used by domctl/sysctl. */
+#if defined(__XEN__) || defined(__XEN_TOOLS__)
+
+#ifndef int64_aligned_t
+#define int64_aligned_t int64_t
+#endif
+#ifndef uint64_aligned_t
+#define uint64_aligned_t uint64_t
+#endif
+#ifndef XEN_GUEST_HANDLE_64
+#define XEN_GUEST_HANDLE_64(name) XEN_GUEST_HANDLE(name)
+#endif
+
+#ifndef __ASSEMBLY__
+struct xenctl_bitmap {
+ XEN_GUEST_HANDLE_64(uint8) bitmap;
+ uint32_t nr_bits;
+};
+#endif
+
+#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
+
+#endif /* __XEN_PUBLIC_XEN_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+#ifndef __XEN_ERRNO_H__
+#define __XEN_ERRNO_H__
+
+#ifndef __ASSEMBLY__
+
+#define XEN_ERRNO(name, value) name = value,
+enum {
+#include <public/errno.h>
+};
+
+#else /* !__ASSEMBLY__ */
+
+#define XEN_ERRNO(name, value) .equ name, value
+#include <public/errno.h>
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __XEN_ERRNO_H__ */
--- /dev/null
+#!python -u
+
+import os, sys
+import subprocess
+import glob
+from pprint import pprint
+
+def regenerate_kdfiles(filename, arch, pkg, source):
+ cwd = os.getcwd()
+ file = open(filename, 'w')
+ os.chdir(pkg + '/' + arch)
+ drivers = glob.glob('*.sys')
+ pprint(drivers)
+ for driver in drivers:
+ file.write("map\n")
+ file.write('\SystemRoot\System32\drivers\\' + driver + '\n')
+ file.write(source + '\\' + pkg + '\\' + arch + '\\' + driver + '\n')
+ file.write('\n')
+ os.chdir(cwd)
+ file.close()
+
+if __name__ == '__main__':
+ pkg = 'xenvkbd'
+ source = os.getcwd()
+ regenerate_kdfiles('kdfiles32.txt', 'x86', pkg, source)
+ regenerate_kdfiles('kdfiles64.txt', 'x64', pkg, source)
--- /dev/null
+call "%VS%\VC\vcvarsall.bat" x86
+@echo on
+msbuild.exe /m:1 /p:Configuration="%CONFIGURATION%" /p:Platform="%PLATFORM%" /t:"%TARGET%" %EXTRA% %FILE%
+if errorlevel 1 goto error
+exit 0
+
+:error
+exit 1
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#include <windows.h>
+#include <setupapi.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strsafe.h>
+#include <malloc.h>
+#include <assert.h>
+
+#include <version.h>
+#include <revision.h>
+
+__user_code;
+
+#define MAXIMUM_BUFFER_SIZE 1024
+
+#define SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services"
+
+#define SERVICE_KEY(_Driver) \
+ SERVICES_KEY ## "\\" ## #_Driver
+
+#define UNPLUG_KEY \
+ SERVICE_KEY(XEN) ## "\\Unplug"
+
+#define CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control"
+
+#define CLASS_KEY \
+ CONTROL_KEY ## "\\Class"
+
+#define ENUM_KEY "SYSTEM\\CurrentControlSet\\Enum"
+
+static VOID
+#pragma prefast(suppress:6262) // Function uses '1036' bytes of stack: exceeds /analyze:stacksize'1024'
+__Log(
+ IN const CHAR *Format,
+ IN ...
+ )
+{
+ TCHAR Buffer[MAXIMUM_BUFFER_SIZE];
+ va_list Arguments;
+ size_t Length;
+ SP_LOG_TOKEN LogToken;
+ DWORD Category;
+ DWORD Flags;
+ HRESULT Result;
+
+ va_start(Arguments, Format);
+ Result = StringCchVPrintf(Buffer, MAXIMUM_BUFFER_SIZE, Format, Arguments);
+ va_end(Arguments);
+
+ if (Result != S_OK && Result != STRSAFE_E_INSUFFICIENT_BUFFER)
+ return;
+
+ Result = StringCchLength(Buffer, MAXIMUM_BUFFER_SIZE, &Length);
+ if (Result != S_OK)
+ return;
+
+ LogToken = SetupGetThreadLogToken();
+ Category = TXTLOG_VENDOR;
+ Flags = TXTLOG_WARNING;
+
+ SetupWriteTextLog(LogToken, Category, Flags, Buffer);
+ Length = __min(MAXIMUM_BUFFER_SIZE - 1, Length + 2);
+
+ __analysis_assume(Length < MAXIMUM_BUFFER_SIZE);
+ __analysis_assume(Length >= 2);
+ Buffer[Length] = '\0';
+ Buffer[Length - 1] = '\n';
+ Buffer[Length - 2] = '\r';
+
+ OutputDebugString(Buffer);
+}
+
+#define Log(_Format, ...) \
+ __Log(__MODULE__ "|" __FUNCTION__ ": " _Format, __VA_ARGS__)
+
+static PTCHAR
+GetErrorMessage(
+ IN DWORD Error
+ )
+{
+ PTCHAR Message;
+ ULONG Index;
+
+ if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ Error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&Message,
+ 0,
+ NULL))
+ return NULL;
+
+ for (Index = 0; Message[Index] != '\0'; Index++) {
+ if (Message[Index] == '\r' || Message[Index] == '\n') {
+ Message[Index] = '\0';
+ break;
+ }
+ }
+
+ return Message;
+}
+
+static FORCEINLINE const CHAR *
+__FunctionName(
+ IN DI_FUNCTION Function
+ )
+{
+#define _NAME(_Function) \
+ case DIF_ ## _Function: \
+ return #_Function;
+
+ switch (Function) {
+ _NAME(INSTALLDEVICE);
+ _NAME(REMOVE);
+ _NAME(SELECTDEVICE);
+ _NAME(ASSIGNRESOURCES);
+ _NAME(PROPERTIES);
+ _NAME(FIRSTTIMESETUP);
+ _NAME(FOUNDDEVICE);
+ _NAME(SELECTCLASSDRIVERS);
+ _NAME(VALIDATECLASSDRIVERS);
+ _NAME(INSTALLCLASSDRIVERS);
+ _NAME(CALCDISKSPACE);
+ _NAME(DESTROYPRIVATEDATA);
+ _NAME(VALIDATEDRIVER);
+ _NAME(MOVEDEVICE);
+ _NAME(DETECT);
+ _NAME(INSTALLWIZARD);
+ _NAME(DESTROYWIZARDDATA);
+ _NAME(PROPERTYCHANGE);
+ _NAME(ENABLECLASS);
+ _NAME(DETECTVERIFY);
+ _NAME(INSTALLDEVICEFILES);
+ _NAME(ALLOW_INSTALL);
+ _NAME(SELECTBESTCOMPATDRV);
+ _NAME(REGISTERDEVICE);
+ _NAME(NEWDEVICEWIZARD_PRESELECT);
+ _NAME(NEWDEVICEWIZARD_SELECT);
+ _NAME(NEWDEVICEWIZARD_PREANALYZE);
+ _NAME(NEWDEVICEWIZARD_POSTANALYZE);
+ _NAME(NEWDEVICEWIZARD_FINISHINSTALL);
+ _NAME(INSTALLINTERFACES);
+ _NAME(DETECTCANCEL);
+ _NAME(REGISTER_COINSTALLERS);
+ _NAME(ADDPROPERTYPAGE_ADVANCED);
+ _NAME(ADDPROPERTYPAGE_BASIC);
+ _NAME(TROUBLESHOOTER);
+ _NAME(POWERMESSAGEWAKE);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _NAME
+}
+
+static BOOLEAN
+ClearUnplugRequest(
+ IN PTCHAR ClassName
+ )
+{
+ HKEY UnplugKey;
+ HRESULT Error;
+
+ Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ UNPLUG_KEY,
+ 0,
+ KEY_ALL_ACCESS,
+ &UnplugKey);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail1;
+ }
+
+ Error = RegDeleteValue(UnplugKey, ClassName);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail2;
+ }
+
+ RegCloseKey(UnplugKey);
+
+ return TRUE;
+
+fail2:
+ Log("fail2");
+
+ RegCloseKey(UnplugKey);
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+AllowUpdate(
+ IN PTCHAR DriverName,
+ OUT PBOOLEAN Allow
+ )
+{
+ TCHAR ServiceKeyName[MAX_PATH];
+ HKEY ServiceKey;
+ HRESULT Result;
+ HRESULT Error;
+ DWORD ValueLength;
+ DWORD Value;
+ DWORD Type;
+
+ Log("====> (%s)", DriverName);
+
+ Result = StringCbPrintf(ServiceKeyName,
+ MAX_PATH,
+ SERVICES_KEY "\\%s",
+ DriverName);
+ assert(SUCCEEDED(Result));
+
+ Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ ServiceKeyName,
+ 0,
+ KEY_READ,
+ &ServiceKey);
+ if (Error != ERROR_SUCCESS) {
+ if (Error == ERROR_FILE_NOT_FOUND) {
+ Value = 1;
+ goto done;
+ }
+
+ SetLastError(Error);
+ goto fail1;
+ }
+
+ ValueLength = sizeof (Value);
+
+ Error = RegQueryValueEx(ServiceKey,
+ "AllowUpdate",
+ NULL,
+ &Type,
+ (LPBYTE)&Value,
+ &ValueLength);
+ if (Error != ERROR_SUCCESS) {
+ if (Error == ERROR_FILE_NOT_FOUND) {
+ Type = REG_DWORD;
+ Value = 1;
+ } else {
+ SetLastError(Error);
+ goto fail2;
+ }
+ }
+
+ if (Type != REG_DWORD) {
+ SetLastError(ERROR_BAD_FORMAT);
+ goto fail3;
+ }
+
+ RegCloseKey(ServiceKey);
+
+done:
+ if (Value == 0) {
+ Log("DISALLOWED");
+ *Allow = FALSE;
+ }
+
+ Log("<====");
+
+ return TRUE;
+
+fail3:
+ Log("fail3");
+
+fail2:
+ Log("fail2");
+
+ RegCloseKey(ServiceKey);
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+AllowInstall(
+ OUT PBOOLEAN Allow
+ )
+{
+ BOOLEAN Success;
+ HRESULT Error;
+
+ Log("====>");
+
+ *Allow = TRUE;
+
+ Success = AllowUpdate("XENVKBD", Allow);
+ if (!Success)
+ goto fail1;
+
+ Log("<====");
+
+ return TRUE;
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+OpenEnumKey(
+ OUT PHKEY EnumKey
+ )
+{
+ HRESULT Error;
+
+ Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ ENUM_KEY,
+ 0,
+ KEY_READ,
+ EnumKey);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail1;
+ }
+
+ return TRUE;
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+OpenBusKey(
+ IN PTCHAR BusKeyName,
+ OUT PHKEY BusKey
+ )
+{
+ BOOLEAN Success;
+ HKEY EnumKey;
+ HRESULT Error;
+
+ Success = OpenEnumKey(&EnumKey);
+ if (!Success)
+ goto fail1;
+
+ Error = RegOpenKeyEx(EnumKey,
+ BusKeyName,
+ 0,
+ KEY_READ,
+ BusKey);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail2;
+ }
+
+ RegCloseKey(EnumKey);
+
+ return TRUE;
+
+fail2:
+ Log("fail2");
+
+ RegCloseKey(EnumKey);
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+OpenDeviceKey(
+ IN PTCHAR BusKeyName,
+ IN PTCHAR DeviceKeyName,
+ OUT PHKEY DeviceKey
+ )
+{
+ BOOLEAN Success;
+ HKEY BusKey;
+ HRESULT Error;
+
+ Success = OpenBusKey(BusKeyName, &BusKey);
+ if (!Success)
+ goto fail1;
+
+ Error = RegOpenKeyEx(BusKey,
+ DeviceKeyName,
+ 0,
+ KEY_READ,
+ DeviceKey);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail2;
+ }
+
+ RegCloseKey(BusKey);
+
+ return TRUE;
+
+fail2:
+ Log("fail2");
+
+ RegCloseKey(BusKey);
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+GetDriverKeyName(
+ IN HKEY DeviceKey,
+ OUT PTCHAR *Name
+ )
+{
+ HRESULT Error;
+ DWORD SubKeys;
+ DWORD MaxSubKeyLength;
+ DWORD SubKeyLength;
+ PTCHAR SubKeyName;
+ DWORD Index;
+ HKEY SubKey;
+ PTCHAR DriverKeyName;
+
+ Error = RegQueryInfoKey(DeviceKey,
+ NULL,
+ NULL,
+ NULL,
+ &SubKeys,
+ &MaxSubKeyLength,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail1;
+ }
+
+ SubKeyLength = MaxSubKeyLength + sizeof (TCHAR);
+
+ SubKeyName = malloc(SubKeyLength);
+ if (SubKeyName == NULL)
+ goto fail2;
+
+ SubKey = NULL;
+ DriverKeyName = NULL;
+
+ for (Index = 0; Index < SubKeys; Index++) {
+ DWORD MaxValueLength;
+ DWORD DriverKeyNameLength;
+ DWORD Type;
+
+ SubKeyLength = MaxSubKeyLength + sizeof (TCHAR);
+ memset(SubKeyName, 0, SubKeyLength);
+
+ Error = RegEnumKeyEx(DeviceKey,
+ Index,
+ (LPTSTR)SubKeyName,
+ &SubKeyLength,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail3;
+ }
+
+ Error = RegOpenKeyEx(DeviceKey,
+ SubKeyName,
+ 0,
+ KEY_READ,
+ &SubKey);
+ if (Error != ERROR_SUCCESS) {
+ SubKey = NULL;
+ continue;
+ }
+
+ Error = RegQueryInfoKey(SubKey,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &MaxValueLength,
+ NULL,
+ NULL);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail4;
+ }
+
+ DriverKeyNameLength = MaxValueLength + sizeof (TCHAR);
+
+ DriverKeyName = calloc(1, DriverKeyNameLength);
+ if (DriverKeyName == NULL)
+ goto fail5;
+
+ Error = RegQueryValueEx(SubKey,
+ "Driver",
+ NULL,
+ &Type,
+ (LPBYTE)DriverKeyName,
+ &DriverKeyNameLength);
+ if (Error == ERROR_SUCCESS &&
+ Type == REG_SZ)
+ break;
+
+ free(DriverKeyName);
+ DriverKeyName = NULL;
+
+ RegCloseKey(SubKey);
+ SubKey = NULL;
+ }
+
+ Log("%s", (DriverKeyName != NULL) ? DriverKeyName : "none found");
+
+ if (SubKey != NULL)
+ RegCloseKey(SubKey);
+
+ free(SubKeyName);
+
+ *Name = DriverKeyName;
+ return TRUE;
+
+fail5:
+ Log("fail5");
+
+fail4:
+ Log("fail4");
+
+ if (SubKey != NULL)
+ RegCloseKey(SubKey);
+
+fail3:
+ Log("fail3");
+
+ free(SubKeyName);
+
+fail2:
+ Log("fail2");
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+OpenClassKey(
+ OUT PHKEY ClassKey
+ )
+{
+ HRESULT Error;
+
+ Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ CLASS_KEY,
+ 0,
+ KEY_READ,
+ ClassKey);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail1;
+ }
+
+ return TRUE;
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+OpenDriverKey(
+ IN PTCHAR DriverKeyName,
+ OUT PHKEY DriverKey
+ )
+{
+ BOOLEAN Success;
+ HKEY ClassKey;
+ HRESULT Error;
+
+ Success = OpenClassKey(&ClassKey);
+ if (!Success)
+ goto fail1;
+
+ Error = RegOpenKeyEx(ClassKey,
+ DriverKeyName,
+ 0,
+ KEY_READ,
+ DriverKey);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail2;
+ }
+
+ RegCloseKey(ClassKey);
+
+ return TRUE;
+
+fail2:
+ Log("fail2");
+
+ RegCloseKey(ClassKey);
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+#define DEFINE_REVISION(_N, _H) \
+ (_N)
+
+static DWORD DeviceRevision[] = {
+ DEFINE_REVISION_TABLE
+};
+
+#undef DEFINE_REVISION
+
+static BOOLEAN
+SupportDeviceID(
+ IN PTCHAR DeviceID
+ )
+{
+ unsigned int Revision;
+ int Count;
+ DWORD Index;
+ HRESULT Error;
+
+ DeviceID = strrchr(DeviceID, '&');
+ assert(DeviceID != NULL);
+ DeviceID++;
+
+ Count = sscanf_s(DeviceID,
+ "REV_%8x",
+ &Revision);
+ if (Count != 1) {
+ SetLastError(ERROR_BAD_FORMAT);
+ goto fail1;
+ }
+
+ for (Index = 0; Index < ARRAYSIZE(DeviceRevision); Index++) {
+ if (Revision == DeviceRevision[Index])
+ goto found;
+ }
+
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ goto fail2;
+
+found:
+ Log("%x", Revision);
+
+ return TRUE;
+
+fail2:
+ Log("fail2");
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+GetMatchingDeviceID(
+ IN HKEY DriverKey,
+ OUT PTCHAR *MatchingDeviceID
+ )
+{
+ HRESULT Error;
+ DWORD MaxValueLength;
+ DWORD MatchingDeviceIDLength;
+ DWORD Type;
+ DWORD Index;
+
+ Error = RegQueryInfoKey(DriverKey,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &MaxValueLength,
+ NULL,
+ NULL);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail1;
+ }
+
+ MatchingDeviceIDLength = MaxValueLength + sizeof (TCHAR);
+
+ *MatchingDeviceID = calloc(1, MatchingDeviceIDLength);
+ if (*MatchingDeviceID == NULL)
+ goto fail2;
+
+ Error = RegQueryValueEx(DriverKey,
+ "MatchingDeviceId",
+ NULL,
+ &Type,
+ (LPBYTE)*MatchingDeviceID,
+ &MatchingDeviceIDLength);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail3;
+ }
+
+ if (Type != REG_SZ) {
+ SetLastError(ERROR_BAD_FORMAT);
+ goto fail4;
+ }
+
+ for (Index = 0; Index < strlen(*MatchingDeviceID); Index++)
+ (*MatchingDeviceID)[Index] = (CHAR)toupper((*MatchingDeviceID)[Index]);
+
+ Log("%s", *MatchingDeviceID);
+
+ return TRUE;
+
+fail4:
+ Log("fail4");
+
+fail3:
+ Log("fail3");
+
+ free(*MatchingDeviceID);
+
+fail2:
+ Log("fail2");
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN
+SupportChildDrivers(
+ VOID
+ )
+{
+ BOOLEAN Success;
+ HKEY XenbusKey;
+ HRESULT Error;
+ DWORD SubKeys;
+ DWORD MaxSubKeyLength;
+ DWORD SubKeyLength;
+ PTCHAR SubKeyName;
+ HKEY DeviceKey;
+ PTCHAR DriverKeyName;
+ HKEY DriverKey;
+ PTCHAR MatchingDeviceID;
+ DWORD Index;
+
+ Log("====>");
+
+ Success = OpenBusKey("XENVKBD", &XenbusKey);
+ if (!Success) {
+ // If there is no key then this must be a fresh installation
+ if (GetLastError() == ERROR_FILE_NOT_FOUND)
+ goto done;
+
+ goto fail1;
+ }
+
+ Error = RegQueryInfoKey(XenbusKey,
+ NULL,
+ NULL,
+ NULL,
+ &SubKeys,
+ &MaxSubKeyLength,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail2;
+ }
+
+ SubKeyLength = MaxSubKeyLength + sizeof (TCHAR);
+
+ SubKeyName = malloc(SubKeyLength);
+ if (SubKeyName == NULL)
+ goto fail3;
+
+ for (Index = 0; Index < SubKeys; Index++) {
+ SubKeyLength = MaxSubKeyLength + sizeof (TCHAR);
+ memset(SubKeyName, 0, SubKeyLength);
+
+ Error = RegEnumKeyEx(XenbusKey,
+ Index,
+ (LPTSTR)SubKeyName,
+ &SubKeyLength,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (Error != ERROR_SUCCESS) {
+ SetLastError(Error);
+ goto fail4;
+ }
+
+ Success = OpenDeviceKey("XENVKBD", SubKeyName, &DeviceKey);
+ if (!Success)
+ goto fail5;
+
+ Success = GetDriverKeyName(DeviceKey, &DriverKeyName);
+ if (!Success)
+ goto fail6;
+
+ if (DriverKeyName == NULL)
+ goto loop;
+
+ Success = OpenDriverKey(DriverKeyName, &DriverKey);
+ if (!Success)
+ goto loop;
+
+ Success = GetMatchingDeviceID(DriverKey, &MatchingDeviceID);
+ if (!Success)
+ goto fail7;
+
+ Success = SupportDeviceID(MatchingDeviceID);
+ if (!Success)
+ goto fail8;
+
+ free(MatchingDeviceID);
+
+ RegCloseKey(DriverKey);
+
+ loop:
+ if (DriverKeyName != NULL)
+ free(DriverKeyName);
+
+ RegCloseKey(DeviceKey);
+ }
+
+ free(SubKeyName);
+
+ RegCloseKey(XenbusKey);
+
+done:
+ Log("<====");
+
+ return TRUE;
+
+fail8:
+ Log("fail8");
+
+ free(MatchingDeviceID);
+
+fail7:
+ Log("fail7");
+
+ RegCloseKey(DriverKey);
+
+ free(DriverKeyName);
+
+fail6:
+ Log("fail6");
+
+ RegCloseKey(DeviceKey);
+
+fail5:
+ Log("fail5");
+
+fail4:
+ Log("fail4");
+
+ free(SubKeyName);
+
+fail3:
+ Log("fail3");
+
+fail2:
+ Log("fail2");
+
+ RegCloseKey(XenbusKey);
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return FALSE;
+}
+
+static HRESULT
+DifInstallPreProcess(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ IN PCOINSTALLER_CONTEXT_DATA Context
+ )
+{
+ HRESULT Error;
+ BOOLEAN Success;
+ BOOLEAN Allow;
+
+ UNREFERENCED_PARAMETER(DeviceInfoSet);
+ UNREFERENCED_PARAMETER(DeviceInfoData);
+ UNREFERENCED_PARAMETER(Context);
+
+ Log("====>");
+
+ Success = AllowInstall(&Allow);
+ if (!Success)
+ goto fail1;
+
+ if (!Allow) {
+ SetLastError(ERROR_ACCESS_DENIED);
+ goto fail2;
+ }
+
+ Success = SupportChildDrivers();
+ if (!Success)
+ goto fail3;
+
+ Log("<====");
+
+ return NO_ERROR;
+
+fail3:
+ Log("fail3");
+
+fail2:
+ Log("fail2");
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return Error;
+}
+
+static HRESULT
+DifInstallPostProcess(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ IN PCOINSTALLER_CONTEXT_DATA Context
+ )
+{
+ UNREFERENCED_PARAMETER(DeviceInfoSet);
+ UNREFERENCED_PARAMETER(DeviceInfoData);
+ UNREFERENCED_PARAMETER(Context);
+
+ Log("<===>");
+
+ return NO_ERROR;
+}
+
+static DECLSPEC_NOINLINE HRESULT
+DifInstall(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ IN PCOINSTALLER_CONTEXT_DATA Context
+ )
+{
+ SP_DEVINSTALL_PARAMS DeviceInstallParams;
+ HRESULT Error;
+
+ DeviceInstallParams.cbSize = sizeof (DeviceInstallParams);
+
+ if (!SetupDiGetDeviceInstallParams(DeviceInfoSet,
+ DeviceInfoData,
+ &DeviceInstallParams))
+ goto fail1;
+
+ Log("Flags = %08x", DeviceInstallParams.Flags);
+
+ if (!Context->PostProcessing) {
+ Error = DifInstallPreProcess(DeviceInfoSet, DeviceInfoData, Context);
+
+ if (Error == NO_ERROR)
+ Error = ERROR_DI_POSTPROCESSING_REQUIRED;
+ } else {
+ Error = Context->InstallResult;
+
+ if (Error == NO_ERROR) {
+ (VOID) DifInstallPostProcess(DeviceInfoSet, DeviceInfoData, Context);
+ } else {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("NOT RUNNING (DifInstallPreProcess Error: %s)", Message);
+ LocalFree(Message);
+ }
+
+ Error = NO_ERROR;
+ }
+
+ return Error;
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return Error;
+}
+
+static HRESULT
+DifRemovePreProcess(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ IN PCOINSTALLER_CONTEXT_DATA Context
+ )
+{
+ UNREFERENCED_PARAMETER(DeviceInfoSet);
+ UNREFERENCED_PARAMETER(DeviceInfoData);
+ UNREFERENCED_PARAMETER(Context);
+
+ Log("<===>");
+
+ return NO_ERROR;
+}
+
+static HRESULT
+DifRemovePostProcess(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ IN PCOINSTALLER_CONTEXT_DATA Context
+ )
+{
+ UNREFERENCED_PARAMETER(DeviceInfoSet);
+ UNREFERENCED_PARAMETER(DeviceInfoData);
+ UNREFERENCED_PARAMETER(Context);
+
+ Log("<===>");
+
+ return NO_ERROR;
+}
+
+static DECLSPEC_NOINLINE HRESULT
+DifRemove(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ IN PCOINSTALLER_CONTEXT_DATA Context
+ )
+{
+ SP_DEVINSTALL_PARAMS DeviceInstallParams;
+ HRESULT Error;
+
+ DeviceInstallParams.cbSize = sizeof (DeviceInstallParams);
+
+ if (!SetupDiGetDeviceInstallParams(DeviceInfoSet,
+ DeviceInfoData,
+ &DeviceInstallParams))
+ goto fail1;
+
+ Log("Flags = %08x", DeviceInstallParams.Flags);
+
+ if (!Context->PostProcessing) {
+ Error = DifRemovePreProcess(DeviceInfoSet, DeviceInfoData, Context);
+
+ if (Error == NO_ERROR)
+ Error = ERROR_DI_POSTPROCESSING_REQUIRED;
+ } else {
+ Error = Context->InstallResult;
+
+ if (Error == NO_ERROR) {
+ (VOID) DifRemovePostProcess(DeviceInfoSet, DeviceInfoData, Context);
+ } else {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("NOT RUNNING (DifRemovePreProcess Error: %s)", Message);
+ LocalFree(Message);
+ }
+
+ Error = NO_ERROR;
+ }
+
+ return Error;
+
+fail1:
+ Error = GetLastError();
+
+ {
+ PTCHAR Message;
+
+ Message = GetErrorMessage(Error);
+ Log("fail1 (%s)", Message);
+ LocalFree(Message);
+ }
+
+ return Error;
+}
+
+DWORD CALLBACK
+Entry(
+ IN DI_FUNCTION Function,
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ IN PCOINSTALLER_CONTEXT_DATA Context
+ )
+{
+ HRESULT Error;
+
+ Log("%s (%s) ===>",
+ MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR,
+ DAY_STR "/" MONTH_STR "/" YEAR_STR);
+
+ if (!Context->PostProcessing) {
+ Log("%s PreProcessing",
+ __FunctionName(Function));
+ } else {
+ Log("%s PostProcessing (%08x)",
+ __FunctionName(Function),
+ Context->InstallResult);
+ }
+
+ switch (Function) {
+ case DIF_INSTALLDEVICE: {
+ SP_DRVINFO_DATA DriverInfoData;
+ BOOLEAN DriverInfoAvailable;
+
+ DriverInfoData.cbSize = sizeof (DriverInfoData);
+ DriverInfoAvailable = SetupDiGetSelectedDriver(DeviceInfoSet,
+ DeviceInfoData,
+ &DriverInfoData) ?
+ TRUE :
+ FALSE;
+
+ // If there is no driver information then the NULL driver is being
+ // installed. Treat this as we would a DIF_REMOVE.
+ Error = (DriverInfoAvailable) ?
+ DifInstall(DeviceInfoSet, DeviceInfoData, Context) :
+ DifRemove(DeviceInfoSet, DeviceInfoData, Context);
+ break;
+ }
+ case DIF_REMOVE:
+ Error = DifRemove(DeviceInfoSet, DeviceInfoData, Context);
+ break;
+ default:
+ if (!Context->PostProcessing) {
+ Error = NO_ERROR;
+ } else {
+ Error = Context->InstallResult;
+ }
+
+ break;
+ }
+
+ Log("%s (%s) <===",
+ MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR,
+ DAY_STR "/" MONTH_STR "/" YEAR_STR);
+
+ return (DWORD)Error;
+}
+
+DWORD CALLBACK
+Version(
+ IN HWND Window,
+ IN HINSTANCE Module,
+ IN PTCHAR Buffer,
+ IN INT Reserved
+ )
+{
+ UNREFERENCED_PARAMETER(Window);
+ UNREFERENCED_PARAMETER(Module);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Reserved);
+
+ Log("%s (%s)",
+ MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR,
+ DAY_STR "/" MONTH_STR "/" YEAR_STR);
+
+ return NO_ERROR;
+}
+
+static FORCEINLINE const CHAR *
+__ReasonName(
+ IN DWORD Reason
+ )
+{
+#define _NAME(_Reason) \
+ case DLL_ ## _Reason: \
+ return #_Reason;
+
+ switch (Reason) {
+ _NAME(PROCESS_ATTACH);
+ _NAME(PROCESS_DETACH);
+ _NAME(THREAD_ATTACH);
+ _NAME(THREAD_DETACH);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _NAME
+}
+
+BOOL WINAPI
+DllMain(
+ IN HINSTANCE Module,
+ IN DWORD Reason,
+ IN PVOID Reserved
+ )
+{
+ UNREFERENCED_PARAMETER(Module);
+ UNREFERENCED_PARAMETER(Reserved);
+
+ Log("%s (%s): %s",
+ MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR,
+ DAY_STR "/" MONTH_STR "/" YEAR_STR,
+ __ReasonName(Reason));
+
+ return TRUE;
+}
--- /dev/null
+; Copyright (c) Citrix Systems Inc.
+; 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.
+;
+; 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.
+
+LIBRARY XENBUS_COINST
+
+EXPORTS
+ Entry
+ Version
+
+ DllMain PRIVATE
--- /dev/null
+; Copyright (c) Citrix Systems Inc.
+; 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.
+;
+; 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.
+
+
+[Version]
+Signature="$Windows NT$"
+Class=System
+ClassGUID={4d36e97d-e325-11ce-bfc1-08002be10318}
+Provider=%Vendor%
+CatalogFile=xenvkbd.cat
+DriverVer=01/01/1900,0.0.0.0
+DriverPackageDisplayName=%DiskDesc%
+
+[DestinationDirs]
+DefaultDestDir=12
+CoInst_CopyFiles=11
+
+[SourceDisksNames]
+0=%DiskDesc%
+
+[SourceDisksFiles]
+xenvkbd.sys=0,,
+xenvkbd_coinst.dll=0,,
+
+[CoInst_CopyFiles]
+xenvkbd_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll,xenvkbd_coinst.dll
+
+[Manufacturer]
+%Vendor%=Inst,NT$ARCH$
+
+[Inst.NT$ARCH$]
+; DisplayName Section DeviceID
+; ----------- ------- --------
+
+%XenVkbdName% =XenVkbd_Inst, XENBUS\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_VKBD&REV_09000000
+%XenVkbdName% =XenVkbd_Inst, XENBUS\VEN_@VENDOR_PREFIX@0001&DEV_VKBD&REV_09000000
+%XenVkbdName% =XenVkbd_Inst, XENBUS\VEN_@VENDOR_PREFIX@0002&DEV_VKBD&REV_09000000
+
+[XenVkbd_Inst]
+CopyFiles=XenVkbd_Copyfiles
+
+[XenVkbd_Copyfiles]
+xenvkbd.sys
+
+[XenVkbd_Inst.Services]
+AddService=xenvkbd,0x02,XenVkbd_Service,
+
+[XenVkbd_Service]
+DisplayName=%XenVkbdName%
+ServiceType=%SERVICE_KERNEL_DRIVER%
+StartType=%SERVICE_DEMAND_START%
+ErrorControl=%SERVICE_ERROR_NORMAL%
+ServiceBinary=%12%\xenvkbd.sys
+AddReg = XenVkbd_Parameters
+
+[XenVkbd_Parameters]
+HKR,"Parameters",,0x00000010
+HKR,"Parameters","RequestKey",0x00000000,%RequestKey%
+
+[XenVkbd_Inst.CoInstallers]
+CopyFiles=CoInst_CopyFiles
+AddReg=CoInst_AddReg
+
+[CoInst_AddReg]
+HKR,,CoInstallers32,0x00010000,"xenvkbd_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll,Entry"
+
+[Strings]
+
+Vendor="@VENDOR_NAME@"
+DiskDesc="@PRODUCT_NAME@ PV Keyboard/Mouse Package"
+XenVkbdName="@PRODUCT_NAME@ PV Keyboard/Mouse"
+RequestKey="SYSTEM\CurrentControlSet\Services\xenbus_monitor\Request"
+
+SERVICE_BOOT_START=0x0
+SERVICE_SYSTEM_START=0x1
+SERVICE_AUTO_START=0x2
+SERVICE_DEMAND_START=0x3
+SERVICE_DISABLED=0x4
+
+SERVICE_KERNEL_DRIVER=0x1
+SERVICE_ERROR_IGNORE=0x0
+SERVICE_ERROR_NORMAL=0x1
+SERVICE_ERROR_SEVERE=0x2
+SERVICE_ERROR_CRITICAL=0x3
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_ASSERT_H
+#define _XENVKBD_ASSERT_H
+
+#include <ntddk.h>
+
+#include "dbg_print.h"
+
+static FORCEINLINE VOID
+__Bug(
+ IN ULONG Code,
+ IN ULONG_PTR Parameter1,
+ IN ULONG_PTR Parameter2,
+ IN ULONG_PTR Parameter3,
+ IN ULONG_PTR Parameter4
+ )
+{
+#pragma prefast(suppress:28159)
+ KeBugCheckEx(Code,
+ Parameter1,
+ Parameter2,
+ Parameter3,
+ Parameter4);
+}
+
+#define ASSERTION_FAILURE 0x0000DEAD
+
+#define BUG(_TEXT) \
+ do { \
+ const CHAR *_Text = (_TEXT); \
+ const CHAR *_File = __FILE__; \
+ ULONG _Line = __LINE__; \
+ \
+ Error("BUG: " _TEXT "\n"); \
+ __Bug(ASSERTION_FAILURE, \
+ (ULONG_PTR)_Text, \
+ (ULONG_PTR)_File, \
+ (ULONG_PTR)_Line, \
+ 0); \
+ } while (FALSE)
+
+#define BUG_ON(_EXP) \
+ if (_EXP) BUG(#_EXP)
+
+#undef ASSERT
+
+#if DBG
+
+#define __NT_ASSERT(_EXP) \
+ ((!(_EXP)) ? \
+ (Error("ASSERTION FAILED: " #_EXP "\n"), \
+ __annotation(L"Debug", L"AssertFail", L#_EXP), \
+ DbgRaiseAssertionFailure(), FALSE) : \
+ TRUE)
+
+#define __ASSERT(_EXP) __NT_ASSERT(_EXP)
+
+#define ASSERT(_EXP) \
+ do { \
+ __ASSERT(_EXP); \
+ __analysis_assume(_EXP); \
+ } while (FALSE)
+
+#define ASSERT3U(_X, _OP, _Y) \
+ do { \
+ ULONGLONG _Lval = (ULONGLONG)(_X); \
+ ULONGLONG _Rval = (ULONGLONG)(_Y); \
+ if (!(_Lval _OP _Rval)) { \
+ Error("%s = %llu\n", #_X, _Lval); \
+ Error("%s = %llu\n", #_Y, _Rval); \
+ ASSERT((_X) _OP (_Y)); \
+ } \
+ } while (FALSE)
+
+#define ASSERT3S(_X, _OP, _Y) \
+ do { \
+ LONGLONG _Lval = (LONGLONG)(_X); \
+ LONGLONG _Rval = (LONGLONG)(_Y); \
+ if (!(_Lval _OP _Rval)) { \
+ Error("%s = %lld\n", #_X, _Lval); \
+ Error("%s = %lld\n", #_Y, _Rval); \
+ ASSERT((_X) _OP (_Y)); \
+ } \
+ } while (FALSE)
+
+#define ASSERT3P(_X, _OP, _Y) \
+ do { \
+ PVOID _Lval = (PVOID)(_X); \
+ PVOID _Rval = (PVOID)(_Y); \
+ if (!(_Lval _OP _Rval)) { \
+ Error("%s = %p\n", #_X, _Lval); \
+ Error("%s = %p\n", #_Y, _Rval); \
+ ASSERT((_X) _OP (_Y)); \
+ } \
+ } while (FALSE)
+
+#else // DBG
+
+#pragma warning(disable:4100)
+#pragma warning(disable:4189)
+
+#define ASSERT(_EXP) \
+ do { \
+ __analysis_assume(_EXP); \
+ } while (FALSE)
+
+#define ASSERT3U(_X, _OP, _Y) \
+ ASSERT((_X) _OP (_Y))
+
+#define ASSERT3S(_X, _OP, _Y) \
+ ASSERT((_X) _OP (_Y))
+
+#define ASSERT3P(_X, _OP, _Y) \
+ ASSERT((_X) _OP (_Y))
+
+#endif // DBG
+
+#ifndef TEST_MEMORY
+#define TEST_MEMORY DBG
+#endif
+
+#if TEST_MEMORY
+
+static __inline BOOLEAN
+_IsZeroMemory(
+ IN const PCHAR Caller,
+ IN const PCHAR Name,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ ULONG Offset;
+
+ Offset = 0;
+ while (Offset < Length) {
+ if (*((PUCHAR)Buffer + Offset) != 0) {
+ Error("%s: non-zero byte in %s (0x%p+0x%x)\n", Caller, Name, Buffer, Offset);
+ return FALSE;
+ }
+ Offset++;
+ }
+
+ return TRUE;
+}
+
+#else // TEST_MEMORY
+
+static __inline BOOLEAN
+_IsZeroMemory(
+ IN const PCHAR Caller,
+ IN const PCHAR Name,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ UNREFERENCED_PARAMETER(Caller);
+ UNREFERENCED_PARAMETER(Name);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+
+ return TRUE;
+}
+
+#endif // TEST_MEMORY
+
+#define IsZeroMemory(_Buffer, _Length) \
+ _IsZeroMemory(__FUNCTION__, #_Buffer, (_Buffer), (_Length))
+
+#define IMPLY(_X, _Y) (!(_X) || (_Y))
+#define EQUIV(_X, _Y) (IMPLY((_X), (_Y)) && IMPLY((_Y), (_X)))
+
+#endif // _XENVKBD_ASSERT_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#include <ntddk.h>
+#include <stdarg.h>
+#include <xen.h>
+
+#include "bus.h"
+#include "fdo.h"
+#include "pdo.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+typedef struct _XENVKBD_BUS_CONTEXT {
+ LONG References;
+ PXENVKBD_PDO Pdo;
+ ULONG InterceptDmaAdapter;
+} XENVKBD_BUS_CONTEXT, *PXENVKBD_BUS_CONTEXT;
+
+#define BUS_TAG 'SUB'
+
+static FORCEINLINE PVOID
+__BusAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, BUS_TAG);
+}
+
+static FORCEINLINE VOID
+__BusFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, BUS_TAG);
+}
+
+static VOID
+BusReference(
+ IN PVOID _Context
+ )
+{
+ PXENVKBD_BUS_CONTEXT Context = _Context;
+
+ InterlockedIncrement(&Context->References);
+}
+
+static VOID
+BusDereference(
+ IN PVOID _Context
+ )
+{
+ PXENVKBD_BUS_CONTEXT Context = _Context;
+
+ ASSERT(Context->References != 0);
+ InterlockedDecrement(&Context->References);
+}
+
+static
+__drv_functionClass(TRANSLATE_BUS_ADDRESS)
+BOOLEAN
+BusTranslateAddress(
+ IN PVOID _Context,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN ULONG Length,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+{
+ PXENVKBD_BUS_CONTEXT Context = _Context;
+
+ return PdoTranslateBusAddress(Context->Pdo,
+ BusAddress,
+ Length,
+ AddressSpace,
+ TranslatedAddress);
+}
+
+static
+__drv_functionClass(GET_DMA_ADAPTER)
+PDMA_ADAPTER
+BusGetDmaAdapter(
+ IN PVOID _Context,
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ )
+{
+ PXENVKBD_BUS_CONTEXT Context = _Context;
+
+ return PdoGetDmaAdapter(Context->Pdo,
+ DeviceDescriptor,
+ NumberOfMapRegisters);
+}
+
+static
+__drv_functionClass(GET_SET_DEVICE_DATA)
+ULONG
+BusSetData(
+ IN PVOID _Context,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ PXENVKBD_BUS_CONTEXT Context = _Context;
+
+ return PdoSetBusData(Context->Pdo,
+ DataType,
+ Buffer,
+ Offset,
+ Length);
+}
+
+static
+__drv_functionClass(GET_SET_DEVICE_DATA)
+ULONG
+BusGetData(
+ IN PVOID _Context,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ PXENVKBD_BUS_CONTEXT Context = _Context;
+
+ return PdoGetBusData(Context->Pdo,
+ DataType,
+ Buffer,
+ Offset,
+ Length);
+}
+
+NTSTATUS
+BusInitialize(
+ IN PXENVKBD_PDO Pdo,
+ OUT PBUS_INTERFACE_STANDARD Interface
+ )
+{
+ PXENVKBD_BUS_CONTEXT Context;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ Context = __BusAllocate(sizeof (XENVKBD_BUS_CONTEXT));
+
+ status = STATUS_NO_MEMORY;
+ if (Context == NULL)
+ goto fail1;
+
+ Context->Pdo = Pdo;
+
+ Interface->Size = sizeof (BUS_INTERFACE_STANDARD);
+ Interface->Version = 1;
+ Interface->Context = Context;
+ Interface->InterfaceReference = BusReference;
+ Interface->InterfaceDereference = BusDereference;
+ Interface->TranslateBusAddress = BusTranslateAddress;
+ Interface->GetDmaAdapter = BusGetDmaAdapter;
+ Interface->SetBusData = BusSetData;
+ Interface->GetBusData = BusGetData;
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+BusTeardown(
+ IN OUT PBUS_INTERFACE_STANDARD Interface
+ )
+{
+ PXENVKBD_BUS_CONTEXT Context = Interface->Context;
+
+ Trace("====>\n");
+
+ Context->Pdo = NULL;
+
+ ASSERT(IsZeroMemory(Context, sizeof (XENVKBD_BUS_CONTEXT)));
+ __BusFree(Context);
+
+ RtlZeroMemory(Interface, sizeof (BUS_INTERFACE_STANDARD));
+
+ Trace("<====\n");
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_BUS_H
+#define _XENVKBD_BUS_H
+
+#include <ntddk.h>
+#include <xen.h>
+
+#include "pdo.h"
+
+extern NTSTATUS
+BusInitialize(
+ IN PXENVKBD_PDO Pdo,
+ OUT PBUS_INTERFACE_STANDARD Interface
+ );
+
+extern VOID
+BusTeardown(
+ IN OUT PBUS_INTERFACE_STANDARD Interface
+ );
+
+#endif // _XENVKBD_BUS_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_DBG_PRINT_H
+#define _XENVKBD_DBG_PRINT_H
+
+#include <ntddk.h>
+#include <stdarg.h>
+
+#ifdef _SDV_
+#define __MODULE__ ""
+#endif
+
+#pragma warning(disable:4127) // conditional expression is constant
+
+static __inline VOID
+__Error(
+ IN const CHAR *Prefix,
+ IN const CHAR *Format,
+ ...
+ )
+{
+ va_list Arguments;
+
+ va_start(Arguments, Format);
+
+#pragma prefast(suppress:6001) // Using uninitialized memory
+ vDbgPrintExWithPrefix(Prefix,
+ DPFLTR_IHVDRIVER_ID,
+ DPFLTR_ERROR_LEVEL,
+ Format,
+ Arguments);
+ va_end(Arguments);
+}
+
+#define Error(...) \
+ __Error(__MODULE__ "|" __FUNCTION__ ": ", __VA_ARGS__)
+
+static __inline VOID
+__Warning(
+ IN const CHAR *Prefix,
+ IN const CHAR *Format,
+ ...
+ )
+{
+ va_list Arguments;
+
+ va_start(Arguments, Format);
+
+#pragma prefast(suppress:6001) // Using uninitialized memory
+ vDbgPrintExWithPrefix(Prefix,
+ DPFLTR_IHVDRIVER_ID,
+ DPFLTR_WARNING_LEVEL,
+ Format,
+ Arguments);
+ va_end(Arguments);
+}
+
+#define Warning(...) \
+ __Warning(__MODULE__ "|" __FUNCTION__ ": ", __VA_ARGS__)
+
+#if DBG
+
+static __inline VOID
+__Trace(
+ IN const CHAR *Prefix,
+ IN const CHAR *Format,
+ ...
+ )
+{
+ va_list Arguments;
+
+ va_start(Arguments, Format);
+
+#pragma prefast(suppress:6001) // Using uninitialized memory
+ vDbgPrintExWithPrefix(Prefix,
+ DPFLTR_IHVDRIVER_ID,
+ DPFLTR_TRACE_LEVEL,
+ Format,
+ Arguments);
+ va_end(Arguments);
+}
+
+#else // DBG
+
+static __inline VOID
+__Trace(
+ IN const CHAR *Prefix,
+ IN const CHAR *Format,
+ ...
+ )
+{
+ UNREFERENCED_PARAMETER(Prefix);
+ UNREFERENCED_PARAMETER(Format);
+}
+
+#endif // DBG
+
+#define Trace(...) \
+ __Trace(__MODULE__ "|" __FUNCTION__ ": ", __VA_ARGS__)
+
+static __inline VOID
+__Info(
+ IN const CHAR *Prefix,
+ IN const CHAR *Format,
+ ...
+ )
+{
+ va_list Arguments;
+
+ va_start(Arguments, Format);
+
+#pragma prefast(suppress:6001) // Using uninitialized memory
+ vDbgPrintExWithPrefix(Prefix,
+ DPFLTR_IHVDRIVER_ID,
+ DPFLTR_INFO_LEVEL,
+ Format,
+ Arguments);
+ va_end(Arguments);
+}
+
+#define Info(...) \
+ __Info(__MODULE__ "|" __FUNCTION__ ": ", __VA_ARGS__)
+
+#endif // _XENVKBD_DBG_PRINT_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#include <ntddk.h>
+#include <procgrp.h>
+#include <ntstrsafe.h>
+#include <version.h>
+
+#include "registry.h"
+#include "fdo.h"
+#include "pdo.h"
+#include "driver.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+typedef struct _XENVKBD_DRIVER {
+ PDRIVER_OBJECT DriverObject;
+ HANDLE ParametersKey;
+ BOOLEAN NeedReboot;
+} XENVKBD_DRIVER, *PXENVKBD_DRIVER;
+
+static XENVKBD_DRIVER Driver;
+
+extern PULONG InitSafeBootMode;
+
+static FORCEINLINE BOOLEAN
+__DriverSafeMode(
+ VOID
+ )
+{
+ return (*InitSafeBootMode > 0) ? TRUE : FALSE;
+}
+
+BOOLEAN
+DriverSafeMode(
+ VOID
+ )
+{
+ return __DriverSafeMode();
+}
+
+static FORCEINLINE VOID
+__DriverSetDriverObject(
+ IN PDRIVER_OBJECT DriverObject
+ )
+{
+ Driver.DriverObject = DriverObject;
+}
+
+static FORCEINLINE PDRIVER_OBJECT
+__DriverGetDriverObject(
+ VOID
+ )
+{
+ return Driver.DriverObject;
+}
+
+PDRIVER_OBJECT
+DriverGetDriverObject(
+ VOID
+ )
+{
+ return __DriverGetDriverObject();
+}
+
+static FORCEINLINE VOID
+__DriverSetParametersKey(
+ IN HANDLE Key
+ )
+{
+ Driver.ParametersKey = Key;
+}
+
+static FORCEINLINE HANDLE
+__DriverGetParametersKey(
+ VOID
+ )
+{
+ return Driver.ParametersKey;
+}
+
+HANDLE
+DriverGetParametersKey(
+ VOID
+ )
+{
+ return __DriverGetParametersKey();
+}
+
+#define MAXNAMELEN 256
+
+static FORCEINLINE VOID
+__DriverRequestReboot(
+ VOID
+ )
+{
+ PANSI_STRING Ansi;
+ CHAR RequestKeyName[MAXNAMELEN];
+ HANDLE RequestKey;
+ HANDLE SubKey;
+ NTSTATUS status;
+
+ Info("====>\n");
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ status = RegistryQuerySzValue(__DriverGetParametersKey(),
+ "RequestKey",
+ NULL,
+ &Ansi);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = RtlStringCbPrintfA(RequestKeyName,
+ MAXNAMELEN,
+ "\\Registry\\Machine\\%Z",
+ &Ansi[0]);
+ ASSERT(NT_SUCCESS(status));
+
+ status = RegistryCreateSubKey(NULL,
+ RequestKeyName,
+ REG_OPTION_NON_VOLATILE,
+ &RequestKey);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = RegistryCreateSubKey(RequestKey,
+ __MODULE__,
+ REG_OPTION_NON_VOLATILE,
+ &SubKey);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = RegistryUpdateDwordValue(SubKey,
+ "Reboot",
+ 1);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ RegistryCloseKey(SubKey);
+
+ RegistryFreeSzValue(Ansi);
+
+ Info("<====\n");
+
+ return;
+
+fail4:
+ Error("fail4\n");
+
+ RegistryCloseKey(SubKey);
+
+fail3:
+ Error("fail3\n");
+
+ RegistryCloseKey(RequestKey);
+
+fail2:
+ Error("fail2\n");
+
+ RegistryFreeSzValue(Ansi);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+}
+
+VOID
+DriverRequestReboot(
+ VOID
+ )
+{
+ if (Driver.NeedReboot)
+ return;
+
+ __DriverRequestReboot();
+
+ Driver.NeedReboot = TRUE;
+}
+
+DRIVER_UNLOAD DriverUnload;
+
+VOID
+DriverUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+{
+ HANDLE ParametersKey;
+
+ ASSERT3P(DriverObject, ==, __DriverGetDriverObject());
+
+ Trace("====>\n");
+
+ Driver.NeedReboot = FALSE;
+
+ ParametersKey = __DriverGetParametersKey();
+ __DriverSetParametersKey(NULL);
+
+ RegistryCloseKey(ParametersKey);
+
+ RegistryTeardown();
+
+ Info("XENVKBD %d.%d.%d (%d) (%02d.%02d.%04d)\n",
+ MAJOR_VERSION,
+ MINOR_VERSION,
+ MICRO_VERSION,
+ BUILD_NUMBER,
+ DAY,
+ MONTH,
+ YEAR);
+
+ __DriverSetDriverObject(NULL);
+
+ ASSERT(IsZeroMemory(&Driver, sizeof (XENVKBD_DRIVER)));
+
+ Trace("<====\n");
+}
+
+DRIVER_ADD_DEVICE AddDevice;
+
+NTSTATUS
+AddDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject
+ )
+{
+ NTSTATUS status;
+
+ ASSERT3P(DriverObject, ==, __DriverGetDriverObject());
+
+ status = FdoCreate(DeviceObject);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ // prefast stupidity
+ ASSERT(!(DeviceObject->Flags & DO_DEVICE_INITIALIZING));
+ DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+DRIVER_DISPATCH Dispatch;
+
+NTSTATUS
+Dispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+ PXENVKBD_DX Dx;
+ NTSTATUS status;
+
+ Dx = (PXENVKBD_DX)DeviceObject->DeviceExtension;
+ ASSERT3P(Dx->DeviceObject, ==, DeviceObject);
+
+ if (Dx->DevicePnpState == Deleted) {
+ status = STATUS_NO_SUCH_DEVICE;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ goto done;
+ }
+
+ status = STATUS_NOT_SUPPORTED;
+ switch (Dx->Type) {
+ case PHYSICAL_DEVICE_OBJECT: {
+ PXENVKBD_PDO Pdo = Dx->Pdo;
+
+ status = PdoDispatch(Pdo, Irp);
+ break;
+ }
+ case FUNCTION_DEVICE_OBJECT: {
+ PXENVKBD_FDO Fdo = Dx->Fdo;
+
+ status = FdoDispatch(Fdo, Irp);
+ break;
+ }
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+done:
+ return status;
+}
+
+DRIVER_INITIALIZE DriverEntry;
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+{
+ HANDLE ServiceKey;
+ HANDLE ParametersKey;
+ ULONG Index;
+ NTSTATUS status;
+
+ ASSERT3P(__DriverGetDriverObject(), ==, NULL);
+
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+ WdmlibProcgrpInitialize();
+
+ Trace("====>\n");
+
+ __DriverSetDriverObject(DriverObject);
+
+ Driver.DriverObject->DriverUnload = DriverUnload;
+
+ Info("XENVKBD %d.%d.%d (%d) (%02d.%02d.%04d)\n",
+ MAJOR_VERSION,
+ MINOR_VERSION,
+ MICRO_VERSION,
+ BUILD_NUMBER,
+ DAY,
+ MONTH,
+ YEAR);
+
+ status = RegistryInitialize(RegistryPath);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = RegistryOpenServiceKey(KEY_ALL_ACCESS, &ServiceKey);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = RegistryOpenSubKey(ServiceKey,
+ "Parameters",
+ KEY_READ,
+ &ParametersKey);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ __DriverSetParametersKey(ParametersKey);
+
+ RegistryCloseKey(ServiceKey);
+
+ DriverObject->DriverExtension->AddDevice = AddDevice;
+
+ for (Index = 0; Index <= IRP_MJ_MAXIMUM_FUNCTION; Index++) {
+#pragma prefast(suppress:28169) // No __drv_dispatchType annotation
+#pragma prefast(suppress:28168) // No matching __drv_dispatchType annotation for IRP_MJ_CREATE
+ DriverObject->MajorFunction[Index] = Dispatch;
+ }
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+
+ RegistryCloseKey(ServiceKey);
+
+fail2:
+ Error("fail2\n");
+
+ RegistryTeardown();
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ __DriverSetDriverObject(NULL);
+
+ ASSERT(IsZeroMemory(&Driver, sizeof (XENVKBD_DRIVER)));
+
+ return status;
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_DRIVER_H
+#define _XENVKBD_DRIVER_H
+
+extern BOOLEAN
+DriverSafeMode(
+ VOID
+ );
+
+extern PDRIVER_OBJECT
+DriverGetDriverObject(
+ VOID
+ );
+
+extern HANDLE
+DriverGetParametersKey(
+ VOID
+ );
+
+extern VOID
+DriverRequestReboot(
+ VOID
+ );
+
+typedef struct _XENVKBD_PDO XENVKBD_PDO, *PXENVKBD_PDO;
+typedef struct _XENVKBD_FDO XENVKBD_FDO, *PXENVKBD_FDO;
+
+#include "fdo.h"
+#include "pdo.h"
+
+#define MAX_DEVICE_ID_LEN 200
+#define MAX_GUID_STRING_LEN 39
+
+#pragma warning(push)
+#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union
+
+typedef struct _XENVKBD_DX {
+ PDEVICE_OBJECT DeviceObject;
+ DEVICE_OBJECT_TYPE Type;
+
+ DEVICE_PNP_STATE DevicePnpState;
+ DEVICE_PNP_STATE PreviousDevicePnpState;
+
+ SYSTEM_POWER_STATE SystemPowerState;
+ DEVICE_POWER_STATE DevicePowerState;
+
+ CHAR Name[MAX_DEVICE_ID_LEN];
+
+ LIST_ENTRY ListEntry;
+
+ union {
+ PXENVKBD_FDO Fdo;
+ PXENVKBD_PDO Pdo;
+ };
+} XENVKBD_DX, *PXENVKBD_DX;
+
+#pragma warning(pop)
+
+#endif // _XENVKBD_DRIVER_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#define INITGUID 1
+
+#include <ntddk.h>
+#include <wdmguid.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+
+#include <evtchn_interface.h>
+#include <debug_interface.h>
+#include <store_interface.h>
+#include <gnttab_interface.h>
+#include <suspend_interface.h>
+#include <unplug_interface.h>
+#include <version.h>
+
+#include "driver.h"
+#include "registry.h"
+#include "fdo.h"
+#include "pdo.h"
+#include "thread.h"
+#include "mutex.h"
+#include "frontend.h"
+#include "names.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+#define FDO_POOL 'ODF'
+
+#define MAXNAMELEN 128
+
+typedef enum _FDO_RESOURCE_TYPE {
+ MEMORY_RESOURCE = 0,
+ INTERRUPT_RESOURCE,
+ RESOURCE_COUNT
+} FDO_RESOURCE_TYPE, *PFDO_RESOURCE_TYPE;
+
+typedef struct _FDO_RESOURCE {
+ CM_PARTIAL_RESOURCE_DESCRIPTOR Raw;
+ CM_PARTIAL_RESOURCE_DESCRIPTOR Translated;
+} FDO_RESOURCE, *PFDO_RESOURCE;
+
+struct _XENVKBD_FDO {
+ PXENVKBD_DX Dx;
+ PDEVICE_OBJECT LowerDeviceObject;
+ PDEVICE_OBJECT PhysicalDeviceObject;
+ DEVICE_CAPABILITIES LowerDeviceCapabilities;
+ PBUS_INTERFACE_STANDARD LowerBusInterface;
+ ULONG Usage[DeviceUsageTypeDumpFile + 1];
+ BOOLEAN NotDisableable;
+
+ PXENVKBD_THREAD SystemPowerThread;
+ PIRP SystemPowerIrp;
+ PXENVKBD_THREAD DevicePowerThread;
+ PIRP DevicePowerIrp;
+
+ CHAR VendorName[MAXNAMELEN];
+
+ PXENVKBD_THREAD ScanThread;
+ KEVENT ScanEvent;
+ PXENBUS_STORE_WATCH ScanWatch;
+ MUTEX Mutex;
+ ULONG References;
+
+ FDO_RESOURCE Resource[RESOURCE_COUNT];
+
+ XENBUS_DEBUG_INTERFACE DebugInterface;
+ XENBUS_SUSPEND_INTERFACE SuspendInterface;
+ XENBUS_EVTCHN_INTERFACE EvtchnInterface;
+ XENBUS_STORE_INTERFACE StoreInterface;
+ XENBUS_RANGE_SET_INTERFACE RangeSetInterface;
+ XENBUS_CACHE_INTERFACE CacheInterface;
+ XENBUS_GNTTAB_INTERFACE GnttabInterface;
+ XENBUS_UNPLUG_INTERFACE UnplugInterface;
+
+ PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
+};
+
+static FORCEINLINE PVOID
+__FdoAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, FDO_POOL);
+}
+
+static FORCEINLINE VOID
+__FdoFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, FDO_POOL);
+}
+
+static FORCEINLINE VOID
+__FdoSetDevicePnpState(
+ IN PXENVKBD_FDO Fdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ // We can never transition out of the deleted state
+ ASSERT(Dx->DevicePnpState != Deleted || State == Deleted);
+
+ Dx->PreviousDevicePnpState = Dx->DevicePnpState;
+ Dx->DevicePnpState = State;
+}
+
+static FORCEINLINE VOID
+__FdoRestoreDevicePnpState(
+ IN PXENVKBD_FDO Fdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ if (Dx->DevicePnpState == State)
+ Dx->DevicePnpState = Dx->PreviousDevicePnpState;
+}
+
+static FORCEINLINE DEVICE_PNP_STATE
+__FdoGetDevicePnpState(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ return Dx->DevicePnpState;
+}
+
+static FORCEINLINE DEVICE_PNP_STATE
+__FdoGetPreviousDevicePnpState(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ return Dx->PreviousDevicePnpState;
+}
+
+static FORCEINLINE VOID
+__FdoSetDevicePowerState(
+ IN PXENVKBD_FDO Fdo,
+ IN DEVICE_POWER_STATE State
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ Dx->DevicePowerState = State;
+}
+
+static FORCEINLINE DEVICE_POWER_STATE
+__FdoGetDevicePowerState(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ return Dx->DevicePowerState;
+}
+
+static FORCEINLINE VOID
+__FdoSetSystemPowerState(
+ IN PXENVKBD_FDO Fdo,
+ IN SYSTEM_POWER_STATE State
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ Dx->SystemPowerState = State;
+}
+
+static FORCEINLINE SYSTEM_POWER_STATE
+__FdoGetSystemPowerState(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ return Dx->SystemPowerState;
+}
+
+static FORCEINLINE PDEVICE_OBJECT
+__FdoGetPhysicalDeviceObject(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ return Fdo->PhysicalDeviceObject;
+}
+
+PDEVICE_OBJECT
+FdoGetPhysicalDeviceObject(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ return __FdoGetPhysicalDeviceObject(Fdo);
+}
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+static FORCEINLINE NTSTATUS
+__FdoAcquireLowerBusInterface(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PBUS_INTERFACE_STANDARD BusInterface;
+ KEVENT Event;
+ IO_STATUS_BLOCK StatusBlock;
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ BusInterface = __FdoAllocate(sizeof (BUS_INTERFACE_STANDARD));
+
+ status = STATUS_NO_MEMORY;
+ if (BusInterface == NULL)
+ goto fail1;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ RtlZeroMemory(&StatusBlock, sizeof(IO_STATUS_BLOCK));
+
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
+ Fdo->LowerDeviceObject,
+ NULL,
+ 0,
+ NULL,
+ &Event,
+ &StatusBlock);
+
+ status = STATUS_UNSUCCESSFUL;
+ if (Irp == NULL)
+ goto fail2;
+
+ StackLocation = IoGetNextIrpStackLocation(Irp);
+ StackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE;
+
+ StackLocation->Parameters.QueryInterface.InterfaceType = &GUID_BUS_INTERFACE_STANDARD;
+ StackLocation->Parameters.QueryInterface.Size = sizeof (BUS_INTERFACE_STANDARD);
+ StackLocation->Parameters.QueryInterface.Version = 1;
+ StackLocation->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
+
+ Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ if (status == STATUS_PENDING) {
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ status = StatusBlock.Status;
+ }
+
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = STATUS_INVALID_PARAMETER;
+ if (BusInterface->Version != 1)
+ goto fail4;
+
+ Fdo->LowerBusInterface = BusInterface;
+
+ return STATUS_SUCCESS;
+
+fail4:
+ Error("fail4\n");
+
+fail3:
+ Error("fail3\n");
+
+fail2:
+ Error("fail2\n");
+
+ __FdoFree(BusInterface);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static FORCEINLINE VOID
+__FdoReleaseLowerBusInterface(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PBUS_INTERFACE_STANDARD BusInterface;
+
+ BusInterface = Fdo->LowerBusInterface;
+
+ if (BusInterface == NULL)
+ return;
+
+ Fdo->LowerBusInterface = NULL;
+
+ BusInterface->InterfaceDereference(BusInterface->Context);
+
+ __FdoFree(BusInterface);
+}
+
+PDMA_ADAPTER
+FdoGetDmaAdapter(
+ IN PXENVKBD_FDO Fdo,
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ )
+{
+ PBUS_INTERFACE_STANDARD BusInterface;
+
+ BusInterface = Fdo->LowerBusInterface;
+ ASSERT(BusInterface != NULL);
+
+ return BusInterface->GetDmaAdapter(BusInterface->Context,
+ DeviceDescriptor,
+ NumberOfMapRegisters);
+}
+
+BOOLEAN
+FdoTranslateBusAddress(
+ IN PXENVKBD_FDO Fdo,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN ULONG Length,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+{
+ PBUS_INTERFACE_STANDARD BusInterface;
+
+ BusInterface = Fdo->LowerBusInterface;
+ ASSERT(BusInterface != NULL);
+
+ return BusInterface->TranslateBusAddress(BusInterface->Context,
+ BusAddress,
+ Length,
+ AddressSpace,
+ TranslatedAddress);
+}
+
+ULONG
+FdoSetBusData(
+ IN PXENVKBD_FDO Fdo,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ PBUS_INTERFACE_STANDARD BusInterface;
+
+ BusInterface = Fdo->LowerBusInterface;
+ ASSERT(BusInterface != NULL);
+
+ return BusInterface->SetBusData(BusInterface->Context,
+ DataType,
+ Buffer,
+ Offset,
+ Length);
+}
+
+ULONG
+FdoGetBusData(
+ IN PXENVKBD_FDO Fdo,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ PBUS_INTERFACE_STANDARD BusInterface;
+
+ BusInterface = Fdo->LowerBusInterface;
+ ASSERT(BusInterface != NULL);
+
+ return BusInterface->GetBusData(BusInterface->Context,
+ DataType,
+ Buffer,
+ Offset,
+ Length);
+}
+
+static FORCEINLINE VOID
+__FdoSetVendorName(
+ IN PXENVKBD_FDO Fdo,
+ IN USHORT DeviceID
+ )
+{
+ NTSTATUS status;
+
+ status = RtlStringCbPrintfA(Fdo->VendorName,
+ MAXNAMELEN,
+ "%s%04X",
+ VENDOR_PREFIX_STR,
+ DeviceID);
+ ASSERT(NT_SUCCESS(status));
+}
+
+static FORCEINLINE PCHAR
+__FdoGetVendorName(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ return Fdo->VendorName;
+}
+
+PCHAR
+FdoGetVendorName(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ return __FdoGetVendorName(Fdo);
+}
+
+static FORCEINLINE VOID
+__FdoSetName(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+ NTSTATUS status;
+
+ status = RtlStringCbPrintfA(Dx->Name,
+ MAXNAMELEN,
+ "%s XENVKBD",
+ __FdoGetVendorName(Fdo));
+ ASSERT(NT_SUCCESS(status));
+}
+
+static FORCEINLINE PCHAR
+__FdoGetName(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+
+ return Dx->Name;
+}
+
+PCHAR
+FdoGetName(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ return __FdoGetName(Fdo);
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoDelegateIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PKEVENT Event = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+FdoDelegateIrp(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PDEVICE_OBJECT DeviceObject;
+ PIO_STACK_LOCATION StackLocation;
+ PIRP SubIrp;
+ KEVENT Event;
+ PIO_STACK_LOCATION SubStackLocation;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ // Find the top of the FDO stack and hold a reference
+ DeviceObject = IoGetAttachedDeviceReference(Fdo->Dx->DeviceObject);
+
+ // Get a new IRP for the FDO stack
+ SubIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+
+ status = STATUS_NO_MEMORY;
+ if (SubIrp == NULL)
+ goto done;
+
+ // Copy in the information from the original IRP
+ SubStackLocation = IoGetNextIrpStackLocation(SubIrp);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ RtlCopyMemory(SubStackLocation, StackLocation,
+ FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
+ SubStackLocation->Control = 0;
+
+ IoSetCompletionRoutine(SubIrp,
+ __FdoDelegateIrp,
+ &Event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ // Default completion status
+ SubIrp->IoStatus.Status = Irp->IoStatus.Status;
+
+ status = IoCallDriver(DeviceObject, SubIrp);
+ if (status == STATUS_PENDING) {
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ status = SubIrp->IoStatus.Status;
+ } else {
+ ASSERT3U(status, ==, SubIrp->IoStatus.Status);
+ }
+
+ IoFreeIrp(SubIrp);
+
+done:
+ ObDereferenceObject(DeviceObject);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoForwardIrpSynchronously(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PKEVENT Event = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static NTSTATUS
+FdoForwardIrpSynchronously(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ KEVENT Event;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoForwardIrpSynchronously,
+ &Event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ if (status == STATUS_PENDING) {
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ status = Irp->IoStatus.Status;
+ } else {
+ ASSERT3U(status, ==, Irp->IoStatus.Status);
+ }
+
+ Trace("%08x\n", status);
+
+ return status;
+}
+
+NTSTATUS
+FdoAddPhysicalDeviceObject(
+ IN PXENVKBD_FDO Fdo,
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PDEVICE_OBJECT DeviceObject;
+ PXENVKBD_DX Dx;
+ NTSTATUS status;
+
+ DeviceObject = PdoGetDeviceObject(Pdo);
+ Dx = (PXENVKBD_DX)DeviceObject->DeviceExtension;
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD3)
+ goto done;
+
+ status = PdoResume(Pdo);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+done:
+ InsertTailList(&Fdo->Dx->ListEntry, &Dx->ListEntry);
+ ASSERT3U(Fdo->References, !=, 0);
+ Fdo->References++;
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+FdoRemovePhysicalDeviceObject(
+ IN PXENVKBD_FDO Fdo,
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PDEVICE_OBJECT DeviceObject;
+ PXENVKBD_DX Dx;
+
+ DeviceObject = PdoGetDeviceObject(Pdo);
+ Dx = (PXENVKBD_DX)DeviceObject->DeviceExtension;
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD3)
+ goto done;
+
+ PdoSuspend(Pdo);
+
+done:
+ RemoveEntryList(&Dx->ListEntry);
+ ASSERT3U(Fdo->References, !=, 0);
+ --Fdo->References;
+
+ if (Fdo->ScanThread)
+ ThreadWake(Fdo->ScanThread);
+}
+
+static FORCEINLINE VOID
+__FdoAcquireMutex(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ AcquireMutex(&Fdo->Mutex);
+}
+
+VOID
+FdoAcquireMutex(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ __FdoAcquireMutex(Fdo);
+}
+
+static FORCEINLINE VOID
+__FdoReleaseMutex(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ ReleaseMutex(&Fdo->Mutex);
+}
+
+VOID
+FdoReleaseMutex(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ __FdoReleaseMutex(Fdo);
+
+ if (Fdo->References == 0)
+ FdoDestroy(Fdo);
+}
+
+static FORCEINLINE BOOLEAN
+__FdoEnumerate(
+ IN PXENVKBD_FDO Fdo,
+ IN PANSI_STRING Devices
+ )
+{
+ BOOLEAN NeedInvalidate;
+ HANDLE ParametersKey;
+ ULONG Enumerate;
+ PLIST_ENTRY ListEntry;
+ ULONG Index;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ NeedInvalidate = FALSE;
+
+ ParametersKey = DriverGetParametersKey();
+
+ status = RegistryQueryDwordValue(ParametersKey,
+ "Enumerate",
+ &Enumerate);
+ if (!NT_SUCCESS(status))
+ Enumerate = 1;
+
+ if (Enumerate == 0)
+ goto done;
+
+ __FdoAcquireMutex(Fdo);
+
+ ListEntry = Fdo->Dx->ListEntry.Flink;
+ while (ListEntry != &Fdo->Dx->ListEntry) {
+ PLIST_ENTRY Next = ListEntry->Flink;
+ PXENVKBD_DX Dx = CONTAINING_RECORD(ListEntry, XENVKBD_DX, ListEntry);
+ PXENVKBD_PDO Pdo = Dx->Pdo;
+
+ if (PdoGetDevicePnpState(Pdo) != Deleted) {
+ PCHAR Name;
+ BOOLEAN Missing;
+
+ Name = PdoGetName(Pdo);
+ Missing = TRUE;
+
+ // If the PDO already exists and its name is in the device list
+ // then we don't want to remove it.
+ for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+ PANSI_STRING Device = &Devices[Index];
+
+ if (Device->Length == 0)
+ continue;
+
+ if (strcmp(Name, Device->Buffer) == 0) {
+ Missing = FALSE;
+ Device->Length = 0; // avoid duplication
+ break;
+ }
+ }
+
+ if (!PdoIsMissing(Pdo)) {
+ if (PdoIsEjectRequested(Pdo)) {
+ IoRequestDeviceEject(PdoGetDeviceObject(Pdo));
+ } else if (Missing) {
+ PdoSetMissing(Pdo, "device disappeared");
+
+ // If the PDO has not yet been enumerated then we can
+ // go ahead and mark it as deleted, otherwise we need
+ // to notify PnP manager and wait for the REMOVE_DEVICE
+ // IRP.
+ if (PdoGetDevicePnpState(Pdo) == Present) {
+ PdoSetDevicePnpState(Pdo, Deleted);
+ PdoDestroy(Pdo);
+ } else {
+ NeedInvalidate = TRUE;
+ }
+ }
+ }
+ }
+
+ ListEntry = Next;
+ }
+
+ // Walk the class list and create PDOs for any new device
+ for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+ PANSI_STRING Device = &Devices[Index];
+
+ if (Device->Length == 0)
+ continue;
+
+ status = PdoCreate(Fdo, Device);
+ if (NT_SUCCESS(status))
+ NeedInvalidate = TRUE;
+ }
+
+ __FdoReleaseMutex(Fdo);
+
+done:
+ Trace("<====\n");
+
+ return NeedInvalidate;
+}
+
+static FORCEINLINE PANSI_STRING
+__FdoMultiSzToUpcaseAnsi(
+ IN PCHAR Buffer
+ )
+{
+ PANSI_STRING Ansi;
+ LONG Index;
+ LONG Count;
+ NTSTATUS status;
+
+ Index = 0;
+ Count = 0;
+ for (;;) {
+ if (Buffer[Index] == '\0') {
+ Count++;
+ Index++;
+
+ // Check for double NUL
+ if (Buffer[Index] == '\0')
+ break;
+ } else {
+ Buffer[Index] = __toupper(Buffer[Index]);
+ Index++;
+ }
+ }
+
+ Ansi = __FdoAllocate(sizeof (ANSI_STRING) * (Count + 1));
+
+ status = STATUS_NO_MEMORY;
+ if (Ansi == NULL)
+ goto fail1;
+
+ for (Index = 0; Index < Count; Index++) {
+ ULONG Length;
+
+ Length = (ULONG)strlen(Buffer);
+ Ansi[Index].MaximumLength = (USHORT)(Length + 1);
+ Ansi[Index].Buffer = __FdoAllocate(Ansi[Index].MaximumLength);
+
+ status = STATUS_NO_MEMORY;
+ if (Ansi[Index].Buffer == NULL)
+ goto fail2;
+
+ RtlCopyMemory(Ansi[Index].Buffer, Buffer, Length);
+ Ansi[Index].Length = (USHORT)Length;
+
+ Buffer += Length + 1;
+ }
+
+ return Ansi;
+
+fail2:
+ Error("fail2\n");
+
+ while (--Index >= 0)
+ __FdoFree(Ansi[Index].Buffer);
+
+ __FdoFree(Ansi);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return NULL;
+}
+
+static FORCEINLINE VOID
+__FdoFreeAnsi(
+ IN PANSI_STRING Ansi
+ )
+{
+ ULONG Index;
+
+ for (Index = 0; Ansi[Index].Buffer != NULL; Index++)
+ __FdoFree(Ansi[Index].Buffer);
+
+ __FdoFree(Ansi);
+}
+
+static NTSTATUS
+FdoScan(
+ PXENVKBD_THREAD Self,
+ PVOID Context
+ )
+{
+ PXENVKBD_FDO Fdo = Context;
+ PKEVENT Event;
+ HANDLE ParametersKey;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ Event = ThreadGetEvent(Self);
+
+ ParametersKey = DriverGetParametersKey();
+
+ for (;;) {
+ PCHAR Buffer;
+ PANSI_STRING Devices;
+ PANSI_STRING UnsupportedDevices;
+ ULONG Index;
+ BOOLEAN NeedInvalidate;
+
+ Trace("waiting...\n");
+
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ // It is not safe to use interfaces before this point
+ if (__FdoGetDevicePnpState(Fdo) != Started) {
+ KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+ continue;
+ }
+
+ status = XENBUS_STORE(Directory,
+ &Fdo->StoreInterface,
+ NULL,
+ "device",
+ "vkbd",
+ &Buffer);
+ if (NT_SUCCESS(status)) {
+ Devices = __FdoMultiSzToUpcaseAnsi(Buffer);
+
+ XENBUS_STORE(Free,
+ &Fdo->StoreInterface,
+ Buffer);
+ } else {
+ Devices = NULL;
+ }
+
+ if (Devices == NULL)
+ goto loop;
+
+ if (ParametersKey != NULL) {
+ status = RegistryQuerySzValue(ParametersKey,
+ "UnsupportedDevices",
+ NULL,
+ &UnsupportedDevices);
+ if (!NT_SUCCESS(status))
+ UnsupportedDevices = NULL;
+ } else {
+ UnsupportedDevices = NULL;
+ }
+
+ // NULL out anything in the Devices list that is in the
+ // UnsupportedDevices list
+ for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+ PANSI_STRING Device = &Devices[Index];
+ ULONG Entry;
+ BOOLEAN Supported;
+
+ Supported = TRUE;
+
+ for (Entry = 0;
+ UnsupportedDevices != NULL && UnsupportedDevices[Entry].Buffer != NULL;
+ Entry++) {
+ if (strncmp(Device->Buffer,
+ UnsupportedDevices[Entry].Buffer,
+ Device->Length) == 0) {
+ Supported = FALSE;
+ break;
+ }
+ }
+
+ if (!Supported)
+ Device->Length = 0;
+ }
+
+ if (UnsupportedDevices != NULL)
+ RegistryFreeSzValue(UnsupportedDevices);
+
+ NeedInvalidate = __FdoEnumerate(Fdo, Devices);
+
+ __FdoFreeAnsi(Devices);
+
+ if (NeedInvalidate) {
+ NeedInvalidate = FALSE;
+ IoInvalidateDeviceRelations(__FdoGetPhysicalDeviceObject(Fdo),
+ BusRelations);
+ }
+
+loop:
+ KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+
+ Trace("<====\n");
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE VOID
+FdoParseResources(
+ IN PXENVKBD_FDO Fdo,
+ IN PCM_RESOURCE_LIST RawResourceList,
+ IN PCM_RESOURCE_LIST TranslatedResourceList
+ )
+{
+ PCM_PARTIAL_RESOURCE_LIST RawPartialList;
+ PCM_PARTIAL_RESOURCE_LIST TranslatedPartialList;
+ ULONG Index;
+
+ ASSERT3U(RawResourceList->Count, ==, 1);
+ RawPartialList = &RawResourceList->List[0].PartialResourceList;
+
+ ASSERT3U(RawPartialList->Version, ==, 1);
+ ASSERT3U(RawPartialList->Revision, ==, 1);
+
+ ASSERT3U(TranslatedResourceList->Count, ==, 1);
+ TranslatedPartialList = &TranslatedResourceList->List[0].PartialResourceList;
+
+ ASSERT3U(TranslatedPartialList->Version, ==, 1);
+ ASSERT3U(TranslatedPartialList->Revision, ==, 1);
+
+ for (Index = 0; Index < TranslatedPartialList->Count; Index++) {
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR RawPartialDescriptor;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedPartialDescriptor;
+
+ RawPartialDescriptor = &RawPartialList->PartialDescriptors[Index];
+ TranslatedPartialDescriptor = &TranslatedPartialList->PartialDescriptors[Index];
+
+ switch (TranslatedPartialDescriptor->Type) {
+ case CmResourceTypeMemory:
+ Fdo->Resource[MEMORY_RESOURCE].Raw = *RawPartialDescriptor;
+ Fdo->Resource[MEMORY_RESOURCE].Translated = *TranslatedPartialDescriptor;
+ break;
+
+ case CmResourceTypeInterrupt:
+ Fdo->Resource[INTERRUPT_RESOURCE].Raw = *RawPartialDescriptor;
+ Fdo->Resource[INTERRUPT_RESOURCE].Translated = *TranslatedPartialDescriptor;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static FORCEINLINE BOOLEAN
+__FdoMatchDistribution(
+ IN PXENVKBD_FDO Fdo,
+ IN PCHAR Buffer
+ )
+{
+ PCHAR Vendor;
+ PCHAR Product;
+ PCHAR Context;
+ const CHAR *Text;
+ BOOLEAN Match;
+ ULONG Index;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Fdo);
+
+ status = STATUS_INVALID_PARAMETER;
+
+ Vendor = __strtok_r(Buffer, " ", &Context);
+ if (Vendor == NULL)
+ goto fail1;
+
+ Product = __strtok_r(NULL, " ", &Context);
+ if (Product == NULL)
+ goto fail2;
+
+ Match = TRUE;
+
+ Text = VENDOR_NAME_STR;
+
+ for (Index = 0; Text[Index] != 0; Index++) {
+ if (!isalnum((UCHAR)Text[Index])) {
+ if (Vendor[Index] != '_') {
+ Match = FALSE;
+ break;
+ }
+ } else {
+ if (Vendor[Index] != Text[Index]) {
+ Match = FALSE;
+ break;
+ }
+ }
+ }
+
+ Text = "XENVKBD";
+
+ if (_stricmp(Product, Text) != 0)
+ Match = FALSE;
+
+ return Match;
+
+fail2:
+ Error("fail2\n");
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return FALSE;
+}
+
+static VOID
+FdoClearDistribution(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PCHAR Buffer;
+ PANSI_STRING Distributions;
+ ULONG Index;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ status = XENBUS_STORE(Directory,
+ &Fdo->StoreInterface,
+ NULL,
+ NULL,
+ "drivers",
+ &Buffer);
+ if (NT_SUCCESS(status)) {
+ Distributions = __FdoMultiSzToUpcaseAnsi(Buffer);
+
+ XENBUS_STORE(Free,
+ &Fdo->StoreInterface,
+ Buffer);
+ } else {
+ Distributions = NULL;
+ }
+
+ if (Distributions == NULL)
+ goto done;
+
+ for (Index = 0; Distributions[Index].Buffer != NULL; Index++) {
+ PANSI_STRING Distribution = &Distributions[Index];
+
+ status = XENBUS_STORE(Read,
+ &Fdo->StoreInterface,
+ NULL,
+ "drivers",
+ Distribution->Buffer,
+ &Buffer);
+ if (!NT_SUCCESS(status))
+ continue;
+
+ if (__FdoMatchDistribution(Fdo, Buffer))
+ (VOID) XENBUS_STORE(Remove,
+ &Fdo->StoreInterface,
+ NULL,
+ "drivers",
+ Distribution->Buffer);
+
+ XENBUS_STORE(Free,
+ &Fdo->StoreInterface,
+ Buffer);
+ }
+
+ __FdoFreeAnsi(Distributions);
+
+done:
+ Trace("<====\n");
+}
+
+#define MAXIMUM_INDEX 255
+
+static NTSTATUS
+FdoSetDistribution(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ ULONG Index;
+ CHAR Distribution[MAXNAMELEN];
+ CHAR Vendor[MAXNAMELEN];
+ const CHAR *Product;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ Index = 0;
+ while (Index <= MAXIMUM_INDEX) {
+ PCHAR Buffer;
+
+ status = RtlStringCbPrintfA(Distribution,
+ MAXNAMELEN,
+ "%u",
+ Index);
+ ASSERT(NT_SUCCESS(status));
+
+ status = XENBUS_STORE(Read,
+ &Fdo->StoreInterface,
+ NULL,
+ "drivers",
+ Distribution,
+ &Buffer);
+ if (!NT_SUCCESS(status)) {
+ if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+ goto update;
+
+ goto fail1;
+ }
+
+ XENBUS_STORE(Free,
+ &Fdo->StoreInterface,
+ Buffer);
+
+ Index++;
+ }
+
+ status = STATUS_UNSUCCESSFUL;
+ goto fail2;
+
+update:
+ status = RtlStringCbPrintfA(Vendor,
+ MAXNAMELEN,
+ "%s",
+ VENDOR_NAME_STR);
+ ASSERT(NT_SUCCESS(status));
+
+ for (Index = 0; Vendor[Index] != '\0'; Index++)
+ if (!isalnum((UCHAR)Vendor[Index]))
+ Vendor[Index] = '_';
+
+ Product = "XENVKBD";
+
+#if DBG
+#define ATTRIBUTES "(DEBUG)"
+#else
+#define ATTRIBUTES ""
+#endif
+
+ (VOID) XENBUS_STORE(Printf,
+ &Fdo->StoreInterface,
+ NULL,
+ "drivers",
+ Distribution,
+ "%s %s %u.%u.%u %s",
+ Vendor,
+ Product,
+ MAJOR_VERSION,
+ MINOR_VERSION,
+ MICRO_VERSION,
+ ATTRIBUTES
+ );
+
+#undef ATTRIBUTES
+
+ Trace("<====\n");
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoD3ToD0(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+ (VOID) FdoSetDistribution(Fdo);
+
+ status = XENBUS_STORE(WatchAdd,
+ &Fdo->StoreInterface,
+ "device",
+ "vkbd",
+ ThreadGetEvent(Fdo->ScanThread),
+ &Fdo->ScanWatch);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ (VOID) XENBUS_STORE(Printf,
+ &Fdo->StoreInterface,
+ NULL,
+ "feature/hotplug",
+ "vkbd",
+ "%u",
+ TRUE);
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static FORCEINLINE VOID
+__FdoD0ToD3(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ Trace("====>\n");
+
+ ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+ (VOID) XENBUS_STORE(Remove,
+ &Fdo->StoreInterface,
+ NULL,
+ "feature/hotplug",
+ "vkbd");
+
+ (VOID) XENBUS_STORE(WatchRemove,
+ &Fdo->StoreInterface,
+ Fdo->ScanWatch);
+ Fdo->ScanWatch = NULL;
+
+ FdoClearDistribution(Fdo);
+
+ Trace("<====\n");
+}
+
+static DECLSPEC_NOINLINE VOID
+FdoSuspendCallbackLate(
+ IN PVOID Argument
+ )
+{
+ PXENVKBD_FDO Fdo = Argument;
+ NTSTATUS status;
+
+ __FdoD0ToD3(Fdo);
+
+ status = __FdoD3ToD0(Fdo);
+ ASSERT(NT_SUCCESS(status));
+}
+
+// This function must not touch pageable code or data
+static DECLSPEC_NOINLINE NTSTATUS
+FdoD3ToD0(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ POWER_STATE PowerState;
+ KIRQL Irql;
+ PLIST_ENTRY ListEntry;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3U(__FdoGetDevicePowerState(Fdo), ==, PowerDeviceD3);
+
+ Trace("====>\n");
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ status = XENBUS_SUSPEND(Acquire, &Fdo->SuspendInterface);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = XENBUS_STORE(Acquire, &Fdo->StoreInterface);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = __FdoD3ToD0(Fdo);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = XENBUS_SUSPEND(Register,
+ &Fdo->SuspendInterface,
+ SUSPEND_CALLBACK_LATE,
+ FdoSuspendCallbackLate,
+ Fdo,
+ &Fdo->SuspendCallbackLate);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ KeLowerIrql(Irql);
+
+ __FdoSetDevicePowerState(Fdo, PowerDeviceD0);
+
+ PowerState.DeviceState = PowerDeviceD0;
+ PoSetPowerState(Fdo->Dx->DeviceObject,
+ DevicePowerState,
+ PowerState);
+
+ __FdoAcquireMutex(Fdo);
+
+ for (ListEntry = Fdo->Dx->ListEntry.Flink;
+ ListEntry != &Fdo->Dx->ListEntry;
+ ListEntry = ListEntry->Flink) {
+ PXENVKBD_DX Dx = CONTAINING_RECORD(ListEntry, XENVKBD_DX, ListEntry);
+ PXENVKBD_PDO Pdo = Dx->Pdo;
+
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ status = PdoResume(Pdo);
+ ASSERT(NT_SUCCESS(status));
+ }
+
+ __FdoReleaseMutex(Fdo);
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail4:
+ Error("fail4\n");
+
+ __FdoD0ToD3(Fdo);
+
+fail3:
+ Error("fail3\n");
+
+ XENBUS_STORE(Release, &Fdo->StoreInterface);
+
+fail2:
+ Error("fail2\n");
+
+ XENBUS_SUSPEND(Release, &Fdo->SuspendInterface);
+
+ __FdoD0ToD3(Fdo);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ KeLowerIrql(Irql);
+
+ return status;
+}
+
+// This function must not touch pageable code or data
+static DECLSPEC_NOINLINE VOID
+FdoD0ToD3(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ POWER_STATE PowerState;
+ PLIST_ENTRY ListEntry;
+ KIRQL Irql;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3U(__FdoGetDevicePowerState(Fdo), ==, PowerDeviceD0);
+
+ Trace("====>\n");
+
+ __FdoAcquireMutex(Fdo);
+
+ for (ListEntry = Fdo->Dx->ListEntry.Flink;
+ ListEntry != &Fdo->Dx->ListEntry;
+ ListEntry = ListEntry->Flink) {
+ PXENVKBD_DX Dx = CONTAINING_RECORD(ListEntry, XENVKBD_DX, ListEntry);
+ PXENVKBD_PDO Pdo = Dx->Pdo;
+
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ if (PdoGetDevicePnpState(Pdo) == Deleted ||
+ PdoIsMissing(Pdo))
+ continue;
+
+ PdoSuspend(Pdo);
+ }
+
+ __FdoReleaseMutex(Fdo);
+
+ PowerState.DeviceState = PowerDeviceD3;
+ PoSetPowerState(Fdo->Dx->DeviceObject,
+ DevicePowerState,
+ PowerState);
+
+ __FdoSetDevicePowerState(Fdo, PowerDeviceD3);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ XENBUS_SUSPEND(Deregister,
+ &Fdo->SuspendInterface,
+ Fdo->SuspendCallbackLate);
+ Fdo->SuspendCallbackLate = NULL;
+
+ __FdoD0ToD3(Fdo);
+
+ XENBUS_STORE(Release, &Fdo->StoreInterface);
+
+ XENBUS_SUSPEND(Release, &Fdo->SuspendInterface);
+
+ KeLowerIrql(Irql);
+
+ Trace("<====\n");
+}
+
+// This function must not touch pageable code or data
+static DECLSPEC_NOINLINE VOID
+FdoS4ToS3(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3U(__FdoGetSystemPowerState(Fdo), ==, PowerSystemHibernate);
+
+ __FdoSetSystemPowerState(Fdo, PowerSystemSleeping3);
+}
+
+// This function must not touch pageable code or data
+static DECLSPEC_NOINLINE VOID
+FdoS3ToS4(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3U(__FdoGetSystemPowerState(Fdo), ==, PowerSystemSleeping3);
+
+ __FdoSetSystemPowerState(Fdo, PowerSystemHibernate);
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoStartDevice(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ NTSTATUS status;
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ FdoParseResources(Fdo,
+ StackLocation->Parameters.StartDevice.AllocatedResources,
+ StackLocation->Parameters.StartDevice.AllocatedResourcesTranslated);
+
+ KeInitializeEvent(&Fdo->ScanEvent, NotificationEvent, FALSE);
+
+ status = ThreadCreate(FdoScan, Fdo, &Fdo->ScanThread);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = FdoD3ToD0(Fdo);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ __FdoSetDevicePnpState(Fdo, Started);
+ ThreadWake(Fdo->ScanThread);
+
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+
+fail3:
+ Error("fail3\n");
+
+ ThreadAlert(Fdo->ScanThread);
+ ThreadJoin(Fdo->ScanThread);
+ Fdo->ScanThread = NULL;
+
+fail2:
+ Error("fail2\n");
+
+ RtlZeroMemory(&Fdo->ScanEvent, sizeof (KEVENT));
+
+ RtlZeroMemory(&Fdo->Resource, sizeof (FDO_RESOURCE) * RESOURCE_COUNT);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoQueryStopDevice(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ __FdoSetDevicePnpState(Fdo, StopPending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoCancelStopDevice(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ __FdoRestoreDevicePnpState(Fdo, StopPending);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoStopDevice(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
+ FdoD0ToD3(Fdo);
+
+ ThreadAlert(Fdo->ScanThread);
+ ThreadJoin(Fdo->ScanThread);
+ Fdo->ScanThread = NULL;
+
+ RtlZeroMemory(&Fdo->ScanEvent, sizeof (KEVENT));
+
+ RtlZeroMemory(&Fdo->Resource, sizeof (FDO_RESOURCE) * RESOURCE_COUNT);
+
+ __FdoSetDevicePnpState(Fdo, Stopped);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoQueryRemoveDevice(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ __FdoSetDevicePnpState(Fdo, RemovePending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoCancelRemoveDevice(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ __FdoRestoreDevicePnpState(Fdo, RemovePending);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoSurpriseRemoval(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PLIST_ENTRY ListEntry;
+ NTSTATUS status;
+
+ __FdoSetDevicePnpState(Fdo, SurpriseRemovePending);
+
+ __FdoAcquireMutex(Fdo);
+
+ for (ListEntry = Fdo->Dx->ListEntry.Flink;
+ ListEntry != &Fdo->Dx->ListEntry;
+ ListEntry = ListEntry->Flink) {
+ PXENVKBD_DX Dx = CONTAINING_RECORD(ListEntry, XENVKBD_DX, ListEntry);
+ PXENVKBD_PDO Pdo = Dx->Pdo;
+
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ if (!PdoIsMissing(Pdo))
+ PdoSetMissing(Pdo, "FDO surprise removed");
+ }
+
+ __FdoReleaseMutex(Fdo);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoRemoveDevice(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PLIST_ENTRY ListEntry;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ if (__FdoGetPreviousDevicePnpState(Fdo) != Started)
+ goto done;
+
+ KeClearEvent(&Fdo->ScanEvent);
+ ThreadWake(Fdo->ScanThread);
+
+ Trace("waiting for scan thread\n");
+
+ (VOID) KeWaitForSingleObject(&Fdo->ScanEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ __FdoAcquireMutex(Fdo);
+
+ ListEntry = Fdo->Dx->ListEntry.Flink;
+ while (ListEntry != &Fdo->Dx->ListEntry) {
+ PLIST_ENTRY Flink = ListEntry->Flink;
+ PXENVKBD_DX Dx = CONTAINING_RECORD(ListEntry, XENVKBD_DX, ListEntry);
+ PXENVKBD_PDO Pdo = Dx->Pdo;
+
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ if (!PdoIsMissing(Pdo))
+ PdoSetMissing(Pdo, "FDO removed");
+
+ if (PdoGetDevicePnpState(Pdo) != SurpriseRemovePending)
+ PdoSetDevicePnpState(Pdo, Deleted);
+
+ if (PdoGetDevicePnpState(Pdo) == Deleted)
+ PdoDestroy(Pdo);
+
+ ListEntry = Flink;
+ }
+
+ __FdoReleaseMutex(Fdo);
+
+ if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
+ FdoD0ToD3(Fdo);
+
+ ThreadAlert(Fdo->ScanThread);
+ ThreadJoin(Fdo->ScanThread);
+ Fdo->ScanThread = NULL;
+
+ RtlZeroMemory(&Fdo->ScanEvent, sizeof (KEVENT));
+
+ RtlZeroMemory(&Fdo->Resource, sizeof (FDO_RESOURCE) * RESOURCE_COUNT);
+
+done:
+ __FdoSetDevicePnpState(Fdo, Deleted);
+
+ // We must release our reference before the PDO is destroyed
+ __FdoReleaseLowerBusInterface(Fdo);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ __FdoAcquireMutex(Fdo);
+ ASSERT3U(Fdo->References, !=, 0);
+ --Fdo->References;
+ __FdoReleaseMutex(Fdo);
+
+ if (Fdo->References == 0)
+ FdoDestroy(Fdo);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoQueryDeviceRelations(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ ULONG Size;
+ PDEVICE_RELATIONS Relations;
+ ULONG Count;
+ PLIST_ENTRY ListEntry;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ status = Irp->IoStatus.Status;
+
+ if (StackLocation->Parameters.QueryDeviceRelations.Type != BusRelations) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ KeClearEvent(&Fdo->ScanEvent);
+ ThreadWake(Fdo->ScanThread);
+
+ Trace("waiting for scan thread\n");
+
+ (VOID) KeWaitForSingleObject(&Fdo->ScanEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ __FdoAcquireMutex(Fdo);
+
+ Count = 0;
+ for (ListEntry = Fdo->Dx->ListEntry.Flink;
+ ListEntry != &Fdo->Dx->ListEntry;
+ ListEntry = ListEntry->Flink)
+ Count++;
+
+ Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + (sizeof (PDEVICE_OBJECT) * __max(Count, 1));
+
+ Relations = ExAllocatePoolWithTag(PagedPool, Size, 'FIV');
+
+ status = STATUS_NO_MEMORY;
+ if (Relations == NULL)
+ goto fail1;
+
+ RtlZeroMemory(Relations, Size);
+
+ for (ListEntry = Fdo->Dx->ListEntry.Flink;
+ ListEntry != &Fdo->Dx->ListEntry;
+ ListEntry = ListEntry->Flink) {
+ PXENVKBD_DX Dx = CONTAINING_RECORD(ListEntry, XENVKBD_DX, ListEntry);
+ PXENVKBD_PDO Pdo = Dx->Pdo;
+
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ if (PdoIsMissing(Pdo))
+ continue;
+
+ if (PdoGetDevicePnpState(Pdo) == Present)
+ PdoSetDevicePnpState(Pdo, Enumerated);
+
+ ObReferenceObject(Dx->DeviceObject);
+ Relations->Objects[Relations->Count++] = Dx->DeviceObject;
+ }
+
+ ASSERT3U(Relations->Count, <=, Count);
+
+ Trace("%d PDO(s)\n", Relations->Count);
+
+ __FdoReleaseMutex(Fdo);
+
+ Irp->IoStatus.Information = (ULONG_PTR)Relations;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ __FdoAcquireMutex(Fdo);
+
+ ListEntry = Fdo->Dx->ListEntry.Flink;
+ while (ListEntry != &Fdo->Dx->ListEntry) {
+ PXENVKBD_DX Dx = CONTAINING_RECORD(ListEntry, XENVKBD_DX, ListEntry);
+ PXENVKBD_PDO Pdo = Dx->Pdo;
+ PLIST_ENTRY Next = ListEntry->Flink;
+
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ if (PdoGetDevicePnpState(Pdo) == Deleted &&
+ PdoIsMissing(Pdo))
+ PdoDestroy(Pdo);
+
+ ListEntry = Next;
+ }
+
+ __FdoReleaseMutex(Fdo);
+
+done:
+ return status;
+
+fail2:
+ Error("fail2\n");
+
+ __FdoAcquireMutex(Fdo);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ __FdoReleaseMutex(Fdo);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoQueryCapabilities(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ PDEVICE_CAPABILITIES Capabilities;
+ SYSTEM_POWER_STATE SystemPowerState;
+ NTSTATUS status;
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ Capabilities = StackLocation->Parameters.DeviceCapabilities.Capabilities;
+
+ Fdo->LowerDeviceCapabilities = *Capabilities;
+
+ for (SystemPowerState = 0; SystemPowerState < PowerSystemMaximum; SystemPowerState++) {
+ DEVICE_POWER_STATE DevicePowerState;
+
+ DevicePowerState = Fdo->LowerDeviceCapabilities.DeviceState[SystemPowerState];
+ }
+
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDeviceUsageNotification(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_USAGE_NOTIFICATION_TYPE Type;
+ BOOLEAN InPath;
+ BOOLEAN NotDisableable;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ Type = StackLocation->Parameters.UsageNotification.Type;
+ InPath = StackLocation->Parameters.UsageNotification.InPath;
+
+ if (InPath) {
+ Trace("%s: ADDING %s\n",
+ __FdoGetName(Fdo),
+ DeviceUsageTypeName(Type));
+ Fdo->Usage[Type]++;
+ } else {
+ if (Fdo->Usage[Type] != 0) {
+ Trace("%s: REMOVING %s\n",
+ __FdoGetName(Fdo),
+ DeviceUsageTypeName(Type));
+ --Fdo->Usage[Type];
+ }
+ }
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ NotDisableable = FALSE;
+ for (Type = 0; Type <= DeviceUsageTypeDumpFile; Type++) {
+ if (Fdo->Usage[Type] != 0) {
+ NotDisableable = TRUE;
+ break;
+ }
+ }
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ if (Fdo->NotDisableable != NotDisableable) {
+ Fdo->NotDisableable = NotDisableable;
+
+ IoInvalidateDeviceState(__FdoGetPhysicalDeviceObject(Fdo));
+ }
+
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoQueryPnpDeviceState(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ ULONG_PTR State;
+ NTSTATUS status;
+
+ if (Irp->IoStatus.Status == STATUS_SUCCESS)
+ State = Irp->IoStatus.Information;
+ else if (Irp->IoStatus.Status == STATUS_NOT_SUPPORTED)
+ State = 0;
+ else
+ goto done;
+
+ if (Fdo->NotDisableable) {
+ Info("%s: not disableable\n", __FdoGetName(Fdo));
+ State |= PNP_DEVICE_NOT_DISABLEABLE;
+ }
+
+ Irp->IoStatus.Information = State;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+done:
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchPnp(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ Trace("====> (%02x:%s)\n",
+ MinorFunction,
+ PnpMinorFunctionName(MinorFunction));
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_START_DEVICE:
+ status = FdoStartDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_STOP_DEVICE:
+ status = FdoQueryStopDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_CANCEL_STOP_DEVICE:
+ status = FdoCancelStopDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_STOP_DEVICE:
+ status = FdoStopDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ status = FdoQueryRemoveDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_SURPRISE_REMOVAL:
+ status = FdoSurpriseRemoval(Fdo, Irp);
+ break;
+
+ case IRP_MN_REMOVE_DEVICE:
+ status = FdoRemoveDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ status = FdoCancelRemoveDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ status = FdoQueryDeviceRelations(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_CAPABILITIES:
+ status = FdoQueryCapabilities(Fdo, Irp);
+ break;
+
+ case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+ status = FdoDeviceUsageNotification(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_PNP_DEVICE_STATE:
+ status = FdoQueryPnpDeviceState(Fdo, Irp);
+ break;
+
+ default:
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ break;
+ }
+
+ Trace("<==== (%02x:%s)(%08x)\n",
+ MinorFunction,
+ PnpMinorFunctionName(MinorFunction),
+ status);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePowerUp(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, <, __FdoGetDevicePowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ Info("%s: %s -> %s\n",
+ __FdoGetName(Fdo),
+ PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
+ PowerDeviceStateName(DeviceState));
+
+ ASSERT3U(DeviceState, ==, PowerDeviceD0);
+ status = FdoD3ToD0(Fdo);
+ ASSERT(NT_SUCCESS(status));
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ Trace("<==== (%08x)\n", status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePowerDown(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, >, __FdoGetDevicePowerState(Fdo));
+
+ Info("%s: %s -> %s\n",
+ __FdoGetName(Fdo),
+ PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
+ PowerDeviceStateName(DeviceState));
+
+ ASSERT3U(DeviceState, ==, PowerDeviceD3);
+
+ if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
+ FdoD0ToD3(Fdo);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePower(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ ASSERT3U(PowerAction, <, PowerActionShutdown);
+
+ if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ status = (DeviceState < __FdoGetDevicePowerState(Fdo)) ?
+ __FdoSetDevicePowerUp(Fdo, Irp) :
+ __FdoSetDevicePowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+__drv_functionClass(REQUEST_POWER_COMPLETE)
+__drv_sameIRQL
+VOID
+__FdoRequestSetDevicePower(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus
+ )
+{
+ PKEVENT Event = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(MinorFunction);
+ UNREFERENCED_PARAMETER(PowerState);
+
+ ASSERT(NT_SUCCESS(IoStatus->Status));
+
+ KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+}
+
+static VOID
+FdoRequestSetDevicePower(
+ IN PXENVKBD_FDO Fdo,
+ IN DEVICE_POWER_STATE DeviceState
+ )
+{
+ POWER_STATE PowerState;
+ KEVENT Event;
+ NTSTATUS status;
+
+ Trace("%s\n", PowerDeviceStateName(DeviceState));
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ PowerState.DeviceState = DeviceState;
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
+ IRP_MN_SET_POWER,
+ PowerState,
+ __FdoRequestSetDevicePower,
+ &Event,
+ NULL);
+ ASSERT(NT_SUCCESS(status));
+
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetSystemPowerUp(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, <, __FdoGetSystemPowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ Info("%s: %s -> %s\n",
+ __FdoGetName(Fdo),
+ PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
+ PowerSystemStateName(SystemState));
+
+ if (SystemState < PowerSystemHibernate &&
+ __FdoGetSystemPowerState(Fdo) >= PowerSystemHibernate) {
+ __FdoSetSystemPowerState(Fdo, PowerSystemHibernate);
+ FdoS4ToS3(Fdo);
+ }
+
+ __FdoSetSystemPowerState(Fdo, SystemState);
+
+ DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+ FdoRequestSetDevicePower(Fdo, DeviceState);
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetSystemPowerDown(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, >, __FdoGetSystemPowerState(Fdo));
+
+ DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+
+ FdoRequestSetDevicePower(Fdo, DeviceState);
+
+ Info("%s: %s -> %s\n",
+ __FdoGetName(Fdo),
+ PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
+ PowerSystemStateName(SystemState));
+
+ if (SystemState >= PowerSystemHibernate &&
+ __FdoGetSystemPowerState(Fdo) < PowerSystemHibernate) {
+ __FdoSetSystemPowerState(Fdo, PowerSystemSleeping3);
+ FdoS3ToS4(Fdo);
+ }
+
+ __FdoSetSystemPowerState(Fdo, SystemState);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetSystemPower(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction));
+
+ ASSERT3U(PowerAction, <, PowerActionShutdown);
+
+ if (SystemState == __FdoGetSystemPowerState(Fdo)) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
+ __FdoSetSystemPowerUp(Fdo, Irp) :
+ __FdoSetSystemPowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQueryDevicePowerUp(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, <, __FdoGetDevicePowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQueryDevicePowerDown(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, >, __FdoGetDevicePowerState(Fdo));
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQueryDevicePower(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ ASSERT3U(PowerAction, <, PowerActionShutdown);
+
+ if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ status = (DeviceState < __FdoGetDevicePowerState(Fdo)) ?
+ __FdoQueryDevicePowerUp(Fdo, Irp) :
+ __FdoQueryDevicePowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+__drv_functionClass(REQUEST_POWER_COMPLETE)
+__drv_sameIRQL
+VOID
+__FdoRequestQueryDevicePower(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus
+ )
+{
+ PKEVENT Event = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(MinorFunction);
+ UNREFERENCED_PARAMETER(PowerState);
+
+ ASSERT(NT_SUCCESS(IoStatus->Status));
+
+ KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+}
+
+static VOID
+FdoRequestQueryDevicePower(
+ IN PXENVKBD_FDO Fdo,
+ IN DEVICE_POWER_STATE DeviceState
+ )
+{
+ POWER_STATE PowerState;
+ KEVENT Event;
+ NTSTATUS status;
+
+ Trace("%s\n", PowerDeviceStateName(DeviceState));
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ PowerState.DeviceState = DeviceState;
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
+ IRP_MN_QUERY_POWER,
+ PowerState,
+ __FdoRequestQueryDevicePower,
+ &Event,
+ NULL);
+ ASSERT(NT_SUCCESS(status));
+
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQuerySystemPowerUp(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, <, __FdoGetSystemPowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+
+ FdoRequestQueryDevicePower(Fdo, DeviceState);
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQuerySystemPowerDown(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, >, __FdoGetSystemPowerState(Fdo));
+
+ DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+
+ FdoRequestQueryDevicePower(Fdo, DeviceState);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQuerySystemPower(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction));
+
+ ASSERT3U(PowerAction, <, PowerActionShutdown);
+
+ if (SystemState == __FdoGetSystemPowerState(Fdo)) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
+ __FdoQuerySystemPowerUp(Fdo, Irp) :
+ __FdoQuerySystemPowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction),
+ status);
+
+ return status;
+}
+
+static NTSTATUS
+FdoDevicePower(
+ IN PXENVKBD_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENVKBD_FDO Fdo = Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+
+ if (Fdo->DevicePowerIrp == NULL) {
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Fdo->DevicePowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Fdo->DevicePowerIrp = NULL;
+ KeMemoryBarrier();
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ (VOID) __FdoSetDevicePower(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ (VOID) __FdoQueryDevicePower(Fdo, Irp);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+FdoSystemPower(
+ IN PXENVKBD_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENVKBD_FDO Fdo = Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+
+ if (Fdo->SystemPowerIrp == NULL) {
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Fdo->SystemPowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Fdo->SystemPowerIrp = NULL;
+ KeMemoryBarrier();
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ (VOID) __FdoSetSystemPower(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ (VOID) __FdoQuerySystemPower(Fdo, Irp);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchPower(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ POWER_STATE_TYPE PowerType;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ if (MinorFunction != IRP_MN_QUERY_POWER &&
+ MinorFunction != IRP_MN_SET_POWER) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ PowerType = StackLocation->Parameters.Power.Type;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ if (PowerAction >= PowerActionShutdown) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ switch (PowerType) {
+ case DevicePowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Fdo->DevicePowerIrp, ==, NULL);
+ Fdo->DevicePowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Fdo->DevicePowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ case SystemPowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Fdo->SystemPowerIrp, ==, NULL);
+ Fdo->SystemPowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Fdo->SystemPowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ default:
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ break;
+ }
+
+done:
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchDefault(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+NTSTATUS
+FdoDispatch(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (StackLocation->MajorFunction) {
+ case IRP_MJ_PNP:
+ status = FdoDispatchPnp(Fdo, Irp);
+ break;
+
+ case IRP_MJ_POWER:
+ status = FdoDispatchPower(Fdo, Irp);
+ break;
+
+ default:
+ status = FdoDispatchDefault(Fdo, Irp);
+ break;
+ }
+
+ return status;
+}
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+static NTSTATUS
+FdoQueryInterface(
+ IN PXENVKBD_FDO Fdo,
+ IN const GUID *Guid,
+ IN ULONG Version,
+ OUT PINTERFACE Interface,
+ IN ULONG Size,
+ IN BOOLEAN Optional
+ )
+{
+ KEVENT Event;
+ IO_STATUS_BLOCK StatusBlock;
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ RtlZeroMemory(&StatusBlock, sizeof(IO_STATUS_BLOCK));
+
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
+ Fdo->LowerDeviceObject,
+ NULL,
+ 0,
+ NULL,
+ &Event,
+ &StatusBlock);
+
+ status = STATUS_UNSUCCESSFUL;
+ if (Irp == NULL)
+ goto fail1;
+
+ StackLocation = IoGetNextIrpStackLocation(Irp);
+ StackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE;
+
+ StackLocation->Parameters.QueryInterface.InterfaceType = Guid;
+ StackLocation->Parameters.QueryInterface.Size = (USHORT)Size;
+ StackLocation->Parameters.QueryInterface.Version = (USHORT)Version;
+ StackLocation->Parameters.QueryInterface.Interface = Interface;
+
+ Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ if (status == STATUS_PENDING) {
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ status = StatusBlock.Status;
+ }
+
+ if (!NT_SUCCESS(status)) {
+ if (status == STATUS_NOT_SUPPORTED && Optional)
+ goto done;
+
+ goto fail2;
+ }
+
+done:
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+#define FDO_QUERY_INTERFACE( \
+ _Fdo, \
+ _ProviderName, \
+ _InterfaceName, \
+ _Interface, \
+ _Size, \
+ _Optional) \
+ FdoQueryInterface((_Fdo), \
+ &GUID_ ## _ProviderName ## _ ## _InterfaceName ## _INTERFACE, \
+ _ProviderName ## _ ## _InterfaceName ## _INTERFACE_VERSION_MAX, \
+ (_Interface), \
+ (_Size), \
+ (_Optional))
+
+#define DEFINE_FDO_GET_INTERFACE(_Interface, _Type) \
+VOID \
+FdoGet ## _Interface ## Interface( \
+ IN PXENVKBD_FDO Fdo, \
+ OUT _Type _Interface ## Interface \
+ ) \
+{ \
+ * ## _Interface ## Interface = Fdo-> ## _Interface ## Interface; \
+}
+
+DEFINE_FDO_GET_INTERFACE(Debug, PXENBUS_DEBUG_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(Suspend, PXENBUS_SUSPEND_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(Evtchn, PXENBUS_EVTCHN_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(Store, PXENBUS_STORE_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(RangeSet, PXENBUS_RANGE_SET_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(Cache, PXENBUS_CACHE_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(Gnttab, PXENBUS_GNTTAB_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(Unplug, PXENBUS_UNPLUG_INTERFACE)
+
+NTSTATUS
+FdoCreate(
+ IN PDEVICE_OBJECT PhysicalDeviceObject
+ )
+{
+ PDEVICE_OBJECT FunctionDeviceObject;
+ PXENVKBD_DX Dx;
+ PXENVKBD_FDO Fdo;
+ USHORT DeviceID;
+ NTSTATUS status;
+
+#pragma prefast(suppress:28197) // Possibly leaking memory 'FunctionDeviceObject'
+ status = IoCreateDevice(DriverGetDriverObject(),
+ sizeof (XENVKBD_DX),
+ NULL,
+ FILE_DEVICE_BUS_EXTENDER,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &FunctionDeviceObject);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Dx = (PXENVKBD_DX)FunctionDeviceObject->DeviceExtension;
+ RtlZeroMemory(Dx, sizeof (XENVKBD_DX));
+
+ Dx->Type = FUNCTION_DEVICE_OBJECT;
+ Dx->DeviceObject = FunctionDeviceObject;
+ Dx->DevicePnpState = Added;
+ Dx->SystemPowerState = PowerSystemWorking;
+ Dx->DevicePowerState = PowerDeviceD3;
+
+ Fdo = __FdoAllocate(sizeof (XENVKBD_FDO));
+
+ status = STATUS_NO_MEMORY;
+ if (Fdo == NULL)
+ goto fail2;
+
+ Fdo->Dx = Dx;
+ Fdo->PhysicalDeviceObject = PhysicalDeviceObject;
+ Fdo->LowerDeviceObject = IoAttachDeviceToDeviceStack(FunctionDeviceObject,
+ PhysicalDeviceObject);
+
+ status = ThreadCreate(FdoSystemPower, Fdo, &Fdo->SystemPowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = ThreadCreate(FdoDevicePower, Fdo, &Fdo->DevicePowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = __FdoAcquireLowerBusInterface(Fdo);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ if (FdoGetBusData(Fdo,
+ PCI_WHICHSPACE_CONFIG,
+ &DeviceID,
+ FIELD_OFFSET(PCI_COMMON_HEADER, DeviceID),
+ FIELD_SIZE(PCI_COMMON_HEADER, DeviceID)) == 0)
+ goto fail6;
+
+ __FdoSetVendorName(Fdo, DeviceID);
+
+ __FdoSetName(Fdo);
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ DEBUG,
+ (PINTERFACE)&Fdo->DebugInterface,
+ sizeof (Fdo->DebugInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail7;
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ SUSPEND,
+ (PINTERFACE)&Fdo->SuspendInterface,
+ sizeof (Fdo->SuspendInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail8;
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ EVTCHN,
+ (PINTERFACE)&Fdo->EvtchnInterface,
+ sizeof (Fdo->EvtchnInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail9;
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ STORE,
+ (PINTERFACE)&Fdo->StoreInterface,
+ sizeof (Fdo->StoreInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail10;
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ RANGE_SET,
+ (PINTERFACE)&Fdo->RangeSetInterface,
+ sizeof (Fdo->RangeSetInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail11;
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ CACHE,
+ (PINTERFACE)&Fdo->CacheInterface,
+ sizeof (Fdo->CacheInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail12;
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ GNTTAB,
+ (PINTERFACE)&Fdo->GnttabInterface,
+ sizeof (Fdo->GnttabInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail13;
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ UNPLUG,
+ (PINTERFACE)&Fdo->UnplugInterface,
+ sizeof (Fdo->UnplugInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail14;
+
+ Dx->Fdo = Fdo;
+
+ InitializeMutex(&Fdo->Mutex);
+ InitializeListHead(&Dx->ListEntry);
+ Fdo->References = 1;
+
+ Info("%p (%s)\n",
+ FunctionDeviceObject,
+ __FdoGetName(Fdo));
+
+ FunctionDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+ return STATUS_SUCCESS;
+
+fail14:
+ Error("fail14\n");
+
+ RtlZeroMemory(&Fdo->UnplugInterface,
+ sizeof (XENBUS_UNPLUG_INTERFACE));
+
+fail13:
+ Error("fail13\n");
+
+ RtlZeroMemory(&Fdo->CacheInterface,
+ sizeof (XENBUS_CACHE_INTERFACE));
+
+fail12:
+ Error("fail12\n");
+
+ RtlZeroMemory(&Fdo->RangeSetInterface,
+ sizeof (XENBUS_RANGE_SET_INTERFACE));
+
+fail11:
+ Error("fail11\n");
+
+ RtlZeroMemory(&Fdo->StoreInterface,
+ sizeof (XENBUS_STORE_INTERFACE));
+
+fail10:
+ Error("fail10\n");
+
+ RtlZeroMemory(&Fdo->EvtchnInterface,
+ sizeof (XENBUS_EVTCHN_INTERFACE));
+
+fail9:
+ Error("fail9\n");
+
+ RtlZeroMemory(&Fdo->SuspendInterface,
+ sizeof (XENBUS_SUSPEND_INTERFACE));
+
+fail8:
+ Error("fail8\n");
+
+ RtlZeroMemory(&Fdo->DebugInterface,
+ sizeof (XENBUS_DEBUG_INTERFACE));
+
+fail7:
+ Error("fail7\n");
+
+ RtlZeroMemory(Fdo->VendorName, MAXNAMELEN);
+
+fail6:
+ Error("fail6\n");
+
+ __FdoReleaseLowerBusInterface(Fdo);
+
+fail5:
+ Error("fail5\n");
+
+ ThreadAlert(Fdo->DevicePowerThread);
+ ThreadJoin(Fdo->DevicePowerThread);
+ Fdo->DevicePowerThread = NULL;
+
+fail4:
+ Error("fail4\n");
+
+ ThreadAlert(Fdo->SystemPowerThread);
+ ThreadJoin(Fdo->SystemPowerThread);
+ Fdo->SystemPowerThread = NULL;
+
+fail3:
+ Error("fail3\n");
+
+#pragma prefast(suppress:28183) // Fdo->LowerDeviceObject could be NULL
+ IoDetachDevice(Fdo->LowerDeviceObject);
+
+ Fdo->PhysicalDeviceObject = NULL;
+ Fdo->LowerDeviceObject = NULL;
+ Fdo->Dx = NULL;
+
+ ASSERT(IsZeroMemory(Fdo, sizeof (XENVKBD_FDO)));
+ __FdoFree(Fdo);
+
+fail2:
+ Error("fail2\n");
+
+ IoDeleteDevice(FunctionDeviceObject);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+FdoDestroy(
+ IN PXENVKBD_FDO Fdo
+ )
+{
+ PXENVKBD_DX Dx = Fdo->Dx;
+ PDEVICE_OBJECT FunctionDeviceObject = Dx->DeviceObject;
+
+ ASSERT(IsListEmpty(&Dx->ListEntry));
+ ASSERT3U(Fdo->References, ==, 0);
+ ASSERT3U(__FdoGetDevicePnpState(Fdo), ==, Deleted);
+
+ Fdo->NotDisableable = FALSE;
+
+ Info("%p (%s)\n",
+ FunctionDeviceObject,
+ __FdoGetName(Fdo));
+
+ RtlZeroMemory(&Fdo->Mutex, sizeof (MUTEX));
+
+ Dx->Fdo = NULL;
+
+ RtlZeroMemory(&Fdo->UnplugInterface,
+ sizeof (XENBUS_UNPLUG_INTERFACE));
+
+ RtlZeroMemory(&Fdo->GnttabInterface,
+ sizeof (XENBUS_GNTTAB_INTERFACE));
+
+ RtlZeroMemory(&Fdo->CacheInterface,
+ sizeof (XENBUS_CACHE_INTERFACE));
+
+ RtlZeroMemory(&Fdo->RangeSetInterface,
+ sizeof (XENBUS_RANGE_SET_INTERFACE));
+
+ RtlZeroMemory(&Fdo->StoreInterface,
+ sizeof (XENBUS_STORE_INTERFACE));
+
+ RtlZeroMemory(&Fdo->EvtchnInterface,
+ sizeof (XENBUS_EVTCHN_INTERFACE));
+
+ RtlZeroMemory(&Fdo->SuspendInterface,
+ sizeof (XENBUS_SUSPEND_INTERFACE));
+
+ RtlZeroMemory(&Fdo->DebugInterface,
+ sizeof (XENBUS_DEBUG_INTERFACE));
+
+ RtlZeroMemory(Fdo->VendorName, MAXNAMELEN);
+
+ __FdoReleaseLowerBusInterface(Fdo);
+
+ ThreadAlert(Fdo->DevicePowerThread);
+ ThreadJoin(Fdo->DevicePowerThread);
+ Fdo->DevicePowerThread = NULL;
+
+ ThreadAlert(Fdo->SystemPowerThread);
+ ThreadJoin(Fdo->SystemPowerThread);
+ Fdo->SystemPowerThread = NULL;
+
+ IoDetachDevice(Fdo->LowerDeviceObject);
+
+ RtlZeroMemory(&Fdo->LowerDeviceCapabilities, sizeof (DEVICE_CAPABILITIES));
+ Fdo->LowerDeviceObject = NULL;
+ Fdo->PhysicalDeviceObject = NULL;
+ Fdo->Dx = NULL;
+
+ ASSERT(IsZeroMemory(Fdo, sizeof (XENVKBD_FDO)));
+ __FdoFree(Fdo);
+
+ IoDeleteDevice(FunctionDeviceObject);
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_FDO_H
+#define _XENVKBD_FDO_H
+
+#include <ntddk.h>
+#include <debug_interface.h>
+#include <suspend_interface.h>
+#include <evtchn_interface.h>
+#include <store_interface.h>
+#include <range_set_interface.h>
+#include <cache_interface.h>
+#include <gnttab_interface.h>
+#include <unplug_interface.h>
+
+#include "driver.h"
+#include "types.h"
+
+extern PCHAR
+FdoGetVendorName(
+ IN PXENVKBD_FDO Fdo
+ );
+
+extern PCHAR
+FdoGetName(
+ IN PXENVKBD_FDO Fdo
+ );
+
+extern NTSTATUS
+FdoAddPhysicalDeviceObject(
+ IN PXENVKBD_FDO Fdo,
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern VOID
+FdoRemovePhysicalDeviceObject(
+ IN PXENVKBD_FDO Fdo,
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern VOID
+FdoAcquireMutex(
+ IN PXENVKBD_FDO Fdo
+ );
+
+extern VOID
+FdoReleaseMutex(
+ IN PXENVKBD_FDO Fdo
+ );
+
+extern PDEVICE_OBJECT
+FdoGetPhysicalDeviceObject(
+ IN PXENVKBD_FDO Fdo
+ );
+
+extern PDMA_ADAPTER
+FdoGetDmaAdapter(
+ IN PXENVKBD_FDO Fdo,
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ );
+
+extern BOOLEAN
+FdoTranslateBusAddress(
+ IN PXENVKBD_FDO Fdo,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN ULONG Length,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+extern ULONG
+FdoSetBusData(
+ IN PXENVKBD_FDO Fdo,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+extern ULONG
+FdoGetBusData(
+ IN PXENVKBD_FDO Fdo,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+extern NTSTATUS
+FdoDelegateIrp(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ );
+
+extern NTSTATUS
+FdoDispatch(
+ IN PXENVKBD_FDO Fdo,
+ IN PIRP Irp
+ );
+
+#define DECLARE_FDO_GET_INTERFACE(_Interface, _Type) \
+extern VOID \
+FdoGet ## _Interface ## Interface( \
+ IN PXENVKBD_FDO Fdo, \
+ OUT _Type _Interface ## Interface \
+ );
+
+DECLARE_FDO_GET_INTERFACE(Debug, PXENBUS_DEBUG_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Suspend, PXENBUS_SUSPEND_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Evtchn, PXENBUS_EVTCHN_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Store, PXENBUS_STORE_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(RangeSet, PXENBUS_RANGE_SET_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Cache, PXENBUS_CACHE_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Gnttab, PXENBUS_GNTTAB_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Unplug, PXENBUS_UNPLUG_INTERFACE)
+
+extern NTSTATUS
+FdoCreate(
+ IN PDEVICE_OBJECT PhysicalDeviceObject
+ );
+
+extern VOID
+FdoDestroy(
+ IN PXENVKBD_FDO Fdo
+ );
+
+#endif // _XENVKBD_FDO_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#include <ntddk.h>
+#include <procgrp.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+#include <xen.h>
+
+#include "driver.h"
+#include "registry.h"
+#include "fdo.h"
+#include "pdo.h"
+#include "thread.h"
+#include "frontend.h"
+#include "names.h"
+#include "ring.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+#define DOMID_INVALID (0x7FF4U)
+
+struct _XENVKBD_FRONTEND {
+ PXENVKBD_PDO Pdo;
+ PCHAR Path;
+ XENVKBD_FRONTEND_STATE State;
+ BOOLEAN Online;
+ KSPIN_LOCK Lock;
+ PXENVKBD_THREAD EjectThread;
+ KEVENT EjectEvent;
+
+ PCHAR BackendPath;
+ USHORT BackendDomain;
+
+ PXENVKBD_RING Ring;
+
+ XENBUS_SUSPEND_INTERFACE SuspendInterface;
+ XENBUS_STORE_INTERFACE StoreInterface;
+
+ PXENBUS_SUSPEND_CALLBACK SuspendCallbackEarly;
+ PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
+ PXENBUS_STORE_WATCH Watch;
+};
+
+static const PCHAR
+FrontendStateName(
+ IN XENVKBD_FRONTEND_STATE State
+ )
+{
+#define _STATE_NAME(_State) \
+ case FRONTEND_ ## _State: \
+ return #_State;
+
+ switch (State) {
+ _STATE_NAME(UNKNOWN);
+ _STATE_NAME(CLOSED);
+ _STATE_NAME(PREPARED);
+ _STATE_NAME(CONNECTED);
+ _STATE_NAME(ENABLED);
+ default:
+ break;
+ }
+
+ return "INVALID";
+
+#undef _STATE_NAME
+}
+
+#define FRONTEND_POOL 'NORF'
+
+static FORCEINLINE PVOID
+__FrontendAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, FRONTEND_POOL);
+}
+
+static FORCEINLINE VOID
+__FrontendFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, FRONTEND_POOL);
+}
+
+static FORCEINLINE PXENVKBD_PDO
+__FrontendGetPdo(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return Frontend->Pdo;
+}
+
+PXENVKBD_PDO
+FrontendGetPdo(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return __FrontendGetPdo(Frontend);
+}
+
+static FORCEINLINE PCHAR
+__FrontendGetPath(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return Frontend->Path;
+}
+
+PCHAR
+FrontendGetPath(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return __FrontendGetPath(Frontend);
+}
+
+static FORCEINLINE PCHAR
+__FrontendGetBackendPath(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return Frontend->BackendPath;
+}
+
+PCHAR
+FrontendGetBackendPath(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return __FrontendGetBackendPath(Frontend);
+}
+
+static FORCEINLINE USHORT
+__FrontendGetBackendDomain(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return Frontend->BackendDomain;
+}
+
+USHORT
+FrontendGetBackendDomain(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return __FrontendGetBackendDomain(Frontend);
+}
+
+#define DEFINE_FRONTEND_GET_FUNCTION(_Function, _Type) \
+static FORCEINLINE _Type \
+__FrontendGet ## _Function( \
+ IN PXENVKBD_FRONTEND Frontend \
+ ) \
+{ \
+ return Frontend-> ## _Function; \
+} \
+ \
+_Type \
+FrontendGet ## _Function( \
+ IN PXENVKBD_FRONTEND Frontend \
+ ) \
+{ \
+ return __FrontendGet ## _Function ## (Frontend); \
+}
+
+DEFINE_FRONTEND_GET_FUNCTION(Ring, PXENVKBD_RING)
+
+static BOOLEAN
+FrontendIsOnline(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ return Frontend->Online;
+}
+
+static BOOLEAN
+FrontendIsBackendOnline(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ PCHAR Buffer;
+ BOOLEAN Online;
+ NTSTATUS status;
+
+ status = XENBUS_STORE(Read,
+ &Frontend->StoreInterface,
+ NULL,
+ __FrontendGetBackendPath(Frontend),
+ "online",
+ &Buffer);
+ if (!NT_SUCCESS(status)) {
+ Online = FALSE;
+ } else {
+ Online = (BOOLEAN)strtol(Buffer, NULL, 2);
+
+ XENBUS_STORE(Free,
+ &Frontend->StoreInterface,
+ Buffer);
+ }
+
+ return Online;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FrontendEject(
+ IN PXENVKBD_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENVKBD_FRONTEND Frontend = Context;
+ PKEVENT Event;
+
+ Trace("%s: ====>\n", __FrontendGetPath(Frontend));
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ KIRQL Irql;
+
+ KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ KeAcquireSpinLock(&Frontend->Lock, &Irql);
+
+ // It is not safe to use interfaces before this point
+ if (Frontend->State == FRONTEND_UNKNOWN ||
+ Frontend->State == FRONTEND_CLOSED)
+ goto loop;
+
+ if (!FrontendIsOnline(Frontend))
+ goto loop;
+
+ if (!FrontendIsBackendOnline(Frontend))
+ PdoRequestEject(__FrontendGetPdo(Frontend));
+
+loop:
+ KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+ KeSetEvent(&Frontend->EjectEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ KeSetEvent(&Frontend->EjectEvent, IO_NO_INCREMENT, FALSE);
+
+ Trace("%s: <====\n", __FrontendGetPath(Frontend));
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+FrontendEjectFailed(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ KIRQL Irql;
+ ULONG Length;
+ PCHAR Path;
+ NTSTATUS status;
+
+ KeAcquireSpinLock(&Frontend->Lock, &Irql);
+
+ Info("%s: device eject failed\n", __FrontendGetPath(Frontend));
+
+ Length = sizeof ("error/") + (ULONG)strlen(__FrontendGetPath(Frontend));
+ Path = __FrontendAllocate(Length);
+
+ status = STATUS_NO_MEMORY;
+ if (Path == NULL)
+ goto fail1;
+
+ status = RtlStringCbPrintfA(Path,
+ Length,
+ "error/%s",
+ __FrontendGetPath(Frontend));
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ (VOID) XENBUS_STORE(Printf,
+ &Frontend->StoreInterface,
+ NULL,
+ Path,
+ "error",
+ "UNPLUG FAILED: device is still in use");
+
+ __FrontendFree(Path);
+
+ KeReleaseSpinLock(&Frontend->Lock, Irql);
+ return;
+
+fail2:
+ Error("fail2\n");
+
+ __FrontendFree(Path);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ KeReleaseSpinLock(&Frontend->Lock, Irql);
+}
+
+static VOID
+FrontendSetOnline(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ Trace("====>\n");
+
+ Frontend->Online = TRUE;
+
+ Trace("<====\n");
+}
+
+static VOID
+FrontendSetOffline(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ Trace("====>\n");
+
+ Frontend->Online = FALSE;
+ PdoRequestEject(__FrontendGetPdo(Frontend));
+
+ Trace("<====\n");
+}
+
+static VOID
+FrontendSetXenbusState(
+ IN PXENVKBD_FRONTEND Frontend,
+ IN XenbusState State
+ )
+{
+ BOOLEAN Online;
+
+ Trace("%s: ====> %s\n",
+ __FrontendGetPath(Frontend),
+ XenbusStateName(State));
+
+ ASSERT(FrontendIsOnline(Frontend));
+
+ Online = FrontendIsBackendOnline(Frontend);
+
+ (VOID) XENBUS_STORE(Printf,
+ &Frontend->StoreInterface,
+ NULL,
+ __FrontendGetPath(Frontend),
+ "state",
+ "%u",
+ State);
+
+ if (State == XenbusStateClosed && !Online)
+ FrontendSetOffline(Frontend);
+
+ Trace("%s: <==== %s\n",
+ __FrontendGetPath(Frontend),
+ XenbusStateName(State));
+}
+
+static VOID
+FrontendWaitForBackendXenbusStateChange(
+ IN PXENVKBD_FRONTEND Frontend,
+ IN OUT XenbusState *State
+ )
+{
+ KEVENT Event;
+ PXENBUS_STORE_WATCH Watch;
+ LARGE_INTEGER Start;
+ ULONGLONG TimeDelta;
+ LARGE_INTEGER Timeout;
+ XenbusState Old = *State;
+ NTSTATUS status;
+
+ Trace("%s: ====> %s\n",
+ __FrontendGetBackendPath(Frontend),
+ XenbusStateName(*State));
+
+ ASSERT(FrontendIsOnline(Frontend));
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ status = XENBUS_STORE(WatchAdd,
+ &Frontend->StoreInterface,
+ __FrontendGetBackendPath(Frontend),
+ "state",
+ &Event,
+ &Watch);
+ if (!NT_SUCCESS(status))
+ Watch = NULL;
+
+ KeQuerySystemTime(&Start);
+ TimeDelta = 0;
+
+ Timeout.QuadPart = 0;
+
+ while (*State == Old && TimeDelta < 120000) {
+ PCHAR Buffer;
+ LARGE_INTEGER Now;
+
+ if (Watch != NULL) {
+ ULONG Attempt = 0;
+
+ while (++Attempt < 1000) {
+ status = KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ &Timeout);
+ if (status != STATUS_TIMEOUT)
+ break;
+
+ // We are waiting for a watch event at DISPATCH_LEVEL so
+ // it is our responsibility to poll the store ring.
+ XENBUS_STORE(Poll,
+ &Frontend->StoreInterface);
+
+ KeStallExecutionProcessor(1000); // 1ms
+ }
+
+ KeClearEvent(&Event);
+ }
+
+ status = XENBUS_STORE(Read,
+ &Frontend->StoreInterface,
+ NULL,
+ __FrontendGetBackendPath(Frontend),
+ "state",
+ &Buffer);
+ if (!NT_SUCCESS(status)) {
+ *State = XenbusStateUnknown;
+ } else {
+ *State = (XenbusState)strtol(Buffer, NULL, 10);
+
+ XENBUS_STORE(Free,
+ &Frontend->StoreInterface,
+ Buffer);
+ }
+
+ KeQuerySystemTime(&Now);
+
+ TimeDelta = (Now.QuadPart - Start.QuadPart) / 10000ull;
+ }
+
+ if (Watch != NULL)
+ (VOID) XENBUS_STORE(WatchRemove,
+ &Frontend->StoreInterface,
+ Watch);
+
+ Trace("%s: <==== (%s)\n",
+ __FrontendGetBackendPath(Frontend),
+ XenbusStateName(*State));
+}
+
+static NTSTATUS
+FrontendUpdatePath(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ ULONG Length;
+ PCHAR Buffer;
+ NTSTATUS status;
+
+ status = XENBUS_STORE(Read,
+ &Frontend->StoreInterface,
+ NULL,
+ Frontend->Path,
+ "backend-id",
+ &Buffer);
+ if (NT_SUCCESS(status)) {
+ Frontend->BackendDomain = (USHORT)strtoul(Buffer, NULL, 10);
+
+ XENBUS_STORE(Free,
+ &Frontend->StoreInterface,
+ Buffer);
+ } else {
+ Frontend->BackendDomain = 0;
+ }
+
+ status = XENBUS_STORE(Read,
+ &Frontend->StoreInterface,
+ NULL,
+ Frontend->Path,
+ "backend",
+ &Buffer);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Length = (ULONG)strlen(Buffer);
+
+ status = STATUS_NO_MEMORY;
+ if (Frontend->BackendPath)
+ __FrontendFree(Frontend->BackendPath);
+
+ Frontend->BackendPath = __FrontendAllocate((Length + 1) * sizeof(CHAR));
+ if (Frontend->BackendPath == NULL)
+ goto fail2;
+
+ RtlCopyMemory(Frontend->BackendPath,
+ Buffer,
+ Length * sizeof(CHAR));
+
+ XENBUS_STORE(Free,
+ &Frontend->StoreInterface,
+ Buffer);
+
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+ XENBUS_STORE(Free,
+ &Frontend->StoreInterface,
+ Buffer);
+
+fail1:
+ Error("fail1 %08x\n", status);
+ return status;
+}
+
+static NTSTATUS
+FrontendClose(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ XenbusState State;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ if (Frontend->Watch)
+ XENBUS_STORE(WatchRemove,
+ &Frontend->StoreInterface,
+ Frontend->Watch);
+ Frontend->Watch = NULL;
+
+ status = FrontendUpdatePath(Frontend);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ State = XenbusStateUnknown;
+ do {
+ FrontendWaitForBackendXenbusStateChange(Frontend,
+ &State);
+ if (State == XenbusStateUnknown)
+ goto fail2;
+ } while (State == XenbusStateInitialising);
+
+ FrontendSetXenbusState(Frontend, XenbusStateClosing);
+
+ status = STATUS_UNSUCCESSFUL;
+ do {
+ FrontendWaitForBackendXenbusStateChange(Frontend,
+ &State);
+ if (State == XenbusStateUnknown)
+ goto fail3;
+ } while (State != XenbusStateClosing &&
+ State != XenbusStateClosed);
+
+ FrontendSetXenbusState(Frontend, XenbusStateClosed);
+
+ do {
+ FrontendWaitForBackendXenbusStateChange(Frontend,
+ &State);
+ if (State == XenbusStateUnknown)
+ goto fail4;
+ } while (State != XenbusStateClosed);
+
+ __FrontendFree(Frontend->BackendPath);
+ Frontend->BackendPath = NULL;
+ Frontend->BackendDomain = DOMID_INVALID;
+
+ Trace("<=====\n");
+ return STATUS_SUCCESS;
+
+fail4:
+ Error("fail4\n");
+fail3:
+ Error("fail3\n");
+fail2:
+ Error("fail2\n");
+fail1:
+ Error("fail1 %08x\n", status);
+ return status;
+}
+
+static NTSTATUS
+FrontendPrepare(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ XenbusState State;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+
+ status = FrontendUpdatePath(Frontend);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = XENBUS_STORE(WatchAdd,
+ &Frontend->StoreInterface,
+ NULL,
+ Frontend->BackendPath,
+ ThreadGetEvent(Frontend->EjectThread),
+ &Frontend->Watch);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ FrontendSetXenbusState(Frontend, XenbusStateInitialising);
+
+ status = STATUS_UNSUCCESSFUL;
+ do {
+ FrontendWaitForBackendXenbusStateChange(Frontend,
+ &State);
+ if (State == XenbusStateUnknown)
+ goto fail3;
+ } while (State != XenbusStateInitWait);
+
+ Trace("<=====\n");
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+ XENBUS_STORE(WatchRemove,
+ &Frontend->StoreInterface,
+ Frontend->Watch);
+ Frontend->Watch = NULL;
+fail2:
+ Error("fail2\n");
+fail1:
+ Error("fail1 %08x\n", status);
+ return status;
+}
+
+static NTSTATUS
+FrontendConnect(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ XenbusState State;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+
+ status = RingConnect(Frontend->Ring);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ for (;;) {
+ PXENBUS_STORE_TRANSACTION Transaction;
+
+ status = XENBUS_STORE(TransactionStart,
+ &Frontend->StoreInterface,
+ &Transaction);
+ if (!NT_SUCCESS(status))
+ break;
+
+ status = RingStoreWrite(Frontend->Ring,
+ Transaction);
+ if (!NT_SUCCESS(status))
+ goto abort;
+
+ status = XENBUS_STORE(TransactionEnd,
+ &Frontend->StoreInterface,
+ Transaction,
+ TRUE);
+ if (status == STATUS_RETRY)
+ continue;
+ break;
+
+abort:
+ (VOID) XENBUS_STORE(TransactionEnd,
+ &Frontend->StoreInterface,
+ Transaction,
+ FALSE);
+ break;
+ }
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ FrontendSetXenbusState(Frontend, XenbusStateInitialised);
+
+ status = STATUS_UNSUCCESSFUL;
+ do {
+ FrontendWaitForBackendXenbusStateChange(Frontend,
+ &State);
+ if (State == XenbusStateUnknown)
+ goto fail3;
+ } while (State == XenbusStateInitWait ||
+ State == XenbusStateInitialising ||
+ State == XenbusStateInitialised);
+
+ if (State != XenbusStateConnected)
+ goto fail4;
+
+ FrontendSetXenbusState(Frontend, XenbusStateConnected);
+
+ Trace("<=====\n");
+ return STATUS_SUCCESS;
+
+fail4:
+ Error("fail4\n");
+fail3:
+ Error("fail3\n");
+fail2:
+ Error("fail2\n");
+fail1:
+ Error("fail1 %08x\n", status);
+ return status;
+}
+
+static VOID
+FrontendDisconnect(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ Trace("====>\n");
+
+ RingDisconnect(__FrontendGetRing(Frontend));
+
+ Trace("<====\n");
+}
+
+static NTSTATUS
+FrontendEnable(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ status = RingEnable(__FrontendGetRing(Frontend));
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Trace("<====\n");
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static VOID
+FrontendDisable(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ Trace("====>\n");
+
+ RingDisable(__FrontendGetRing(Frontend));
+
+ Trace("<====\n");
+}
+
+NTSTATUS
+FrontendSetState(
+ IN PXENVKBD_FRONTEND Frontend,
+ IN XENVKBD_FRONTEND_STATE State
+ )
+{
+ BOOLEAN Failed;
+ KIRQL Irql;
+
+ KeAcquireSpinLock(&Frontend->Lock, &Irql);
+
+ Info("%s: ====> '%s' -> '%s'\n",
+ __FrontendGetPath(Frontend),
+ FrontendStateName(Frontend->State),
+ FrontendStateName(State));
+
+ Failed = FALSE;
+ while (Frontend->State != State && !Failed) {
+ NTSTATUS status;
+
+ switch (Frontend->State) {
+ case FRONTEND_UNKNOWN:
+ switch (State) {
+ case FRONTEND_CLOSING:
+ case FRONTEND_CLOSED:
+ case FRONTEND_PREPARED:
+ case FRONTEND_CONNECTED:
+ case FRONTEND_ENABLED:
+ status = FrontendClose(Frontend);
+ if (NT_SUCCESS(status)) {
+ Frontend->State = FRONTEND_CLOSED;
+ } else {
+ Failed = TRUE;
+ }
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ break;
+
+ case FRONTEND_CLOSING:
+ switch (State) {
+ case FRONTEND_UNKNOWN:
+ case FRONTEND_CLOSED:
+ case FRONTEND_PREPARED:
+ case FRONTEND_CONNECTED:
+ case FRONTEND_ENABLED:
+ FrontendDisconnect(Frontend);
+ Frontend->State = FRONTEND_CLOSED;
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ break;
+
+ case FRONTEND_CLOSED:
+ switch (State) {
+ case FRONTEND_PREPARED:
+ case FRONTEND_CONNECTED:
+ case FRONTEND_ENABLED:
+ status = FrontendPrepare(Frontend);
+ if (NT_SUCCESS(status)) {
+ Frontend->State = FRONTEND_PREPARED;
+ } else {
+ FrontendClose(Frontend);
+ Frontend->State = FRONTEND_CLOSED;
+ }
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ break;
+
+ case FRONTEND_PREPARED:
+ switch (State) {
+ case FRONTEND_CLOSING:
+ case FRONTEND_CLOSED:
+ status = FrontendClose(Frontend);
+ if (NT_SUCCESS(status))
+ Frontend->State = FRONTEND_CLOSED;
+ break;
+ case FRONTEND_CONNECTED:
+ case FRONTEND_ENABLED:
+ status = FrontendConnect(Frontend);
+ if (NT_SUCCESS(status)) {
+ Frontend->State = FRONTEND_CONNECTED;
+ } else {
+ FrontendClose(Frontend);
+ Frontend->State = FRONTEND_CLOSED;
+ }
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ break;
+
+ case FRONTEND_CONNECTED:
+ switch (State) {
+ case FRONTEND_ENABLED:
+ FrontendEnable(Frontend);
+ Frontend->State = FRONTEND_ENABLED;
+ break;
+ case FRONTEND_CLOSING:
+ case FRONTEND_CLOSED:
+ FrontendClose(Frontend);
+ Frontend->State = FRONTEND_CLOSING;
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ break;
+
+ case FRONTEND_ENABLED:
+ switch (State) {
+ case FRONTEND_CLOSING:
+ case FRONTEND_CLOSED:
+ case FRONTEND_CONNECTED:
+ FrontendDisable(Frontend);
+ Frontend->State = FRONTEND_CONNECTED;
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ Info("%s in state '%s'\n",
+ __FrontendGetPath(Frontend),
+ FrontendStateName(Frontend->State));
+ }
+
+ KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+ Info("%s: <=====\n", __FrontendGetPath(Frontend));
+
+ return (!Failed) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+}
+
+static FORCEINLINE VOID
+__FrontendResume(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+ ASSERT3U(Frontend->State, ==, FRONTEND_UNKNOWN);
+ (VOID) FrontendSetState(Frontend, FRONTEND_CLOSED);
+}
+
+static FORCEINLINE VOID
+__FrontendSuspend(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+ (VOID) FrontendSetState(Frontend, FRONTEND_UNKNOWN);
+}
+
+static DECLSPEC_NOINLINE VOID
+FrontendSuspendCallbackEarly(
+ IN PVOID Argument
+ )
+{
+ PXENVKBD_FRONTEND Frontend = Argument;
+
+ Frontend->Online = FALSE;
+}
+
+static DECLSPEC_NOINLINE VOID
+FrontendSuspendCallbackLate(
+ IN PVOID Argument
+ )
+{
+ PXENVKBD_FRONTEND Frontend = Argument;
+
+ __FrontendSuspend(Frontend);
+ __FrontendResume(Frontend);
+}
+
+NTSTATUS
+FrontendResume(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ KIRQL Irql;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ status = XENBUS_SUSPEND(Acquire, &Frontend->SuspendInterface);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __FrontendResume(Frontend);
+
+ status = XENBUS_SUSPEND(Register,
+ &Frontend->SuspendInterface,
+ SUSPEND_CALLBACK_EARLY,
+ FrontendSuspendCallbackEarly,
+ Frontend,
+ &Frontend->SuspendCallbackEarly);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = XENBUS_SUSPEND(Register,
+ &Frontend->SuspendInterface,
+ SUSPEND_CALLBACK_LATE,
+ FrontendSuspendCallbackLate,
+ Frontend,
+ &Frontend->SuspendCallbackLate);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ KeLowerIrql(Irql);
+
+ KeClearEvent(&Frontend->EjectEvent);
+ ThreadWake(Frontend->EjectThread);
+
+ Trace("waiting for eject thread\n");
+
+ (VOID) KeWaitForSingleObject(&Frontend->EjectEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+
+ XENBUS_SUSPEND(Deregister,
+ &Frontend->SuspendInterface,
+ Frontend->SuspendCallbackEarly);
+ Frontend->SuspendCallbackEarly = NULL;
+
+fail2:
+ Error("fail2\n");
+
+ __FrontendSuspend(Frontend);
+
+ XENBUS_SUSPEND(Release, &Frontend->SuspendInterface);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ KeLowerIrql(Irql);
+
+ return status;
+}
+
+VOID
+FrontendSuspend(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ KIRQL Irql;
+
+ Trace("====>\n");
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ XENBUS_SUSPEND(Deregister,
+ &Frontend->SuspendInterface,
+ Frontend->SuspendCallbackLate);
+ Frontend->SuspendCallbackLate = NULL;
+
+ XENBUS_SUSPEND(Deregister,
+ &Frontend->SuspendInterface,
+ Frontend->SuspendCallbackEarly);
+ Frontend->SuspendCallbackEarly = NULL;
+
+ __FrontendSuspend(Frontend);
+
+ XENBUS_SUSPEND(Release, &Frontend->SuspendInterface);
+
+ KeLowerIrql(Irql);
+
+ KeClearEvent(&Frontend->EjectEvent);
+ ThreadWake(Frontend->EjectThread);
+
+ Trace("waiting for eject thread\n");
+
+ (VOID) KeWaitForSingleObject(&Frontend->EjectEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ Trace("<====\n");
+}
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+NTSTATUS
+FrontendInitialize(
+ IN PXENVKBD_PDO Pdo,
+ OUT PXENVKBD_FRONTEND *Frontend
+ )
+{
+ PCHAR Name;
+ ULONG Length;
+ PCHAR Path;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ Name = PdoGetName(Pdo);
+
+ Length = sizeof ("devices/vkbd/") + (ULONG)strlen(Name);
+ Path = __FrontendAllocate(Length);
+
+ status = STATUS_NO_MEMORY;
+ if (Path == NULL)
+ goto fail1;
+
+ status = RtlStringCbPrintfA(Path,
+ Length,
+ "device/vkbd/%s",
+ Name);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ *Frontend = __FrontendAllocate(sizeof (XENVKBD_FRONTEND));
+
+ status = STATUS_NO_MEMORY;
+ if (*Frontend == NULL)
+ goto fail3;
+
+ (*Frontend)->Pdo = Pdo;
+ (*Frontend)->Path = Path;
+ (*Frontend)->BackendDomain = DOMID_INVALID;
+
+ KeInitializeSpinLock(&(*Frontend)->Lock);
+
+ (*Frontend)->Online = TRUE;
+
+ FdoGetSuspendInterface(PdoGetFdo(Pdo), &(*Frontend)->SuspendInterface);
+ FdoGetStoreInterface(PdoGetFdo(Pdo), &(*Frontend)->StoreInterface);
+
+ status = RingInitialize(*Frontend, &(*Frontend)->Ring);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ KeInitializeEvent(&(*Frontend)->EjectEvent, NotificationEvent, FALSE);
+
+ status = ThreadCreate(FrontendEject, *Frontend, &(*Frontend)->EjectThread);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail5:
+ Error("fail5\n");
+
+ RtlZeroMemory(&(*Frontend)->EjectEvent, sizeof (KEVENT));
+
+ RingTeardown(__FrontendGetRing(*Frontend));
+ (*Frontend)->Ring = NULL;
+
+fail4:
+ Error("fail4\n");
+
+ RtlZeroMemory(&(*Frontend)->StoreInterface,
+ sizeof (XENBUS_STORE_INTERFACE));
+
+ RtlZeroMemory(&(*Frontend)->SuspendInterface,
+ sizeof (XENBUS_SUSPEND_INTERFACE));
+
+ (*Frontend)->Online = FALSE;
+
+ RtlZeroMemory(&(*Frontend)->Lock, sizeof (KSPIN_LOCK));
+
+ (*Frontend)->BackendDomain = 0;
+ (*Frontend)->Path = NULL;
+ (*Frontend)->Pdo = NULL;
+
+ ASSERT(IsZeroMemory(*Frontend, sizeof (XENVKBD_FRONTEND)));
+
+ __FrontendFree(*Frontend);
+ *Frontend = NULL;
+
+fail3:
+ Error("fail3\n");
+
+fail2:
+ Error("fail2\n");
+
+ __FrontendFree(Path);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+FrontendTeardown(
+ IN PXENVKBD_FRONTEND Frontend
+ )
+{
+ Trace("====>\n");
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ ASSERT(Frontend->State == FRONTEND_UNKNOWN);
+
+ ThreadAlert(Frontend->EjectThread);
+ ThreadJoin(Frontend->EjectThread);
+ Frontend->EjectThread = NULL;
+
+ RtlZeroMemory(&Frontend->EjectEvent, sizeof (KEVENT));
+
+ RingTeardown(__FrontendGetRing(Frontend));
+ Frontend->Ring = NULL;
+
+ RtlZeroMemory(&Frontend->StoreInterface,
+ sizeof (XENBUS_STORE_INTERFACE));
+
+ RtlZeroMemory(&Frontend->SuspendInterface,
+ sizeof (XENBUS_SUSPEND_INTERFACE));
+
+ Frontend->Online = FALSE;
+
+ RtlZeroMemory(&Frontend->Lock, sizeof (KSPIN_LOCK));
+
+ Frontend->BackendDomain = 0;
+
+ __FrontendFree(Frontend->Path);
+ Frontend->Path = NULL;
+
+ Frontend->Pdo = NULL;
+
+ ASSERT(IsZeroMemory(Frontend, sizeof (XENVKBD_FRONTEND)));
+
+ __FrontendFree(Frontend);
+
+ Trace("<====\n");
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_FRONTEND_H
+#define _XENVKBD_FRONTEND_H
+
+#include <ntddk.h>
+#include <debug_interface.h>
+#include <suspend_interface.h>
+#include <evtchn_interface.h>
+#include <store_interface.h>
+#include <range_set_interface.h>
+#include <cache_interface.h>
+#include <gnttab_interface.h>
+#include <hid_interface.h>
+
+#include "pdo.h"
+
+typedef struct _XENVKBD_FRONTEND XENVKBD_FRONTEND, *PXENVKBD_FRONTEND;
+
+typedef enum _XENVKBD_FRONTEND_STATE {
+ FRONTEND_UNKNOWN,
+ FRONTEND_CLOSING,
+ FRONTEND_CLOSED,
+ FRONTEND_PREPARED,
+ FRONTEND_CONNECTED,
+ FRONTEND_ENABLED
+} XENVKBD_FRONTEND_STATE, *PXENVKBD_FRONTEND_STATE;
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+extern NTSTATUS
+FrontendInitialize(
+ IN PXENVKBD_PDO Pdo,
+ OUT PXENVKBD_FRONTEND *Frontend
+ );
+
+extern VOID
+FrontendTeardown(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+extern VOID
+FrontendEjectFailed(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+extern NTSTATUS
+FrontendSetState(
+ IN PXENVKBD_FRONTEND Frontend,
+ IN XENVKBD_FRONTEND_STATE State
+ );
+
+extern NTSTATUS
+FrontendResume(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+extern VOID
+FrontendSuspend(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+extern PXENVKBD_PDO
+FrontendGetPdo(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+extern PCHAR
+FrontendGetPath(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+extern PCHAR
+FrontendGetBackendPath(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+extern USHORT
+FrontendGetBackendDomain(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+#include "ring.h"
+
+extern PXENVKBD_RING
+FrontendGetRing(
+ IN PXENVKBD_FRONTEND Frontend
+ );
+
+#endif // _XENVKBD_FRONTEND_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <xen.h>
+
+#include <debug_interface.h>
+#include <suspend_interface.h>
+
+#include "pdo.h"
+#include "hid.h"
+#include "mrsw.h"
+#include "thread.h"
+#include "vkbd.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+struct _XENVKBD_HID_CONTEXT {
+ PXENVKBD_PDO Pdo;
+ XENVKBD_MRSW_LOCK Lock;
+ LONG References;
+ PXENVKBD_FRONTEND Frontend;
+ BOOLEAN Enabled;
+ ULONG Version;
+ XENHID_HID_CALLBACK Callback;
+ PVOID Argument;
+ XENBUS_DEBUG_INTERFACE DebugInterface;
+ XENBUS_SUSPEND_INTERFACE SuspendInterface;
+ PXENBUS_DEBUG_CALLBACK DebugCallback;
+ PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
+
+ XENVKBD_HID_KEYBOARD KeyboardReport;
+ XENVKBD_HID_ABSMOUSE AbsMouseReport;
+ BOOLEAN KeyboardPending;
+ BOOLEAN AbsMousePending;
+};
+
+#define XENVKBD_VKBD_TAG 'FIV'
+
+static FORCEINLINE NTSTATUS
+HidCopyBuffer(
+ IN PVOID Buffer,
+ IN ULONG Length,
+ IN const VOID *Source,
+ IN ULONG SourceLength,
+ OUT PULONG Returned
+ )
+{
+ if (Buffer == NULL)
+ return STATUS_INVALID_PARAMETER;
+ if (Length < SourceLength)
+ return STATUS_NO_MEMORY;
+
+ RtlCopyMemory(Buffer,
+ Source,
+ SourceLength);
+ if (Returned)
+ *Returned = SourceLength;
+ return STATUS_SUCCESS;
+}
+
+static FORCEINLINE PVOID
+__HidAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, XENVKBD_VKBD_TAG);
+}
+
+static FORCEINLINE VOID
+__HidFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, XENVKBD_VKBD_TAG);
+}
+
+static DECLSPEC_NOINLINE VOID
+HidSuspendCallbackLate(
+ IN PVOID Argument
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Argument;
+ NTSTATUS status;
+
+ RtlZeroMemory(&Context->KeyboardReport, sizeof(XENVKBD_HID_KEYBOARD));
+ RtlZeroMemory(&Context->AbsMouseReport, sizeof(XENVKBD_HID_ABSMOUSE));
+ Context->KeyboardReport.ReportId = 1;
+ Context->AbsMouseReport.ReportId = 2;
+
+ if (!Context->Enabled)
+ return;
+
+ status = FrontendSetState(Context->Frontend, FRONTEND_ENABLED);
+ ASSERT(NT_SUCCESS(status));
+}
+
+static DECLSPEC_NOINLINE VOID
+HidDebugCallback(
+ IN PVOID Argument,
+ IN BOOLEAN Crashing
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Argument;
+
+ UNREFERENCED_PARAMETER(Crashing);
+
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "%u 0x%p(0x%p)%s\n",
+ Context->Version,
+ Context->Callback,
+ Context->Argument,
+ Context->Enabled ? " ENABLED" : "");
+
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "KBD: %02x %02x %02x %02x %02x %02x %02x %02x%s\n",
+ Context->KeyboardReport.ReportId,
+ Context->KeyboardReport.Modifiers,
+ Context->KeyboardReport.Keys[0],
+ Context->KeyboardReport.Keys[1],
+ Context->KeyboardReport.Keys[2],
+ Context->KeyboardReport.Keys[3],
+ Context->KeyboardReport.Keys[4],
+ Context->KeyboardReport.Keys[5],
+ Context->KeyboardPending ? " PENDING" : "");
+
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "MOU: %02x %02x %04x %04x %02x%s\n",
+ Context->AbsMouseReport.ReportId,
+ Context->AbsMouseReport.Buttons,
+ Context->AbsMouseReport.X,
+ Context->AbsMouseReport.Y,
+ Context->AbsMouseReport.dZ,
+ Context->AbsMousePending ? " PENDING" : "");
+}
+
+static NTSTATUS
+HidEnable(
+ IN PINTERFACE Interface,
+ IN XENHID_HID_CALLBACK Callback,
+ IN PVOID Argument
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ KIRQL Irql;
+ BOOLEAN Exclusive;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ AcquireMrswLockExclusive(&Context->Lock, &Irql);
+ Exclusive = TRUE;
+
+ if (Context->Enabled)
+ goto done;
+
+ Context->Callback = Callback;
+ Context->Argument = Argument;
+
+ Context->Enabled = TRUE;
+
+ KeMemoryBarrier();
+
+ status = XENBUS_SUSPEND(Acquire, &Context->SuspendInterface);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = FrontendSetState(Context->Frontend, FRONTEND_ENABLED);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = XENBUS_SUSPEND(Register,
+ &Context->SuspendInterface,
+ SUSPEND_CALLBACK_LATE,
+ HidSuspendCallbackLate,
+ Context,
+ &Context->SuspendCallbackLate);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = XENBUS_DEBUG(Acquire, &Context->DebugInterface);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = XENBUS_DEBUG(Register,
+ &Context->DebugInterface,
+ __MODULE__"|DEBUG",
+ HidDebugCallback,
+ Context,
+ &Context->DebugCallback);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+done:
+ ASSERT(Exclusive);
+ ReleaseMrswLockExclusive(&Context->Lock, Irql, FALSE);
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail5:
+ Error("fail5\n");
+
+ XENBUS_DEBUG(Release, &Context->DebugInterface);
+
+fail4:
+ Error("fail4\n");
+
+ XENBUS_SUSPEND(Deregister,
+ &Context->SuspendInterface,
+ Context->SuspendCallbackLate);
+ Context->SuspendCallbackLate = NULL;
+
+fail3:
+ Error("fail3\n");
+
+ (VOID) FrontendSetState(Context->Frontend, FRONTEND_CONNECTED);
+
+ ReleaseMrswLockExclusive(&Context->Lock, Irql, TRUE);
+ Exclusive = FALSE;
+
+fail2:
+ Error("fail2\n");
+
+ XENBUS_SUSPEND(Release, &Context->SuspendInterface);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Context->Enabled = FALSE;
+
+ KeMemoryBarrier();
+
+ Context->Argument = NULL;
+ Context->Callback = NULL;
+
+ if (Exclusive)
+ ReleaseMrswLockExclusive(&Context->Lock, Irql, FALSE);
+ else
+ ReleaseMrswLockShared(&Context->Lock);
+
+ return status;
+}
+
+static VOID
+HidDisable(
+ IN PINTERFACE Interface
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ KIRQL Irql;
+
+ Trace("====>\n");
+
+ AcquireMrswLockExclusive(&Context->Lock, &Irql);
+
+ if (!Context->Enabled) {
+ ReleaseMrswLockExclusive(&Context->Lock, Irql, FALSE);
+ goto done;
+ }
+
+ Context->Enabled = FALSE;
+
+ KeMemoryBarrier();
+
+ XENBUS_DEBUG(Deregister,
+ &Context->DebugInterface,
+ Context->DebugCallback);
+ Context->DebugCallback = NULL;
+
+ XENBUS_DEBUG(Release, &Context->DebugInterface);
+
+ XENBUS_SUSPEND(Deregister,
+ &Context->SuspendInterface,
+ Context->SuspendCallbackLate);
+ Context->SuspendCallbackLate = NULL;
+
+ (VOID) FrontendSetState(Context->Frontend, FRONTEND_CONNECTED);
+
+ ReleaseMrswLockExclusive(&Context->Lock, Irql, TRUE);
+
+ XENBUS_SUSPEND(Release, &Context->SuspendInterface);
+
+ Context->Argument = NULL;
+ Context->Callback = NULL;
+
+ ReleaseMrswLockShared(&Context->Lock);
+
+done:
+ Trace("<====\n");
+}
+
+static NTSTATUS
+HidGetDeviceAttributes(
+ IN PINTERFACE Interface,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ status = HidCopyBuffer(Buffer,
+ Length,
+ &VkbdDeviceAttributes,
+ sizeof(VkbdDeviceAttributes),
+ Returned);
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ return status;
+}
+
+static NTSTATUS
+HidGetDeviceDescriptor(
+ IN PINTERFACE Interface,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ status = HidCopyBuffer(Buffer,
+ Length,
+ &VkbdDeviceDescriptor,
+ sizeof(VkbdDeviceDescriptor),
+ Returned);
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ return status;
+}
+
+static NTSTATUS
+HidGetReportDescriptor(
+ IN PINTERFACE Interface,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ status = HidCopyBuffer(Buffer,
+ Length,
+ VkbdReportDescriptor,
+ sizeof(VkbdReportDescriptor),
+ Returned);
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ return status;
+}
+
+static NTSTATUS
+HidGetString(
+ IN PINTERFACE Interface,
+ IN ULONG Identifier,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ PXENVKBD_PDO Pdo;
+ PXENVKBD_FDO Fdo;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ Pdo = FrontendGetPdo(Context->Frontend);
+ Fdo = PdoGetFdo(Pdo);
+
+ // Ignore LangID
+ switch (Identifier & 0xFF) {
+ case HID_STRING_ID_IMANUFACTURER:
+ status = HidCopyBuffer(Buffer,
+ Length,
+ FdoGetVendorName(Fdo),
+ (ULONG)strlen(FdoGetVendorName(Fdo)),
+ Returned);
+ break;
+ case HID_STRING_ID_IPRODUCT:
+ status = HidCopyBuffer(Buffer,
+ Length,
+ "PV HID Device",
+ sizeof("PV HID Device"),
+ Returned);
+ break;
+ //case HID_STRING_ID_ISERIALNUMBER:
+ default:
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ return status;
+}
+
+static NTSTATUS
+HidGetIndexedString(
+ IN PINTERFACE Interface,
+ IN ULONG Index,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ status = STATUS_NOT_SUPPORTED;
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ UNREFERENCED_PARAMETER(Index);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ UNREFERENCED_PARAMETER(Returned);
+ return status;
+}
+
+static NTSTATUS
+HidGetFeature(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ status = STATUS_NOT_SUPPORTED;
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ UNREFERENCED_PARAMETER(ReportId);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ UNREFERENCED_PARAMETER(Returned);
+ return status;
+}
+
+static NTSTATUS
+HidSetFeature(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ status = STATUS_NOT_SUPPORTED;
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ UNREFERENCED_PARAMETER(ReportId);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ return status;
+}
+
+static NTSTATUS
+HidGetInputReport(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Returned
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ switch (ReportId) {
+ case 1:
+ status = HidCopyBuffer(Buffer,
+ Length,
+ &Context->KeyboardReport,
+ sizeof(XENVKBD_HID_KEYBOARD),
+ Returned);
+ break;
+ case 2:
+ status = HidCopyBuffer(Buffer,
+ Length,
+ &Context->AbsMouseReport,
+ sizeof(XENVKBD_HID_ABSMOUSE),
+ Returned);
+ break;
+ default:
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ UNREFERENCED_PARAMETER(ReportId);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ return status;
+}
+
+static NTSTATUS
+HidSetOutputReport(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ status = STATUS_NOT_SUPPORTED;
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ UNREFERENCED_PARAMETER(ReportId);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ return status;
+}
+
+static BOOLEAN
+HidSendReadReport(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ if (!Context->Enabled)
+ return TRUE; // flag as pending
+
+ // Callback returns TRUE on success, FALSE when Irp could not be completed
+ // Invert the result to indicate Pending state
+ return !Context->Callback(Context->Argument,
+ Buffer,
+ Length);
+}
+
+static VOID
+HidReadReport(
+ IN PINTERFACE Interface
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+
+ AcquireMrswLockShared(&Context->Lock);
+
+ // Check for pending reports, push 1 pending report to subscriber
+ if (Context->KeyboardPending)
+ Context->KeyboardPending = HidSendReadReport(Context,
+ &Context->KeyboardReport,
+ sizeof(XENVKBD_HID_KEYBOARD));
+ else if (Context->AbsMousePending)
+ Context->AbsMousePending = HidSendReadReport(Context,
+ &Context->AbsMouseReport,
+ sizeof(XENVKBD_HID_ABSMOUSE));
+
+ ReleaseMrswLockShared(&Context->Lock);
+}
+
+static NTSTATUS
+HidWriteReport(
+ IN PINTERFACE Interface,
+ IN ULONG ReportId,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ AcquireMrswLockShared(&Context->Lock);
+
+ status = STATUS_NOT_SUPPORTED;
+
+ ReleaseMrswLockShared(&Context->Lock);
+ Trace("<=====\n");
+
+ UNREFERENCED_PARAMETER(ReportId);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ return status;
+}
+
+static NTSTATUS
+HidAcquire(
+ PINTERFACE Interface
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ KIRQL Irql;
+
+ AcquireMrswLockExclusive(&Context->Lock, &Irql);
+
+ if (Context->References++ != 0)
+ goto done;
+
+ Trace("====>\n");
+
+ Context->Frontend = PdoGetFrontend(Context->Pdo);
+ Context->Version = Interface->Version;
+
+ Trace("<====\n");
+
+done:
+ ReleaseMrswLockExclusive(&Context->Lock, Irql, FALSE);
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+HidRelease(
+ IN PINTERFACE Interface
+ )
+{
+ PXENVKBD_HID_CONTEXT Context = Interface->Context;
+ KIRQL Irql;
+
+ AcquireMrswLockExclusive(&Context->Lock, &Irql);
+
+ if (--Context->References > 0)
+ goto done;
+
+ Trace("====>\n");
+
+ ASSERT(!Context->Enabled);
+
+ Context->Version = 0;
+ Context->Frontend = NULL;
+
+ Trace("<====\n");
+
+done:
+ ReleaseMrswLockExclusive(&Context->Lock, Irql, FALSE);
+}
+
+static struct _XENHID_HID_INTERFACE_V1 HidInterfaceVersion1 = {
+ { sizeof (struct _XENHID_HID_INTERFACE_V1), 1, NULL, NULL, NULL },
+ HidAcquire,
+ HidRelease,
+ HidEnable,
+ HidDisable,
+ HidGetDeviceAttributes,
+ HidGetDeviceDescriptor,
+ HidGetReportDescriptor,
+ HidGetString,
+ HidGetIndexedString,
+ HidGetFeature,
+ HidSetFeature,
+ HidGetInputReport,
+ HidSetOutputReport,
+ HidReadReport,
+ HidWriteReport
+};
+
+NTSTATUS
+HidInitialize(
+ IN PXENVKBD_PDO Pdo,
+ OUT PXENVKBD_HID_CONTEXT *Context
+ )
+{
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ *Context = __HidAllocate(sizeof (XENVKBD_HID_CONTEXT));
+
+ status = STATUS_NO_MEMORY;
+ if (*Context == NULL)
+ goto fail1;
+
+ InitializeMrswLock(&(*Context)->Lock);
+
+ FdoGetDebugInterface(PdoGetFdo(Pdo),&(*Context)->DebugInterface);
+ FdoGetSuspendInterface(PdoGetFdo(Pdo),&(*Context)->SuspendInterface);
+
+ (*Context)->Pdo = Pdo;
+ (*Context)->KeyboardReport.ReportId = 1;
+ (*Context)->AbsMouseReport.ReportId = 2;
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+NTSTATUS
+HidGetInterface(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN ULONG Version,
+ IN OUT PINTERFACE Interface,
+ IN ULONG Size
+ )
+{
+ NTSTATUS status;
+
+ switch (Version) {
+ case 1: {
+ struct _XENHID_HID_INTERFACE_V1 *HidInterface;
+
+ HidInterface = (struct _XENHID_HID_INTERFACE_V1 *)Interface;
+
+ status = STATUS_BUFFER_OVERFLOW;
+ if (Size < sizeof (struct _XENHID_HID_INTERFACE_V1))
+ break;
+
+ *HidInterface = HidInterfaceVersion1;
+
+ ASSERT3U(Interface->Version, ==, Version);
+ Interface->Context = Context;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+ default:
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return status;
+}
+
+VOID
+HidTeardown(
+ IN PXENVKBD_HID_CONTEXT Context
+ )
+{
+ Trace("====>\n");
+
+ RtlZeroMemory(&Context->KeyboardReport, sizeof(XENVKBD_HID_KEYBOARD));
+ RtlZeroMemory(&Context->AbsMouseReport, sizeof(XENVKBD_HID_ABSMOUSE));
+ Context->KeyboardPending = FALSE;
+ Context->AbsMousePending = FALSE;
+
+ Context->Pdo = NULL;
+ Context->Version = 0;
+
+ RtlZeroMemory(&Context->SuspendInterface,
+ sizeof (XENBUS_SUSPEND_INTERFACE));
+ RtlZeroMemory(&Context->DebugInterface,
+ sizeof (XENBUS_DEBUG_INTERFACE));
+
+ RtlZeroMemory(&Context->Lock, sizeof (XENVKBD_MRSW_LOCK));
+
+ ASSERT(IsZeroMemory(Context, sizeof (XENVKBD_HID_CONTEXT)));
+ __HidFree(Context);
+
+ Trace("<====\n");
+}
+
+static FORCEINLINE LONG
+Constrain(
+ IN LONG Value,
+ IN LONG Min,
+ IN LONG Max
+ )
+{
+ if (Value < Min)
+ return Min;
+ if (Value > Max)
+ return Max;
+ return Value;
+}
+
+static FORCEINLINE UCHAR
+SetBit(
+ IN UCHAR Value,
+ IN UCHAR BitIdx,
+ IN BOOLEAN Pressed
+ )
+{
+ if (Pressed) {
+ return Value | (1 << BitIdx);
+ } else {
+ return Value & ~(1 << BitIdx);
+ }
+}
+
+static FORCEINLINE VOID
+SetArray(
+ IN PUCHAR Array,
+ IN ULONG Size,
+ IN UCHAR Value,
+ IN BOOLEAN Pressed
+ )
+{
+ ULONG Idx;
+ if (Pressed) {
+ for (Idx = 0; Idx < Size; ++Idx) {
+ if (Array[Idx] == Value)
+ break;
+ if (Array[Idx] != 0)
+ continue;
+ Array[Idx] = Value;
+ break;
+ }
+ } else {
+ for (Idx = 0; Idx < Size; ++Idx) {
+ if (Array[Idx] == 0)
+ break;
+ if (Array[Idx] != Value)
+ continue;
+ for (; Idx < Size - 1; ++Idx)
+ Array[Idx] = Array[Idx + 1];
+ Array[Size - 1] = 0;
+ break;
+ }
+ }
+}
+
+static FORCEINLINE USHORT
+KeyCodeToUsage(
+ IN ULONG KeyCode
+ )
+{
+ if (KeyCode < sizeof(VkbdKeyCodeToUsage)/sizeof(VkbdKeyCodeToUsage[0]))
+ return VkbdKeyCodeToUsage[KeyCode];
+ return 0;
+}
+
+VOID
+HidEventMotion(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN LONG dX,
+ IN LONG dY,
+ IN LONG dZ
+ )
+{
+ Context->AbsMouseReport.X = (USHORT)Constrain(Context->AbsMouseReport.X + dX, 0, 32767);
+ Context->AbsMouseReport.Y = (USHORT)Constrain(Context->AbsMouseReport.Y + dY, 0, 32767);
+ Context->AbsMouseReport.dZ = -(CHAR)Constrain(dZ, -127, 127);
+
+ Context->AbsMousePending = HidSendReadReport(Context,
+ &Context->AbsMouseReport,
+ sizeof(XENVKBD_HID_ABSMOUSE));
+}
+
+VOID
+HidEventKeypress(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN ULONG KeyCode,
+ IN BOOLEAN Pressed
+ )
+{
+ if (KeyCode >= 0x110 && KeyCode <= 0x114) {
+ // Mouse Buttons
+ Context->AbsMouseReport.Buttons = SetBit(Context->AbsMouseReport.Buttons,
+ (UCHAR)(KeyCode - 0x110),
+ Pressed);
+
+ Context->AbsMousePending = HidSendReadReport(Context,
+ &Context->AbsMouseReport,
+ sizeof(XENVKBD_HID_ABSMOUSE));
+
+ } else {
+ // map KeyCode to Usage
+ USHORT Usage = KeyCodeToUsage(KeyCode);
+ if (Usage == 0)
+ return; // non-standard key
+
+ if (Usage >= 0xE0 && Usage <= 0xE7) {
+ // Modifier
+ Context->KeyboardReport.Modifiers = SetBit(Context->KeyboardReport.Modifiers,
+ (UCHAR)(Usage - 0xE0),
+ Pressed);
+ } else {
+ // Standard Key
+ SetArray(Context->KeyboardReport.Keys,
+ 6,
+ (UCHAR)Usage,
+ Pressed);
+ }
+ Context->KeyboardPending = HidSendReadReport(Context,
+ &Context->KeyboardReport,
+ sizeof(XENVKBD_HID_KEYBOARD));
+
+ }
+}
+
+VOID
+HidEventPosition(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN ULONG X,
+ IN ULONG Y,
+ IN LONG dZ
+ )
+{
+ Context->AbsMouseReport.X = (USHORT)Constrain(X, 0, 32767);
+ Context->AbsMouseReport.Y = (USHORT)Constrain(Y, 0, 32767);
+ Context->AbsMouseReport.dZ = -(CHAR)Constrain(dZ, -127, 127);
+
+ Context->AbsMousePending = HidSendReadReport(Context,
+ &Context->AbsMouseReport,
+ sizeof(XENVKBD_HID_ABSMOUSE));
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_HID_H
+#define _XENVKBD_HID_H
+
+#include <ntddk.h>
+#include <hid_interface.h>
+
+#include "thread.h"
+
+typedef struct _XENVKBD_HID_CONTEXT XENVKBD_HID_CONTEXT, *PXENVKBD_HID_CONTEXT;
+
+#include "fdo.h"
+
+extern NTSTATUS
+HidInitialize(
+ IN PXENVKBD_PDO Pdo,
+ OUT PXENVKBD_HID_CONTEXT *Context
+ );
+
+extern NTSTATUS
+HidGetInterface(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN ULONG Version,
+ IN OUT PINTERFACE Interface,
+ IN ULONG Size
+ );
+
+extern VOID
+HidTeardown(
+ IN PXENVKBD_HID_CONTEXT Context
+ );
+
+// CALLBACKS
+
+extern VOID
+HidEventMotion(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN LONG dX,
+ IN LONG dY,
+ IN LONG dZ
+ );
+
+extern VOID
+HidEventKeypress(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN ULONG KeyCode,
+ IN BOOLEAN Pressed
+ );
+
+extern VOID
+HidEventPosition(
+ IN PXENVKBD_HID_CONTEXT Context,
+ IN ULONG X,
+ IN ULONG Y,
+ IN LONG dZ
+ );
+
+#endif // _XENVKBD_VKBD_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_MRSW_H
+#define _XENVKBD_MRSW_H
+
+#include <ntddk.h>
+
+#include "assert.h"
+#include "util.h"
+
+#pragma warning(disable:4127) // conditional expression is constant
+
+typedef struct _XENVKBD_MRSW_HOLDER {
+ PKTHREAD Thread;
+ LONG Level;
+} XENVKBD_MRSW_HOLDER, *PXENVKBD_MRSW_HOLDER;
+
+typedef struct _XENVKBD_MRSW_LOCK {
+ volatile LONG64 Mask;
+ XENVKBD_MRSW_HOLDER Holder[64];
+ KEVENT Event;
+} XENVKBD_MRSW_LOCK, *PXENVKBD_MRSW_LOCK;
+
+C_ASSERT(RTL_FIELD_SIZE(XENVKBD_MRSW_LOCK, Holder) == RTL_FIELD_SIZE(XENVKBD_MRSW_LOCK, Mask) * 8 * sizeof (XENVKBD_MRSW_HOLDER));
+
+#define XENVKBD_MRSW_EXCLUSIVE_SLOT 0
+
+static FORCEINLINE VOID
+InitializeMrswLock(
+ IN PXENVKBD_MRSW_LOCK Lock
+ )
+{
+ LONG Slot;
+
+ RtlZeroMemory(Lock, sizeof (XENVKBD_MRSW_LOCK));
+
+ for (Slot = 0; Slot < sizeof (Lock->Mask) * 8; Slot++)
+ Lock->Holder[Slot].Level = -1;
+
+ KeInitializeEvent(&Lock->Event, NotificationEvent, FALSE);
+}
+
+static FORCEINLINE BOOLEAN
+__ClaimExclusive(
+ IN PXENVKBD_MRSW_LOCK Lock
+ )
+{
+ LONG64 Old;
+ LONG64 New;
+
+ Old = 0;
+ New = 1ll << XENVKBD_MRSW_EXCLUSIVE_SLOT;
+
+ return (InterlockedCompareExchange64(&Lock->Mask, New, Old) == Old) ? TRUE : FALSE;
+}
+
+static FORCEINLINE KIRQL
+__drv_maxIRQL(APC_LEVEL)
+__drv_raisesIRQL(DISPATCH_LEVEL)
+__drv_savesIRQL
+__AcquireMrswLockExclusive(
+ IN PXENVKBD_MRSW_LOCK Lock
+ )
+{
+ KIRQL Irql;
+ LONG Slot;
+ PKTHREAD Self;
+ PXENVKBD_MRSW_HOLDER Holder;
+
+ ASSERT3U(KeGetCurrentIrql(), <, DISPATCH_LEVEL);
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ Self = KeGetCurrentThread();
+
+ // Make sure we do not already hold the lock
+ for (Slot = 0; Slot < sizeof (Lock->Mask) * 8; Slot++)
+ ASSERT(Lock->Holder[Slot].Thread != Self);
+
+ for (;;) {
+ if (__ClaimExclusive(Lock))
+ break;
+
+ KeLowerIrql(Irql);
+
+ (VOID) KeWaitForSingleObject(&Lock->Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(&Lock->Event);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+ }
+
+ Holder = &Lock->Holder[XENVKBD_MRSW_EXCLUSIVE_SLOT];
+
+ ASSERT3P(Holder->Thread, ==, NULL);
+ Holder->Thread = Self;
+ Holder->Level = 0;
+
+ return Irql;
+}
+
+#define AcquireMrswLockExclusive(_Lock, _Irql) \
+ do { \
+ *(_Irql) = __AcquireMrswLockExclusive(_Lock); \
+ } while (FALSE)
+
+static FORCEINLINE VOID
+__drv_maxIRQL(DISPATCH_LEVEL)
+__drv_requiresIRQL(DISPATCH_LEVEL)
+ReleaseMrswLockExclusive(
+ IN PXENVKBD_MRSW_LOCK Lock,
+ IN __drv_restoresIRQL KIRQL Irql,
+ IN BOOLEAN Shared
+ )
+{
+ LONG Slot;
+ PKTHREAD Self;
+ LONG64 Old;
+ LONG64 New;
+ PXENVKBD_MRSW_HOLDER Holder;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+ Slot = XENVKBD_MRSW_EXCLUSIVE_SLOT + 1; // Choose any slot other than the exclusive slot
+
+ Old = 1ll << XENVKBD_MRSW_EXCLUSIVE_SLOT;
+ New = (Shared) ? (1ll << Slot) : 0;
+
+ Old = InterlockedCompareExchange64(&Lock->Mask, New, Old);
+ ASSERT3U(Old, == , 1ll << XENVKBD_MRSW_EXCLUSIVE_SLOT);
+
+ Self = KeGetCurrentThread();
+
+ ASSERT3P(Lock->Holder[XENVKBD_MRSW_EXCLUSIVE_SLOT].Thread, ==, Self);
+
+ // If we are leaving the lock held shared then we need to transfer
+ // our identity information into the hew slot.
+ if (Shared)
+ Lock->Holder[Slot] = Lock->Holder[XENVKBD_MRSW_EXCLUSIVE_SLOT];
+
+ Holder = &Lock->Holder[XENVKBD_MRSW_EXCLUSIVE_SLOT];
+
+ Holder->Thread = NULL;
+ Holder->Level = -1;
+
+ KeLowerIrql(Irql);
+}
+
+static FORCEINLINE LONG
+__ClaimShared(
+ IN PXENVKBD_MRSW_LOCK Lock
+ )
+{
+ LONG Slot;
+ LONG64 Old;
+ LONG64 New;
+
+ // Make sure the exclusive bit is set so that we don't find it
+ Old = Lock->Mask | (1ll << XENVKBD_MRSW_EXCLUSIVE_SLOT);
+
+ Slot = __ffu((ULONG64)Old);
+ ASSERT(Slot >= 0);
+ ASSERT3U(Slot, != , XENVKBD_MRSW_EXCLUSIVE_SLOT);
+
+ Old &= ~(1ll << XENVKBD_MRSW_EXCLUSIVE_SLOT);
+ New = Old | (1ll << Slot);
+
+ return (InterlockedCompareExchange64(&Lock->Mask, New, Old) == Old) ? Slot : -1;
+}
+
+static FORCEINLINE VOID
+AcquireMrswLockShared(
+ IN PXENVKBD_MRSW_LOCK Lock
+ )
+{
+ KIRQL Irql;
+ LONG Level;
+ LONG Slot;
+ PKTHREAD Self;
+ PXENVKBD_MRSW_HOLDER Holder;
+
+ ASSERT3U(KeGetCurrentIrql(), <=, DISPATCH_LEVEL);
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ Self = KeGetCurrentThread();
+
+ // Do we already hold the lock? If so, get the nesting level
+ Level = -1;
+ for (Slot = 0; Slot < sizeof (Lock->Mask) * 8; Slot++) {
+ if (Lock->Holder[Slot].Thread == Self && Lock->Holder[Slot].Level > Level)
+ Level = Lock->Holder[Slot].Level;
+ }
+ Level++;
+
+ for (;;) {
+ Slot = __ClaimShared(Lock);
+ if (Slot >= 0)
+ break;
+
+ _mm_pause();
+ }
+
+ Holder = &Lock->Holder[Slot];
+
+ Holder->Thread = Self;
+ Holder->Level = Level;
+
+ KeLowerIrql(Irql);
+}
+
+static FORCEINLINE VOID
+ReleaseMrswLockShared(
+ IN PXENVKBD_MRSW_LOCK Lock
+ )
+{
+ KIRQL Irql;
+ PKTHREAD Self;
+ LONG Level;
+ LONG Deepest;
+ LONG Slot;
+ LONG64 Old;
+ LONG64 New;
+ PXENVKBD_MRSW_HOLDER Holder;
+
+ ASSERT3U(KeGetCurrentIrql(), <=, DISPATCH_LEVEL);
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ Self = KeGetCurrentThread();
+
+ Level = -1;
+ Deepest = -1;
+ for (Slot = 0; Slot < sizeof (Lock->Mask) * 8; Slot++) {
+ if (Lock->Holder[Slot].Thread == Self && Lock->Holder[Slot].Level > Level) {
+ Level = Lock->Holder[Slot].Level;
+ Deepest = Slot;
+ }
+ }
+ ASSERT(Level >= 0);
+
+ Slot = Deepest;
+ ASSERT3U(Slot, !=, XENVKBD_MRSW_EXCLUSIVE_SLOT);
+
+ Holder = &Lock->Holder[Slot];
+
+ Holder->Thread = NULL;
+ Holder->Level = -1;
+
+ do {
+ Old = Lock->Mask;
+ New = Old & ~(1ll << Slot);
+ } while (InterlockedCompareExchange64(&Lock->Mask, New, Old) != Old);
+
+ KeSetEvent(&Lock->Event, IO_NO_INCREMENT, FALSE);
+ KeLowerIrql(Irql);
+}
+
+#endif // _XENVKBD_MRSW_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_MUTEX_H
+#define _XENVKBD_MUTEX_H
+
+#include <ntddk.h>
+
+#include "assert.h"
+
+typedef struct _MUTEX {
+ PKTHREAD Owner;
+ KEVENT Event;
+} MUTEX, *PMUTEX;
+
+static FORCEINLINE VOID
+InitializeMutex(
+ IN PMUTEX Mutex
+ )
+{
+ RtlZeroMemory(Mutex, sizeof (MUTEX));
+
+ KeInitializeEvent(&Mutex->Event, SynchronizationEvent, TRUE);
+}
+
+static FORCEINLINE VOID
+__drv_maxIRQL(PASSIVE_LEVEL)
+AcquireMutex(
+ IN PMUTEX Mutex
+ )
+{
+ (VOID) KeWaitForSingleObject(&Mutex->Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ASSERT3P(Mutex->Owner, ==, NULL);
+ Mutex->Owner = KeGetCurrentThread();
+}
+
+static FORCEINLINE VOID
+__drv_maxIRQL(PASSIVE_LEVEL)
+ReleaseMutex(
+ IN PMUTEX Mutex
+ )
+{
+ ASSERT3P(Mutex->Owner, ==, KeGetCurrentThread());
+ Mutex->Owner = NULL;
+
+ KeSetEvent(&Mutex->Event, IO_NO_INCREMENT, FALSE);
+}
+
+#endif // _XENVKBD_MUTEX_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_NAMES_H_
+#define _XENVKBD_NAMES_H_
+
+#include <ntddk.h>
+#include <xen.h>
+
+static FORCEINLINE const CHAR *
+PowerTypeName(
+ IN POWER_STATE_TYPE Type
+ )
+{
+#define _POWER_TYPE_NAME(_Type) \
+ case _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _POWER_TYPE_NAME(SystemPowerState);
+ _POWER_TYPE_NAME(DevicePowerState);
+ default:
+ break;
+ }
+
+ return ("UNKNOWN");
+#undef _POWER_ACTION_NAME
+}
+
+static FORCEINLINE const CHAR *
+PowerSystemStateName(
+ IN SYSTEM_POWER_STATE State
+ )
+{
+#define _POWER_SYSTEM_STATE_NAME(_State) \
+ case PowerSystem ## _State: \
+ return #_State;
+
+ switch (State) {
+ _POWER_SYSTEM_STATE_NAME(Unspecified);
+ _POWER_SYSTEM_STATE_NAME(Working);
+ _POWER_SYSTEM_STATE_NAME(Sleeping1);
+ _POWER_SYSTEM_STATE_NAME(Sleeping2);
+ _POWER_SYSTEM_STATE_NAME(Sleeping3);
+ _POWER_SYSTEM_STATE_NAME(Hibernate);
+ _POWER_SYSTEM_STATE_NAME(Shutdown);
+ _POWER_SYSTEM_STATE_NAME(Maximum);
+ default:
+ break;
+ }
+
+ return ("UNKNOWN");
+#undef _POWER_SYSTEM_STATE_NAME
+}
+
+static FORCEINLINE const CHAR *
+PowerDeviceStateName(
+ IN DEVICE_POWER_STATE State
+ )
+{
+#define _POWER_DEVICE_STATE_NAME(_State) \
+ case PowerDevice ## _State: \
+ return #_State;
+
+ switch (State) {
+ _POWER_DEVICE_STATE_NAME(Unspecified);
+ _POWER_DEVICE_STATE_NAME(D0);
+ _POWER_DEVICE_STATE_NAME(D1);
+ _POWER_DEVICE_STATE_NAME(D2);
+ _POWER_DEVICE_STATE_NAME(D3);
+ _POWER_DEVICE_STATE_NAME(Maximum);
+ default:
+ break;
+ }
+
+ return ("UNKNOWN");
+#undef _POWER_DEVICE_STATE_NAME
+}
+
+static FORCEINLINE const CHAR *
+PowerActionName(
+ IN POWER_ACTION Type
+ )
+{
+#define _POWER_ACTION_NAME(_Type) \
+ case PowerAction ## _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _POWER_ACTION_NAME(None);
+ _POWER_ACTION_NAME(Reserved);
+ _POWER_ACTION_NAME(Sleep);
+ _POWER_ACTION_NAME(Hibernate);
+ _POWER_ACTION_NAME(Shutdown);
+ _POWER_ACTION_NAME(ShutdownReset);
+ _POWER_ACTION_NAME(ShutdownOff);
+ _POWER_ACTION_NAME(WarmEject);
+ default:
+ break;
+ }
+
+ return ("UNKNOWN");
+#undef _POWER_ACTION_NAME
+}
+
+static FORCEINLINE const CHAR *
+PowerMinorFunctionName(
+ IN ULONG MinorFunction
+ )
+{
+#define _POWER_MINOR_FUNCTION_NAME(_Function) \
+ case IRP_MN_ ## _Function: \
+ return #_Function;
+
+ switch (MinorFunction) {
+ _POWER_MINOR_FUNCTION_NAME(WAIT_WAKE);
+ _POWER_MINOR_FUNCTION_NAME(POWER_SEQUENCE);
+ _POWER_MINOR_FUNCTION_NAME(SET_POWER);
+ _POWER_MINOR_FUNCTION_NAME(QUERY_POWER);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _POWER_MINOR_FUNCTION_NAME
+}
+
+static FORCEINLINE const CHAR *
+PnpMinorFunctionName(
+ IN ULONG Function
+ )
+{
+#define _PNP_MINOR_FUNCTION_NAME(_Function) \
+ case IRP_MN_ ## _Function: \
+ return #_Function;
+
+ switch (Function) {
+ _PNP_MINOR_FUNCTION_NAME(START_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_REMOVE_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(REMOVE_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(CANCEL_REMOVE_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(STOP_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_STOP_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(CANCEL_STOP_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_DEVICE_RELATIONS);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_INTERFACE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_CAPABILITIES);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_RESOURCES);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_RESOURCE_REQUIREMENTS);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_DEVICE_TEXT);
+ _PNP_MINOR_FUNCTION_NAME(FILTER_RESOURCE_REQUIREMENTS);
+ _PNP_MINOR_FUNCTION_NAME(READ_CONFIG);
+ _PNP_MINOR_FUNCTION_NAME(WRITE_CONFIG);
+ _PNP_MINOR_FUNCTION_NAME(EJECT);
+ _PNP_MINOR_FUNCTION_NAME(SET_LOCK);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_ID);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_PNP_DEVICE_STATE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_BUS_INFORMATION);
+ _PNP_MINOR_FUNCTION_NAME(DEVICE_USAGE_NOTIFICATION);
+ _PNP_MINOR_FUNCTION_NAME(SURPRISE_REMOVAL);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_LEGACY_BUS_INFORMATION);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _PNP_MINOR_FUNCTION_NAME
+}
+
+static FORCEINLINE const CHAR *
+PartialResourceDescriptorTypeName(
+ IN UCHAR Type
+ )
+{
+#define _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(_Type) \
+ case CmResourceType ## _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Null);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Port);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Interrupt);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Memory);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Dma);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(DeviceSpecific);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(BusNumber);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(MemoryLarge);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(ConfigData);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(DevicePrivate);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME
+}
+
+static FORCEINLINE const CHAR *
+DeviceUsageTypeName(
+ IN DEVICE_USAGE_NOTIFICATION_TYPE Type
+ )
+{
+#define _DEVICE_USAGE_TYPE_NAME(_Type) \
+ case DeviceUsageType ## _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _DEVICE_USAGE_TYPE_NAME(Paging);
+ _DEVICE_USAGE_TYPE_NAME(Hibernation);
+ _DEVICE_USAGE_TYPE_NAME(DumpFile);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _DEVICE_USAGE_TYPE_NAME
+}
+
+static FORCEINLINE const CHAR *
+InterfaceTypeName(
+ IN INTERFACE_TYPE Type
+ )
+{
+#define _INTERFACE_TYPE_NAME(_Type) \
+ case _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _INTERFACE_TYPE_NAME(InterfaceTypeUndefined);
+ _INTERFACE_TYPE_NAME(Internal);
+ _INTERFACE_TYPE_NAME(Isa);
+ _INTERFACE_TYPE_NAME(Eisa);
+ _INTERFACE_TYPE_NAME(MicroChannel);
+ _INTERFACE_TYPE_NAME(TurboChannel);
+ _INTERFACE_TYPE_NAME(PCIBus);
+ _INTERFACE_TYPE_NAME(VMEBus);
+ _INTERFACE_TYPE_NAME(NuBus);
+ _INTERFACE_TYPE_NAME(PCMCIABus);
+ _INTERFACE_TYPE_NAME(CBus);
+ _INTERFACE_TYPE_NAME(MPIBus);
+ _INTERFACE_TYPE_NAME(MPSABus);
+ _INTERFACE_TYPE_NAME(ProcessorInternal);
+ _INTERFACE_TYPE_NAME(InternalPowerBus);
+ _INTERFACE_TYPE_NAME(PNPISABus);
+ _INTERFACE_TYPE_NAME(PNPBus);
+ _INTERFACE_TYPE_NAME(Vmcs);
+ _INTERFACE_TYPE_NAME(ACPIBus);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _INTERFACE_TYPE_NAME
+}
+
+static FORCEINLINE const CHAR *
+DmaWidthName(
+ IN DMA_WIDTH Width
+ )
+{
+#define _DMA_WIDTH_NAME(_Width) \
+ case Width ## _Width: \
+ return #_Width;
+
+ switch (Width) {
+ _DMA_WIDTH_NAME(8Bits);
+ _DMA_WIDTH_NAME(16Bits);
+ _DMA_WIDTH_NAME(32Bits);
+ _DMA_WIDTH_NAME(64Bits);
+ _DMA_WIDTH_NAME(NoWrap);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _DMA_WIDTH_NAME
+}
+
+static FORCEINLINE const CHAR *
+DmaSpeedName(
+ IN DMA_SPEED Speed
+ )
+{
+#define _DMA_SPEED_NAME(_Speed) \
+ case _Speed: \
+ return #_Speed;
+
+ switch (Speed) {
+ _DMA_SPEED_NAME(Compatible);
+ _DMA_SPEED_NAME(TypeA);
+ _DMA_SPEED_NAME(TypeB);
+ _DMA_SPEED_NAME(TypeC);
+ _DMA_SPEED_NAME(TypeF);
+ _DMA_SPEED_NAME(MaximumDmaSpeed);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _DMA_SPEED_NAME
+}
+
+static FORCEINLINE const PCHAR
+XenbusStateName(
+ IN XenbusState State
+ )
+{
+#define _STATE_NAME(_State) \
+ case XenbusState ## _State: \
+ return #_State;
+
+ switch (State) {
+ _STATE_NAME(Unknown);
+ _STATE_NAME(Initialising);
+ _STATE_NAME(InitWait);
+ _STATE_NAME(Initialised);
+ _STATE_NAME(Connected);
+ _STATE_NAME(Closing);
+ _STATE_NAME(Closed);
+ _STATE_NAME(Reconfiguring);
+ _STATE_NAME(Reconfigured);
+ default:
+ break;
+ }
+
+ return "INVALID";
+
+#undef _STATE_NAME
+}
+
+#endif // _XENVKBD_NAMES_H_
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#define INITGUID 1
+
+#include <ntddk.h>
+#include <wdmguid.h>
+#include <devguid.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+#include <xen.h>
+
+#include <suspend_interface.h>
+#include <unplug_interface.h>
+#include <debug_interface.h>
+
+#include "names.h"
+#include "fdo.h"
+#include "pdo.h"
+#include "bus.h"
+#include "frontend.h"
+#include "hid.h"
+#include "driver.h"
+#include "registry.h"
+#include "thread.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+#include "version.h"
+#include "revision.h"
+
+#define PDO_POOL 'ODP'
+
+#define MAXNAMELEN 128
+
+struct _XENVKBD_PDO {
+ PXENVKBD_DX Dx;
+
+ PXENVKBD_THREAD SystemPowerThread;
+ PIRP SystemPowerIrp;
+ PXENVKBD_THREAD DevicePowerThread;
+ PIRP DevicePowerIrp;
+
+ PXENVKBD_FDO Fdo;
+ BOOLEAN Missing;
+ const CHAR *Reason;
+ LONG Eject;
+
+ BUS_INTERFACE_STANDARD BusInterface;
+
+ XENBUS_SUSPEND_INTERFACE SuspendInterface;
+ PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
+
+ XENBUS_UNPLUG_INTERFACE UnplugInterface;
+ BOOLEAN UnplugRequested;
+
+ PXENVKBD_FRONTEND Frontend;
+
+ PXENVKBD_HID_CONTEXT HidContext;
+ XENHID_HID_INTERFACE HidInterface;
+};
+
+static FORCEINLINE PVOID
+__PdoAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, PDO_POOL);
+}
+
+static FORCEINLINE VOID
+__PdoFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, PDO_POOL);
+}
+
+static FORCEINLINE VOID
+__PdoSetDevicePnpState(
+ IN PXENVKBD_PDO Pdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ // We can never transition out of the deleted state
+ ASSERT(Dx->DevicePnpState != Deleted || State == Deleted);
+
+ Dx->PreviousDevicePnpState = Dx->DevicePnpState;
+ Dx->DevicePnpState = State;
+}
+
+VOID
+PdoSetDevicePnpState(
+ IN PXENVKBD_PDO Pdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ __PdoSetDevicePnpState(Pdo, State);
+}
+
+static FORCEINLINE VOID
+__PdoRestoreDevicePnpState(
+ IN PXENVKBD_PDO Pdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ if (Dx->DevicePnpState == State)
+ Dx->DevicePnpState = Dx->PreviousDevicePnpState;
+}
+
+static FORCEINLINE DEVICE_PNP_STATE
+__PdoGetDevicePnpState(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ return Dx->DevicePnpState;
+}
+
+DEVICE_PNP_STATE
+PdoGetDevicePnpState(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return __PdoGetDevicePnpState(Pdo);
+}
+
+static FORCEINLINE VOID
+__PdoSetSystemPowerState(
+ IN PXENVKBD_PDO Pdo,
+ IN SYSTEM_POWER_STATE State
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ Dx->SystemPowerState = State;
+}
+
+static FORCEINLINE SYSTEM_POWER_STATE
+__PdoGetSystemPowerState(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ return Dx->SystemPowerState;
+}
+
+static FORCEINLINE VOID
+__PdoSetDevicePowerState(
+ IN PXENVKBD_PDO Pdo,
+ IN DEVICE_POWER_STATE State
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ Dx->DevicePowerState = State;
+}
+
+static FORCEINLINE DEVICE_POWER_STATE
+__PdoGetDevicePowerState(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ return Dx->DevicePowerState;
+}
+
+static FORCEINLINE VOID
+__PdoSetMissing(
+ IN PXENVKBD_PDO Pdo,
+ IN const CHAR *Reason
+ )
+{
+ Pdo->Reason = Reason;
+ Pdo->Missing = TRUE;
+}
+
+VOID
+PdoSetMissing(
+ IN PXENVKBD_PDO Pdo,
+ IN const CHAR *Reason
+ )
+{
+ __PdoSetMissing(Pdo, Reason);
+}
+
+static FORCEINLINE BOOLEAN
+__PdoIsMissing(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return Pdo->Missing;
+}
+
+BOOLEAN
+PdoIsMissing(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return __PdoIsMissing(Pdo);
+}
+
+static FORCEINLINE PXENVKBD_FDO
+__PdoGetFdo(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return Pdo->Fdo;
+}
+
+PXENVKBD_FDO
+PdoGetFdo(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return __PdoGetFdo(Pdo);
+}
+
+static FORCEINLINE VOID
+__PdoSetName(
+ IN PXENVKBD_PDO Pdo,
+ IN PCHAR Path
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+ NTSTATUS status;
+
+ status = RtlStringCbPrintfA(Dx->Name,
+ MAX_DEVICE_ID_LEN,
+ "%s",
+ Path);
+ ASSERT(NT_SUCCESS(status));
+}
+
+static FORCEINLINE PCHAR
+__PdoGetName(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ return Dx->Name;
+}
+
+PCHAR
+PdoGetName(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return __PdoGetName(Pdo);
+}
+
+static FORCEINLINE BOOLEAN
+__PdoSetEjectRequested(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return (InterlockedBitTestAndSet(&Pdo->Eject, 0) == 0) ? TRUE : FALSE;
+}
+
+VOID
+PdoRequestEject(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+ PDEVICE_OBJECT PhysicalDeviceObject = Dx->DeviceObject;
+ PXENVKBD_FDO Fdo = __PdoGetFdo(Pdo);
+
+ if (!__PdoSetEjectRequested(Pdo))
+ return;
+
+ Info("%p (%s)\n",
+ PhysicalDeviceObject,
+ __PdoGetName(Pdo));
+
+ IoInvalidateDeviceRelations(FdoGetPhysicalDeviceObject(Fdo),
+ BusRelations);
+}
+
+static FORCEINLINE BOOLEAN
+__PdoClearEjectRequested(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return (InterlockedBitTestAndReset(&Pdo->Eject, 0) != 0) ? TRUE : FALSE;
+}
+
+static FORCEINLINE BOOLEAN
+__PdoIsEjectRequested(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ KeMemoryBarrier();
+ return (Pdo->Eject & 1) ? TRUE : FALSE;
+}
+
+BOOLEAN
+PdoIsEjectRequested(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return __PdoIsEjectRequested(Pdo);
+}
+
+#define MAXTEXTLEN 1024
+
+typedef struct _XENVKBD_PDO_REVISION {
+ ULONG Number;
+ ULONG HidInterfaceVersion;
+} XENVKBD_PDO_REVISION, *PXENVKBD_PDO_REVISION;
+
+#define DEFINE_REVISION(_N, _H) \
+ { (_N), (_H) }
+
+static XENVKBD_PDO_REVISION PdoRevision[] = {
+ DEFINE_REVISION_TABLE
+};
+
+#undef DEFINE_REVISION
+
+static VOID
+PdoDumpRevisions(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ ULONG Index;
+
+ UNREFERENCED_PARAMETER(Pdo);
+
+ for (Index = 0; Index < ARRAYSIZE(PdoRevision); Index++) {
+ PXENVKBD_PDO_REVISION Revision = &PdoRevision[Index];
+
+ ASSERT3U(Revision->HidInterfaceVersion, >=, XENHID_HID_INTERFACE_VERSION_MIN);
+ ASSERT3U(Revision->HidInterfaceVersion, <=, XENHID_HID_INTERFACE_VERSION_MAX);
+ ASSERT(IMPLY(Index == ARRAYSIZE(PdoRevision) - 1,
+ Revision->HidInterfaceVersion == XENHID_HID_INTERFACE_VERSION_MAX));
+
+ Info("%08X -> "
+ "HID v%u\n",
+ Revision->Number,
+ Revision->HidInterfaceVersion);
+ }
+}
+
+static FORCEINLINE PDEVICE_OBJECT
+__PdoGetDeviceObject(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+
+ return (Dx->DeviceObject);
+}
+
+PDEVICE_OBJECT
+PdoGetDeviceObject(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return __PdoGetDeviceObject(Pdo);
+}
+
+static FORCEINLINE PCHAR
+__PdoGetVendorName(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return FdoGetVendorName(__PdoGetFdo(Pdo));
+}
+
+static FORCEINLINE PXENVKBD_FRONTEND
+__PdoGetFrontend(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return Pdo->Frontend;
+}
+
+PXENVKBD_FRONTEND
+PdoGetFrontend(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return __PdoGetFrontend(Pdo);
+}
+
+static FORCEINLINE PXENVKBD_HID_CONTEXT
+__PdoGetHidContext(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return Pdo->HidContext;
+}
+
+PXENVKBD_HID_CONTEXT
+PdoGetHidContext(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return __PdoGetHidContext(Pdo);
+}
+
+PDMA_ADAPTER
+PdoGetDmaAdapter(
+ IN PXENVKBD_PDO Pdo,
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ )
+{
+ Trace("<===>\n");
+
+ return FdoGetDmaAdapter(__PdoGetFdo(Pdo),
+ DeviceDescriptor,
+ NumberOfMapRegisters);
+}
+
+BOOLEAN
+PdoTranslateBusAddress(
+ IN PXENVKBD_PDO Pdo,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN ULONG Length,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+{
+ Trace("<===>\n");
+
+ return FdoTranslateBusAddress(__PdoGetFdo(Pdo),
+ BusAddress,
+ Length,
+ AddressSpace,
+ TranslatedAddress);
+}
+
+ULONG
+PdoSetBusData(
+ IN PXENVKBD_PDO Pdo,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ Trace("<===>\n");
+
+ return FdoSetBusData(__PdoGetFdo(Pdo),
+ DataType,
+ Buffer,
+ Offset,
+ Length);
+}
+
+ULONG
+PdoGetBusData(
+ IN PXENVKBD_PDO Pdo,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ Trace("<===>\n");
+
+ return FdoGetBusData(__PdoGetFdo(Pdo),
+ DataType,
+ Buffer,
+ Offset,
+ Length);
+}
+
+static FORCEINLINE NTSTATUS
+__PdoD3ToD0(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ POWER_STATE PowerState;
+ NTSTATUS status;
+
+ Trace("(%s) ====>\n", __PdoGetName(Pdo));
+
+ ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+ ASSERT3U(__PdoGetDevicePowerState(Pdo), ==, PowerDeviceD3);
+
+ // Dont take over keyboard/mouse until XenHid starts
+ // XenHid calling XENHID_HID(Enable...) sets state to ENABLED
+ status = FrontendSetState(__PdoGetFrontend(Pdo), FRONTEND_CLOSED);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __PdoSetDevicePowerState(Pdo, PowerDeviceD0);
+
+ PowerState.DeviceState = PowerDeviceD0;
+ PoSetPowerState(__PdoGetDeviceObject(Pdo),
+ DevicePowerState,
+ PowerState);
+
+ Trace("(%s) <====\n", __PdoGetName(Pdo));
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static FORCEINLINE VOID
+__PdoD0ToD3(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ POWER_STATE PowerState;
+
+ Trace("(%s) ====>\n", __PdoGetName(Pdo));
+
+ ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+ ASSERT3U(__PdoGetDevicePowerState(Pdo), ==, PowerDeviceD0);
+
+ PowerState.DeviceState = PowerDeviceD3;
+ PoSetPowerState(__PdoGetDeviceObject(Pdo),
+ DevicePowerState,
+ PowerState);
+
+ __PdoSetDevicePowerState(Pdo, PowerDeviceD3);
+
+ (VOID) FrontendSetState(__PdoGetFrontend(Pdo), FRONTEND_CLOSED);
+
+ Trace("(%s) <====\n", __PdoGetName(Pdo));
+}
+
+static DECLSPEC_NOINLINE VOID
+PdoSuspendCallbackLate(
+ IN PVOID Argument
+ )
+{
+ PXENVKBD_PDO Pdo = Argument;
+ NTSTATUS status;
+
+ __PdoD0ToD3(Pdo);
+
+ status = __PdoD3ToD0(Pdo);
+ ASSERT(NT_SUCCESS(status));
+}
+
+// This function must not touch pageable code or data
+static DECLSPEC_NOINLINE NTSTATUS
+PdoD3ToD0(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ KIRQL Irql;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ status = XENBUS_SUSPEND(Acquire, &Pdo->SuspendInterface);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = __PdoD3ToD0(Pdo);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = XENBUS_SUSPEND(Register,
+ &Pdo->SuspendInterface,
+ SUSPEND_CALLBACK_LATE,
+ PdoSuspendCallbackLate,
+ Pdo,
+ &Pdo->SuspendCallbackLate);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ KeLowerIrql(Irql);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+
+ __PdoD0ToD3(Pdo);
+
+fail2:
+ Error("fail2\n");
+
+ XENBUS_SUSPEND(Release, &Pdo->SuspendInterface);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ KeLowerIrql(Irql);
+
+ return status;
+}
+
+// This function must not touch pageable code or data
+static DECLSPEC_NOINLINE VOID
+PdoD0ToD3(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ KIRQL Irql;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+ XENBUS_SUSPEND(Deregister,
+ &Pdo->SuspendInterface,
+ Pdo->SuspendCallbackLate);
+ Pdo->SuspendCallbackLate = NULL;
+
+ __PdoD0ToD3(Pdo);
+
+ XENBUS_SUSPEND(Release, &Pdo->SuspendInterface);
+
+ KeLowerIrql(Irql);
+}
+
+// This function must not touch pageable code or data
+static DECLSPEC_NOINLINE VOID
+PdoS4ToS3(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ Trace("(%s) ====>\n", __PdoGetName(Pdo));
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3U(__PdoGetSystemPowerState(Pdo), ==, PowerSystemHibernate);
+
+ __PdoSetSystemPowerState(Pdo, PowerSystemSleeping3);
+
+ Trace("(%s) <====\n", __PdoGetName(Pdo));
+}
+
+// This function must not touch pageable code or data
+static DECLSPEC_NOINLINE VOID
+PdoS3ToS4(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ Trace("(%s) ====>\n", __PdoGetName(Pdo));
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3U(__PdoGetSystemPowerState(Pdo), ==, PowerSystemSleeping3);
+
+ __PdoSetSystemPowerState(Pdo, PowerSystemHibernate);
+
+ Trace("(%s) <====\n", __PdoGetName(Pdo));
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoStartDevice(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = PdoD3ToD0(Pdo);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __PdoSetDevicePnpState(Pdo, Started);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryStopDevice(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ __PdoSetDevicePnpState(Pdo, StopPending);
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoCancelStopDevice(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ __PdoRestoreDevicePnpState(Pdo, StopPending);
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoStopDevice(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0)
+ goto done;
+
+ PdoD0ToD3(Pdo);
+
+done:
+ __PdoSetDevicePnpState(Pdo, Stopped);
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryRemoveDevice(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ __PdoSetDevicePnpState(Pdo, RemovePending);
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoCancelRemoveDevice(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ if (__PdoClearEjectRequested(Pdo))
+ FrontendEjectFailed(__PdoGetFrontend(Pdo));
+
+ __PdoRestoreDevicePnpState(Pdo, RemovePending);
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoSurpriseRemoval(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ Warning("%s\n", __PdoGetName(Pdo));
+
+ __PdoSetDevicePnpState(Pdo, SurpriseRemovePending);
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoRemoveDevice(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PXENVKBD_FDO Fdo = __PdoGetFdo(Pdo);
+ BOOLEAN NeedInvalidate;
+ NTSTATUS status;
+
+ if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0)
+ goto done;
+
+ PdoD0ToD3(Pdo);
+
+done:
+ NeedInvalidate = FALSE;
+
+ FdoAcquireMutex(Fdo);
+
+ if (__PdoIsMissing(Pdo)) {
+ DEVICE_PNP_STATE State = __PdoGetDevicePnpState(Pdo);
+
+ __PdoSetDevicePnpState(Pdo, Deleted);
+
+ if (State == SurpriseRemovePending)
+ PdoDestroy(Pdo);
+ else
+ NeedInvalidate = TRUE;
+ } else {
+ __PdoSetDevicePnpState(Pdo, Enumerated);
+ }
+
+ FdoReleaseMutex(Fdo);
+
+ if (NeedInvalidate)
+ IoInvalidateDeviceRelations(FdoGetPhysicalDeviceObject(Fdo),
+ BusRelations);
+
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryDeviceRelations(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ PDEVICE_RELATIONS Relations;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ status = Irp->IoStatus.Status;
+
+ if (StackLocation->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
+ goto done;
+
+ Relations = ExAllocatePoolWithTag(PagedPool, sizeof (DEVICE_RELATIONS), 'FIV');
+
+ status = STATUS_NO_MEMORY;
+ if (Relations == NULL)
+ goto done;
+
+ RtlZeroMemory(Relations, sizeof (DEVICE_RELATIONS));
+
+ Relations->Count = 1;
+ ObReferenceObject(__PdoGetDeviceObject(Pdo));
+ Relations->Objects[0] = __PdoGetDeviceObject(Pdo);
+
+ Irp->IoStatus.Information = (ULONG_PTR)Relations;
+ status = STATUS_SUCCESS;
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static NTSTATUS
+PdoDelegateIrp(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ return FdoDelegateIrp(Pdo->Fdo, Irp);
+}
+
+static NTSTATUS
+PdoQueryBusInterface(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ USHORT Size;
+ USHORT Version;
+ PBUS_INTERFACE_STANDARD BusInterface;
+ NTSTATUS status;
+
+ status = Irp->IoStatus.Status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ Size = StackLocation->Parameters.QueryInterface.Size;
+ Version = StackLocation->Parameters.QueryInterface.Version;
+ BusInterface = (PBUS_INTERFACE_STANDARD)StackLocation->Parameters.QueryInterface.Interface;
+
+ if (Version != 1)
+ goto done;
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ if (Size < sizeof (BUS_INTERFACE_STANDARD))
+ goto done;
+
+ *BusInterface = Pdo->BusInterface;
+ BusInterface->InterfaceReference(BusInterface->Context);
+
+ Irp->IoStatus.Information = 0;
+ status = STATUS_SUCCESS;
+
+done:
+ return status;
+}
+
+static NTSTATUS
+PdoQueryHidInterface(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ USHORT Size;
+ USHORT Version;
+ PINTERFACE Interface;
+ PVOID Context;
+ NTSTATUS status;
+
+ status = Irp->IoStatus.Status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ Size = StackLocation->Parameters.QueryInterface.Size;
+ Version = StackLocation->Parameters.QueryInterface.Version;
+ Interface = StackLocation->Parameters.QueryInterface.Interface;
+
+ Context = __PdoGetHidContext(Pdo);
+
+ status = HidGetInterface(Context,
+ Version,
+ Interface,
+ Size);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ Irp->IoStatus.Information = 0;
+ status = STATUS_SUCCESS;
+
+done:
+ return status;
+}
+
+struct _INTERFACE_ENTRY {
+ const GUID *Guid;
+ const CHAR *Name;
+ NTSTATUS (*Query)(PXENVKBD_PDO, PIRP);
+};
+
+struct _INTERFACE_ENTRY PdoInterfaceTable[] = {
+ { &GUID_BUS_INTERFACE_STANDARD, "BUS_INTERFACE", PdoQueryBusInterface },
+ { &GUID_XENHID_HID_INTERFACE, "HID_INTERFACE", PdoQueryHidInterface },
+ { &GUID_XENBUS_CACHE_INTERFACE, "CACHE_INTERFACE", PdoDelegateIrp },
+ { &GUID_XENBUS_STORE_INTERFACE, "STORE_INTERFACE", PdoDelegateIrp },
+ { &GUID_XENBUS_SUSPEND_INTERFACE, "SUSPEND_INTERFACE", PdoDelegateIrp },
+ { NULL, NULL, NULL }
+};
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryInterface(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ const GUID *InterfaceType;
+ struct _INTERFACE_ENTRY *Entry;
+ USHORT Version;
+ NTSTATUS status;
+
+ status = Irp->IoStatus.Status;
+
+ if (status != STATUS_NOT_SUPPORTED)
+ goto done;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ InterfaceType = StackLocation->Parameters.QueryInterface.InterfaceType;
+ Version = StackLocation->Parameters.QueryInterface.Version;
+
+ for (Entry = PdoInterfaceTable; Entry->Guid != NULL; Entry++) {
+ if (IsEqualGUID(InterfaceType, Entry->Guid)) {
+ Info("%s: %s (VERSION %d)\n",
+ __PdoGetName(Pdo),
+ Entry->Name,
+ Version);
+ status = Entry->Query(Pdo, Irp);
+ goto done;
+ }
+ }
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryCapabilities(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ PDEVICE_CAPABILITIES Capabilities;
+ SYSTEM_POWER_STATE SystemPowerState;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Pdo);
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ Capabilities = StackLocation->Parameters.DeviceCapabilities.Capabilities;
+
+ status = STATUS_INVALID_PARAMETER;
+ if (Capabilities->Version != 1)
+ goto done;
+
+ Capabilities->DeviceD1 = 0;
+ Capabilities->DeviceD2 = 0;
+ Capabilities->LockSupported = 0;
+ Capabilities->EjectSupported = 1;
+ Capabilities->Removable = 1;
+ Capabilities->DockDevice = 0;
+ Capabilities->UniqueID = 1;
+ Capabilities->SilentInstall = 1;
+ Capabilities->RawDeviceOK = 0;
+ Capabilities->SurpriseRemovalOK = 1;
+ Capabilities->HardwareDisabled = 0;
+ Capabilities->NoDisplayInUI = 0;
+
+ Capabilities->Address = 0xffffffff;
+ Capabilities->UINumber = 0xffffffff;
+
+ for (SystemPowerState = 0; SystemPowerState < PowerSystemMaximum; SystemPowerState++) {
+ switch (SystemPowerState) {
+ case PowerSystemUnspecified:
+ case PowerSystemSleeping1:
+ case PowerSystemSleeping2:
+ break;
+
+ case PowerSystemWorking:
+ Capabilities->DeviceState[SystemPowerState] = PowerDeviceD0;
+ break;
+
+ default:
+ Capabilities->DeviceState[SystemPowerState] = PowerDeviceD3;
+ break;
+ }
+ }
+
+ Capabilities->SystemWake = PowerSystemUnspecified;
+ Capabilities->DeviceWake = PowerDeviceUnspecified;
+ Capabilities->D1Latency = 0;
+ Capabilities->D2Latency = 0;
+ Capabilities->D3Latency = 0;
+
+ status = STATUS_SUCCESS;
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryDeviceText(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ PWCHAR Buffer;
+ UNICODE_STRING Text;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (StackLocation->Parameters.QueryDeviceText.DeviceTextType) {
+ case DeviceTextDescription:
+ Trace("DeviceTextDescription\n");
+ break;
+
+ case DeviceTextLocationInformation:
+ Trace("DeviceTextLocationInformation\n");
+ break;
+
+ default:
+ Irp->IoStatus.Information = 0;
+ status = STATUS_NOT_SUPPORTED;
+ goto done;
+ }
+
+ Buffer = ExAllocatePoolWithTag(PagedPool, MAXTEXTLEN, 'FIV');
+
+ status = STATUS_NO_MEMORY;
+ if (Buffer == NULL)
+ goto done;
+
+ RtlZeroMemory(Buffer, MAXTEXTLEN);
+
+ Text.Buffer = Buffer;
+ Text.MaximumLength = MAXTEXTLEN;
+ Text.Length = 0;
+
+ switch (StackLocation->Parameters.QueryDeviceText.DeviceTextType) {
+ case DeviceTextDescription:
+ status = RtlStringCbPrintfW(Buffer,
+ MAXTEXTLEN,
+ L"%hs %hs",
+ FdoGetName(__PdoGetFdo(Pdo)),
+ __PdoGetName(Pdo));
+ ASSERT(NT_SUCCESS(status));
+
+ Buffer += wcslen(Buffer);
+
+ break;
+
+ case DeviceTextLocationInformation:
+ status = RtlStringCbPrintfW(Buffer,
+ MAXTEXTLEN,
+ L"%hs",
+ __PdoGetName(Pdo));
+ ASSERT(NT_SUCCESS(status));
+
+ Buffer += wcslen(Buffer);
+
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ Text.Length = (USHORT)((ULONG_PTR)Buffer - (ULONG_PTR)Text.Buffer);
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ Trace("%s: %wZ\n", __PdoGetName(Pdo), &Text);
+
+ Irp->IoStatus.Information = (ULONG_PTR)Text.Buffer;
+ status = STATUS_SUCCESS;
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoReadConfig(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ UNREFERENCED_PARAMETER(Pdo);
+
+ Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_NOT_SUPPORTED;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoWriteConfig(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ UNREFERENCED_PARAMETER(Pdo);
+
+ Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_NOT_SUPPORTED;
+}
+
+#define REGSTR_VAL_MAX_HCID_LEN 1024
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryId(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ PWCHAR Buffer;
+ UNICODE_STRING Id;
+ ULONG Type;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (StackLocation->Parameters.QueryId.IdType) {
+ case BusQueryInstanceID:
+ Trace("BusQueryInstanceID\n");
+ Id.MaximumLength = (USHORT)(strlen(__PdoGetName(Pdo)) + 1) * sizeof (WCHAR);
+ break;
+
+ case BusQueryDeviceID:
+ Trace("BusQueryDeviceID\n");
+ Id.MaximumLength = (MAX_DEVICE_ID_LEN - 2) * sizeof (WCHAR);
+ break;
+
+ case BusQueryHardwareIDs:
+ Trace("BusQueryHardwareIDs\n");
+ Id.MaximumLength = (USHORT)(MAX_DEVICE_ID_LEN * ARRAYSIZE(PdoRevision)) * sizeof (WCHAR);
+ break;
+
+ case BusQueryCompatibleIDs:
+ Trace("BusQueryCompatibleIDs\n");
+ Id.MaximumLength = (USHORT)(MAX_DEVICE_ID_LEN * ARRAYSIZE(PdoRevision)) * sizeof (WCHAR);
+ break;
+
+ default:
+ Irp->IoStatus.Information = 0;
+ status = STATUS_NOT_SUPPORTED;
+ goto done;
+ }
+
+ Buffer = ExAllocatePoolWithTag(PagedPool, Id.MaximumLength, 'FIV');
+
+ status = STATUS_NO_MEMORY;
+ if (Buffer == NULL)
+ goto done;
+
+ RtlZeroMemory(Buffer, Id.MaximumLength);
+
+ Id.Buffer = Buffer;
+ Id.Length = 0;
+
+ switch (StackLocation->Parameters.QueryId.IdType) {
+ case BusQueryInstanceID:
+ Type = REG_SZ;
+
+ status = RtlStringCbPrintfW(Buffer,
+ Id.MaximumLength,
+ L"%hs",
+ __PdoGetName(Pdo));
+ ASSERT(NT_SUCCESS(status));
+
+ Buffer += wcslen(Buffer);
+
+ break;
+
+ case BusQueryDeviceID: {
+ ULONG Index;
+ PXENVKBD_PDO_REVISION Revision;
+
+ Type = REG_SZ;
+ Index = ARRAYSIZE(PdoRevision) - 1;
+ Revision = &PdoRevision[Index];
+
+ status = RtlStringCbPrintfW(Buffer,
+ Id.MaximumLength,
+ L"XENVKBD\\VEN_%hs&DEV_HID&REV_%08X",
+ __PdoGetVendorName(Pdo),
+ Revision->Number);
+ ASSERT(NT_SUCCESS(status));
+
+ Buffer += wcslen(Buffer);
+
+ break;
+ }
+ case BusQueryHardwareIDs:
+ case BusQueryCompatibleIDs: {
+ LONG Index;
+ ULONG Length;
+
+ Type = REG_MULTI_SZ;
+ Index = ARRAYSIZE(PdoRevision) - 1;
+
+ Length = Id.MaximumLength;
+
+ while (Index >= 0) {
+ PXENVKBD_PDO_REVISION Revision = &PdoRevision[Index];
+
+ status = RtlStringCbPrintfW(Buffer,
+ Length,
+ L"XENVKBD\\VEN_%hs&DEV_HID&REV_%08X",
+ __PdoGetVendorName(Pdo),
+ Revision->Number);
+ ASSERT(NT_SUCCESS(status));
+
+ Buffer += wcslen(Buffer);
+ Length -= (ULONG)(wcslen(Buffer) * sizeof (WCHAR));
+
+ Buffer++;
+ Length -= sizeof (WCHAR);
+
+ --Index;
+ }
+
+ status = RtlStringCbPrintfW(Buffer,
+ Length,
+ L"XENDEVICE");
+ ASSERT(NT_SUCCESS(status));
+
+ Buffer += wcslen(Buffer);
+ Buffer++;
+
+ ASSERT3U((ULONG_PTR)Buffer - (ULONG_PTR)Id.Buffer, <,
+ REGSTR_VAL_MAX_HCID_LEN);
+ break;
+ }
+ default:
+ Type = REG_NONE;
+
+ ASSERT(FALSE);
+ break;
+ }
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ Id.Length = (USHORT)((ULONG_PTR)Buffer - (ULONG_PTR)Id.Buffer);
+ Buffer = Id.Buffer;
+
+ switch (Type) {
+ case REG_SZ:
+ Trace("- %ws\n", Buffer);
+ break;
+
+ case REG_MULTI_SZ:
+ do {
+ Trace("- %ws\n", Buffer);
+ Buffer += wcslen(Buffer);
+ Buffer++;
+ } while (*Buffer != L'\0');
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ Irp->IoStatus.Information = (ULONG_PTR)Id.Buffer;
+ status = STATUS_SUCCESS;
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryBusInformation(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PPNP_BUS_INFORMATION Info;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Pdo);
+
+ Info = ExAllocatePoolWithTag(PagedPool, sizeof (PNP_BUS_INFORMATION), 'FIV');
+
+ status = STATUS_NO_MEMORY;
+ if (Info == NULL)
+ goto done;
+
+ RtlZeroMemory(Info, sizeof (PNP_BUS_INFORMATION));
+
+ Info->BusTypeGuid = GUID_BUS_TYPE_INTERNAL;
+ Info->LegacyBusType = PNPBus;
+ Info->BusNumber = 0;
+
+ Irp->IoStatus.Information = (ULONG_PTR)Info;
+ status = STATUS_SUCCESS;
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoDeviceUsageNotification(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = PdoDelegateIrp(Pdo, Irp);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoEject(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PXENVKBD_FDO Fdo = __PdoGetFdo(Pdo);
+ NTSTATUS status;
+
+ Trace("%s\n", __PdoGetName(Pdo));
+
+ FdoAcquireMutex(Fdo);
+
+ __PdoSetDevicePnpState(Pdo, Deleted);
+ __PdoSetMissing(Pdo, "device ejected");
+
+ FdoReleaseMutex(Fdo);
+
+ IoInvalidateDeviceRelations(FdoGetPhysicalDeviceObject(Fdo),
+ BusRelations);
+
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoDispatchPnp(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ Trace("====> (%s) (%02x:%s)\n",
+ __PdoGetName(Pdo),
+ MinorFunction,
+ PnpMinorFunctionName(MinorFunction));
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_START_DEVICE:
+ status = PdoStartDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_STOP_DEVICE:
+ status = PdoQueryStopDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_CANCEL_STOP_DEVICE:
+ status = PdoCancelStopDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_STOP_DEVICE:
+ status = PdoStopDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ status = PdoQueryRemoveDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ status = PdoCancelRemoveDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_SURPRISE_REMOVAL:
+ status = PdoSurpriseRemoval(Pdo, Irp);
+ break;
+
+ case IRP_MN_REMOVE_DEVICE:
+ status = PdoRemoveDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ status = PdoQueryDeviceRelations(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_INTERFACE:
+ status = PdoQueryInterface(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_CAPABILITIES:
+ status = PdoQueryCapabilities(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_DEVICE_TEXT:
+ status = PdoQueryDeviceText(Pdo, Irp);
+ break;
+
+ case IRP_MN_READ_CONFIG:
+ status = PdoReadConfig(Pdo, Irp);
+ break;
+
+ case IRP_MN_WRITE_CONFIG:
+ status = PdoWriteConfig(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_ID:
+ status = PdoQueryId(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_BUS_INFORMATION:
+ status = PdoQueryBusInformation(Pdo, Irp);
+ break;
+
+ case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+ status = PdoDeviceUsageNotification(Pdo, Irp);
+ break;
+
+ case IRP_MN_EJECT:
+ status = PdoEject(Pdo, Irp);
+ break;
+
+ default:
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ break;
+ }
+
+ Trace("<==== (%02x:%s)(%08x)\n",
+ MinorFunction,
+ PnpMinorFunctionName(MinorFunction),
+ status);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoSetDevicePower(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s) (%s:%s)\n",
+ __PdoGetName(Pdo),
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ ASSERT3U(PowerAction, <, PowerActionShutdown);
+
+ if (__PdoGetDevicePowerState(Pdo) > DeviceState) {
+ Trace("%s: POWERING UP: %s -> %s\n",
+ __PdoGetName(Pdo),
+ PowerDeviceStateName(__PdoGetDevicePowerState(Pdo)),
+ PowerDeviceStateName(DeviceState));
+
+ ASSERT3U(DeviceState, ==, PowerDeviceD0);
+ status = PdoD3ToD0(Pdo);
+ ASSERT(NT_SUCCESS(status));
+ } else if (__PdoGetDevicePowerState(Pdo) < DeviceState) {
+ Trace("%s: POWERING DOWN: %s -> %s\n",
+ __PdoGetName(Pdo),
+ PowerDeviceStateName(__PdoGetDevicePowerState(Pdo)),
+ PowerDeviceStateName(DeviceState));
+
+ ASSERT3U(DeviceState, ==, PowerDeviceD3);
+ PdoD0ToD3(Pdo);
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ Trace("<==== (%s:%s)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+PdoDevicePower(
+ IN PXENVKBD_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENVKBD_PDO Pdo = Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+
+ if (Pdo->DevicePowerIrp == NULL) {
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Pdo->DevicePowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Pdo->DevicePowerIrp = NULL;
+ KeMemoryBarrier();
+
+ (VOID) __PdoSetDevicePower(Pdo, Irp);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoSetSystemPower(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ POWER_ACTION PowerAction;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s) (%s:%s)\n",
+ __PdoGetName(Pdo),
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction));
+
+ ASSERT3U(PowerAction, <, PowerActionShutdown);
+
+ if (__PdoGetSystemPowerState(Pdo) > SystemState) {
+ if (SystemState < PowerSystemHibernate &&
+ __PdoGetSystemPowerState(Pdo) >= PowerSystemHibernate) {
+ __PdoSetSystemPowerState(Pdo, PowerSystemHibernate);
+ PdoS4ToS3(Pdo);
+ }
+
+ Trace("%s: POWERING UP: %s -> %s\n",
+ __PdoGetName(Pdo),
+ PowerSystemStateName(__PdoGetSystemPowerState(Pdo)),
+ PowerSystemStateName(SystemState));
+ } else if (__PdoGetSystemPowerState(Pdo) < SystemState) {
+ Trace("%s: POWERING DOWN: %s -> %s\n",
+ __PdoGetName(Pdo),
+ PowerSystemStateName(__PdoGetSystemPowerState(Pdo)),
+ PowerSystemStateName(SystemState));
+
+ if (SystemState >= PowerSystemHibernate &&
+ __PdoGetSystemPowerState(Pdo) < PowerSystemHibernate) {
+ __PdoSetSystemPowerState(Pdo, PowerSystemSleeping3);
+ PdoS3ToS4(Pdo);
+ }
+ }
+
+ __PdoSetSystemPowerState(Pdo, SystemState);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ Trace("<==== (%s:%s)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction));
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+PdoSystemPower(
+ IN PXENVKBD_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENVKBD_PDO Pdo = Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+
+ if (Pdo->SystemPowerIrp == NULL) {
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Pdo->SystemPowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Pdo->SystemPowerIrp = NULL;
+ KeMemoryBarrier();
+
+ (VOID) __PdoSetSystemPower(Pdo, Irp);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoSetPower(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ POWER_STATE_TYPE PowerType;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ PowerType = StackLocation->Parameters.Power.Type;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ if (PowerAction >= PowerActionShutdown) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ switch (PowerType) {
+ case DevicePowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Pdo->DevicePowerIrp, ==, NULL);
+ Pdo->DevicePowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Pdo->DevicePowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ case SystemPowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Pdo->SystemPowerIrp, ==, NULL);
+ Pdo->SystemPowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Pdo->SystemPowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ default:
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ break;
+ }
+
+done:
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryPower(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Pdo);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoDispatchPower(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ status = PdoSetPower(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ status = PdoQueryPower(Pdo, Irp);
+ break;
+
+ default:
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ break;
+ }
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoDispatchDefault(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Pdo);
+
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+NTSTATUS
+PdoDispatch(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (StackLocation->MajorFunction) {
+ case IRP_MJ_PNP:
+ status = PdoDispatchPnp(Pdo, Irp);
+ break;
+
+ case IRP_MJ_POWER:
+ status = PdoDispatchPower(Pdo, Irp);
+ break;
+
+ default:
+ status = PdoDispatchDefault(Pdo, Irp);
+ break;
+ }
+
+ return status;
+}
+
+NTSTATUS
+PdoResume(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ return FrontendResume(__PdoGetFrontend(Pdo));
+}
+
+VOID
+PdoSuspend(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ FrontendSuspend(__PdoGetFrontend(Pdo));
+}
+
+NTSTATUS
+PdoCreate(
+ IN PXENVKBD_FDO Fdo,
+ IN PANSI_STRING Path
+ )
+{
+ PDEVICE_OBJECT PhysicalDeviceObject;
+ PXENVKBD_DX Dx;
+ PXENVKBD_PDO Pdo;
+ NTSTATUS status;
+
+#pragma prefast(suppress:28197) // Possibly leaking memory 'PhysicalDeviceObject'
+ status = IoCreateDevice(DriverGetDriverObject(),
+ sizeof(XENVKBD_DX),
+ NULL,
+ FILE_DEVICE_UNKNOWN,
+ FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,
+ FALSE,
+ &PhysicalDeviceObject);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Dx = (PXENVKBD_DX)PhysicalDeviceObject->DeviceExtension;
+ RtlZeroMemory(Dx, sizeof (XENVKBD_DX));
+
+ Dx->Type = PHYSICAL_DEVICE_OBJECT;
+ Dx->DeviceObject = PhysicalDeviceObject;
+ Dx->DevicePnpState = Present;
+ Dx->SystemPowerState = PowerSystemWorking;
+ Dx->DevicePowerState = PowerDeviceD3;
+
+ Pdo = __PdoAllocate(sizeof (XENVKBD_PDO));
+
+ status = STATUS_NO_MEMORY;
+ if (Pdo == NULL)
+ goto fail2;
+
+ Pdo->Dx = Dx;
+ Pdo->Fdo = Fdo;
+
+ status = ThreadCreate(PdoSystemPower, Pdo, &Pdo->SystemPowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = ThreadCreate(PdoDevicePower, Pdo, &Pdo->DevicePowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ __PdoSetName(Pdo, Path->Buffer);
+
+ status = BusInitialize(Pdo, &Pdo->BusInterface);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ status = HidInitialize(Pdo, &Pdo->HidContext);
+ if (!NT_SUCCESS(status))
+ goto fail6;
+
+ status = FrontendInitialize(Pdo, &Pdo->Frontend);
+ if (!NT_SUCCESS(status))
+ goto fail7;
+
+ FdoGetSuspendInterface(Fdo, &Pdo->SuspendInterface);
+ FdoGetUnplugInterface(Fdo, &Pdo->UnplugInterface);
+
+ Dx->Pdo = Pdo;
+
+ status = FdoAddPhysicalDeviceObject(Fdo, Pdo);
+ if (!NT_SUCCESS(status))
+ goto fail8;
+
+ status = STATUS_UNSUCCESSFUL;
+ if (__PdoIsEjectRequested(Pdo))
+ goto fail9;
+
+ Info("%p (%s)\n",
+ PhysicalDeviceObject,
+ __PdoGetName(Pdo));
+
+ PdoDumpRevisions(Pdo);
+
+ PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+ return STATUS_SUCCESS;
+
+fail9:
+ Error("fail9\n");
+
+ FdoRemovePhysicalDeviceObject(Fdo, Pdo);
+
+fail8:
+ Error("fail8\n");
+
+ (VOID) __PdoClearEjectRequested(Pdo);
+
+ Dx->Pdo = NULL;
+
+ RtlZeroMemory(&Pdo->UnplugInterface,
+ sizeof (XENBUS_UNPLUG_INTERFACE));
+
+ RtlZeroMemory(&Pdo->SuspendInterface,
+ sizeof (XENBUS_SUSPEND_INTERFACE));
+
+ FrontendTeardown(__PdoGetFrontend(Pdo));
+ Pdo->Frontend = NULL;
+
+fail7:
+ Error("fail7\n");
+
+ HidTeardown(Pdo->HidContext);
+ Pdo->HidContext = NULL;
+
+fail6:
+ Error("fail6\n");
+
+ BusTeardown(&Pdo->BusInterface);
+
+fail5:
+ Error("fail5\n");
+
+ ThreadAlert(Pdo->DevicePowerThread);
+ ThreadJoin(Pdo->DevicePowerThread);
+ Pdo->DevicePowerThread = NULL;
+
+fail4:
+ Error("fail4\n");
+
+ ThreadAlert(Pdo->SystemPowerThread);
+ ThreadJoin(Pdo->SystemPowerThread);
+ Pdo->SystemPowerThread = NULL;
+
+fail3:
+ Error("fail3\n");
+
+ Pdo->Fdo = NULL;
+ Pdo->Dx = NULL;
+
+ ASSERT(IsZeroMemory(Pdo, sizeof (XENVKBD_PDO)));
+ __PdoFree(Pdo);
+
+fail2:
+ Error("fail2\n");
+
+ IoDeleteDevice(PhysicalDeviceObject);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+PdoDestroy(
+ IN PXENVKBD_PDO Pdo
+ )
+{
+ PXENVKBD_DX Dx = Pdo->Dx;
+ PDEVICE_OBJECT PhysicalDeviceObject = Dx->DeviceObject;
+ PXENVKBD_FDO Fdo = __PdoGetFdo(Pdo);
+
+ Pdo->UnplugRequested = FALSE;
+
+ ASSERT3U(__PdoGetDevicePnpState(Pdo), ==, Deleted);
+
+ ASSERT(__PdoIsMissing(Pdo));
+ Pdo->Missing = FALSE;
+
+ Info("%p (%s) (%s)\n",
+ PhysicalDeviceObject,
+ __PdoGetName(Pdo),
+ Pdo->Reason);
+
+ Pdo->Reason = NULL;
+
+ FdoRemovePhysicalDeviceObject(Fdo, Pdo);
+
+ (VOID) __PdoClearEjectRequested(Pdo);
+
+ Dx->Pdo = NULL;
+
+ RtlZeroMemory(&Pdo->UnplugInterface,
+ sizeof (XENBUS_UNPLUG_INTERFACE));
+
+ RtlZeroMemory(&Pdo->SuspendInterface,
+ sizeof (XENBUS_SUSPEND_INTERFACE));
+
+ FrontendTeardown(__PdoGetFrontend(Pdo));
+ Pdo->Frontend = NULL;
+
+ HidTeardown(Pdo->HidContext);
+ Pdo->HidContext = NULL;
+
+ BusTeardown(&Pdo->BusInterface);
+
+ ThreadAlert(Pdo->DevicePowerThread);
+ ThreadJoin(Pdo->DevicePowerThread);
+ Pdo->DevicePowerThread = NULL;
+
+ ThreadAlert(Pdo->SystemPowerThread);
+ ThreadJoin(Pdo->SystemPowerThread);
+ Pdo->SystemPowerThread = NULL;
+
+ Pdo->Fdo = NULL;
+ Pdo->Dx = NULL;
+
+ ASSERT(IsZeroMemory(Pdo, sizeof (XENVKBD_PDO)));
+ __PdoFree(Pdo);
+
+ IoDeleteDevice(PhysicalDeviceObject);
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_PDO_H
+#define _XENVKBD_PDO_H
+
+#include <ntddk.h>
+#include <ifdef.h>
+
+#include "driver.h"
+#include "types.h"
+
+extern VOID
+PdoSetDevicePnpState(
+ IN PXENVKBD_PDO Pdo,
+ IN DEVICE_PNP_STATE State
+ );
+
+extern DEVICE_PNP_STATE
+PdoGetDevicePnpState(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern VOID
+PdoSetMissing(
+ IN PXENVKBD_PDO Pdo,
+ IN const CHAR *Reason
+ );
+
+extern BOOLEAN
+PdoIsMissing(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern VOID
+PdoRequestEject(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern BOOLEAN
+PdoIsEjectRequested(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PCHAR
+PdoGetName(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PXENVKBD_FDO
+PdoGetFdo(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PDEVICE_OBJECT
+PdoGetDeviceObject(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PDMA_ADAPTER
+PdoGetDmaAdapter(
+ IN PXENVKBD_PDO Pdo,
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ );
+
+extern BOOLEAN
+PdoTranslateBusAddress(
+ IN PXENVKBD_PDO Pdo,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN ULONG Length,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+extern ULONG
+PdoSetBusData(
+ IN PXENVKBD_PDO Pdo,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+extern ULONG
+PdoGetBusData(
+ IN PXENVKBD_PDO Pdo,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+extern NTSTATUS
+PdoCreate(
+ IN PXENVKBD_FDO Fdo,
+ IN PANSI_STRING Path
+ );
+
+extern NTSTATUS
+PdoResume(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern VOID
+PdoSuspend(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern VOID
+PdoDestroy(
+ IN PXENVKBD_PDO Pdo
+ );
+
+#include "frontend.h"
+
+extern PXENVKBD_FRONTEND
+PdoGetFrontend(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PXENBUS_EVTCHN_INTERFACE
+PdoGetEvtchnInterface(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PXENBUS_DEBUG_INTERFACE
+PdoGetDebugInterface(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PXENBUS_STORE_INTERFACE
+PdoGetStoreInterface(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PXENBUS_CACHE_INTERFACE
+PdoGetCacheInterface(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PXENBUS_GNTTAB_INTERFACE
+PdoGetGnttabInterface(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PXENBUS_SUSPEND_INTERFACE
+PdoGetSuspendInterface(
+ IN PXENVKBD_PDO Pdo
+ );
+
+#include "hid.h"
+
+extern PXENVKBD_HID_CONTEXT
+PdoGetHidContext(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern PXENHID_HID_INTERFACE
+PdoGetHidInterface(
+ IN PXENVKBD_PDO Pdo
+ );
+
+extern NTSTATUS
+PdoDispatch(
+ IN PXENVKBD_PDO Pdo,
+ IN PIRP Irp
+ );
+
+#endif // _XENVKBD_PDO_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#include <ntddk.h>
+
+#include "registry.h"
+#include "assert.h"
+#include "util.h"
+
+#define REGISTRY_TAG 'GERX'
+
+static UNICODE_STRING RegistryPath;
+
+static FORCEINLINE PVOID
+__RegistryAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, REGISTRY_TAG);
+}
+
+static FORCEINLINE VOID
+__RegistryFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, REGISTRY_TAG);
+}
+
+NTSTATUS
+RegistryInitialize(
+ IN PUNICODE_STRING Path
+ )
+{
+ NTSTATUS status;
+
+ ASSERT3P(RegistryPath.Buffer, ==, NULL);
+
+ status = RtlUpcaseUnicodeString(&RegistryPath, Path, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+RegistryTeardown(
+ VOID
+ )
+{
+ RtlFreeUnicodeString(&RegistryPath);
+ RegistryPath.Buffer = NULL;
+ RegistryPath.MaximumLength = RegistryPath.Length = 0;
+}
+
+NTSTATUS
+RegistryOpenKey(
+ IN HANDLE Parent,
+ IN PUNICODE_STRING Path,
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE Key
+ )
+{
+ OBJECT_ATTRIBUTES Attributes;
+ NTSTATUS status;
+
+ InitializeObjectAttributes(&Attributes,
+ Path,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ Parent,
+ NULL);
+
+ status = ZwOpenKey(Key,
+ DesiredAccess,
+ &Attributes);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ return STATUS_SUCCESS;
+
+fail1:
+ return status;
+}
+
+static NTSTATUS
+RegistryOpenRoot(
+ IN PWCHAR Path,
+ OUT PHANDLE Parent,
+ OUT PWCHAR *ChildPath
+ )
+{
+ const WCHAR Prefix[] = L"\\Registry\\Machine\\";
+ ULONG Length;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ Length = (ULONG)wcslen(Prefix);
+
+ status = STATUS_INVALID_PARAMETER;
+ if (_wcsnicmp(Path, Prefix, Length) != 0)
+ goto fail1;
+
+ RtlInitUnicodeString(&Unicode, Prefix);
+
+ status = RegistryOpenKey(NULL, &Unicode, KEY_ALL_ACCESS, Parent);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ *ChildPath = Path + Length;
+
+ return STATUS_SUCCESS;
+
+fail2:
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryCreateKey(
+ IN HANDLE Parent,
+ IN PUNICODE_STRING Path,
+ IN ULONG Options,
+ OUT PHANDLE Key
+ )
+{
+ PWCHAR Buffer;
+ HANDLE Root;
+ PWCHAR ChildPath;
+ PWCHAR ChildName;
+ PWCHAR Context;
+ HANDLE Child;
+ NTSTATUS status;
+
+ //
+ // UNICODE_STRINGs are not guaranteed to have NUL terminated
+ // buffers.
+ //
+
+ Buffer = __RegistryAllocate(Path->MaximumLength + sizeof (WCHAR));
+
+ status = STATUS_NO_MEMORY;
+ if (Buffer == NULL)
+ goto fail1;
+
+ RtlCopyMemory(Buffer, Path->Buffer, Path->Length);
+
+ Root = Parent;
+
+ if (Parent != NULL) {
+ ChildPath = Buffer;
+ } else {
+ status = RegistryOpenRoot(Buffer, &Parent, &ChildPath);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+ }
+
+ ChildName = __wcstok_r(ChildPath, L"\\", &Context);
+
+ status = STATUS_INVALID_PARAMETER;
+ if (ChildName == NULL)
+ goto fail3;
+
+ Child = NULL;
+
+ while (ChildName != NULL) {
+ UNICODE_STRING Unicode;
+ OBJECT_ATTRIBUTES Attributes;
+
+ RtlInitUnicodeString(&Unicode, ChildName);
+
+ InitializeObjectAttributes(&Attributes,
+ &Unicode,
+ OBJ_CASE_INSENSITIVE |
+ OBJ_KERNEL_HANDLE |
+ OBJ_OPENIF,
+ Parent,
+ NULL);
+
+ status = ZwCreateKey(&Child,
+ KEY_ALL_ACCESS,
+ &Attributes,
+ 0,
+ NULL,
+ Options,
+ NULL
+ );
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ ChildName = __wcstok_r(NULL, L"\\", &Context);
+
+ if (Parent != Root)
+ ZwClose(Parent);
+
+ Parent = Child;
+ }
+
+ ASSERT(Child != NULL);
+
+ *Key = Child;
+
+ __RegistryFree(Buffer);
+
+ return STATUS_SUCCESS;
+
+fail4:
+fail3:
+ if (Parent != Root)
+ ZwClose(Parent);
+
+fail2:
+ __RegistryFree(Buffer);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryOpenServiceKey(
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE Key
+ )
+{
+ return RegistryOpenKey(NULL, &RegistryPath, DesiredAccess, Key);
+}
+
+NTSTATUS
+RegistryCreateServiceKey(
+ OUT PHANDLE Key
+ )
+{
+ return RegistryCreateKey(NULL, &RegistryPath, REG_OPTION_NON_VOLATILE, Key);
+}
+
+NTSTATUS
+RegistryOpenSoftwareKey(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE Key
+ )
+{
+ NTSTATUS status;
+
+ status = IoOpenDeviceRegistryKey(DeviceObject,
+ PLUGPLAY_REGKEY_DRIVER,
+ DesiredAccess,
+ Key);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ return STATUS_SUCCESS;
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryOpenHardwareKey(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE Key
+ )
+{
+ HANDLE SubKey;
+ ULONG Length;
+ PKEY_NAME_INFORMATION Info;
+ PWCHAR Cursor;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ status = IoOpenDeviceRegistryKey(DeviceObject,
+ PLUGPLAY_REGKEY_DEVICE,
+ KEY_READ,
+ &SubKey);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Length = 0;
+ status = ZwQueryKey(SubKey,
+ KeyNameInformation,
+ NULL,
+ 0,
+ &Length);
+ if (status != STATUS_BUFFER_OVERFLOW &&
+ status != STATUS_BUFFER_TOO_SMALL)
+ goto fail2;
+
+#pragma prefast(suppress:6102)
+ Info = __RegistryAllocate(Length + sizeof (WCHAR));
+
+ status = STATUS_NO_MEMORY;
+ if (Info == NULL)
+ goto fail3;
+
+ status = ZwQueryKey(SubKey,
+ KeyNameInformation,
+ Info,
+ Length,
+ &Length);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ Info->Name[Info->NameLength / sizeof (WCHAR)] = '\0';
+
+ Cursor = wcsrchr(Info->Name, L'\\');
+ ASSERT(Cursor != NULL);
+
+ *Cursor = L'\0';
+
+ RtlInitUnicodeString(&Unicode, Info->Name);
+
+ status = RegistryOpenKey(NULL, &Unicode, DesiredAccess, Key);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ __RegistryFree(Info);
+
+ RegistryCloseKey(SubKey);
+
+ return STATUS_SUCCESS;
+
+fail5:
+fail4:
+ __RegistryFree(Info);
+
+fail3:
+fail2:
+ RegistryCloseKey(SubKey);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryOpenSubKey(
+ IN PHANDLE Key,
+ IN PCHAR Name,
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE SubKey
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = RegistryOpenKey(Key, &Unicode, DesiredAccess, SubKey);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryCreateSubKey(
+ IN PHANDLE Key,
+ IN PCHAR Name,
+ IN ULONG Options,
+ OUT PHANDLE SubKey
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = RegistryCreateKey(Key, &Unicode, Options, SubKey);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryDeleteSubKey(
+ IN PHANDLE Key,
+ IN PCHAR Name
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ HANDLE SubKey;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = RegistryOpenKey(Key, &Unicode, KEY_ALL_ACCESS, &SubKey);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = ZwDeleteKey(SubKey);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ ZwClose(SubKey);
+
+ (VOID) ZwFlushKey(Key);
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ ZwClose(SubKey);
+
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryEnumerateSubKeys(
+ IN HANDLE Key,
+ IN NTSTATUS (*Callback)(PVOID, HANDLE, PANSI_STRING),
+ IN PVOID Context
+ )
+{
+ ULONG Size;
+ NTSTATUS status;
+ PKEY_FULL_INFORMATION Full;
+ PKEY_BASIC_INFORMATION Basic;
+ ULONG Index;
+
+ status = ZwQueryKey(Key,
+ KeyFullInformation,
+ NULL,
+ 0,
+ &Size);
+ if (status != STATUS_BUFFER_OVERFLOW &&
+ status != STATUS_BUFFER_TOO_SMALL)
+ goto fail1;
+
+#pragma prefast(suppress:6102)
+ Full = __RegistryAllocate(Size);
+
+ status = STATUS_NO_MEMORY;
+ if (Full == NULL)
+ goto fail2;
+
+ status = ZwQueryKey(Key,
+ KeyFullInformation,
+ Full,
+ Size,
+ &Size);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ Size = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) +
+ Full->MaxNameLen;
+
+ Basic = __RegistryAllocate(Size);
+ status = STATUS_NO_MEMORY;
+ if (Basic == NULL)
+ goto fail4;
+
+ for (Index = 0; Index < Full->SubKeys; Index++) {
+ ULONG Ignore;
+ UNICODE_STRING Unicode;
+ ANSI_STRING Ansi;
+
+ status = ZwEnumerateKey(Key,
+ Index,
+ KeyBasicInformation,
+ Basic,
+ Size,
+ &Ignore);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ Unicode.MaximumLength = (USHORT)Basic->NameLength;
+ Unicode.Buffer = Basic->Name;
+ Unicode.Length = (USHORT)Basic->NameLength;
+
+ Ansi.MaximumLength = (USHORT)((Basic->NameLength / sizeof (WCHAR)) + sizeof (CHAR));
+ Ansi.Buffer = __RegistryAllocate(Ansi.MaximumLength);
+
+ status = STATUS_NO_MEMORY;
+ if (Ansi.Buffer == NULL)
+ goto fail6;
+
+ status = RtlUnicodeStringToAnsiString(&Ansi, &Unicode, FALSE);
+ ASSERT(NT_SUCCESS(status));
+
+ Ansi.Length = (USHORT)(strlen(Ansi.Buffer) * sizeof (CHAR));
+
+ status = Callback(Context, Key, &Ansi);
+
+ __RegistryFree(Ansi.Buffer);
+ Ansi.Buffer = NULL;
+
+ if (!NT_SUCCESS(status))
+ goto fail7;
+ }
+
+ __RegistryFree(Basic);
+
+ __RegistryFree(Full);
+
+ return STATUS_SUCCESS;
+
+fail7:
+fail6:
+fail5:
+ __RegistryFree(Basic);
+
+fail4:
+fail3:
+ __RegistryFree(Full);
+
+fail2:
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryEnumerateValues(
+ IN HANDLE Key,
+ IN NTSTATUS (*Callback)(PVOID, HANDLE, PANSI_STRING, ULONG),
+ IN PVOID Context
+ )
+{
+ ULONG Size;
+ NTSTATUS status;
+ PKEY_FULL_INFORMATION Full;
+ PKEY_VALUE_BASIC_INFORMATION Basic;
+ ULONG Index;
+
+ status = ZwQueryKey(Key,
+ KeyFullInformation,
+ NULL,
+ 0,
+ &Size);
+ if (status != STATUS_BUFFER_OVERFLOW &&
+ status != STATUS_BUFFER_TOO_SMALL)
+ goto fail1;
+
+#pragma prefast(suppress:6102)
+ Full = __RegistryAllocate(Size);
+
+ status = STATUS_NO_MEMORY;
+ if (Full == NULL)
+ goto fail2;
+
+ status = ZwQueryKey(Key,
+ KeyFullInformation,
+ Full,
+ Size,
+ &Size);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
+ Full->MaxValueNameLen;
+
+ Basic = __RegistryAllocate(Size);
+ status = STATUS_NO_MEMORY;
+ if (Basic == NULL)
+ goto fail4;
+
+ for (Index = 0; Index < Full->Values; Index++) {
+ ULONG Ignore;
+ UNICODE_STRING Unicode;
+ ANSI_STRING Ansi;
+
+ status = ZwEnumerateValueKey(Key,
+ Index,
+ KeyValueBasicInformation,
+ Basic,
+ Size,
+ &Ignore);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ Unicode.MaximumLength = (USHORT)Basic->NameLength;
+ Unicode.Buffer = Basic->Name;
+ Unicode.Length = (USHORT)Basic->NameLength;
+
+ Ansi.MaximumLength = (USHORT)((Basic->NameLength / sizeof (WCHAR)) + sizeof (CHAR));
+ Ansi.Buffer = __RegistryAllocate(Ansi.MaximumLength);
+
+ status = RtlUnicodeStringToAnsiString(&Ansi, &Unicode, FALSE);
+ ASSERT(NT_SUCCESS(status));
+
+ Ansi.Length = (USHORT)(strlen(Ansi.Buffer) * sizeof (CHAR));
+
+ status = Callback(Context, Key, &Ansi, Basic->Type);
+
+ __RegistryFree(Ansi.Buffer);
+
+ if (!NT_SUCCESS(status))
+ goto fail6;
+ }
+
+ __RegistryFree(Basic);
+
+ __RegistryFree(Full);
+
+ return STATUS_SUCCESS;
+
+fail6:
+fail5:
+ __RegistryFree(Basic);
+
+fail4:
+fail3:
+ __RegistryFree(Full);
+
+fail2:
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryDeleteValue(
+ IN PHANDLE Key,
+ IN PCHAR Name
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = ZwDeleteValueKey(Key, &Unicode);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ RtlFreeUnicodeString(&Unicode);
+
+ (VOID) ZwFlushKey(Key);
+
+ return STATUS_SUCCESS;
+
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryQueryDwordValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ OUT PULONG Value
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ PKEY_VALUE_PARTIAL_INFORMATION Partial;
+ ULONG Size;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = ZwQueryValueKey(Key,
+ &Unicode,
+ KeyValuePartialInformation,
+ NULL,
+ 0,
+ &Size);
+ if (status != STATUS_BUFFER_OVERFLOW &&
+ status != STATUS_BUFFER_TOO_SMALL)
+ goto fail2;
+
+#pragma prefast(suppress:6102)
+ Partial = __RegistryAllocate(Size);
+
+ status = STATUS_NO_MEMORY;
+ if (Partial == NULL)
+ goto fail3;
+
+ status = ZwQueryValueKey(Key,
+ &Unicode,
+ KeyValuePartialInformation,
+ Partial,
+ Size,
+ &Size);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = STATUS_INVALID_PARAMETER;
+ if (Partial->Type != REG_DWORD ||
+ Partial->DataLength != sizeof (ULONG))
+ goto fail5;
+
+ *Value = *(PULONG)Partial->Data;
+
+ __RegistryFree(Partial);
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail5:
+fail4:
+ __RegistryFree(Partial);
+
+fail3:
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryUpdateDwordValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ IN ULONG Value
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ PKEY_VALUE_PARTIAL_INFORMATION Partial;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Partial = __RegistryAllocate(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
+ sizeof (ULONG));
+
+ status = STATUS_NO_MEMORY;
+ if (Partial == NULL)
+ goto fail2;
+
+ Partial->TitleIndex = 0;
+ Partial->Type = REG_DWORD;
+ Partial->DataLength = sizeof (ULONG);
+ *(PULONG)Partial->Data = Value;
+
+ status = ZwSetValueKey(Key,
+ &Unicode,
+ Partial->TitleIndex,
+ Partial->Type,
+ Partial->Data,
+ Partial->DataLength);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ __RegistryFree(Partial);
+
+ (VOID) ZwFlushKey(Key);
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ __RegistryFree(Partial);
+
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+
+ return status;
+}
+
+static PANSI_STRING
+RegistrySzToAnsi(
+ IN PWCHAR Buffer
+ )
+{
+ PANSI_STRING Ansi;
+ ULONG Length;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ Ansi = __RegistryAllocate(sizeof (ANSI_STRING) * 2);
+
+ status = STATUS_NO_MEMORY;
+ if (Ansi == NULL)
+ goto fail1;
+
+ Length = (ULONG)wcslen(Buffer);
+ Ansi[0].MaximumLength = (USHORT)(Length + 1) * sizeof (CHAR);
+ Ansi[0].Buffer = __RegistryAllocate(Ansi[0].MaximumLength);
+
+ status = STATUS_NO_MEMORY;
+ if (Ansi[0].Buffer == NULL)
+ goto fail2;
+
+ RtlInitUnicodeString(&Unicode, Buffer);
+ status = RtlUnicodeStringToAnsiString(&Ansi[0], &Unicode, FALSE);
+ ASSERT(NT_SUCCESS(status));
+
+ Ansi[0].Length = (USHORT)Length * sizeof (CHAR);
+
+ return Ansi;
+
+fail2:
+ __RegistryFree(Ansi);
+
+fail1:
+ return NULL;
+}
+
+static PANSI_STRING
+RegistryMultiSzToAnsi(
+ IN PWCHAR Buffer
+ )
+{
+ PANSI_STRING Ansi;
+ LONG Index;
+ LONG Count;
+ NTSTATUS status;
+
+ Index = 0;
+ Count = 0;
+ for (;;) {
+ ULONG Length;
+
+ Length = (ULONG)wcslen(&Buffer[Index]);
+ if (Length == 0)
+ break;
+
+ Index += Length + 1;
+ Count++;
+ }
+
+ Ansi = __RegistryAllocate(sizeof (ANSI_STRING) * (Count + 1));
+
+ status = STATUS_NO_MEMORY;
+ if (Ansi == NULL)
+ goto fail1;
+
+ for (Index = 0; Index < Count; Index++) {
+ ULONG Length;
+ UNICODE_STRING Unicode;
+
+ Length = (ULONG)wcslen(Buffer);
+ Ansi[Index].MaximumLength = (USHORT)(Length + 1) * sizeof (CHAR);
+ Ansi[Index].Buffer = __RegistryAllocate(Ansi[Index].MaximumLength);
+
+ status = STATUS_NO_MEMORY;
+ if (Ansi[Index].Buffer == NULL)
+ goto fail2;
+
+ RtlInitUnicodeString(&Unicode, Buffer);
+
+ status = RtlUnicodeStringToAnsiString(&Ansi[Index], &Unicode, FALSE);
+ ASSERT(NT_SUCCESS(status));
+
+ Ansi[Index].Length = (USHORT)Length * sizeof (CHAR);
+ Buffer += Length + 1;
+ }
+
+ return Ansi;
+
+fail2:
+ while (--Index >= 0)
+ __RegistryFree(Ansi[Index].Buffer);
+
+ __RegistryFree(Ansi);
+
+fail1:
+ return NULL;
+}
+
+NTSTATUS
+RegistryQuerySzValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ OUT PULONG Type OPTIONAL,
+ OUT PANSI_STRING *Array
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ PKEY_VALUE_PARTIAL_INFORMATION Value;
+ ULONG Size;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = ZwQueryValueKey(Key,
+ &Unicode,
+ KeyValuePartialInformation,
+ NULL,
+ 0,
+ &Size);
+ if (status != STATUS_BUFFER_OVERFLOW &&
+ status != STATUS_BUFFER_TOO_SMALL)
+ goto fail2;
+
+#pragma prefast(suppress:6102)
+ Value = __RegistryAllocate(Size);
+
+ status = STATUS_NO_MEMORY;
+ if (Value == NULL)
+ goto fail3;
+
+ status = ZwQueryValueKey(Key,
+ &Unicode,
+ KeyValuePartialInformation,
+ Value,
+ Size,
+ &Size);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ switch (Value->Type) {
+ case REG_SZ:
+ status = STATUS_NO_MEMORY;
+ *Array = RegistrySzToAnsi((PWCHAR)Value->Data);
+ break;
+
+ case REG_MULTI_SZ:
+ status = STATUS_NO_MEMORY;
+ *Array = RegistryMultiSzToAnsi((PWCHAR)Value->Data);
+ break;
+
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ *Array = NULL;
+ break;
+ }
+
+ if (*Array == NULL)
+ goto fail5;
+
+ if (Type != NULL)
+ *Type = Value->Type;
+
+ __RegistryFree(Value);
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail5:
+fail4:
+ __RegistryFree(Value);
+
+fail3:
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryQueryBinaryValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ OUT PVOID *Buffer,
+ OUT PULONG Length
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ PKEY_VALUE_PARTIAL_INFORMATION Partial;
+ ULONG Size;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = ZwQueryValueKey(Key,
+ &Unicode,
+ KeyValuePartialInformation,
+ NULL,
+ 0,
+ &Size);
+ if (status != STATUS_BUFFER_OVERFLOW &&
+ status != STATUS_BUFFER_TOO_SMALL)
+ goto fail2;
+
+#pragma prefast(suppress:6102)
+ Partial = __RegistryAllocate(Size);
+
+ status = STATUS_NO_MEMORY;
+ if (Partial == NULL)
+ goto fail3;
+
+ status = ZwQueryValueKey(Key,
+ &Unicode,
+ KeyValuePartialInformation,
+ Partial,
+ Size,
+ &Size);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ switch (Partial->Type) {
+ case REG_BINARY:
+ *Buffer = __RegistryAllocate(Partial->DataLength);
+
+ status = STATUS_NO_MEMORY;
+ if (*Buffer == NULL)
+ break;
+
+ *Length = Partial->DataLength;
+ RtlCopyMemory(*Buffer, Partial->Data, Partial->DataLength);
+ break;
+
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ *Buffer = NULL;
+ break;
+ }
+
+ if (*Buffer == NULL)
+ goto fail5;
+
+ __RegistryFree(Partial);
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail5:
+fail4:
+ __RegistryFree(Partial);
+
+fail3:
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryUpdateBinaryValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ PKEY_VALUE_PARTIAL_INFORMATION Partial;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Partial = __RegistryAllocate(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
+ Length);
+
+ status = STATUS_NO_MEMORY;
+ if (Partial == NULL)
+ goto fail2;
+
+ Partial->TitleIndex = 0;
+ Partial->Type = REG_BINARY;
+ Partial->DataLength = Length;
+ RtlCopyMemory(Partial->Data, Buffer, Partial->DataLength);
+
+ status = ZwSetValueKey(Key,
+ &Unicode,
+ Partial->TitleIndex,
+ Partial->Type,
+ Partial->Data,
+ Partial->DataLength);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ __RegistryFree(Partial);
+
+ (VOID) ZwFlushKey(Key);
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ __RegistryFree(Partial);
+
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+
+ return status;
+}
+
+NTSTATUS
+RegistryQueryKeyName(
+ IN HANDLE Key,
+ OUT PANSI_STRING *Array
+ )
+{
+ PKEY_NAME_INFORMATION Value;
+ ULONG Size;
+ NTSTATUS status;
+
+ status = ZwQueryKey(Key,
+ KeyNameInformation,
+ NULL,
+ 0,
+ &Size);
+ if (status != STATUS_BUFFER_OVERFLOW &&
+ status != STATUS_BUFFER_TOO_SMALL)
+ goto fail1;
+
+ // Name information is not intrinsically NULL terminated
+#pragma prefast(suppress:6102)
+ Value = __RegistryAllocate(Size + sizeof (WCHAR));
+
+ status = STATUS_NO_MEMORY;
+ if (Value == NULL)
+ goto fail2;
+
+ status = ZwQueryKey(Key,
+ KeyNameInformation,
+ Value,
+ Size,
+ &Size);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ Value->Name[Value->NameLength / sizeof (WCHAR)] = L'\0';
+ *Array = RegistrySzToAnsi((PWCHAR)Value->Name);
+
+ status = STATUS_NO_MEMORY;
+ if (*Array == NULL)
+ goto fail4;
+
+ __RegistryFree(Value);
+
+ return STATUS_SUCCESS;
+
+fail4:
+fail3:
+ __RegistryFree(Value);
+
+fail2:
+fail1:
+ return status;
+}
+
+NTSTATUS
+RegistryQuerySystemStartOption(
+ IN PCHAR Prefix,
+ OUT PANSI_STRING *Value
+ )
+{
+ UNICODE_STRING Unicode;
+ HANDLE Key;
+ PANSI_STRING Ansi;
+ ULONG Length;
+ PCHAR Option;
+ PCHAR Context;
+ NTSTATUS status;
+
+ RtlInitUnicodeString(&Unicode, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control");
+
+ status = RegistryOpenKey(NULL, &Unicode, KEY_READ, &Key);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = RegistryQuerySzValue(Key, "SystemStartOptions", NULL, &Ansi);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ // SystemStartOptions is a space separated list of options.
+ // Scan it looking for the one we want.
+ Length = (ULONG)strlen(Prefix);
+
+ Option = __strtok_r(Ansi[0].Buffer, " ", &Context);
+ while (Option != NULL) {
+ if (strncmp(Prefix, Option, Length) == 0)
+ goto found;
+
+ Option = __strtok_r(NULL, " ", &Context);
+ }
+
+ status = STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail3;
+
+found:
+ *Value = __RegistryAllocate(sizeof (ANSI_STRING) * 2);
+
+ status = STATUS_NO_MEMORY;
+ if (*Value == NULL)
+ goto fail4;
+
+ Length = (ULONG)strlen(Option);
+ (*Value)[0].MaximumLength = (USHORT)(Length + 1) * sizeof (CHAR);
+ (*Value)[0].Buffer = __RegistryAllocate((*Value)[0].MaximumLength);
+
+ status = STATUS_NO_MEMORY;
+ if ((*Value)[0].Buffer == NULL)
+ goto fail5;
+
+ RtlCopyMemory((*Value)[0].Buffer, Option, Length * sizeof (CHAR));
+
+ (*Value)[0].Length = (USHORT)Length * sizeof (CHAR);
+
+ RegistryFreeSzValue(Ansi);
+
+ ZwClose(Key);
+
+ return STATUS_SUCCESS;
+
+fail5:
+ __RegistryFree(*Value);
+
+fail4:
+fail3:
+ RegistryFreeSzValue(Ansi);
+
+fail2:
+ ZwClose(Key);
+
+fail1:
+ return status;
+}
+
+static PKEY_VALUE_PARTIAL_INFORMATION
+RegistryAnsiToSz(
+ PANSI_STRING Ansi
+ )
+{
+ ULONG Length;
+ PKEY_VALUE_PARTIAL_INFORMATION Partial;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ Length = Ansi->Length + 1;
+ Partial = __RegistryAllocate(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
+ Length * sizeof (WCHAR));
+
+ status = STATUS_NO_MEMORY;
+ if (Partial == NULL)
+ goto fail1;
+
+ Partial->TitleIndex = 0;
+ Partial->Type = REG_SZ;
+ Partial->DataLength = Length * sizeof (WCHAR);
+
+ Unicode.MaximumLength = (UCHAR)Partial->DataLength;
+ Unicode.Buffer = (PWCHAR)Partial->Data;
+ Unicode.Length = 0;
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, Ansi, FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ return Partial;
+
+fail2:
+ __RegistryFree(Partial);
+
+fail1:
+ return NULL;
+}
+
+static PKEY_VALUE_PARTIAL_INFORMATION
+RegistryAnsiToMultiSz(
+ PANSI_STRING Ansi
+ )
+{
+ ULONG Length;
+ ULONG Index;
+ PKEY_VALUE_PARTIAL_INFORMATION Partial;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ Length = 1;
+ for (Index = 0; Ansi[Index].Buffer != NULL; Index++)
+ Length += Ansi[Index].Length + 1;
+
+ Partial = __RegistryAllocate(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
+ Length * sizeof (WCHAR));
+
+ status = STATUS_NO_MEMORY;
+ if (Partial == NULL)
+ goto fail1;
+
+ Partial->TitleIndex = 0;
+ Partial->Type = REG_MULTI_SZ;
+ Partial->DataLength = Length * sizeof (WCHAR);
+
+ Unicode.MaximumLength = (USHORT)Partial->DataLength;
+ Unicode.Buffer = (PWCHAR)Partial->Data;
+ Unicode.Length = 0;
+
+ for (Index = 0; Ansi[Index].Buffer != NULL; Index++) {
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi[Index], FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ Length = Unicode.Length / sizeof (WCHAR);
+
+ ASSERT3U(Unicode.MaximumLength, >=, (Length + 1) * sizeof (WCHAR));
+ Unicode.MaximumLength -= (USHORT)((Length + 1) * sizeof (WCHAR));
+ Unicode.Buffer += Length + 1;
+ Unicode.Length = 0;
+ }
+ *Unicode.Buffer = L'\0';
+
+ return Partial;
+
+fail2:
+ __RegistryFree(Partial);
+
+fail1:
+ return NULL;
+}
+
+NTSTATUS
+RegistryUpdateSzValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ IN ULONG Type,
+ IN PANSI_STRING Array
+ )
+{
+ ANSI_STRING Ansi;
+ UNICODE_STRING Unicode;
+ PKEY_VALUE_PARTIAL_INFORMATION Partial;
+ NTSTATUS status;
+
+ RtlInitAnsiString(&Ansi, Name);
+
+ status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ switch (Type) {
+ case REG_SZ:
+ status = STATUS_NO_MEMORY;
+ Partial = RegistryAnsiToSz(Array);
+ break;
+
+ case REG_MULTI_SZ:
+ status = STATUS_NO_MEMORY;
+ Partial = RegistryAnsiToMultiSz(Array);
+ break;
+
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ Partial = NULL;
+ break;
+ }
+
+ if (Partial == NULL)
+ goto fail2;
+
+ status = ZwSetValueKey(Key,
+ &Unicode,
+ Partial->TitleIndex,
+ Partial->Type,
+ Partial->Data,
+ Partial->DataLength);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ __RegistryFree(Partial);
+
+ (VOID) ZwFlushKey(Key);
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ __RegistryFree(Partial);
+
+fail2:
+ RtlFreeUnicodeString(&Unicode);
+
+fail1:
+ return status;
+}
+
+VOID
+RegistryFreeSzValue(
+ IN PANSI_STRING Array
+ )
+{
+ ULONG Index;
+
+ if (Array == NULL)
+ return;
+
+ for (Index = 0; Array[Index].Buffer != NULL; Index++)
+ __RegistryFree(Array[Index].Buffer);
+
+ __RegistryFree(Array);
+}
+
+VOID
+RegistryFreeBinaryValue(
+ IN PVOID Buffer
+ )
+{
+ __RegistryFree(Buffer);
+}
+
+VOID
+RegistryCloseKey(
+ IN HANDLE Key
+ )
+{
+ ZwClose(Key);
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_REGISTRY_H
+#define _XENVKBD_REGISTRY_H
+
+#include <ntddk.h>
+
+extern NTSTATUS
+RegistryInitialize(
+ IN PUNICODE_STRING Path
+ );
+
+extern VOID
+RegistryTeardown(
+ VOID
+ );
+
+extern NTSTATUS
+RegistryOpenKey(
+ IN HANDLE Parent,
+ IN PUNICODE_STRING Path,
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE Key
+ );
+
+extern NTSTATUS
+RegistryCreateKey(
+ IN HANDLE Parent,
+ IN PUNICODE_STRING Path,
+ IN ULONG Options,
+ OUT PHANDLE Key
+ );
+
+extern NTSTATUS
+RegistryOpenServiceKey(
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE Key
+ );
+
+extern NTSTATUS
+RegistryCreateServiceKey(
+ OUT PHANDLE Key
+ );
+
+extern NTSTATUS
+RegistryOpenSoftwareKey(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE Key
+ );
+
+extern NTSTATUS
+RegistryOpenHardwareKey(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE Key
+ );
+
+extern NTSTATUS
+RegistryOpenSubKey(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ IN ACCESS_MASK DesiredAccess,
+ OUT PHANDLE SubKey
+ );
+
+extern NTSTATUS
+RegistryCreateSubKey(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ IN ULONG Options,
+ OUT PHANDLE SubKey
+ );
+
+extern NTSTATUS
+RegistryDeleteSubKey(
+ IN HANDLE Key,
+ IN PCHAR Name
+ );
+
+extern NTSTATUS
+RegistryEnumerateSubKeys(
+ IN HANDLE Key,
+ IN NTSTATUS (*Callback)(PVOID, HANDLE, PANSI_STRING),
+ IN PVOID Context
+ );
+
+extern NTSTATUS
+RegistryEnumerateValues(
+ IN HANDLE Key,
+ IN NTSTATUS (*Callback)(PVOID, HANDLE, PANSI_STRING, ULONG),
+ IN PVOID Context
+ );
+
+extern NTSTATUS
+RegistryDeleteValue(
+ IN HANDLE Key,
+ IN PCHAR Name
+ );
+
+extern NTSTATUS
+RegistryQueryDwordValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ OUT PULONG Value
+ );
+
+extern NTSTATUS
+RegistryUpdateDwordValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ IN ULONG Value
+ );
+
+extern NTSTATUS
+RegistryQuerySzValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ OUT PULONG Type OPTIONAL,
+ OUT PANSI_STRING *Array
+ );
+
+extern NTSTATUS
+RegistryQueryBinaryValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ OUT PVOID *Buffer,
+ OUT PULONG Length
+ );
+
+extern NTSTATUS
+RegistryUpdateBinaryValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+extern NTSTATUS
+RegistryQueryKeyName(
+ IN HANDLE Key,
+ OUT PANSI_STRING *Array
+ );
+
+extern NTSTATUS
+RegistryQuerySystemStartOption(
+ IN PCHAR Name,
+ OUT PANSI_STRING *Option
+ );
+
+extern VOID
+RegistryFreeSzValue(
+ IN PANSI_STRING Array
+ );
+
+extern VOID
+RegistryFreeBinaryValue(
+ IN PVOID Buffer
+ );
+
+extern NTSTATUS
+RegistryUpdateSzValue(
+ IN HANDLE Key,
+ IN PCHAR Name,
+ IN ULONG Type,
+ IN PANSI_STRING Array
+ );
+
+extern VOID
+RegistryCloseKey(
+ IN HANDLE Key
+ );
+
+#endif // _XENVKBD_REGISTRY_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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 documetation 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.
+ */
+
+#include <ntddk.h>
+#include <procgrp.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+#include <xen.h>
+
+#include <debug_interface.h>
+#include <store_interface.h>
+#include <cache_interface.h>
+#include <gnttab_interface.h>
+#include <range_set_interface.h>
+#include <evtchn_interface.h>
+
+#include "pdo.h"
+#include "frontend.h"
+#include "ring.h"
+#include "hid.h"
+#include "thread.h"
+#include "registry.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+#define MAXNAMELEN 128
+
+struct _XENVKBD_RING {
+ PXENVKBD_FRONTEND Frontend;
+ PXENVKBD_HID_CONTEXT Hid;
+
+ XENBUS_DEBUG_INTERFACE DebugInterface;
+ XENBUS_STORE_INTERFACE StoreInterface;
+ XENBUS_GNTTAB_INTERFACE GnttabInterface;
+ XENBUS_EVTCHN_INTERFACE EvtchnInterface;
+
+ PXENBUS_DEBUG_CALLBACK DebugCallback;
+
+ PXENBUS_GNTTAB_CACHE GnttabCache;
+ PMDL Mdl;
+ struct xenkbd_page *Shared;
+ PXENBUS_GNTTAB_ENTRY Entry;
+ PXENBUS_EVTCHN_CHANNEL Channel;
+ KSPIN_LOCK Lock;
+ KDPC Dpc;
+ ULONG Dpcs;
+ ULONG Events;
+ BOOLEAN Connected;
+ BOOLEAN Enabled;
+ BOOLEAN AbsPointer;
+};
+
+#define XENVKBD_RING_TAG 'gniR'
+
+static FORCEINLINE PVOID
+__RingAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, XENVKBD_RING_TAG);
+}
+
+static FORCEINLINE VOID
+__RingFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, XENVKBD_RING_TAG);
+}
+
+__drv_functionClass(KDEFERRED_ROUTINE)
+__drv_maxIRQL(DISPATCH_LEVEL)
+__drv_minIRQL(DISPATCH_LEVEL)
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__drv_sameIRQL
+static VOID
+RingDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID Argument1,
+ IN PVOID Argument2
+ )
+{
+ PXENVKBD_RING Ring = Context;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(Argument1);
+ UNREFERENCED_PARAMETER(Argument2);
+
+ ASSERT(Ring != NULL);
+
+ for (;;) {
+ ULONG in_cons;
+ ULONG in_prod;
+
+ KeMemoryBarrier();
+
+ in_cons = Ring->Shared->in_cons;
+ in_prod = Ring->Shared->in_prod;
+
+ KeMemoryBarrier();
+
+ if (in_cons == in_prod)
+ break;
+
+ while (in_cons != in_prod) {
+ union xenkbd_in_event *in_evt;
+
+ in_evt = &XENKBD_IN_RING_REF(Ring->Shared, in_cons);
+ ++in_cons;
+
+ switch (in_evt->type) {
+ case XENKBD_TYPE_MOTION:
+ HidEventMotion(Ring->Hid,
+ in_evt->motion.rel_x,
+ in_evt->motion.rel_y,
+ in_evt->motion.rel_z);
+ break;
+ case XENKBD_TYPE_KEY:
+ HidEventKeypress(Ring->Hid,
+ in_evt->key.keycode,
+ in_evt->key.pressed);
+ break;
+ case XENKBD_TYPE_POS:
+ HidEventPosition(Ring->Hid,
+ in_evt->pos.abs_x,
+ in_evt->pos.abs_y,
+ in_evt->pos.rel_z);
+ break;
+ case XENKBD_TYPE_MTOUCH:
+ Trace("MTOUCH: %u %u %u %u\n",
+ in_evt->mtouch.event_type,
+ in_evt->mtouch.contact_id,
+ in_evt->mtouch.u.pos.abs_x,
+ in_evt->mtouch.u.pos.abs_y);
+ // call Frontend
+ break;
+ default:
+ Trace("UNKNOWN: %u\n",
+ in_evt->type);
+ break;
+ }
+ }
+
+ KeMemoryBarrier();
+
+ Ring->Shared->in_cons = in_cons;
+ }
+
+ XENBUS_EVTCHN(Unmask,
+ &Ring->EvtchnInterface,
+ Ring->Channel,
+ FALSE);
+}
+
+static VOID
+RingAcquireLock(
+ IN PVOID Context
+ )
+{
+ PXENVKBD_RING Ring = Context;
+ KeAcquireSpinLockAtDpcLevel(&Ring->Lock);
+}
+
+static VOID
+RingReleaseLock(
+ IN PVOID Context
+ )
+{
+ PXENVKBD_RING Ring = Context;
+#pragma warning(suppress:26110)
+ KeReleaseSpinLockFromDpcLevel(&Ring->Lock);
+}
+
+KSERVICE_ROUTINE RingEvtchnCallback;
+
+BOOLEAN
+RingEvtchnCallback(
+ IN PKINTERRUPT InterruptObject,
+ IN PVOID Argument
+ )
+{
+ PXENVKBD_RING Ring = Argument;
+
+ UNREFERENCED_PARAMETER(InterruptObject);
+
+ ASSERT(Ring != NULL);
+ Ring->Events++;
+
+ if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
+ Ring->Dpcs++;
+
+ return TRUE;
+}
+
+static VOID
+RingDebugCallback(
+ IN PVOID Argument,
+ IN BOOLEAN Crashing
+ )
+{
+ PXENVKBD_RING Ring = Argument;
+
+ UNREFERENCED_PARAMETER(Crashing);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "0x%p [%s]\n",
+ Ring,
+ (Ring->Enabled) ? "ENABLED" : "DISABLED");
+}
+
+NTSTATUS
+RingInitialize(
+ IN PXENVKBD_FRONTEND Frontend,
+ OUT PXENVKBD_RING *Ring
+ )
+{
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ status = STATUS_NO_MEMORY;
+ *Ring = __RingAllocate(sizeof(XENVKBD_RING));
+ if (*Ring == NULL)
+ goto fail1;
+
+ (*Ring)->Frontend = Frontend;
+ (*Ring)->Hid = PdoGetHidContext(FrontendGetPdo(Frontend));
+ KeInitializeDpc(&(*Ring)->Dpc, RingDpc, *Ring);
+ KeInitializeSpinLock(&(*Ring)->Lock);
+
+ FdoGetDebugInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+ &(*Ring)->DebugInterface);
+
+ FdoGetStoreInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+ &(*Ring)->StoreInterface);
+
+ FdoGetGnttabInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+ &(*Ring)->GnttabInterface);
+
+ FdoGetEvtchnInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+ &(*Ring)->EvtchnInterface);
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 %08x\n", status);
+ return status;
+}
+
+static FORCEINLINE VOID
+RingReadFeatures(
+ IN PXENVKBD_RING Ring
+ )
+{
+ PCHAR Buffer;
+ NTSTATUS status;
+
+ status = XENBUS_STORE(Read,
+ &Ring->StoreInterface,
+ NULL,
+ FrontendGetBackendPath(Ring->Frontend),
+ "feature-abs-pointer",
+ &Buffer);
+ if (NT_SUCCESS(status)) {
+ Ring->AbsPointer = (BOOLEAN)strtoul(Buffer, NULL, 2);
+
+ XENBUS_STORE(Free,
+ &Ring->StoreInterface,
+ Buffer);
+ } else {
+ Ring->AbsPointer = FALSE;
+ }
+}
+
+NTSTATUS
+RingConnect(
+ IN PXENVKBD_RING Ring
+ )
+{
+ PFN_NUMBER Pfn;
+ PXENVKBD_FRONTEND Frontend;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ Frontend = Ring->Frontend;
+
+ status = XENBUS_DEBUG(Acquire, &Ring->DebugInterface);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = XENBUS_STORE(Acquire, &Ring->StoreInterface);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = XENBUS_EVTCHN(Acquire, &Ring->EvtchnInterface);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = XENBUS_GNTTAB(Acquire, &Ring->GnttabInterface);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = XENBUS_GNTTAB(CreateCache,
+ &Ring->GnttabInterface,
+ "VKBD_Ring_Gnttab",
+ 0,
+ RingAcquireLock,
+ RingReleaseLock,
+ Ring,
+ &Ring->GnttabCache);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ RingReadFeatures(Ring);
+
+ Ring->Mdl = __AllocatePage();
+
+ status = STATUS_NO_MEMORY;
+ if (Ring->Mdl == NULL)
+ goto fail6;
+
+ ASSERT(Ring->Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
+ Ring->Shared = Ring->Mdl->MappedSystemVa;
+ ASSERT(Ring->Shared != NULL);
+
+ ASSERT(Ring->Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
+ RtlZeroMemory(Ring->Mdl->MappedSystemVa, PAGE_SIZE);
+
+ Pfn = MmGetMdlPfnArray(Ring->Mdl)[0];
+
+ status = XENBUS_GNTTAB(PermitForeignAccess,
+ &Ring->GnttabInterface,
+ Ring->GnttabCache,
+ TRUE,
+ FrontendGetBackendDomain(Frontend),
+ Pfn,
+ FALSE,
+ &Ring->Entry);
+ if (!NT_SUCCESS(status))
+ goto fail7;
+
+ Ring->Channel = XENBUS_EVTCHN(Open,
+ &Ring->EvtchnInterface,
+ XENBUS_EVTCHN_TYPE_UNBOUND,
+ RingEvtchnCallback,
+ Ring,
+ FrontendGetBackendDomain(Frontend),
+ TRUE);
+
+ status = STATUS_UNSUCCESSFUL;
+ if (Ring->Channel == NULL)
+ goto fail8;
+
+ XENBUS_EVTCHN(Unmask,
+ &Ring->EvtchnInterface,
+ Ring->Channel,
+ FALSE);
+
+ status = XENBUS_DEBUG(Register,
+ &Ring->DebugInterface,
+ __MODULE__ "|RING",
+ RingDebugCallback,
+ Ring,
+ &Ring->DebugCallback);
+ if (!NT_SUCCESS(status))
+ goto fail9;
+
+ Ring->Connected = TRUE;
+ return STATUS_SUCCESS;
+
+fail9:
+ Error("fail9\n");
+
+ XENBUS_EVTCHN(Close,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+ Ring->Channel = NULL;
+
+ Ring->Events = 0;
+
+fail8:
+ Error("fail8\n");
+
+ (VOID) XENBUS_GNTTAB(RevokeForeignAccess,
+ &Ring->GnttabInterface,
+ Ring->GnttabCache,
+ TRUE,
+ Ring->Entry);
+ Ring->Entry = NULL;
+
+fail7:
+ Error("fail7\n");
+
+ Ring->Shared = NULL;
+ __FreePage(Ring->Mdl);
+ Ring->Mdl = NULL;
+
+fail6:
+ Error("fail6\n");
+
+ XENBUS_GNTTAB(DestroyCache,
+ &Ring->GnttabInterface,
+ Ring->GnttabCache);
+ Ring->GnttabCache = NULL;
+
+fail5:
+ Error("fail5\n");
+
+ XENBUS_GNTTAB(Release, &Ring->GnttabInterface);
+
+fail4:
+ Error("fail4\n");
+
+ XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
+
+fail3:
+ Error("fail3\n");
+
+ XENBUS_STORE(Release, &Ring->StoreInterface);
+
+fail2:
+ Error("fail2\n");
+
+ XENBUS_DEBUG(Release, &Ring->DebugInterface);
+
+fail1:
+ Error("fail1 %08x\n", status);
+
+ return status;
+}
+
+NTSTATUS
+RingStoreWrite(
+ IN PXENVKBD_RING Ring,
+ IN PXENBUS_STORE_TRANSACTION Transaction
+ )
+{
+ ULONG Port;
+ NTSTATUS status;
+
+ Trace("=====>\n");
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetPath(Ring->Frontend),
+ "page-gref",
+ "%u",
+ XENBUS_GNTTAB(GetReference,
+ &Ring->GnttabInterface,
+ Ring->Entry));
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ // this should not be required - QEMU should use grant references
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetPath(Ring->Frontend),
+ "page-ref",
+ "%llu",
+ (ULONG64)MmGetMdlPfnArray(Ring->Mdl)[0]);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ Port = XENBUS_EVTCHN(GetPort,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetPath(Ring->Frontend),
+ "event-channel",
+ "%u",
+ Port);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetPath(Ring->Frontend),
+ "request-abs-pointer",
+ "%u",
+ Ring->AbsPointer);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ Trace("<=====\n");
+ return STATUS_SUCCESS;
+
+fail4:
+ Error("fail4\n");
+fail3:
+ Error("fail3\n");
+fail2:
+ Error("fail2\n");
+fail1:
+ Error("fail1 %08x\n", status);
+ return status;
+}
+
+NTSTATUS
+RingEnable(
+ IN PXENVKBD_RING Ring
+ )
+{
+ Trace("=====>\n");
+
+ ASSERT(!Ring->Enabled);
+ Ring->Enabled = TRUE;
+
+ KeInsertQueueDpc(&Ring->Dpc, NULL, NULL);
+
+ Trace("<=====\n");
+ return STATUS_SUCCESS;
+}
+
+VOID
+RingDisable(
+ IN PXENVKBD_RING Ring
+ )
+{
+ Trace("=====>\n");
+
+ ASSERT(Ring->Enabled);
+ Ring->Enabled = FALSE;
+
+ Trace("<=====\n");
+}
+
+VOID
+RingDisconnect(
+ IN PXENVKBD_RING Ring
+ )
+{
+ Trace("=====>\n");
+
+ XENBUS_DEBUG(Deregister,
+ &Ring->DebugInterface,
+ Ring->DebugCallback);
+ Ring->DebugCallback = NULL;
+
+ XENBUS_EVTCHN(Close,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+ Ring->Channel = NULL;
+
+ Ring->Events = 0;
+
+ (VOID) XENBUS_GNTTAB(RevokeForeignAccess,
+ &Ring->GnttabInterface,
+ Ring->GnttabCache,
+ TRUE,
+ Ring->Entry);
+ Ring->Entry = NULL;
+
+ Ring->Shared = NULL;
+ __FreePage(Ring->Mdl);
+ Ring->Mdl = NULL;
+
+ XENBUS_GNTTAB(DestroyCache,
+ &Ring->GnttabInterface,
+ Ring->GnttabCache);
+ Ring->GnttabCache = NULL;
+
+ XENBUS_GNTTAB(Release, &Ring->GnttabInterface);
+ XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
+ XENBUS_STORE(Release, &Ring->StoreInterface);
+ XENBUS_DEBUG(Release, &Ring->DebugInterface);
+
+ Trace("<=====\n");
+}
+
+VOID
+RingTeardown(
+ IN PXENVKBD_RING Ring
+ )
+{
+ Trace("=====>\n");
+ Ring->Dpcs = 0;
+
+ Ring->AbsPointer = FALSE;
+
+ RtlZeroMemory(&Ring->Dpc, sizeof (KDPC));
+
+ RtlZeroMemory(&Ring->Lock,
+ sizeof (KSPIN_LOCK));
+
+ RtlZeroMemory(&Ring->GnttabInterface,
+ sizeof (XENBUS_GNTTAB_INTERFACE));
+
+ RtlZeroMemory(&Ring->StoreInterface,
+ sizeof (XENBUS_STORE_INTERFACE));
+
+ RtlZeroMemory(&Ring->DebugInterface,
+ sizeof (XENBUS_DEBUG_INTERFACE));
+
+ RtlZeroMemory(&Ring->EvtchnInterface,
+ sizeof (XENBUS_EVTCHN_INTERFACE));
+
+ Ring->Frontend = NULL;
+ Ring->Hid = NULL;
+
+ ASSERT(IsZeroMemory(Ring, sizeof (XENVKBD_RING)));
+ __RingFree(Ring);
+ Trace("<=====\n");
+}
+
+VOID
+RingNotify(
+ IN PXENVKBD_RING Ring
+ )
+{
+ if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
+ Ring->Dpcs++;
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_RING_H
+#define _XENVKBD_RING_H
+
+#include <ntddk.h>
+
+#include <hid_interface.h>
+
+#include "frontend.h"
+
+typedef struct _XENVKBD_RING XENVKBD_RING, *PXENVKBD_RING;
+
+extern NTSTATUS
+RingInitialize(
+ IN PXENVKBD_FRONTEND Frontend,
+ OUT PXENVKBD_RING *Ring
+ );
+
+extern NTSTATUS
+RingConnect(
+ IN PXENVKBD_RING Ring
+ );
+
+extern NTSTATUS
+RingStoreWrite(
+ IN PXENVKBD_RING Ring,
+ IN PXENBUS_STORE_TRANSACTION Transaction
+ );
+
+extern NTSTATUS
+RingEnable(
+ IN PXENVKBD_RING Ring
+ );
+
+extern VOID
+RingDisable(
+ IN PXENVKBD_RING Ring
+ );
+
+extern VOID
+RingDisconnect(
+ IN PXENVKBD_RING Ring
+ );
+
+extern VOID
+RingTeardown(
+ IN PXENVKBD_RING Ring
+ );
+
+extern VOID
+RingNotify(
+ IN PXENVKBD_RING Ring
+ );
+
+#endif // _XENVKBD_RING_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#include <ntddk.h>
+
+#include "thread.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+#define THREAD_POOL 'ERHT'
+
+struct _XENVKBD_THREAD {
+ XENVKBD_THREAD_FUNCTION Function;
+ PVOID Context;
+ KEVENT Event;
+ BOOLEAN Alerted;
+ LONG References;
+ PKTHREAD Thread;
+};
+
+static FORCEINLINE PVOID
+__ThreadAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, THREAD_POOL);
+}
+
+static FORCEINLINE VOID
+__ThreadFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, THREAD_POOL);
+}
+
+static FORCEINLINE VOID
+__ThreadWake(
+ IN PXENVKBD_THREAD Thread
+ )
+{
+ KeSetEvent(&Thread->Event, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+ThreadWake(
+ IN PXENVKBD_THREAD Thread
+ )
+{
+ __ThreadWake(Thread);
+}
+
+static FORCEINLINE VOID
+__ThreadAlert(
+ IN PXENVKBD_THREAD Thread
+ )
+{
+ Thread->Alerted = TRUE;
+ __ThreadWake(Thread);
+}
+
+VOID
+ThreadAlert(
+ IN PXENVKBD_THREAD Thread
+ )
+{
+ __ThreadAlert(Thread);
+}
+
+KSTART_ROUTINE ThreadFunction;
+
+VOID
+ThreadFunction(
+ IN PVOID Argument
+ )
+{
+ PXENVKBD_THREAD Self = Argument;
+ NTSTATUS status;
+
+ status = Self->Function(Self, Self->Context);
+
+ if (InterlockedDecrement(&Self->References) == 0)
+ __ThreadFree(Self);
+
+ PsTerminateSystemThread(status);
+ // NOT REACHED
+}
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+NTSTATUS
+ThreadCreate(
+ IN XENVKBD_THREAD_FUNCTION Function,
+ IN PVOID Context,
+ OUT PXENVKBD_THREAD *Thread
+ )
+{
+ HANDLE Handle;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ (*Thread) = __ThreadAllocate(sizeof (XENVKBD_THREAD));
+
+ status = STATUS_NO_MEMORY;
+ if (*Thread == NULL)
+ goto fail1;
+
+ (*Thread)->Function = Function;
+ (*Thread)->Context = Context;
+ (*Thread)->Alerted = FALSE;
+ (*Thread)->References = 2; // One for us, one for the thread function
+
+ KeInitializeEvent(&(*Thread)->Event, NotificationEvent, FALSE);
+
+ status = PsCreateSystemThread(&Handle,
+ STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
+ NULL,
+ NULL,
+ NULL,
+ ThreadFunction,
+ *Thread);
+ if (!NT_SUCCESS(status)) {
+ --(*Thread)->References; // Fake thread function termination
+ goto fail2;
+ }
+
+ status = ObReferenceObjectByHandle(Handle,
+ SYNCHRONIZE,
+ *PsThreadType,
+ KernelMode,
+ &(*Thread)->Thread,
+ NULL);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ ZwClose(Handle);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+
+ __ThreadAlert(*Thread);
+ ZwClose(Handle);
+
+fail2:
+ Error("fail2\n");
+
+ if (InterlockedDecrement(&(*Thread)->References) == 0)
+ __ThreadFree(*Thread);
+
+ *Thread = NULL;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+PKEVENT
+ThreadGetEvent(
+ IN PXENVKBD_THREAD Thread
+ )
+{
+ return &Thread->Event;
+}
+
+BOOLEAN
+ThreadIsAlerted(
+ IN PXENVKBD_THREAD Thread
+ )
+{
+ return Thread->Alerted;
+}
+
+VOID
+ThreadJoin(
+ IN PXENVKBD_THREAD Thread
+ )
+{
+ LONG References;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3P(KeGetCurrentThread(), !=, Thread->Thread);
+
+ (VOID) KeWaitForSingleObject(Thread->Thread,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ References = InterlockedDecrement(&Thread->References);
+ ASSERT3U(References, ==, 0);
+
+ __ThreadFree(Thread);
+}
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_THREAD_H
+#define _XENVKBD_THREAD_H
+
+#include <ntddk.h>
+
+typedef struct _XENVKBD_THREAD XENVKBD_THREAD, *PXENVKBD_THREAD;
+
+typedef NTSTATUS (*XENVKBD_THREAD_FUNCTION)(PXENVKBD_THREAD, PVOID);
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+extern NTSTATUS
+ThreadCreate(
+ IN XENVKBD_THREAD_FUNCTION Function,
+ IN PVOID Context,
+ OUT PXENVKBD_THREAD *Thread
+ );
+
+extern PKEVENT
+ThreadGetEvent(
+ IN PXENVKBD_THREAD Self
+ );
+
+extern BOOLEAN
+ThreadIsAlerted(
+ IN PXENVKBD_THREAD Self
+ );
+
+extern VOID
+ThreadWake(
+ IN PXENVKBD_THREAD Thread
+ );
+
+extern VOID
+ThreadAlert(
+ IN PXENVKBD_THREAD Thread
+ );
+
+extern VOID
+ThreadJoin(
+ IN PXENVKBD_THREAD Thread
+ );
+
+#endif // _XENVKBD_THREAD_H
+
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_TYPES_H
+#define _XENVKBD_TYPES_H
+
+typedef enum _DEVICE_OBJECT_TYPE {
+ PHYSICAL_DEVICE_OBJECT = 'ODP',
+ FUNCTION_DEVICE_OBJECT = 'ODF'
+} DEVICE_OBJECT_TYPE, *PDEVICE_OBJECT_TYPE;
+
+typedef enum _DEVICE_PNP_STATE {
+ Invalid = 0,
+ Present, // PDO only
+ Enumerated, // PDO only
+ Added, // FDO only
+ Started,
+ StopPending,
+ Stopped,
+ RemovePending,
+ SurpriseRemovePending,
+ Deleted
+} DEVICE_PNP_STATE, *PDEVICE_PNP_STATE;
+
+#endif // _XENVKBD_TYPES_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_UTIL_H
+#define _XENVKBD_UTIL_H
+
+#include <ntddk.h>
+
+#include "assert.h"
+
+#define P2ROUNDUP(_x, _a) \
+ (-(-(_x) & -(_a)))
+
+static FORCEINLINE LONG
+__ffs(
+ IN unsigned long long mask
+ )
+{
+ unsigned char *array = (unsigned char *)&mask;
+ unsigned int byte;
+ unsigned int bit;
+ unsigned char val;
+
+ val = 0;
+
+ byte = 0;
+ while (byte < 8) {
+ val = array[byte];
+
+ if (val != 0)
+ break;
+
+ byte++;
+ }
+ if (byte == 8)
+ return -1;
+
+ bit = 0;
+ while (bit < 8) {
+ if (val & 0x01)
+ break;
+
+ val >>= 1;
+ bit++;
+ }
+
+ return (byte * 8) + bit;
+}
+
+#define __ffu(_mask) \
+ __ffs(~(_mask))
+
+static FORCEINLINE VOID
+__CpuId(
+ IN ULONG Leaf,
+ OUT PULONG EAX OPTIONAL,
+ OUT PULONG EBX OPTIONAL,
+ OUT PULONG ECX OPTIONAL,
+ OUT PULONG EDX OPTIONAL
+ )
+{
+ ULONG Value[4] = {0};
+
+ __cpuid(Value, Leaf);
+
+ if (EAX)
+ *EAX = Value[0];
+
+ if (EBX)
+ *EBX = Value[1];
+
+ if (ECX)
+ *ECX = Value[2];
+
+ if (EDX)
+ *EDX = Value[3];
+}
+
+static FORCEINLINE LONG
+__InterlockedAdd(
+ IN LONG *Value,
+ IN LONG Delta
+ )
+{
+ LONG New;
+ LONG Old;
+
+ do {
+ Old = *Value;
+ New = Old + Delta;
+ } while (InterlockedCompareExchange(Value, New, Old) != Old);
+
+ return New;
+}
+
+static FORCEINLINE LONG
+__InterlockedSubtract(
+ IN LONG *Value,
+ IN LONG Delta
+ )
+{
+ LONG New;
+ LONG Old;
+
+ do {
+ Old = *Value;
+ New = Old - Delta;
+ } while (InterlockedCompareExchange(Value, New, Old) != Old);
+
+ return New;
+}
+
+__checkReturn
+static FORCEINLINE PVOID
+__AllocatePoolWithTag(
+ IN POOL_TYPE PoolType,
+ IN SIZE_T NumberOfBytes,
+ IN ULONG Tag
+ )
+{
+ PUCHAR Buffer;
+
+ __analysis_assume(PoolType == NonPagedPool ||
+ PoolType == PagedPool);
+
+#pragma warning(suppress:28160) // annotation error
+ Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
+ if (Buffer == NULL)
+ return NULL;
+
+ RtlZeroMemory(Buffer, NumberOfBytes);
+ return Buffer;
+}
+
+static FORCEINLINE VOID
+__FreePoolWithTag(
+ IN PVOID Buffer,
+ IN ULONG Tag
+ )
+{
+ ExFreePoolWithTag(Buffer, Tag);
+}
+
+static FORCEINLINE PMDL
+__AllocatePages(
+ IN ULONG Count
+ )
+{
+ PHYSICAL_ADDRESS LowAddress;
+ PHYSICAL_ADDRESS HighAddress;
+ LARGE_INTEGER SkipBytes;
+ SIZE_T TotalBytes;
+ PMDL Mdl;
+ PUCHAR MdlMappedSystemVa;
+ NTSTATUS status;
+
+ LowAddress.QuadPart = 0ull;
+ HighAddress.QuadPart = ~0ull;
+ SkipBytes.QuadPart = 0ull;
+ TotalBytes = (SIZE_T)PAGE_SIZE * Count;
+
+ Mdl = MmAllocatePagesForMdlEx(LowAddress,
+ HighAddress,
+ SkipBytes,
+ TotalBytes,
+ MmCached,
+ MM_DONT_ZERO_ALLOCATION);
+
+ status = STATUS_NO_MEMORY;
+ if (Mdl == NULL)
+ goto fail1;
+
+ if (Mdl->ByteCount < TotalBytes)
+ goto fail2;
+
+ ASSERT((Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA |
+ MDL_PARTIAL_HAS_BEEN_MAPPED |
+ MDL_PARTIAL |
+ MDL_PARENT_MAPPED_SYSTEM_VA |
+ MDL_SOURCE_IS_NONPAGED_POOL |
+ MDL_IO_SPACE)) == 0);
+
+ MdlMappedSystemVa = MmMapLockedPagesSpecifyCache(Mdl,
+ KernelMode,
+ MmCached,
+ NULL,
+ FALSE,
+ NormalPagePriority);
+
+ status = STATUS_UNSUCCESSFUL;
+ if (MdlMappedSystemVa == NULL)
+ goto fail3;
+
+ ASSERT3P(MdlMappedSystemVa, ==, Mdl->MappedSystemVa);
+
+ RtlZeroMemory(MdlMappedSystemVa, Mdl->ByteCount);
+
+ return Mdl;
+
+fail3:
+ Error("fail3\n");
+
+fail2:
+ Error("fail2\n");
+
+ MmFreePagesFromMdl(Mdl);
+ ExFreePool(Mdl);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return NULL;
+}
+
+#define __AllocatePage() __AllocatePages(1)
+
+static FORCEINLINE VOID
+__FreePages(
+ IN PMDL Mdl
+ )
+{
+ PUCHAR MdlMappedSystemVa;
+
+ ASSERT(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
+ MdlMappedSystemVa = Mdl->MappedSystemVa;
+
+ MmUnmapLockedPages(MdlMappedSystemVa, Mdl);
+
+ MmFreePagesFromMdl(Mdl);
+ ExFreePool(Mdl);
+}
+
+#define __FreePage(_Mdl) __FreePages(_Mdl)
+
+static FORCEINLINE PCHAR
+__strtok_r(
+ IN PCHAR Buffer,
+ IN PCHAR Delimiter,
+ IN OUT PCHAR *Context
+ )
+{
+ PCHAR Token;
+ PCHAR End;
+
+ if (Buffer != NULL)
+ *Context = Buffer;
+
+ Token = *Context;
+
+ if (Token == NULL)
+ return NULL;
+
+ while (*Token != '\0' &&
+ strchr(Delimiter, *Token) != NULL)
+ Token++;
+
+ if (*Token == '\0')
+ return NULL;
+
+ End = Token + 1;
+ while (*End != '\0' &&
+ strchr(Delimiter, *End) == NULL)
+ End++;
+
+ if (*End != '\0')
+ *End++ = '\0';
+
+ *Context = End;
+
+ return Token;
+}
+
+static FORCEINLINE PWCHAR
+__wcstok_r(
+ IN PWCHAR Buffer,
+ IN PWCHAR Delimiter,
+ IN OUT PWCHAR *Context
+ )
+{
+ PWCHAR Token;
+ PWCHAR End;
+
+ if (Buffer != NULL)
+ *Context = Buffer;
+
+ Token = *Context;
+
+ if (Token == NULL)
+ return NULL;
+
+ while (*Token != L'\0' &&
+ wcschr(Delimiter, *Token) != NULL)
+ Token++;
+
+ if (*Token == L'\0')
+ return NULL;
+
+ End = Token + 1;
+ while (*End != L'\0' &&
+ wcschr(Delimiter, *End) == NULL)
+ End++;
+
+ if (*End != L'\0')
+ *End++ = L'\0';
+
+ *Context = End;
+
+ return Token;
+}
+
+static FORCEINLINE CHAR
+__toupper(
+ IN CHAR Character
+ )
+{
+ if (Character < 'a' || Character > 'z')
+ return Character;
+
+ return 'A' + Character - 'a';
+}
+
+static FORCEINLINE CHAR
+__tolower(
+ IN CHAR Character
+ )
+{
+ if (Character < 'A' || Character > 'Z')
+ return Character;
+
+ return 'a' + Character - 'A';
+}
+
+#endif // _XENVKBD_UTIL_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _XENVKBD_VKBD_H
+#define _XENVKBD_VKBD_H
+
+#include <ntddk.h>
+#include <hidport.h>
+
+typedef struct _XENVKBD_HID_KEYBOARD {
+ UCHAR ReportId; // = 1
+ UCHAR Modifiers;
+ UCHAR Keys[6];
+} XENVKBD_HID_KEYBOARD;
+
+typedef struct _XENVKBD_HID_ABSMOUSE {
+ UCHAR ReportId; // = 2
+ UCHAR Buttons;
+ USHORT X;
+ USHORT Y;
+ CHAR dZ;
+} XENVKBD_HID_ABSMOUSE;
+
+static const UCHAR VkbdReportDescriptor[] = {
+ /* ReportId 1 : Keyboard */
+ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */\r
+ 0x09, 0x06, /* USAGE (Keyboard 6) */\r
+ 0xa1, 0x01, /* COLLECTION (Application) */\r
+ 0x85, 0x01, /* REPORT_ID (1) */\r
+ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */\r
+ 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */\r
+ 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */\r
+ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */\r
+ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */\r
+ 0x75, 0x01, /* REPORT_SIZE (1) */\r
+ 0x95, 0x08, /* REPORT_COUNT (8) */\r
+ 0x81, 0x02, /* INPUT (Data,Var,Abs) */\r
+ 0x95, 0x06, /* REPORT_COUNT (6) */\r
+ 0x75, 0x08, /* REPORT_SIZE (8) */\r
+ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */\r
+ 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */\r
+ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */\r
+ 0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */\r
+ 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */\r
+ 0x81, 0x00, /* INPUT (Data,Ary,Abs) */\r
+ 0xc0, /* END_COLLECTION */
+ /* Report Id 2 : Absolute Mouse */
+ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */\r
+ 0x09, 0x02, /* USAGE (Mouse 2) */\r
+ 0xa1, 0x01, /* COLLECTION (Application) */\r
+ 0x85, 0x02, /* REPORT_ID (2) */\r
+ 0x09, 0x01, /* USAGE (Pointer) */\r
+ 0xa1, 0x00, /* COLLECTION (Physical) */\r
+ 0x05, 0x09, /* USAGE_PAGE (Button) */\r
+ 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */\r
+ 0x29, 0x05, /* USAGE_MAXIMUM (Button 5) */\r
+ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */\r
+ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */\r
+ 0x95, 0x05, /* REPORT_COUNT (5) */\r
+ 0x75, 0x01, /* REPORT_SIZE (1) */\r
+ 0x81, 0x02, /* INPUT (Data,Var,Abs) */\r
+ 0x95, 0x01, /* REPORT_COUNT (1) */\r
+ 0x75, 0x03, /* REPORT_SIZE (3) */\r
+ 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */\r
+ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */\r
+ 0x09, 0x30, /* USAGE (X) */\r
+ 0x09, 0x31, /* USAGE (Y) */\r
+ 0x16, 0x00, 0x00, /* LOGICAL_MINIMUM (0) */\r
+ 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (32767) */\r
+ 0x75, 0x10, /* REPORT_SIZE (16) */\r
+ 0x95, 0x02, /* REPORT_COUNT (2) */\r
+ 0x81, 0x02, /* INPUT (Data,Var,Abs) */\r
+ 0x09, 0x38, /* USAGE (Z) */\r
+ 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */\r
+ 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */\r
+ 0x75, 0x08, /* REPORT_SIZE (8) */\r
+ 0x95, 0x01, /* REPORT_COUNT (1) */\r
+ 0x81, 0x06, /* INPUT (Data,Var,Rel) */\r
+ 0xc0, /* END_COLLECTION */\r
+ 0xc0 /* END_COLLECTION */\r
+
+};
+
+static const HID_DESCRIPTOR VkbdDeviceDescriptor = {
+ sizeof(HID_DESCRIPTOR),
+ 0x09,
+ 0x0101,
+ 0x00,
+ 0x01,
+ { 0x22, sizeof(VkbdReportDescriptor) }
+};
+
+static const HID_DEVICE_ATTRIBUTES VkbdDeviceAttributes = {
+ sizeof(HID_DEVICE_ATTRIBUTES),
+ 0xF001, // Random Vendor ID - this may need changing to a valid USBIF designation
+ 0xF001, // Random Product ID
+ 0x0101
+};
+
+static const USHORT VkbdKeyCodeToUsage[] = {
+ 0x00, // KEY_RESERVED\r
+ 0x29, // KEY_ESC\r
+ 0x1E, // KEY_1\r
+ 0x1F, // KEY_2\r
+ 0x20, // KEY_3\r
+ 0x21, // KEY_4\r
+ 0x22, // KEY_5\r
+ 0x23, // KEY_6\r
+ 0x24, // KEY_7\r
+ 0x25, // KEY_8\r
+ 0x26, // KEY_9\r
+ 0x27, // KEY_0\r
+ 0x2D, // KEY_MINUS\r
+ 0x2E, // KEY_EQUAL\r
+ 0x2A, // KEY_BACKSPACE\r
+ 0x2B, // KEY_TAB\r
+ 0x14, // KEY_Q\r
+ 0x1A, // KEY_W\r
+ 0x08, // KEY_E\r
+ 0x15, // KEY_R\r
+ 0x17, // KEY_T\r
+ 0x1C, // KEY_Y\r
+ 0x18, // KEY_U\r
+ 0x0C, // KEY_I\r
+ 0x12, // KEY_O\r
+ 0x13, // KEY_P\r
+ 0x2F, // KEY_LEFTBRACE\r
+ 0x30, // KEY_RIGHTBRACE\r
+ 0x29, // KEY_ENTER\r
+ 0xE0, // KEY_LEFTCTRL\r
+ 0x04, // KEY_A\r
+ 0x16, // KEY_S\r
+ 0x07, // KEY_D\r
+ 0x09, // KEY_F\r
+ 0x0A, // KEY_G\r
+ 0x0B, // KEY_H\r
+ 0x0D, // KEY_J\r
+ 0x0E, // KEY_K\r
+ 0x0F, // KEY_L\r
+ 0x33, // KEY_SEMICOLON\r
+ 0x24, // KEY_APOSTROPHE\r
+ 0x35, // KEY_GRAVE\r
+ 0xE1, // KEY_LEFTSHIFT\r
+ 0x31, // KEY_BACKSLASH\r
+ 0x1D, // KEY_Z\r
+ 0x1B, // KEY_X\r
+ 0x06, // KEY_C\r
+ 0x19, // KEY_V\r
+ 0x05, // KEY_B\r
+ 0x11, // KEY_N\r
+ 0x10, // KEY_M\r
+ 0x36, // KEY_COMMA\r
+ 0x37, // KEY_DOT\r
+ 0x38, // KEY_SLASH\r
+ 0xE5, // KEY_RIGHTSHIFT\r
+ 0x55, // KEY_KPASTERISK\r
+ 0xE2, // KEY_LEFTALT\r
+ 0x2C, // KEY_SPACE\r
+ 0x39, // KEY_CAPSLOCK\r
+ 0x3A, // KEY_F1\r
+ 0x3B, // KEY_F2\r
+ 0x3C, // KEY_F3\r
+ 0x3D, // KEY_F4\r
+ 0x3E, // KEY_F5\r
+ 0x3F, // KEY_F6\r
+ 0x40, // KEY_F7\r
+ 0x41, // KEY_F8\r
+ 0x42, // KEY_F9\r
+ 0x43, // KEY_F10\r
+ 0x53, // KEY_NUMLOCK\r
+ 0x47, // KEY_SCROLLLOCK\r
+ 0x5F, // KEY_KP7\r
+ 0x60, // KEY_KP8\r
+ 0x61, // KEY_KP9\r
+ 0x56, // KEY_KPMINUS\r
+ 0x5C, // KEY_KP4\r
+ 0x5D, // KEY_KP5\r
+ 0x5E, // KEY_KP6\r
+ 0x57, // KEY_KPPLUS\r
+ 0x59, // KEY_KP1\r
+ 0x5A, // KEY_KP2\r
+ 0x5B, // KEY_KP3\r
+ 0x62, // KEY_KP0\r
+ 0x63, // KEY_KPDOT\r
+ 0x00, // gap in sequence\r
+ 0x8F, // KEY_ZENKAKUHANKAKU\r
+ 0x64, // KEY_102ND\r
+ 0x44, // KEY_F11\r
+ 0x45, // KEY_F12\r
+ 0x87, // KEY_RO\r
+ 0x88, // KEY_KATAKANA\r
+ 0x8A, // KEY_HIRAGANA\r
+ 0x8B, // KEY_HENKAN\r
+ 0x8C, // KEY_KATAKANAHIRAGANA\r
+ 0x8D, // KEY_MUHENKAN\r
+ 0x8E, // KEY_KPJPCOMMA\r
+ 0x58, // KEY_KPENTER\r
+ 0xE4, // KEY_RIGHTCTRL\r
+ 0x54, // KEY_KPSLASH\r
+ 0x48, // KEY_SYSRQ\r
+ 0xE6, // KEY_RIGHTALT\r
+ 0x00, // gap in sequence\r
+ 0x4A, // KEY_HOME\r
+ 0x52, // KEY_UP\r
+ 0x4B, // KEY_PAGEUP\r
+ 0x50, // KEY_LEFT\r
+ 0x4F, // KEY_RIGHT\r
+ 0x4D, // KEY_END\r
+ 0x51, // KEY_DOWN\r
+ 0x4E, // KEY_PAGEDOWN\r
+ 0x49, // KEY_INSERT\r
+ 0x4D, // KEY_DELETE\r
+ 0x00, // gap in sequence\r
+ 0x7F, // KEY_MUTE\r
+ 0x81, // KEY_VOLUMEDOWN\r
+ 0x80, // KEY_VOLUMEUP\r
+ 0x66, // KEY_POWER\r
+ 0x67, // KEY_KPEQUAL\r
+ 0x00, // KEY_KPPLUSMINUS\r
+ 0x00, // gap in sequence\r
+ 0x00, // gap in sequence\r
+ 0x00, // gap in sequence\r
+ 0x85, // KEY_KPCOMMA\r
+ 0x90, // KEY_HANGEUL\r
+ 0x91, // KEY_HANJA\r
+ 0x89, // KEY_YEN\r
+ 0xE3, // KEY_LEFTMETA\r
+ 0xE7, // KEY_RIGHTMETA\r
+};
+
+#endif // _XENVKBD_VKBD_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * 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.
+ *
+ * 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.
+ */
+
+#include <windows.h>
+#include <ntverp.h>
+
+
+#undef VER_COMPANYNAME_STR
+#undef VER_PRODUCTNAME_STR
+#undef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION_STR
+
+#include <version.h>
+
+#define VER_COMPANYNAME_STR VENDOR_NAME_STR
+#define VER_LEGALCOPYRIGHT_STR "Copyright (c) Citrix Systems Inc."
+
+#define VER_PRODUCTNAME_STR "XENVKBD"
+#define VER_PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,MICRO_VERSION,BUILD_NUMBER
+#define VER_PRODUCTVERSION_STR MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR
+
+#define VER_INTERNALNAME_STR "XENVKBD.SYS"
+#define VER_FILEDESCRIPTION_STR "XENVKBD"
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+
+#include <common.ver>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Windows 8 Debug|Win32">
+ <Configuration>Windows 8 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 7 Debug|Win32">
+ <Configuration>Windows 7 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows Vista Debug|Win32">
+ <Configuration>Windows Vista Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 8 Release|Win32">
+ <Configuration>Windows 8 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 7 Release|Win32">
+ <Configuration>Windows 7 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows Vista Release|Win32">
+ <Configuration>Windows Vista Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 8 Debug|x64">
+ <Configuration>Windows 8 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 7 Debug|x64">
+ <Configuration>Windows 7 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows Vista Debug|x64">
+ <Configuration>Windows Vista Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 8 Release|x64">
+ <Configuration>Windows 8 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 7 Release|x64">
+ <Configuration>Windows 7 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows Vista Release|x64">
+ <Configuration>Windows Vista Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\configs.props" />
+ <PropertyGroup Label="PropertySheets">
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsApplicationForDrivers8.1</PlatformToolset>
+ <ConfigurationType>Utility</ConfigurationType>
+ <DriverType>Package</DriverType>
+ <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals">
+ <Configuration>Windows Vista Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{73768CC9-DB26-4297-9EC8-1042F815EB15}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="..\targets.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <EnableInf2cat>true</EnableInf2cat>
+ <Inf2CatWindowsVersionList Condition="'$(Platform)'=='x64'">Vista_x64;7_x64;Server2008_x64;Server2008R2_x64;Server8_x64</Inf2CatWindowsVersionList>
+ <Inf2CatWindowsVersionList Condition="'$(Platform)'=='Win32'">Vista_x86;7_x86;Server2008_x86;8_x86</Inf2CatWindowsVersionList>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ <EnableDeployment>False</EnableDeployment>
+ <ImportToStore>False</ImportToStore>
+ <InstallMode>None</InstallMode>
+ <ScriptDeviceQuery>%PathToInf%</ScriptDeviceQuery>
+ <EnableVerifier>False</EnableVerifier>
+ <AllDrivers>False</AllDrivers>
+ <VerifyProjectOutput>True</VerifyProjectOutput>
+ <VerifyFlags>133563</VerifyFlags>
+ <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
+ <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
+ <PackageDir>..\..\xenvkbd\$(DDKPlatform)</PackageDir>
+ </PropertyGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\xenvkbd\xenvkbd.vcxproj">
+ <Project>{C3F96D4C-E441-47F7-A44C-D2D0543C1D18}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\xenvkbd_coinst\xenvkbd_coinst.vcxproj">
+ <Project>{2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(KIT)\Redist\DIFx\dpinst\EngMui\x86\dpinst.exe" Condition="'$(Platform)'=='Win32'" />
+ <FilesToPackage Include="$(KIT)\Redist\DIFx\dpinst\EngMui\x64\dpinst.exe" Condition="'$(Platform)'=='x64'" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SignMode>TestSign</SignMode>
+ <TestCertificate>..\..\src\xenvkbd.pfx</TestCertificate>
+ <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+ </PropertyGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|Win32'">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|Win32'">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|x64'">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|x64'">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|Win32'">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|Win32'">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|x64'">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|x64'">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|Win32'">
+ <TargetVersion>Vista</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|Win32'">
+ <TargetVersion>Vista</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|x64'">
+ <TargetVersion>Vista</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|x64'">
+ <TargetVersion>Vista</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+</Project>
--- /dev/null
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvkbd", "xenvkbd\xenvkbd.vcxproj", "{C3F96D4C-E441-47F7-A44C-D2D0543C1D18}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvkbd_coinst", "xenvkbd_coinst\xenvkbd_coinst.vcxproj", "{2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18} = {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package.vcxproj", "{73768CC9-DB26-4297-9EC8-1042F815EB15}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18} = {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44} = {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Windows 7 Debug|Win32 = Windows 7 Debug|Win32
+ Windows 7 Debug|x64 = Windows 7 Debug|x64
+ Windows 7 Release|Win32 = Windows 7 Release|Win32
+ Windows 7 Release|x64 = Windows 7 Release|x64
+ Windows 8 Debug|Win32 = Windows 8 Debug|Win32
+ Windows 8 Debug|x64 = Windows 8 Debug|x64
+ Windows 8 Release|Win32 = Windows 8 Release|Win32
+ Windows 8 Release|x64 = Windows 8 Release|x64
+ Windows Vista Debug|Win32 = Windows Vista Debug|Win32
+ Windows Vista Debug|x64 = Windows Vista Debug|x64
+ Windows Vista Release|Win32 = Windows Vista Release|Win32
+ Windows Vista Release|x64 = Windows Vista Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Debug|Win32.Build.0 = Windows 7 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Debug|Win32.Deploy.0 = Windows 7 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Debug|x64.ActiveCfg = Windows 7 Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Release|Win32.Build.0 = Windows 7 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Release|Win32.Deploy.0 = Windows 7 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Release|x64.ActiveCfg = Windows 7 Release|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 7 Release|x64.Build.0 = Windows 7 Release|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|Win32.Deploy.0 = Windows 8 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|Win32.Deploy.0 = Windows 8 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Debug|Win32.ActiveCfg = Windows Vista Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Debug|Win32.Build.0 = Windows Vista Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Debug|Win32.Deploy.0 = Windows Vista Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Debug|x64.ActiveCfg = Windows Vista Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Debug|x64.Build.0 = Windows Vista Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Release|Win32.ActiveCfg = Windows Vista Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Release|Win32.Build.0 = Windows Vista Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Release|Win32.Deploy.0 = Windows Vista Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Release|x64.ActiveCfg = Windows Vista Release|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows Vista Release|x64.Build.0 = Windows Vista Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Debug|Win32.Build.0 = Windows 7 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Debug|Win32.Deploy.0 = Windows 7 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Debug|x64.ActiveCfg = Windows 7 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Debug|x64.Deploy.0 = Windows 7 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Release|Win32.Build.0 = Windows 7 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Release|Win32.Deploy.0 = Windows 7 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Release|x64.ActiveCfg = Windows 7 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Release|x64.Build.0 = Windows 7 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 7 Release|x64.Deploy.0 = Windows 7 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|Win32.Deploy.0 = Windows 8 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|x64.Deploy.0 = Windows 8 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|Win32.Deploy.0 = Windows 8 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|x64.Deploy.0 = Windows 8 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Debug|Win32.ActiveCfg = Windows Vista Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Debug|Win32.Build.0 = Windows Vista Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Debug|Win32.Deploy.0 = Windows Vista Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Debug|x64.ActiveCfg = Windows Vista Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Debug|x64.Build.0 = Windows Vista Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Debug|x64.Deploy.0 = Windows Vista Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Release|Win32.ActiveCfg = Windows Vista Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Release|Win32.Build.0 = Windows Vista Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Release|Win32.Deploy.0 = Windows Vista Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Release|x64.ActiveCfg = Windows Vista Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Release|x64.Build.0 = Windows Vista Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows Vista Release|x64.Deploy.0 = Windows Vista Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Debug|Win32.Build.0 = Windows 7 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Debug|Win32.Deploy.0 = Windows 7 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Debug|x64.ActiveCfg = Windows 7 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Debug|x64.Deploy.0 = Windows 7 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Release|Win32.Build.0 = Windows 7 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Release|Win32.Deploy.0 = Windows 7 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Release|x64.ActiveCfg = Windows 7 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Release|x64.Build.0 = Windows 7 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 7 Release|x64.Deploy.0 = Windows 7 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|Win32.Deploy.0 = Windows 8 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|x64.Deploy.0 = Windows 8 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|Win32.Deploy.0 = Windows 8 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|x64.Deploy.0 = Windows 8 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Debug|Win32.ActiveCfg = Windows Vista Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Debug|Win32.Build.0 = Windows Vista Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Debug|Win32.Deploy.0 = Windows Vista Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Debug|x64.ActiveCfg = Windows Vista Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Debug|x64.Build.0 = Windows Vista Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Debug|x64.Deploy.0 = Windows Vista Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Release|Win32.ActiveCfg = Windows Vista Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Release|Win32.Build.0 = Windows Vista Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Release|Win32.Deploy.0 = Windows Vista Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Release|x64.ActiveCfg = Windows Vista Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Release|x64.Build.0 = Windows Vista Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows Vista Release|x64.Deploy.0 = Windows Vista Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\configs.props" />
+ <PropertyGroup Label="Globals">
+ <Configuration>Windows Vista Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Label="PropertySheets">
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{C3F96D4C-E441-47F7-A44C-D2D0543C1D18}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="..\targets.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <EnableInf2cat>false</EnableInf2cat>
+ <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
+ <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>$(WindowsSdkDir)\include\km;..\..\include;..\..\include\xen;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>__MODULE__="XENVKBD";POOL_NX_OPTIN=1;NT_PROCESSOR_GROUPS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>EnableAllWarnings</WarningLevel>
+ <DisableSpecificWarnings>4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnablePREfast>true</EnablePREfast>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalDependencies>$(DDK_LIB_PATH)/Rtlver.lib;$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/aux_klib.lib;$(DDK_LIB_PATH)/ksecdd.lib;$(DDK_LIB_PATH)/procgrp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <EnableCOMDATFolding>false</EnableCOMDATFolding>
+ </Link>
+ <Inf>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <SpecifyDriverVerDirectiveVersion>true</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp>$(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION).$(BUILD_NUMBER)</TimeStamp>
+ <EnableVerbose>true</EnableVerbose>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Inf>
+ <Architecture>x86</Architecture>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Inf>
+ <Architecture>amd64</Architecture>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="../../src/xenvkbd/bus.c" />
+ <ClCompile Include="../../src/xenvkbd/driver.c" />
+ <ClCompile Include="../../src/xenvkbd/fdo.c" />
+ <ClCompile Include="../../src/xenvkbd/frontend.c" />
+ <ClCompile Include="../../src/xenvkbd/pdo.c" />
+ <ClCompile Include="../../src/xenvkbd/registry.c" />
+ <ClCompile Include="../../src/xenvkbd/ring.c" />
+ <ClCompile Include="../../src/xenvkbd/thread.c" />
+ <ClCompile Include="../../src/xenvkbd/hid.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\..\src\xenvkbd\xenvkbd.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="..\xenvkbd.inf" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\package\package.vcxproj" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SignMode>TestSign</SignMode>
+ <TestCertificate>..\..\src\xenvkbd.pfx</TestCertificate>
+ <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+ </PropertyGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\configs.props" />
+ <PropertyGroup Label="PropertySheets">
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsApplicationForDrivers8.1</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals">
+ <Configuration>Windows Vista Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="..\targets.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ <IncludePath>..\..\include;$(IncludePath)</IncludePath>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <EnableInf2cat>false</EnableInf2cat>
+ <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
+ <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <PreprocessorDefinitions>__MODULE__="XENVKBD_COINST";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>EnableAllWarnings</WarningLevel>
+ <DisableSpecificWarnings>4127;4548;4711;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnablePREfast>true</EnablePREfast>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <ModuleDefinitionFile>../../src/coinst/xenvkbd_coinst.def</ModuleDefinitionFile>
+ <AdditionalDependencies>setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\coinst\coinst.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\src\coinst\xenvkbd_coinst.def" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SignMode>TestSign</SignMode>
+ <TestCertificate>..\..\src\xenvkbd.pfx</TestCertificate>
+ <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+ </PropertyGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Windows 10 Debug|Win32">
+ <Configuration>Windows 10 Debug</Configuration>
+ <Platform>Win32</Platform>
+ <WindowsTargetPlatformVersion>10</WindowsTargetPlatformVersion>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 10 Release|Win32">
+ <Configuration>Windows 10 Release</Configuration>
+ <Platform>Win32</Platform>
+ <WindowsTargetPlatformVersion>10</WindowsTargetPlatformVersion>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 10 Debug|x64">
+ <Configuration>Windows 10 Debug</Configuration>
+ <Platform>x64</Platform>
+ <WindowsTargetPlatformVersion>10</WindowsTargetPlatformVersion>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 10 Release|x64">
+ <Configuration>Windows 10 Release</Configuration>
+ <Platform>x64</Platform>
+ <WindowsTargetPlatformVersion>10</WindowsTargetPlatformVersion>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 8 Debug|Win32">
+ <Configuration>Windows 8 Debug</Configuration>
+ <Platform>Win32</Platform>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 8 Release|Win32">
+ <Configuration>Windows 8 Release</Configuration>
+ <Platform>Win32</Platform>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 8 Debug|x64">
+ <Configuration>Windows 8 Debug</Configuration>
+ <Platform>x64</Platform>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Windows 8 Release|x64">
+ <Configuration>Windows 8 Release</Configuration>
+ <Platform>x64</Platform>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ </ProjectConfiguration>
+ </ItemGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\configs.props" />
+ <PropertyGroup Label="PropertySheets">
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Utility</ConfigurationType>
+ <DriverType>Package</DriverType>
+ <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
+ <SupportsPackaging>true</SupportsPackaging>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{73768CC9-DB26-4297-9EC8-1042F815EB15}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="..\targets.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <EnableInf2cat>true</EnableInf2cat>
+ <Inf2CatWindowsVersionList Condition="'$(Platform)'=='x64'">8_x64;Server8_x64;10_x64;Server10_x64</Inf2CatWindowsVersionList>
+ <Inf2CatWindowsVersionList Condition="'$(Platform)'=='Win32'">8_x86;10_x86</Inf2CatWindowsVersionList>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ <EnableDeployment>False</EnableDeployment>
+ <ImportToStore>False</ImportToStore>
+ <InstallMode>None</InstallMode>
+ <ScriptDeviceQuery>%PathToInf%</ScriptDeviceQuery>
+ <EnableVerifier>False</EnableVerifier>
+ <AllDrivers>False</AllDrivers>
+ <VerifyProjectOutput>True</VerifyProjectOutput>
+ <VerifyFlags>133563</VerifyFlags>
+ <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
+ <OutDir>..\..\xenvkbd\$(DDKPlatform)\</OutDir>
+ </PropertyGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\xenvkbd\xenvkbd.vcxproj">
+ <Project>{C3F96D4C-E441-47F7-A44C-D2D0543C1D18}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\xenvkbd_coinst\xenvkbd_coinst.vcxproj">
+ <Project>{2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(DPINST_REDIST)\x86\dpinst.exe" Condition="'$(Platform)'=='Win32'" />
+ <FilesToPackage Include="$(DPINST_REDIST)\x64\dpinst.exe" Condition="'$(Platform)'=='x64'" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SignMode>TestSign</SignMode>
+ <TestCertificate>..\..\src\xenvkbd.pfx</TestCertificate>
+ <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+ </PropertyGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 10 Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 10 Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 10 Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 10 Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|Win32'">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|Win32'">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|x64'">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|x64'">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+</Project>
--- /dev/null
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvkbd", "xenvkbd\xenvkbd.vcxproj", "{C3F96D4C-E441-47F7-A44C-D2D0543C1D18}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvkbd_coinst", "xenvkbd_coinst\xenvkbd_coinst.vcxproj", "{2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18} = {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package.vcxproj", "{73768CC9-DB26-4297-9EC8-1042F815EB15}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18} = {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44} = {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Windows 8 Debug|Win32 = Windows 8 Debug|Win32
+ Windows 8 Debug|x64 = Windows 8 Debug|x64
+ Windows 8 Release|Win32 = Windows 8 Release|Win32
+ Windows 8 Release|x64 = Windows 8 Release|x64
+ Windows 10 Debug|Win32 = Windows 10 Debug|Win32
+ Windows 10 Debug|x64 = Windows 10 Debug|x64
+ Windows 10 Release|Win32 = Windows 10 Release|Win32
+ Windows 10 Release|x64 = Windows 10 Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|Win32.Deploy.0 = Windows 8 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|Win32.Deploy.0 = Windows 8 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Debug|Win32.ActiveCfg = Windows 10 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Debug|Win32.Build.0 = Windows 10 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Debug|Win32.Deploy.0 = Windows 10 Debug|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Debug|x64.ActiveCfg = Windows 10 Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Debug|x64.Build.0 = Windows 10 Debug|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Release|Win32.ActiveCfg = Windows 10 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Release|Win32.Build.0 = Windows 10 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Release|Win32.Deploy.0 = Windows 10 Release|Win32
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Release|x64.ActiveCfg = Windows 10 Release|x64
+ {2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}.Windows 10 Release|x64.Build.0 = Windows 10 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|Win32.Deploy.0 = Windows 8 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Debug|x64.Deploy.0 = Windows 8 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|Win32.Deploy.0 = Windows 8 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 8 Release|x64.Deploy.0 = Windows 8 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Debug|Win32.ActiveCfg = Windows 10 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Debug|Win32.Build.0 = Windows 10 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Debug|Win32.Deploy.0 = Windows 10 Debug|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Debug|x64.ActiveCfg = Windows 10 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Debug|x64.Build.0 = Windows 10 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Debug|x64.Deploy.0 = Windows 10 Debug|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Release|Win32.ActiveCfg = Windows 10 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Release|Win32.Build.0 = Windows 10 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Release|Win32.Deploy.0 = Windows 10 Release|Win32
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Release|x64.ActiveCfg = Windows 10 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Release|x64.Build.0 = Windows 10 Release|x64
+ {73768CC9-DB26-4297-9EC8-1042F815EB15}.Windows 10 Release|x64.Deploy.0 = Windows 10 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|Win32.Deploy.0 = Windows 8 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Debug|x64.Deploy.0 = Windows 8 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|Win32.Deploy.0 = Windows 8 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 8 Release|x64.Deploy.0 = Windows 8 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Debug|Win32.ActiveCfg = Windows 10 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Debug|Win32.Build.0 = Windows 10 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Debug|Win32.Deploy.0 = Windows 10 Debug|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Debug|x64.ActiveCfg = Windows 10 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Debug|x64.Build.0 = Windows 10 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Debug|x64.Deploy.0 = Windows 10 Debug|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Release|Win32.ActiveCfg = Windows 10 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Release|Win32.Build.0 = Windows 10 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Release|Win32.Deploy.0 = Windows 10 Release|Win32
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Release|x64.ActiveCfg = Windows 10 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Release|x64.Build.0 = Windows 10 Release|x64
+ {C3F96D4C-E441-47F7-A44C-D2D0543C1D18}.Windows 10 Release|x64.Deploy.0 = Windows 10 Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\configs.props" />
+ <PropertyGroup Label="PropertySheets">
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{C3F96D4C-E441-47F7-A44C-D2D0543C1D18}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="..\targets.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <EnableInf2cat>false</EnableInf2cat>
+ <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
+ <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>$(WindowsSdkDir)\include\km;..\..\include;..\..\include\xen;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>__MODULE__="XENVKBD";POOL_NX_OPTIN=1;NT_PROCESSOR_GROUPS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>EnableAllWarnings</WarningLevel>
+ <DisableSpecificWarnings>4464;4711;4548;4820;4668;4255;6001;6054;28196;30030;30029;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnablePREfast>true</EnablePREfast>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalDependencies>$(DDK_LIB_PATH)/Rtlver.lib;$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/aux_klib.lib;$(DDK_LIB_PATH)/ksecdd.lib;$(DDK_LIB_PATH)/procgrp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <EnableCOMDATFolding>false</EnableCOMDATFolding>
+ </Link>
+ <Inf>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <SpecifyDriverVerDirectiveVersion>true</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp>$(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION).$(BUILD_NUMBER)</TimeStamp>
+ <EnableVerbose>true</EnableVerbose>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Inf>
+ <Architecture>x86</Architecture>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Inf>
+ <Architecture>amd64</Architecture>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="../../src/xenvkbd/bus.c" />
+ <ClCompile Include="../../src/xenvkbd/driver.c" />
+ <ClCompile Include="../../src/xenvkbd/fdo.c" />
+ <ClCompile Include="../../src/xenvkbd/frontend.c" />
+ <ClCompile Include="../../src/xenvkbd/pdo.c" />
+ <ClCompile Include="../../src/xenvkbd/registry.c" />
+ <ClCompile Include="../../src/xenvkbd/ring.c" />
+ <ClCompile Include="../../src/xenvkbd/thread.c" />
+ <ClCompile Include="../../src/xenvkbd/hid.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\..\src\xenvkbd\xenvkbd.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="..\xenvkbd.inf" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\package\package.vcxproj" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SignMode>TestSign</SignMode>
+ <TestCertificate>..\..\src\xenvkbd.pfx</TestCertificate>
+ <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+ </PropertyGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\configs.props" />
+ <PropertyGroup Label="PropertySheets">
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{2BFAC7E6-3420-47A5-A092-BDC5C9D78A44}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="..\targets.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ <IncludePath>..\..\include;$(IncludePath)</IncludePath>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <EnableInf2cat>false</EnableInf2cat>
+ <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
+ <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <PreprocessorDefinitions>__MODULE__="XENVKBD_COINST";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>EnableAllWarnings</WarningLevel>
+ <DisableSpecificWarnings>4127;4548;4711;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnablePREfast>true</EnablePREfast>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <ModuleDefinitionFile>../../src/coinst/xenvkbd_coinst.def</ModuleDefinitionFile>
+ <AdditionalDependencies>setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\coinst\coinst.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\src\coinst\xenvkbd_coinst.def" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SignMode>TestSign</SignMode>
+ <TestCertificate>..\..\src\xenvkbd.pfx</TestCertificate>
+ <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+ </PropertyGroup>
+</Project>