Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:lashkevi:branches:home:ChronosXYZ
dkms-digimend
_service:obs_scm:digimend-kernel-drivers-0~git2...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:digimend-kernel-drivers-0~git20230503.obscpio of Package dkms-digimend
07070100000000000081A40000000000000000000000016452046B00000027000000000000000000000000000000000000003500000000digimend-kernel-drivers-0~git20230503/.gitattributes.* export-ignore /debian export-ignore 07070100000001000081A40000000000000000000000016452046B0000005B000000000000000000000000000000000000003100000000digimend-kernel-drivers-0~git20230503/.gitignore*.ko *.mod *.mod.c *.o .* *.tar.gz /Module.symvers /modules.order !.travis.yml /cscope.out 07070100000002000081A40000000000000000000000016452046B0000005A000000000000000000000000000000000000003300000000digimend-kernel-drivers-0~git20230503/.kunitconfigCONFIG_KUNIT=y CONFIG_USB=y CONFIG_USB_HID=y CONFIG_HID_UCLOGIC=y CONFIG_HID_KUNIT_TEST=y 07070100000003000081A40000000000000000000000016452046B00000594000000000000000000000000000000000000003200000000digimend-kernel-drivers-0~git20230503/.travis.ymllanguage: c sudo: required compiler: - gcc matrix: include: - os: linux dist: xenial - os: linux dist: trusty - os: linux dist: bionic before_install: - sudo apt-get -qq update - sudo apt-get install -y dpkg-dev debhelper dkms lintian sparse fakeroot - sudo apt-get install linux-headers-`uname -r` - pip install --user ply GitPython before_script: - |- git clone --quiet --depth=1 \ git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git \ ../linux script: - |- ../linux/scripts/checkpatch.pl \ --ignore COMPLEX_MACRO,TRAILING_STATEMENTS \ --show-types \ -f *.[hc] |& tee ../checkpatch.log || [ $? == 1 ] && ! grep -Eiq '^[a-z0-9_]*error:' ../checkpatch.log - make C=1 W=1 KCFLAGS=-Werror # Testing dkms install/uninstall - sudo make dkms_install - sudo make dkms_uninstall # Testing Debian package installation, configuration, and uninstall - dpkg-buildpackage -b -uc # Checks Debian packages for common inconsistencies and errors - lintian -i -I --profile debian --show-overrides ../digimend-dkms_*.changes - sudo apt-get install -y ../digimend-dkms_*_all.deb - sudo apt-get remove -y digimend-dkms - make dist - sudo make install - sudo make uninstall 07070100000004000081A40000000000000000000000016452046B0000002F000000000000000000000000000000000000002D00000000digimend-kernel-drivers-0~git20230503/.vimrcset tabstop=8 set shiftwidth=8 set noexpandtab 07070100000005000081A40000000000000000000000016452046B000046AC000000000000000000000000000000000000002E00000000digimend-kernel-drivers-0~git20230503/COPYING GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. 07070100000006000081A40000000000000000000000016452046B00001067000000000000000000000000000000000000002F00000000digimend-kernel-drivers-0~git20230503/Makefileobj-m := hid-kye.o hid-uclogic.o hid-polostar.o hid-viewsonic.o hid-uclogic-objs := \ hid-uclogic-core.o \ hid-uclogic-rdesc.o \ hid-uclogic-params.o KVERSION := $(shell uname -r) KDIR := /lib/modules/$(KVERSION)/build PWD := $(shell pwd) DESTDIR = UDEV_RULES = $(DESTDIR)/lib/udev/rules.d/90-digimend.rules DEPMOD_CONF = $(DESTDIR)/etc/depmod.d/digimend.conf DRACUT_CONF_DIR = $(DESTDIR)/usr/lib/dracut/dracut.conf.d DRACUT_CONF = $(DRACUT_CONF_DIR)/90-digimend.conf HID_REBIND = $(DESTDIR)/lib/udev/hid-rebind DIGIMEND_DEBUG = $(DESTDIR)/usr/sbin/digimend-debug XORG_CONF := $(DESTDIR)/usr/share/X11/xorg.conf.d/50-digimend.conf PACKAGE_NAME = digimend-kernel-drivers PACKAGE_VERSION = 11 PACKAGE = $(PACKAGE_NAME)-$(PACKAGE_VERSION) DKMS_MODULES_NAME = digimend DKMS_MODULES = $(DKMS_MODULES_NAME)/$(PACKAGE_VERSION) DKMS_SOURCE_DIR = $(DESTDIR)/usr/src/$(DKMS_MODULES_NAME)-$(PACKAGE_VERSION) modules modules_install clean: $(MAKE) -C $(KDIR) M=$(PWD) $@ depmod_conf_install: install -D -m 0644 depmod.conf $(DEPMOD_CONF) depmod -a depmod_conf_uninstall: rm -vf $(DEPMOD_CONF) depmod -a dracut_conf_install: set -e -x; \ if test -e $(DRACUT_CONF_DIR); then \ install -m 0644 dracut.conf $(DRACUT_CONF); \ dracut --force; \ fi dracut_conf_uninstall: set -e -x; \ if test -e $(DRACUT_CONF); then \ rm -v $(DRACUT_CONF); \ dracut --force; \ fi xorg_conf_install: install -D -m 0644 xorg.conf $(XORG_CONF) xorg_conf_uninstall: rm -vf $(XORG_CONF) tools_install: install -D -m 0755 digimend-debug $(DIGIMEND_DEBUG) tools_uninstall: rm -vf $(DIGIMEND_DEBUG) udev_rules_install_files: install -D -m 0755 hid-rebind $(HID_REBIND) install -D -m 0644 udev.rules $(UDEV_RULES) udev_rules_install: udev_rules_install_files udevadm control --reload udev_rules_uninstall_files: rm -vf $(UDEV_RULES) $(HID_REBIND) udev_rules_uninstall: udev_rules_uninstall_files udevadm control --reload modules_uninstall: rm -vf /lib/modules/*/extra/hid-kye.ko \ /lib/modules/*/extra/hid-polostar.ko \ /lib/modules/*/extra/hid-uclogic.ko \ /lib/modules/*/extra/hid-viewsonic.ko install: modules modules_install depmod_conf_install dracut_conf_install udev_rules_install xorg_conf_install tools_install uninstall: tools_uninstall xorg_conf_uninstall udev_rules_uninstall dracut_conf_uninstall depmod_conf_uninstall modules_uninstall dkms_check: @if ! which dkms >/dev/null; then \ echo "DKMS not found, aborting." >&2; \ echo "Make sure DKMS is installed,"; \ echo "and \"make\" is running under sudo, or as root."; \ exit 1; \ fi dkms_source_install: install -m 0755 -d $(DKMS_SOURCE_DIR) install -m 0644 Makefile *.[hc] $(DKMS_SOURCE_DIR) install -m 0755 -d $(DKMS_SOURCE_DIR)/usbhid install -m 0644 usbhid/*.[hc] $(DKMS_SOURCE_DIR)/usbhid dkms_modules_install: dkms_check @if dkms status $(DKMS_MODULES_NAME) | grep . >/dev/null; then \ echo "DKMS has DIGImend modules added already, aborting." >&2; \ echo "Run \"make dkms_uninstall\" first" >&2; \ exit 1; \ fi dkms add . dkms build $(DKMS_MODULES) dkms install $(DKMS_MODULES) dkms_modules_uninstall: dkms_check set -e -x; \ dkms status $(DKMS_MODULES_NAME) | \ while IFS=':' read -r modules status; do \ echo "$$modules" | { \ IFS=',/ ' read -r modules_name modules_version \ kernel_version kernel_arch ignore; \ if [ -z "$$kernel_version" ]; then \ dkms remove \ "$$modules_name/$$modules_version" \ --all; \ else \ dkms remove \ "$$modules_name/$$modules_version" \ -k "$$kernel_version/$$kernel_arch"; \ fi; \ } \ done dkms_install: dkms_modules_install depmod_conf_install dracut_conf_install udev_rules_install xorg_conf_install tools_install dkms_uninstall: tools_uninstall xorg_conf_uninstall udev_rules_uninstall dracut_conf_uninstall depmod_conf_uninstall dkms_modules_uninstall dist: git archive --format=tar.gz --prefix=$(PACKAGE)/ HEAD > $(PACKAGE).tar.gz 07070100000007000081A40000000000000000000000016452046B00003189000000000000000000000000000000000000003000000000digimend-kernel-drivers-0~git20230503/README.mdDIGImend kernel drivers ======================= [![Travis CI Build Status][travis_ci_badge]][travis_ci_page] This is a collection of graphics tablet drivers for the Linux kernel, produced and maintained by the DIGImend project. We maintain this package to provide newer drivers for older kernel versions which don't have them, and to allow users to test new drivers before we contribute them to the mainline kernel. See the [list of supported tablets][supported_tablets] on the [project website][website]. Installing ---------- Kernel v3.5 or newer is required. Download appropriate files for one of the releases from the [releases page][releases]. The "Download ZIP" link on the right of the GitHub page leads to the source of the current development version, use it only if you know what you're doing. ### Installing Debian package ### If you're using Debian or a derived distro, such as Ubuntu, and are installing a release, please use the .deb package. If you're not using a Debian-based distro, or the .deb package didn't work, you can install the driver using DKMS, or manually, as described below. ### Installing from source ### Source is either an unpacked release tarball (.tar.gz file), an unpacked source code archive downloaded from GitHub (.zip file), or source code checked out from Git. Before installing from source in any way, make sure you have the headers for your kernel installed (on Debian-based systems): sudo apt-get install -y "linux-headers-$(uname -r)" or (on Fedora-based systems): sudo dnf install -y "kernel-devel-uname-r == $(uname -r)" If you get "Error: Unable to find a match" from the above command, make sure your kernel is up-to-date, and if not, update it and try again. #### Installing from source with DKMS #### DKMS (Dynamic Kernel Module Support) is a system for installing out-of-tree Linux kernel modules, such as DIGImend kernel drivers. It helps make sure the modules are built with correct kernel headers and are properly installed, and also automatically reinstalls the modules when the kernel is updated. Installing with DKMS is the recommended way of installing development versions of DIGImend kernel drivers. To install with DKMS, make sure you have the `dkms` package installed (on Debian-based distros): sudo apt-get install -y dkms or (on Fedora-based distros): sudo dnf install -y dkms After that, run the following command from the source directory to install: sudo make dkms_install Watch for any errors in the output, and if the drivers installed successfully, they will be automatically rebuilt and reinstalled each time the kernel is updated. #### Installing from source manually #### To install from source manually, first build the drivers. Run the following command in the source directory: make Then, to install the drivers, run this command in the same directory: sudo make install Note that if you have built and installed the drivers this way, you will need to run `make clean` in the source directory, and then redo the above, after each kernel upgrade. #### SSL errors during installation #### On Ubuntu, and possibly other distros, the driver installation process attempts to cryptographically sign the modules being installed. Most of the users don't have the system configured to support this, so during the installation they get error messages similar to these: INSTALL /home/danghai/digimend-kernel-drivers/hid-uclogic.ko At main.c:160: - SSL error:02001002:system library:fopen:No such file or directory: bss_file.c:175 - SSL error:2006D080:BIO routines:BIO_new_file:no such file: bss_file.c:178 sign-file: certs/signing_key.pem: No such file or directory The above basically means that the system tried to sign the module, but couldn't find the key to sign with. This does not interfere with module installation and operation and can safely be ignored. That is, unless you set up module signature verification, but then you would recognize the problem, and would be able to fix it. Configuration ------------- After installing the drivers, make sure the previous versions of the drivers were unloaded. To do that, simply reboot the machine. Alternatively, execute the following command: sudo modprobe -r hid-kye hid-uclogic hid-polostar hid-viewsonic and reconnect the tablet. If your tablet is supported, its pen will work after this, and applications will be able to recognize the pressure after appropriate configuration. Refer to the application documentation for instructions on how to do that, but in most cases it is enough to simply enable the tablet in the application. ### X.org drivers ### By default, your tablet will be handled by the libinput X.org driver (`xserver-xorg-input-libinput` package in Debian, Ubuntu, and derived distros, `xorg-x11-drv-libinput` in Fedora and derived distros). This driver will support reporting pen coordinates and pressure, and some frame controls. Some tablets, however, can work with the Wacom driver, which has support for configuring pressure curves, keyboard shortcuts for buttons on the tablet frame, and other advanced features. This driver package includes configuration enabling Wacom driver for tablets that are known to work with it. For those tablets, all you need to do is make sure the Wacom driver is installed, which is done automatically when installing the driver from the .deb package. In other cases, you can install the driver package (`xserver-xorg-input-wacom` or `xorg-x11-drv-wacom`) yourself. To verify that your tablet is handled by the Wacom driver, see if its devices appear in the output of `xsetwacom list`. ### Enabling Wacom X.org driver ### If this driver package hasn't configured your tablet to work with the Wacom driver, but you know it works, or would like to try to make it work, you can write the following to `/etc/X11/xorg.conf.d/50-tablet.conf` file: Section "InputClass" Identifier "Tablet" Driver "wacom" MatchDevicePath "/dev/input/event*" MatchUSBID "<VID>:<PID>" EndSection Here `<VID>` and `<PID>` would be the tablet's USB vendor and product IDs respectively, as seen in `lsusb` output. E.g. if your tablet's line in `lsusb` output looks like this: Bus 001 Device 003: ID 1234:abcd then your `/etc/X11/xorg.conf.d/50-tablet.conf` should look like this: Section "InputClass" Identifier "Tablet" Driver "wacom" MatchDevicePath "/dev/input/event*" MatchUSBID "1234:abcd" EndSection You will need to log out of your X.org session and login again, or simply restart your machine for these changes to take effect. If your configuration worked, please open an issue, or contribute code directly, to have configuration for your tablet included into this driver package. ### Configuring Wacom X.org driver ### If your tablet is handled by the Wacom driver, you should be able to use the `xsetwacom` tool to configure the advanced features. For example, if `xsetwacom list` produces this output: HID 256c:006e Pad pad id: 9 type: PAD HID 256c:006e Pen stylus id: 10 type: STYLUS you can assign Ctrl-Z ("Undo") key combination to the fifth button on the tablet frame this way: xsetwacom set "HID 256c:006e Pad pad" button 9 key Ctrl Z Note that buttons are numbered 1, 2, 3, 8, 9, 10, and so on, i.e. buttons 4, 5, 6, and 7 are not used. They're reserved for vertical and horizontal scrolling events by the X server. Another example: if `xrandr` output has this line: HDMI-3 connected 1440x900+0+0 (normal left inverted right x axis y axis) 408mm x 255mm you can restrict the tablet input to that display like this: xsetwacom set "HID 256c:006e Pen stylus" MapToOutput HDMI-3 See [the `xsetwacom` man page][xsetwacom_manpage] for more parameters and details. ### Wacom GUI configuration tools ### Note that so far, in most cases, graphical Wacom tablet configuration tools won't work with non-Wacom tablets, and you will need to use the `xsetwacom` tool, even if the Wacom X.org driver supports them. Uninstalling ------------ ### Debian package ### To uninstall a Debian package simply use your favorite package-management tools. ### DKMS-installed package ### To uninstall a DKMS-installed package execute `make dkms_uninstall` as root in the package source directory. ### Manually-installed package ### To uninstall a manually-installed package execute `make uninstall` as root in the package source directory. Upgrading / downgrading ----------------------- ### Manually-installed package ### If you've manually installed a version of this package before, please uninstall it before installing another one, using the sources you used for installation. Building Debian package ----------------------- If you're a developer, or simply want to install a development version of the drivers as a Debian package, make sure you have `dpkg-dev`, `debhelper`, and `dkms` packages installed, and run the following command in the source directory: dpkg-buildpackage -b -uc The resulting package files will be written to the parent directory. Known issues ------------ ### DKMS issues preventing correct installation ### If you're installing Debian packages, or installing from source with DKMS, you might hit one of DKMS bugs which prevent some of the driver modules from installing. They make DKMS produce messages like this: hid-uclogic.ko: Running module version sanity check. Error! Module version 7 for hid-uclogic.ko is not newer than what is already found in kernel 4.9.0-5-amd64 (7). You may override by specifying --force. or this: hid-uclogic.ko.xz: Running module version sanity check. Error! Module version 9 for hid-uclogic.ko.xz is not newer than what is already found in kernel 3.10.0-862.14.4.el7.x86_64 (27A2028780DCB320780F53D). while trying to install the drivers. Fixes for these were accepted upstream ([first fix][dkms_issue1_pr] and [second fix][dkms_issue2_pr]) and should eventually appear in distributions. Meanwhile, to fix the issues, you can apply these yourself, or execute the following command: sudo sed -i \ -e '/^get_module_verinfo()/,+3 s/\<unset res$\|\<res=()$/res=("" "" "")/' \ /usr/sbin/dkms Be aware that the operation of the above command is inexact, and might not work, or might break DKMS. You've been warned. In any case, simply reinstall DKMS to restore it. ### Systems with Secure Boot enabled ### If your system has [Secure Boot][secure_boot] enabled, then the installed driver modules won't be permitted to load. You will see messages like "Required key not available". To make them work, you will need to sign them, or disable Secure Boot entirely. See documentation for your Linux distribution on how to sign kernel modules, or documentation for your computer's UEFI firmware on how to disable Secure Boot. ### Touch ring/strip scrolling doesn't work in Gnome ### Scrolling with a touch ring or a touch strip [doesn't work][gnome_touch_scroll_issue] in Gnome version 3.24 and later. At the moment there doesn't seem to be a workaround beside not using Gnome. Support ------- If you have any problems with the drivers, look through [HOWTOs][howtos] on [the project website][website], and search for solutions and report new issues at [the issues page on GitHub][issues]. If you find somebody has already reported your issue and it's not resolved yet, leave a thumbs-up :thumbsup: reaction on the first post in the issue. This will let developers identify popular issues and pick them first for solving! Join the [#DIGImend channel on irc.libera.chat][irc_channel] to discuss the drivers, tablets, development, to ask for help, and to help others! [travis_ci_badge]: https://travis-ci.org/DIGImend/digimend-kernel-drivers.svg?branch=master [travis_ci_page]: https://travis-ci.org/DIGImend/digimend-kernel-drivers [website]: http://digimend.github.io/ [supported_tablets]: http://digimend.github.io/drivers/digimend/tablets/ [releases]: https://github.com/DIGImend/digimend-kernel-drivers/releases [dkms_issue1_pr]: https://github.com/dell/dkms/pull/47 [dkms_issue2_pr]: https://github.com/dell/dkms/pull/66 [secure_boot]: https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface#Secure_boot [xsetwacom_manpage]: https://www.mankier.com/1/xsetwacom [howtos]: http://digimend.github.io/support/ [issues]: https://github.com/DIGImend/digimend-kernel-drivers/issues [irc_channel]: https://web.libera.chat/#DIGImend [gnome_touch_scroll_issue]: https://gitlab.gnome.org/GNOME/gnome-control-center/issues/118 07070100000008000081A40000000000000000000000016452046B0000056F000000000000000000000000000000000000002F00000000digimend-kernel-drivers-0~git20230503/compat.h/* SPDX-License-Identifier: GPL-2.0+ */ /* * Backported definitions to support building with older kernels */ #ifndef __COMPAT_H #define __COMPAT_H #ifndef HID_CP_CONSUMER_CONTROL #define HID_CP_CONSUMER_CONTROL 0x000c0001 #endif #ifndef HID_GD_SYSTEM_CONTROL #define HID_GD_SYSTEM_CONTROL 0x00010080 #endif #ifndef module_hid_driver /** * module_hid_driver() - Helper macro for registering a HID driver * @__hid_driver: hid_driver struct * * Helper macro for HID drivers which do not do anything special in module * init/exit. This eliminates a lot of boilerplate. Each module may only * use this macro once, and calling it replaces module_init() and module_exit() */ #define module_hid_driver(__hid_driver) \ module_driver(__hid_driver, hid_register_driver, \ hid_unregister_driver) #endif #ifndef from_timer #define from_timer(var, callback_timer, timer_fieldname) \ container_of(callback_timer, typeof(*var), timer_fieldname) #endif /* If we're on an old kernel where setup_timer was still defined */ #ifdef setup_timer /* * Define a replacement of timer_setup found in newer kernels. * NOTE Casting function pointers like this is a dirty hack, * but will probably work, and should do for now. */ #define timer_setup(timer, callback, flags) \ __setup_timer((timer), (void (*)(unsigned long))(callback), \ (unsigned long)(timer), (flags)) #endif #endif 07070100000009000041ED0000000000000000000000036452046B00000000000000000000000000000000000000000000002D00000000digimend-kernel-drivers-0~git20230503/debian0707010000000A000081A40000000000000000000000016452046B0000003A000000000000000000000000000000000000003800000000digimend-kernel-drivers-0~git20230503/debian/.gitignoredebhelper-build-stamp digimend-dkms digimend-dkms.* files 0707010000000B000081A40000000000000000000000016452046B00001199000000000000000000000000000000000000003700000000digimend-kernel-drivers-0~git20230503/debian/changelogdigimend-dkms (11) unstable; urgency=low * Fix uninstallation with newer DKMS versions. * Bring in the latest changes from the (upstream) Linux kernel, listed below. * Add support for Trust Flex Design Tablet / UGTizer GT5040, with PID 0x0077. By Martijn van de Streek. * Add support for Trust Panora (UGEE G5), with VID:PID 145f:0212. By Cristian Klein. * Add support for XP-Pen Deco L. Thank you, José Expósito! -- Nikolai Kondrashov <spbnick@gmail.com> Sun, 07 Aug 2022 18:51:41 +0300 digimend-dkms (10) unstable; urgency=low * Add support for Huion tilt reporting protocol. * Add support for Ugee Rainbow CV720. Thank you, Wang Xuerui! * Handle the new Huion product ID (006d), unlocking support for many new models. * Add support for 13th button on Huion tablet frames. * Do not expose unused input interfaces, to simplify code and reduce user confusion. * Support touch rings and strips on Huion devices. However, this requires the user-space Wacom drivers v0.34.99.1 or older for now. See way too many details about this in issue #275. Also note that Gnome has support for this broken. * Support dials on Huion devices. * Add support for Huion Q620M. * Add support for Huion HS611. * Add pen support for XP-Pen Star 06. Thank you, romanenkor! * Add digimend-debug tool. Now you can make debug messages to appear in your dmesg upon tablet connection, if you run sudo digimend-debug on first. * Fix multiple issues with compatibility with newer kernels and distros. -- Nikolai Kondrashov <spbnick@gmail.com> Sun, 4 Oct 2020 15:23:30 +0300 digimend-dkms (9) unstable; urgency=low * Add support for XP-Pen G640. * Fix support for Ugee M540. * Fix support for Huion WH1409. * Add installation of X.org configuration, which requests the Wacom driver to handle all known compatible tablets, by default. Any X.org configuration for the same tablets in /etc would still override this. * Move installed hid-rebind to /lib/udev -- Nikolai Kondrashov <spbnick@gmail.com> Sat, 15 Dec 2018 17:47:50 +0200 digimend-dkms (8) unstable; urgency=low * Rework the UC-Logic driver to support the new Huion tablets, while keeping support of all the other tablets. This brings support for the following tablets (at least): - Huion H430P - Huion H640P - Huion H950P - Huion New 1060 Plus Thank you to Björn Paetzel and Andrey Zabolotnyi for initial implementation and figuring out proximity detection, to Huion for tablet samples and financing the work, and to all the users for testing and bug reports! * Add support for Ugee G5. Thank you for the tablet sample and financing, Neoblast Inc.! * Add support for XP-Pen Deco 01. Thank you for the initial implementation and testing, kodkuce! * Add "dkms_install" and "dkms_uninstall" targets to the Makefile. These should be used now for installing and uninstalling the driver on all non-Debian based distros, as well as for installing and uninstalling the development versions of the driver. Use "install" and "uninstall" only if those didn't work (and report your issue). * Add "dist" target to the Makefile for building tarballs for external packaging. Thank you, Hai Hoang Dang! * Various documentation fixes and improvements. -- Nikolai Kondrashov <spbnick@gmail.com> Sat, 14 Jul 2018 14:00:00 +0300 digimend-dkms (7) unstable; urgency=low * Add support for building with v4.4 and newer kernels. * Add support for KYE PenSketch M912. Thank you, Milan Plzik! * Fix possible buffer overflow in hid-uclogic.c. Thank you, Dan Carpenter! * Ensure hid-rebind looks for programs in /sbin and /usr/sbin. Fixes #49. * Re-enable tablet on resume. Fixes UC-Logic tablets not working after a suspend/resume cycle. * Add support for KYE EasyPen M406XE. Thank you, Andrey Alekseenko! * Add support for XP-Pen G540. Thank you, slawkis! * Add support for Ugee EX07(S)/XP-Pen star05. * Add support for Ugee M540, which reuses VID:PID of UC-Logic WP5540U. * Add support for Ugee 2150. Thank you, Pierre-Marc Jobin! * Add support for ViewSonic PD1011, aka Signotec Delta PD 10.1. * Fix several issues with the Debian package. Thank you, Martin Owens! -- Nikolai Kondrashov <spbnick@gmail.com> Sun, 11 Feb 2018 15:58:45 +0200 digimend-dkms (6) unstable; urgency=low * Initial Release. -- Nikolai Kondrashov <spbnick@gmail.com> Sun, 05 Apr 2015 15:38:04 +0300 0707010000000C000081A40000000000000000000000016452046B00000003000000000000000000000000000000000000003400000000digimend-kernel-drivers-0~git20230503/debian/compat10 0707010000000D000081A40000000000000000000000016452046B000002ED000000000000000000000000000000000000003500000000digimend-kernel-drivers-0~git20230503/debian/controlSource: digimend-dkms Section: kernel Priority: optional Maintainer: Nikolai Kondrashov <spbnick@gmail.com> Build-Depends: debhelper (>= 10), dkms Standards-Version: 3.9.8 Homepage: https://github.com/DIGImend/digimend-kernel-drivers Vcs-Git: https://github.com/DIGImend/digimend-kernel-drivers.git Vcs-Browser: https://github.com/DIGImend/digimend-kernel-drivers Package: digimend-dkms Architecture: all Depends: ${misc:Depends}, xserver-xorg-input-wacom Description: Collection of graphics tablet drivers by DIGImend project This is a collection of graphics tablet drivers for the Linux kernel, produced and maintained by the DIGImend project. . See http://digimend.github.io/drivers/digimend/tablets/ for a list of supported tablet models. 0707010000000E000081A40000000000000000000000016452046B00000539000000000000000000000000000000000000003700000000digimend-kernel-drivers-0~git20230503/debian/copyrightFormat: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: digimend-kernel-drivers Source: https://github.com/DIGImend/digimend-kernel-drivers Files: * Copyright: 2009 Jiri Kosina <jkosina@suse.cz> 2009 Tomas Hanak <tomas.hanak@gmail.com> 2010-2015 Nikolai Kondrashov <spbnick@gmail.com> 2013 Martin Rusko <martin.rusko@gmail.com> 2015 Yann Vernier <yann.vernier@orsoc.se> License: GPL-2.0+ Files: debian/* Copyright: 2015 Nikolai Kondrashov <spbnick@gmail.com> License: GPL-2.0+ License: GPL-2.0+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/> . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". 0707010000000F000081A40000000000000000000000016452046B0000000A000000000000000000000000000000000000003200000000digimend-kernel-drivers-0~git20230503/debian/docsREADME.md 07070100000010000081A40000000000000000000000016452046B0000015F000000000000000000000000000000000000003600000000digimend-kernel-drivers-0~git20230503/debian/postinst#!/bin/sh set -e case "$1" in configure) if ! udevadm control --reload; then echo "udevadm control --reload failed, ignoring" >&2 fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac #DEBHELPER# exit 0 07070100000011000081A40000000000000000000000016452046B00000163000000000000000000000000000000000000003400000000digimend-kernel-drivers-0~git20230503/debian/postrm#!/bin/sh set -e case "$1" in purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) if ! udevadm control --reload; then echo "udevadm control --reload failed, ignoring" >&2 fi ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 ;; esac #DEBHELPER# exit 0 07070100000012000081ED0000000000000000000000016452046B000003FC000000000000000000000000000000000000003300000000digimend-kernel-drivers-0~git20230503/debian/rules#!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. DH_VERBOSE = 1 # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/default.mk # see FEATURE AREAS in dpkg-buildflags(1) #export DEB_BUILD_MAINT_OPTIONS = hardening=+all # see ENVIRONMENT in dpkg-buildflags(1) # package maintainers to append CFLAGS #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic # package maintainers to append LDFLAGS #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed version := $(shell dpkg-parsechangelog --show-field Version | cut -d'-' -f1) # main packaging script based on dh7 syntax %: dh $@ --with dkms build: override_dh_auto_clean: override_dh_auto_build: override_dh_auto_test: override_dh_auto_install: $(MAKE) DESTDIR=$(CURDIR)/debian/digimend-dkms dkms_source_install udev_rules_install_files xorg_conf_install tools_install override_dh_dkms: dh_dkms -p digimend-dkms -V -- dkms.conf 07070100000013000041ED0000000000000000000000026452046B00000000000000000000000000000000000000000000003400000000digimend-kernel-drivers-0~git20230503/debian/source07070100000014000081A40000000000000000000000016452046B0000000D000000000000000000000000000000000000003B00000000digimend-kernel-drivers-0~git20230503/debian/source/format3.0 (native) 07070100000015000081A40000000000000000000000016452046B000000E8000000000000000000000000000000000000003200000000digimend-kernel-drivers-0~git20230503/depmod.conf# Depmod(8) configuration for DIGImend kernel drivers # # Load DIGImend drivers from the "extra" module subdirectory override hid-kye * extra override hid-polostar * extra override hid-uclogic * extra override hid-viewsonic * extra 07070100000016000081ED0000000000000000000000016452046B00000794000000000000000000000000000000000000003500000000digimend-kernel-drivers-0~git20230503/digimend-debug#!/bin/bash # # Enable/disable debug code in DIGImend kernel drivers. # Author: Nikolai Kondrashov <spbnick@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # set -e -u -o pipefail function usage() { local progname=`basename "$0"` echo "Usage: $progname STATUS" echo "Enable/disable debug code in DIGImend kernel drivers," echo "making sure affected modules are loaded." echo "" echo "Arguments:" echo " STATUS 1/on/enable to enable, 0/off/disable to disable" echo "" } declare -r CONTROL_FILE="/sys/kernel/debug/dynamic_debug/control" declare -r -a MODULE_LIST=("hid_uclogic") if [ "$#" != 1 ]; then echo "Invalid number of arguments" >&2 echo "" >&2 usage >&2 exit 1 fi case "${1,,}" in 0|off|disable) op="-" ;; 1|on|enable) op="+" ;; *) echo "Unknown status: $1" >&2 echo "" >&2 usage >&2 exit 1 ;; esac # Make sure modules are loaded, otherwise enabling will have no effect if ! modprobe -a "${MODULE_LIST[@]}"; then echo "Failed loading DIGImend modules." >&2 echo "Make sure they're installed, and you're root or using sudo." >&2 exit 1 fi if ! [ -r "$CONTROL_FILE" -a -w "$CONTROL_FILE" ]; then echo "Cannot access control file." >&2 echo "Make sure you're root or using sudo." >&2 exit 1 fi for MODULE in "${MODULE_LIST[@]}"; do echo "module ${MODULE} ${op}pmfl" > "$CONTROL_FILE" done 07070100000017000081A40000000000000000000000016452046B00000171000000000000000000000000000000000000003000000000digimend-kernel-drivers-0~git20230503/dkms.confPACKAGE_NAME="digimend" PACKAGE_VERSION="11" AUTOINSTALL="yes" MAKE[0]="make KVERSION=$kernelver" BUILT_MODULE_NAME[0]="hid-kye" BUILT_MODULE_NAME[1]="hid-uclogic" BUILT_MODULE_NAME[2]="hid-polostar" BUILT_MODULE_NAME[3]="hid-viewsonic" DEST_MODULE_LOCATION[0]="/extra" DEST_MODULE_LOCATION[1]="/extra" DEST_MODULE_LOCATION[2]="/extra" DEST_MODULE_LOCATION[3]="/extra" 07070100000018000081A40000000000000000000000016452046B000000CD000000000000000000000000000000000000003200000000digimend-kernel-drivers-0~git20230503/dracut.conf# Explicitly add our modules to initramfs/initrd to override the stock ones # added there, so that tablets work when plugged in before boot. add_drivers+=" hid-kye hid-polostar hid-uclogic hid-viewsonic " 07070100000019000081A40000000000000000000000016452046B00000A99000000000000000000000000000000000000003000000000digimend-kernel-drivers-0~git20230503/hid-ids.h/* SPDX-License-Identifier: GPL-2.0+ */ /* * Definitions from the Linux kernel's private header * drivers/hid/hid-ids.h */ #ifndef HID_IDS_H_FILE #define HID_IDS_H_FILE #define USB_VENDOR_ID_HUION 0x256c #define USB_DEVICE_ID_HUION_TABLET 0x006e #define USB_DEVICE_ID_HUION_TABLET2 0x006d #define USB_VENDOR_ID_KYE 0x0458 #define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 #define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138 #define USB_DEVICE_ID_GENIUS_MANTICORE 0x0153 #define USB_DEVICE_ID_GENIUS_GX_IMPERATOR 0x4018 #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 #define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010 #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011 #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2 0x501a #define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013 #define USB_DEVICE_ID_KYE_PENSKETCH_M912 0x5015 #define USB_DEVICE_ID_KYE_EASYPEN_M406XE 0x5019 #define USB_VENDOR_ID_TRUST 0x145f #define USB_DEVICE_ID_TRUST_PANORA_TABLET 0x0212 #define USB_VENDOR_ID_UCLOGIC 0x5543 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 #define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064 #define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522 #define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781 #define USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3 0x3031 #define USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81 0x0081 #define USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45 0x0045 #define USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47 0x0047 #define USB_DEVICE_ID_YIYNOVA_TABLET 0x004d /* Known as Zippy Technology Corp. in usbutils */ #define USB_VENDOR_ID_POLOSTAR 0x099a #define USB_DEVICE_ID_POLOSTAR_TABLET_PT1001 0x2620 /* UGTizer Technology Corp. */ #define USB_VENDOR_ID_UGTIZER 0x2179 #define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053 #define USB_DEVICE_ID_UGTIZER_TABLET_GT5040 0x0077 /* Ugee Technology / XP-Pen Technology CO. */ #define USB_VENDOR_ID_UGEE 0x28bd #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071 #define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055 /* ViewSonic Corporation */ #define USB_VENDOR_ID_VIEWSONIC 0x0543 #define USB_DEVICE_ID_VIEWSONIC_PD1011 0xe621 /* Signotec GmbH */ #define USB_VENDOR_ID_SIGNOTEC 0x2133 #define USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011 0x0018 #endif 0707010000001A000081A40000000000000000000000016452046B00009F6F000000000000000000000000000000000000003000000000digimend-kernel-drivers-0~git20230503/hid-kye.c// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for Kye/Genius devices not fully compliant with HID standard * * Copyright (c) 2009 Jiri Kosina * Copyright (c) 2009 Tomas Hanak * Copyright (c) 2012 Nikolai Kondrashov */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include <linux/device.h> #include <linux/hid.h> #include <linux/module.h> #include "hid-ids.h" /* Original EasyPen i405X report descriptor size */ #define EASYPEN_I405X_RDESC_ORIG_SIZE 476 /* Fixed EasyPen i405X report descriptor */ static __u8 easypen_i405x_rdesc_fixed[] = { 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ 0x09, 0x01, /* Usage (01h), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x05, /* Report ID (5), */ 0x09, 0x01, /* Usage (01h), */ 0x15, 0x80, /* Logical Minimum (-128), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x07, /* Report Count (7), */ 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x7C, 0x15, /* Physical Maximum (5500), */ 0x26, 0x00, 0x37, /* Logical Maximum (14080), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */ 0x26, 0x00, 0x28, /* Logical Maximum (10240), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; /* Original MousePen i608X report descriptor size */ #define MOUSEPEN_I608X_RDESC_ORIG_SIZE 476 /* Fixed MousePen i608X report descriptor */ static __u8 mousepen_i608x_rdesc_fixed[] = { 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ 0x09, 0x01, /* Usage (01h), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x05, /* Report ID (5), */ 0x09, 0x01, /* Usage (01h), */ 0x15, 0x80, /* Logical Minimum (-128), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x07, /* Report Count (7), */ 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */ 0x26, 0x00, 0x50, /* Logical Maximum (20480), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */ 0x26, 0x00, 0x3C, /* Logical Maximum (15360), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x02, /* Usage (Mouse), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x11, /* Report ID (17), */ 0x09, 0x01, /* Usage (Pointer), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0xA4, /* Push, */ 0x05, 0x09, /* Usage Page (Button), */ 0x75, 0x01, /* Report Size (1), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x03, /* Usage Maximum (03h), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0xB4, /* Pop, */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x75, 0x10, /* Report Size (16), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */ 0x26, 0x00, 0x50, /* Logical Maximum (20480), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */ 0x26, 0x00, 0x3C, /* Logical Maximum (15360), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x75, 0x08, /* Report Size (8), */ 0x09, 0x38, /* Usage (Wheel), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; /* Original MousePen i608X v2 report descriptor size */ #define MOUSEPEN_I608X_V2_RDESC_ORIG_SIZE 482 /* Fixed MousePen i608X v2 report descriptor */ static __u8 mousepen_i608x_v2_rdesc_fixed[] = { 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ 0x09, 0x01, /* Usage (01h), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x05, /* Report ID (5), */ 0x09, 0x01, /* Usage (01h), */ 0x15, 0x80, /* Logical Minimum (-128), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x07, /* Report Count (7), */ 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */ 0x27, 0x00, 0xA0, 0x00, 0x00, /* Logical Maximum (40960), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */ 0x26, 0x00, 0x78, /* Logical Maximum (30720), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x07, /* Logical Maximum (2047), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x02, /* Usage (Mouse), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x11, /* Report ID (17), */ 0x09, 0x01, /* Usage (Pointer), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0xA4, /* Push, */ 0x05, 0x09, /* Usage Page (Button), */ 0x75, 0x01, /* Report Size (1), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x03, /* Usage Maximum (03h), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0xB4, /* Pop, */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x75, 0x10, /* Report Size (16), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */ 0x27, 0x00, 0xA0, 0x00, 0x00, /* Logical Maximum (40960), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */ 0x26, 0x00, 0x78, /* Logical Maximum (30720), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x75, 0x08, /* Report Size (8), */ 0x09, 0x38, /* Usage (Wheel), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; /* Original EasyPen M610X report descriptor size */ #define EASYPEN_M610X_RDESC_ORIG_SIZE 476 /* Fixed EasyPen M610X report descriptor */ static __u8 easypen_m610x_rdesc_fixed[] = { 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ 0x09, 0x01, /* Usage (01h), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x05, /* Report ID (5), */ 0x09, 0x01, /* Usage (01h), */ 0x15, 0x80, /* Logical Minimum (-128), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x07, /* Report Count (7), */ 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x10, 0x27, /* Physical Maximum (10000), */ 0x27, 0x00, 0xA0, 0x00, 0x00, /* Logical Maximum (40960), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x6A, 0x18, /* Physical Maximum (6250), */ 0x26, 0x00, 0x64, /* Logical Maximum (25600), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ 0x05, 0x0C, /* Usage Page (Consumer), */ 0x09, 0x01, /* Usage (Consumer Control), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x12, /* Report ID (18), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x04, /* Report Count (4), */ 0x0A, 0x1A, 0x02, /* Usage (AC Undo), */ 0x0A, 0x79, 0x02, /* Usage (AC Redo Or Repeat), */ 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x01, /* Report Count (1), */ 0x75, 0x14, /* Report Size (20), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x75, 0x20, /* Report Size (32), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0xC0 /* End Collection */ }; /* Original PenSketch M912 report descriptor size */ #define PENSKETCH_M912_RDESC_ORIG_SIZE 482 /* Fixed PenSketch M912 report descriptor */ static __u8 pensketch_m912_rdesc_fixed[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x08, /* Usage (00h), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x05, /* Report ID (5), */ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ 0x09, 0x01, /* Usage (01h), */ 0x15, 0x81, /* Logical Minimum (-127), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x07, /* Report Count (7), */ 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x14, /* Logical Minimum (0), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x27, 0x00, 0xF0, 0x00, 0x00, /* Logical Maximum (61440), */ 0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x27, 0x00, 0xB4, 0x00, 0x00, /* Logical Maximum (46080), */ 0x46, 0x28, 0x23, /* Physical Maximum (9000), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x14, /* Logical Minimum (0), */ 0x26, 0xFF, 0x07, /* Logical Maximum (2047), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x21, /* Usage (Puck), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x11, /* Report ID (17), */ 0x09, 0x21, /* Usage (Puck), */ 0xA0, /* Collection (Physical), */ 0x05, 0x09, /* Usage Page (Button), */ 0x75, 0x01, /* Report Size (1), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x03, /* Usage Maximum (03h), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x01, /* Input (Constant), */ 0x95, 0x01, /* Report Count (1), */ 0x0B, 0x32, 0x00, 0x0D, 0x00, /* Usage (Digitizer In Range), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x81, 0x02, /* Input (Variable), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x14, /* Logical Minimum (0), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x27, 0x00, 0xF0, 0x00, 0x00, /* Logical Maximum (61440), */ 0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x27, 0x00, 0xB4, 0x00, 0x00, /* Logical Maximum (46080), */ 0x46, 0x28, 0x23, /* Physical Maximum (9000), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x38, /* Usage (Wheel), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x01, /* Report Count (1), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x34, /* Physical Minimum (0), */ 0x44, /* Physical Maximum (0), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0xB4, /* Pop, */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ 0x05, 0x0C, /* Usage Page (Consumer), */ 0x09, 0x01, /* Usage (Consumer Control), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x12, /* Report ID (18), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x08, /* Report Count (8), */ 0x05, 0x0C, /* Usage Page (Consumer), */ 0x0A, 0x6A, 0x02, /* Usage (AC Delete), */ 0x0A, 0x1A, 0x02, /* Usage (AC Undo), */ 0x0A, 0x01, 0x02, /* Usage (AC New), */ 0x0A, 0x2F, 0x02, /* Usage (AC Zoom), */ 0x0A, 0x25, 0x02, /* Usage (AC Forward), */ 0x0A, 0x24, 0x02, /* Usage (AC Back), */ 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x30, /* Report Count (48), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0xC0 /* End Collection */ }; /* Original EasyPen M406XE report descriptor size */ #define EASYPEN_M406XE_RDESC_ORIG_SIZE 476 /* Fixed EasyPen M406XE report descriptor */ static __u8 easypen_m406xe_rdesc_fixed[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x01, /* Usage (01h), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x05, /* Report ID (5), */ 0x09, 0x01, /* Usage (01h), */ 0x15, 0x80, /* Logical Minimum (-128), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x07, /* Report Count (7), */ 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */ 0x26, 0x00, 0x3C, /* Logical Maximum (15360), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */ 0x26, 0x00, 0x28, /* Logical Maximum (10240), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection */ 0x05, 0x0C, /* Usage Page (Consumer), */ 0x09, 0x01, /* Usage (Consumer Control), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x12, /* Report ID (18), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x04, /* Report Count (4), */ 0x0A, 0x79, 0x02, /* Usage (AC Redo Or Repeat), */ 0x0A, 0x1A, 0x02, /* Usage (AC Undo), */ 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x34, /* Report Count (52), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0xC0 /* End Collection */ }; static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize, int offset, const char *device_name) { /* * the fixup that need to be done: * - change Usage Maximum in the Consumer Control * (report ID 3) to a reasonable value */ if (*rsize >= offset + 31 && /* Usage Page (Consumer Devices) */ rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c && /* Usage (Consumer Control) */ rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 && /* Usage Maximum > 12287 */ rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) { hid_info(hdev, "fixing up %s report descriptor\n", device_name); rdesc[offset + 12] = 0x2f; } return rdesc; } static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { switch (hdev->product) { case USB_DEVICE_ID_KYE_ERGO_525V: /* the fixups that need to be done: * - change led usage page to button for extra buttons * - report size 8 count 1 must be size 1 count 8 for button * bitfield * - change the button usage range to 4-7 for the extra * buttons */ if (*rsize >= 75 && rdesc[61] == 0x05 && rdesc[62] == 0x08 && rdesc[63] == 0x19 && rdesc[64] == 0x08 && rdesc[65] == 0x29 && rdesc[66] == 0x0f && rdesc[71] == 0x75 && rdesc[72] == 0x08 && rdesc[73] == 0x95 && rdesc[74] == 0x01) { hid_info(hdev, "fixing up Kye/Genius Ergo Mouse report descriptor\n"); rdesc[62] = 0x09; rdesc[64] = 0x04; rdesc[66] = 0x07; rdesc[72] = 0x01; rdesc[74] = 0x08; } break; case USB_DEVICE_ID_KYE_EASYPEN_I405X: if (*rsize == EASYPEN_I405X_RDESC_ORIG_SIZE) { rdesc = easypen_i405x_rdesc_fixed; *rsize = sizeof(easypen_i405x_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) { rdesc = mousepen_i608x_rdesc_fixed; *rsize = sizeof(mousepen_i608x_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2: if (*rsize == MOUSEPEN_I608X_V2_RDESC_ORIG_SIZE) { rdesc = mousepen_i608x_v2_rdesc_fixed; *rsize = sizeof(mousepen_i608x_v2_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_EASYPEN_M610X: if (*rsize == EASYPEN_M610X_RDESC_ORIG_SIZE) { rdesc = easypen_m610x_rdesc_fixed; *rsize = sizeof(easypen_m610x_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_EASYPEN_M406XE: if (*rsize == EASYPEN_M406XE_RDESC_ORIG_SIZE) { rdesc = easypen_m406xe_rdesc_fixed; *rsize = sizeof(easypen_m406xe_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_PENSKETCH_M912: if (*rsize == PENSKETCH_M912_RDESC_ORIG_SIZE) { rdesc = pensketch_m912_rdesc_fixed; *rsize = sizeof(pensketch_m912_rdesc_fixed); } break; case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE: rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104, "Genius Gila Gaming Mouse"); break; case USB_DEVICE_ID_GENIUS_GX_IMPERATOR: rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83, "Genius Gx Imperator Keyboard"); break; case USB_DEVICE_ID_GENIUS_MANTICORE: rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104, "Genius Manticore Keyboard"); break; } return rdesc; } /** * Enable fully-functional tablet mode by setting a special feature report. * * @hdev: HID device * * The specific report ID and data were discovered by sniffing the * Windows driver traffic. */ static int kye_tablet_enable(struct hid_device *hdev) { struct list_head *list; struct list_head *head; struct hid_report *report; __s32 *value; list = &hdev->report_enum[HID_FEATURE_REPORT].report_list; list_for_each(head, list) { report = list_entry(head, struct hid_report, list); if (report->id == 5) break; } if (head == list) { hid_err(hdev, "tablet-enabling feature report not found\n"); return -ENODEV; } if (report->maxfield < 1 || report->field[0]->report_count < 7) { hid_err(hdev, "invalid tablet-enabling feature report\n"); return -ENODEV; } value = report->field[0]->value; value[0] = 0x12; value[1] = 0x10; value[2] = 0x11; value[3] = 0x12; value[4] = 0x00; value[5] = 0x00; value[6] = 0x00; hid_hw_request(hdev, report, HID_REQ_SET_REPORT); return 0; } static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; /* Assign quirks missing from global hid_blacklist */ switch (id->product) { case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2: case USB_DEVICE_ID_KYE_PENSKETCH_M912: case USB_DEVICE_ID_KYE_EASYPEN_M406XE: hdev->quirks |= HID_QUIRK_MULTI_INPUT; break; } ret = hid_parse(hdev); if (ret) { hid_err(hdev, "parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { hid_err(hdev, "hw start failed\n"); goto err; } switch (id->product) { case USB_DEVICE_ID_KYE_EASYPEN_I405X: case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2: case USB_DEVICE_ID_KYE_EASYPEN_M610X: case USB_DEVICE_ID_KYE_EASYPEN_M406XE: case USB_DEVICE_ID_KYE_PENSKETCH_M912: ret = kye_tablet_enable(hdev); if (ret) { hid_err(hdev, "tablet enabling failed\n"); goto enabling_err; } break; case USB_DEVICE_ID_GENIUS_MANTICORE: /* * The manticore keyboard needs to have all the interfaces * opened at least once to be fully functional. */ if (hid_hw_open(hdev)) hid_hw_close(hdev); break; } return 0; enabling_err: hid_hw_stop(hdev); err: return ret; } static const struct hid_device_id kye_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_MANTICORE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912) }, { } }; MODULE_DEVICE_TABLE(hid, kye_devices); static struct hid_driver kye_driver = { .name = "kye", .id_table = kye_devices, .probe = kye_probe, .report_fixup = kye_report_fixup, }; module_hid_driver(kye_driver); MODULE_LICENSE("GPL"); MODULE_VERSION("11"); 0707010000001B000081A40000000000000000000000016452046B0000265C000000000000000000000000000000000000003500000000digimend-kernel-drivers-0~git20230503/hid-polostar.c// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for Polostar devices not fully compliant with HID standard * * Copyright (c) 2015 Yann Vernier */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include <linux/device.h> #include <linux/hid.h> #include <linux/module.h> #include <linux/usb.h> #include "hid-ids.h" /* Size of the original descriptor of PT-1001 tablets */ #define PT1001_RDESC_ORIG_SIZE 317 /* Fixed PT1001 report descriptor */ static __u8 pt1001_rdesc_fixed[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x02, /* Usage (Mouse), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x01, /* Report ID (1), */ 0x09, 0x01, /* Usage (Pointer), */ 0xA1, 0x00, /* Collection (Physical), */ 0x05, 0x09, /* Usage Page (Button), */ /* Swap mouse buttons for consistency with tablets */ 0x09, 0x01, /* Usage (1), */ 0x09, 0x03, /* Usage (3), */ 0x09, 0x02, /* Usage (2), */ 0x09, 0x04, /* Usage (4), */ 0x09, 0x05, /* Usage (5), */ 0x95, 0x05, /* Report Count (5), */ 0x75, 0x01, /* Report Size (1), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x95, 0x02, /* Report Count (2), */ 0x75, 0x10, /* Report Size (16), */ 0x16, 0x01, 0x80, /* Logical Minimum (-32767), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x06, /* Input (Variable, Relative), */ /* Scroll functionality */ 0x15, 0x81, /* Logical Minimum (-127), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x01, /* Report Count (2), */ 0x09, 0x38, /* Usage (Wheel), */ 0x05, 0x0C, /* Usage Page (Consumer), */ 0x0A, 0x38, 0x02, /* Usage (AC Pan), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ /* Report ID 5 is used for some periphery buttons */ 0x05, 0x0C, /* Usage Page (Consumer), */ 0x09, 0x01, /* Usage (Consumer Control), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x05, /* Report ID (5), */ 0x95, 0x01, /* Report Count (1), */ 0x75, 0x08, /* Report Size (8), */ 0x81, 0x01, /* Input (Constant), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x12, /* Report Count (18), */ 0x0A, 0x83, 0x01, /* Usage (AL Consumer Control Config), */ 0x0A, 0x8A, 0x01, /* Usage (AL Email Reader), */ 0x0A, 0x92, 0x01, /* Usage (AL Calculator), */ 0x0A, 0x94, 0x01, /* Usage (AL Local Machine Brwsr), */ 0x0A, 0x21, 0x02, /* Usage (AC Search), */ 0x0A, 0x23, 0x02, /* Usage (AC Home), */ 0x0A, 0x24, 0x02, /* Usage (AC Back), */ 0x0A, 0x25, 0x02, /* Usage (AC Forward), */ 0x0A, 0x26, 0x02, /* Usage (AC Stop), */ 0x0A, 0x27, 0x02, /* Usage (AC Refresh), */ 0x0A, 0x2A, 0x02, /* Usage (AC Bookmarks), */ 0x09, 0xB5, /* Usage (Scan Next Track), */ 0x09, 0xB6, /* Usage (Scan Previous Track), */ 0x09, 0xB7, /* Usage (Stop), */ 0x09, 0xCD, /* Usage (Play Pause), */ 0x09, 0xE2, /* Usage (Mute), */ 0x09, 0xE9, /* Usage (Volume Inc), */ 0x09, 0xEA, /* Usage (Volume Dec), */ 0x81, 0x62, /* Input (Variable, No Preferred, */ /* Null State), */ 0x95, 0x06, /* Report Count (6), */ 0x75, 0x01, /* Report Size (1), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0xC0, /* End Collection, */ /* Report 9 is the primary digitizer report. */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA1, 0x00, /* Collection (Physical), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x75, 0x01, /* Report Size (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x26, 0x00, 0x10, /* Logical Maximum (4096), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xa4, /* Push */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xfe, /* Unit exponent -2: cm -> 0.1mm */ 0x65, 0x11, /* Unit: SI linear centimeters */ 0x09, 0x30, /* Usage (X), */ 0x35, 0x00, /* Physical Minimum (0), */ 0x46, 0x20, 0x04, /* Physical Maximum (1056), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x94, 0x02, /* Physical Maximum (660), */ 0x81, 0x02, /* Input (Variable), */ 0xb4, /* Pop (restore no unit) */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection */ }; static __u8 *polostar_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { struct usb_interface *iface = to_usb_interface(hdev->dev.parent); __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber; switch (hdev->product) { case USB_DEVICE_ID_POLOSTAR_TABLET_PT1001: if (iface_num == 1 && *rsize == PT1001_RDESC_ORIG_SIZE) { rdesc = pt1001_rdesc_fixed; *rsize = sizeof(pt1001_rdesc_fixed); } break; } return rdesc; } static int polostar_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct usb_interface *iface = to_usb_interface(hdev->dev.parent); __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber; int rc; if (hdev->product == USB_DEVICE_ID_POLOSTAR_TABLET_PT1001 && iface_num == 2) return -ENODEV; hdev->quirks |= id->driver_data; rc = hid_parse(hdev); if (rc) { hid_err(hdev, "parse failed\n"); return rc; } rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (rc) { hid_err(hdev, "hw start failed\n"); return rc; } return 0; } static const struct hid_device_id polostar_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_POLOSTAR, USB_DEVICE_ID_POLOSTAR_TABLET_PT1001), .driver_data = HID_QUIRK_MULTI_INPUT }, { } }; MODULE_DEVICE_TABLE(hid, polostar_devices); static struct hid_driver polostar_driver = { .name = "polostar", .id_table = polostar_devices, .probe = polostar_probe, .report_fixup = polostar_report_fixup, }; module_hid_driver(polostar_driver); MODULE_LICENSE("GPL"); MODULE_VERSION("11"); 0707010000001C000081ED0000000000000000000000016452046B00000AB7000000000000000000000000000000000000003100000000digimend-kernel-drivers-0~git20230503/hid-rebind#!/bin/sh # # Rebind HID device to specific driver. # Author: Nikolai Kondrashov <spbnick@gmail.com> # # To be used with udev rules like this one: # SUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:0000172F:*", \ # RUN+="/usr/local/bin/hid-rebind" # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # set -e -u export PATH="/sbin:/usr/sbin:$PATH" progname=`basename "$0"` # Write a string to a file, ignoring ENODEV. write_ignore_enodev() { local str="$1" local path="$2" local output # Write the string with tee, capturing error output if ! output=`echo "$str" | tee "$path" 2>&1 >/dev/null`; then # Raise anything except ENODEV if test "${output##*: }" != "No such device"; then echo "$output" >&2 return 1 fi fi } { id=`basename "$DEVPATH"` cur_driver_path=`readlink -v -f "/sys${DEVPATH}/driver"` if test -e "$cur_driver_path"; then cur_driver=`basename "$cur_driver_path"` else cur_driver="" fi # Choose a matching module installed under /extra or /updates new_module=$( modprobe -R "$MODALIAS" | tr - _ | while read -r m; do if modinfo -F filename "$m" | grep -q '/extra/\|/updates/'; then echo "$m" break fi done ) if test -z "$new_module"; then exit 0 fi # Assume the driver will be called the same as module, # but without the "hid_" prefix new_driver="${new_module#hid_}" new_driver_path="/sys/bus/hid/drivers/$new_driver" if test "$new_driver" = "$cur_driver"; then exit 0 fi logger -p daemon.notice -t "$progname" \ "rebinding $DEVPATH to \"$new_driver\" driver" # Ensure the new driver module is loaded modprobe "$new_module" # Unbind from the current driver, if any if test -e "$cur_driver_path"; then write_ignore_enodev "$id" "$cur_driver_path/unbind" fi # Bind to the new driver write_ignore_enodev "$id" "$new_driver_path/bind" } 2>&1 | logger -p daemon.warning -t "$progname" 0707010000001D000081A40000000000000000000000016452046B00003BD2000000000000000000000000000000000000003900000000digimend-kernel-drivers-0~git20230503/hid-uclogic-core.c// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for UC-Logic devices not fully compliant with HID standard * * Copyright (c) 2010-2014 Nikolai Kondrashov * Copyright (c) 2013 Martin Rusko */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include <linux/device.h> #include <linux/hid.h> #include <linux/module.h> #include <linux/timer.h> #include "usbhid/usbhid.h" #include "hid-uclogic-params.h" #include "hid-ids.h" #include "compat.h" #include <linux/version.h> /* Driver data */ struct uclogic_drvdata { /* Interface parameters */ struct uclogic_params params; /* Pointer to the replacement report descriptor. NULL if none. */ __u8 *desc_ptr; /* * Size of the replacement report descriptor. * Only valid if desc_ptr is not NULL */ unsigned int desc_size; /* Pen input device */ struct input_dev *pen_input; /* In-range timer */ struct timer_list inrange_timer; /* Last rotary encoder state, or U8_MAX for none */ u8 re_state; }; /** * uclogic_inrange_timeout - handle pen in-range state timeout. * Emulate input events normally generated when pen goes out of range for * tablets which don't report that. * * @t: The timer the timeout handler is attached to, stored in a struct * uclogic_drvdata. */ static void uclogic_inrange_timeout(struct timer_list *t) { struct uclogic_drvdata *drvdata = from_timer(drvdata, t, inrange_timer); struct input_dev *input = drvdata->pen_input; if (input == NULL) return; input_report_abs(input, ABS_PRESSURE, 0); /* If BTN_TOUCH state is changing */ if (test_bit(BTN_TOUCH, input->key)) { input_event(input, EV_MSC, MSC_SCAN, /* Digitizer Tip Switch usage */ 0xd0042); input_report_key(input, BTN_TOUCH, 0); } input_report_key(input, BTN_TOOL_PEN, 0); input_sync(input); } static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); if (drvdata->desc_ptr != NULL) { rdesc = drvdata->desc_ptr; *rsize = drvdata->desc_size; } return rdesc; } static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); struct uclogic_params *params = &drvdata->params; /* Discard invalid pen usages */ if (params->pen.usage_invalid && (field->application == HID_DG_PEN)) return -1; /* Let hid-core decide what to do */ return 0; } #if KERNEL_VERSION(4, 4, 0) > LINUX_VERSION_CODE #define RETURN_SUCCESS return static void uclogic_input_configured(struct hid_device *hdev, struct hid_input *hi) #else #define RETURN_SUCCESS return 0 static int uclogic_input_configured(struct hid_device *hdev, struct hid_input *hi) #endif { struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); struct uclogic_params *params = &drvdata->params; char *name; const char *suffix = NULL; struct hid_field *field; size_t len; size_t i; const struct uclogic_params_frame *frame; /* no report associated (HID_QUIRK_MULTI_INPUT not set) */ if (!hi->report) RETURN_SUCCESS; /* * If this is the input corresponding to the pen report * in need of tweaking. */ if (hi->report->id == params->pen.id) { /* Remember the input device so we can simulate events */ drvdata->pen_input = hi->input; } /* If it's one of the frame devices */ for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { frame = ¶ms->frame_list[i]; if (hi->report->id == frame->id) { /* Assign custom suffix, if any */ suffix = frame->suffix; /* * Disable EV_MSC reports for touch ring interfaces to * make the Wacom driver pickup touch ring extents */ if (frame->touch_byte > 0) __clear_bit(EV_MSC, hi->input->evbit); } } if (!suffix) { field = hi->report->field[0]; switch (field->application) { case HID_GD_KEYBOARD: suffix = "Keyboard"; break; case HID_GD_MOUSE: suffix = "Mouse"; break; case HID_GD_KEYPAD: suffix = "Pad"; break; case HID_DG_PEN: suffix = "Pen"; break; case HID_CP_CONSUMER_CONTROL: suffix = "Consumer Control"; break; case HID_GD_SYSTEM_CONTROL: suffix = "System Control"; break; } } if (suffix) { len = strlen(hdev->name) + 2 + strlen(suffix); name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL); if (name) { snprintf(name, len, "%s %s", hdev->name, suffix); hi->input->name = name; } } RETURN_SUCCESS; } #undef RETURN_SUCCESS static int uclogic_probe(struct hid_device *hdev, const struct hid_device_id *id) { int rc; struct uclogic_drvdata *drvdata = NULL; bool params_initialized = false; /* * libinput requires the pad interface to be on a different node * than the pen, so use QUIRK_MULTI_INPUT for all tablets. */ hdev->quirks |= HID_QUIRK_MULTI_INPUT; #ifdef HID_QUIRK_NO_EMPTY_INPUT hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT; #endif /* Allocate and assign driver data */ drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); if (drvdata == NULL) { rc = -ENOMEM; goto failure; } timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0); drvdata->re_state = U8_MAX; hid_set_drvdata(hdev, drvdata); /* Initialize the device and retrieve interface parameters */ rc = uclogic_params_init(&drvdata->params, hdev); if (rc != 0) { hid_err(hdev, "failed probing parameters: %d\n", rc); goto failure; } params_initialized = true; hid_dbg(hdev, "parameters:\n"); uclogic_params_hid_dbg(hdev, &drvdata->params); if (drvdata->params.invalid) { hid_info(hdev, "interface is invalid, ignoring\n"); rc = -ENODEV; goto failure; } /* Generate replacement report descriptor */ rc = uclogic_params_get_desc(&drvdata->params, &drvdata->desc_ptr, &drvdata->desc_size); if (rc) { hid_err(hdev, "failed generating replacement report descriptor: %d\n", rc); goto failure; } rc = hid_parse(hdev); if (rc) { hid_err(hdev, "parse failed\n"); goto failure; } rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (rc) { hid_err(hdev, "hw start failed\n"); goto failure; } return 0; failure: /* Assume "remove" might not be called if "probe" failed */ if (params_initialized) uclogic_params_cleanup(&drvdata->params); return rc; } #ifdef CONFIG_PM static int uclogic_resume(struct hid_device *hdev) { int rc; struct uclogic_params params; /* Re-initialize the device, but discard parameters */ rc = uclogic_params_init(¶ms, hdev); if (rc != 0) hid_err(hdev, "failed to re-initialize the device\n"); else uclogic_params_cleanup(¶ms); return rc; } #endif /** * uclogic_raw_event_pen - handle raw pen events (pen HID reports). * * @drvdata: Driver data. * @data: Report data buffer, can be modified. * @size: Report data size, bytes. * * Returns: * Negative value on error (stops event delivery), zero for success. */ static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata, u8 *data, int size) { struct uclogic_params_pen *pen = &drvdata->params.pen; WARN_ON(drvdata == NULL); WARN_ON(data == NULL && size != 0); /* If in-range reports are inverted */ if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) { /* Invert the in-range bit */ data[1] ^= 0x40; } /* * If report contains fragmented high-resolution pen * coordinates */ if (size >= 10 && pen->fragmented_hires) { u8 pressure_low_byte; u8 pressure_high_byte; /* Lift pressure bytes */ pressure_low_byte = data[6]; pressure_high_byte = data[7]; /* * Move Y coord to make space for high-order X * coord byte */ data[6] = data[5]; data[5] = data[4]; /* Move high-order X coord byte */ data[4] = data[8]; /* Move high-order Y coord byte */ data[7] = data[9]; /* Place pressure bytes */ data[8] = pressure_low_byte; data[9] = pressure_high_byte; } /* If we need to emulate in-range detection */ if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) { /* Set in-range bit */ data[1] |= 0x40; /* (Re-)start in-range timeout */ mod_timer(&drvdata->inrange_timer, jiffies + msecs_to_jiffies(100)); } /* If we report tilt and Y direction is flipped */ if (size >= 12 && pen->tilt_y_flipped) data[11] = -data[11]; return 0; } /** * uclogic_raw_event_frame - handle raw frame events (frame HID reports). * * @drvdata: Driver data. * @frame: The parameters of the frame controls to handle. * @data: Report data buffer, can be modified. * @size: Report data size, bytes. * * Returns: * Negative value on error (stops event delivery), zero for success. */ static int uclogic_raw_event_frame( struct uclogic_drvdata *drvdata, const struct uclogic_params_frame *frame, u8 *data, int size) { WARN_ON(drvdata == NULL); WARN_ON(data == NULL && size != 0); /* If need to, and can, set pad device ID for Wacom drivers */ if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) { /* If we also have a touch ring and the finger left it */ if (frame->touch_byte > 0 && frame->touch_byte < size && data[frame->touch_byte] == 0) { data[frame->dev_id_byte] = 0; } else { data[frame->dev_id_byte] = 0xf; } } /* If need to, and can, read rotary encoder state change */ if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) { unsigned int byte = frame->re_lsb / 8; unsigned int bit = frame->re_lsb % 8; u8 change; u8 prev_state = drvdata->re_state; /* Read Gray-coded state */ u8 state = (data[byte] >> bit) & 0x3; /* Encode state change into 2-bit signed integer */ if ((prev_state == 1 && state == 0) || (prev_state == 2 && state == 3)) { change = 1; } else if ((prev_state == 2 && state == 0) || (prev_state == 1 && state == 3)) { change = 3; } else { change = 0; } /* Write change */ data[byte] = (data[byte] & ~((u8)3 << bit)) | (change << bit); /* Remember state */ drvdata->re_state = state; } /* If need to, and can, transform the touch ring reports */ if (frame->touch_byte > 0 && frame->touch_byte < size) { __s8 value = data[frame->touch_byte]; if (value != 0) { if (frame->touch_flip_at != 0) { value = frame->touch_flip_at - value; if (value <= 0) value = frame->touch_max + value; } data[frame->touch_byte] = value - 1; } } /* If need to, and can, transform the bitmap dial reports */ if (frame->bitmap_dial_byte > 0 && frame->bitmap_dial_byte < size) { if (data[frame->bitmap_dial_byte] == 2) data[frame->bitmap_dial_byte] = -1; } return 0; } static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { unsigned int report_id = report->id; struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); struct uclogic_params *params = &drvdata->params; struct uclogic_params_pen_subreport *subreport; struct uclogic_params_pen_subreport *subreport_list_end; size_t i; /* Do not handle anything but input reports */ if (report->type != HID_INPUT_REPORT) return 0; while (true) { /* Tweak pen reports, if necessary */ if ((report_id == params->pen.id) && (size >= 2)) { subreport_list_end = params->pen.subreport_list + ARRAY_SIZE(params->pen.subreport_list); /* Try to match a subreport */ for (subreport = params->pen.subreport_list; subreport < subreport_list_end; subreport++) { if (subreport->value != 0 && subreport->value == data[1]) { break; } } /* If a subreport matched */ if (subreport < subreport_list_end) { /* Change to subreport ID, and restart */ report_id = data[0] = subreport->id; continue; } else { return uclogic_raw_event_pen(drvdata, data, size); } } /* Tweak frame control reports, if necessary */ for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { if (report_id == params->frame_list[i].id) { return uclogic_raw_event_frame( drvdata, ¶ms->frame_list[i], data, size); } } break; } return 0; } static void uclogic_remove(struct hid_device *hdev) { struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); del_timer_sync(&drvdata->inrange_timer); hid_hw_stop(hdev); kfree(drvdata->desc_ptr); uclogic_params_cleanup(&drvdata->params); } static const struct hid_device_id uclogic_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET2) }, { HID_USB_DEVICE(USB_VENDOR_ID_TRUST, USB_DEVICE_ID_TRUST_PANORA_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GT5040) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_G5) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, { } }; MODULE_DEVICE_TABLE(hid, uclogic_devices); static struct hid_driver uclogic_driver = { .name = "uclogic", .id_table = uclogic_devices, .probe = uclogic_probe, .remove = uclogic_remove, .report_fixup = uclogic_report_fixup, .raw_event = uclogic_raw_event, .input_mapping = uclogic_input_mapping, .input_configured = uclogic_input_configured, #ifdef CONFIG_PM .resume = uclogic_resume, .reset_resume = uclogic_resume, #endif }; module_hid_driver(uclogic_driver); MODULE_AUTHOR("Martin Rusko"); MODULE_AUTHOR("Nikolai Kondrashov"); MODULE_LICENSE("GPL"); MODULE_VERSION("11"); 0707010000001E000081A40000000000000000000000016452046B0000AA8F000000000000000000000000000000000000003B00000000digimend-kernel-drivers-0~git20230503/hid-uclogic-params.c// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for UC-Logic devices not fully compliant with HID standard * - tablet initialization and parameter retrieval * * Copyright (c) 2018 Nikolai Kondrashov */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include "hid-uclogic-params.h" #include "hid-uclogic-rdesc.h" #include "usbhid/usbhid.h" #include "hid-ids.h" #include <linux/ctype.h> #include <asm/unaligned.h> #include <linux/version.h> /** * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type * to a string. * * @inrange: The in-range reporting type to convert. * * Returns: * The string representing the type, or NULL if the type is unknown. */ static const char *uclogic_params_pen_inrange_to_str( enum uclogic_params_pen_inrange inrange) { switch (inrange) { case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL: return "normal"; case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED: return "inverted"; case UCLOGIC_PARAMS_PEN_INRANGE_NONE: return "none"; default: return NULL; } } /** * Dump tablet interface pen parameters with hid_dbg(), indented with one tab. * * @hdev: The HID device the pen parameters describe. * @pen: The pen parameters to dump. */ static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev, const struct uclogic_params_pen *pen) { size_t i; hid_dbg(hdev, "\t.usage_invalid = %s\n", (pen->usage_invalid ? "true" : "false")); hid_dbg(hdev, "\t.desc_ptr = %p\n", pen->desc_ptr); hid_dbg(hdev, "\t.desc_size = %u\n", pen->desc_size); hid_dbg(hdev, "\t.id = %u\n", pen->id); hid_dbg(hdev, "\t.subreport_list = {\n"); for (i = 0; i < ARRAY_SIZE(pen->subreport_list); i++) { hid_dbg(hdev, "\t\t{0x%02hhx, %hhu}%s\n", pen->subreport_list[i].value, pen->subreport_list[i].id, i < (ARRAY_SIZE(pen->subreport_list) - 1) ? "," : ""); } hid_dbg(hdev, "\t}\n"); hid_dbg(hdev, "\t.inrange = %s\n", uclogic_params_pen_inrange_to_str(pen->inrange)); hid_dbg(hdev, "\t.fragmented_hires = %s\n", (pen->fragmented_hires ? "true" : "false")); hid_dbg(hdev, "\t.tilt_y_flipped = %s\n", (pen->tilt_y_flipped ? "true" : "false")); } /** * Dump tablet interface frame parameters with hid_dbg(), indented with two * tabs. * * @hdev: The HID device the pen parameters describe. * @frame: The frame parameters to dump. */ static void uclogic_params_frame_hid_dbg( const struct hid_device *hdev, const struct uclogic_params_frame *frame) { hid_dbg(hdev, "\t\t.desc_ptr = %p\n", frame->desc_ptr); hid_dbg(hdev, "\t\t.desc_size = %u\n", frame->desc_size); hid_dbg(hdev, "\t\t.id = %u\n", frame->id); hid_dbg(hdev, "\t\t.suffix = %s\n", frame->suffix); hid_dbg(hdev, "\t\t.re_lsb = %u\n", frame->re_lsb); hid_dbg(hdev, "\t\t.dev_id_byte = %u\n", frame->dev_id_byte); hid_dbg(hdev, "\t\t.touch_byte = %u\n", frame->touch_byte); hid_dbg(hdev, "\t\t.touch_max = %hhd\n", frame->touch_max); hid_dbg(hdev, "\t\t.touch_flip_at = %hhd\n", frame->touch_flip_at); hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n", frame->bitmap_dial_byte); } /** * Dump tablet interface parameters with hid_dbg(). * * @hdev: The HID device the parameters describe. * @params: The parameters to dump. */ void uclogic_params_hid_dbg(const struct hid_device *hdev, const struct uclogic_params *params) { size_t i; hid_dbg(hdev, ".invalid = %s\n", params->invalid ? "true" : "false"); hid_dbg(hdev, ".desc_ptr = %p\n", params->desc_ptr); hid_dbg(hdev, ".desc_size = %u\n", params->desc_size); hid_dbg(hdev, ".pen = {\n"); uclogic_params_pen_hid_dbg(hdev, ¶ms->pen); hid_dbg(hdev, "\t}\n"); hid_dbg(hdev, ".frame_list = {\n"); for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { hid_dbg(hdev, "\t{\n"); uclogic_params_frame_hid_dbg(hdev, ¶ms->frame_list[i]); hid_dbg(hdev, "\t}%s\n", i < (ARRAY_SIZE(params->frame_list) - 1) ? "," : ""); } hid_dbg(hdev, "}\n"); } /** * uclogic_params_get_str_desc - retrieve a string descriptor from a HID * device interface, putting it into a kmalloc-allocated buffer as is, without * character encoding conversion. * * @pbuf: Location for the kmalloc-allocated buffer pointer containing * the retrieved descriptor. Not modified in case of error. * Can be NULL to have retrieved descriptor discarded. * @hdev: The HID device of the tablet interface to retrieve the string * descriptor from. Cannot be NULL. * @idx: Index of the string descriptor to request from the device. * @len: Length of the buffer to allocate and the data to retrieve. * * Returns: * number of bytes retrieved (<= len), * -EPIPE, if the descriptor was not found, or * another negative errno code in case of other error. */ static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev, __u8 idx, size_t len) { int rc; struct usb_device *udev; __u8 *buf = NULL; /* Check arguments */ if (hdev == NULL) { rc = -EINVAL; goto cleanup; } udev = hid_to_usb_dev(hdev); buf = kmalloc(len, GFP_KERNEL); if (buf == NULL) { rc = -ENOMEM; goto cleanup; } rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (USB_DT_STRING << 8) + idx, 0x0409, buf, len, USB_CTRL_GET_TIMEOUT); if (rc == -EPIPE) { hid_dbg(hdev, "string descriptor #%hhu not found\n", idx); goto cleanup; } else if (rc < 0) { hid_err(hdev, "failed retrieving string descriptor #%u: %d\n", idx, rc); goto cleanup; } if (pbuf != NULL) { *pbuf = buf; buf = NULL; } cleanup: kfree(buf); return rc; } /** * uclogic_params_pen_cleanup - free resources used by struct * uclogic_params_pen (tablet interface's pen input parameters). * Can be called repeatedly. * * @pen: Pen input parameters to cleanup. Cannot be NULL. */ static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen) { kfree(pen->desc_ptr); memset(pen, 0, sizeof(*pen)); } /** * uclogic_params_pen_init_v1() - initialize tablet interface pen * input and retrieve its parameters from the device, using v1 protocol. * * @pen: Pointer to the pen parameters to initialize (to be * cleaned up with uclogic_params_pen_cleanup()). Not modified in * case of error, or if parameters are not found. Cannot be NULL. * @pfound: Location for a flag which is set to true if the parameters * were found, and to false if not (e.g. device was * incompatible). Not modified in case of error. Cannot be NULL. * @hdev: The HID device of the tablet interface to initialize and get * parameters from. Cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error. */ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen, bool *pfound, struct hid_device *hdev) { int rc; bool found = false; /* Buffer for (part of) the string descriptor */ __u8 *buf = NULL; /* Minimum descriptor length required, maximum seen so far is 18 */ const int len = 12; s32 resolution; /* Pen report descriptor template parameters */ s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; __u8 *desc_ptr = NULL; /* Check arguments */ if (pen == NULL || pfound == NULL || hdev == NULL) { rc = -EINVAL; goto cleanup; } /* * Read string descriptor containing pen input parameters. * The specific string descriptor and data were discovered by sniffing * the Windows driver traffic. * NOTE: This enables fully-functional tablet mode. */ rc = uclogic_params_get_str_desc(&buf, hdev, 100, len); if (rc == -EPIPE) { hid_dbg(hdev, "string descriptor with pen parameters not found, assuming not compatible\n"); goto finish; } else if (rc < 0) { hid_err(hdev, "failed retrieving pen parameters: %d\n", rc); goto cleanup; } else if (rc != len) { hid_dbg(hdev, "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n", rc, len); goto finish; } /* * Fill report descriptor parameters from the string descriptor */ desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = get_unaligned_le16(buf + 2); desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = get_unaligned_le16(buf + 4); desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = get_unaligned_le16(buf + 8); resolution = get_unaligned_le16(buf + 10); if (resolution == 0) { desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; } else { desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / resolution; desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / resolution; } kfree(buf); buf = NULL; /* * Generate pen report descriptor */ desc_ptr = uclogic_rdesc_template_apply( uclogic_rdesc_v1_pen_template_arr, uclogic_rdesc_v1_pen_template_size, desc_params, ARRAY_SIZE(desc_params)); if (desc_ptr == NULL) { rc = -ENOMEM; goto cleanup; } /* * Fill-in the parameters */ memset(pen, 0, sizeof(*pen)); pen->desc_ptr = desc_ptr; desc_ptr = NULL; pen->desc_size = uclogic_rdesc_v1_pen_template_size; pen->id = UCLOGIC_RDESC_V1_PEN_ID; pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED; found = true; finish: *pfound = found; rc = 0; cleanup: kfree(desc_ptr); kfree(buf); return rc; } /** * uclogic_params_get_le24() - get a 24-bit little-endian number from a * buffer. * * @p: The pointer to the number buffer. * * Returns: * The retrieved number */ static s32 uclogic_params_get_le24(const void *p) { const __u8 *b = p; return b[0] | (b[1] << 8UL) | (b[2] << 16UL); } /** * uclogic_params_pen_init_v2() - initialize tablet interface pen * input and retrieve its parameters from the device, using v2 protocol. * * @pen: Pointer to the pen parameters to initialize (to be * cleaned up with uclogic_params_pen_cleanup()). Not * modified in case of error, or if parameters are not * found. Cannot be NULL. * @pfound: Location for a flag which is set to true if the * parameters were found, and to false if not (e.g. * device was incompatible). Not modified in case of * error. Cannot be NULL. * @pparams_ptr: Location for a kmalloc'ed pointer to the retrieved raw * parameters, which could be used to identify the tablet * to some extent. Should be freed with kfree after use. * NULL, if not needed. Not modified in case of error. * Only set if *pfound is set to true. * @pparams_len: Location for the length of the retrieved raw * parameters. NULL, if not needed. Not modified in case * of error. Only set if *pfound is set to true. * @hdev: The HID device of the tablet interface to initialize * and get parameters from. Cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error. */ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, bool *pfound, __u8 **pparams_ptr, size_t *pparams_len, struct hid_device *hdev) { int rc; bool found = false; /* Buffer for (part of) the parameter string descriptor */ __u8 *buf = NULL; /* Parameter string descriptor required length */ const int params_len_min = 18; /* Parameter string descriptor accepted length */ const int params_len_max = 32; /* Parameter string descriptor received length */ int params_len; size_t i; s32 resolution; /* Pen report descriptor template parameters */ s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; __u8 *desc_ptr = NULL; /* Check arguments */ if (pen == NULL || pfound == NULL || hdev == NULL) { rc = -EINVAL; goto cleanup; } /* * Read string descriptor containing pen input parameters. * The specific string descriptor and data were discovered by sniffing * the Windows driver traffic. * NOTE: This enables fully-functional tablet mode. */ rc = uclogic_params_get_str_desc(&buf, hdev, 200, params_len_max); if (rc == -EPIPE) { hid_dbg(hdev, "string descriptor with pen parameters not found, assuming not compatible\n"); goto finish; } else if (rc < 0) { hid_err(hdev, "failed retrieving pen parameters: %d\n", rc); goto cleanup; } else if (rc < params_len_min) { hid_dbg(hdev, "string descriptor with pen parameters is too short (got %d, expected at least %d), assuming not compatible\n", rc, params_len_min); goto finish; } params_len = rc; /* * Check it's not just a catch-all UTF-16LE-encoded ASCII * string (such as the model name) some tablets put into all * unknown string descriptors. */ for (i = 2; i < params_len && (buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0); i += 2); if (i >= params_len) { hid_dbg(hdev, "string descriptor with pen parameters seems to contain only text, assuming not compatible\n"); goto finish; } /* * Fill report descriptor parameters from the string descriptor */ desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = uclogic_params_get_le24(buf + 2); desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = uclogic_params_get_le24(buf + 5); desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = get_unaligned_le16(buf + 8); resolution = get_unaligned_le16(buf + 10); if (resolution == 0) { desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; } else { desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / resolution; desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / resolution; } /* * Generate pen report descriptor */ desc_ptr = uclogic_rdesc_template_apply( uclogic_rdesc_v2_pen_template_arr, uclogic_rdesc_v2_pen_template_size, desc_params, ARRAY_SIZE(desc_params)); if (desc_ptr == NULL) { rc = -ENOMEM; goto cleanup; } /* * Fill-in the parameters */ memset(pen, 0, sizeof(*pen)); pen->desc_ptr = desc_ptr; desc_ptr = NULL; pen->desc_size = uclogic_rdesc_v2_pen_template_size; pen->id = UCLOGIC_RDESC_V2_PEN_ID; pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE; pen->fragmented_hires = true; pen->tilt_y_flipped = true; found = true; if (pparams_ptr != NULL) { *pparams_ptr = buf; buf = NULL; } if (pparams_len != NULL) *pparams_len = params_len; finish: *pfound = found; rc = 0; cleanup: kfree(desc_ptr); kfree(buf); return rc; } /** * uclogic_params_frame_cleanup - free resources used by struct * uclogic_params_frame (tablet interface's frame controls input parameters). * Can be called repeatedly. * * @frame: Frame controls input parameters to cleanup. Cannot be NULL. */ static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame) { kfree(frame->desc_ptr); memset(frame, 0, sizeof(*frame)); } /** * uclogic_params_frame_init_with_desc() - initialize tablet's frame control * parameters with a static report descriptor. * * @frame: Pointer to the frame parameters to initialize (to be cleaned * up with uclogic_params_frame_cleanup()). Not modified in case * of error. Cannot be NULL. * @desc_ptr: Report descriptor pointer. Can be NULL, if desc_size is zero. * @desc_size: Report descriptor size. * @id: Report ID used for frame reports, if they should be tweaked, * zero if not. * * Returns: * Zero, if successful. A negative errno code on error. */ static int uclogic_params_frame_init_with_desc( struct uclogic_params_frame *frame, const __u8 *desc_ptr, size_t desc_size, unsigned int id) { __u8 *copy_desc_ptr; if (frame == NULL || (desc_ptr == NULL && desc_size != 0)) return -EINVAL; copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL); if (copy_desc_ptr == NULL) return -ENOMEM; memset(frame, 0, sizeof(*frame)); frame->desc_ptr = copy_desc_ptr; frame->desc_size = desc_size; frame->id = id; return 0; } /** * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame * controls. * * @frame: Pointer to the frame parameters to initialize (to be cleaned * up with uclogic_params_frame_cleanup()). Not modified in case * of error, or if parameters are not found. Cannot be NULL. * @pfound: Location for a flag which is set to true if the parameters * were found, and to false if not (e.g. device was * incompatible). Not modified in case of error. Cannot be NULL. * @hdev: The HID device of the tablet interface to initialize and get * parameters from. Cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error. */ static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame, bool *pfound, struct hid_device *hdev) { int rc; bool found = false; struct usb_device *usb_dev; char *str_buf = NULL; const size_t str_len = 16; /* Check arguments */ if (frame == NULL || pfound == NULL || hdev == NULL) { rc = -EINVAL; goto cleanup; } usb_dev = hid_to_usb_dev(hdev); /* * Enable generic button mode */ str_buf = kzalloc(str_len, GFP_KERNEL); if (str_buf == NULL) { rc = -ENOMEM; goto cleanup; } rc = usb_string(usb_dev, 123, str_buf, str_len); if (rc == -EPIPE) { hid_dbg(hdev, "generic button -enabling string descriptor not found\n"); } else if (rc < 0) { goto cleanup; } else if (strncmp(str_buf, "HK On", rc) != 0) { hid_dbg(hdev, "invalid response to enabling generic buttons: \"%s\"\n", str_buf); } else { hid_dbg(hdev, "generic buttons enabled\n"); rc = uclogic_params_frame_init_with_desc( frame, uclogic_rdesc_v1_frame_arr, uclogic_rdesc_v1_frame_size, UCLOGIC_RDESC_V1_FRAME_ID); if (rc != 0) goto cleanup; found = true; } *pfound = found; rc = 0; cleanup: kfree(str_buf); return rc; } /** * uclogic_params_cleanup - free resources used by struct uclogic_params * (tablet interface's parameters). * Can be called repeatedly. * * @params: Input parameters to cleanup. Cannot be NULL. */ void uclogic_params_cleanup(struct uclogic_params *params) { if (!params->invalid) { size_t i; kfree(params->desc_ptr); uclogic_params_pen_cleanup(¶ms->pen); for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) uclogic_params_frame_cleanup(¶ms->frame_list[i]); memset(params, 0, sizeof(*params)); } } /** * uclogic_params_get_desc() - Get a replacement report descriptor for a * tablet's interface. * * @params: The parameters of a tablet interface to get report * descriptor for. Cannot be NULL. * @pdesc: Location for the resulting, kmalloc-allocated report * descriptor pointer, or for NULL, if there's no replacement * report descriptor. Not modified in case of error. Cannot be * NULL. * @psize: Location for the resulting report descriptor size, not set if * there's no replacement report descriptor. Not modified in case * of error. Cannot be NULL. * * Returns: * Zero, if successful. * -EINVAL, if invalid arguments are supplied. * -ENOMEM, if failed to allocate memory. */ int uclogic_params_get_desc(const struct uclogic_params *params, __u8 **pdesc, unsigned int *psize) { int rc = -ENOMEM; bool present = false; unsigned int size = 0; __u8 *desc = NULL; size_t i; /* Check arguments */ if (params == NULL || pdesc == NULL || psize == NULL) return -EINVAL; /* Concatenate descriptors */ #define ADD_DESC(_desc_ptr, _desc_size) \ do { \ unsigned int new_size; \ __u8 *new_desc; \ if ((_desc_ptr) == NULL) { \ break; \ } \ new_size = size + (_desc_size); \ new_desc = krealloc(desc, new_size, GFP_KERNEL); \ if (new_desc == NULL) { \ goto cleanup; \ } \ memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \ desc = new_desc; \ size = new_size; \ present = true; \ } while (0) ADD_DESC(params->desc_ptr, params->desc_size); ADD_DESC(params->pen.desc_ptr, params->pen.desc_size); for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { ADD_DESC(params->frame_list[i].desc_ptr, params->frame_list[i].desc_size); } #undef ADD_DESC if (present) { *pdesc = desc; *psize = size; desc = NULL; } rc = 0; cleanup: kfree(desc); return rc; } /** * uclogic_params_init_invalid() - initialize tablet interface parameters, * specifying the interface is invalid. * * @params: Parameters to initialize (to be cleaned with * uclogic_params_cleanup()). Cannot be NULL. */ static void uclogic_params_init_invalid(struct uclogic_params *params) { params->invalid = true; } /** * uclogic_params_init_with_opt_desc() - initialize tablet interface * parameters with an optional replacement report descriptor. Only modify * report descriptor, if the original report descriptor matches the expected * size. * * @params: Parameters to initialize (to be cleaned with * uclogic_params_cleanup()). Not modified in case of * error. Cannot be NULL. * @hdev: The HID device of the tablet interface create the * parameters for. Cannot be NULL. * @orig_desc_size: Expected size of the original report descriptor to * be replaced. * @desc_ptr: Pointer to the replacement report descriptor. * Can be NULL, if desc_size is zero. * @desc_size: Size of the replacement report descriptor. * * Returns: * Zero, if successful. -EINVAL if an invalid argument was passed. * -ENOMEM, if failed to allocate memory. */ static int uclogic_params_init_with_opt_desc(struct uclogic_params *params, struct hid_device *hdev, unsigned int orig_desc_size, __u8 *desc_ptr, unsigned int desc_size) { __u8 *desc_copy_ptr = NULL; unsigned int desc_copy_size; int rc; /* Check arguments */ if (params == NULL || hdev == NULL || (desc_ptr == NULL && desc_size != 0)) { rc = -EINVAL; goto cleanup; } /* Replace report descriptor, if it matches */ if (hdev->dev_rsize == orig_desc_size) { hid_dbg(hdev, "device report descriptor matches the expected size, replacing\n"); desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL); if (desc_copy_ptr == NULL) { rc = -ENOMEM; goto cleanup; } desc_copy_size = desc_size; } else { hid_dbg(hdev, "device report descriptor doesn't match the expected size (%u != %u), preserving\n", hdev->dev_rsize, orig_desc_size); desc_copy_ptr = NULL; desc_copy_size = 0; } /* Output parameters */ memset(params, 0, sizeof(*params)); params->desc_ptr = desc_copy_ptr; desc_copy_ptr = NULL; params->desc_size = desc_copy_size; rc = 0; cleanup: kfree(desc_copy_ptr); return rc; } /** * uclogic_params_huion_init() - initialize a Huion tablet interface and discover * its parameters. * * @params: Parameters to fill in (to be cleaned with * uclogic_params_cleanup()). Not modified in case of error. * Cannot be NULL. * @hdev: The HID device of the tablet interface to initialize and get * parameters from. Cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error. */ static int uclogic_params_huion_init(struct uclogic_params *params, struct hid_device *hdev) { int rc; struct usb_device *udev; struct usb_interface *iface; __u8 bInterfaceNumber; bool found; /* The resulting parameters (noop) */ struct uclogic_params p = {0, }; static const char transition_ver[] = "HUION_T153_160607"; char *ver_ptr = NULL; const size_t ver_len = sizeof(transition_ver) + 1; __u8 *params_ptr = NULL; size_t params_len = 0; /* Parameters string descriptor of a model with touch ring (HS610) */ const __u8 touch_ring_model_params_buf[] = { 0x13, 0x03, 0x70, 0xC6, 0x00, 0x06, 0x7C, 0x00, 0xFF, 0x1F, 0xD8, 0x13, 0x03, 0x0D, 0x10, 0x01, 0x04, 0x3C, 0x3E }; /* Check arguments */ if (params == NULL || hdev == NULL) { rc = -EINVAL; goto cleanup; } udev = hid_to_usb_dev(hdev); iface = to_usb_interface(hdev->dev.parent); bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; /* If it's a custom keyboard interface */ if (bInterfaceNumber == 1) { /* Keep everything intact, but mark pen usage invalid */ p.pen.usage_invalid = true; goto output; /* Else, if it's not a pen interface */ } else if (bInterfaceNumber != 0) { uclogic_params_init_invalid(&p); goto output; } /* Try to get firmware version */ ver_ptr = kzalloc(ver_len, GFP_KERNEL); if (ver_ptr == NULL) { rc = -ENOMEM; goto cleanup; } rc = usb_string(udev, 201, ver_ptr, ver_len); if (rc == -EPIPE) { *ver_ptr = '\0'; } else if (rc < 0) { hid_err(hdev, "failed retrieving Huion firmware version: %d\n", rc); goto cleanup; } /* If this is a transition firmware */ if (strcmp(ver_ptr, transition_ver) == 0) { hid_dbg(hdev, "transition firmware detected, not probing pen v2 parameters\n"); } else { /* Try to probe v2 pen parameters */ rc = uclogic_params_pen_init_v2(&p.pen, &found, ¶ms_ptr, ¶ms_len, hdev); if (rc != 0) { hid_err(hdev, "failed probing pen v2 parameters: %d\n", rc); goto cleanup; } else if (found) { hid_dbg(hdev, "pen v2 parameters found\n"); /* Create v2 frame button parameters */ rc = uclogic_params_frame_init_with_desc( &p.frame_list[0], uclogic_rdesc_v2_frame_buttons_arr, uclogic_rdesc_v2_frame_buttons_size, UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID); if (rc != 0) { hid_err(hdev, "failed creating v2 frame button parameters: %d\n", rc); goto cleanup; } /* Link from pen sub-report */ p.pen.subreport_list[0].value = 0xe0; p.pen.subreport_list[0].id = UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID; /* If this is the model with touch ring */ if (params_ptr != NULL && params_len == sizeof(touch_ring_model_params_buf) && memcmp(params_ptr, touch_ring_model_params_buf, params_len) == 0) { /* Create touch ring parameters */ rc = uclogic_params_frame_init_with_desc( &p.frame_list[1], uclogic_rdesc_v2_frame_touch_ring_arr, uclogic_rdesc_v2_frame_touch_ring_size, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID); if (rc != 0) { hid_err(hdev, "failed creating v2 frame touch ring parameters: %d\n", rc); goto cleanup; } p.frame_list[1].suffix = "Touch Ring"; p.frame_list[1].dev_id_byte = UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE; p.frame_list[1].touch_byte = 5; p.frame_list[1].touch_max = 12; p.frame_list[1].touch_flip_at = 7; } else { /* Create touch strip parameters */ rc = uclogic_params_frame_init_with_desc( &p.frame_list[1], uclogic_rdesc_v2_frame_touch_strip_arr, uclogic_rdesc_v2_frame_touch_strip_size, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID); if (rc != 0) { hid_err(hdev, "failed creating v2 frame touch strip parameters: %d\n", rc); goto cleanup; } p.frame_list[1].suffix = "Touch Strip"; p.frame_list[1].dev_id_byte = UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE; p.frame_list[1].touch_byte = 5; p.frame_list[1].touch_max = 8; } /* Link from pen sub-report */ p.pen.subreport_list[1].value = 0xf0; p.pen.subreport_list[1].id = UCLOGIC_RDESC_V2_FRAME_TOUCH_ID; /* Create v2 frame dial parameters */ rc = uclogic_params_frame_init_with_desc( &p.frame_list[2], uclogic_rdesc_v2_frame_dial_arr, uclogic_rdesc_v2_frame_dial_size, UCLOGIC_RDESC_V2_FRAME_DIAL_ID); if (rc != 0) { hid_err(hdev, "failed creating v2 frame dial parameters: %d\n", rc); goto cleanup; } p.frame_list[2].suffix = "Dial"; p.frame_list[2].dev_id_byte = UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE; p.frame_list[2].bitmap_dial_byte = 5; /* Link from pen sub-report */ p.pen.subreport_list[2].value = 0xf1; p.pen.subreport_list[2].id = UCLOGIC_RDESC_V2_FRAME_DIAL_ID; goto output; } hid_dbg(hdev, "pen v2 parameters not found\n"); } /* Try to probe v1 pen parameters */ rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); if (rc != 0) { hid_err(hdev, "failed probing pen v1 parameters: %d\n", rc); goto cleanup; } else if (found) { hid_dbg(hdev, "pen v1 parameters found\n"); /* Try to probe v1 frame */ rc = uclogic_params_frame_init_v1(&p.frame_list[0], &found, hdev); if (rc != 0) { hid_err(hdev, "v1 frame probing failed: %d\n", rc); goto cleanup; } hid_dbg(hdev, "frame v1 parameters%s found\n", (found ? "" : " not")); if (found) { /* Link frame button subreports from pen reports */ p.pen.subreport_list[0].value = 0xe0; p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID; } goto output; } hid_dbg(hdev, "pen v1 parameters not found\n"); uclogic_params_init_invalid(&p); output: /* Output parameters */ memcpy(params, &p, sizeof(*params)); memset(&p, 0, sizeof(p)); rc = 0; cleanup: kfree(params_ptr); kfree(ver_ptr); uclogic_params_cleanup(&p); return rc; } /** * uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or * the XP-PEN Deco Mini 7, need to be initialized by sending them magic data. * * @hdev: The HID device of the tablet interface to initialize and get * parameters from. Cannot be NULL. * @magic_arr: The magic data that should be sent to probe the interface. * Cannot be NULL. * @magic_size: Size of the magic data. * @endpoint: Endpoint where the magic data should be sent. * * Returns: * Zero, if successful. A negative errno code on error. */ static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr, int magic_size, int endpoint) { struct usb_device *udev; unsigned int pipe = 0; int sent; u8 *buf = NULL; int rc = 0; if (!hdev || !magic_arr) { rc = -EINVAL; goto cleanup; } buf = kmemdup(magic_arr, magic_size, GFP_KERNEL); if (!buf) { rc = -ENOMEM; goto cleanup; } udev = hid_to_usb_dev(hdev); pipe = usb_sndintpipe(udev, endpoint); rc = usb_interrupt_msg(udev, pipe, buf, magic_size, &sent, 1000); if (rc || sent != magic_size) { hid_err(hdev, "Interface probing failed: %d\n", rc); rc = -1; goto cleanup; } rc = 0; cleanup: kfree(buf); return rc; } /** * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by * discovering their parameters. * * These tables, internally designed as v2 to differentiate them from older * models, expect a payload of magic data in orther to be switched to the fully * functional mode and expose their parameters in a similar way to the * information present in uclogic_params_pen_init_v1() but with some * differences. * * @params: Parameters to fill in (to be cleaned with * uclogic_params_cleanup()). Not modified in case of error. * Cannot be NULL. * @hdev: The HID device of the tablet interface to initialize and get * parameters from. Cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error. */ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, struct hid_device *hdev) { int rc = 0; struct usb_interface *iface; __u8 bInterfaceNumber; const int str_desc_len = 12; __u8 *str_desc = NULL; __u8 *rdesc_pen = NULL; __u8 *rdesc_frame = NULL; s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; s32 resolution; __u8 magic_arr[] = { 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* The resulting parameters (noop) */ struct uclogic_params p = {0, }; if (!params || !hdev) { rc = -EINVAL; goto cleanup; } iface = to_usb_interface(hdev->dev.parent); bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; if (bInterfaceNumber != 2) { uclogic_params_init_invalid(&p); goto output; } /* * Initialize the interface by sending magic data. * The specific data was discovered by sniffing the Windows driver * traffic. */ rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03); if (rc) { uclogic_params_init_invalid(&p); goto output; } /* * Read the string descriptor containing pen and frame parameters. * The specific string descriptor and data were discovered by sniffing * the Windows driver traffic. */ rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len); if (rc != str_desc_len) { hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc); uclogic_params_init_invalid(&p); goto output; } desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = get_unaligned_le16(str_desc + 2); desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = get_unaligned_le16(str_desc + 4); desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6]; desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = get_unaligned_le16(str_desc + 8); resolution = get_unaligned_le16(str_desc + 10); if (resolution == 0) { desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; } else { desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / resolution; desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / resolution; } kfree(str_desc); str_desc = NULL; /* Initialize the pen interface */ rdesc_pen = uclogic_rdesc_template_apply( uclogic_rdesc_ugee_v2_pen_template_arr, uclogic_rdesc_ugee_v2_pen_template_size, desc_params, ARRAY_SIZE(desc_params)); if (!rdesc_pen) { rc = -ENOMEM; goto cleanup; } p.pen.desc_ptr = rdesc_pen; p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size; p.pen.id = 0x02; p.pen.subreport_list[0].value = 0xf0; p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID; /* Initialize the frame interface */ rdesc_frame = uclogic_rdesc_template_apply( uclogic_rdesc_ugee_v2_frame_btn_template_arr, uclogic_rdesc_ugee_v2_frame_btn_template_size, desc_params, ARRAY_SIZE(desc_params)); if (!rdesc_frame) { rc = -ENOMEM; goto cleanup; } rc = uclogic_params_frame_init_with_desc(&p.frame_list[0], rdesc_frame, uclogic_rdesc_ugee_v2_frame_btn_template_size, UCLOGIC_RDESC_V1_FRAME_ID); kfree(rdesc_frame); if (rc) { uclogic_params_init_invalid(&p); goto output; } output: /* Output parameters */ memcpy(params, &p, sizeof(*params)); memset(&p, 0, sizeof(p)); rc = 0; cleanup: kfree(str_desc); uclogic_params_cleanup(&p); return rc; } /** * uclogic_params_init() - initialize a tablet interface and discover its * parameters. * * @params: Parameters to fill in (to be cleaned with * uclogic_params_cleanup()). Not modified in case of error. * Cannot be NULL. * @hdev: The HID device of the tablet interface to initialize and get * parameters from. Cannot be NULL. Must be using the USB low-level * driver, i.e. be an actual USB tablet. * * Returns: * Zero, if successful. A negative errno code on error. */ int uclogic_params_init(struct uclogic_params *params, struct hid_device *hdev) { int rc; struct usb_device *udev; __u8 bNumInterfaces; struct usb_interface *iface; __u8 bInterfaceNumber; bool found; /* The resulting parameters (noop) */ struct uclogic_params p = {0, }; /* Check arguments */ if (params == NULL || hdev == NULL #if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE || !hid_is_usb(hdev) #elif KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE || !hid_is_using_ll_driver(hdev, &usb_hid_driver) #endif ) { rc = -EINVAL; goto cleanup; } udev = hid_to_usb_dev(hdev); bNumInterfaces = udev->config->desc.bNumInterfaces; iface = to_usb_interface(hdev->dev.parent); bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; /* * Set replacement report descriptor if the original matches the * specified size. Otherwise keep interface unchanged. */ #define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \ uclogic_params_init_with_opt_desc( \ &p, hdev, \ UCLOGIC_RDESC_##_orig_desc_token##_SIZE, \ uclogic_rdesc_##_new_desc_token##_arr, \ uclogic_rdesc_##_new_desc_token##_size) #define VID_PID(_vid, _pid) \ (((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX)) /* * Handle specific interfaces for specific tablets. * * Observe the following logic: * * If the interface is recognized as producing certain useful input: * Mark interface as valid. * Output interface parameters. * Else, if the interface is recognized as *not* producing any useful * input: * Mark interface as invalid. * Else: * Mark interface as valid. * Output noop parameters. * * Rule of thumb: it is better to disable a broken interface than let * it spew garbage input. */ switch (VID_PID(hdev->vendor, hdev->product)) { case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209): rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U): rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U): if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) { if (bInterfaceNumber == 0) { /* Try to probe v1 pen parameters */ rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); if (rc != 0) { hid_err(hdev, "pen probing failed: %d\n", rc); goto cleanup; } if (!found) { hid_warn(hdev, "pen parameters not found"); } } else { uclogic_params_init_invalid(&p); } } else { rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed); if (rc != 0) goto cleanup; } break; case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U): rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062): rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850): switch (bInterfaceNumber) { case 0: rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0); if (rc != 0) goto cleanup; break; case 1: rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1); if (rc != 0) goto cleanup; break; case 2: rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2); if (rc != 0) goto cleanup; break; } break; case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60): /* * If it is not a three-interface version, which is known to * respond to initialization. */ if (bNumInterfaces != 3) { switch (bInterfaceNumber) { case 0: rc = WITH_OPT_DESC(TWHA60_ORIG0, twha60_fixed0); if (rc != 0) goto cleanup; break; case 1: rc = WITH_OPT_DESC(TWHA60_ORIG1, twha60_fixed1); if (rc != 0) goto cleanup; break; } break; } /* FALLTHROUGH */ case VID_PID(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET2): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47): rc = uclogic_params_huion_init(&p, hdev); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610): case VID_PID(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GT5040): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720): /* If this is the pen interface */ if (bInterfaceNumber == 1) { /* Probe v1 pen parameters */ rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); if (rc != 0) { hid_err(hdev, "pen probing failed: %d\n", rc); goto cleanup; } if (!found) { hid_warn(hdev, "pen parameters not found"); uclogic_params_init_invalid(&p); } } else { uclogic_params_init_invalid(&p); } break; case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01): /* If this is the pen and frame interface */ if (bInterfaceNumber == 1) { /* Probe v1 pen parameters */ rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); if (rc != 0) { hid_err(hdev, "pen probing failed: %d\n", rc); goto cleanup; } /* Initialize frame parameters */ rc = uclogic_params_frame_init_with_desc( &p.frame_list[0], uclogic_rdesc_xppen_deco01_frame_arr, uclogic_rdesc_xppen_deco01_frame_size, 0); if (rc != 0) goto cleanup; } else { uclogic_params_init_invalid(&p); } break; case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): rc = uclogic_params_ugee_v2_init(&p, hdev); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_TRUST, USB_DEVICE_ID_TRUST_PANORA_TABLET): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_G5): /* Ignore non-pen interfaces */ if (bInterfaceNumber != 1) { uclogic_params_init_invalid(&p); break; } rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); if (rc != 0) { hid_err(hdev, "pen probing failed: %d\n", rc); goto cleanup; } else if (found) { rc = uclogic_params_frame_init_with_desc( &p.frame_list[0], uclogic_rdesc_ugee_g5_frame_arr, uclogic_rdesc_ugee_g5_frame_size, UCLOGIC_RDESC_UGEE_G5_FRAME_ID); if (rc != 0) { hid_err(hdev, "failed creating frame parameters: %d\n", rc); goto cleanup; } p.frame_list[0].re_lsb = UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB; p.frame_list[0].dev_id_byte = UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE; } else { hid_warn(hdev, "pen parameters not found"); uclogic_params_init_invalid(&p); } break; case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S): /* Ignore non-pen interfaces */ if (bInterfaceNumber != 1) { uclogic_params_init_invalid(&p); break; } rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); if (rc != 0) { hid_err(hdev, "pen probing failed: %d\n", rc); goto cleanup; } else if (found) { rc = uclogic_params_frame_init_with_desc( &p.frame_list[0], uclogic_rdesc_ugee_ex07_frame_arr, uclogic_rdesc_ugee_ex07_frame_size, 0); if (rc != 0) { hid_err(hdev, "failed creating frame parameters: %d\n", rc); goto cleanup; } } else { hid_warn(hdev, "pen parameters not found"); uclogic_params_init_invalid(&p); } break; } #undef VID_PID #undef WITH_OPT_DESC /* Output parameters */ memcpy(params, &p, sizeof(*params)); memset(&p, 0, sizeof(p)); rc = 0; cleanup: uclogic_params_cleanup(&p); return rc; } 0707010000001F000081A40000000000000000000000016452046B00001C47000000000000000000000000000000000000003B00000000digimend-kernel-drivers-0~git20230503/hid-uclogic-params.h/* SPDX-License-Identifier: GPL-2.0+ */ /* * HID driver for UC-Logic devices not fully compliant with HID standard * - tablet initialization and parameter retrieval * * Copyright (c) 2018 Nikolai Kondrashov */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #ifndef _HID_UCLOGIC_PARAMS_H #define _HID_UCLOGIC_PARAMS_H #include <linux/usb.h> #include <linux/hid.h> /* Types of pen in-range reporting */ enum uclogic_params_pen_inrange { /* Normal reports: zero - out of proximity, one - in proximity */ UCLOGIC_PARAMS_PEN_INRANGE_NORMAL = 0, /* Inverted reports: zero - in proximity, one - out of proximity */ UCLOGIC_PARAMS_PEN_INRANGE_INVERTED, /* No reports */ UCLOGIC_PARAMS_PEN_INRANGE_NONE, }; /* * Pen report's subreport data. */ struct uclogic_params_pen_subreport { /* * The value of the second byte of the pen report indicating this * subreport. If zero, the subreport should be considered invalid and * not matched. */ __u8 value; /* * The ID to be assigned to the report, if the second byte of the pen * report is equal to "value". Only valid if "value" is not zero. */ __u8 id; }; /* * Tablet interface's pen input parameters. * * Must use declarative (descriptive) language, not imperative, to simplify * understanding and maintain consistency. * * Noop (preserving functionality) when filled with zeroes. */ struct uclogic_params_pen { /* * True if pen usage is invalid for this interface and should be * ignored, false otherwise. */ bool usage_invalid; /* * Pointer to report descriptor part describing the pen inputs. * Allocated with kmalloc. NULL if the part is not specified. */ __u8 *desc_ptr; /* * Size of the report descriptor. * Only valid, if "desc_ptr" is not NULL. */ unsigned int desc_size; /* Report ID, if reports should be tweaked, zero if not */ unsigned int id; /* The list of subreports, only valid if "id" is not zero */ struct uclogic_params_pen_subreport subreport_list[3]; /* Type of in-range reporting, only valid if "id" is not zero */ enum uclogic_params_pen_inrange inrange; /* * True, if reports include fragmented high resolution coords, with * high-order X and then Y bytes following the pressure field. * Only valid if "id" is not zero. */ bool fragmented_hires; /* * True if the pen reports tilt in bytes at offset 10 (X) and 11 (Y), * and the Y tilt direction is flipped. * Only valid if "id" is not zero. */ bool tilt_y_flipped; }; /* * Parameters of frame control inputs of a tablet interface. * * Must use declarative (descriptive) language, not imperative, to simplify * understanding and maintain consistency. * * Noop (preserving functionality) when filled with zeroes. */ struct uclogic_params_frame { /* * Pointer to report descriptor part describing the frame inputs. * Allocated with kmalloc. NULL if the part is not specified. */ __u8 *desc_ptr; /* * Size of the report descriptor. * Only valid, if "desc_ptr" is not NULL. */ unsigned int desc_size; /* * Report ID, if reports should be tweaked, zero if not. */ unsigned int id; /* * The suffix to add to the input device name, if not NULL. */ const char *suffix; /* * Number of the least-significant bit of the 2-bit state of a rotary * encoder, in the report. Cannot point to a 2-bit field crossing a * byte boundary. Zero if not present. Only valid if "id" is not zero. */ unsigned int re_lsb; /* * Offset of the Wacom-style device ID byte in the report, to be set * to pad device ID (0xf), for compatibility with Wacom drivers. Zero * if no changes to the report should be made. The ID byte will be set * to zero whenever the byte pointed by "touch_byte" is zero, if * the latter is valid. Only valid if "id" is not zero. */ unsigned int dev_id_byte; /* * Offset of the touch ring/strip state byte, in the report. * Zero if not present. If dev_id_byte is also valid and non-zero, * then the device ID byte will be cleared when the byte pointed to by * this offset is zero. Only valid if "id" is not zero. */ unsigned int touch_byte; /* * The value to anchor the reversed touch ring/strip reports at. * I.e. one, if the reports should be flipped without offset. * Zero if no reversal should be done. * Only valid if "touch_byte" is valid and not zero. */ __s8 touch_flip_at; /* * Maximum value of the touch ring/strip report around which the value * should be wrapped when flipping according to "touch_flip_at". * The minimum valid value is considered to be one, with zero being * out-of-proximity (finger lift) value. * Only valid if "touch_flip_at" is valid and not zero. */ __s8 touch_max; /* * Offset of the bitmap dial byte, in the report. Zero if not present. * Only valid if "id" is not zero. A bitmap dial sends reports with a * dedicated bit per direction: 1 means clockwise rotation, 2 means * counterclockwise, as opposed to the normal 1 and -1. */ unsigned int bitmap_dial_byte; }; /* * Tablet interface report parameters. * * Must use declarative (descriptive) language, not imperative, to simplify * understanding and maintain consistency. * * When filled with zeros represents a "noop" configuration - passes all * reports unchanged and lets the generic HID driver handle everything. * * The resulting device report descriptor is assembled from all the report * descriptor parts referenced by the structure. No order of assembly should * be assumed. The structure represents original device report descriptor if * all the parts are NULL. */ struct uclogic_params { /* * True if the whole interface is invalid, false otherwise. */ bool invalid; /* * Pointer to the common part of the replacement report descriptor, * allocated with kmalloc. NULL if no common part is needed. * Only valid, if "invalid" is false. */ __u8 *desc_ptr; /* * Size of the common part of the replacement report descriptor. * Only valid, if "desc_ptr" is valid and not NULL. */ unsigned int desc_size; /* * Pen parameters and optional report descriptor part. * Only valid, if "invalid" is false. */ struct uclogic_params_pen pen; /* * The list of frame control parameters and optional report descriptor * parts. Only valid, if "invalid" is false. */ struct uclogic_params_frame frame_list[3]; }; /* Initialize a tablet interface and discover its parameters */ extern int uclogic_params_init(struct uclogic_params *params, struct hid_device *hdev); /* Get a replacement report descriptor for a tablet's interface. */ extern int uclogic_params_get_desc(const struct uclogic_params *params, __u8 **pdesc, unsigned int *psize); /* Free resources used by tablet interface's parameters */ extern void uclogic_params_cleanup(struct uclogic_params *params); /* Dump tablet interface parameters with hid_dbg() */ extern void uclogic_params_hid_dbg(const struct hid_device *hdev, const struct uclogic_params *params); #endif /* _HID_UCLOGIC_PARAMS_H */ 07070100000020000081A40000000000000000000000016452046B000017AD000000000000000000000000000000000000003F00000000digimend-kernel-drivers-0~git20230503/hid-uclogic-rdesc-test.c// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for UC-Logic devices not fully compliant with HID standard * * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com> */ #include <kunit/test.h> #include "./hid-uclogic-rdesc.h" struct uclogic_template_case { const char *name; const __u8 *template; size_t template_size; const s32 *param_list; size_t param_num; const __u8 *expected; }; static const s32 params_pen_all[UCLOGIC_RDESC_PH_ID_NUM] = { [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA, [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0xCC, [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0xDD, [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0xEE, }; static const s32 params_pen_some[] = { [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA, [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, }; static const s32 params_frame_all[UCLOGIC_RDESC_PH_ID_NUM] = { [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0xFF, }; static const __u8 template_empty[] = { }; static const __u8 template_small[] = { 0x00 }; static const __u8 template_no_ph[] = { 0xAA, 0xFE, 0xAA, 0xED, 0x1D }; static const __u8 template_pen_ph_end[] = { 0xAA, 0xBB, UCLOGIC_RDESC_PEN_PH_HEAD }; static const __u8 template_btn_ph_end[] = { 0xAA, 0xBB, UCLOGIC_RDESC_FRAME_PH_BTN_HEAD }; static const __u8 template_pen_all_params[] = { UCLOGIC_RDESC_PEN_PH(X_LM), 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), UCLOGIC_RDESC_PEN_PH(Y_PM), 0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), }; static const __u8 expected_pen_all_params[] = { 0xAA, 0x00, 0x00, 0x00, 0x47, 0xBB, 0x00, 0x00, 0x00, 0x27, 0xCC, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x00, 0x00, 0x00, }; static const __u8 template_frame_all_params[] = { 0x01, 0x02, UCLOGIC_RDESC_FRAME_PH_BTN, 0x99, }; static const __u8 expected_frame_all_params[] = { 0x01, 0x02, 0x2A, 0xFF, 0x00, 0x99, }; static const __u8 template_pen_some_params[] = { 0x01, 0x02, UCLOGIC_RDESC_PEN_PH(X_LM), 0x03, UCLOGIC_RDESC_PEN_PH(X_PM), 0x04, 0x05, }; static const __u8 expected_pen_some_params[] = { 0x01, 0x02, 0xAA, 0x00, 0x00, 0x00, 0x03, 0xBB, 0x00, 0x00, 0x00, 0x04, 0x05, }; static const __u8 template_params_none[] = { 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), UCLOGIC_RDESC_PEN_PH(Y_PM), 0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), }; static struct uclogic_template_case uclogic_template_cases[] = { { .name = "Empty template", .template = template_empty, .template_size = sizeof(template_empty), .param_list = params_pen_all, .param_num = ARRAY_SIZE(params_pen_all), .expected = template_empty, }, { .name = "Template smaller than the placeholder", .template = template_small, .template_size = sizeof(template_small), .param_list = params_pen_all, .param_num = ARRAY_SIZE(params_pen_all), .expected = template_small, }, { .name = "No placeholder", .template = template_no_ph, .template_size = sizeof(template_no_ph), .param_list = params_pen_all, .param_num = ARRAY_SIZE(params_pen_all), .expected = template_no_ph, }, { .name = "Pen placeholder at the end, without ID", .template = template_pen_ph_end, .template_size = sizeof(template_pen_ph_end), .param_list = params_pen_all, .param_num = ARRAY_SIZE(params_pen_all), .expected = template_pen_ph_end, }, { .name = "Frame button placeholder at the end, without ID", .template = template_btn_ph_end, .template_size = sizeof(template_btn_ph_end), .param_list = params_frame_all, .param_num = ARRAY_SIZE(params_frame_all), .expected = template_btn_ph_end, }, { .name = "All params present in the pen template", .template = template_pen_all_params, .template_size = sizeof(template_pen_all_params), .param_list = params_pen_all, .param_num = ARRAY_SIZE(params_pen_all), .expected = expected_pen_all_params, }, { .name = "All params present in the frame template", .template = template_frame_all_params, .template_size = sizeof(template_frame_all_params), .param_list = params_frame_all, .param_num = ARRAY_SIZE(params_frame_all), .expected = expected_frame_all_params, }, { .name = "Some params present in the pen template (complete param list)", .template = template_pen_some_params, .template_size = sizeof(template_pen_some_params), .param_list = params_pen_all, .param_num = ARRAY_SIZE(params_pen_all), .expected = expected_pen_some_params, }, { .name = "Some params present in the pen template (incomplete param list)", .template = template_pen_some_params, .template_size = sizeof(template_pen_some_params), .param_list = params_pen_some, .param_num = ARRAY_SIZE(params_pen_some), .expected = expected_pen_some_params, }, { .name = "No params present in the template", .template = template_params_none, .template_size = sizeof(template_params_none), .param_list = params_pen_some, .param_num = ARRAY_SIZE(params_pen_some), .expected = template_params_none, }, }; static void uclogic_template_case_desc(struct uclogic_template_case *t, char *desc) { strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); } KUNIT_ARRAY_PARAM(uclogic_template, uclogic_template_cases, uclogic_template_case_desc); static void uclogic_template_test(struct kunit *test) { __u8 *res; const struct uclogic_template_case *params = test->param_value; res = uclogic_rdesc_template_apply(params->template, params->template_size, params->param_list, params->param_num); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res); KUNIT_EXPECT_EQ(test, 0, memcmp(res, params->expected, params->template_size)); kfree(res); } static struct kunit_case hid_uclogic_rdesc_test_cases[] = { KUNIT_CASE_PARAM(uclogic_template_test, uclogic_template_gen_params), {} }; static struct kunit_suite hid_uclogic_rdesc_test_suite = { .name = "hid-uclogic-rdesc-test", .test_cases = hid_uclogic_rdesc_test_cases, }; kunit_test_suite(hid_uclogic_rdesc_test_suite); MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>"); 07070100000021000081A40000000000000000000000016452046B0000FCF3000000000000000000000000000000000000003A00000000digimend-kernel-drivers-0~git20230503/hid-uclogic-rdesc.c// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for UC-Logic devices not fully compliant with HID standard * - original and fixed report descriptors * * Copyright (c) 2010-2017 Nikolai Kondrashov * Copyright (c) 2013 Martin Rusko */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include "hid-uclogic-rdesc.h" #include <linux/slab.h> #include <asm/unaligned.h> /* Fixed WP4030U report descriptor */ __u8 uclogic_rdesc_wp4030u_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x14, /* Logical Minimum (0), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0xB8, 0x0B, /* Physical Maximum (3000), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_wp4030u_fixed_size = sizeof(uclogic_rdesc_wp4030u_fixed_arr); /* Fixed WP5540U report descriptor */ __u8 uclogic_rdesc_wp5540u_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x14, /* Logical Minimum (0), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x7C, 0x15, /* Physical Maximum (5500), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x02, /* Usage (Mouse), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x08, /* Report ID (8), */ 0x09, 0x01, /* Usage (Pointer), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x03, /* Usage Maximum (03h), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x75, 0x08, /* Report Size (8), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x15, 0x81, /* Logical Minimum (-127), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x09, 0x38, /* Usage (Wheel), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_wp5540u_fixed_size = sizeof(uclogic_rdesc_wp5540u_fixed_arr); /* Fixed WP8060U report descriptor */ __u8 uclogic_rdesc_wp8060u_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x14, /* Logical Minimum (0), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x02, /* Usage (Mouse), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x08, /* Report ID (8), */ 0x09, 0x01, /* Usage (Pointer), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x03, /* Usage Maximum (03h), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x75, 0x08, /* Report Size (8), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x15, 0x81, /* Logical Minimum (-127), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x09, 0x38, /* Usage (Wheel), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_wp8060u_fixed_size = sizeof(uclogic_rdesc_wp8060u_fixed_arr); /* Fixed WP1062 report descriptor */ __u8 uclogic_rdesc_wp1062_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x01, /* Input (Constant), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x14, /* Logical Minimum (0), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x10, 0x27, /* Physical Maximum (10000), */ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0xB7, 0x19, /* Physical Maximum (6583), */ 0x26, 0x6E, 0x33, /* Logical Maximum (13166), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_wp1062_fixed_size = sizeof(uclogic_rdesc_wp1062_fixed_arr); /* Fixed PF1209 report descriptor */ __u8 uclogic_rdesc_pf1209_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x14, /* Logical Minimum (0), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x28, 0x23, /* Physical Maximum (9000), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0, /* End Collection, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x02, /* Usage (Mouse), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x08, /* Report ID (8), */ 0x09, 0x01, /* Usage (Pointer), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x03, /* Usage Maximum (03h), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x75, 0x08, /* Report Size (8), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x15, 0x81, /* Logical Minimum (-127), */ 0x25, 0x7F, /* Logical Maximum (127), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x09, 0x38, /* Usage (Wheel), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_pf1209_fixed_size = sizeof(uclogic_rdesc_pf1209_fixed_arr); /* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */ __u8 uclogic_rdesc_twhl850_fixed0_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x03, /* Report Count (3), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x81, 0x02, /* Input (Variable), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x95, 0x01, /* Report Count (1), */ 0x09, 0x32, /* Usage (In Range), */ 0x81, 0x02, /* Input (Variable), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x75, 0x10, /* Report Size (16), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x65, 0x13, /* Unit (Inch), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */ 0x26, 0x00, 0x7D, /* Logical Maximum (32000), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x88, 0x13, /* Physical Maximum (5000), */ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_twhl850_fixed0_size = sizeof(uclogic_rdesc_twhl850_fixed0_arr); /* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */ __u8 uclogic_rdesc_twhl850_fixed1_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x02, /* Usage (Mouse), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x01, /* Report ID (1), */ 0x09, 0x01, /* Usage (Pointer), */ 0xA0, /* Collection (Physical), */ 0x05, 0x09, /* Usage Page (Button), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x03, /* Report Count (3), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x03, /* Usage Maximum (03h), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x09, 0x38, /* Usage (Wheel), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x01, /* Report Count (1), */ 0x75, 0x08, /* Report Size (8), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_twhl850_fixed1_size = sizeof(uclogic_rdesc_twhl850_fixed1_arr); /* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */ __u8 uclogic_rdesc_twhl850_fixed2_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x06, /* Usage (Keyboard), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x03, /* Report ID (3), */ 0x05, 0x07, /* Usage Page (Keyboard), */ 0x14, /* Logical Minimum (0), */ 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */ 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x08, /* Report Count (8), */ 0x81, 0x02, /* Input (Variable), */ 0x18, /* Usage Minimum (None), */ 0x29, 0xFF, /* Usage Maximum (FFh), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x06, /* Report Count (6), */ 0x80, /* Input, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_twhl850_fixed2_size = sizeof(uclogic_rdesc_twhl850_fixed2_arr); /* Fixed TWHA60 report descriptor, interface 0 (stylus) */ __u8 uclogic_rdesc_twha60_fixed0_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x01, /* Input (Constant), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x14, /* Logical Minimum (0), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x65, 0x13, /* Unit (Inch), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x10, 0x27, /* Physical Maximum (10000), */ 0x27, 0x3F, 0x9C, 0x00, 0x00, /* Logical Maximum (39999), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0x6A, 0x18, /* Physical Maximum (6250), */ 0x26, 0xA7, 0x61, /* Logical Maximum (24999), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_twha60_fixed0_size = sizeof(uclogic_rdesc_twha60_fixed0_arr); /* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */ __u8 uclogic_rdesc_twha60_fixed1_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x06, /* Usage (Keyboard), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x05, /* Report ID (5), */ 0x05, 0x07, /* Usage Page (Keyboard), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x08, /* Report Count (8), */ 0x81, 0x01, /* Input (Constant), */ 0x95, 0x0C, /* Report Count (12), */ 0x19, 0x3A, /* Usage Minimum (KB F1), */ 0x29, 0x45, /* Usage Maximum (KB F12), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x0C, /* Report Count (12), */ 0x19, 0x68, /* Usage Minimum (KB F13), */ 0x29, 0x73, /* Usage Maximum (KB F24), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x08, /* Report Count (8), */ 0x81, 0x01, /* Input (Constant), */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_twha60_fixed1_size = sizeof(uclogic_rdesc_twha60_fixed1_arr); /* Fixed report descriptor template for (tweaked) v1 pen reports */ const __u8 uclogic_rdesc_v1_pen_template_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x07, /* Report ID (7), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x65, 0x13, /* Unit (Inch), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x27, UCLOGIC_RDESC_PEN_PH(X_LM), /* Logical Maximum (PLACEHOLDER), */ 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), /* Physical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), /* Logical Maximum (PLACEHOLDER), */ 0x47, UCLOGIC_RDESC_PEN_PH(Y_PM), /* Physical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), /* Logical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_v1_pen_template_size = sizeof(uclogic_rdesc_v1_pen_template_arr); /* Fixed report descriptor template for (tweaked) v2 pen reports */ const __u8 uclogic_rdesc_v2_pen_template_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x08, /* Report ID (8), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x65, 0x13, /* Unit (Inch), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x75, 0x18, /* Report Size (24), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x27, UCLOGIC_RDESC_PEN_PH(X_LM), /* Logical Maximum (PLACEHOLDER), */ 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), /* Physical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), /* Logical Maximum (PLACEHOLDER), */ 0x47, UCLOGIC_RDESC_PEN_PH(Y_PM), /* Physical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x75, 0x10, /* Report Size (16), */ 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), /* Logical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ 0x54, /* Unit Exponent (0), */ 0x65, 0x14, /* Unit (Degrees), */ 0x35, 0xC4, /* Physical Minimum (-60), */ 0x45, 0x3C, /* Physical Maximum (60), */ 0x15, 0xC4, /* Logical Minimum (-60), */ 0x25, 0x3C, /* Logical Maximum (60), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x02, /* Report Count (2), */ 0x09, 0x3D, /* Usage (X Tilt), */ 0x09, 0x3E, /* Usage (Y Tilt), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_v2_pen_template_size = sizeof(uclogic_rdesc_v2_pen_template_arr); /* * Expand to the contents of a generic frame buttons report descriptor. * * @_id: The report ID to use. * @_size: Size of the report to pad to, including report ID, bytes. */ #define UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(_id, _size) \ 0x05, 0x01, /* Usage Page (Desktop), */ \ 0x09, 0x07, /* Usage (Keypad), */ \ 0xA1, 0x01, /* Collection (Application), */ \ 0x85, (_id), /* Report ID (_id), */ \ 0x14, /* Logical Minimum (0), */ \ 0x25, 0x01, /* Logical Maximum (1), */ \ 0x75, 0x01, /* Report Size (1), */ \ 0x05, 0x0D, /* Usage Page (Digitizer), */ \ 0x09, 0x39, /* Usage (Tablet Function Keys), */ \ 0xA0, /* Collection (Physical), */ \ 0x09, 0x44, /* Usage (Barrel Switch), */ \ 0x95, 0x01, /* Report Count (1), */ \ 0x81, 0x02, /* Input (Variable), */ \ 0x05, 0x01, /* Usage Page (Desktop), */ \ 0x09, 0x30, /* Usage (X), */ \ 0x09, 0x31, /* Usage (Y), */ \ 0x95, 0x02, /* Report Count (2), */ \ 0x81, 0x02, /* Input (Variable), */ \ 0x95, 0x15, /* Report Count (21), */ \ 0x81, 0x01, /* Input (Constant), */ \ 0x05, 0x09, /* Usage Page (Button), */ \ 0x19, 0x01, /* Usage Minimum (01h), */ \ 0x29, 0x0A, /* Usage Maximum (0Ah), */ \ 0x95, 0x0A, /* Report Count (10), */ \ 0x81, 0x02, /* Input (Variable), */ \ 0xC0, /* End Collection, */ \ 0x05, 0x01, /* Usage Page (Desktop), */ \ 0x09, 0x05, /* Usage (Gamepad), */ \ 0xA0, /* Collection (Physical), */ \ 0x05, 0x09, /* Usage Page (Button), */ \ 0x19, 0x01, /* Usage Minimum (01h), */ \ 0x29, 0x03, /* Usage Maximum (03h), */ \ 0x95, 0x03, /* Report Count (3), */ \ 0x81, 0x02, /* Input (Variable), */ \ 0x95, ((_size) * 8 - 45), \ /* Report Count (padding), */ \ 0x81, 0x01, /* Input (Constant), */ \ 0xC0, /* End Collection, */ \ 0xC0 /* End Collection */ /* Fixed report descriptor for (tweaked) v1 frame reports */ const __u8 uclogic_rdesc_v1_frame_arr[] = { UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(UCLOGIC_RDESC_V1_FRAME_ID, 8) }; const size_t uclogic_rdesc_v1_frame_size = sizeof(uclogic_rdesc_v1_frame_arr); /* Fixed report descriptor for (tweaked) v2 frame button reports */ const __u8 uclogic_rdesc_v2_frame_buttons_arr[] = { UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID, 12) }; const size_t uclogic_rdesc_v2_frame_buttons_size = sizeof(uclogic_rdesc_v2_frame_buttons_arr); /* Fixed report descriptor for (tweaked) v2 frame touch ring reports */ const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID, /* Report ID (TOUCH_ID), */ 0x14, /* Logical Minimum (0), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x39, /* Usage (Tablet Function Keys), */ 0xA0, /* Collection (Physical), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x05, 0x09, /* Usage Page (Button), */ 0x09, 0x01, /* Usage (01h), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x07, /* Report Count (7), */ 0x81, 0x01, /* Input (Constant), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x38, /* Usage (Wheel), */ 0x95, 0x01, /* Report Count (1), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x0B, /* Logical Maximum (11), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x2E, /* Report Count (46), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_v2_frame_touch_ring_size = sizeof(uclogic_rdesc_v2_frame_touch_ring_arr); /* Fixed report descriptor for (tweaked) v2 frame touch strip reports */ const __u8 uclogic_rdesc_v2_frame_touch_strip_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID, /* Report ID (TOUCH_ID), */ 0x14, /* Logical Minimum (0), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x39, /* Usage (Tablet Function Keys), */ 0xA0, /* Collection (Physical), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x05, 0x09, /* Usage Page (Button), */ 0x09, 0x01, /* Usage (01h), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x07, /* Report Count (7), */ 0x81, 0x01, /* Input (Constant), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x38, /* Usage (Wheel), */ 0x95, 0x01, /* Report Count (1), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x07, /* Logical Maximum (7), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x2E, /* Report Count (46), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_v2_frame_touch_strip_size = sizeof(uclogic_rdesc_v2_frame_touch_strip_arr); /* Fixed report descriptor for (tweaked) v2 frame dial reports */ const __u8 uclogic_rdesc_v2_frame_dial_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, UCLOGIC_RDESC_V2_FRAME_DIAL_ID, /* Report ID (DIAL_ID), */ 0x14, /* Logical Minimum (0), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x39, /* Usage (Tablet Function Keys), */ 0xA0, /* Collection (Physical), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x09, /* Usage Page (Button), */ 0x09, 0x01, /* Usage (01h), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x06, /* Report Count (6), */ 0x81, 0x01, /* Input (Constant), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x38, /* Usage (Wheel), */ 0x95, 0x01, /* Report Count (1), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x2E, /* Report Count (46), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_v2_frame_dial_size = sizeof(uclogic_rdesc_v2_frame_dial_arr); /* Fixed report descriptor template for UGEE v2 pen reports */ const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[] = { 0x05, 0x0d, /* Usage Page (Digitizers), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xa1, 0x01, /* Collection (Application), */ 0x85, 0x02, /* Report ID (2), */ 0x09, 0x20, /* Usage (Stylus), */ 0xa1, 0x00, /* Collection (Physical), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x09, 0x46, /* Usage (Tablet Pick), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x03, /* Report Count (3), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x35, 0x00, /* Physical Minimum (0), */ 0xa4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x30, /* Usage (X), */ 0x65, 0x13, /* Unit (Inch), */ 0x55, 0x0d, /* Unit Exponent (-3), */ 0x27, UCLOGIC_RDESC_PEN_PH(X_LM), /* Logical Maximum (PLACEHOLDER), */ 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), /* Physical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), /* Logical Maximum (PLACEHOLDER), */ 0x47, UCLOGIC_RDESC_PEN_PH(Y_PM), /* Physical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ 0xb4, /* Pop, */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x45, 0x00, /* Physical Maximum (0), */ 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), /* Logical Maximum (PLACEHOLDER), */ 0x75, 0x0D, /* Report Size (13), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x01, /* Input (Constant), */ 0x09, 0x3d, /* Usage (X Tilt), */ 0x35, 0xC3, /* Physical Minimum (-61), */ 0x45, 0x3C, /* Physical Maximum (60), */ 0x15, 0xC3, /* Logical Minimum (-61), */ 0x25, 0x3C, /* Logical Maximum (60), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x3e, /* Usage (Y Tilt), */ 0x35, 0xC3, /* Physical Minimum (-61), */ 0x45, 0x3C, /* Physical Maximum (60), */ 0x15, 0xC3, /* Logical Minimum (-61), */ 0x25, 0x3C, /* Logical Maximum (60), */ 0x81, 0x02, /* Input (Variable), */ 0xc0, /* End Collection, */ 0xc0, /* End Collection */ }; const size_t uclogic_rdesc_ugee_v2_pen_template_size = sizeof(uclogic_rdesc_ugee_v2_pen_template_arr); /* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */ const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, UCLOGIC_RDESC_V1_FRAME_ID, /* Report ID, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x39, /* Usage (Tablet Function Keys), */ 0xA0, /* Collection (Physical), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x08, /* Report Count (8), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ UCLOGIC_RDESC_FRAME_PH_BTN, /* Usage Maximum (PLACEHOLDER), */ 0x95, 0x0A, /* Report Count (10), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x46, /* Report Count (70), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size = sizeof(uclogic_rdesc_ugee_v2_frame_btn_template_arr); /* Fixed report descriptor for Ugee EX07 frame */ const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x06, /* Report ID (6), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x39, /* Usage (Tablet Function Keys), */ 0xA0, /* Collection (Physical), */ 0x05, 0x09, /* Usage Page (Button), */ 0x75, 0x01, /* Report Size (1), */ 0x19, 0x03, /* Usage Minimum (03h), */ 0x29, 0x06, /* Usage Maximum (06h), */ 0x95, 0x04, /* Report Count (4), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x1A, /* Report Count (26), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x02, /* Usage Maximum (02h), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_ugee_ex07_frame_size = sizeof(uclogic_rdesc_ugee_ex07_frame_arr); /* Fixed report descriptor for Ugee G5 frame controls */ const __u8 uclogic_rdesc_ugee_g5_frame_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x06, /* Report ID (6), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x39, /* Usage (Tablet Function Keys), */ 0xA0, /* Collection (Physical), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x05, /* Usage Maximum (05h), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x03, /* Report Count (3), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x0B, /* Report Count (11), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x38, /* Usage (Wheel), */ 0x15, 0xFF, /* Logical Minimum (-1), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x02, /* Report Size (2), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x06, /* Input (Variable, Relative), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_ugee_g5_frame_size = sizeof(uclogic_rdesc_ugee_g5_frame_arr); /* Fixed report descriptor for XP-Pen Deco 01 frame controls */ const __u8 uclogic_rdesc_xppen_deco01_frame_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x06, /* Report ID (6), */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x39, /* Usage (Tablet Function Keys), */ 0xA0, /* Collection (Physical), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x08, /* Usage Maximum (08h), */ 0x95, 0x08, /* Report Count (8), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x44, /* Usage (Barrel Switch), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x30, /* Usage (X), */ 0x09, 0x31, /* Usage (Y), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x15, /* Report Count (21), */ 0x81, 0x01, /* Input (Constant), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; const size_t uclogic_rdesc_xppen_deco01_frame_size = sizeof(uclogic_rdesc_xppen_deco01_frame_arr); /** * uclogic_rdesc_template_apply() - apply report descriptor parameters to a * report descriptor template, creating a report descriptor. Copies the * template over to the new report descriptor and replaces every occurrence of * the template placeholders, followed by an index byte, with the value from the * parameter list at that index. * * @template_ptr: Pointer to the template buffer. * @template_size: Size of the template buffer. * @param_list: List of template parameters. * @param_num: Number of parameters in the list. * * Returns: * Kmalloc-allocated pointer to the created report descriptor, * or NULL if allocation failed. */ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, size_t template_size, const s32 *param_list, size_t param_num) { static const __u8 btn_head[] = {UCLOGIC_RDESC_FRAME_PH_BTN_HEAD}; static const __u8 pen_head[] = {UCLOGIC_RDESC_PEN_PH_HEAD}; __u8 *rdesc_ptr; __u8 *p; s32 v; rdesc_ptr = kmemdup(template_ptr, template_size, GFP_KERNEL); if (rdesc_ptr == NULL) return NULL; for (p = rdesc_ptr; p + sizeof(btn_head) < rdesc_ptr + template_size;) { if (p + sizeof(pen_head) < rdesc_ptr + template_size && memcmp(p, pen_head, sizeof(pen_head)) == 0 && p[sizeof(pen_head)] < param_num) { v = param_list[p[sizeof(pen_head)]]; put_unaligned(cpu_to_le32(v), (s32 *)p); p += sizeof(pen_head) + 1; } else if (memcmp(p, btn_head, sizeof(btn_head)) == 0 && p[sizeof(btn_head)] < param_num) { v = param_list[p[sizeof(btn_head)]]; put_unaligned((__u8)0x2A, p); /* Usage Maximum */ put_unaligned_le16((__force u16)cpu_to_le16(v), p + 1); p += sizeof(btn_head) + 1; } else { p++; } } return rdesc_ptr; } 07070100000022000081A40000000000000000000000016452046B00001BEF000000000000000000000000000000000000003A00000000digimend-kernel-drivers-0~git20230503/hid-uclogic-rdesc.h/* SPDX-License-Identifier: GPL-2.0+ */ /* * HID driver for UC-Logic devices not fully compliant with HID standard * - original and fixed report descriptors * * Copyright (c) 2010-2018 Nikolai Kondrashov * Copyright (c) 2013 Martin Rusko */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #ifndef _HID_UCLOGIC_RDESC_H #define _HID_UCLOGIC_RDESC_H #include <linux/usb.h> /* Size of the original descriptor of WPXXXXU tablets */ #define UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE 212 /* Fixed WP4030U report descriptor */ extern __u8 uclogic_rdesc_wp4030u_fixed_arr[]; extern const size_t uclogic_rdesc_wp4030u_fixed_size; /* Fixed WP5540U report descriptor */ extern __u8 uclogic_rdesc_wp5540u_fixed_arr[]; extern const size_t uclogic_rdesc_wp5540u_fixed_size; /* Fixed WP8060U report descriptor */ extern __u8 uclogic_rdesc_wp8060u_fixed_arr[]; extern const size_t uclogic_rdesc_wp8060u_fixed_size; /* Size of the original descriptor of the new WP5540U tablet */ #define UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE 232 /* Size of the original descriptor of WP1062 tablet */ #define UCLOGIC_RDESC_WP1062_ORIG_SIZE 254 /* Fixed WP1062 report descriptor */ extern __u8 uclogic_rdesc_wp1062_fixed_arr[]; extern const size_t uclogic_rdesc_wp1062_fixed_size; /* Size of the original descriptor of PF1209 tablet */ #define UCLOGIC_RDESC_PF1209_ORIG_SIZE 234 /* Fixed PF1209 report descriptor */ extern __u8 uclogic_rdesc_pf1209_fixed_arr[]; extern const size_t uclogic_rdesc_pf1209_fixed_size; /* Size of the original descriptors of TWHL850 tablet */ #define UCLOGIC_RDESC_TWHL850_ORIG0_SIZE 182 #define UCLOGIC_RDESC_TWHL850_ORIG1_SIZE 161 #define UCLOGIC_RDESC_TWHL850_ORIG2_SIZE 92 /* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */ extern __u8 uclogic_rdesc_twhl850_fixed0_arr[]; extern const size_t uclogic_rdesc_twhl850_fixed0_size; /* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */ extern __u8 uclogic_rdesc_twhl850_fixed1_arr[]; extern const size_t uclogic_rdesc_twhl850_fixed1_size; /* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */ extern __u8 uclogic_rdesc_twhl850_fixed2_arr[]; extern const size_t uclogic_rdesc_twhl850_fixed2_size; /* Size of the original descriptors of TWHA60 tablet */ #define UCLOGIC_RDESC_TWHA60_ORIG0_SIZE 254 #define UCLOGIC_RDESC_TWHA60_ORIG1_SIZE 139 /* Fixed TWHA60 report descriptor, interface 0 (stylus) */ extern __u8 uclogic_rdesc_twha60_fixed0_arr[]; extern const size_t uclogic_rdesc_twha60_fixed0_size; /* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */ extern __u8 uclogic_rdesc_twha60_fixed1_arr[]; extern const size_t uclogic_rdesc_twha60_fixed1_size; /* Report descriptor template placeholder head */ #define UCLOGIC_RDESC_PEN_PH_HEAD 0xFE, 0xED, 0x1D #define UCLOGIC_RDESC_FRAME_PH_BTN_HEAD 0xFE, 0xED /* Apply report descriptor parameters to a report descriptor template */ extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, size_t template_size, const s32 *param_list, size_t param_num); /* Report descriptor template placeholder IDs */ enum uclogic_rdesc_ph_id { UCLOGIC_RDESC_PEN_PH_ID_X_LM, UCLOGIC_RDESC_PEN_PH_ID_X_PM, UCLOGIC_RDESC_PEN_PH_ID_Y_LM, UCLOGIC_RDESC_PEN_PH_ID_Y_PM, UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM, UCLOGIC_RDESC_FRAME_PH_ID_UM, UCLOGIC_RDESC_PH_ID_NUM }; /* Report descriptor pen template placeholder */ #define UCLOGIC_RDESC_PEN_PH(_ID) \ UCLOGIC_RDESC_PEN_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID /* Report descriptor frame buttons template placeholder */ #define UCLOGIC_RDESC_FRAME_PH_BTN \ UCLOGIC_RDESC_FRAME_PH_BTN_HEAD, UCLOGIC_RDESC_FRAME_PH_ID_UM /* Report ID for v1 pen reports */ #define UCLOGIC_RDESC_V1_PEN_ID 0x07 /* Fixed report descriptor template for (tweaked) v1 pen reports */ extern const __u8 uclogic_rdesc_v1_pen_template_arr[]; extern const size_t uclogic_rdesc_v1_pen_template_size; /* Report ID for v2 pen reports */ #define UCLOGIC_RDESC_V2_PEN_ID 0x08 /* Fixed report descriptor template for (tweaked) v2 pen reports */ extern const __u8 uclogic_rdesc_v2_pen_template_arr[]; extern const size_t uclogic_rdesc_v2_pen_template_size; /* Report ID for tweaked v1 frame reports */ #define UCLOGIC_RDESC_V1_FRAME_ID 0xf7 /* Fixed report descriptor for (tweaked) v1 frame reports */ extern const __u8 uclogic_rdesc_v1_frame_arr[]; extern const size_t uclogic_rdesc_v1_frame_size; /* Report ID for tweaked v2 frame button reports */ #define UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID 0xf7 /* Fixed report descriptor for (tweaked) v2 frame button reports */ extern const __u8 uclogic_rdesc_v2_frame_buttons_arr[]; extern const size_t uclogic_rdesc_v2_frame_buttons_size; /* Report ID for tweaked v2 frame touch ring/strip reports */ #define UCLOGIC_RDESC_V2_FRAME_TOUCH_ID 0xf8 /* Fixed report descriptor for (tweaked) v2 frame touch ring reports */ extern const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[]; extern const size_t uclogic_rdesc_v2_frame_touch_ring_size; /* Fixed report descriptor for (tweaked) v2 frame touch strip reports */ extern const __u8 uclogic_rdesc_v2_frame_touch_strip_arr[]; extern const size_t uclogic_rdesc_v2_frame_touch_strip_size; /* Device ID byte offset in v2 frame touch ring/strip reports */ #define UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE 0x4 /* Report ID for tweaked v2 frame dial reports */ #define UCLOGIC_RDESC_V2_FRAME_DIAL_ID 0xf9 /* Fixed report descriptor for (tweaked) v2 frame dial reports */ extern const __u8 uclogic_rdesc_v2_frame_dial_arr[]; extern const size_t uclogic_rdesc_v2_frame_dial_size; /* Device ID byte offset in v2 frame dial reports */ #define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4 /* Fixed report descriptor template for UGEE v2 pen reports */ extern const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[]; extern const size_t uclogic_rdesc_ugee_v2_pen_template_size; /* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */ extern const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[]; extern const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size; /* Fixed report descriptor for Ugee EX07 frame */ extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[]; extern const size_t uclogic_rdesc_ugee_ex07_frame_size; /* Fixed report descriptor for XP-Pen Deco 01 frame controls */ extern const __u8 uclogic_rdesc_xppen_deco01_frame_arr[]; extern const size_t uclogic_rdesc_xppen_deco01_frame_size; /* Fixed report descriptor for Ugee G5 frame controls */ extern const __u8 uclogic_rdesc_ugee_g5_frame_arr[]; extern const size_t uclogic_rdesc_ugee_g5_frame_size; /* Report ID of Ugee G5 frame control reports */ #define UCLOGIC_RDESC_UGEE_G5_FRAME_ID 0x06 /* Device ID byte offset in Ugee G5 frame report */ #define UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE 0x2 /* Least-significant bit of Ugee G5 frame rotary encoder state */ #define UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB 38 #endif /* _HID_UCLOGIC_RDESC_H */ 07070100000023000081A40000000000000000000000016452046B00001360000000000000000000000000000000000000003600000000digimend-kernel-drivers-0~git20230503/hid-viewsonic.c// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for ViewSonic devices not fully compliant with HID standard * * Copyright (c) 2017 Nikolai Kondrashov */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include <linux/device.h> #include <linux/hid.h> #include <linux/module.h> #include <linux/usb.h> #include "hid-ids.h" /* Size of the original descriptor of PD1011 signature pad */ #define PD1011_RDESC_ORIG_SIZE 408 /* Fixed report descriptor of PD1011 signature pad */ static __u8 pd1011_rdesc_fixed[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x02, /* Report ID (2), */ 0x09, 0x20, /* Usage (Stylus), */ 0xA0, /* Collection (Physical), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0xA4, /* Push, */ 0x05, 0x01, /* Usage Page (Desktop), */ 0x65, 0x13, /* Unit (Inch), */ 0x55, 0xFD, /* Unit Exponent (-3), */ 0x34, /* Physical Minimum (0), */ 0x09, 0x30, /* Usage (X), */ 0x46, 0x5D, 0x21, /* Physical Maximum (8541), */ 0x27, 0x80, 0xA9, 0x00, 0x00, /* Logical Maximum (43392), */ 0x81, 0x02, /* Input (Variable), */ 0x09, 0x31, /* Usage (Y), */ 0x46, 0xDA, 0x14, /* Physical Maximum (5338), */ 0x26, 0xF0, 0x69, /* Logical Maximum (27120), */ 0x81, 0x02, /* Input (Variable), */ 0xB4, /* Pop, */ 0x14, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x09, 0x32, /* Usage (In Range), */ 0x09, 0x42, /* Usage (Tip Switch), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x09, 0x30, /* Usage (Tip Pressure), */ 0x15, 0x05, /* Logical Minimum (5), */ 0x26, 0xFF, 0x07, /* Logical Maximum (2047), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x10, /* Report Size (16), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x03, /* Input (Constant, Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; static __u8 *viewsonic_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { switch (hdev->product) { case USB_DEVICE_ID_VIEWSONIC_PD1011: case USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011: if (*rsize == PD1011_RDESC_ORIG_SIZE) { rdesc = pd1011_rdesc_fixed; *rsize = sizeof(pd1011_rdesc_fixed); } break; } return rdesc; } static int viewsonic_probe(struct hid_device *hdev, const struct hid_device_id *id) { int rc; rc = hid_parse(hdev); if (rc) { hid_err(hdev, "parse failed\n"); return rc; } rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (rc) { hid_err(hdev, "hw start failed\n"); return rc; } return 0; } static const struct hid_device_id viewsonic_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_VIEWSONIC, USB_DEVICE_ID_VIEWSONIC_PD1011) }, { HID_USB_DEVICE(USB_VENDOR_ID_SIGNOTEC, USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011) }, { } }; MODULE_DEVICE_TABLE(hid, viewsonic_devices); static struct hid_driver viewsonic_driver = { .name = "viewsonic", .id_table = viewsonic_devices, .probe = viewsonic_probe, .report_fixup = viewsonic_report_fixup, }; module_hid_driver(viewsonic_driver); MODULE_LICENSE("GPL"); MODULE_VERSION("11"); 07070100000024000081A40000000000000000000000016452046B00000347000000000000000000000000000000000000003100000000digimend-kernel-drivers-0~git20230503/udev.rulesSUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:0000099A:00002620", \ RUN+="hid-rebind" SUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:0000256C:*", \ RUN+="hid-rebind" SUBSYSTEM=="input", ENV{ID_BUS}=="usb" ENV{ID_VENDOR_ID}=="256c", \ ATTRS{name}=="* Touch *", ENV{ID_INPUT.tags}="low_res_touch" SUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:00005543:*", \ RUN+="hid-rebind" SUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:00000458:*", \ RUN+="hid-rebind" SUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:00002179:*", \ RUN+="hid-rebind" SUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:000028BD:*", \ RUN+="hid-rebind" SUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:00000543:0000E621", \ RUN+="hid-rebind" SUBSYSTEM=="hid", ACTION=="add", ENV{HID_ID}=="0003:00002133:00000018", \ RUN+="hid-rebind" 07070100000025000041ED0000000000000000000000026452046B00000000000000000000000000000000000000000000002D00000000digimend-kernel-drivers-0~git20230503/usbhid07070100000026000081A40000000000000000000000016452046B000000F1000000000000000000000000000000000000003600000000digimend-kernel-drivers-0~git20230503/usbhid/usbhid.h/* * Definitions from the Linux kernel's private header * drivers/hid/usbhid/usbhid.h. */ #ifndef __USBHID_H #define __USBHID_H #define hid_to_usb_dev(hid_dev) \ container_of(hid_dev->dev.parent->parent, struct usb_device, dev) #endif 07070100000027000081A40000000000000000000000016452046B000004BB000000000000000000000000000000000000003000000000digimend-kernel-drivers-0~git20230503/xorg.conf# # InputClass sections for some tablets supported by the DIGImend kernel # drivers. Organized into separate InputClass sections based on (one of) the # advertised brands. Mostly because the MatchUSBID options would become too # long otherwise. # Section "InputClass" Identifier "Huion tablets with Wacom driver" MatchUSBID "5543:006e|256c:006e|256c:006d" MatchDevicePath "/dev/input/event*" MatchIsKeyboard "false" Driver "wacom" EndSection Section "InputClass" Identifier "Tablet low-res touch controls with Wacom driver" MatchUSBID "256c:*" MatchDevicePath "/dev/input/event*" MatchTag "low_res_touch" Driver "wacom" Option "Suppress" "0" EndSection Section "InputClass" Identifier "Ugee/XP-Pen tablets with Wacom driver" MatchUSBID "28bd:007[1458]|28bd:0094|28bd:0042|5543:004[57]|5543:0081|5543:0004|5543:3031" MatchDevicePath "/dev/input/event*" Driver "wacom" EndSection Section "InputClass" Identifier "Ugtizer tablets with Wacom driver" MatchUSBID "2179:0053" MatchDevicePath "/dev/input/event*" Driver "wacom" EndSection Section "InputClass" Identifier "Yiynova tablets with Wacom driver" MatchUSBID "5543:004d" MatchDevicePath "/dev/input/event*" Driver "wacom" EndSection 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!515 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor