sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/translations/zh_CN/hid/hid-bpfmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/zh_TW/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/it_IT/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/ja_JP/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/ko_KR/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/sp_SP/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageEnglishuh1h hh _documenthsourceNlineNubhcomment)}(h SPDX-License-Identifier: GPL-2.0h]h SPDX-License-Identifier: GPL-2.0}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhh9/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf.rsthKubhsection)}(hhh](htitle)}(hHID-BPFh]hHID-BPF}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh paragraph)}(hHID is a standard protocol for input devices but some devices may require custom tweaks, traditionally done with a kernel driver fix. Using the eBPF capabilities instead speeds up development and adds new capabilities to the existing HID interfaces.h]hHID is a standard protocol for input devices but some devices may require custom tweaks, traditionally done with a kernel driver fix. Using the eBPF capabilities instead speeds up development and adds new capabilities to the existing HID interfaces.}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhhhubhtopic)}(hhh]h bullet_list)}(hhh](h list_item)}(hhh](h)}(hhh]h reference)}(hhh]hWhen (and why) to use HID-BPF}(hhhhhNhNubah}(h]id1ah ]h"]h$]h&]refidwhen-and-why-to-use-hid-bpfuh1hhhubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]h)}(hhh]h)}(hhh]hDead zone of a joystick}(hj hhhNhNubah}(h]id2ah ]h"]h$]h&]refiddead-zone-of-a-joystickuh1hhj ubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]h!Simple fixup of report descriptor}(hj.hhhNhNubah}(h]id3ah ]h"]h$]h&]refid!simple-fixup-of-report-descriptoruh1hhj+ubah}(h]h ]h"]h$]h&]uh1hhj(ubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]h0Add a new feature that requires a new kernel API}(hjPhhhNhNubah}(h]id4ah ]h"]h$]h&]refid0add-a-new-feature-that-requires-a-new-kernel-apiuh1hhjMubah}(h]h ]h"]h$]h&]uh1hhjJubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]hBMorph a device into something else and control that from userspace}(hjrhhhNhNubah}(h]id5ah ]h"]h$]h&]refidBmorph-a-device-into-something-else-and-control-that-from-userspaceuh1hhjoubah}(h]h ]h"]h$]h&]uh1hhjlubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]hFirewall}(hjhhhNhNubah}(h]id6ah ]h"]h$]h&]refidfirewalluh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]hTracing}(hjhhhNhNubah}(h]id7ah ]h"]h$]h&]refidtracinguh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh]h)}(hhh]h)}(hhh]hHigh-level view of HID-BPF}(hjhhhNhNubah}(h]id8ah ]h"]h$]h&]refidhigh-level-view-of-hid-bpfuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh]h)}(hhh]h)}(hhh](hIn-tree HID-BPF programs and }(hjhhhNhNubhliteral)}(h``udev-hid-bpf``h]h udev-hid-bpf}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hNhNhjubeh}(h]id9ah ]h"]h$]h&]refid)in-tree-hid-bpf-programs-and-udev-hid-bpfuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh]h)}(hhh]h)}(hhh]hAvailable types of programs}(hj8hhhNhNubah}(h]id10ah ]h"]h$]h&]refidavailable-types-of-programsuh1hhj5ubah}(h]h ]h"]h$]h&]uh1hhj2ubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]h)}(hhh]hDeveloper API:}(hjZhhhNhNubah}(h]id11ah ]h"]h$]h&]refid developer-apiuh1hhjWubah}(h]h ]h"]h$]h&]uh1hhjTubh)}(hhh](h)}(hhh]h)}(hhh]h)}(hhh](h Available }(hjyhhhNhNubj)}(h``struct_ops``h]h struct_ops}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hNhNhjyubh for HID-BPF:}(hjyhhhNhNubeh}(h]id12ah ]h"]h$]h&]refid available-struct-ops-for-hid-bpfuh1hhjvubah}(h]h ]h"]h$]h&]uh1hhjsubah}(h]h ]h"]h$]h&]uh1hhjpubh)}(hhh]h)}(hhh]h)}(hhh]h/User API data structures available in programs:}(hjhhhNhNubah}(h]id13ah ]h"]h$]h&]refid.user-api-data-structures-available-in-programsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjpubh)}(hhh]h)}(hhh]h)}(hhh]hBAvailable API that can be used in all HID-BPF struct_ops programs:}(hjhhhNhNubah}(h]id14ah ]h"]h$]h&]refidAavailable-api-that-can-be-used-in-all-hid-bpf-struct-ops-programsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjpubh)}(hhh]h)}(hhh]h)}(hhh]hgAvailable API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs:}(hjhhhNhNubah}(h]id15ah ]h"]h$]h&]refidfavailable-api-that-can-be-used-in-syscall-hid-bpf-programs-or-in-sleepable-hid-bpf-struct-ops-programsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjpubeh}(h]h ]h"]h$]h&]uh1hhjTubeh}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]h)}(hhh]h%General overview of a HID-BPF program}(hjhhhNhNubah}(h]id16ah ]h"]h$]h&]refid%general-overview-of-a-hid-bpf-programuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh](h)}(hhh]h)}(hhh]h)}(hhh]h*Accessing the data attached to the context}(hj>hhhNhNubah}(h]id17ah ]h"]h$]h&]refid*accessing-the-data-attached-to-the-contextuh1hhj;ubah}(h]h ]h"]h$]h&]uh1hhj8ubah}(h]h ]h"]h$]h&]uh1hhj5ubh)}(hhh]h)}(hhh]h)}(hhh]hEffect of a HID-BPF program}(hj`hhhNhNubah}(h]id18ah ]h"]h$]h&]refideffect-of-a-hid-bpf-programuh1hhj]ubah}(h]h ]h"]h$]h&]uh1hhjZubah}(h]h ]h"]h$]h&]uh1hhj5ubeh}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh]h)}(hhh]h)}(hhh]h#Attaching a bpf program to a device}(hjhhhNhNubah}(h]id19ah ]h"]h$]h&]refid#attaching-a-bpf-program-to-a-deviceuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]h)}(hhh]h9An (almost) complete example of a BPF enhanced HID device}(hjhhhNhNubah}(h]id20ah ]h"]h$]h&]refid7an-almost-complete-example-of-a-bpf-enhanced-hid-deviceuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh](h)}(hhh]h)}(hhh]h)}(hhh]hFiltering events}(hjhhhNhNubah}(h]id21ah ]h"]h$]h&]refidfiltering-eventsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]hControlling the device}(hjhhhNhNubah}(h]id22ah ]h"]h$]h&]refidcontrolling-the-deviceuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhNhNubah}(h]contentsah ](contentslocaleh"]contentsah$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(hWhen (and why) to use HID-BPFh]hWhen (and why) to use HID-BPF}(hj,hhhNhNubah}(h]h ]h"]h$]h&]refidhuh1hhj)hhhhhKubh)}(hYThere are several use cases when using HID-BPF is better than standard kernel driver fix:h]hYThere are several use cases when using HID-BPF is better than standard kernel driver fix:}(hj;hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj)hhubh)}(hhh](h)}(hDead zone of a joystickh]hDead zone of a joystick}(hjLhhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhjIhhhhhKubh)}(hAssuming you have a joystick that is getting older, it is common to see it wobbling around its neutral point. This is usually filtered at the application level by adding a *dead zone* for this specific axis.h](hAssuming you have a joystick that is getting older, it is common to see it wobbling around its neutral point. This is usually filtered at the application level by adding a }(hjZhhhNhNubhemphasis)}(h *dead zone*h]h dead zone}(hjdhhhNhNubah}(h]h ]h"]h$]h&]uh1jbhjZubh for this specific axis.}(hjZhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjIhhubh)}(hWith HID-BPF, we can apply this filtering in the kernel directly so userspace does not get woken up when nothing else is happening on the input controller.h]hWith HID-BPF, we can apply this filtering in the kernel directly so userspace does not get woken up when nothing else is happening on the input controller.}(hj|hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjIhhubh)}(hXOf course, given that this dead zone is specific to an individual device, we can not create a generic fix for all of the same joysticks. Adding a custom kernel API for this (e.g. by adding a sysfs entry) does not guarantee this new kernel API will be broadly adopted and maintained.h]hXOf course, given that this dead zone is specific to an individual device, we can not create a generic fix for all of the same joysticks. Adding a custom kernel API for this (e.g. by adding a sysfs entry) does not guarantee this new kernel API will be broadly adopted and maintained.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK!hjIhhubh)}(hzHID-BPF allows the userspace program to load the program itself, ensuring we only load the custom API when we have a user.h]hzHID-BPF allows the userspace program to load the program itself, ensuring we only load the custom API when we have a user.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK&hjIhhubeh}(h]jah ]h"]dead zone of a joystickah$]h&]uh1hhj)hhhhhKubh)}(hhh](h)}(h!Simple fixup of report descriptorh]h!Simple fixup of report descriptor}(hjhhhNhNubah}(h]h ]h"]h$]h&]j:j7uh1hhjhhhhhK*ubh)}(hIn the HID tree, half of the drivers only fix one key or one byte in the report descriptor. These fixes all require a kernel patch and the subsequent shepherding into a release, a long and painful process for users.h]hIn the HID tree, half of the drivers only fix one key or one byte in the report descriptor. These fixes all require a kernel patch and the subsequent shepherding into a release, a long and painful process for users.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK,hjhhubh)}(hXWe can reduce this burden by providing an eBPF program instead. Once such a program has been verified by the user, we can embed the source code into the kernel tree and ship the eBPF program and load it directly instead of loading a specific kernel module for it.h]hXWe can reduce this burden by providing an eBPF program instead. Once such a program has been verified by the user, we can embed the source code into the kernel tree and ship the eBPF program and load it directly instead of loading a specific kernel module for it.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK0hjhhubh)}(hbNote: distribution of eBPF programs and their inclusion in the kernel is not yet fully implementedh]hbNote: distribution of eBPF programs and their inclusion in the kernel is not yet fully implemented}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK5hjhhubeh}(h]j=ah ]h"]!simple fixup of report descriptorah$]h&]uh1hhj)hhhhhK*ubh)}(hhh](h)}(h0Add a new feature that requires a new kernel APIh]h0Add a new feature that requires a new kernel API}(hjhhhNhNubah}(h]h ]h"]h$]h&]j:jYuh1hhjhhhhhK9ubh)}(hXAn example for such a feature are the Universal Stylus Interface (USI) pens. Basically, USI pens require a new kernel API because there are new channels of communication that our HID and input stack do not support. Instead of using hidraw or creating new sysfs entries or ioctls, we can rely on eBPF to have the kernel API controlled by the consumer and to not impact the performances by waking up userspace every time there is an event.h]hXAn example for such a feature are the Universal Stylus Interface (USI) pens. Basically, USI pens require a new kernel API because there are new channels of communication that our HID and input stack do not support. Instead of using hidraw or creating new sysfs entries or ioctls, we can rely on eBPF to have the kernel API controlled by the consumer and to not impact the performances by waking up userspace every time there is an event.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK;hjhhubeh}(h]j_ah ]h"]0add a new feature that requires a new kernel apiah$]h&]uh1hhj)hhhhhK9ubh)}(hhh](h)}(hBMorph a device into something else and control that from userspaceh]hBMorph a device into something else and control that from userspace}(hjhhhNhNubah}(h]h ]h"]h$]h&]j:j{uh1hhjhhhhhKDubh)}(hX The kernel has a relatively static mapping of HID items to evdev bits. It cannot decide to dynamically transform a given device into something else as it does not have the required context and any such transformation cannot be undone (or even discovered) by userspace.h]hX The kernel has a relatively static mapping of HID items to evdev bits. It cannot decide to dynamically transform a given device into something else as it does not have the required context and any such transformation cannot be undone (or even discovered) by userspace.}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKFhjhhubh)}(hHowever, some devices are useless with that static way of defining devices. For example, the Microsoft Surface Dial is a pushbutton with haptic feedback that is barely usable as of today.h]hHowever, some devices are useless with that static way of defining devices. For example, the Microsoft Surface Dial is a pushbutton with haptic feedback that is barely usable as of today.}(hj4hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKKhjhhubh)}(hXWith eBPF, userspace can morph that device into a mouse, and convert the dial events into wheel events. Also, the userspace program can set/unset the haptic feedback depending on the context. For example, if a menu is visible on the screen we likely need to have a haptic click every 15 degrees. But when scrolling in a web page the user experience is better when the device emits events at the highest resolution.h]hXWith eBPF, userspace can morph that device into a mouse, and convert the dial events into wheel events. Also, the userspace program can set/unset the haptic feedback depending on the context. For example, if a menu is visible on the screen we likely need to have a haptic click every 15 degrees. But when scrolling in a web page the user experience is better when the device emits events at the highest resolution.}(hjBhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKOhjhhubeh}(h]jah ]h"]Bmorph a device into something else and control that from userspaceah$]h&]uh1hhj)hhhhhKDubh)}(hhh](h)}(hFirewallh]hFirewall}(hjZhhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhjWhhhhhKWubh)}(hWhat if we want to prevent other users to access a specific feature of a device? (think a possibly broken firmware update entry point)h]hWhat if we want to prevent other users to access a specific feature of a device? (think a possibly broken firmware update entry point)}(hjhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKYhjWhhubh)}(hYWith eBPF, we can intercept any HID command emitted to the device and validate it or not.h]hYWith eBPF, we can intercept any HID command emitted to the device and validate it or not.}(hjvhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK\hjWhhubh)}(hThis also allows to sync the state between the userspace and the kernel/bpf program because we can intercept any incoming command.h]hThis also allows to sync the state between the userspace and the kernel/bpf program because we can intercept any incoming command.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK_hjWhhubeh}(h]jah ]h"]firewallah$]h&]uh1hhj)hhhhhKWubh)}(hhh](h)}(hTracingh]hTracing}(hjhhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhjhhhhhKcubh)}(hbThe last usage is tracing events and all the fun we can do we BPF to summarize and analyze events.h]hbThe last usage is tracing events and all the fun we can do we BPF to summarize and analyze events.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKehjhhubh)}(hQRight now, tracing relies on hidraw. It works well except for a couple of issues:h]hQRight now, tracing relies on hidraw. It works well except for a couple of issues:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhjhhubhenumerated_list)}(hhh](h)}(hif the driver doesn't export a hidraw node, we can't trace anything (eBPF will be a "god-mode" there, so this may raise some eyebrows)h]h)}(hif the driver doesn't export a hidraw node, we can't trace anything (eBPF will be a "god-mode" there, so this may raise some eyebrows)h]hif the driver doesn’t export a hidraw node, we can’t trace anything (eBPF will be a “god-mode” there, so this may raise some eyebrows)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKkhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubh)}(hhidraw doesn't catch other processes' requests to the device, which means that we have cases where we need to add printks to the kernel to understand what is happening. h]h)}(hhidraw doesn't catch other processes' requests to the device, which means that we have cases where we need to add printks to the kernel to understand what is happening.h]hhidraw doesn’t catch other processes’ requests to the device, which means that we have cases where we need to add printks to the kernel to understand what is happening.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKmhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubeh}(h]h ]h"]h$]h&]enumtypearabicprefixhsuffix.uh1jhjhhhhhKkubeh}(h]jah ]h"]tracingah$]h&]uh1hhj)hhhhhKcubeh}(h]hah ]h"]when (and why) to use hid-bpfah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hHigh-level view of HID-BPFh]hHigh-level view of HID-BPF}(hjhhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhjhhhhhKrubh)}(hThe main idea behind HID-BPF is that it works at an array of bytes level. Thus, all of the parsing of the HID report and the HID report descriptor must be implemented in the userspace component that loads the eBPF program.h]hThe main idea behind HID-BPF is that it works at an array of bytes level. Thus, all of the parsing of the HID report and the HID report descriptor must be implemented in the userspace component that loads the eBPF program.}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKthjhhubh)}(hFor example, in the dead zone joystick from above, knowing which fields in the data stream needs to be set to ``0`` needs to be computed by userspace.h](hnFor example, in the dead zone joystick from above, knowing which fields in the data stream needs to be set to }(hj3hhhNhNubj)}(h``0``h]h0}(hj;hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj3ubh# needs to be computed by userspace.}(hj3hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKyhjhhubh)}(hA corollary of this is that HID-BPF doesn't know about the other subsystems available in the kernel. *You can not directly emit input event through the input API from eBPF*.h](hgA corollary of this is that HID-BPF doesn’t know about the other subsystems available in the kernel. }(hjShhhNhNubjc)}(hG*You can not directly emit input event through the input API from eBPF*h]hEYou can not directly emit input event through the input API from eBPF}(hj[hhhNhNubah}(h]h ]h"]h$]h&]uh1jbhjSubh.}(hjShhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK|hjhhubh)}(hWhen a BPF program needs to emit input events, it needs to talk with the HID protocol, and rely on the HID kernel processing to translate the HID data into input events.h]hWhen a BPF program needs to emit input events, it needs to talk with the HID protocol, and rely on the HID kernel processing to translate the HID data into input events.}(hjshhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]jah ]h"]high-level view of hid-bpfah$]h&]uh1hhhhhhhhKrubh)}(hhh](h)}(h-In-tree HID-BPF programs and ``udev-hid-bpf``h](hIn-tree HID-BPF programs and }(hjhhhNhNubj)}(hjh]h udev-hid-bpf}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]j:juh1hhjhhhhhKubh)}(hOfficial device fixes are shipped in the kernel tree as source in the ``drivers/hid/bpf/progs`` directory. This allows to add selftests to them in ``tools/testing/selftests/hid``.h](hFOfficial device fixes are shipped in the kernel tree as source in the }(hjhhhNhNubj)}(h``drivers/hid/bpf/progs``h]hdrivers/hid/bpf/progs}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh4 directory. This allows to add selftests to them in }(hjhhhNhNubj)}(h``tools/testing/selftests/hid``h]htools/testing/selftests/hid}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hHowever, the compilation of these objects is not part of a regular kernel compilation given that they need an external tool to be loaded. This tool is currently `udev-hid-bpf `_.h](hHowever, the compilation of these objects is not part of a regular kernel compilation given that they need an external tool to be loaded. This tool is currently }(hjhhhNhNubh)}(hP`udev-hid-bpf `_h]h udev-hid-bpf}(hjhhhNhNubah}(h]h ]h"]h$]h&]name udev-hid-bpfrefuri>https://libevdev.pages.freedesktop.org/udev-hid-bpf/index.htmluh1hhjubhtarget)}(hA h]h}(h] udev-hid-bpfah ]h"] udev-hid-bpfah$]h&]refurijuh1j referencedKhjubh.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hX|For convenience, that external repository duplicates the files from here in ``drivers/hid/bpf/progs`` into its own ``src/bpf/stable`` directory. This allows distributions to not have to pull the entire kernel source tree to ship and package those HID-BPF fixes. ``udev-hid-bpf`` also has capabilities of handling multiple objects files depending on the kernel the user is running.h](hLFor convenience, that external repository duplicates the files from here in }(hj hhhNhNubj)}(h``drivers/hid/bpf/progs``h]hdrivers/hid/bpf/progs}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh into its own }(hj hhhNhNubj)}(h``src/bpf/stable``h]hsrc/bpf/stable}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh directory. This allows distributions to not have to pull the entire kernel source tree to ship and package those HID-BPF fixes. }(hj hhhNhNubj)}(h``udev-hid-bpf``h]h udev-hid-bpf}(hj8hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubhf also has capabilities of handling multiple objects files depending on the kernel the user is running.}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]j%ah ]h"])in-tree hid-bpf programs and udev-hid-bpfah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hAvailable types of programsh]hAvailable types of programs}(hjZhhhNhNubah}(h]h ]h"]h$]h&]j:jAuh1hhjWhhhhhKubh)}(hdHID-BPF is built "on top" of BPF, meaning that we use bpf struct_ops method to declare our programs.h]hhHID-BPF is built “on top” of BPF, meaning that we use bpf struct_ops method to declare our programs.}(hjhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjWhhubh)}(h5HID-BPF has the following attachment types available:h]h5HID-BPF has the following attachment types available:}(hjvhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjWhhubj)}(hhh](h)}(hPevent processing/filtering with ``SEC("struct_ops/hid_device_event")`` in libbpfh]h)}(hjh](h event processing/filtering with }(hjhhhNhNubj)}(h&``SEC("struct_ops/hid_device_event")``h]h"SEC("struct_ops/hid_device_event")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh in libbpf}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubh)}(h?actions coming from userspace with ``SEC("syscall")`` in libbpfh]h)}(hjh](h#actions coming from userspace with }(hjhhhNhNubj)}(h``SEC("syscall")``h]hSEC("syscall")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh in libbpf}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubh)}(hchange of the report descriptor with ``SEC("struct_ops/hid_rdesc_fixup")`` or ``SEC("struct_ops.s/hid_rdesc_fixup")`` in libbpf h]h)}(hchange of the report descriptor with ``SEC("struct_ops/hid_rdesc_fixup")`` or ``SEC("struct_ops.s/hid_rdesc_fixup")`` in libbpfh](h%change of the report descriptor with }(hjhhhNhNubj)}(h%``SEC("struct_ops/hid_rdesc_fixup")``h]h!SEC("struct_ops/hid_rdesc_fixup")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh or }(hjhhhNhNubj)}(h'``SEC("struct_ops.s/hid_rdesc_fixup")``h]h#SEC("struct_ops.s/hid_rdesc_fixup")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh in libbpf}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubeh}(h]h ]h"]h$]h&]jjjhjjuh1jhjWhhhhhKubh)}(hA ``hid_device_event`` is calling a BPF program when an event is received from the device. Thus we are in IRQ context and can act on the data or notify userspace. And given that we are in IRQ context, we can not talk back to the device.h](hA }(hjhhhNhNubj)}(h``hid_device_event``h]hhid_device_event}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh is calling a BPF program when an event is received from the device. Thus we are in IRQ context and can act on the data or notify userspace. And given that we are in IRQ context, we can not talk back to the device.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjWhhubh)}(hA ``syscall`` means that userspace called the syscall ``BPF_PROG_RUN`` facility. This time, we can do any operations allowed by HID-BPF, and talking to the device is allowed.h](hA }(hj;hhhNhNubj)}(h ``syscall``h]hsyscall}(hjChhhNhNubah}(h]h ]h"]h$]h&]uh1j hj;ubh) means that userspace called the syscall }(hj;hhhNhNubj)}(h``BPF_PROG_RUN``h]h BPF_PROG_RUN}(hjUhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj;ubhh facility. This time, we can do any operations allowed by HID-BPF, and talking to the device is allowed.}(hj;hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjWhhubh)}(hXLast, ``hid_rdesc_fixup`` is different from the others as there can be only one BPF program of this type. This is called on ``probe`` from the driver and allows to change the report descriptor from the BPF program. Once a ``hid_rdesc_fixup`` program has been loaded, it is not possible to overwrite it unless the program which inserted it allows us by pinning the program and closing all of its fds pointing to it.h](hLast, }(hjmhhhNhNubj)}(h``hid_rdesc_fixup``h]hhid_rdesc_fixup}(hjuhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjmubhc is different from the others as there can be only one BPF program of this type. This is called on }(hjmhhhNhNubj)}(h ``probe``h]hprobe}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjmubhY from the driver and allows to change the report descriptor from the BPF program. Once a }(hjmhhhNhNubj)}(h``hid_rdesc_fixup``h]hhid_rdesc_fixup}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjmubh program has been loaded, it is not possible to overwrite it unless the program which inserted it allows us by pinning the program and closing all of its fds pointing to it.}(hjmhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjWhhubh)}(heNote that ``hid_rdesc_fixup`` can be declared as sleepable (``SEC("struct_ops.s/hid_rdesc_fixup")``).h](h Note that }(hjhhhNhNubj)}(h``hid_rdesc_fixup``h]hhid_rdesc_fixup}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh can be declared as sleepable (}(hjhhhNhNubj)}(h'``SEC("struct_ops.s/hid_rdesc_fixup")``h]h#SEC("struct_ops.s/hid_rdesc_fixup")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh).}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjWhhubeh}(h]jGah ]h"]available types of programsah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hDeveloper API:h]hDeveloper API:}(hjhhhNhNubah}(h]h ]h"]h$]h&]j:jcuh1hhjhhhhhKubh)}(hhh](h)}(h%Available ``struct_ops`` for HID-BPF:h](h Available }(hjhhhNhNubj)}(hjh]h struct_ops}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh for HID-BPF:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]j:juh1hhjhhhhhKubhindex)}(hhh]h}(h]h ]h"]h$]h&]entries](singlehid_bpf_ops (C struct) c.hid_bpf_opshNtauh1j hjhhhNhNubhdesc)}(hhh](hdesc_signature)}(h hid_bpf_opsh]hdesc_signature_line)}(hstruct hid_bpf_opsh](hdesc_sig_keyword)}(hstructh]hstruct}(hjA hhhNhNubah}(h]h ]kah"]h$]h&]uh1j? hj; hhhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKubhdesc_sig_space)}(h h]h }(hjS hhhNhNubah}(h]h ]wah"]h$]h&]uh1jQ hj; hhhjP hKubh desc_name)}(h hid_bpf_opsh]h desc_sig_name)}(hj7 h]h hid_bpf_ops}(hjj hhhNhNubah}(h]h ]nah"]h$]h&]uh1jh hjd ubah}(h]h ](sig-namedescnameeh"]h$]h&]hhuh1jb hj; hhhjP hKubeh}(h]h ]h"]h$]h&]hh add_permalinkuh1j9 sphinx_line_type declaratorhj5 hhhjP hKubah}(h]j, ah ](sig sig-objecteh"]h$]h&] is_multiline _toc_parts) _toc_namehuh1j3 hjP hKhj0 hhubh desc_content)}(hhh]h)}(hQA BPF struct_ops of callbacks allowing to attach HID-BPF programs to a HID deviceh]hQA BPF struct_ops of callbacks allowing to attach HID-BPF programs to a HID device}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKThj hhubah}(h]h ]h"]h$]h&]uh1j hj0 hhhjP hKubeh}(h]h ](cstructeh"]h$]h&]domainj objtypej desctypej noindex noindexentrynocontentsentryuh1j. hhhjhNhNubh container)}(hX **Definition**:: struct hid_bpf_ops { int hid_id; u32 flags; int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, u64 source); int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum,enum hid_report_type rtype, enum hid_class_request reqtype, u64 source); int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source); }; **Members** ``hid_id`` the HID uniq ID to attach to. This is writeable before ``load()``, and cannot be changed after ``flags`` flags used while attaching the struct_ops to the device. Currently only available value is ``0`` or ``BPF_F_BEFORE``. Writeable only before ``load()`` ``hid_device_event`` called whenever an event is coming in from the device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` Return: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this event Context: Interrupt context. ``hid_rdesc_fixup`` called when the probe function parses the report descriptor of the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` Return: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this device ``hid_hw_request`` called whenever a hid_hw_raw_request() call is emitted on the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` ``reportnum``: the report number, as in hid_hw_raw_request() ``rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``reqtype``: the request ``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``. Return: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes returned in the incoming buffer; a negative error code interrupts the processing of this call. ``hid_hw_output_report`` called whenever a hid_hw_output_report() call is emitted on the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` ``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``. Return: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes written to the device; a negative error code interrupts the processing of this call.h](h)}(h**Definition**::h](hstrong)}(h**Definition**h]h Definition}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh:}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKXhj ubh literal_block)}(hXstruct hid_bpf_ops { int hid_id; u32 flags; int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, u64 source); int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum,enum hid_report_type rtype, enum hid_class_request reqtype, u64 source); int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source); };h]hXstruct hid_bpf_ops { int hid_id; u32 flags; int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, u64 source); int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum,enum hid_report_type rtype, enum hid_class_request reqtype, u64 source); int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source); };}hj sbah}(h]h ]h"]h$]h&]hhuh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKZhj ubh)}(h **Members**h]j )}(hj h]hMembers}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKchj ubhdefinition_list)}(hhh](hdefinition_list_item)}(hj``hid_id`` the HID uniq ID to attach to. This is writeable before ``load()``, and cannot be changed after h](hterm)}(h ``hid_id``h]j)}(hj h]hhid_id}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKXhj ubh definition)}(hhh]h)}(h^the HID uniq ID to attach to. This is writeable before ``load()``, and cannot be changed afterh](h7the HID uniq ID to attach to. This is writeable before }(hj4 hhhNhNubj)}(h ``load()``h]hload()}(hj< hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj4 ubh, and cannot be changed after}(hj4 hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKWhj1 ubah}(h]h ]h"]h$]h&]uh1j/ hj ubeh}(h]h ]h"]h$]h&]uh1j hj. hKXhj ubj )}(h``flags`` flags used while attaching the struct_ops to the device. Currently only available value is ``0`` or ``BPF_F_BEFORE``. Writeable only before ``load()`` h](j )}(h ``flags``h]j)}(hjg h]hflags}(hji hhhNhNubah}(h]h ]h"]h$]h&]uh1j hje ubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhK[hja ubj0 )}(hhh]h)}(hflags used while attaching the struct_ops to the device. Currently only available value is ``0`` or ``BPF_F_BEFORE``. Writeable only before ``load()``h](h[flags used while attaching the struct_ops to the device. Currently only available value is }(hj hhhNhNubj)}(h``0``h]h0}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh or }(hj hhhNhNubj)}(h``BPF_F_BEFORE``h]h BPF_F_BEFORE}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh. Writeable only before }(hj hhhNhNubj)}(h ``load()``h]hload()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKYhj} ubah}(h]h ]h"]h$]h&]uh1j/ hja ubeh}(h]h ]h"]h$]h&]uh1j hj| hK[hj ubj )}(hXy``hid_device_event`` called whenever an event is coming in from the device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` Return: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this event Context: Interrupt context. h](j )}(h``hid_device_event``h]j)}(hj h]hhid_device_event}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKthj ubj0 )}(hhh](h)}(h5called whenever an event is coming in from the deviceh]h5called whenever an event is coming in from the device}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKjhj ubh)}(hIt has the following arguments:h]hIt has the following arguments:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKlhj ubh)}(hJ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx `h](j)}(h``ctx``h]hctx}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh: The HID-BPF context as }(hj hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j)}(hj" h]hstruct hid_bpf_ctx}(hj$ hhhNhNubah}(h]h ](xrefj c-typeeh"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]refdoc hid/hid-bpf refdomainj reftypetype refexplicitrefwarn c:parent_keysphinx.domains.c LookupKey)}data]sb reftarget hid_bpf_ctxuh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKnhj ubeh}(h]h ]h"]h$]h&]uh1hhjJ hKnhj ubh)}(hReturn: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this eventh](hReturn: }(hjQ hhhNhNubj)}(h``0``h]h0}(hjY hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjQ ubh on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this event}(hjQ hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKphj ubh)}(hContext: Interrupt context.h]hContext: Interrupt context.}(hjr hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hKthj ubeh}(h]h ]h"]h$]h&]uh1j/ hj ubeh}(h]h ]h"]h$]h&]uh1j hj hKthj ubj )}(hXt``hid_rdesc_fixup`` called when the probe function parses the report descriptor of the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` Return: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this device h](j )}(h``hid_rdesc_fixup``h]j)}(hj h]hhid_rdesc_fixup}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubj0 )}(hhh](h)}(hMcalled when the probe function parses the report descriptor of the HID deviceh]hMcalled when the probe function parses the report descriptor of the HID device}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKzhj ubh)}(hIt has the following arguments:h]hIt has the following arguments:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhK}hj ubh)}(hJ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx `h](j)}(h``ctx``h]hctx}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh: The HID-BPF context as }(hj hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j)}(hj h]hstruct hid_bpf_ctx}(hj hhhNhNubah}(h]h ](j. j c-typeeh"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypetype refexplicitrefwarnj@ jD jH hid_bpf_ctxuh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1hhj hKhj ubh)}(hReturn: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this deviceh](hReturn: }(hj hhhNhNubj)}(h``0``h]h0}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this device}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1j/ hj ubeh}(h]h ]h"]h$]h&]uh1j hj hKhj ubj )}(hXG``hid_hw_request`` called whenever a hid_hw_raw_request() call is emitted on the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` ``reportnum``: the report number, as in hid_hw_raw_request() ``rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``reqtype``: the request ``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``. Return: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes returned in the incoming buffer; a negative error code interrupts the processing of this call. h](j )}(h``hid_hw_request``h]j)}(hj8 h]hhid_hw_request}(hj: hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj6 ubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj2 ubj0 )}(hhh](h)}(hHcalled whenever a hid_hw_raw_request() call is emitted on the HID deviceh]hHcalled whenever a hid_hw_raw_request() call is emitted on the HID device}(hjQ hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjN ubh)}(hIt has the following arguments:h]hIt has the following arguments:}(hj` hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjN ubh)}(hJ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx `h](j)}(h``ctx``h]hctx}(hjs hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjo ubh: The HID-BPF context as }(hjo hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j)}(hj h]hstruct hid_bpf_ctx}(hj hhhNhNubah}(h]h ](j. j c-typeeh"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypetype refexplicitrefwarnj@ jD jH hid_bpf_ctxuh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjo ubeh}(h]h ]h"]h$]h&]uh1hhj hKhjN ubh)}(h<``reportnum``: the report number, as in hid_hw_raw_request()h](j)}(h ``reportnum``h]h reportnum}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh/: the report number, as in hid_hw_raw_request()}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjN ubh)}(h```rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](j)}(h ``rtype``h]hrtype}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh: the report type (}(hj hhhNhNubj)}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh, }(hj hhhNhNubj)}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh, }(hj hhhNhNubj)}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh)}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjN ubh)}(h``reqtype``: the requesth](j)}(h ``reqtype``h]hreqtype}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh : the request}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjN ubh)}(h``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``.h](j)}(h ``source``h]hsource}(hj< hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj8 ubh8: a u64 referring to a uniq but identifiable source. If }(hj8 hhhNhNubj)}(h``0``h]h0}(hjN hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj8 ubh3, the kernel itself emitted that call. For hidraw, }(hj8 hhhNhNubj)}(h ``source``h]hsource}(hj` hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj8 ubh is set to the associated }(hj8 hhhNhNubj)}(h``struct file *``h]h struct file *}(hjr hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj8 ubh.}(hj8 hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjN ubh)}(hXReturn: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes returned in the incoming buffer; a negative error code interrupts the processing of this call.h](hReturn: }(hj hhhNhNubj)}(h``0``h]h0}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubhX to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes returned in the incoming buffer; a negative error code interrupts the processing of this call.}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjN ubeh}(h]h ]h"]h$]h&]uh1j/ hj2 ubeh}(h]h ]h"]h$]h&]uh1j hjM hKhj ubj )}(hX``hid_hw_output_report`` called whenever a hid_hw_output_report() call is emitted on the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` ``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``. Return: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes written to the device; a negative error code interrupts the processing of this call.h](j )}(h``hid_hw_output_report``h]j)}(hj h]hhid_hw_output_report}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubj0 )}(hhh](h)}(hJcalled whenever a hid_hw_output_report() call is emitted on the HID deviceh]hJcalled whenever a hid_hw_output_report() call is emitted on the HID device}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubh)}(hIt has the following arguments:h]hIt has the following arguments:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubh)}(hJ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx `h](j)}(h``ctx``h]hctx}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh: The HID-BPF context as }(hj hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j)}(hj h]hstruct hid_bpf_ctx}(hjhhhNhNubah}(h]h ](j. j c-typeeh"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypetype refexplicitrefwarnj@ jD jH hid_bpf_ctxuh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1hhj*hKhj ubh)}(h``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``.h](j)}(h ``source``h]hsource}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj1ubh8: a u64 referring to a uniq but identifiable source. If }(hj1hhhNhNubj)}(h``0``h]h0}(hjGhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj1ubh3, the kernel itself emitted that call. For hidraw, }(hj1hhhNhNubj)}(h ``source``h]hsource}(hjYhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj1ubh is set to the associated }(hj1hhhNhNubj)}(h``struct file *``h]h struct file *}(hjkhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj1ubh.}(hj1hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubh)}(hXReturn: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes written to the device; a negative error code interrupts the processing of this call.h](hReturn: }(hjhhhNhNubj)}(h``0``h]h0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes written to the device; a negative error code interrupts the processing of this call.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1j/ hj ubeh}(h]h ]h"]h$]h&]uh1j hj hKhj ubeh}(h]h ]h"]h$]h&]uh1j hj ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjhhhNhNubeh}(h]jah ]h"]!available struct_ops for hid-bpf:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(h/User API data structures available in programs:h]h/User API data structures available in programs:}(hjhhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhjhhhhhKubj )}(hhh]h}(h]h ]h"]h$]h&]entries](j* hid_bpf_ctx (C struct) c.hid_bpf_ctxhNtauh1j hjhhhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhNubj/ )}(hhh](j4 )}(h hid_bpf_ctxh]j: )}(hstruct hid_bpf_ctxh](j@ )}(hjC h]hstruct}(hjhhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjhhhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjhhhjhKubjc )}(h hid_bpf_ctxh]ji )}(hjh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj ubah}(h]h ](j{ j| eh"]h$]h&]hhuh1jb hjhhhjhKubeh}(h]h ]h"]h$]h&]hhj uh1j9 j j hjhhhjhKubah}(h]jah ](j j eh"]h$]h&]j j )j huh1j3 hjhKhjhhubj )}(hhh]h)}(h)User accessible data for all HID programsh]h)User accessible data for all HID programs}(hj2hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhj/hhubah}(h]h ]h"]h$]h&]uh1j hjhhhjhKubeh}(h]h ](j structeh"]h$]h&]j j j jJj jJj j j uh1j. hhhjhjhNubj )}(hX**Definition**:: struct hid_bpf_ctx { struct hid_device *hid; __u32 allocated_size; union { __s32 retval; __s32 size; }; }; **Members** ``hid`` the :c:type:`struct hid_device ` representing the device itself ``allocated_size`` Allocated size of data. This is how much memory is available and can be requested by the HID program. Note that for ``HID_BPF_RDESC_FIXUP``, that memory is set to ``4096`` (4 KB) ``{unnamed_union}`` anonymous ``retval`` Return value of the previous program. ``size`` Valid data in the data field. Programs can get the available valid size in data by fetching this field. Programs can also change this value by returning a positive number in the program. To discard the event, return a negative error code. ``size`` must always be less or equal than ``allocated_size`` (it is enforced once all BPF programs have been run).h](h)}(h**Definition**::h](j )}(h**Definition**h]h Definition}(hjVhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjRubh:}(hjRhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjNubj )}(hstruct hid_bpf_ctx { struct hid_device *hid; __u32 allocated_size; union { __s32 retval; __s32 size; }; };h]hstruct hid_bpf_ctx { struct hid_device *hid; __u32 allocated_size; union { __s32 retval; __s32 size; }; };}hjosbah}(h]h ]h"]h$]h&]hhuh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjNubh)}(h **Members**h]j )}(hjh]hMembers}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj~ubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK$hjNubj )}(hhh](j )}(hT``hid`` the :c:type:`struct hid_device ` representing the device itself h](j )}(h``hid``h]j)}(hjh]hhid}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjubj0 )}(hhh]h)}(hKthe :c:type:`struct hid_device ` representing the device itselfh](hthe }(hjhhhNhNubh)}(h(:c:type:`struct hid_device `h]j)}(hjh]hstruct hid_device}(hjhhhNhNubah}(h]h ](j. j c-typeeh"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypetype refexplicitrefwarnj@ jD jH hid_deviceuh1hhjhKhjubh representing the device itself}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhKhjubah}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hjhKhjubj )}(h``allocated_size`` Allocated size of data. This is how much memory is available and can be requested by the HID program. Note that for ``HID_BPF_RDESC_FIXUP``, that memory is set to ``4096`` (4 KB) h](j )}(h``allocated_size``h]j)}(hjh]hallocated_size}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK!hjubj0 )}(hhh](h)}(hAllocated size of data.h]hAllocated size of data.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjubh)}(hThis is how much memory is available and can be requested by the HID program. Note that for ``HID_BPF_RDESC_FIXUP``, that memory is set to ``4096`` (4 KB)h](h\This is how much memory is available and can be requested by the HID program. Note that for }(hj#hhhNhNubj)}(h``HID_BPF_RDESC_FIXUP``h]hHID_BPF_RDESC_FIXUP}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj#ubh, that memory is set to }(hj#hhhNhNubj)}(h``4096``h]h4096}(hj=hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj#ubh (4 KB)}(hj#hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjubeh}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hjhK!hjubj )}(h``{unnamed_union}`` anonymous h](j )}(h``{unnamed_union}``h]j)}(hjhh]h{unnamed_union}}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjfubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK$hjbubj0 )}(hhh]h)}(h anonymoush]h anonymous}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhj}hK$hj~ubah}(h]h ]h"]h$]h&]uh1j/ hjbubeh}(h]h ]h"]h$]h&]uh1j hj}hK$hjubj )}(h1``retval`` Return value of the previous program. h](j )}(h ``retval``h]j)}(hjh]hretval}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK+hjubj0 )}(hhh]h)}(h%Return value of the previous program.h]h%Return value of the previous program.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhK+hjubah}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hjhK+hjubj )}(hXm``size`` Valid data in the data field. Programs can get the available valid size in data by fetching this field. Programs can also change this value by returning a positive number in the program. To discard the event, return a negative error code. ``size`` must always be less or equal than ``allocated_size`` (it is enforced once all BPF programs have been run).h](j )}(h``size``h]j)}(hjh]hsize}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK)hjubj0 )}(hhh](h)}(hValid data in the data field.h]hValid data in the data field.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK"hjubh)}(hPrograms can get the available valid size in data by fetching this field. Programs can also change this value by returning a positive number in the program. To discard the event, return a negative error code.h]hPrograms can get the available valid size in data by fetching this field. Programs can also change this value by returning a positive number in the program. To discard the event, return a negative error code.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK$hjubh)}(hs``size`` must always be less or equal than ``allocated_size`` (it is enforced once all BPF programs have been run).h](j)}(h``size``h]hsize}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh# must always be less or equal than }(hjhhhNhNubj)}(h``allocated_size``h]hallocated_size}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh6 (it is enforced once all BPF programs have been run).}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhK)hjubeh}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hjhK)hjubeh}(h]h ]h"]h$]h&]uh1j hjNubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjhhhjhNubh)}(h**Description**h]j )}(hjZh]h Description}(hj\hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjXubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK-hjhhubh)}(h``data`` is not directly accessible from the context. We need to issue a call to hid_bpf_get_data() in order to get a pointer to that field.h](j)}(h``data``h]hdata}(hjthhhNhNubah}(h]h ]h"]h$]h&]uh1j hjpubh is not directly accessible from the context. We need to issue a call to hid_bpf_get_data() in order to get a pointer to that field.}(hjphhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjhhubh)}(hU``hid`` and ``allocated_size`` are read-only, ``size`` and ``retval`` are read-write.h](j)}(h``hid``h]hhid}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh and }(hjhhhNhNubj)}(h``allocated_size``h]hallocated_size}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh are read-only, }(hjhhhNhNubj)}(h``size``h]hsize}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh and }hjsbj)}(h ``retval``h]hretval}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh are read-write.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjhhubeh}(h]jah ]h"]/user api data structures available in programs:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(hBAvailable API that can be used in all HID-BPF struct_ops programs:h]hBAvailable API that can be used in all HID-BPF struct_ops programs:}(hjhhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhjhhhhhKubj )}(hhh]h}(h]h ]h"]h$]h&]entries](j* hid_bpf_get_data (C function)c.hid_bpf_get_datahNtauh1j hjhhhNhNubj/ )}(hhh](j4 )}(hn__bpf_kfunc __u8 * hid_bpf_get_data (struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)h]j: )}(hl__bpf_kfunc __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)h](h __bpf_kfunc}(hj hhhNhNubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj hhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMubh)}(hhh]ji )}(h__u8h]h__u8}(hj'hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj$ubah}(h]h ]h"]h$]h&] refdomainj reftype identifier reftargetj)modnameN classnameNj@ jC )}jF ]jA ASTIdentifier)}j=hid_bpf_get_datasbc.hid_bpf_get_dataasbuh1hhj hhhj#hMubjR )}(h h]h }(hjKhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj hhhj#hMubhdesc_sig_punctuation)}(h*h]h*}(hj[hhhNhNubah}(h]h ]pah"]h$]h&]uh1jYhj hhhj#hMubjc )}(hhid_bpf_get_datah]ji )}(hjHh]hhid_bpf_get_data}(hjnhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjjubah}(h]h ](j{ j| eh"]h$]h&]hhuh1jb hj hhhj#hMubhdesc_parameterlist)}(hJ(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)h](hdesc_parameter)}(hstruct hid_bpf_ctx *ctxh](j@ )}(hjC h]hstruct}(hjhhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubh)}(hhh]ji )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjmodnameN classnameNj@ jC )}jF ]jFc.hid_bpf_get_dataasbuh1hhjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubjZ)}(hj]h]h*}(hjhhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhjubji )}(hctxh]hctx}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(hunsigned int offseth](hdesc_sig_keyword_type)}(hunsignedh]hunsigned}(hjhhhNhNubah}(h]h ]ktah"]h$]h&]uh1jhjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubj)}(hinth]hint}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjubjR )}(h h]h }(hj*hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubji )}(hoffseth]hoffset}(hj8hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(hconst size_t rdwr_buf_sizeh](j@ )}(hconsth]hconst}(hjQhhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjMubjR )}(h h]h }(hj_hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjMubh)}(hhh]ji )}(hsize_th]hsize_t}(hjphhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjmubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjrmodnameN classnameNj@ jC )}jF ]jFc.hid_bpf_get_dataasbuh1hhjMubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjMubji )}(h rdwr_buf_sizeh]h rdwr_buf_size}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjMubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubeh}(h]h ]h"]h$]h&]hhuh1jhj hhhj#hMubeh}(h]h ]h"]h$]h&]hhj uh1j9 j j hj hhhj#hMubah}(h]jah ](j j eh"]h$]h&]j j )j huh1j3 hj#hMhjhhubj )}(hhh]h)}(hAGet the kernel memory pointer associated with the context **ctx**h](h:Get the kernel memory pointer associated with the context }(hjhhhNhNubj )}(h**ctx**h]hctx}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubah}(h]h ]h"]h$]h&]uh1j hjhhhj#hMubeh}(h]h ](j functioneh"]h$]h&]j j j jj jj j j uh1j. hhhjhNhNubj )}(hX**Parameters** ``struct hid_bpf_ctx *ctx`` The HID-BPF context ``unsigned int offset`` The offset within the memory ``const size_t rdwr_buf_size`` the const size of the buffer **Description** **returns** ``NULL`` on error, an ``__u8`` memory pointer on successh](h)}(h**Parameters**h]j )}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj )}(hhh](j )}(h0``struct hid_bpf_ctx *ctx`` The HID-BPF context h](j )}(h``struct hid_bpf_ctx *ctx``h]j)}(hjh]hstruct hid_bpf_ctx *ctx}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj0 )}(hhh]h)}(hThe HID-BPF contexth]hThe HID-BPF context}(hj.hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj*hMhj+ubah}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hj*hMhj ubj )}(h5``unsigned int offset`` The offset within the memory h](j )}(h``unsigned int offset``h]j)}(hjNh]hunsigned int offset}(hjPhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjLubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjHubj0 )}(hhh]h)}(hThe offset within the memoryh]hThe offset within the memory}(hjghhhNhNubah}(h]h ]h"]h$]h&]uh1hhjchMhjdubah}(h]h ]h"]h$]h&]uh1j/ hjHubeh}(h]h ]h"]h$]h&]uh1j hjchMhj ubj )}(h<``const size_t rdwr_buf_size`` the const size of the buffer h](j )}(h``const size_t rdwr_buf_size``h]j)}(hjh]hconst size_t rdwr_buf_size}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj0 )}(hhh]h)}(hthe const size of the bufferh]hthe const size of the buffer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hjhMhj ubeh}(h]h ]h"]h$]h&]uh1j hjubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubh)}(hD**returns** ``NULL`` on error, an ``__u8`` memory pointer on successh](j )}(h **returns**h]hreturns}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh }(hjhhhNhNubj)}(h``NULL``h]hNULL}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh on error, an }(hjhhhNhNubj)}(h``__u8``h]h__u8}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh memory pointer on success}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjhhhNhNubeh}(h]jah ]h"]Bavailable api that can be used in all hid-bpf struct_ops programs:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(hgAvailable API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs:h]hgAvailable API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs:}(hj*hhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhj'hhhhhKubj )}(hhh]h}(h]h ]h"]h$]h&]entries](j* %hid_bpf_allocate_context (C function)c.hid_bpf_allocate_contexthNtauh1j hj'hhhNhNubj/ )}(hhh](j4 )}(hO__bpf_kfunc struct hid_bpf_ctx * hid_bpf_allocate_context (unsigned int hid_id)h]j: )}(hM__bpf_kfunc struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id)h](h __bpf_kfunc}(hjMhhhNhNubjR )}(h h]h }(hjUhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjMhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM3ubj@ )}(hjC h]hstruct}(hjdhhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjMhhhjchM3ubjR )}(h h]h }(hjqhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjMhhhjchM3ubh)}(hhh]ji )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjmodnameN classnameNj@ jC )}jF ]jE)}j=hid_bpf_allocate_contextsbc.hid_bpf_allocate_contextasbuh1hhjMhhhjchM3ubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjMhhhjchM3ubjZ)}(hj]h]h*}(hjhhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhjMhhhjchM3ubjc )}(hhid_bpf_allocate_contexth]ji )}(hjh]hhid_bpf_allocate_context}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ](j{ j| eh"]h$]h&]hhuh1jb hjMhhhjchM3ubj)}(h(unsigned int hid_id)h]j)}(hunsigned int hid_idh](j)}(hunsignedh]hunsigned}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubj)}(hinth]hint}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubji )}(hhid_idh]hhid_id}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubah}(h]h ]h"]h$]h&]hhuh1jhjMhhhjchM3ubeh}(h]h ]h"]h$]h&]hhj uh1j9 j j hjIhhhjchM3ubah}(h]jDah ](j j eh"]h$]h&]j j )j huh1j3 hjchM3hjFhhubj )}(hhh]h)}(h*Allocate a context to the given HID deviceh]h*Allocate a context to the given HID device}(hj?hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM-hj<hhubah}(h]h ]h"]h$]h&]uh1j hjFhhhjchM3ubeh}(h]h ](j functioneh"]h$]h&]j j j jWj jWj j j uh1j. hhhj'hNhNubj )}(h**Parameters** ``unsigned int hid_id`` the system unique identifier of the HID device **Description** **returns** A pointer to :c:type:`struct hid_bpf_ctx ` on success, ``NULL`` on error.h](h)}(h**Parameters**h]j )}(hjah]h Parameters}(hjchhhNhNubah}(h]h ]h"]h$]h&]uh1j hj_ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM1hj[ubj )}(hhh]j )}(hG``unsigned int hid_id`` the system unique identifier of the HID device h](j )}(h``unsigned int hid_id``h]j)}(hjh]hunsigned int hid_id}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj~ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM/hjzubj0 )}(hhh]h)}(h.the system unique identifier of the HID deviceh]h.the system unique identifier of the HID device}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhM/hjubah}(h]h ]h"]h$]h&]uh1j/ hjzubeh}(h]h ]h"]h$]h&]uh1j hjhM/hjwubah}(h]h ]h"]h$]h&]uh1j hj[ubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM1hj[ubh)}(hb**returns** A pointer to :c:type:`struct hid_bpf_ctx ` on success, ``NULL`` on error.h](j )}(h **returns**h]hreturns}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh A pointer to }(hjhhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j)}(hjh]hstruct hid_bpf_ctx}(hjhhhNhNubah}(h]h ](j. j c-typeeh"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypetype refexplicitrefwarnj@ jD jH hid_bpf_ctxuh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM1hjubh on success, }(hjhhhNhNubj)}(h``NULL``h]hNULL}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh on error.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhM1hj[ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hj'hhhNhNubj )}(hhh]h}(h]h ]h"]h$]h&]entries](j* $hid_bpf_release_context (C function)c.hid_bpf_release_contexthNtauh1j hj'hhhNhNubj/ )}(hhh](j4 )}(hB__bpf_kfunc void hid_bpf_release_context (struct hid_bpf_ctx *ctx)h]j: )}(hA__bpf_kfunc void hid_bpf_release_context(struct hid_bpf_ctx *ctx)h](h __bpf_kfunc}(hj?hhhNhNubjR )}(h h]h }(hjGhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj?hhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMNubj)}(hvoidh]hvoid}(hjVhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj?hhhjUhMNubjR )}(h h]h }(hjdhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj?hhhjUhMNubjc )}(hhid_bpf_release_contexth]ji )}(hhid_bpf_release_contexth]hhid_bpf_release_context}(hjvhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjrubah}(h]h ](j{ j| eh"]h$]h&]hhuh1jb hj?hhhjUhMNubj)}(h(struct hid_bpf_ctx *ctx)h]j)}(hstruct hid_bpf_ctx *ctxh](j@ )}(hjC h]hstruct}(hjhhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubh)}(hhh]ji )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjmodnameN classnameNj@ jC )}jF ]jE)}j=jxsbc.hid_bpf_release_contextasbuh1hhjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubjZ)}(hj]h]h*}(hjhhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhjubji )}(hctxh]hctx}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubah}(h]h ]h"]h$]h&]hhuh1jhj?hhhjUhMNubeh}(h]h ]h"]h$]h&]hhj uh1j9 j j hj;hhhjUhMNubah}(h]j6ah ](j j eh"]h$]h&]j j )j huh1j3 hjUhMNhj8hhubj )}(hhh]h)}(h0Release the previously allocated context **ctx**h](h)Release the previously allocated context }(hjhhhNhNubj )}(h**ctx**h]hctx}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMIhjhhubah}(h]h ]h"]h$]h&]uh1j hj8hhhjUhMNubeh}(h]h ](j functioneh"]h$]h&]j j j j;j j;j j j uh1j. hhhj'hNhNubj )}(hL**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context to releaseh](h)}(h**Parameters**h]j )}(hjEh]h Parameters}(hjGhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjCubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMMhj?ubj )}(hhh]j )}(h:``struct hid_bpf_ctx *ctx`` the HID-BPF context to releaseh](j )}(h``struct hid_bpf_ctx *ctx``h]j)}(hjdh]hstruct hid_bpf_ctx *ctx}(hjfhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjbubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMOhj^ubj0 )}(hhh]h)}(hthe HID-BPF context to releaseh]hthe HID-BPF context to release}(hj}hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMKhjzubah}(h]h ]h"]h$]h&]uh1j/ hj^ubeh}(h]h ]h"]h$]h&]uh1j hjyhMOhj[ubah}(h]h ]h"]h$]h&]uh1j hj?ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hj'hhhNhNubj )}(hhh]h}(h]h ]h"]h$]h&]entries](j* hid_bpf_hw_request (C function)c.hid_bpf_hw_requesthNtauh1j hj'hhhNhNubj/ )}(hhh](j4 )}(h__bpf_kfunc int hid_bpf_hw_request (struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, enum hid_report_type rtype, enum hid_class_request reqtype)h]j: )}(h__bpf_kfunc int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, enum hid_report_type rtype, enum hid_class_request reqtype)h](h __bpf_kfunc}(hjhhhNhNubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj)}(hinth]hint}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjhhhjhMubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjhhhjhMubjc )}(hhid_bpf_hw_requesth]ji )}(hhid_bpf_hw_requesth]hhid_bpf_hw_request}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ](j{ j| eh"]h$]h&]hhuh1jb hjhhhjhMubj)}(hp(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, enum hid_report_type rtype, enum hid_class_request reqtype)h](j)}(hstruct hid_bpf_ctx *ctxh](j@ )}(hjC h]hstruct}(hj hhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hj ubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj ubh)}(hhh]ji )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hj+hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj(ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetj-modnameN classnameNj@ jC )}jF ]jE)}j=jsbc.hid_bpf_hw_requestasbuh1hhj ubjR )}(h h]h }(hjKhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj ubjZ)}(hj]h]h*}(hjYhhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhj ubji )}(hctxh]hctx}(hjfhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(h __u8 *bufh](h)}(hhh]ji )}(h__u8h]h__u8}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjmodnameN classnameNj@ jC )}jF ]jGc.hid_bpf_hw_requestasbuh1hhj{ubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj{ubjZ)}(hj]h]h*}(hjhhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhj{ubji )}(hbufh]hbuf}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj{ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(hsize_t buf__szh](h)}(hhh]ji )}(hsize_th]hsize_t}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjmodnameN classnameNj@ jC )}jF ]jGc.hid_bpf_hw_requestasbuh1hhjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubji )}(hbuf__szh]hbuf__sz}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(henum hid_report_type rtypeh](j@ )}(henumh]henum}(hjhhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjubjR )}(h h]h }(hj*hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubh)}(hhh]ji )}(hhid_report_typeh]hhid_report_type}(hj;hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj8ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetj=modnameN classnameNj@ jC )}jF ]jGc.hid_bpf_hw_requestasbuh1hhjubjR )}(h h]h }(hjYhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubji )}(hrtypeh]hrtype}(hjghhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(henum hid_class_request reqtypeh](j@ )}(hjh]henum}(hjhhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hj|ubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj|ubh)}(hhh]ji )}(hhid_class_requesth]hhid_class_request}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjmodnameN classnameNj@ jC )}jF ]jGc.hid_bpf_hw_requestasbuh1hhj|ubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj|ubji )}(hreqtypeh]hreqtype}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj|ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubeh}(h]h ]h"]h$]h&]hhuh1jhjhhhjhMubeh}(h]h ]h"]h$]h&]hhj uh1j9 j j hjhhhjhMubah}(h]jah ](j j eh"]h$]h&]j j )j huh1j3 hjhMhjhhubj )}(hhh]h)}(hCommunicate with a HID deviceh]hCommunicate with a HID device}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubah}(h]h ]h"]h$]h&]uh1j hjhhhjhMubeh}(h]h ](j functioneh"]h$]h&]j j j j j j j j j uh1j. hhhj'hNhNubj )}(hX**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() ``__u8 *buf`` a ``PTR_TO_MEM`` buffer ``size_t buf__sz`` the size of the data to transfer ``enum hid_report_type rtype`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``enum hid_class_request reqtype`` the type of the request (``HID_REQ_GET_REPORT``, ``HID_REQ_SET_REPORT``, ...) **Description** **returns** ``0`` on success, a negative error code otherwise.h](h)}(h**Parameters**h]j )}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj )}(hhh](j )}(hc``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() h](j )}(h``struct hid_bpf_ctx *ctx``h]j)}(hj5h]hstruct hid_bpf_ctx *ctx}(hj7hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj3ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj/ubj0 )}(hhh]h)}(hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()h]hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()}(hjNhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjJhMhjKubah}(h]h ]h"]h$]h&]uh1j/ hj/ubeh}(h]h ]h"]h$]h&]uh1j hjJhMhj,ubj )}(h&``__u8 *buf`` a ``PTR_TO_MEM`` buffer h](j )}(h ``__u8 *buf``h]j)}(hjnh]h __u8 *buf}(hjphhhNhNubah}(h]h ]h"]h$]h&]uh1j hjlubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhubj0 )}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(hjhhhNhNubj)}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh buffer}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1j/ hjhubeh}(h]h ]h"]h$]h&]uh1j hjhMhj,ubj )}(h4``size_t buf__sz`` the size of the data to transfer h](j )}(h``size_t buf__sz``h]j)}(hjh]hsize_t buf__sz}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj0 )}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hjhMhj,ubj )}(h|``enum hid_report_type rtype`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) h](j )}(h``enum hid_report_type rtype``h]j)}(hjh]henum hid_report_type rtype}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj0 )}(hhh]h)}(h\the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](hthe type of the report (}(hj hhhNhNubj)}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh, }(hj hhhNhNubj)}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh, }hj sbj)}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hj7hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh)}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hjhMhj,ubj )}(hq``enum hid_class_request reqtype`` the type of the request (``HID_REQ_GET_REPORT``, ``HID_REQ_SET_REPORT``, ...) h](j )}(h"``enum hid_class_request reqtype``h]j)}(hjah]henum hid_class_request reqtype}(hjchhhNhNubah}(h]h ]h"]h$]h&]uh1j hj_ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj[ubj0 )}(hhh]h)}(hMthe type of the request (``HID_REQ_GET_REPORT``, ``HID_REQ_SET_REPORT``, ...)h](hthe type of the request (}(hjzhhhNhNubj)}(h``HID_REQ_GET_REPORT``h]hHID_REQ_GET_REPORT}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjzubh, }(hjzhhhNhNubj)}(h``HID_REQ_SET_REPORT``h]hHID_REQ_SET_REPORT}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjzubh, ...)}(hjzhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjvhMhjwubah}(h]h ]h"]h$]h&]uh1j/ hj[ubeh}(h]h ]h"]h$]h&]uh1j hjvhMhj,ubeh}(h]h ]h"]h$]h&]uh1j hjubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubh)}(h>**returns** ``0`` on success, a negative error code otherwise.h](j )}(h **returns**h]hreturns}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh }(hjhhhNhNubj)}(h``0``h]h0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh- on success, a negative error code otherwise.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubeh}(h]h ] kernelindentah"]h$]h&]uh1j hj'hhhNhNubj )}(hhh]h}(h]h ]h"]h$]h&]entries](j* %hid_bpf_hw_output_report (C function)c.hid_bpf_hw_output_reporthNtauh1j hj'hhhNhNubj/ )}(hhh](j4 )}(h]__bpf_kfunc int hid_bpf_hw_output_report (struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)h]j: )}(h\__bpf_kfunc int hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)h](h __bpf_kfunc}(hj!hhhNhNubjR )}(h h]h }(hj)hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj!hhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj)}(hinth]hint}(hj8hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj!hhhj7hMubjR )}(h h]h }(hjFhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj!hhhj7hMubjc )}(hhid_bpf_hw_output_reporth]ji )}(hhid_bpf_hw_output_reporth]hhid_bpf_hw_output_report}(hjXhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjTubah}(h]h ](j{ j| eh"]h$]h&]hhuh1jb hj!hhhj7hMubj)}(h4(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)h](j)}(hstruct hid_bpf_ctx *ctxh](j@ )}(hjC h]hstruct}(hjthhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjpubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjpubh)}(hhh]ji )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjmodnameN classnameNj@ jC )}jF ]jE)}j=jZsbc.hid_bpf_hw_output_reportasbuh1hhjpubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjpubjZ)}(hj]h]h*}(hjhhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhjpubji )}(hctxh]hctx}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjpubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjlubj)}(h __u8 *bufh](h)}(hhh]ji )}(h__u8h]h__u8}(hjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjmodnameN classnameNj@ jC )}jF ]jc.hid_bpf_hw_output_reportasbuh1hhjubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjubjZ)}(hj]h]h*}(hjhhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhjubji )}(hbufh]hbuf}(hj"hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjlubj)}(hsize_t buf__szh](h)}(hhh]ji )}(hsize_th]hsize_t}(hj>hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj;ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetj@modnameN classnameNj@ jC )}jF ]jc.hid_bpf_hw_output_reportasbuh1hhj7ubjR )}(h h]h }(hj\hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj7ubji )}(hbuf__szh]hbuf__sz}(hjjhhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj7ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjlubeh}(h]h ]h"]h$]h&]hhuh1jhj!hhhj7hMubeh}(h]h ]h"]h$]h&]hhj uh1j9 j j hjhhhj7hMubah}(h]jah ](j j eh"]h$]h&]j j )j huh1j3 hj7hMhjhhubj )}(hhh]h)}(h%Send an output report to a HID deviceh]h%Send an output report to a HID device}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubah}(h]h ]h"]h$]h&]uh1j hjhhhj7hMubeh}(h]h ](j functioneh"]h$]h&]j j j jj jj j j uh1j. hhhj'hNhNubj )}(hX;**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() ``__u8 *buf`` a ``PTR_TO_MEM`` buffer ``size_t buf__sz`` the size of the data to transfer **Description** Returns the number of bytes transferred on success, a negative error code otherwise.h](h)}(h**Parameters**h]j )}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj )}(hhh](j )}(hc``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() h](j )}(h``struct hid_bpf_ctx *ctx``h]j)}(hjh]hstruct hid_bpf_ctx *ctx}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj0 )}(hhh]h)}(hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()h]hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hjhMhjubj )}(h&``__u8 *buf`` a ``PTR_TO_MEM`` buffer h](j )}(h ``__u8 *buf``h]j)}(hjh]h __u8 *buf}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj0 )}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(hj'hhhNhNubj)}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hj/hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj'ubh buffer}(hj'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj#hMhj$ubah}(h]h ]h"]h$]h&]uh1j/ hjubeh}(h]h ]h"]h$]h&]uh1j hj#hMhjubj )}(h4``size_t buf__sz`` the size of the data to transfer h](j )}(h``size_t buf__sz``h]j)}(hjYh]hsize_t buf__sz}(hj[hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjWubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjSubj0 )}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hjrhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjnhMhjoubah}(h]h ]h"]h$]h&]uh1j/ hjSubeh}(h]h ]h"]h$]h&]uh1j hjnhMhjubeh}(h]h ]h"]h$]h&]uh1j hjubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubh)}(hTReturns the number of bytes transferred on success, a negative error code otherwise.h]hTReturns the number of bytes transferred on success, a negative error code otherwise.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubeh}(h]h ] kernelindentah"]h$]h&]uh1j hj'hhhNhNubj )}(hhh]h}(h]h ]h"]h$]h&]entries](j* %hid_bpf_try_input_report (C function)c.hid_bpf_try_input_reporthNtauh1j hj'hhhNhNubj/ )}(hhh](j4 )}(h|__bpf_kfunc int hid_bpf_try_input_report (struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h]j: )}(h{__bpf_kfunc int hid_bpf_try_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h](h __bpf_kfunc}(hjhhhNhNubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj)}(hinth]hint}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhjhhhjhMubjR )}(h h]h }(hjhhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjhhhjhMubjc )}(hhid_bpf_try_input_reporth]ji )}(hhid_bpf_try_input_reporth]hhid_bpf_try_input_report}(hj hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj ubah}(h]h ](j{ j| eh"]h$]h&]hhuh1jb hjhhhjhMubj)}(hS(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h](j)}(hstruct hid_bpf_ctx *ctxh](j@ )}(hjC h]hstruct}(hj( hhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hj$ ubjR )}(h h]h }(hj5 hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj$ ubh)}(hhh]ji )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjF hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjC ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjH modnameN classnameNj@ jC )}jF ]jE)}j=j sbc.hid_bpf_try_input_reportasbuh1hhj$ ubjR )}(h h]h }(hjf hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj$ ubjZ)}(hj]h]h*}(hjt hhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhj$ ubji )}(hctxh]hctx}(hj hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj$ ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj ubj)}(henum hid_report_type typeh](j@ )}(hjh]henum}(hj hhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hj ubjR )}(h h]h }(hj hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj ubh)}(hhh]ji )}(hhid_report_typeh]hhid_report_type}(hj hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetj modnameN classnameNj@ jC )}jF ]jb c.hid_bpf_try_input_reportasbuh1hhj ubjR )}(h h]h }(hj hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj ubji )}(htypeh]htype}(hj hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj ubj)}(hu8 *bufh](h)}(hhh]ji )}(hu8h]hu8}(hj!hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetj!modnameN classnameNj@ jC )}jF ]jb c.hid_bpf_try_input_reportasbuh1hhj ubjR )}(h h]h }(hj!hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj ubjZ)}(hj]h]h*}(hj,!hhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhj ubji )}(hbufh]hbuf}(hj9!hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj ubj)}(hconst size_t buf__szh](j@ )}(hjSh]hconst}(hjR!hhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjN!ubjR )}(h h]h }(hj_!hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjN!ubh)}(hhh]ji )}(hsize_th]hsize_t}(hjp!hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjm!ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjr!modnameN classnameNj@ jC )}jF ]jb c.hid_bpf_try_input_reportasbuh1hhjN!ubjR )}(h h]h }(hj!hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjN!ubji )}(hbuf__szh]hbuf__sz}(hj!hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjN!ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj ubeh}(h]h ]h"]h$]h&]hhuh1jhjhhhjhMubeh}(h]h ]h"]h$]h&]hhj uh1j9 j j hjhhhjhMubah}(h]jah ](j j eh"]h$]h&]j j )j huh1j3 hjhMhjhhubj )}(hhh]h)}(h3Inject a HID report in the kernel from a HID deviceh]h3Inject a HID report in the kernel from a HID device}(hj!hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj!hhubah}(h]h ]h"]h$]h&]uh1j hjhhhjhMubeh}(h]h ](j functioneh"]h$]h&]j j j j!j j!j j j uh1j. hhhj'hNhNubj )}(hX**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() ``enum hid_report_type type`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``u8 *buf`` a ``PTR_TO_MEM`` buffer ``const size_t buf__sz`` the size of the data to transfer **Description** Returns ``0`` on success, a negative error code otherwise. This function will immediately fail if the device is not available, thus can be safely used in IRQ context.h](h)}(h**Parameters**h]j )}(hj!h]h Parameters}(hj!hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj!ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj!ubj )}(hhh](j )}(hc``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() h](j )}(h``struct hid_bpf_ctx *ctx``h]j)}(hj"h]hstruct hid_bpf_ctx *ctx}(hj "hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj"ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj"ubj0 )}(hhh]h)}(hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()h]hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()}(hj "hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj"hMhj"ubah}(h]h ]h"]h$]h&]uh1j/ hj"ubeh}(h]h ]h"]h$]h&]uh1j hj"hMhj!ubj )}(h{``enum hid_report_type type`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) h](j )}(h``enum hid_report_type type``h]j)}(hj@"h]henum hid_report_type type}(hjB"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj>"ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj:"ubj0 )}(hhh]h)}(h\the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](hthe type of the report (}(hjY"hhhNhNubj)}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hja"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjY"ubh, }(hjY"hhhNhNubj)}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hjs"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjY"ubh, }hjY"sbj)}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjY"ubh)}(hjY"hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjU"hMhjV"ubah}(h]h ]h"]h$]h&]uh1j/ hj:"ubeh}(h]h ]h"]h$]h&]uh1j hjU"hMhj!ubj )}(h$``u8 *buf`` a ``PTR_TO_MEM`` buffer h](j )}(h ``u8 *buf``h]j)}(hj"h]hu8 *buf}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj"ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj"ubj0 )}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(hj"hhhNhNubj)}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj"ubh buffer}(hj"hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj"hMhj"ubah}(h]h ]h"]h$]h&]uh1j/ hj"ubeh}(h]h ]h"]h$]h&]uh1j hj"hMhj!ubj )}(h:``const size_t buf__sz`` the size of the data to transfer h](j )}(h``const size_t buf__sz``h]j)}(hj"h]hconst size_t buf__sz}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj"ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj"ubj0 )}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj#hMhj#ubah}(h]h ]h"]h$]h&]uh1j/ hj"ubeh}(h]h ]h"]h$]h&]uh1j hj#hMhj!ubeh}(h]h ]h"]h$]h&]uh1j hj!ubh)}(h**Description**h]j )}(hj5#h]h Description}(hj7#hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj3#ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj!ubh)}(hReturns ``0`` on success, a negative error code otherwise. This function will immediately fail if the device is not available, thus can be safely used in IRQ context.h](hReturns }(hjK#hhhNhNubj)}(h``0``h]h0}(hjS#hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjK#ubh on success, a negative error code otherwise. This function will immediately fail if the device is not available, thus can be safely used in IRQ context.}(hjK#hhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj!ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hj'hhhNhNubj )}(hhh]h}(h]h ]h"]h$]h&]entries](j* !hid_bpf_input_report (C function)c.hid_bpf_input_reporthNtauh1j hj'hhhNhNubj/ )}(hhh](j4 )}(hx__bpf_kfunc int hid_bpf_input_report (struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h]j: )}(hw__bpf_kfunc int hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h](h __bpf_kfunc}(hj#hhhNhNubjR )}(h h]h }(hj#hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj#hhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj)}(hinth]hint}(hj#hhhNhNubah}(h]h ]j ah"]h$]h&]uh1jhj#hhhj#hMubjR )}(h h]h }(hj#hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj#hhhj#hMubjc )}(hhid_bpf_input_reporth]ji )}(hhid_bpf_input_reporth]hhid_bpf_input_report}(hj#hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj#ubah}(h]h ](j{ j| eh"]h$]h&]hhuh1jb hj#hhhj#hMubj)}(hS(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h](j)}(hstruct hid_bpf_ctx *ctxh](j@ )}(hjC h]hstruct}(hj#hhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hj#ubjR )}(h h]h }(hj#hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj#ubh)}(hhh]ji )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hj#hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj#ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetj#modnameN classnameNj@ jC )}jF ]jE)}j=j#sbc.hid_bpf_input_reportasbuh1hhj#ubjR )}(h h]h }(hj$hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj#ubjZ)}(hj]h]h*}(hj'$hhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhj#ubji )}(hctxh]hctx}(hj4$hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj#ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj#ubj)}(henum hid_report_type typeh](j@ )}(hjh]henum}(hjM$hhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hjI$ubjR )}(h h]h }(hjZ$hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjI$ubh)}(hhh]ji )}(hhid_report_typeh]hhid_report_type}(hjk$hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjh$ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetjm$modnameN classnameNj@ jC )}jF ]j$c.hid_bpf_input_reportasbuh1hhjI$ubjR )}(h h]h }(hj$hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hjI$ubji )}(htypeh]htype}(hj$hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hjI$ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj#ubj)}(hu8 *bufh](h)}(hhh]ji )}(hu8h]hu8}(hj$hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj$ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetj$modnameN classnameNj@ jC )}jF ]j$c.hid_bpf_input_reportasbuh1hhj$ubjR )}(h h]h }(hj$hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj$ubjZ)}(hj]h]h*}(hj$hhhNhNubah}(h]h ]jfah"]h$]h&]uh1jYhj$ubji )}(hbufh]hbuf}(hj$hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj$ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj#ubj)}(hconst size_t buf__szh](j@ )}(hjSh]hconst}(hj%hhhNhNubah}(h]h ]jL ah"]h$]h&]uh1j? hj%ubjR )}(h h]h }(hj%hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj%ubh)}(hhh]ji )}(hsize_th]hsize_t}(hj#%hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj %ubah}(h]h ]h"]h$]h&] refdomainj reftypej= reftargetj%%modnameN classnameNj@ jC )}jF ]j$c.hid_bpf_input_reportasbuh1hhj%ubjR )}(h h]h }(hjA%hhhNhNubah}(h]h ]j^ ah"]h$]h&]uh1jQ hj%ubji )}(hbuf__szh]hbuf__sz}(hjO%hhhNhNubah}(h]h ]jt ah"]h$]h&]uh1jh hj%ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj#ubeh}(h]h ]h"]h$]h&]hhuh1jhj#hhhj#hMubeh}(h]h ]h"]h$]h&]hhj uh1j9 j j hj#hhhj#hMubah}(h]j#ah ](j j eh"]h$]h&]j j )j huh1j3 hj#hMhj#hhubj )}(hhh]h)}(h3Inject a HID report in the kernel from a HID deviceh]h3Inject a HID report in the kernel from a HID device}(hjy%hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjv%hhubah}(h]h ]h"]h$]h&]uh1j hj#hhhj#hMubeh}(h]h ](j functioneh"]h$]h&]j j j j%j j%j j j uh1j. hhhj'hNhNubj )}(hX$**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() ``enum hid_report_type type`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``u8 *buf`` a ``PTR_TO_MEM`` buffer ``const size_t buf__sz`` the size of the data to transfer **Description** Returns ``0`` on success, a negative error code otherwise. This function will wait for the device to be available before injecting the event, thus needs to be called in sleepable context.h](h)}(h**Parameters**h]j )}(hj%h]h Parameters}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj%ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%ubj )}(hhh](j )}(hc``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() h](j )}(h``struct hid_bpf_ctx *ctx``h]j)}(hj%h]hstruct hid_bpf_ctx *ctx}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj%ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%ubj0 )}(hhh]h)}(hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()h]hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj%hMhj%ubah}(h]h ]h"]h$]h&]uh1j/ hj%ubeh}(h]h ]h"]h$]h&]uh1j hj%hMhj%ubj )}(h{``enum hid_report_type type`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) h](j )}(h``enum hid_report_type type``h]j)}(hj%h]henum hid_report_type type}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj%ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%ubj0 )}(hhh]h)}(h\the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](hthe type of the report (}(hj &hhhNhNubj)}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj &ubh, }(hj &hhhNhNubj)}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hj&&hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj &ubh, }hj &sbj)}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hj8&hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj &ubh)}(hj &hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj&hMhj &ubah}(h]h ]h"]h$]h&]uh1j/ hj%ubeh}(h]h ]h"]h$]h&]uh1j hj&hMhj%ubj )}(h$``u8 *buf`` a ``PTR_TO_MEM`` buffer h](j )}(h ``u8 *buf``h]j)}(hjb&h]hu8 *buf}(hjd&hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj`&ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj\&ubj0 )}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(hj{&hhhNhNubj)}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj{&ubh buffer}(hj{&hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjw&hMhjx&ubah}(h]h ]h"]h$]h&]uh1j/ hj\&ubeh}(h]h ]h"]h$]h&]uh1j hjw&hMhj%ubj )}(h:``const size_t buf__sz`` the size of the data to transfer h](j )}(h``const size_t buf__sz``h]j)}(hj&h]hconst size_t buf__sz}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj&ubah}(h]h ]h"]h$]h&]uh1j h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj&ubj0 )}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj&hMhj&ubah}(h]h ]h"]h$]h&]uh1j/ hj&ubeh}(h]h ]h"]h$]h&]uh1j hj&hMhj%ubeh}(h]h ]h"]h$]h&]uh1j hj%ubh)}(h**Description**h]j )}(hj&h]h Description}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj&ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%ubh)}(hReturns ``0`` on success, a negative error code otherwise. This function will wait for the device to be available before injecting the event, thus needs to be called in sleepable context.h](hReturns }(hj&hhhNhNubj)}(h``0``h]h0}(hj'hhhNhNubah}(ţh]h ]h"]h$]h&]uh1j hj&ubh on success, a negative error code otherwise. This function will wait for the device to be available before injecting the event, thus needs to be called in sleepable context.}(hj&hhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hj'hhhNhNubeh}(h]jah ]h"]gavailable api that can be used in syscall hid-bpf programs or in sleepable hid-bpf struct_ops programs:ah$]h&]uh1hhjhhhhhKubeh}(h]jiah ]h"]developer api:ah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h%General overview of a HID-BPF programh]h%General overview of a HID-BPF program}(hj7'hhhNhNubah}(h]h ]h"]h$]h&]j:j(uh1hhj4'hhhhhKubh)}(hhh](h)}(h*Accessing the data attached to the contexth]h*Accessing the data attached to the context}(hjH'hhhNhNubah}(h]h ]h"]h$]h&]j:jGuh1hhjE'hhhhhKubh)}(hThe ``struct hid_bpf_ctx`` doesn't export the ``data`` fields directly and to access it, a bpf program needs to first call :c:func:`hid_bpf_get_data`.h](hThe }(hjV'hhhNhNubj)}(h``struct hid_bpf_ctx``h]hstruct hid_bpf_ctx}(hj^'hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjV'ubh doesn’t export the }(hjV'hhhNhNubj)}(h``data``h]hdata}(hjp'hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjV'ubhE fields directly and to access it, a bpf program needs to first call }(hjV'hhhNhNubh)}(h:c:func:`hid_bpf_get_data`h]j)}(hj'h]hhid_bpf_get_data()}(hj'hhhNhNubah}(h]h ](j. j c-funceh"]h$]h&]uh1j hj'ubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypefunc refexplicitrefwarnj@ jD jH hid_bpf_get_datauh1hhhhKhjV'ubh.}(hjV'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjE'hhubh)}(hX``offset`` can be any integer, but ``size`` needs to be constant, known at compile time.h](j)}(h ``offset``h]hoffset}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj'ubh can be any integer, but }(hj'hhhNhNubj)}(h``size``h]hsize}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj'ubh- needs to be constant, known at compile time.}(hj'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjE'hhubh)}(hThis allows the following:h]hThis allows the following:}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjE'hhubj)}(hhh](h)}(hXRfor a given device, if we know that the report length will always be of a certain value, we can request the ``data`` pointer to point at the full report length. The kernel will ensure we are using a correct size and offset and eBPF will ensure the code will not attempt to read or write outside of the boundaries:: __u8 *data = hid_bpf_get_data(ctx, 0 /* offset */, 256 /* size */); if (!data) return 0; /* ensure data is correct, now the verifier knows we * have 256 bytes available */ bpf_printk("hello world: %02x %02x %02x", data[0], data[128], data[255]); h](h)}(hfor a given device, if we know that the report length will always be of a certain value, we can request the ``data`` pointer to point at the full report length.h](hlfor a given device, if we know that the report length will always be of a certain value, we can request the }(hj'hhhNhNubj)}(h``data``h]hdata}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj'ubh, pointer to point at the full report length.}(hj'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj'ubh)}(hThe kernel will ensure we are using a correct size and offset and eBPF will ensure the code will not attempt to read or write outside of the boundaries::h]hThe kernel will ensure we are using a correct size and offset and eBPF will ensure the code will not attempt to read or write outside of the boundaries:}(hj(hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj'ubj )}(hX __u8 *data = hid_bpf_get_data(ctx, 0 /* offset */, 256 /* size */); if (!data) return 0; /* ensure data is correct, now the verifier knows we * have 256 bytes available */ bpf_printk("hello world: %02x %02x %02x", data[0], data[128], data[255]);h]hX __u8 *data = hid_bpf_get_data(ctx, 0 /* offset */, 256 /* size */); if (!data) return 0; /* ensure data is correct, now the verifier knows we * have 256 bytes available */ bpf_printk("hello world: %02x %02x %02x", data[0], data[128], data[255]);}hj(sbah}(h]h ]h"]h$]h&]hhuh1j hhhKhj'ubeh}(h]h ]h"]h$]h&]uh1hhj'hhhhhNubh)}(hX%if the report length is variable, but we know the value of ``X`` is always a 16-bit integer, we can then have a pointer to that value only:: __u16 *x = hid_bpf_get_data(ctx, offset, sizeof(*x)); if (!x) return 0; /* something went wrong */ *x += 1; /* increment X by one */ h](h)}(hif the report length is variable, but we know the value of ``X`` is always a 16-bit integer, we can then have a pointer to that value only::h](h;if the report length is variable, but we know the value of }(hj4(hhhNhNubj)}(h``X``h]hX}(hj<(hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj4(ubhK is always a 16-bit integer, we can then have a pointer to that value only:}(hj4(hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj0(ubj )}(h__u16 *x = hid_bpf_get_data(ctx, offset, sizeof(*x)); if (!x) return 0; /* something went wrong */ *x += 1; /* increment X by one */h]h__u16 *x = hid_bpf_get_data(ctx, offset, sizeof(*x)); if (!x) return 0; /* something went wrong */ *x += 1; /* increment X by one */}hjT(sbah}(h]h ]h"]h$]h&]hhuh1j hhhKhj0(ubeh}(h]h ]h"]h$]h&]uh1hhj'hhhhhNubeh}(h]h ]h"]h$]h&]jjjhjjuh1jhjE'hhhhhKubeh}(h]jMah ]h"]*accessing the data attached to the contextah$]h&]uh1hhj4'hhhhhKubh)}(hhh](h)}(hEffect of a HID-BPF programh]hEffect of a HID-BPF program}(hjx(hhhNhNubah}(h]h ]h"]h$]h&]j:jiuh1hhju(hhhhhKubh)}(hX)For all HID-BPF attachment types except for :c:func:`hid_rdesc_fixup`, several eBPF programs can be attached to the same device. If a HID-BPF struct_ops has a :c:func:`hid_rdesc_fixup` while another is already attached to the device, the kernel will return `-EINVAL` when attaching the struct_ops.h](h,For all HID-BPF attachment types except for }(hj(hhhNhNubh)}(h:c:func:`hid_rdesc_fixup`h]j)}(hj(h]hhid_rdesc_fixup()}(hj(hhhNhNubah}(h]h ](j. j c-funceh"]h$]h&]uh1j hj(ubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypefunc refexplicitrefwarnj@ jD jH hid_rdesc_fixupuh1hhhhKhj(ubhZ, several eBPF programs can be attached to the same device. If a HID-BPF struct_ops has a }(hj(hhhNhNubh)}(h:c:func:`hid_rdesc_fixup`h]j)}(hj(h]hhid_rdesc_fixup()}(hj(hhhNhNubah}(h]h ](j. j c-funceh"]h$]h&]uh1j hj(ubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypefunc refexplicitrefwarnj@ jD jH hid_rdesc_fixupuh1hhhhKhj(ubhI while another is already attached to the device, the kernel will return }(hj(hhhNhNubhtitle_reference)}(h `-EINVAL`h]h-EINVAL}(hj(hhhNhNubah}(h]h ]h"]h$]h&]uh1j(hj(ubh when attaching the struct_ops.}(hj(hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhju(hhubh)}(hX&Unless ``BPF_F_BEFORE`` is added to the flags while attaching the program, the new program is appended at the end of the list. ``BPF_F_BEFORE`` will insert the new program at the beginning of the list which is useful for e.g. tracing where we need to get the unprocessed events from the device.h](hUnless }(hj(hhhNhNubj)}(h``BPF_F_BEFORE``h]h BPF_F_BEFORE}(hj(hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj(ubhh is added to the flags while attaching the program, the new program is appended at the end of the list. }(hj(hhhNhNubj)}(h``BPF_F_BEFORE``h]h BPF_F_BEFORE}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj(ubh will insert the new program at the beginning of the list which is useful for e.g. tracing where we need to get the unprocessed events from the device.}(hj(hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhju(hhubh)}(hNote that if there are multiple programs using the ``BPF_F_BEFORE`` flag, only the most recently loaded one is actually the first in the list.h](h3Note that if there are multiple programs using the }(hj )hhhNhNubj)}(h``BPF_F_BEFORE``h]h BPF_F_BEFORE}(hj()hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj )ubhK flag, only the most recently loaded one is actually the first in the list.}(hj )hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhju(hhubh)}(hhh](h)}(h&``SEC("struct_ops/hid_device_event")``h]j)}(hjE)h]h"SEC("struct_ops/hid_device_event")}(hjG)hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjC)ubah}(h]h ]h"]h$]h&]uh1hhj@)hhhhhMubh)}(h~Whenever a matching event is raised, the eBPF programs are called one after the other and are working on the same data buffer.h]h~Whenever a matching event is raised, the eBPF programs are called one after the other and are working on the same data buffer.}(hjZ)hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj@)hhubh)}(hIf a program changes the data associated with the context, the next one will see the modified data but it will have *no* idea of what the original data was.h](htIf a program changes the data associated with the context, the next one will see the modified data but it will have }(hjh)hhhNhNubjc)}(h*no*h]hno}(hjp)hhhNhNubah}(h]h ]h"]h$]h&]uh1jbhjh)ubh$ idea of what the original data was.}(hjh)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM hj@)hhubh)}(hOnce all the programs are run and return ``0`` or a positive value, the rest of the HID stack will work on the modified data, with the ``size`` field of the last hid_bpf_ctx being the new size of the input stream of data.h](h)Once all the programs are run and return }(hj)hhhNhNubj)}(h``0``h]h0}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj)ubhY or a positive value, the rest of the HID stack will work on the modified data, with the }(hj)hhhNhNubj)}(h``size``h]hsize}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj)ubhN field of the last hid_bpf_ctx being the new size of the input stream of data.}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj@)hhubh)}(hA BPF program returning a negative error discards the event, i.e. this event will not be processed by the HID stack. Clients (hidraw, input, LEDs) will **not** see this event.h](hA BPF program returning a negative error discards the event, i.e. this event will not be processed by the HID stack. Clients (hidraw, input, LEDs) will }(hj)hhhNhNubj )}(h**not**h]hnot}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj)ubh see this event.}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj@)hhubeh}(h]sec-struct-ops-hid-device-eventah ]h"]"sec("struct_ops/hid_device_event")ah$]h&]uh1hhju(hhhhhMubh)}(hhh](h)}(h``SEC("syscall")``h]j)}(hj)h]hSEC("syscall")}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj)ubah}(h]h ]h"]h$]h&]uh1hhj)hhhhhMubh)}(h``syscall`` are not attached to a given device. To tell which device we are working with, userspace needs to refer to the device by its unique system id (the last 4 numbers in the sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``).h](j)}(h ``syscall``h]hsyscall}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj)ubh are not attached to a given device. To tell which device we are working with, userspace needs to refer to the device by its unique system id (the last 4 numbers in the sysfs path: }(hj)hhhNhNubj)}(h,``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``h]h(/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj)ubh).}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj)hhubh)}(hXjTo retrieve a context associated with the device, the program must call hid_bpf_allocate_context() and must release it with hid_bpf_release_context() before returning. Once the context is retrieved, one can also request a pointer to kernel memory with hid_bpf_get_data(). This memory is big enough to support all input/output/feature reports of the given device.h]hXjTo retrieve a context associated with the device, the program must call hid_bpf_allocate_context() and must release it with hid_bpf_release_context() before returning. Once the context is retrieved, one can also request a pointer to kernel memory with hid_bpf_get_data(). This memory is big enough to support all input/output/feature reports of the given device.}(hj**hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj)hhubeh}(h] sec-syscallah ]h"]sec("syscall")ah$]h&]uh1hhju(hhhhhMubh)}(hhh](h)}(h%``SEC("struct_ops/hid_rdesc_fixup")``h]j)}(hjE*h]h!SEC("struct_ops/hid_rdesc_fixup")}(hjG*hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjC*ubah}(h]h ]h"]h$]h&]uh1hhj@*hhhhhM$ubh)}(hhThe ``hid_rdesc_fixup`` program works in a similar manner to ``.report_fixup`` of ``struct hid_driver``.h](hThe }(hjZ*hhhNhNubj)}(h``hid_rdesc_fixup``h]hhid_rdesc_fixup}(hjb*hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjZ*ubh& program works in a similar manner to }(hjZ*hhhNhNubj)}(h``.report_fixup``h]h .report_fixup}(hjt*hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjZ*ubh of }(hjZ*hhhNhNubj)}(h``struct hid_driver``h]hstruct hid_driver}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjZ*ubh.}(hjZ*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM&hj@*hhubh)}(hWhen the device is probed, the kernel sets the data buffer of the context with the content of the report descriptor. The memory associated with that buffer is ``HID_MAX_DESCRIPTOR_SIZE`` (currently 4kB).h](hWhen the device is probed, the kernel sets the data buffer of the context with the content of the report descriptor. The memory associated with that buffer is }(hj*hhhNhNubj)}(h``HID_MAX_DESCRIPTOR_SIZE``h]hHID_MAX_DESCRIPTOR_SIZE}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj*ubh (currently 4kB).}(hj*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM)hj@*hhubh)}(hThe eBPF program can modify the data buffer at-will and the kernel uses the modified content and size as the report descriptor.h]hThe eBPF program can modify the data buffer at-will and the kernel uses the modified content and size as the report descriptor.}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM-hj@*hhubh)}(hWhenever a struct_ops containing a ``SEC("struct_ops/hid_rdesc_fixup")`` program is attached (if no program was attached before), the kernel immediately disconnects the HID device and does a reprobe.h](h#Whenever a struct_ops containing a }(hj*hhhNhNubj)}(h%``SEC("struct_ops/hid_rdesc_fixup")``h]h!SEC("struct_ops/hid_rdesc_fixup")}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj*ubh program is attached (if no program was attached before), the kernel immediately disconnects the HID device and does a reprobe.}(hj*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM0hj@*hhubh)}(h`In the same way, when this struct_ops is detached, the kernel issues a disconnect on the device.h]h`In the same way, when this struct_ops is detached, the kernel issues a disconnect on the device.}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM4hj@*hhubh)}(hXThere is no ``detach`` facility in HID-BPF. Detaching a program happens when all the user space file descriptors pointing at a HID-BPF struct_ops link are closed. Thus, if we need to replace a report descriptor fixup, some cooperation is required from the owner of the original report descriptor fixup. The previous owner will likely pin the struct_ops link in the bpffs, and we can then replace it through normal bpf operations.h](h There is no }(hj*hhhNhNubj)}(h ``detach``h]hdetach}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj*ubhX facility in HID-BPF. Detaching a program happens when all the user space file descriptors pointing at a HID-BPF struct_ops link are closed. Thus, if we need to replace a report descriptor fixup, some cooperation is required from the owner of the original report descriptor fixup. The previous owner will likely pin the struct_ops link in the bpffs, and we can then replace it through normal bpf operations.}(hj*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM7hj@*hhubeh}(h]sec-struct-ops-hid-rdesc-fixupah ]h"]!sec("struct_ops/hid_rdesc_fixup")ah$]h&]uh1hhju(hhhhhM$ubeh}(h]joah ]h"]effect of a hid-bpf programah$]h&]uh1hhj4'hhhhhKubeh}(h]j.ah ]h"]%general overview of a hid-bpf programah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h#Attaching a bpf program to a deviceh]h#Attaching a bpf program to a device}(hj3+hhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhj0+hhhhhM?ubh)}(hWe now use standard struct_ops attachment through ``bpf_map__attach_struct_ops()``. But given that we need to attach a struct_ops to a dedicated HID device, the caller must set ``hid_id`` in the struct_ops map before loading the program in the kernel.h](h2We now use standard struct_ops attachment through }(hjA+hhhNhNubj)}(h ``bpf_map__attach_struct_ops()``h]hbpf_map__attach_struct_ops()}(hjI+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjA+ubh_. But given that we need to attach a struct_ops to a dedicated HID device, the caller must set }(hjA+hhhNhNubj)}(h ``hid_id``h]hhid_id}(hj[+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjA+ubh@ in the struct_ops map before loading the program in the kernel.}(hjA+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMAhj0+hhubh)}(h``hid_id`` is the unique system ID of the HID device (the last 4 numbers in the sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``)h](j)}(h ``hid_id``h]hhid_id}(hjw+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjs+ubhR is the unique system ID of the HID device (the last 4 numbers in the sysfs path: }(hjs+hhhNhNubj)}(h,``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``h]h(/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjs+ubh)}(hjs+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMEhj0+hhubh)}(hKOne can also set ``flags``, which is of type ``enum hid_bpf_attach_flags``.h](hOne can also set }(hj+hhhNhNubj)}(h ``flags``h]hflags}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj+ubh, which is of type }(hj+hhhNhNubj)}(h``enum hid_bpf_attach_flags``h]henum hid_bpf_attach_flags}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj+ubh.}(hj+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMHhj0+hhubh)}(hXWe can not rely on hidraw to bind a BPF program to a HID device. hidraw is an artefact of the processing of the HID device, and is not stable. Some drivers even disable it, so that removes the tracing capabilities on those devices (where it is interesting to get the non-hidraw traces).h]hXWe can not rely on hidraw to bind a BPF program to a HID device. hidraw is an artefact of the processing of the HID device, and is not stable. Some drivers even disable it, so that removes the tracing capabilities on those devices (where it is interesting to get the non-hidraw traces).}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMJhj0+hhubh)}(h{On the other hand, the ``hid_id`` is stable for the entire life of the HID device, even if we change its report descriptor.h](hOn the other hand, the }(hj+hhhNhNubj)}(h ``hid_id``h]hhid_id}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj+ubhZ is stable for the entire life of the HID device, even if we change its report descriptor.}(hj+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMOhj0+hhubh)}(hXGiven that hidraw is not stable when the device disconnects/reconnects, we recommend accessing the current report descriptor of the device through the sysfs. This is available at ``/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor`` as a binary stream.h](hGiven that hidraw is not stable when the device disconnects/reconnects, we recommend accessing the current report descriptor of the device through the sysfs. This is available at }(hj,hhhNhNubj)}(h;``/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor``h]h7/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor}(hj ,hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj,ubh as a binary stream.}(hj,hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMRhj0+hhubh)}(hParsing the report descriptor is the responsibility of the BPF programmer or the userspace component that loads the eBPF program.h]hParsing the report descriptor is the responsibility of the BPF programmer or the userspace component that loads the eBPF program.}(hj!,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMWhj0+hhubeh}(h]jah ]h"]#attaching a bpf program to a deviceah$]h&]uh1hhhhhhhhM?ubh)}(hhh](h)}(h9An (almost) complete example of a BPF enhanced HID deviceh]h9An (almost) complete example of a BPF enhanced HID device}(hj9,hhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhj6,hhhhhM[ubh)}(hH*Foreword: for most parts, this could be implemented as a kernel driver*h]jc)}(hjI,h]hFForeword: for most parts, this could be implemented as a kernel driver}(hjK,hhhNhNubah}(h]h ]h"]h$]h&]uh1jbhjG,ubah}(h]h ]h"]h$]h&]uh1hhhhM]hj6,hhubh)}(hXyLet's imagine we have a new tablet device that has some haptic capabilities to simulate the surface the user is scratching on. This device would also have a specific 3 positions switch to toggle between *pencil on paper*, *cray on a wall* and *brush on a painting canvas*. To make things even better, we can control the physical position of the switch through a feature report.h](hLet’s imagine we have a new tablet device that has some haptic capabilities to simulate the surface the user is scratching on. This device would also have a specific 3 positions switch to toggle between }(hj^,hhhNhNubjc)}(h*pencil on paper*h]hpencil on paper}(hjf,hhhNhNubah}(h]h ]h"]h$]h&]uh1jbhj^,ubh, }(hj^,hhhNhNubjc)}(h*cray on a wall*h]hcray on a wall}(hjx,hhhNhNubah}(h]h ]h"]h$]h&]uh1jbhj^,ubh and }(hj^,hhhNhNubjc)}(h*brush on a painting canvas*h]hbrush on a painting canvas}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1jbhj^,ubhj. To make things even better, we can control the physical position of the switch through a feature report.}(hj^,hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM_hj6,hhubh)}(htAnd of course, the switch is relying on some userspace component to control the haptic feature of the device itself.h]htAnd of course, the switch is relying on some userspace component to control the haptic feature of the device itself.}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMehj6,hhubh)}(hhh](h)}(hFiltering eventsh]hFiltering events}(hj,hhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhj,hhhhhMiubh)}(hThe first step consists in filtering events from the device. Given that the switch position is actually reported in the flow of the pen events, using hidraw to implement that filtering would mean that we wake up userspace for every single event.h]hThe first step consists in filtering events from the device. Given that the switch position is actually reported in the flow of the pen events, using hidraw to implement that filtering would mean that we wake up userspace for every single event.}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMkhj,hhubh)}(h}This is OK for libinput, but having an external library that is just interested in one byte in the report is less than ideal.h]h}This is OK for libinput, but having an external library that is just interested in one byte in the report is less than ideal.}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMohj,hhubh)}(h>For that, we can create a basic skeleton for our BPF program::h]h=For that, we can create a basic skeleton for our BPF program:}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMrhj,hhubj )}(hX#include "vmlinux.h" #include #include /* HID programs need to be GPL */ char _license[] SEC("license") = "GPL"; /* HID-BPF kfunc API definitions */ extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz) __ksym; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 4096 * 64); } ringbuf SEC(".maps"); __u8 current_value = 0; SEC("struct_ops/hid_device_event") int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 192 /* size */); __u8 *buf; if (!data) return 0; /* EPERM check */ if (current_value != data[152]) { buf = bpf_ringbuf_reserve(&ringbuf, 1, 0); if (!buf) return 0; *buf = data[152]; bpf_ringbuf_commit(buf, 0); current_value = data[152]; } return 0; } SEC(".struct_ops.link") struct hid_bpf_ops haptic_tablet = { .hid_device_event = (void *)filter_switch, };h]hX#include "vmlinux.h" #include #include /* HID programs need to be GPL */ char _license[] SEC("license") = "GPL"; /* HID-BPF kfunc API definitions */ extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz) __ksym; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 4096 * 64); } ringbuf SEC(".maps"); __u8 current_value = 0; SEC("struct_ops/hid_device_event") int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 192 /* size */); __u8 *buf; if (!data) return 0; /* EPERM check */ if (current_value != data[152]) { buf = bpf_ringbuf_reserve(&ringbuf, 1, 0); if (!buf) return 0; *buf = data[152]; bpf_ringbuf_commit(buf, 0); current_value = data[152]; } return 0; } SEC(".struct_ops.link") struct hid_bpf_ops haptic_tablet = { .hid_device_event = (void *)filter_switch, };}hj,sbah}(h]h ]h"]h$]h&]hhuh1j hhhMthj,hhubh)}(hFTo attach ``haptic_tablet``, userspace needs to set ``hid_id`` first::h](h To attach }(hj,hhhNhNubj)}(h``haptic_tablet``h]h haptic_tablet}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj,ubh, userspace needs to set }(hj,hhhNhNubj)}(h ``hid_id``h]hhid_id}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj,ubh first:}(hj,hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj,hhubj )}(hXstatic int attach_filter(struct hid *hid_skel, int hid_id) { int err, link_fd; hid_skel->struct_ops.haptic_tablet->hid_id = hid_id; err = hid__load(skel); if (err) return err; link_fd = bpf_map__attach_struct_ops(hid_skel->maps.haptic_tablet); if (!link_fd) { fprintf(stderr, "can not attach HID-BPF program: %m\n"); return -1; } return link_fd; /* the fd of the created bpf_link */ }h]hXstatic int attach_filter(struct hid *hid_skel, int hid_id) { int err, link_fd; hid_skel->struct_ops.haptic_tablet->hid_id = hid_id; err = hid__load(skel); if (err) return err; link_fd = bpf_map__attach_struct_ops(hid_skel->maps.haptic_tablet); if (!link_fd) { fprintf(stderr, "can not attach HID-BPF program: %m\n"); return -1; } return link_fd; /* the fd of the created bpf_link */ }}hj+-sbah}(h]h ]h"]h$]h&]hhuh1j hhhMhj,hhubh)}(htOur userspace program can now listen to notifications on the ring buffer, and is awaken only when the value changes.h]htOur userspace program can now listen to notifications on the ring buffer, and is awaken only when the value changes.}(hj9-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj,hhubh)}(hWhen the userspace program doesn't need to listen to events anymore, it can just close the returned bpf link from :c:func:`attach_filter`, which will tell the kernel to detach the program from the HID device.h](htWhen the userspace program doesn’t need to listen to events anymore, it can just close the returned bpf link from }(hjG-hhhNhNubh)}(h:c:func:`attach_filter`h]j)}(hjQ-h]hattach_filter()}(hjS-hhhNhNubah}(h]h ](j. j c-funceh"]h$]h&]uh1j hjO-ubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypefunc refexplicitrefwarnj@ jD jH attach_filteruh1hhhhMhjG-ubhG, which will tell the kernel to detach the program from the HID device.}(hjG-hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj,hhubh)}(hOf course, in other use cases, the userspace program can also pin the fd to the BPF filesystem through a call to :c:func:`bpf_obj_pin`, as with any bpf_link.h](hqOf course, in other use cases, the userspace program can also pin the fd to the BPF filesystem through a call to }(hjx-hhhNhNubh)}(h:c:func:`bpf_obj_pin`h]j)}(hj-h]h bpf_obj_pin()}(hj-hhhNhNubah}(h]h ](j. j c-funceh"]h$]h&]uh1j hj-ubah}(h]h ]h"]h$]h&]refdocj: refdomainj reftypefunc refexplicitrefwarnj@ jD jH bpf_obj_pinuh1hhhhMhjx-ubh, as with any bpf_link.}(hjx-hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj,hhubeh}(h]jah ]h"]filtering eventsah$]h&]uh1hhj6,hhhhhMiubh)}(hhh](h)}(hControlling the deviceh]hControlling the device}(hj-hhhNhNubah}(h]h ]h"]h$]h&]j:juh1hhj-hhhhhMubh)}(hTo be able to change the haptic feedback from the tablet, the userspace program needs to emit a feature report on the device itself.h]hTo be able to change the haptic feedback from the tablet, the userspace program needs to emit a feature report on the device itself.}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj-hhubh)}(hgInstead of using hidraw for that, we can create a ``SEC("syscall")`` program that talks to the device::h](h2Instead of using hidraw for that, we can create a }(hj-hhhNhNubj)}(h``SEC("syscall")``h]hSEC("syscall")}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj-ubh" program that talks to the device:}(hj-hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj-hhubj )}(hXW/* some more HID-BPF kfunc API definitions */ extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym; extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym; extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8* data, size_t len, enum hid_report_type type, enum hid_class_request reqtype) __ksym; struct hid_send_haptics_args { /* data needs to come at offset 0 so we can do a memcpy into it */ __u8 data[10]; unsigned int hid; }; SEC("syscall") int send_haptic(struct hid_send_haptics_args *args) { struct hid_bpf_ctx *ctx; int ret = 0; ctx = hid_bpf_allocate_context(args->hid); if (!ctx) return 0; /* EPERM check */ ret = hid_bpf_hw_request(ctx, args->data, 10, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); hid_bpf_release_context(ctx); return ret; }h]hXW/* some more HID-BPF kfunc API definitions */ extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym; extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym; extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8* data, size_t len, enum hid_report_type type, enum hid_class_request reqtype) __ksym; struct hid_send_haptics_args { /* data needs to come at offset 0 so we can do a memcpy into it */ __u8 data[10]; unsigned int hid; }; SEC("syscall") int send_haptic(struct hid_send_haptics_args *args) { struct hid_bpf_ctx *ctx; int ret = 0; ctx = hid_bpf_allocate_context(args->hid); if (!ctx) return 0; /* EPERM check */ ret = hid_bpf_hw_request(ctx, args->data, 10, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); hid_bpf_release_context(ctx); return ret; }}hj-sbah}(h]h ]h"]h$]h&]hhuh1j hhhMhj-hhubh)}(h8And then userspace needs to call that program directly::h]h7And then userspace needs to call that program directly:}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj-hhubj )}(hXGstatic int set_haptic(struct hid *hid_skel, int hid_id, __u8 haptic_value) { int err, prog_fd; int ret = -1; struct hid_send_haptics_args args = { .hid = hid_id, }; DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, .ctx_in = &args, .ctx_size_in = sizeof(args), ); args.data[0] = 0x02; /* report ID of the feature on our device */ args.data[1] = haptic_value; prog_fd = bpf_program__fd(hid_skel->progs.set_haptic); err = bpf_prog_test_run_opts(prog_fd, &tattrs); return err; }h]hXGstatic int set_haptic(struct hid *hid_skel, int hid_id, __u8 haptic_value) { int err, prog_fd; int ret = -1; struct hid_send_haptics_args args = { .hid = hid_id, }; DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, .ctx_in = &args, .ctx_size_in = sizeof(args), ); args.data[0] = 0x02; /* report ID of the feature on our device */ args.data[1] = haptic_value; prog_fd = bpf_program__fd(hid_skel->progs.set_haptic); err = bpf_prog_test_run_opts(prog_fd, &tattrs); return err; }}hj .sbah}(h]h ]h"]h$]h&]hhuh1j hhhMhj-hhubh)}(hNow our userspace program is aware of the haptic state and can control it. The program could make this state further available to other userspace programs (e.g. via a DBus API).h]hNow our userspace program is aware of the haptic state and can control it. The program could make this state further available to other userspace programs (e.g. via a DBus API).}(hj.hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj-hhubh)}(hXThe interesting bit here is that we did not created a new kernel API for this. Which means that if there is a bug in our implementation, we can change the interface with the kernel at-will, because the userspace application is responsible for its own usage.h]hXThe interesting bit here is that we did not created a new kernel API for this. Which means that if there is a bug in our implementation, we can change the interface with the kernel at-will, because the userspace application is responsible for its own usage.}(hj'.hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM hj-hhubeh}(h]jah ]h"]controlling the deviceah$]h&]uh1hhj6,hhhhhMubeh}(h]jah ]h"]9an (almost) complete example of a bpf enhanced hid deviceah$]h&]uh1hhhhhhhhM[ubeh}(h]hid-bpfah ]h"]hid-bpfah$]h&]uh1hhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerjn.error_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(jH.jE.j&j!jhjjjj=jj_jTjjjj jjjjTj%jjjjGj1'jijjjjj$jj*'jj-+j.jr(jMj&+joj)j)j=*j:*j+j+j3,jj@.jj-jj9.ju nametypes}(jH.j&jjjjjTjj jjTjjj1'jjj$j*'j-+jr(j&+j)j=*j+j3,j@.j-j9.uh}(jE.hj!hhj)jjIj=jj_jjjjjWjjjjj%jjjjGjWjijjjj, j5 jjjjjjjj jj'jDjIj6j;jjjjjjj#j#j.j4'jMjE'joju(j)j@)j:*j)j+j@*jj0+jj6,jj,jj-hhjj j7j.jYjPj{jrjjjjjjjjjAj8jcjZjjyjjjjjjj(jjGj>jij`jjjjjjjju footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}j|.KsRparse_messages]transform_messages] transformerN include_log] decorationNhhub.