sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}(hhparenthuba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/translations/zh_CN/hid/hid-bpfmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}(hhhh2ubah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/zh_TW/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}(hhhhFubah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/it_IT/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}(hhhhZubah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/ja_JP/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}(hhhhnubah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/ko_KR/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}(hhhhubah}(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}(hhhhubah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhh9/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf.rsthKubhsection)}(hhh](htitle)}(hHID-BPFh]hHID-BPF}(hhhhhhhNhNubah}(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.}(hhhhhhhNhNubah}(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}(hWhen (and why) to use HID-BPFhhhhhNhNubah}(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}(hDead zone of a joystickhj 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}(h!Simple fixup of report descriptorhj0hhhNhNubah}(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}(h0Add a new feature that requires a new kernel APIhjShhhNhNubah}(h]id4ah ]h"]h$]h&]refid0add-a-new-feature-that-requires-a-new-kernel-apiuh1hhjPubah}(h]h ]h"]h$]h&]uh1hhjMubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]hBMorph a device into something else and control that from userspace}(hBMorph a device into something else and control that from userspacehjvhhhNhNubah}(h]id5ah ]h"]h$]h&]refidBmorph-a-device-into-something-else-and-control-that-from-userspaceuh1hhjsubah}(h]h ]h"]h$]h&]uh1hhjpubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]hFirewall}(hFirewallhjhhhNhNubah}(h]id6ah ]h"]h$]h&]refidfirewalluh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]hTracing}(hTracinghjhhhNhNubah}(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}(hHigh-level view of HID-BPFhjhhhNhNubah}(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]hAvailable types of programs}(hAvailable types of programshjhhhNhNubah}(h]id9ah ]h"]h$]h&]refidavailable-types-of-programsuh1hhj ubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]h)}(hhh]hDeveloper API:}(hDeveloper API:hj1hhhNhNubah}(h]id10ah ]h"]h$]h&]refid developer-apiuh1hhj.ubah}(h]h ]h"]h$]h&]uh1hhj+ubh)}(hhh](h)}(hhh]h)}(hhh]h)}(hhh]h/User API data structures available in programs:}(h/User API data structures available in programs:hjQhhhNhNubah}(h]id11ah ]h"]h$]h&]refid.user-api-data-structures-available-in-programsuh1hhjNubah}(h]h ]h"]h$]h&]uh1hhjKubah}(h]h ]h"]h$]h&]uh1hhjHubh)}(hhh]h)}(hhh]h)}(hhh]h8Available tracing functions to attach a HID-BPF program:}(h8Available tracing functions to attach a HID-BPF program:hjthhhNhNubah}(h]id12ah ]h"]h$]h&]refid7available-tracing-functions-to-attach-a-hid-bpf-programuh1hhjqubah}(h]h ]h"]h$]h&]uh1hhjnubah}(h]h ]h"]h$]h&]uh1hhjHubh)}(hhh]h)}(hhh]h)}(hhh]h7Available API that can be used in all HID-BPF programs:}(h7Available API that can be used in all HID-BPF programs:hjhhhNhNubah}(h]id13ah ]h"]h$]h&]refid6available-api-that-can-be-used-in-all-hid-bpf-programsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjHubh)}(hhh]h)}(hhh]h)}(hhh]h;Available API that can be used in syscall HID-BPF programs:}(h;Available API that can be used in syscall HID-BPF programs:hjhhhNhNubah}(h]id14ah ]h"]h$]h&]refid:available-api-that-can-be-used-in-syscall-hid-bpf-programsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjHubeh}(h]h ]h"]h$]h&]uh1hhj+ubeh}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]h)}(hhh]h%General overview of a HID-BPF program}(h%General overview of a HID-BPF programhjhhhNhNubah}(h]id15ah ]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}(h*Accessing the data attached to the contexthj hhhNhNubah}(h]id16ah ]h"]h$]h&]refid*accessing-the-data-attached-to-the-contextuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]h)}(hhh]hEffect of a HID-BPF program}(hEffect of a HID-BPF programhj,hhhNhNubah}(h]id17ah ]h"]h$]h&]refideffect-of-a-hid-bpf-programuh1hhj)ubah}(h]h ]h"]h$]h&]uh1hhj&ubah}(h]h ]h"]h$]h&]uh1hhjubeh}(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}(h#Attaching a bpf program to a devicehj[hhhNhNubah}(h]id18ah ]h"]h$]h&]refid#attaching-a-bpf-program-to-a-deviceuh1hhjXubah}(h]h ]h"]h$]h&]uh1hhjUubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]h)}(hhh]h9An (almost) complete example of a BPF enhanced HID device}(h9An (almost) complete example of a BPF enhanced HID devicehj~hhhNhNubah}(h]id19ah ]h"]h$]h&]refid7an-almost-complete-example-of-a-bpf-enhanced-hid-deviceuh1hhj{ubah}(h]h ]h"]h$]h&]uh1hhjxubh)}(hhh](h)}(hhh]h)}(hhh]h)}(hhh]hFiltering events}(hFiltering eventshjhhhNhNubah}(h]id20ah ]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}(hControlling the devicehjhhhNhNubah}(h]id21ah ]h"]h$]h&]refidcontrolling-the-deviceuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhjxubeh}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhNhNubah}(h]contentsah ](contentslocaleh"]contentsah$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(hhh]hWhen (and why) to use HID-BPF}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]refidhuh1hhjhhhhhKubh)}(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 hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hhh](h)}(hjh]hDead zone of a joystick}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]j juh1hhjhhhhhKubh)}(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 }(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 hj)hhhNhNubhemphasis)}(h *dead zone*h]h dead zone}(hhhj4hhhNhNubah}(h]h ]h"]h$]h&]uh1j2hj)ubh for this specific axis.}(h for this specific axis.hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(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.}(hjOhjMhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(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.}(hj]hj[hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK!hjhhubh)}(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.}(hjkhjihhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK&hjhhubeh}(h]jah ]h"]dead zone of a joystickah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(hj7h]h!Simple fixup of report descriptor}(hj7hjhhhNhNubah}(h]h ]h"]h$]h&]j j:uh1hhj~hhhhhK*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.}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK,hj~hhubh)}(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.}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK0hj~hhubh)}(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}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK5hj~hhubeh}(h]j@ah ]h"]!simple fixup of report descriptorah$]h&]uh1hhjhhhhhK*ubh)}(hhh](h)}(hjZh]h0Add a new feature that requires a new kernel API}(hjZhjhhhNhNubah}(h]h ]h"]h$]h&]j j]uh1hhjhhhhhK9ubh)}(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.}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK;hjhhubeh}(h]jcah ]h"]0add a new feature that requires a new kernel apiah$]h&]uh1hhjhhhhhK9ubh)}(hhh](h)}(hj}h]hBMorph a device into something else and control that from userspace}(hj}hjhhhNhNubah}(h]h ]h"]h$]h&]j juh1hhjhhhhhKDubh)}(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.}(hjhjhhhNhNubah}(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.}(hjhjhhhNhNubah}(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.}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKOhjhhubeh}(h]jah ]h"]Bmorph a device into something else and control that from userspaceah$]h&]uh1hhjhhhhhKDubh)}(hhh](h)}(hjh]hFirewall}(hjhj(hhhNhNubah}(h]h ]h"]h$]h&]j juh1hhj%hhhhhKWubh)}(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)}(hj7hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKYhj%hhubh)}(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.}(hjEhjChhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK\hj%hhubh)}(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.}(hjShjQhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK_hj%hhubeh}(h]jah ]h"]firewallah$]h&]uh1hhjhhhhhKWubh)}(hhh](h)}(hjh]hTracing}(hjhjihhhNhNubah}(h]h ]h"]h$]h&]j juh1hhjfhhhhhKcubh)}(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.}(hjxhjvhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKehjfhhubh)}(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:}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhjfhhubhenumerated_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)}(hjhjhhhNhNubah}(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.}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKmhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubeh}(h]h ]h"]h$]h&]enumtypearabicprefixhsuffix.uh1jhjfhhhhhKkubeh}(h]jah ]h"]tracingah$]h&]uh1hhjhhhhhKcubeh}(h]hah ]h"]when (and why) to use hid-bpfah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hjh]hHigh-level view of HID-BPF}(hjhjhhhNhNubah}(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.}(hjhjhhhNhNubah}(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 }(hnFor example, in the dead zone joystick from above, knowing which fields in the data stream needs to be set to hjhhhNhNubhliteral)}(h``0``h]h0}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh# needs to be computed by userspace.}(h# needs to be computed by userspace.hjhhhNhNubeh}(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. }(heA corollary of this is that HID-BPF doesn't know about the other subsystems available in the kernel. hj"hhhNhNubj3)}(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}(hhhj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j2hj"ubh.}(hjhj"hhhNhNubeh}(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.}(hjEhjChhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]jah ]h"]high-level view of hid-bpfah$]h&]uh1hhhhhhhhKrubh)}(hhh](h)}(hjh]hAvailable types of programs}(hjhj[hhhNhNubah}(h]h ]h"]h$]h&]j juh1hhjXhhhhhKubh)}(h]HID-BPF is built "on top" of BPF, meaning that we use tracing method to declare our programs.h]haHID-BPF is built “on top” of BPF, meaning that we use tracing method to declare our programs.}(hjjhjhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjXhhubh)}(h5HID-BPF has the following attachment types available:h]h5HID-BPF has the following attachment types available:}(hjxhjvhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjXhhubj)}(hhh](h)}(hRevent processing/filtering with ``SEC("fmod_ret/hid_bpf_device_event")`` in libbpfh]h)}(hjh](h event processing/filtering with }(h event processing/filtering with hjhhhNhNubj)}(h(``SEC("fmod_ret/hid_bpf_device_event")``h]h$SEC("fmod_ret/hid_bpf_device_event")}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh in libbpf}(h in libbpfhjhhhNhNubeh}(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 }(h#actions coming from userspace with hjhhhNhNubj)}(h``SEC("syscall")``h]hSEC("syscall")}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh in libbpf}(h in libbpfhjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubh)}(hWchange of the report descriptor with ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` in libbpf h]h)}(hVchange of the report descriptor with ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` in libbpfh](h%change of the report descriptor with }(h%change of the report descriptor with hjhhhNhNubj)}(h'``SEC("fmod_ret/hid_bpf_rdesc_fixup")``h]h#SEC("fmod_ret/hid_bpf_rdesc_fixup")}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh in libbpf}(h in libbpfhjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubeh}(h]h ]h"]h$]h&]jjjhjjuh1jhjXhhhhhKubh)}(hA ``hid_bpf_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 }(hA hjhhhNhNubj)}(h``hid_bpf_device_event``h]hhid_bpf_device_event}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 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 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&]uh1hhhhKhjXhhubh)}(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 }(hA hj1hhhNhNubj)}(h ``syscall``h]hsyscall}(hhhj:hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj1ubh) means that userspace called the syscall }(h) means that userspace called the syscall hj1hhhNhNubj)}(h``BPF_PROG_RUN``h]h BPF_PROG_RUN}(hhhjMhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj1ubhh facility. This time, we can do any operations allowed by HID-BPF, and talking to the device is allowed.}(hh facility. This time, we can do any operations allowed by HID-BPF, and talking to the device is allowed.hj1hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjXhhubh)}(hXLast, ``hid_bpf_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_bpf_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, }(hLast, hjfhhhNhNubj)}(h``hid_bpf_rdesc_fixup``h]hhid_bpf_rdesc_fixup}(hhhjohhhNhNubah}(h]h ]h"]h$]h&]uh1jhjfubhc is different from the others as there can be only one BPF program of this type. This is called on }(hc is different from the others as there can be only one BPF program of this type. This is called on hjfhhhNhNubj)}(h ``probe``h]hprobe}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjfubhY from the driver and allows to change the report descriptor from the BPF program. Once a }(hY from the driver and allows to change the report descriptor from the BPF program. Once a hjfhhhNhNubj)}(h``hid_bpf_rdesc_fixup``h]hhid_bpf_rdesc_fixup}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjfubh 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 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.hjfhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjXhhubeh}(h]jah ]h"]available types of programsah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hj8h]hDeveloper API:}(hj8hjhhhNhNubah}(h]h ]h"]h$]h&]j j;uh1hhjhhhhhKubh)}(hhh](h)}(hjXh]h/User API data structures available in programs:}(hjXhjhhhNhNubah}(h]h ]h"]h$]h&]j j[uh1hhjhhhhhKubhindex)}(hhh]h}(h]h ]h"]h$]h&]entries](singlehid_bpf_ctx (C struct) c.hid_bpf_ctxhNtauh1jhjhhhNhNubhdesc)}(hhh](hdesc_signature)}(h hid_bpf_ctxh]hdesc_signature_line)}(hstruct hid_bpf_ctxh](hdesc_sig_keyword)}(hstructh]hstruct}(hhhjhhhNhNubah}(h]h ]kah"]h$]h&]uh1jhjhhhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKubhdesc_sig_space)}(h h]h }(hhhj hhhNhNubah}(h]h ]wah"]h$]h&]uh1j hjhhhjhKubh desc_name)}(h hid_bpf_ctxh]h desc_sig_name)}(hjh]h hid_bpf_ctx}(hhhj"hhhNhNubah}(h]h ]nah"]h$]h&]uh1j hjubah}(h]h ](sig-namedescnameeh"]h$]h&]hhuh1jhjhhhjhKubeh}(h]h ]h"]h$]h&]hh add_permalinkuh1jsphinx_line_type declaratorhjhhhjhKubah}(h]jah ](sig sig-objecteh"]h$]h&] is_multilineuh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjhhubh desc_content)}(hhh]h)}(h)User accessible data for all HID programsh]h)User accessible data for all HID programs}(hjRhjPhhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjMhhubah}(h]h ]h"]h$]h&]uh1jKhjhhhjhKubeh}(h]h ](cstructeh"]h$]h&]domainjhobjtypejidesctypejinoindexuh1jhhhjhNhNubh container)}(hX**Definition**:: struct hid_bpf_ctx { __u32 index; const struct hid_device *hid; __u32 allocated_size; enum hid_report_type report_type; union { __s32 retval; __s32 size; }; }; **Members** ``index`` program index in the jump table. No special meaning (a smaller index doesn't mean the program will be executed before another program with a bigger index). ``hid`` the ``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) ``report_type`` used for ``hid_bpf_device_event()`` ``{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](hstrong)}(h**Definition**h]h Definition}(hhhj}hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjwubh:}(h:hjwhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjsubh literal_block)}(hstruct hid_bpf_ctx { __u32 index; const struct hid_device *hid; __u32 allocated_size; enum hid_report_type report_type; union { __s32 retval; __s32 size; }; };h]hstruct hid_bpf_ctx { __u32 index; const struct hid_device *hid; __u32 allocated_size; enum hid_report_type report_type; union { __s32 retval; __s32 size; }; };}(hhhjubah}(h]h ]h"]h$]h&]hhuh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjsubh)}(h **Members**h]j|)}(hjh]hMembers}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK%hjsubhdefinition_list)}(hhh](hdefinition_list_item)}(h``index`` program index in the jump table. No special meaning (a smaller index doesn't mean the program will be executed before another program with a bigger index). h](hterm)}(h ``index``h]j)}(hjh]hindex}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjubh definition)}(hhh]h)}(hprogram index in the jump table. No special meaning (a smaller index doesn't mean the program will be executed before another program with a bigger index).h]hprogram index in the jump table. No special meaning (a smaller index doesn’t mean the program will be executed before another program with a bigger index).}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhKhjubj)}(hA``hid`` the ``struct hid_device`` representing the device itself h](j)}(h``hid``h]j)}(hj h]hhid}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhj ubj)}(hhh]h)}(h8the ``struct hid_device`` representing the device itselfh](hthe }(hthe hj$ hhhNhNubj)}(h``struct hid_device``h]hstruct hid_device}(hhhj- hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj$ ubh representing the device itself}(h representing the device itselfhj$ hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj hKhj! ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj hKhjubj)}(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)}(hjX h]hallocated_size}(hhhjZ hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjV ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK&hjR ubj)}(hhh](h)}(hAllocated size of data.h]hAllocated size of data.}(hjs hjq hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK!hjn ubh)}(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 }(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}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh, that memory is set to }(h, that memory is set to hj hhhNhNubj)}(h``4096``h]h4096}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh (4 KB)}(h (4 KB)hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK#hjn ubeh}(h]h ]h"]h$]h&]uh1jhjR ubeh}(h]h ]h"]h$]h&]uh1jhjm hK&hjubj)}(h4``report_type`` used for ``hid_bpf_device_event()`` h](j)}(h``report_type``h]j)}(hj h]h report_type}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK hj ubj)}(hhh]h)}(h#used for ``hid_bpf_device_event()``h](h used for }(h used for hj hhhNhNubj)}(h``hid_bpf_device_event()``h]hhid_bpf_device_event()}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1hhj hK hj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj hK hjubj)}(h``{unnamed_union}`` anonymous h](j)}(h``{unnamed_union}``h]j)}(hj h]h{unnamed_union}}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK#hj ubj)}(hhh]h)}(h anonymoush]h anonymous}(hj+ hj) hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj% hK#hj& ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj% hK#hjubj)}(h1``retval`` Return value of the previous program. h](j)}(h ``retval``h]j)}(hjI h]hretval}(hhhjK hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjG ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK0hjC ubj)}(hhh]h)}(h%Return value of the previous program.h]h%Return value of the previous program.}(hjd hjb hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj^ hK0hj_ ubah}(h]h ]h"]h$]h&]uh1jhjC ubeh}(h]h ]h"]h$]h&]uh1jhj^ hK0hjubj)}(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)}(hj h]hsize}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK.hj| ubj)}(hhh](h)}(hValid data in the data field.h]hValid data in the data field.}(hj hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK'hj ubh)}(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.}(hj hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK)hj ubh)}(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}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh# must always be less or equal than }(h# must always be less or equal than hj hhhNhNubj)}(h``allocated_size``h]hallocated_size}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh6 (it is enforced once all BPF programs have been run).}(h6 (it is enforced once all BPF programs have been run).hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj hK.hj ubeh}(h]h ]h"]h$]h&]uh1jhj| ubeh}(h]h ]h"]h$]h&]uh1jhj hK.hjubeh}(h]h ]h"]h$]h&]uh1jhjsubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubh)}(h**Description**h]j|)}(hj h]h Description}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj ubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK2hjhhubh)}(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}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubhI is not directly accessible from the context. We need to issue a call to }(hI is not directly accessible from the context. We need to issue a call to hj hhhNhNubj)}(h``hid_bpf_get_data()``h]hhid_bpf_get_data()}(hhhj1 hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh) in order to get a pointer to that field.}(h) in order to get a pointer to that field.hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjhhubh)}(h,All of these fields are currently read-only.h]h,All of these fields are currently read-only.}(hjM hjK hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjhhubj)}(hhh]h}(h]h ]h"]h$]h&]entries](jhid_bpf_attach_flags (C enum)c.hid_bpf_attach_flagshNtauh1jhjhhhNhNubj)}(hhh](j)}(hhid_bpf_attach_flagsh]j)}(henum hid_bpf_attach_flagsh](j)}(henumh]henum}(hhhjs hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjo hhhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK>ubj )}(h h]h }(hhhj hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjo hhhj hK>ubj)}(hhid_bpf_attach_flagsh]j!)}(hjm h]hhid_bpf_attach_flags}(hhhj hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj ubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjo hhhj hK>ubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hjk hhhj hK>ubah}(h]jf ah ](jDjEeh"]h$]h&]jIuh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKhjh hhubjL)}(hhh]h)}(h+flags used when attaching a HIF-BPF programh]h+flags used when attaching a HIF-BPF program}(hj hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhK=hj hhubah}(h]h ]h"]h$]h&]uh1jKhjh hhhj hK>ubeh}(h]h ](jhenumeh"]h$]h&]jmjhjnj joj jpuh1jhhhjhNhNubjr)}(hXl**Constants** ``HID_BPF_FLAG_NONE`` no specific flag is used, the kernel choses where to insert the program ``HID_BPF_FLAG_INSERT_HEAD`` insert the given program before any other program currently attached to the device. This doesn't guarantee that this program will always be first ``HID_BPF_FLAG_MAX`` sentinel value, not to be used by the callersh](h)}(h **Constants**h]j|)}(hj h]h Constants}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj ubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKAhj ubj)}(hhh](j)}(h^``HID_BPF_FLAG_NONE`` no specific flag is used, the kernel choses where to insert the program h](j)}(h``HID_BPF_FLAG_NONE``h]j)}(hj h]hHID_BPF_FLAG_NONE}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKEhj ubj)}(hhh]h)}(hGno specific flag is used, the kernel choses where to insert the programh]hGno specific flag is used, the kernel choses where to insert the program}(hj hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKDhj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj hKEhj ubj)}(h``HID_BPF_FLAG_INSERT_HEAD`` insert the given program before any other program currently attached to the device. This doesn't guarantee that this program will always be first h](j)}(h``HID_BPF_FLAG_INSERT_HEAD``h]j)}(hj2 h]hHID_BPF_FLAG_INSERT_HEAD}(hhhj4 hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj0 ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKJhj, ubj)}(hhh]h)}(hinsert the given program before any other program currently attached to the device. This doesn't guarantee that this program will always be firsth]hinsert the given program before any other program currently attached to the device. This doesn’t guarantee that this program will always be first}(hjM hjK hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKHhjH ubah}(h]h ]h"]h$]h&]uh1jhj, ubeh}(h]h ]h"]h$]h&]uh1jhjG hKJhj ubj)}(hB``HID_BPF_FLAG_MAX`` sentinel value, not to be used by the callersh](j)}(h``HID_BPF_FLAG_MAX``h]j)}(hjl h]hHID_BPF_FLAG_MAX}(hhhjn hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjj ubah}(h]h ]h"]h$]h&]uh1jhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKLhjf ubj)}(hhh]h)}(h-sentinel value, not to be used by the callersh]h-sentinel value, not to be used by the callers}(hj hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:164: ./include/linux/hid_bpf.hhKMhj ubah}(h]h ]h"]h$]h&]uh1jhjf ubeh}(h]h ]h"]h$]h&]uh1jhj hKLhj ubeh}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubeh}(h]jaah ]h"]/user api data structures available in programs:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(hj{h]h8Available tracing functions to attach a HID-BPF program:}(hj{hj hhhNhNubah}(h]h ]h"]h$]h&]j j~uh1hhj hhhhhKubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j!hid_bpf_device_event (C function)c.hid_bpf_device_eventhNtauh1jhj hhhNhNubj)}(hhh](j)}(h;noinline int hid_bpf_device_event (struct hid_bpf_ctx *ctx)h]j)}(h:noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx)h](hnoinline}(hhhj hhhNhNubj )}(h h]h }(hhhj hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj hhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chKubhdesc_sig_keyword_type)}(hinth]hint}(hhhj hhhNhNubah}(h]h ]ktah"]h$]h&]uh1j hj hhhj hKubj )}(h h]h }(hhhj hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj hhhj hKubj)}(hhid_bpf_device_eventh]j!)}(hhid_bpf_device_eventh]hhid_bpf_device_event}(hhhj hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj ubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhj hhhj hKubhdesc_parameterlist)}(h(struct hid_bpf_ctx *ctx)h]hdesc_parameter)}(hstruct hid_bpf_ctx *ctxh](j)}(hjh]hstruct}(hhhj3 hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj/ ubj )}(h h]h }(hhhj@ hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj/ ubh)}(hhh]j!)}(h hid_bpf_ctxh]h hid_bpf_ctx}(hhhjQ hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjN ubah}(h]h ]h"]h$]h&] refdomainjhreftype identifier reftargetjS modnameN classnameN c:parent_keysphinx.domains.c LookupKey)}data]jl ASTIdentifier)}jg j sbc.hid_bpf_device_eventasbuh1hhj/ ubj )}(h h]h }(hhhjy hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj/ ubhdesc_sig_punctuation)}(h*h]h*}(hhhj hhhNhNubah}(h]h ]pah"]h$]h&]uh1j hj/ ubj!)}(hctxh]hctx}(hhhj hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj/ ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj) ubah}(h]h ]h"]h$]h&]hhuh1j' hj hhhj hKubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hj hhhj hKubah}(h]j ah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK*hj hhubjL)}(hhh]h)}(h5Called whenever an event is coming in from the deviceh]h5Called whenever an event is coming in from the device}(hj hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chKhj hhubah}(h]h ]h"]h$]h&]uh1jKhj hhhj hKubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnj joj jpuh1jhhhj hNhNubjr)}(hX**Parameters** ``struct hid_bpf_ctx *ctx`` The HID-BPF context **Description** **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 Declare an ``fmod_ret`` tracing bpf program to this function and attach this program through hid_bpf_attach_prog() to have this helper called for any incoming event from the device itself. The function is called while on IRQ context, so we can not sleep.h](h)}(h**Parameters**h]j|)}(hj h]h Parameters}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK hj ubj)}(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}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chKhj ubj)}(hhh]h)}(hThe HID-BPF contexth]hThe HID-BPF context}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhKhjubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhjhKhj ubah}(h]h ]h"]h$]h&]uh1jhj ubh)}(h**Description**h]j|)}(hj?h]h Description}(hhhjAhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj=ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK hj ubh)}(h**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 eventh](j|)}(h **return**h]hreturn}(hhhjYhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjUubh }(h hjUhhhNhNubj)}(h``0``h]h0}(hhhjlhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjUubh 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}(h on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this eventhjUhhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK hj ubh)}(hDeclare an ``fmod_ret`` tracing bpf program to this function and attach this program through hid_bpf_attach_prog() to have this helper called for any incoming event from the device itself.h](h Declare an }(h Declare an hjhhhNhNubj)}(h ``fmod_ret``h]hfmod_ret}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh tracing bpf program to this function and attach this program through hid_bpf_attach_prog() to have this helper called for any incoming event from the device itself.}(h tracing bpf program to this function and attach this program through hid_bpf_attach_prog() to have this helper called for any incoming event from the device itself.hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK$hj ubh)}(hAThe function is called while on IRQ context, so we can not sleep.h]hAThe function is called while on IRQ context, so we can not sleep.}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK(hj ubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhj hhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j hid_bpf_rdesc_fixup (C function)c.hid_bpf_rdesc_fixuphNtauh1jhj hhhNhNubj)}(hhh](j)}(h:noinline int hid_bpf_rdesc_fixup (struct hid_bpf_ctx *ctx)h]j)}(h9noinline int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx)h](hnoinline}(hhhjhhhNhNubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chKZubj )}(hinth]hint}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjhhhjhKZubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhhjhKZubj)}(hhid_bpf_rdesc_fixuph]j!)}(hhid_bpf_rdesc_fixuph]hhid_bpf_rdesc_fixup}(hhhj hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjhhhjhKZubj( )}(h(struct hid_bpf_ctx *ctx)h]j. )}(hstruct hid_bpf_ctx *ctxh](j)}(hjh]hstruct}(hhhj'hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj#ubj )}(h h]h }(hhhj4hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj#ubh)}(hhh]j!)}(h hid_bpf_ctxh]h hid_bpf_ctx}(hhhjEhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjBubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjGmodnameN classnameNjk jn )}jq ]jt )}jg j sbc.hid_bpf_rdesc_fixupasbuh1hhj#ubj )}(h h]h }(hhhjehhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj#ubj )}(hj h]h*}(hhhjshhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hj#ubj!)}(hctxh]hctx}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj#ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjubah}(h]h ]h"]h$]h&]hhuh1j' hjhhhjhKZubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hjhhhjhKZubah}(h]jah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chKfhjhhubjL)}(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}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chKYhjhhubah}(h]h ]h"]h$]h&]uh1jKhjhhhjhKZubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnjjojjpuh1jhhhj hNhNubjr)}(hX**Parameters** ``struct hid_bpf_ctx *ctx`` The HID-BPF context **Description** **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 Declare an ``fmod_ret`` tracing bpf program to this function and attach this program through hid_bpf_attach_prog() to have this helper called before any parsing of the report descriptor by HID.h](h)}(h**Parameters**h]j|)}(hjh]h Parameters}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK]hjubj)}(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}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK\hjubj)}(hhh]h)}(hThe HID-BPF contexth]hThe HID-BPF context}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhK\hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhK\hjubah}(h]h ]h"]h$]h&]uh1jhjubh)}(h**Description**h]j|)}(hj'h]h Description}(hhhj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj%ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK^hjubh)}(h**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 eventh](j|)}(h **return**h]hreturn}(hhhjAhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj=ubh 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}(h 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 eventhj=hhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chK^hjubh)}(hDeclare an ``fmod_ret`` tracing bpf program to this function and attach this program through hid_bpf_attach_prog() to have this helper called before any parsing of the report descriptor by HID.h](h Declare an }(h Declare an hj[hhhNhNubj)}(h ``fmod_ret``h]hfmod_ret}(hhhjdhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj[ubh tracing bpf program to this function and attach this program through hid_bpf_attach_prog() to have this helper called before any parsing of the report descriptor by HID.}(h tracing bpf program to this function and attach this program through hid_bpf_attach_prog() to have this helper called before any parsing of the report descriptor by HID.hj[hhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:169: ./drivers/hid/bpf/hid_bpf_dispatch.chKbhjubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhj hhhNhNubeh}(h]jah ]h"]8available tracing functions to attach a hid-bpf program:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(hjh]h7Available API that can be used in all HID-BPF programs:}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]j juh1hhjhhhhhKubj)}(hhh]h}(h]h ]h"]h$]h&]entries](jhid_bpf_get_data (C function)c.hid_bpf_get_datahNtauh1jhjhhhNhNubj)}(hhh](j)}(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}(hhhjhhhNhNubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKubh)}(hhh]j!)}(h__u8h]h__u8}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jt )}jg hid_bpf_get_datasbc.hid_bpf_get_dataasbuh1hhjhhhjhKubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhhjhKubj )}(hj h]h*}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjhhhjhKubj)}(hhid_bpf_get_datah]j!)}(hjh]hhid_bpf_get_data}(hhhj hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjhhhjhKubj( )}(hJ(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)h](j. )}(hstruct hid_bpf_ctx *ctxh](j)}(hjh]hstruct=}(hhhj&hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj"ubj )}(h h]h }(hhhj3hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj"ubh)}(hhh]j!)}(h hid_bpf_ctxh]h hid_bpf_ctx}(hhhjDhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjAubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjFmodnameN classnameNjk jn )}jq ]jc.hid_bpf_get_dataasbuh1hhj"ubj )}(h h]h }(hhhjbhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj"ubj )}(hj h]h*}(hhhjphhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hj"ubj!)}(hctxh]hctx}(hhhj}hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj"ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjubj. )}(hunsigned int offseth](j )}(hunsignedh]hunsigned}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj )}(hinth]hint}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj!)}(hoffseth]hoffset}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjubj. )}(hconst size_t rdwr_buf_sizeh](j)}(hconsth]hconst}(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubh)}(hhh]j!)}(hsize_th]hsize_t}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jc.hid_bpf_get_dataasbuh1hhjubj )}(h h]h }(hhhj$hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj!)}(h rdwr_buf_sizeh]h rdwr_buf_size}(hhhj2hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjubeh}(h]h ]h"]h$]h&]hhuh1j' hjhhhjhKubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hjhhhjhKubah}(h]jah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKhjhhubjL)}(hhh]h)}(hAGet the kernel memory pointer associated with the context **ctx**h](h:Get the kernel memory pointer associated with the context }(h:Get the kernel memory pointer associated with the context hj]hhhNhNubj|)}(h**ctx**h]hctx}(hhhjfhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj]ubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKhjZhhubah}(h]h ]h"]h$]h&]uh1jKhjhhhjhKubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnjjojjpuh1jhhhjhNhNubjr)}(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}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKhjubj)}(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}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKhjubj)}(hhh]h)}(hThe HID-BPF contexth]hThe HID-BPF context}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhKhjubj)}(h5``unsigned int offset`` The offset within the memory h](j)}(h``unsigned int offset``h]j)}(hjh]hunsigned int offset}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKhjubj)}(hhh]h)}(hThe offset within the memoryh]hThe offset within the memory}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhKhjubj)}(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}(hhhj!hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKhjubj)}(hhh]h)}(hthe const size of the bufferh]hthe const size of the buffer}(hj:hj8hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj4hKhj5ubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhj4hKhjubeh}(h]h ]h"]h$]h&]uh1jhjubh)}(h**Description**h]j|)}(hjZh]h Description}(hhhj\hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjXubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKhjubh)}(hD**returns** ``NULL`` on error, an ``__u8`` memory pointer on successh](j|)}(h **returns**h]hreturns}(hhhjthhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjpubh }(hjkhjphhhNhNubj)}(h``NULL``h]hNULL}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjpubh on error, an }(h on error, an hjphhhNhNubj)}(h``__u8``h]h__u8}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjpubh memory pointer on success}(h memory pointer on successhjphhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:175: ./drivers/hid/bpf/hid_bpf_dispatch.chKhjubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubeh}(h]jah ]h"]7available api that can be used in all hid-bpf programs:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(hjh]h;Available API that can be used in syscall HID-BPF programs:}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]j juh1hhjhhhhhKubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j hid_bpf_attach_prog (C function)c.hid_bpf_attach_proghNtauh1jhjhhhNhNubj)}(hhh](j)}(hS__bpf_kfunc int hid_bpf_attach_prog (unsigned int hid_id, int prog_fd, __u32 flags)h]j)}(hR__bpf_kfunc int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)h](h __bpf_kfunc}(hhhjhhhNhNubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chM ubj )}(hinth]hint}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjhhhjhM ubj )}(h h]h }(hhhj hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhhjhM ubj)}(hhid_bpf_attach_progh]j!)}(hhid_bpf_attach_progh]hhid_bpf_attach_prog}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjhhhjhM ubj( )}(h/(unsigned int hid_id, int prog_fd, __u32 flags)h](j. )}(hunsigned int hid_idh](j )}(hunsignedh]hunsigned}(hhhj9hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hj5ubj )}(h h]h }(hhhjGhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj5ubj )}(hinth]hint}(hhhjUhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hj5ubj )}(h h]h }(hhhjchhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj5ubj!)}(hhid_idh]hhid_id}(hhhjqhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj5ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj1ubj. )}(h int prog_fdh](j )}(hinth]hint}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj!)}(hprog_fdh]hprog_fd}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj1ubj. )}(h __u32 flagsh](h)}(hhh]j!)}(h__u32h]h__u32}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jt )}jg jsbc.hid_bpf_attach_progasbuh1hhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj!)}(hflagsh]hflags}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj1ubeh}(h]h ]h"]h$]h&]hhuh1j' hjhhhjhM ubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hjhhhjhM ubah}(h]jah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubjL)}(hhh]h)}(h4Attach the given **prog_fd** to the given HID deviceh](hAttach the given }(hAttach the given hjhhhNhNubj|)}(h **prog_fd**h]hprog_fd}(hhhj$hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjubh to the given HID device}(h to the given HID devicehjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chM hjhhubah}(h]h ]h"]h$]h&]uh1jKhjhhhjhM ubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnjGjojGjpuh1jhhhjhNhNubjr)}(hX**Parameters** ``unsigned int hid_id`` the system unique identifier of the HID device ``int prog_fd`` an fd in the user process representing the program to attach ``__u32 flags`` any logical OR combination of :c:type:`enum hid_bpf_attach_flags ` **Description** **returns** an fd of a bpf_link object on success (> ``0``), an error code otherwise. Closing this fd will detach the program from the HID device (unless the bpf_link is pinned to the BPF file system).h](h)}(h**Parameters**h]j|)}(hjQh]h Parameters}(hhhjShhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjOubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjKubj)}(hhh](j)}(hG``unsigned int hid_id`` the system unique identifier of the HID device h](j)}(h``unsigned int hid_id``h]j)}(hjph]hunsigned int hid_id}(hhhjrhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjnubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjjubj)}(hhh]h)}(h.the system unique identifier of the HID deviceh]h.the system unique identifier of the HID device}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jhjjubeh}(h]h ]h"]h$]h&]uh1jhjhMhjgubj)}(hM``int prog_fd`` an fd in the user process representing the program to attach h](j)}(h``int prog_fd``h]j)}(hjh]h int prog_fd}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj)}(hhh]h)}(h` h](j)}(h``__u32 flags``h]j)}(hjh]h __u32 flags}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj)}(hhh]h)}(hXany logical OR combination of :c:type:`enum hid_bpf_attach_flags `h](hany logical OR combination of }(hany logical OR combination of hjhhhNhNubh)}(h::c:type:`enum hid_bpf_attach_flags `h]j)}(hjh]henum hid_bpf_attach_flags}(hhhjhhhNhNubah}(h]h ](xrefjhc-typeeh"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]refdoc hid/hid-bpf refdomainjhreftypetype refexplicitrefwarn c:parent_keyjn )}jq ]sb reftargethid_bpf_attach_flagsuh1hhjhMhjubeh}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhMhjgubeh}(h]h ]h"]h$]h&]uh1jhjKubh)}(h**Description**h]j|)}(hjDh]h Description}(hhhjFhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjBubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjKubh)}(h**returns** an fd of a bpf_link object on success (> ``0``), an error code otherwise. Closing this fd will detach the program from the HID device (unless the bpf_link is pinned to the BPF file system).h](j|)}(h **returns**h]hreturns}(hhhj^hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjZubh* an fd of a bpf_link object on success (> }(h* an fd of a bpf_link object on success (> hjZhhhNhNubj)}(h``0``h]h0}(hhhjqhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjZubh), an error code otherwise. Closing this fd will detach the program from the HID device (unless the bpf_link is pinned to the BPF file system).}(h), an error code otherwise. Closing this fd will detach the program from the HID device (unless the bpf_link is pinned to the BPF file system).hjZhhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjKubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j%hid_bpf_allocate_context (C function)c.hid_bpf_allocate_contexthNtauh1jhjhhhNhNubj)}(hhh](j)}(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}(hhhjhhhNhNubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMFubj)}(hjh]hstruct}(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjhhhjhMFubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhhjhMFubh)}(hhh]j!)}(h hid_bpf_ctxh]h hid_bpf_ctx}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jt )}jg hid_bpf_allocate_contextsbc.hid_bpf_allocate_contextasbuh1hhjhhhjhMFubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhhjhMFubj )}(hj h]h*}(hhhj hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjhhhjhMFubj)}(hhid_bpf_allocate_contexth]j!)}(hjh]hhid_bpf_allocate_context}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjhhhjhMFubj( )}(h(unsigned int hid_id)h]j. )}(hunsigned int hid_idh](j )}(hunsignedh]hunsigned}(hhhj7hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hj3ubj )}(h h]h }(hhhjEhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj3ubj )}(hinth]hint}(hhhjShhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hj3ubj )}(h h]h }(hhhjahhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj3ubj!)}(hhid_idh]hhid_id}(hhhjohhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj3ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj/ubah}(h]h ]h"]h$]h&]hhuh1j' hjhhhjhMFubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hjhhhjhMFubah}(h]jah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMKhjhhubjL)}(hhh]h)}(h*Allocate a context to the given HID deviceh]h*Allocate a context to the given HID device}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMEhjhhubah}(h]h ]h"]h$]h&]uh1jKhjhhhjhMFubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnjjojjpuh1jhhhjhNhNubjr)}(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|)}(hjh]h Parameters}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMIhjubj)}(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}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMGhjubj)}(hhh]h)}(h.the system unique identifier of the HID deviceh]h.the system unique identifier of the HID device}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMGhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhMGhjubah}(h]h ]h"]h$]h&]uh1jhjubh)}(h**Description**h]j|)}(hjh]h Description}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMIhjubh)}(hb**returns** A pointer to :c:type:`struct hid_bpf_ctx ` on success, ``NULL`` on error.h](j|)}(h **returns**h]hreturns}(hhhj0hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj,ubh A pointer to }(h A pointer to hj,hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j)}(hjEh]hstruct hid_bpf_ctx}(hhhjGhhhNhNubah}(h]h ](jjhc-typeeh"]h$]h&]uh1jhjCubah}(h]h ]h"]h$]h&]refdocj refdomainjhreftypetype refexplicitrefwarnj$j%j( hid_bpf_ctxuh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMIhj,ubh on success, }(h on success, hj,hhhNhNubj)}(h``NULL``h]hNULL}(hhhjhhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj,ubh on error.}(h on error.hj,hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjbhMIhjubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j$hid_bpf_release_context (C function)c.hid_bpf_release_contexthNtauh1jhjhhhNhNubj)}(hhh](j)}(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}(hhhjhhhNhNubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhubj )}(hvoidh]hvoid}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjhhhjhMhubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhhjhMhubj)}(hhid_bpf_release_contexth]j!)}(hhid_bpf_release_contexth]hhid_bpf_release_context}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjhhhjhMhubj( )}(h(struct hid_bpf_ctx *ctx)h]j. )}(hstruct hid_bpf_ctx *ctxh](j)}(hjh]hstruct}(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubh)}(hhh]j!)}(h hid_bpf_ctxh]h hid_bpf_ctx}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jt )}jg jsbc.hid_bpf_release_contextasbuh1hhjubj )}(h h]h }(hhhj.hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj )}(hj h]h*}(hhhj<hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjubj!)}(hctxh]hctx}(hhhjIhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjubah}(h]h ]h"]h$]h&]hhuh1j' hjhhhjhMhubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hjhhhjhMhubah}(h]jah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMlhjhhubjL)}(hhh]h)}(h0Release the previously allocated context **ctx**h](h)Release the previously allocated context }(h)Release the previously allocated context hjthhhNhNubj|)}(h**ctx**h]hctx}(hhhj}hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjtubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMghjqhhubah}(h]h ]h"]h$]h&]uh1jKhjhhhjhMhubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnjjojjpuh1jhhhjhNhNubjr)}(hL**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context to releaseh](h)}(h**Parameters**h]j|)}(hjh]h Parameters}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMkhjubj)}(hhh]j)}(h:``struct hid_bpf_ctx *ctx`` the HID-BPF context to releaseh](j)}(h``struct hid_bpf_ctx *ctx``h]j)}(hjh]hstruct hid_bpf_ctx *ctx}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMmhjubj)}(hhh]h)}(hthe HID-BPF context to releaseh]hthe HID-BPF context to release}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMihjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhMmhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](jhid_bpf_hw_request (C function)c.hid_bpf_hw_requesthNtauh1jhjhhhNhNubj)}(hhh](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]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}(hhhjhhhNhNubj )}(h h]h }(hhhj"hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj )}(hinth]hint}(hhhj1hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjhhhj0hMubj )}(h h]h }(hhhj?hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhhj0hMubj)}(hhid_bpf_hw_requesth]j!)}(hhid_bpf_hw_requesth]hhid_bpf_hw_request}(hhhjQhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjMubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjhhhj0hMubj( )}(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)}(hjh]hstruct}(hhhjmhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjiubj )}(h h]h }(hhhjzhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjiubh)}(hhh]j!)}(h hid_bpf_ctxh]h hid_bpf_ctx}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jt )}jg jSsbc.hid_bpf_hw_requestasbuh1hhjiubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjiubj )}(hj h]h*}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjiubj!)}(hctxh]hctx}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjiubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjeubj. )}(h __u8 *bufh](h)}(hhh]j!)}(h__u8h]h__u8}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jc.hid_bpf_hw_requestasbuh1hhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj )}(hj h]h*}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjubj!)}(hbufh]hbuf}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjeubj. )}(hsize_t buf__szh](h)}(hhh]j!)}(hsize_th]hsize_t}(hhhj7hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj4ubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetj9modnameN classnameNjk jn )}jq ]jc.hid_bpf_hw_requestasbuh1hhj0ubj )}(h h]h }(hhhjUhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj0ubj!)}(hbuf__szh]hbuf__sz}(hhhjchhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj0ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjeubj. )}(henum hid_report_type rtypeh](j)}(hju h]henum}(hhhj|hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjxubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjxubh)}(hhh]j!)}(hhid_report_typeh]hhid_report_type}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jc.hid_bpf_hw_requestasbuh1hhjxubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjxubj!)}(hrtypeh]hrtype}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjxubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjeubj. )}(henum hid_class_request reqtypeh](j)}(hju h]henum}(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubh)}(hhh]j!)}(hhid_class_requesth]hhid_class_request}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jc.hid_bpf_hw_requestasbuh1hhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj!)}(hreqtypeh]hreqtype}(hhhj)hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjeubeh}(h]h ]h"]h$]h&]hhuh1j' hjhhhj0hMubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hjhhhj0hMubah}(h]jah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubjL)}(hhh]h)}(hCommunicate with a HID deviceh]hCommunicate with a HID device}(hjVhjThhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjQhhubah}(h]h ]h"]h$]h&]uh1jKhjhhhj0hMubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnjljojljpuh1jhhhjhNhNubjr)}(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|)}(hjvh]h Parameters}(hhhjxhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjtubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjpubj)}(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}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj)}(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()}(hjhjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhMhjubj)}(h&``__u8 *buf`` a ``PTR_TO_MEM`` buffer h](j)}(h ``__u8 *buf``h]j)}(hjh]h __u8 *buf}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj)}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(ha hjhhhNhNubj)}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh buffer}(h bufferhjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhMhjubj)}(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}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj)}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hj6hj4hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj0hMhj1ubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhj0hMhjubj)}(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)}(hjTh]henum hid_report_type rtype}(hhhjVhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjRubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjNubj)}(hhh]h)}(h\the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](hthe type of the report (}(hthe type of the report (hjmhhhNhNubj)}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hhhjvhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjmubh, }(h, hjmhhhNhNubj)}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjmubh, }(hjhjmubj)}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjmubh)}(h)hjmhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjihMhjjubah}(h]h ]h"]h$]h&]uh1jhjNubeh}(h]h ]h"]h$]h&]uh1jhjihMhjubj)}(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)}(hjh]henum hid_class_request reqtype}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj)}(hhh]h)}(hMthe type of the request (``HID_REQ_GET_REPORT``, ``HID_REQ_SET_REPORT``, ...)h](hthe type of the request (}(hthe type of the request (hjhhhNhNubj)}(h``HID_REQ_GET_REPORT``h]hHID_REQ_GET_REPORT}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh, }(h, hjhhhNhNubj)}(h``HID_REQ_SET_REPORT``h]hHID_REQ_SET_REPORT}(hhhjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh, ...)}(h, ...)hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhMhjubeh}(h]h ]h"]h$]h&]uh1jhjpubh)}(h**Description**h]j|)}(hj(h]h Description}(hhhj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj&ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjpubh)}(h>**returns** ``0`` on success, a negative error code otherwise.h](j|)}(h **returns**h]hreturns}(hhhjBhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj>ubh }(hjkhj>hhhNhNubj)}(h``0``h]h0}(hhhjThhhNhNubah}(h]h ]h"]h$]h&]uh1jhj>ubh- on success, a negative error code otherwise.}(h- on success, a negative error code otherwise.hj>hhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjpubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j%hid_bpf_hw_output_report (C function)c.hid_bpf_hw_output_reporthNtauh1jhjhhhNhNubj)}(hhh](j)}(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}(hhhjhhhNhNubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj )}(hinth]hint}(hhhjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjhhhjhMubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjhhhjhMubj)}(hhid_bpf_hw_output_reporth]j!)}(hhid_bpf_hw_output_reporth]hhid_bpf_hw_output_report}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjhhhjhMubj( )}(h4(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)h](j. )}(hstruct hid_bpf_ctx *ctxh](j)}(hjh]hstruct}(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubh)}(hhh]j!)}(h hid_bpf_ctxh]h hid_bpf_ctx}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jt )}jg jsbc.hid_bpf_hw_output_reportasbuh1hhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj )}(hj h]h*}(hhhj)hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjubj!)}(hctxh]hctx}(hhhj6hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjubj. )}(h __u8 *bufh](h)}(hhh]j!)}(h__u8h]h__u8}(hhhjRhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjOubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjTmodnameN classnameNjk jn )}jq ]jc.hid_bpf_hw_output_reportasbuh1hhjKubj )}(h h]h }(hhhjphhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjKubj )}(hj h]h*}(hhhj~hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjKubj!)}(hbufh]hbuf}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjKubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjubj. )}(hsize_t buf__szh](h)}(hhh]j!)}(hsize_th]hsize_t}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjmodnameN classnameNjk jn )}jq ]jc.hid_bpf_hw_output_reportasbuh1hhjubj )}(h h]h }(hhhjhhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjubj!)}(hbuf__szh]hbuf__sz}(hhhjhhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hjubeh}(h]h ]h"]h$]h&]hhuh1j' hjhhhjhMubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hjhhhjhMubah}(h]jah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubjL)}(hhh]h)}(h%Send an output report to a HID deviceh]h%Send an output report to a HID device}(hj hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubah}(h]h ]h"]h$]h&]uh1jKhjhhhjhMubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnj joj jpuh1jhhhjhNhNubjr)}(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|)}(hj h]h Parameters}(hhhj" hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./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}(hhhjA hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj= ubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj9 ubj)}(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()}(hjZ hjX hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjT hMhjU ubah}(h]h ]h"]h$]h&]uh1jhj9 ubeh}(h]h ]h"]h$]h&]uh1jhjT hMhj6 ubj)}(h&``__u8 *buf`` a ``PTR_TO_MEM`` buffer h](j)}(h ``__u8 *buf``h]j)}(hjx h]h __u8 *buf}(hhhjz hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjv ubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjr ubj)}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(ha hj hhhNhNubj)}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh buffer}(h bufferhj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj hMhj ubah}(h]h ]h"]h$]h&]uh1jhjr ubeh}(h]h ]h"]h$]h&]uh1jhj hMhj6 ubj)}(h4``size_t buf__sz`` the size of the data to transfer h](j)}(h``size_t buf__sz``h]j)}(hj h]hsize_t buf__sz}(hhhj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj ubj)}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hj hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hMhj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj hMhj6 ubeh}(h]h ]h"]h$]h&]uh1jhj ubh)}(h**Description**h]j|)}(hj!h]h Description}(hhhj!hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj ubh)}(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.}(hj!hj!hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj ubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubj)}(hhh]h}(h]h ]h"]h$]h&]entries](j!hid_bpf_input_report (C function)c.hid_bpf_input_reporthNtauh1jhjhhhNhNubj)}(hhh](j)}(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}(hhhjA!hhhNhNubj )}(h h]h }(hhhjI!hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjA!hhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj )}(hinth]hint}(hhhjX!hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hjA!hhhjW!hMubj )}(h h]h }(hhhjf!hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hjA!hhhjW!hMubj)}(hhid_bpf_input_reporth]j!)}(hhid_bpf_input_reporth]hhid_bpf_input_report}(hhhjx!hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hjt!ubah}(h]h ](j3j4eh"]h$]h&]hhuh1jhjA!hhhjW!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)}(hjh]hstruct}(hhhj!hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj!ubj )}(h h]h }(hhhj!hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj!ubh)}(hhh]j!)}(h hid_bpf_ctxh]h hid_bpf_ctx}(hhhj!hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj!ubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetj!modnameN classnameNjk jn )}jq ]jt )}jg jz!sbc.hid_bpf_input_reportasbuh1hhj!ubj )}(h h]h }(hhhj!hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj!ubj )}(hj h]h*}(hhhj!hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hj!ubj!)}(hctxh]hctx}(hhhj!hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj!ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj!ubj. )}(henum hid_report_type typeh](j)}(hju h]henum}(hhhj"hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj"ubj )}(h h]h }(hhhj"hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj"ubh)}(hhh]j!)}(hhid_report_typeh]hhid_report_type}(hhhj$"hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj!"ubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetj&"modnameN classnameNjk jn )}jq ]j!c.hid_bpf_input_reportasbuh1hhj"ubj )}(h h]h }(hhhjB"hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj"ubj!)}(htypeh]htype}(hhhjP"hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj"ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj!ubj. )}(hu8 *bufh](h)}(hhh]j!)}(hu8h]hu8}(hhhjl"hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hji"ubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetjn"modnameN classnameNjk jn )}jq ]j!c.hid_bpf_input_reportasbuh1hhje"ubj )}(h h]h }(hhhj"hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hje"ubj )}(hj h]h*}(hhhj"hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j hje"ubj!)}(hbufh]hbuf}(hhhj"hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hje"ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj!ubj. )}(hconst size_t buf__szh](j)}(hjh]hconst}(hhhj"hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj"ubj )}(h h]h }(hhhj"hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj"ubh)}(hhh]j!)}(hsize_th]hsize_t}(hhhj"hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj"ubah}(h]h ]h"]h$]h&] refdomainjhreftypejg reftargetj"modnameN classnameNjk jn )}jq ]j!c.hid_bpf_input_reportasbuh1hhj"ubj )}(h h]h }(hhhj"hhhNhNubah}(h]h ]jah"]h$]h&]uh1j hj"ubj!)}(hbuf__szh]hbuf__sz}(hhhj#hhhNhNubah}(h]h ]j,ah"]h$]h&]uh1j hj"ubeh}(h]h ]h"]h$]h&]noemphhhuh1j- hj!ubeh}(h]h ]h"]h$]h&]hhuh1j' hjA!hhhjW!hMubeh}(h]h ]h"]h$]h&]hhj>uh1jj?j@hj=!hhhjW!hMubah}(h]j8!ah ](jDjEeh"]h$]h&]jIuh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chM hj:!hhubjL)}(hhh]h)}(h3Inject a HID report in the kernel from a HID deviceh]h3Inject a HID report in the kernel from a HID device}(hj5#hj3#hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj0#hhubah}(h]h ]h"]h$]h&]uh1jKhj:!hhhjW!hMubeh}(h]h ](jhfunctioneh"]h$]h&]jmjhjnjK#jojK#jpuh1jhhhjhNhNubjr)}(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.h](h)}(h**Parameters**h]j|)}(hjU#h]h Parameters}(hhhjW#hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjS#ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjO#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)}(hjt#h]hstruct hid_bpf_ctx *ctx}(hhhjv#hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjr#ubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjn#ubj)}(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#hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj#hMhj#ubah}(h]h ]h"]h$]h&]uh1jhjn#ubeh}(h]h ]h"]h$]h&]uh1jhj#hMhjk#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}(hhhj#hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj#ubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj#ubj)}(hhh]h)}(h\the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](hthe type of the report (}(hthe type of the report (hj#hhhNhNubj)}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hhhj#hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj#ubh, }(h, hj#hhhNhNubj)}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hhhj#hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj#ubh, }(hj#hj#ubj)}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hhhj#hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj#ubh)}(hjhj#hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj#hMhj#ubah}(h]h ]h"]h$]h&]uh1jhj#ubeh}(h]h ]h"]h$]h&]uh1jhj#hMhjk#ubj)}(h$``u8 *buf`` a ``PTR_TO_MEM`` buffer h](j)}(h ``u8 *buf``h]j)}(hj$h]hu8 *buf}(hhhj $hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj$ubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj$ubj)}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(ha hj7$hhhNhNubj)}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hhhj@$hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj7$ubh buffer}(h bufferhj7$hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj3$hMhj4$ubah}(h]h ]h"]h$]h&]uh1jhj$ubeh}(h]h ]h"]h$]h&]uh1jhj3$hMhjk#ubj)}(h:``const size_t buf__sz`` the size of the data to transfer h](j)}(h``const size_t buf__sz``h]j)}(hjk$h]hconst size_t buf__sz}(hhhjm$hhhNhNubah}(h]h ]h"]h$]h&]uh1jhji$ubah}(h]h ]h"]h$]h&]uh1jh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhje$ubj)}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hj$hj$hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj$hMhj$ubah}(h]h ]h"]h$]h&]uh1jhje$ubeh}(h]h ]h"]h$]h&]uh1jhj$hMhjk#ubeh}(h]h ]h"]h$]h&]uh1jhjO#ubh)}(h**Description**h]j|)}(hj$h]h Description}(hhhj$hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj$ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjO#ubh)}(h:Returns ``0`` on success, a negative error code otherwise.h](hReturns }(hReturns hj$hhhNhNubj)}(h``0``h]h0}(hhhj$hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj$ubh- on success, a negative error code otherwise.}(h- on success, a negative error code otherwise.hj$hhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:181: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjO#ubeh}(h]h ] kernelindentah"]h$]h&]uh1jqhjhhhNhNubeh}(h]jah ]h"];available api that can be used in syscall hid-bpf programs:ah$]h&]uh1hhjhhhhhKubeh}(h]jAah ]h"]developer api:ah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hjh]h%General overview of a HID-BPF program}(hjhj$hhhNhNubah}(h]h ]h"]h$]h&]j juh1hhj$hhhhhKubh)}(hhh](h)}(hjh]h*Accessing the data attached to the context}(hjhj%hhhNhNubah}(h]h ]h"]h$]h&]j juh1hhj%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 }(hThe hj%hhhNhNubj)}(h``struct hid_bpf_ctx``h]hstruct hid_bpf_ctx}(hhhj%hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj%ubh doesn’t export the }(h doesn't export the hj%hhhNhNubj)}(h``data``h]hdata}(hhhj0%hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj%ubhE fields directly and to access it, a bpf program needs to first call }(hE fields directly and to access it, a bpf program needs to first call hj%hhhNhNubh)}(h:c:func:`hid_bpf_get_data`h]j)}(hjE%h]hhid_bpf_get_data()}(hhhjG%hhhNhNubah}(h]h ](jjhc-funceh"]h$]h&]uh1jhjC%ubah}(h]h ]h"]h$]h&]refdocj refdomainjhreftypefunc refexplicitrefwarnj$j%j(hid_bpf_get_datauh1hhhhKhj%ubh.}(hjhj%hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj%hhubh)}(hX``offset`` can be any integer, but ``size`` needs to be constant, known at compile time.h](j)}(h ``offset``h]hoffset}(hhhjp%hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjl%ubh can be any integer, but }(h can be any integer, but hjl%hhhNhNubj)}(h``size``h]hsize}(hhhj%hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjl%ubh- needs to be constant, known at compile time.}(h- needs to be constant, known at compile time.hjl%hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj%hhubh)}(hThis allows the following:h]hThis allows the following:}(hj%hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj%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 }(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}(hhhj%hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj%ubh, pointer to point at the full report length.}(h, 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:}(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]);}(hhhj%ubah}(h]h ]h"]h$]h&]hhuh1jhhhKhj%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 }(h;if the report length is variable, but we know the value of hj%hhhNhNubj)}(h``X``h]hX}(hhhj&hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj%ubhK is always a 16-bit integer, we can then have a pointer to that value only:}(hK is always a 16-bit integer, we can then have a pointer to that value only:hj%hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj%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 */}(hhhj&ubah}(h]h ]h"]h$]h&]hhuh1jhhhKhj%ubeh}(h]h ]h"]h$]h&]uh1hhj%hhhhhNubeh}(h]h ]h"]h$]h&]jjjhjjuh1jhj%hhhhhKubeh}(h]jah ]h"]*accessing the data attached to the contextah$]h&]uh1hhj$hhhhhKubh)}(hhh](h)}(hj3h]hEffect of a HID-BPF program}(hj3hj@&hhhNhNubah}(h]h ]h"]h$]h&]j j6uh1hhj=&hhhhhKubh)}(hFor all HID-BPF attachment types except for :c:func:`hid_bpf_rdesc_fixup`, several eBPF programs can be attached to the same device.h](h,For all HID-BPF attachment types except for }(h,For all HID-BPF attachment types except for hjM&hhhNhNubh)}(h:c:func:`hid_bpf_rdesc_fixup`h]j)}(hjX&h]hhid_bpf_rdesc_fixup()}(hhhjZ&hhhNhNubah}(h]h ](jjhc-funceh"]h$]h&]uh1jhjV&ubah}(h]h ]h"]h$]h&]refdocj refdomainjhreftypefunc refexplicitrefwarnj$j%j(hid_bpf_rdesc_fixupuh1hhhhKhjM&ubh;, several eBPF programs can be attached to the same device.}(h;, several eBPF programs can be attached to the same device.hjM&hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj=&hhubh)}(hX>Unless ``HID_BPF_FLAG_INSERT_HEAD`` is added to the flags while attaching the program, the new program is appended at the end of the list. ``HID_BPF_FLAG_INSERT_HEAD`` 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 }(hUnless hj&hhhNhNubj)}(h``HID_BPF_FLAG_INSERT_HEAD``h]hHID_BPF_FLAG_INSERT_HEAD}(hhhj&hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj&ubhh is added to the flags while attaching the program, the new program is appended at the end of the list. }(hh is added to the flags while attaching the program, the new program is appended at the end of the list. hj&hhhNhNubj)}(h``HID_BPF_FLAG_INSERT_HEAD``h]hHID_BPF_FLAG_INSERT_HEAD}(hhhj&hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj&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.}(h 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&]uh1hhhhKhj=&hhubh)}(hNote that if there are multiple programs using the ``HID_BPF_FLAG_INSERT_HEAD`` flag, only the most recently loaded one is actually the first in the list.h](h3Note that if there are multiple programs using the }(h3Note that if there are multiple programs using the hj&hhhNhNubj)}(h``HID_BPF_FLAG_INSERT_HEAD``h]hHID_BPF_FLAG_INSERT_HEAD}(hhhj&hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj&ubhK flag, only the most recently loaded one is actually the first in the list.}(hK flag, only the most recently loaded one is actually the first in the list.hj&hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj=&hhubh)}(hhh](h)}(h(``SEC("fmod_ret/hid_bpf_device_event")``h]j)}(hj&h]h$SEC("fmod_ret/hid_bpf_device_event")}(hhhj&hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj&ubah}(h]h ]h"]h$]h&]uh1hhj&hhhhhKubh)}(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.}(hj&hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj&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 }(htIf a program changes the data associated with the context, the next one will see the modified data but it will have hj&hhhNhNubj3)}(h*no*h]hno}(hhhj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j2hj&ubh$ idea of what the original data was.}(h$ idea of what the original data was.hj&hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj&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 }(h)Once all the programs are run and return hj!'hhhNhNubj)}(h``0``h]h0}(hhhj*'hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj!'ubhY or a positive value, the rest of the HID stack will work on the modified data, with the }(hY or a positive value, the rest of the HID stack will work on the modified data, with the hj!'hhhNhNubj)}(h``size``h]hsize}(hhhj='hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj!'ubhN field of the last hid_bpf_ctx being the new size of the input stream of data.}(hN field of the last hid_bpf_ctx being the new size of the input stream of data.hj!'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj&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 }(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 hjV'hhhNhNubj|)}(h**not**h]hnot}(hhhj_'hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjV'ubh see this event.}(h see this event.hjV'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj&hhubeh}(h]!sec-fmod-ret-hid-bpf-device-eventah ]h"]$sec("fmod_ret/hid_bpf_device_event")ah$]h&]uh1hhj=&hhhhhKubh)}(hhh](h)}(h``SEC("syscall")``h]j)}(hj'h]hSEC("syscall")}(hhhj'hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj'ubah}(h]h ]h"]h$]h&]uh1hhj'hhhhhKubh)}(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}(hhhj'hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj'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: }(h 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}(hhhj'hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj'ubh).}(h).hj'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj'hhubh)}(hXTo retrieve a context associated with the device, the program must call :c:func:`hid_bpf_allocate_context` and must release it with :c:func:`hid_bpf_release_context` before returning. Once the context is retrieved, one can also request a pointer to kernel memory with :c:func:`hid_bpf_get_data`. This memory is big enough to support all input/output/feature reports of the given device.h](hHTo retrieve a context associated with the device, the program must call }(hHTo retrieve a context associated with the device, the program must call hj'hhhNhNubh)}(h":c:func:`hid_bpf_allocate_context`h]j)}(hj'h]hhid_bpf_allocate_context()}(hhhj'hhhNhNubah}(h]h ](jjhc-funceh"]h$]h&]uh1jhj'ubah}(h]h ]h"]h$]h&]refdocj refdomainjhreftypefunc refexplicitrefwarnj$j%j(hid_bpf_allocate_contextuh1hhhhMhj'ubh and must release it with }(h and must release it with hj'hhhNhNubh)}(h!:c:func:`hid_bpf_release_context`h]j)}(hj'h]hhid_bpf_release_context()}(hhhj'hhhNhNubah}(h]h ](jjhc-funceh"]h$]h&]uh1jhj'ubah}(h]h ]h"]h$]h&]refdocj refdomainjhreftypefunc refexplicitrefwarnj$j%j(hid_bpf_release_contextuh1hhhhMhj'ubhg before returning. Once the context is retrieved, one can also request a pointer to kernel memory with }(hg before returning. Once the context is retrieved, one can also request a pointer to kernel memory with hj'hhhNhNubh)}(h:c:func:`hid_bpf_get_data`h]j)}(hj(h]hhid_bpf_get_data()}(hhhj(hhhNhNubah}(h]h ](jjhc-funceh"]h$]h&]uh1jhj(ubah}(h]h ]h"]h$]h&]refdocj refdomainjhreftypefunc refexplicitrefwarnj$j%j(hid_bpf_get_datauh1hhhhMhj'ubh\. This memory is big enough to support all input/output/feature reports of the given device.}(h\. This memory is big enough to support all input/output/feature reports of the given device.hj'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj'hhubeh}(h] sec-syscallah ]h"]sec("syscall")ah$]h&]uh1hhj=&hhhhhKubh)}(hhh](h)}(h'``SEC("fmod_ret/hid_bpf_rdesc_fixup")``h]j)}(hjR(h]h#SEC("fmod_ret/hid_bpf_rdesc_fixup")}(hhhjT(hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjP(ubah}(h]h ]h"]h$]h&]uh1hhjM(hhhhhM ubh)}(hlThe ``hid_bpf_rdesc_fixup`` program works in a similar manner to ``.report_fixup`` of ``struct hid_driver``.h](hThe }(hThe hjg(hhhNhNubj)}(h``hid_bpf_rdesc_fixup``h]hhid_bpf_rdesc_fixup}(hhhjp(hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjg(ubh& program works in a similar manner to }(h& program works in a similar manner to hjg(hhhNhNubj)}(h``.report_fixup``h]h .report_fixup}(hhhj(hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjg(ubh of }(h of hjg(hhhNhNubj)}(h``struct hid_driver``h]hstruct hid_driver}(hhhj(hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjg(ubh.}(hjhjg(hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhjM(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 }(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}(hhhj(hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj(ubh (currently 4kB).}(h (currently 4kB).hj(hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhjM(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(hj(hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjM(hhubh)}(hWhenever a ``SEC("fmod_ret/hid_bpf_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 }(h Whenever a hj(hhhNhNubj)}(h'``SEC("fmod_ret/hid_bpf_rdesc_fixup")``h]h#SEC("fmod_ret/hid_bpf_rdesc_fixup")}(hhhj(hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj(ubh program is attached (if no program was attached before), the kernel immediately disconnects the HID device and does a reprobe.}(h 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&]uh1hhhhMhjM(hhubh)}(hIn the same way, when the ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` program is detached, the kernel issues a disconnect on the device.h](hIn the same way, when the }(hIn the same way, when the hj)hhhNhNubj)}(h'``SEC("fmod_ret/hid_bpf_rdesc_fixup")``h]h#SEC("fmod_ret/hid_bpf_rdesc_fixup")}(hhhj )hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj)ubhC program is detached, the kernel issues a disconnect on the device.}(hC program is detached, the kernel issues a disconnect on the device.hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhjM(hhubh)}(hXThere is no ``detach`` facility in HID-BPF. Detaching a program happens when all the user space file descriptors pointing at a program 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 program in the bpffs, and we can then replace it through normal bpf operations.h](h There is no }(h There is no hj")hhhNhNubj)}(h ``detach``h]hdetach}(hhhj+)hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj")ubhX facility in HID-BPF. Detaching a program happens when all the user space file descriptors pointing at a program 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 program in the bpffs, and we can then replace it through normal bpf operations.}(hX facility in HID-BPF. Detaching a program happens when all the user space file descriptors pointing at a program 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 program in the bpffs, and we can then replace it through normal bpf operations.hj")hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhjM(hhubeh}(h] sec-fmod-ret-hid-bpf-rdesc-fixupah ]h"]#sec("fmod_ret/hid_bpf_rdesc_fixup")ah$]h&]uh1hhj=&hhhhhM ubeh}(h]j<ah ]h"]effect of a hid-bpf programah$]h&]uh1hhj$hhhhhKubeh}(h]jah ]h"]%general overview of a hid-bpf programah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hjbh]h#Attaching a bpf program to a device}(hjbhj])hhhNhNubah}(h]h ]h"]h$]h&]j jeuh1hhjZ)hhhhhM'ubh)}(h``libbpf`` does not export any helper to attach a HID-BPF program. Users need to use a dedicated ``syscall`` program which will call ``hid_bpf_attach_prog(hid_id, program_fd, flags)``.h](j)}(h ``libbpf``h]hlibbpf}(hhhjn)hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjj)ubhW does not export any helper to attach a HID-BPF program. Users need to use a dedicated }(hW does not export any helper to attach a HID-BPF program. Users need to use a dedicated hjj)hhhNhNubj)}(h ``syscall``h]hsyscall}(hhhj)hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjj)ubh program which will call }(h program which will call hjj)hhhNhNubj)}(h2``hid_bpf_attach_prog(hid_id, program_fd, flags)``h]h.hid_bpf_attach_prog(hid_id, program_fd, flags)}(hhhj)hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjj)ubh.}(hjhjj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM)hjZ)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}(hhhj)hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj)ubhR is the unique system ID of the HID device (the last 4 numbers in the sysfs path: }(hR is the unique system ID of the HID device (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}(hhhj)hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj)ubh)}(hjhj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM-hjZ)hhubh)}(hE``progam_fd`` is the opened file descriptor of the program to attach.h](j)}(h ``progam_fd``h]h progam_fd}(hhhj)hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj)ubh8 is the opened file descriptor of the program to attach.}(h8 is the opened file descriptor of the program to attach.hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM0hjZ)hhubh)}(h3``flags`` is of type ``enum hid_bpf_attach_flags``.h](j)}(h ``flags``h]hflags}(hhhj)hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj)ubh is of type }(h is of type hj)hhhNhNubj)}(h``enum hid_bpf_attach_flags``h]henum hid_bpf_attach_flags}(hhhj*hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj)ubh.}(hjhj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM2hjZ)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)*hj'*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM4hjZ)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 }(hOn the other hand, the hj5*hhhNhNubj)}(h ``hid_id``h]hhid_id}(hhhj>*hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj5*ubhZ is stable for the entire life of the HID device, even if we change its report descriptor.}(hZ is stable for the entire life of the HID device, even if we change its report descriptor.hj5*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM9hjZ)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 }(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 hjW*hhhNhNubj)}(h;``/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor``h]h7/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor}(hhhj`*hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjW*ubh as a binary stream.}(h as a binary stream.hjW*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM<hjZ)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{*hjy*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMAhjZ)hhubeh}(h]jkah ]h"]#attaching a bpf program to a deviceah$]h&]uh1hhhhhhhhM'ubh)}(hhh](h)}(hjh]h9An (almost) complete example of a BPF enhanced HID device}(hjhj*hhhNhNubah}(h]h ]h"]h$]h&]j juh1hhj*hhhhhMEubh)}(hH*Foreword: for most parts, this could be implemented as a kernel driver*h]j3)}(hj*h]hFForeword: for most parts, this could be implemented as a kernel driver}(hhhj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j2hj*ubah}(h]h ]h"]h$]h&]uh1hhhhMGhj*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 }(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*hhhNhNubj3)}(h*pencil on paper*h]hpencil on paper}(hhhj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j2hj*ubh, }(h, hj*hhhNhNubj3)}(h*cray on a wall*h]hcray on a wall}(hhhj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j2hj*ubh and }(h and hj*hhhNhNubj3)}(h*brush on a painting canvas*h]hbrush on a painting canvas}(hhhj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j2hj*ubhj. To make things even better, we can control the physical position of the switch through a feature report.}(hj. 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&]uh1hhhhMIhj*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*hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMOhj*hhubh)}(hhh](h)}(hjh]hFiltering events}(hjhj+hhhNhNubah}(h]h ]h"]h$]h&]j juh1hhj +hhhhhMSubh)}(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+hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMUhj +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++hj)+hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMYhj +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:}(h=For that, we can create a basic skeleton for our BPF program:hj7+hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM\hj +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; extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 4096 * 64); } ringbuf SEC(".maps"); struct attach_prog_args { int prog_fd; unsigned int hid; unsigned int flags; int retval; }; SEC("syscall") int attach_prog(struct attach_prog_args *ctx) { ctx->retval = hid_bpf_attach_prog(ctx->hid, ctx->prog_fd, ctx->flags); return 0; } __u8 current_value = 0; SEC("?fmod_ret/hid_bpf_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; }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; extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 4096 * 64); } ringbuf SEC(".maps"); struct attach_prog_args { int prog_fd; unsigned int hid; unsigned int flags; int retval; }; SEC("syscall") int attach_prog(struct attach_prog_args *ctx) { ctx->retval = hid_bpf_attach_prog(ctx->hid, ctx->prog_fd, ctx->flags); return 0; } __u8 current_value = 0; SEC("?fmod_ret/hid_bpf_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; }}(hhhjF+ubah}(h]h ]h"]h$]h&]hhuh1jhhhM^hj +hhubh)}(h`To attach ``filter_switch``, userspace needs to call the ``attach_prog`` syscall program first::h](h To attach }(h To attach hjT+hhhNhNubj)}(h``filter_switch``h]h filter_switch}(hhhj]+hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjT+ubh, userspace needs to call the }(h, userspace needs to call the hjT+hhhNhNubj)}(h``attach_prog``h]h attach_prog}(hhhjp+hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjT+ubh syscall program first:}(h syscall program first:hjT+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj +hhubj)}(hXdstatic int attach_filter(struct hid *hid_skel, int hid_id) { int err, prog_fd; int ret = -1; struct attach_prog_args args = { .hid = hid_id, }; DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, .ctx_in = &args, .ctx_size_in = sizeof(args), ); args.prog_fd = bpf_program__fd(hid_skel->progs.filter_switch); prog_fd = bpf_program__fd(hid_skel->progs.attach_prog); err = bpf_prog_test_run_opts(prog_fd, &tattrs); if (err) return err; return args.retval; /* the fd of the created bpf_link */ }h]hXdstatic int attach_filter(struct hid *hid_skel, int hid_id) { int err, prog_fd; int ret = -1; struct attach_prog_args args = { .hid = hid_id, }; DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, .ctx_in = &args, .ctx_size_in = sizeof(args), ); args.prog_fd = bpf_program__fd(hid_skel->progs.filter_switch); prog_fd = bpf_program__fd(hid_skel->progs.attach_prog); err = bpf_prog_test_run_opts(prog_fd, &tattrs); if (err) return err; return args.retval; /* the fd of the created bpf_link */ }}(hhhj+ubah}(h]h ]h"]h$]h&]hhuh1jhhhMhj +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.}(hj+hj+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 fd from :c:func:`attach_filter`, which will tell the kernel to detach the program from the HID device.h](hnWhen the userspace program doesn’t need to listen to events anymore, it can just close the returned fd from }(hlWhen the userspace program doesn't need to listen to events anymore, it can just close the returned fd from hj+hhhNhNubh)}(h:c:func:`attach_filter`h]j)}(hj+h]hattach_filter()}(hhhj+hhhNhNubah}(h]h ](jjhc-funceh"]h$]h&]uh1jhj+ubah}(h]h ]h"]h$]h&]refdocj refdomainjhreftypefunc refexplicitrefwarnj$j%j( attach_filteruh1hhhhMhj+ubhG, which will tell the kernel to detach the program from the HID device.}(hG, which will tell the kernel to detach the program from the HID device.hj+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 }(hqOf course, in other use cases, the userspace program can also pin the fd to the BPF filesystem through a call to hj+hhhNhNubh)}(h:c:func:`bpf_obj_pin`h]j)}(hj+h]h bpf_obj_pin()}(hhhj+hhhNhNubah}(h]h ](jjhc-funceh"]h$]h&]uh1jhj+ubah}(h]h ]h"]h$]h&]refdocj refdomainjhreftypefunc refexplicitrefwarnj$j%j( bpf_obj_pinuh1hhhhMhj+ubh, as with any bpf_link.}(h, as with any bpf_link.hj+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj +hhubeh}(h]jah ]h"]filtering eventsah$]h&]uh1hhj*hhhhhMSubh)}(hhh](h)}(hjh]hControlling the device}(hjhj,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$,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 }(h2Instead of using hidraw for that, we can create a hj0,hhhNhNubj)}(h``SEC("syscall")``h]hSEC("syscall")}(hhhj9,hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj0,ubh" program that talks to the device:}(h" program that talks to the device:hj0,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; }}(hhhjR,ubah}(h]h ]h"]h$]h&]hhuh1jhhhMhj,hhubh)}(h8And then userspace needs to call that program directly::h]h7And then userspace needs to call that program directly:}(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; }}(hhhjo,ubah}(h]h ]h"]h$]h&]hhuh1jhhhMhj,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,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,hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj,hhubeh}(h]jah ]h"]controlling the deviceah$]h&]uh1hhj*hhhhhMubeh}(h]jah ]h"]9an (almost) complete example of a bpf enhanced hid deviceah$]h&]uh1hhhhhhhhMEubeh}(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_handlerj,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.confapep_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_spacefile_insertion_enabled raw_enabledKline_length_limitM'syntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_link embed_imagesenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(j,j,jjjhj{jjj@jjcj"jjcjjjjUjjjj$jAj jajjjjj$jjW)jj:&jjP)j<j}'jz'jJ(jG(jI)jF)j*jkj,jj,jj,ju nametypes}(j,NjNjNj{NjNjNj"NjcNjNjUNjNj$Nj NjNjNj$NjW)Nj:&NjP)Nj}'NjJ(NjI)Nj*Nj,Nj,Nj,Nuh}(j,hjhhjjjj@j~jcjjjjj%jjfjjjjXjAjjajjjjf jk jj j j jjjjjjjjjjjjjjjjjjj8!j=!jj$jj%j<j=&jz'j&jG(j'jF)jM(jkjZ)jj*jj +jj,hhjj j:j0j]jSjjvjjjjjjjjj;j1j[jQj~jtjjjjjjjj j6j,jej[jj~jjjju 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.