Ksphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/translations/zh_CN/hid/hid-bpfmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/zh_TW/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/it_IT/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/ja_JP/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/ko_KR/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hPortuguese (Brazilian)}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/pt_BR/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget/translations/sp_SP/hid/hid-bpfmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageEnglishuh1h hh _documenthsourceNlineNubhcomment)}(h SPDX-License-Identifier: GPL-2.0h]h SPDX-License-Identifier: GPL-2.0}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhh9/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf.rsthKubhsection)}(hhh](htitle)}(hHID-BPFh]hHID-BPF}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh paragraph)}(hHID is a standard protocol for input devices but some devices may require custom tweaks, traditionally done with a kernel driver fix. Using the eBPF capabilities instead speeds up development and adds new capabilities to the existing HID interfaces.h]hHID is a standard protocol for input devices but some devices may require custom tweaks, traditionally done with a kernel driver fix. Using the eBPF capabilities instead speeds up development and adds new capabilities to the existing HID interfaces.}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhhhubhtopic)}(hhh]h bullet_list)}(hhh](h list_item)}(hhh](h)}(hhh]h reference)}(hhh]hWhen (and why) to use HID-BPF}(hjhhhNhNubah}(h]id1ah ]h"]h$]h&]refidwhen-and-why-to-use-hid-bpfuh1hhhubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]h)}(hhh]j)}(hhh]hDead zone of a joystick}(hj hhhNhNubah}(h]id2ah ]h"]h$]h&]refiddead-zone-of-a-joystickuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]j)}(hhh]h!Simple fixup of report descriptor}(hjBhhhNhNubah}(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]j)}(hhh]h0Add a new feature that requires a new kernel API}(hjdhhhNhNubah}(h]id4ah ]h"]h$]h&]refid0add-a-new-feature-that-requires-a-new-kernel-apiuh1hhjaubah}(h]h ]h"]h$]h&]uh1hhj^ubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]j)}(hhh]hBMorph a device into something else and control that from userspace}(hjhhhNhNubah}(h]id5ah ]h"]h$]h&]refidBmorph-a-device-into-something-else-and-control-that-from-userspaceuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]j)}(hhh]hFirewall}(hjhhhNhNubah}(h]id6ah ]h"]h$]h&]refidfirewalluh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]j)}(hhh]hTracing}(hjhhhNhNubah}(h]id7ah ]h"]h$]h&]refidtracinguh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh]h)}(hhh]j)}(hhh]hHigh-level view of HID-BPF}(hjhhhNhNubah}(h]id8ah ]h"]h$]h&]refidhigh-level-view-of-hid-bpfuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh]h)}(hhh]j)}(hhh](hIn-tree HID-BPF programs and }(hjhhhNhNubhliteral)}(h``udev-hid-bpf``h]h udev-hid-bpf}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hNhNhjubeh}(h]id9ah ]h"]h$]h&]refid)in-tree-hid-bpf-programs-and-udev-hid-bpfuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh]h)}(hhh]j)}(hhh]hAvailable types of programs}(hjLhhhNhNubah}(h]id10ah ]h"]h$]h&]refidavailable-types-of-programsuh1hhjIubah}(h]h ]h"]h$]h&]uh1hhjFubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]j)}(hhh]hDeveloper API:}(hjnhhhNhNubah}(h]id11ah ]h"]h$]h&]refid developer-apiuh1hhjkubah}(h]h ]h"]h$]h&]uh1hhjhubh)}(hhh](h)}(hhh]h)}(hhh]j)}(hhh](h Available }(hjhhhNhNubj")}(h``struct_ops``h]h struct_ops}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hNhNhjubh for HID-BPF:}(hjhhhNhNubeh}(h]id12ah ]h"]h$]h&]refid available-struct-ops-for-hid-bpfuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]j)}(hhh]h/User API data structures available in programs:}(hjhhhNhNubah}(h]id13ah ]h"]h$]h&]refid.user-api-data-structures-available-in-programsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]j)}(hhh]hBAvailable API that can be used in all HID-BPF struct_ops programs:}(hjhhhNhNubah}(h]id14ah ]h"]h$]h&]refidAavailable-api-that-can-be-used-in-all-hid-bpf-struct-ops-programsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]j)}(hhh]hgAvailable API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs:}(hjhhhNhNubah}(h]id15ah ]h"]h$]h&]refidfavailable-api-that-can-be-used-in-syscall-hid-bpf-programs-or-in-sleepable-hid-bpf-struct-ops-programsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhjhubeh}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]j)}(hhh]h%General overview of a HID-BPF program}(hj3hhhNhNubah}(h]id16ah ]h"]h$]h&]refid%general-overview-of-a-hid-bpf-programuh1hhj0ubah}(h]h ]h"]h$]h&]uh1hhj-ubh)}(hhh](h)}(hhh]h)}(hhh]j)}(hhh]h*Accessing the data attached to the context}(hjRhhhNhNubah}(h]id17ah ]h"]h$]h&]refid*accessing-the-data-attached-to-the-contextuh1hhjOubah}(h]h ]h"]h$]h&]uh1hhjLubah}(h]h ]h"]h$]h&]uh1hhjIubh)}(hhh]h)}(hhh]j)}(hhh]hEffect of a HID-BPF program}(hjthhhNhNubah}(h]id18ah ]h"]h$]h&]refideffect-of-a-hid-bpf-programuh1hhjqubah}(h]h ]h"]h$]h&]uh1hhjnubah}(h]h ]h"]h$]h&]uh1hhjIubeh}(h]h ]h"]h$]h&]uh1hhj-ubeh}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh]h)}(hhh]j)}(hhh]h#Attaching a bpf program to a device}(hjhhhNhNubah}(h]id19ah ]h"]h$]h&]refid#attaching-a-bpf-program-to-a-deviceuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhhubh)}(hhh](h)}(hhh]j)}(hhh]h9An (almost) complete example of a BPF enhanced HID device}(hjhhhNhNubah}(h]id20ah ]h"]h$]h&]refid7an-almost-complete-example-of-a-bpf-enhanced-hid-deviceuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh](h)}(hhh]h)}(hhh]j)}(hhh]hFiltering events}(hjhhhNhNubah}(h]id21ah ]h"]h$]h&]refidfiltering-eventsuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubh)}(hhh]h)}(hhh]j)}(hhh]hControlling the device}(hjhhhNhNubah}(h]id22ah ]h"]h$]h&]refidcontrolling-the-deviceuh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhNhNubah}(h]contentsah ](contentslocaleh"]contentsah$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(hWhen (and why) to use HID-BPFh]hWhen (and why) to use HID-BPF}(hj@hhhNhNubah}(h]h ]h"]h$]h&]refidj uh1hhj=hhhhhKubh)}(hYThere are several use cases when using HID-BPF is better than standard kernel driver fix:h]hYThere are several use cases when using HID-BPF is better than standard kernel driver fix:}(hjOhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj=hhubh)}(hhh](h)}(hDead zone of a joystickh]hDead zone of a joystick}(hj`hhhNhNubah}(h]h ]h"]h$]h&]jNj)uh1hhj]hhhhhKubh)}(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 }(hjnhhhNhNubhemphasis)}(h *dead zone*h]h dead zone}(hjxhhhNhNubah}(h]h ]h"]h$]h&]uh1jvhjnubh for this specific axis.}(hjnhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj]hhubh)}(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.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj]hhubh)}(hXOf course, given that this dead zone is specific to an individual device, we can not create a generic fix for all of the same joysticks. Adding a custom kernel API for this (e.g. by adding a sysfs entry) does not guarantee this new kernel API will be broadly adopted and maintained.h]hXOf course, given that this dead zone is specific to an individual device, we can not create a generic fix for all of the same joysticks. Adding a custom kernel API for this (e.g. by adding a sysfs entry) does not guarantee this new kernel API will be broadly adopted and maintained.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK!hj]hhubh)}(hzHID-BPF allows the userspace program to load the program itself, ensuring we only load the custom API when we have a user.h]hzHID-BPF allows the userspace program to load the program itself, ensuring we only load the custom API when we have a user.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK&hj]hhubeh}(h]j/ah ]h"]dead zone of a joystickah$]h&]uh1hhj=hhhhhKubh)}(hhh](h)}(h!Simple fixup of report descriptorh]h!Simple fixup of report descriptor}(hjhhhNhNubah}(h]h ]h"]h$]h&]jNjKuh1hhjhhhhhK*ubh)}(hIn the HID tree, half of the drivers only fix one key or one byte in the report descriptor. These fixes all require a kernel patch and the subsequent shepherding into a release, a long and painful process for users.h]hIn the HID tree, half of the drivers only fix one key or one byte in the report descriptor. These fixes all require a kernel patch and the subsequent shepherding into a release, a long and painful process for users.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK,hjhhubh)}(hXWe can reduce this burden by providing an eBPF program instead. Once such a program has been verified by the user, we can embed the source code into the kernel tree and ship the eBPF program and load it directly instead of loading a specific kernel module for it.h]hXWe can reduce this burden by providing an eBPF program instead. Once such a program has been verified by the user, we can embed the source code into the kernel tree and ship the eBPF program and load it directly instead of loading a specific kernel module for it.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK0hjhhubh)}(hbNote: distribution of eBPF programs and their inclusion in the kernel is not yet fully implementedh]hbNote: distribution of eBPF programs and their inclusion in the kernel is not yet fully implemented}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK5hjhhubeh}(h]jQah ]h"]!simple fixup of report descriptorah$]h&]uh1hhj=hhhhhK*ubh)}(hhh](h)}(h0Add a new feature that requires a new kernel APIh]h0Add a new feature that requires a new kernel API}(hjhhhNhNubah}(h]h ]h"]h$]h&]jNjmuh1hhjhhhhhK9ubh)}(hXAn example for such a feature are the Universal Stylus Interface (USI) pens. Basically, USI pens require a new kernel API because there are new channels of communication that our HID and input stack do not support. Instead of using hidraw or creating new sysfs entries or ioctls, we can rely on eBPF to have the kernel API controlled by the consumer and to not impact the performances by waking up userspace every time there is an event.h]hXAn example for such a feature are the Universal Stylus Interface (USI) pens. Basically, USI pens require a new kernel API because there are new channels of communication that our HID and input stack do not support. Instead of using hidraw or creating new sysfs entries or ioctls, we can rely on eBPF to have the kernel API controlled by the consumer and to not impact the performances by waking up userspace every time there is an event.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK;hjhhubeh}(h]jsah ]h"]0add a new feature that requires a new kernel apiah$]h&]uh1hhj=hhhhhK9ubh)}(hhh](h)}(hBMorph a device into something else and control that from userspaceh]hBMorph a device into something else and control that from userspace}(hj,hhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhj)hhhhhKDubh)}(hX The kernel has a relatively static mapping of HID items to evdev bits. It cannot decide to dynamically transform a given device into something else as it does not have the required context and any such transformation cannot be undone (or even discovered) by userspace.h]hX The kernel has a relatively static mapping of HID items to evdev bits. It cannot decide to dynamically transform a given device into something else as it does not have the required context and any such transformation cannot be undone (or even discovered) by userspace.}(hj:hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKFhj)hhubh)}(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.}(hjHhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKKhj)hhubh)}(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.}(hjVhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKOhj)hhubeh}(h]jah ]h"]Bmorph a device into something else and control that from userspaceah$]h&]uh1hhj=hhhhhKDubh)}(hhh](h)}(hFirewallh]hFirewall}(hjnhhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhjkhhhhhKWubh)}(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)}(hj|hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKYhjkhhubh)}(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.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK\hjkhhubh)}(hThis also allows to sync the state between the userspace and the kernel/bpf program because we can intercept any incoming command.h]hThis also allows to sync the state between the userspace and the kernel/bpf program because we can intercept any incoming command.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK_hjkhhubeh}(h]jah ]h"]firewallah$]h&]uh1hhj=hhhhhKWubh)}(hhh](h)}(hTracingh]hTracing}(hjhhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhjhhhhhKcubh)}(hbThe last usage is tracing events and all the fun we can do we BPF to summarize and analyze events.h]hbThe last usage is tracing events and all the fun we can do we BPF to summarize and analyze events.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKehjhhubh)}(hQRight now, tracing relies on hidraw. It works well except for a couple of issues:h]hQRight now, tracing relies on hidraw. It works well except for a couple of issues:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhjhhubhenumerated_list)}(hhh](h)}(hif the driver doesn't export a hidraw node, we can't trace anything (eBPF will be a "god-mode" there, so this may raise some eyebrows)h]h)}(hif the driver doesn't export a hidraw node, we can't trace anything (eBPF will be a "god-mode" there, so this may raise some eyebrows)h]hif the driver doesn’t export a hidraw node, we can’t trace anything (eBPF will be a “god-mode” there, so this may raise some eyebrows)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKkhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubh)}(hhidraw doesn't catch other processes' requests to the device, which means that we have cases where we need to add printks to the kernel to understand what is happening. h]h)}(hhidraw doesn't catch other processes' requests to the device, which means that we have cases where we need to add printks to the kernel to understand what is happening.h]hhidraw doesn’t catch other processes’ requests to the device, which means that we have cases where we need to add printks to the kernel to understand what is happening.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKmhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubeh}(h]h ]h"]h$]h&]enumtypearabicprefixhsuffix.uh1jhjhhhhhKkubeh}(h]jah ]h"]tracingah$]h&]uh1hhj=hhhhhKcubeh}(h]jah ]h"]when (and why) to use hid-bpfah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hHigh-level view of HID-BPFh]hHigh-level view of HID-BPF}(hj+hhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhj(hhhhhKrubh)}(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.}(hj9hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKthj(hhubh)}(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 }(hjGhhhNhNubj")}(h``0``h]h0}(hjOhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjGubh# needs to be computed by userspace.}(hjGhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKyhj(hhubh)}(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. }(hjghhhNhNubjw)}(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}(hjohhhNhNubah}(h]h ]h"]h$]h&]uh1jvhjgubh.}(hjghhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK|hj(hhubh)}(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.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj(hhubeh}(h]jah ]h"]high-level view of hid-bpfah$]h&]uh1hhhhhhhhKrubh)}(hhh](h)}(h-In-tree HID-BPF programs and ``udev-hid-bpf``h](hIn-tree HID-BPF programs and }(hjhhhNhNubj")}(hj%h]h udev-hid-bpf}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubeh}(h]h ]h"]h$]h&]jNj3uh1hhjhhhhhKubh)}(hOfficial device fixes are shipped in the kernel tree as source in the ``drivers/hid/bpf/progs`` directory. This allows to add selftests to them in ``tools/testing/selftests/hid``.h](hFOfficial device fixes are shipped in the kernel tree as source in the }(hjhhhNhNubj")}(h``drivers/hid/bpf/progs``h]hdrivers/hid/bpf/progs}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh4 directory. This allows to add selftests to them in }(hjhhhNhNubj")}(h``tools/testing/selftests/hid``h]htools/testing/selftests/hid}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hHowever, the compilation of these objects is not part of a regular kernel compilation given that they need an external tool to be loaded. This tool is currently `udev-hid-bpf `_.h](hHowever, the compilation of these objects is not part of a regular kernel compilation given that they need an external tool to be loaded. This tool is currently }(hjhhhNhNubj)}(hP`udev-hid-bpf `_h]h udev-hid-bpf}(hjhhhNhNubah}(h]h ]h"]h$]h&]name udev-hid-bpfrefuri>https://libevdev.pages.freedesktop.org/udev-hid-bpf/index.htmluh1hhjubhtarget)}(hA h]h}(h] udev-hid-bpfah ]h"] udev-hid-bpfah$]h&]refurijuh1j referencedKhjubh.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hX|For convenience, that external repository duplicates the files from here in ``drivers/hid/bpf/progs`` into its own ``src/bpf/stable`` directory. This allows distributions to not have to pull the entire kernel source tree to ship and package those HID-BPF fixes. ``udev-hid-bpf`` also has capabilities of handling multiple objects files depending on the kernel the user is running.h](hLFor convenience, that external repository duplicates the files from here in }(hj hhhNhNubj")}(h``drivers/hid/bpf/progs``h]hdrivers/hid/bpf/progs}(hj(hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh into its own }(hj hhhNhNubj")}(h``src/bpf/stable``h]hsrc/bpf/stable}(hj:hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh directory. This allows distributions to not have to pull the entire kernel source tree to ship and package those HID-BPF fixes. }(hj hhhNhNubj")}(h``udev-hid-bpf``h]h udev-hid-bpf}(hjLhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubhf also has capabilities of handling multiple objects files depending on the kernel the user is running.}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]j9ah ]h"])in-tree hid-bpf programs and udev-hid-bpfah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hAvailable types of programsh]hAvailable types of programs}(hjnhhhNhNubah}(h]h ]h"]h$]h&]jNjUuh1hhjkhhhhhKubh)}(hdHID-BPF is built "on top" of BPF, meaning that we use bpf struct_ops method to declare our programs.h]hhHID-BPF is built “on top” of BPF, meaning that we use bpf struct_ops method to declare our programs.}(hj|hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjkhhubh)}(h5HID-BPF has the following attachment types available:h]h5HID-BPF has the following attachment types available:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjkhhubj)}(hhh](h)}(hPevent processing/filtering with ``SEC("struct_ops/hid_device_event")`` in libbpfh]h)}(hjh](h event processing/filtering with }(hjhhhNhNubj")}(h&``SEC("struct_ops/hid_device_event")``h]h"SEC("struct_ops/hid_device_event")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh in libbpf}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubh)}(h?actions coming from userspace with ``SEC("syscall")`` in libbpfh]h)}(hjh](h#actions coming from userspace with }(hjhhhNhNubj")}(h``SEC("syscall")``h]hSEC("syscall")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh in libbpf}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubh)}(hchange of the report descriptor with ``SEC("struct_ops/hid_rdesc_fixup")`` or ``SEC("struct_ops.s/hid_rdesc_fixup")`` in libbpf h]h)}(hchange of the report descriptor with ``SEC("struct_ops/hid_rdesc_fixup")`` or ``SEC("struct_ops.s/hid_rdesc_fixup")`` in libbpfh](h%change of the report descriptor with }(hjhhhNhNubj")}(h%``SEC("struct_ops/hid_rdesc_fixup")``h]h!SEC("struct_ops/hid_rdesc_fixup")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh or }(hjhhhNhNubj")}(h'``SEC("struct_ops.s/hid_rdesc_fixup")``h]h#SEC("struct_ops.s/hid_rdesc_fixup")}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh in libbpf}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubeh}(h]h ]h"]h$]h&]jjjhjjuh1jhjkhhhhhKubh)}(hA ``hid_device_event`` is calling a BPF program when an event is received from the device. Thus we are in IRQ context and can act on the data or notify userspace. And given that we are in IRQ context, we can not talk back to the device.h](hA }(hj/hhhNhNubj")}(h``hid_device_event``h]hhid_device_event}(hj7hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj/ubh 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.}(hj/hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjkhhubh)}(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 }(hjOhhhNhNubj")}(h ``syscall``h]hsyscall}(hjWhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjOubh) means that userspace called the syscall }(hjOhhhNhNubj")}(h``BPF_PROG_RUN``h]h BPF_PROG_RUN}(hjihhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjOubhh facility. This time, we can do any operations allowed by HID-BPF, and talking to the device is allowed.}(hjOhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjkhhubh)}(hXLast, ``hid_rdesc_fixup`` is different from the others as there can be only one BPF program of this type. This is called on ``probe`` from the driver and allows to change the report descriptor from the BPF program. Once a ``hid_rdesc_fixup`` program has been loaded, it is not possible to overwrite it unless the program which inserted it allows us by pinning the program and closing all of its fds pointing to it.h](hLast, }(hjhhhNhNubj")}(h``hid_rdesc_fixup``h]hhid_rdesc_fixup}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubhc is different from the others as there can be only one BPF program of this type. This is called on }(hjhhhNhNubj")}(h ``probe``h]hprobe}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubhY from the driver and allows to change the report descriptor from the BPF program. Once a }(hjhhhNhNubj")}(h``hid_rdesc_fixup``h]hhid_rdesc_fixup}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh 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.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjkhhubh)}(heNote that ``hid_rdesc_fixup`` can be declared as sleepable (``SEC("struct_ops.s/hid_rdesc_fixup")``).h](h Note that }(hjhhhNhNubj")}(h``hid_rdesc_fixup``h]hhid_rdesc_fixup}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh can be declared as sleepable (}(hjhhhNhNubj")}(h'``SEC("struct_ops.s/hid_rdesc_fixup")``h]h#SEC("struct_ops.s/hid_rdesc_fixup")}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh).}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjkhhubeh}(h]j[ah ]h"]available types of programsah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hDeveloper API:h]hDeveloper API:}(hj hhhNhNubah}(h]h ]h"]h$]h&]jNjwuh1hhjhhhhhKubh)}(hhh](h)}(h%Available ``struct_ops`` for HID-BPF:h](h Available }(hj hhhNhNubj")}(hjh]h struct_ops}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh for HID-BPF:}(hj hhhNhNubeh}(h]h ]h"]h$]h&]jNjuh1hhj hhhhhKubhindex)}(hhh]h}(h]h ]h"]h$]h&]entries](singlehid_bpf_ops (C struct) c.hid_bpf_opshNtauh1j1 hj hhhNhNubhdesc)}(hhh](hdesc_signature)}(h hid_bpf_opsh]hdesc_signature_line)}(hstruct hid_bpf_opsh](hdesc_sig_keyword)}(hstructh]hstruct}(hjU hhhNhNubah}(h]h ]kah"]h$]h&]uh1jS hjO hhhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKubhdesc_sig_space)}(h h]h }(hjg hhhNhNubah}(h]h ]wah"]h$]h&]uh1je hjO hhhjd hKubh desc_name)}(h hid_bpf_opsh]h desc_sig_name)}(hjK h]h hid_bpf_ops}(hj~ hhhNhNubah}(h]h ]nah"]h$]h&]uh1j| hjx ubah}(h]h ](sig-namedescnameeh"]h$]h&]hhuh1jv hjO hhhjd hKubeh}(h]h ]h"]h$]h&]hhƌ add_permalinkuh1jM sphinx_line_type declaratorhjI hhhjd hKubah}(h]j@ ah ](sig sig-objecteh"]h$]h&] is_multiline _toc_parts) _toc_namehuh1jG hjd hKhjD hhubh desc_content)}(hhh]h)}(hQA BPF struct_ops of callbacks allowing to attach HID-BPF programs to a HID deviceh]hQA BPF struct_ops of callbacks allowing to attach HID-BPF programs to a HID device}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKThj hhubah}(h]h ]h"]h$]h&]uh1j hjD hhhjd hKubeh}(h]h ](cstructeh"]h$]h&]domainj objtypej desctypej noindex noindexentrynocontentsentryuh1jB hhhj hNhNubh container)}(hX **Definition**:: struct hid_bpf_ops { int hid_id; u32 flags; int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, u64 source); int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum, enum hid_report_type rtype, enum hid_class_request reqtype, u64 source); int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source); }; **Members** ``hid_id`` the HID uniq ID to attach to. This is writeable before ``load()``, and cannot be changed after ``flags`` flags used while attaching the struct_ops to the device. Currently only available value is ``0`` or ``BPF_F_BEFORE``. Writeable only before ``load()`` ``hid_device_event`` called whenever an event is coming in from the device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` Return: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this event Context: Interrupt context. ``hid_rdesc_fixup`` called when the probe function parses the report descriptor of the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` Return: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this device ``hid_hw_request`` called whenever a hid_hw_raw_request() call is emitted on the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` ``reportnum``: the report number, as in hid_hw_raw_request() ``rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``reqtype``: the request ``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``. Return: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes returned in the incoming buffer; a negative error code interrupts the processing of this call. ``hid_hw_output_report`` called whenever a hid_hw_output_report() call is emitted on the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` ``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``. Return: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes written to the device; a negative error code interrupts the processing of this call.h](h)}(h**Definition**::h](hstrong)}(h**Definition**h]h Definition}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh:}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKXhj ubh literal_block)}(hXstruct hid_bpf_ops { int hid_id; u32 flags; int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, u64 source); int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum, enum hid_report_type rtype, enum hid_class_request reqtype, u64 source); int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source); };h]hXstruct hid_bpf_ops { int hid_id; u32 flags; int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, u64 source); int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum, enum hid_report_type rtype, enum hid_class_request reqtype, u64 source); int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source); };}hj sbah}(h]h ]h"]h$]h&]hhuh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKZhj ubh)}(h **Members**h]j )}(hj h]hMembers}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKchj ubhdefinition_list)}(hhh](hdefinition_list_item)}(hj``hid_id`` the HID uniq ID to attach to. This is writeable before ``load()``, and cannot be changed after h](hterm)}(h ``hid_id``h]j")}(hj- h]hhid_id}(hj/ hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj+ ubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKXhj% ubh definition)}(hhh]h)}(h^the HID uniq ID to attach to. This is writeable before ``load()``, and cannot be changed afterh](h7the HID uniq ID to attach to. This is writeable before }(hjH hhhNhNubj")}(h ``load()``h]hload()}(hjP hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjH ubh, and cannot be changed after}(hjH hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKWhjE ubah}(h]h ]h"]h$]h&]uh1jC hj% ubeh}(h]h ]h"]h$]h&]uh1j# hjB hKXhj ubj$ )}(h``flags`` flags used while attaching the struct_ops to the device. Currently only available value is ``0`` or ``BPF_F_BEFORE``. Writeable only before ``load()`` h](j* )}(h ``flags``h]j")}(hj{ h]hflags}(hj} hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjy ubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhK[hju ubjD )}(hhh]h)}(hflags used while attaching the struct_ops to the device. Currently only available value is ``0`` or ``BPF_F_BEFORE``. Writeable only before ``load()``h](h[flags used while attaching the struct_ops to the device. Currently only available value is }(hj hhhNhNubj")}(h``0``h]h0}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh or }(hj hhhNhNubj")}(h``BPF_F_BEFORE``h]h BPF_F_BEFORE}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh. Writeable only before }(hj hhhNhNubj")}(h ``load()``h]hload()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKYhj ubah}(h]h ]h"]h$]h&]uh1jC hju ubeh}(h]h ]h"]h$]h&]uh1j# hj hK[hj ubj$ )}(hXy``hid_device_event`` called whenever an event is coming in from the device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` Return: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this event Context: Interrupt context. h](j* )}(h``hid_device_event``h]j")}(hj h]hhid_device_event}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKthj ubjD )}(hhh](h)}(h5called whenever an event is coming in from the deviceh]h5called whenever an event is coming in from the device}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKjhj ubh)}(hIt has the following arguments:h]hIt has the following arguments:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKlhj ubh)}(hJ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx `h](j")}(h``ctx``h]hctx}(hj" hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh: The HID-BPF context as }(hj hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j")}(hj6 h]hstruct hid_bpf_ctx}(hj8 hhhNhNubah}(h]h ](xrefj c-typeeh"]h$]h&]uh1j!hj4 ubah}(h]h ]h"]h$]h&]refdoc hid/hid-bpf refdomainj reftypetype refexplicitrefwarn c:parent_keysphinx.domains.c LookupKey)}data]sb reftarget hid_bpf_ctxuh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKnhj ubeh}(h]h ]h"]h$]h&]uh1hhj^ hKnhj ubh)}(hReturn: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this eventh](hReturn: }(hje hhhNhNubj")}(h``0``h]h0}(hjm hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hje ubh on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this event}(hje hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKphj ubh)}(hContext: Interrupt context.h]hContext: Interrupt context.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hKthj ubeh}(h]h ]h"]h$]h&]uh1jC hj ubeh}(h]h ]h"]h$]h&]uh1j# hj hKthj ubj$ )}(hXt``hid_rdesc_fixup`` called when the probe function parses the report descriptor of the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` Return: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this device h](j* )}(h``hid_rdesc_fixup``h]j")}(hj h]hhid_rdesc_fixup}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubjD )}(hhh](h)}(hMcalled when the probe function parses the report descriptor of the HID deviceh]hMcalled when the probe function parses the report descriptor of the HID device}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKzhj ubh)}(hIt has the following arguments:h]hIt has the following arguments:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhK}hj ubh)}(hJ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx `h](j")}(h``ctx``h]hctx}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh: The HID-BPF context as }(hj hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j")}(hj h]hstruct hid_bpf_ctx}(hj hhhNhNubah}(h]h ](jB j c-typeeh"]h$]h&]uh1j!hj ubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypetype refexplicitrefwarnjT jX j\ hid_bpf_ctxuh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1hhj hKhj ubh)}(hReturn: ``0`` on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this deviceh](hReturn: }(hj hhhNhNubj")}(h``0``h]h0}(hj! hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh on success and keep processing; a positive value to change the incoming size buffer; a negative error code to interrupt the processing of this device}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1jC hj ubeh}(h]h ]h"]h$]h&]uh1j# hj hKhj ubj$ )}(hXG``hid_hw_request`` called whenever a hid_hw_raw_request() call is emitted on the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` ``reportnum``: the report number, as in hid_hw_raw_request() ``rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``reqtype``: the request ``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``. Return: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes returned in the incoming buffer; a negative error code interrupts the processing of this call. h](j* )}(h``hid_hw_request``h]j")}(hjL h]hhid_hw_request}(hjN hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjJ ubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjF ubjD )}(hhh](h)}(hHcalled whenever a hid_hw_raw_request() call is emitted on the HID deviceh]hHcalled whenever a hid_hw_raw_request() call is emitted on the HID device}(hje hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjb ubh)}(hIt has the following arguments:h]hIt has the following arguments:}(hjt hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjb ubh)}(hJ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx `h](j")}(h``ctx``h]hctx}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh: The HID-BPF context as }(hj hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j")}(hj h]hstruct hid_bpf_ctx}(hj hhhNhNubah}(h]h ](jB j c-typeeh"]h$]h&]uh1j!hj ubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypetype refexplicitrefwarnjT jX j\ hid_bpf_ctxuh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1hhj hKhjb ubh)}(h<``reportnum``: the report number, as in hid_hw_raw_request()h](j")}(h ``reportnum``h]h reportnum}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh/: the report number, as in hid_hw_raw_request()}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjb ubh)}(h```rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](j")}(h ``rtype``h]hrtype}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh: the report type (}(hj hhhNhNubj")}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh, }(hj hhhNhNubj")}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh, }(hj hhhNhNubj")}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh)}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjb ubh)}(h``reqtype``: the requesth](j")}(h ``reqtype``h]hreqtype}(hj3 hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj/ ubh : the request}(hj/ hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjb ubh)}(h``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``.h](j")}(h ``source``h]hsource}(hjP hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjL ubh8: a u64 referring to a uniq but identifiable source. If }(hjL hhhNhNubj")}(h``0``h]h0}(hjb hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjL ubh3, the kernel itself emitted that call. For hidraw, }(hjL hhhNhNubj")}(h ``source``h]hsource}(hjt hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjL ubh is set to the associated }(hjL hhhNhNubj")}(h``struct file *``h]h struct file *}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjL ubh.}(hjL hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjb ubh)}(hXReturn: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes returned in the incoming buffer; a negative error code interrupts the processing of this call.h](hReturn: }(hj hhhNhNubj")}(h``0``h]h0}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubhX to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes returned in the incoming buffer; a negative error code interrupts the processing of this call.}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhjb ubeh}(h]h ]h"]h$]h&]uh1jC hjF ubeh}(h]h ]h"]h$]h&]uh1j# hja hKhj ubj$ )}(hX``hid_hw_output_report`` called whenever a hid_hw_output_report() call is emitted on the HID device It has the following arguments: ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx ` ``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``. Return: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes written to the device; a negative error code interrupts the processing of this call.h](j* )}(h``hid_hw_output_report``h]j")}(hj h]hhid_hw_output_report}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubjD )}(hhh](h)}(hJcalled whenever a hid_hw_output_report() call is emitted on the HID deviceh]hJcalled whenever a hid_hw_output_report() call is emitted on the HID device}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubh)}(hIt has the following arguments:h]hIt has the following arguments:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubh)}(hJ``ctx``: The HID-BPF context as :c:type:`struct hid_bpf_ctx `h](j")}(h``ctx``h]hctx}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubh: The HID-BPF context as }(hj hhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j")}(hj!h]hstruct hid_bpf_ctx}(hj#hhhNhNubah}(h]h ](jB j c-typeeh"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypetype refexplicitrefwarnjT jX j\ hid_bpf_ctxuh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1hhj>hKhj ubh)}(h``source``: a u64 referring to a uniq but identifiable source. If ``0``, the kernel itself emitted that call. For hidraw, ``source`` is set to the associated ``struct file *``.h](j")}(h ``source``h]hsource}(hjIhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjEubh8: a u64 referring to a uniq but identifiable source. If }(hjEhhhNhNubj")}(h``0``h]h0}(hj[hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjEubh3, the kernel itself emitted that call. For hidraw, }(hjEhhhNhNubj")}(h ``source``h]hsource}(hjmhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjEubh is set to the associated }(hjEhhhNhNubj")}(h``struct file *``h]h struct file *}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjEubh.}(hjEhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubh)}(hXReturn: ``0`` to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes written to the device; a negative error code interrupts the processing of this call.h](hReturn: }(hjhhhNhNubj")}(h``0``h]h0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh to keep processing the request by hid-core; any other value stops hid-core from processing that event. A positive value should be returned with the number of bytes written to the device; a negative error code interrupts the processing of this call.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:185: ./include/linux/hid_bpf.hhKhj ubeh}(h]h ]h"]h$]h&]uh1jC hj ubeh}(h]h ]h"]h$]h&]uh1j# hj hKhj ubeh}(h]h ]h"]h$]h&]uh1j hj ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hj hhhNhNubeh}(h]jah ]h"]!available struct_ops for hid-bpf:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(h/User API data structures available in programs:h]h/User API data structures available in programs:}(hjhhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhjhhhhhKubj2 )}(hhh]h}(h]h ]h"]h$]h&]entries](j> hid_bpf_ctx (C struct) c.hid_bpf_ctxhNtauh1j1 hjhhhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhNubjC )}(hhh](jH )}(h hid_bpf_ctxh]jN )}(hstruct hid_bpf_ctxh](jT )}(hjW h]hstruct}(hjhhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjhhhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjhhhjhKubjw )}(h hid_bpf_ctxh]j} )}(hjh]h hid_bpf_ctx}(hj$hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj ubah}(h]h ](j j eh"]h$]h&]hhuh1jv hjhhhjhKubeh}(h]h ]h"]h$]h&]hhj uh1jM j j hjhhhjhKubah}(h]jah ](j j eh"]h$]h&]j j )j huh1jG hjhKhjhhubj )}(hhh]h)}(h)User accessible data for all HID programsh]h)User accessible data for all HID programs}(hjFhhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjChhubah}(h]h ]h"]h$]h&]uh1j hjhhhjhKubeh}(h]h ](j structeh"]h$]h&]j j j j^j j^j j j uh1jB hhhjhjhNubj )}(hX**Definition**:: struct hid_bpf_ctx { struct hid_device *hid; __u32 allocated_size; union { __s32 retval; __s32 size; }; }; **Members** ``hid`` the :c:type:`struct hid_device ` representing the device itself ``allocated_size`` Allocated size of data. ``{unnamed_union}`` anonymous ``retval`` Return value of the previous program. ``size`` Valid data in the data field.h](h)}(h**Definition**::h](j )}(h**Definition**h]h Definition}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjfubh:}(hjfhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjbubj )}(hstruct hid_bpf_ctx { struct hid_device *hid; __u32 allocated_size; union { __s32 retval; __s32 size; }; };h]hstruct hid_bpf_ctx { struct hid_device *hid; __u32 allocated_size; union { __s32 retval; __s32 size; }; };}hjsbah}(h]h ]h"]h$]h&]hhuh1j hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjbubh)}(h **Members**h]j )}(hjh]hMembers}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK$hjbubj )}(hhh](j$ )}(hT``hid`` the :c:type:`struct hid_device ` representing the device itself h](j* )}(h``hid``h]j")}(hjh]hhid}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjubjD )}(hhh]h)}(hKthe :c:type:`struct hid_device ` representing the device itselfh](hthe }(hjhhhNhNubh)}(h(:c:type:`struct hid_device `h]j")}(hjh]hstruct hid_device}(hjhhhNhNubah}(h]h ](jB j c-typeeh"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypetype refexplicitrefwarnjT jX j\ hid_deviceuh1hhjhKhjubh representing the device itself}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhKhjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhKhjubj$ )}(h+``allocated_size`` Allocated size of data. h](j* )}(h``allocated_size``h]j")}(hjh]hallocated_size}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhj ubjD )}(hhh]h)}(hAllocated size of data.h]hAllocated size of data.}(hj(hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj$hKhj%ubah}(h]h ]h"]h$]h&]uh1jC hj ubeh}(h]h ]h"]h$]h&]uh1j# hj$hKhjubj$ )}(h``{unnamed_union}`` anonymous h](j* )}(h``{unnamed_union}``h]j")}(hjHh]h{unnamed_union}}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjFubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjBubjD )}(hhh]h)}(h anonymoush]h anonymous}(hjahhhNhNubah}(h]h ]h"]h$]h&]uh1hhj]hKhj^ubah}(h]h ]h"]h$]h&]uh1jC hjBubeh}(h]h ]h"]h$]h&]uh1j# hj]hKhjubj$ )}(h1``retval`` Return value of the previous program. h](j* )}(h ``retval``h]j")}(hjh]hretval}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK+hj{ubjD )}(hhh]h)}(h%Return value of the previous program.h]h%Return value of the previous program.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhK+hjubah}(h]h ]h"]h$]h&]uh1jC hj{ubeh}(h]h ]h"]h$]h&]uh1j# hjhK+hjubj$ )}(h&``size`` Valid data in the data field.h](j* )}(h``size``h]j")}(hjh]hsize}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) hT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK!hjubjD )}(hhh]h)}(hValid data in the data field.h]hValid data in the data field.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK"hjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhK!hjubeh}(h]h ]h"]h$]h&]uh1j hjbubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjhhhjhNubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK%hjhhubh)}(h``data`` is not directly accessible from the context. We need to issue a call to hid_bpf_get_data() in order to get a pointer to that field.h](j")}(h``data``h]hdata}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh 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.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhjhhubh block_quote)}(hX  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) 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](j1)}(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)}(hThis is how much memory is available and can be requested by the HID program. Note that for ``HID_BPF_RDESC_FIXUP``, that memory is set to ``4096`` (4 KB)h](h\This is how much memory is available and can be requested by the HID program. Note that for }(hj:hhhNhNubj")}(h``HID_BPF_RDESC_FIXUP``h]hHID_BPF_RDESC_FIXUP}(hjBhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj:ubh, that memory is set to }(hj:hhhNhNubj")}(h``4096``h]h4096}(hjThhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj:ubh (4 KB)}(hj:hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhj6ubah}(h]h ]h"]h$]h&]uh1j0hjlhKhj2ubh)}(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.}(hjshhhNhNubah}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhKhj2ubh)}(hs``size`` must always be less or equal than ``allocated_size`` (it is enforced once all BPF programs have been run).h](j")}(h``size``h]hsize}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh# must always be less or equal than }(hjhhhNhNubj")}(h``allocated_size``h]hallocated_size}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh6 (it is enforced once all BPF programs have been run).}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK$hj2ubeh}(h]h ]h"]h$]h&]uh1j0hjlhKhjhhubh)}(hU``hid`` and ``allocated_size`` are read-only, ``size`` and ``retval`` are read-write.h](j")}(h``hid``h]hhid}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh and }(hjhhhNhNubj")}(h``allocated_size``h]hallocated_size}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh are read-only, }(hjhhhNhNubj")}(h``size``h]hsize}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh and }hjsbj")}(h ``retval``h]hretval}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh are read-write.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhT/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:192: ./include/linux/hid_bpf.hhK'hjhhubeh}(h]jah ]h"]/user api data structures available in programs:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(hBAvailable API that can be used in all HID-BPF struct_ops programs:h]hBAvailable API that can be used in all HID-BPF struct_ops programs:}(hjhhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhjhhhhhKubj2 )}(hhh]h}(h]h ]h"]h$]h&]entries](j> hid_bpf_get_data (C function)c.hid_bpf_get_datahNtauh1j1 hjhhhNhNubjC )}(hhh](jH )}(hn__bpf_kfunc __u8 * hid_bpf_get_data (struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)h]jN )}(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}(hj7hhhNhNubjf )}(h h]h }(hj?hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj7hhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMubh)}(hhh]j} )}(h__u8h]h__u8}(hjQhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjNubah}(h]h ]h"]h$]h&] refdomainj reftype identifier reftargetjSmodnameN classnameNjT jW )}jZ ]jU ASTIdentifier)}jghid_bpf_get_datasbc.hid_bpf_get_dataasbuh1hhj7hhhjMhMubjf )}(h h]h }(hjuhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj7hhhjMhMubhdesc_sig_punctuation)}(h*h]h*}(hjhhhNhNubah}(h]h ]pah"]h$]h&]uh1jhj7hhhjMhMubjw )}(hhid_bpf_get_datah]j} )}(hjrh]hhid_bpf_get_data}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ](j j eh"]h$]h&]hhuh1jv hj7hhhjMhMubhdesc_parameterlist)}(hJ(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)h](hdesc_parameter)}(hstruct hid_bpf_ctx *ctxh](jT )}(hjW h]hstruct}(hjhhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubh)}(hhh]j} )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jpc.hid_bpf_get_dataasbuh1hhjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj} )}(hctxh]hctx}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(hunsigned int offseth](hdesc_sig_keyword_type)}(hunsignedh]hunsigned}(hj)hhhNhNubah}(h]h ]ktah"]h$]h&]uh1j'hj#ubjf )}(h h]h }(hj8hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj#ubj()}(hinth]hint}(hjFhhhNhNubah}(h]h ]j4ah"]h$]h&]uh1j'hj#ubjf )}(h h]h }(hjThhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj#ubj} )}(hoffseth]hoffset}(hjbhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj#ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(hconst size_t rdwr_buf_sizeh](jT )}(hconsth]hconst}(hj{hhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjwubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjwubh)}(hhh]j} )}(hsize_th]hsize_t}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jpc.hid_bpf_get_dataasbuh1hhjwubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjwubj} )}(h rdwr_buf_sizeh]h rdwr_buf_size}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjwubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubeh}(h]h ]h"]h$]h&]hhuh1jhj7hhhjMhMubeh}(h]h ]h"]h$]h&]hhj uh1jM j j hj3hhhjMhMubah}(h]j.ah ](j j eh"]h$]h&]j j )j huh1jG hjMhMhj0hhubj )}(hhh]h)}(hAGet the kernel memory pointer associated with the context **ctx**h](h:Get the kernel memory pointer associated with the context }(hjhhhNhNubj )}(h**ctx**h]hctx}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubah}(h]h ]h"]h$]h&]uh1j hj0hhhjMhMubeh}(h]h ](j functioneh"]h$]h&]j j j jj jj j j uh1jB hhhjhNhNubj )}(hX**Parameters** ``struct hid_bpf_ctx *ctx`` The HID-BPF context ``unsigned int offset`` The offset within the memory ``const size_t rdwr_buf_size`` the const size of the buffer **Description** **returns** ``NULL`` on error, an ``__u8`` memory pointer on successh](h)}(h**Parameters**h]j )}(hj h]h Parameters}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chM!hjubj )}(hhh](j$ )}(h0``struct hid_bpf_ctx *ctx`` The HID-BPF context h](j* )}(h``struct hid_bpf_ctx *ctx``h]j")}(hj?h]hstruct hid_bpf_ctx *ctx}(hjAhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj=ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj9ubjD )}(hhh]h)}(hThe HID-BPF contexth]hThe HID-BPF context}(hjXhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjThMhjUubah}(h]h ]h"]h$]h&]uh1jC hj9ubeh}(h]h ]h"]h$]h&]uh1j# hjThMhj6ubj$ )}(h5``unsigned int offset`` The offset within the memory h](j* )}(h``unsigned int offset``h]j")}(hjxh]hunsigned int offset}(hjzhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjvubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chM hjrubjD )}(hhh]h)}(hThe offset within the memoryh]hThe offset within the memory}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhM hjubah}(h]h ]h"]h$]h&]uh1jC hjrubeh}(h]h ]h"]h$]h&]uh1j# hjhM hj6ubj$ )}(h<``const size_t rdwr_buf_size`` the const size of the buffer h](j* )}(h``const size_t rdwr_buf_size``h]j")}(hjh]hconst size_t rdwr_buf_size}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chM!hjubjD )}(hhh]h)}(hthe const size of the bufferh]hthe const size of the buffer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhM!hjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhM!hj6ubeh}(h]h ]h"]h$]h&]uh1j hjubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chM#hjubh)}(hD**returns** ``NULL`` on error, an ``__u8`` memory pointer on successh](j )}(h **returns**h]hreturns}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh }(hjhhhNhNubj")}(h``NULL``h]hNULL}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh on error, an }(hjhhhNhNubj")}(h``__u8``h]h__u8}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh memory pointer on success}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:198: ./drivers/hid/bpf/hid_bpf_dispatch.chM"hjubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjhhhNhNubeh}(h]jah ]h"]Bavailable api that can be used in all hid-bpf struct_ops programs:ah$]h&]uh1hhjhhhhhKubh)}(hhh](h)}(hgAvailable API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs:h]hgAvailable API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs:}(hjThhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhjQhhhhhKubj2 )}(hhh]h}(h]h ]h"]h$]h&]entries](j> %hid_bpf_allocate_context (C function)c.hid_bpf_allocate_contexthNtauh1j1 hjQhhhNhNubjC )}(hhh](jH )}(hO__bpf_kfunc struct hid_bpf_ctx * hid_bpf_allocate_context (unsigned int hid_id)h]jN )}(hM__bpf_kfunc struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id)h](h __bpf_kfunc}(hjwhhhNhNubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjwhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM3ubjT )}(hjW h]hstruct}(hjhhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjwhhhjhM3ubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjwhhhjhM3ubh)}(hhh]j} )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jo)}jghid_bpf_allocate_contextsbc.hid_bpf_allocate_contextasbuh1hhjwhhhjhM3ubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjwhhhjhM3ubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjwhhhjhM3ubjw )}(hhid_bpf_allocate_contexth]j} )}(hjh]hhid_bpf_allocate_context}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ](j j eh"]h$]h&]hhuh1jv hjwhhhjhM3ubj)}(h(unsigned int hid_id)h]j)}(hunsigned int hid_idh](j()}(hunsignedh]hunsigned}(hjhhhNhNubah}(h]h ]j4ah"]h$]h&]uh1j'hjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubj()}(hinth]hint}(hj#hhhNhNubah}(h]h ]j4ah"]h$]h&]uh1j'hjubjf )}(h h]h }(hj1hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubj} )}(hhid_idh]hhid_id}(hj?hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubah}(h]h ]h"]h$]h&]hhuh1jhjwhhhjhM3ubeh}(h]h ]h"]h$]h&]hhj uh1jM j j hjshhhjhM3ubah}(h]jnah ](j j eh"]h$]h&]j j )j huh1jG hjhM3hjphhubj )}(hhh]h)}(h*Allocate a context to the given HID deviceh]h*Allocate a context to the given HID device}(hjihhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM3hjfhhubah}(h]h ]h"]h$]h&]uh1j hjphhhjhM3ubeh}(h]h ](j functioneh"]h$]h&]j j j jj jj j j uh1jB hhhjQhNhNubj )}(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}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM7hjubj )}(hhh]j$ )}(hG``unsigned int hid_id`` the system unique identifier of the HID device h](j* )}(h``unsigned int hid_id``h]j")}(hjh]hunsigned int hid_id}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM5hjubjD )}(hhh]h)}(h.the system unique identifier of the HID deviceh]h.the system unique identifier of the HID device}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhM5hjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhM5hjubah}(h]h ]h"]h$]h&]uh1j hjubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM7hjubh)}(hb**returns** A pointer to :c:type:`struct hid_bpf_ctx ` on success, ``NULL`` on error.h](j )}(h **returns**h]hreturns}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh A pointer to }(hjhhhNhNubh)}(h*:c:type:`struct hid_bpf_ctx `h]j")}(hjh]hstruct hid_bpf_ctx}(hjhhhNhNubah}(h]h ](jB j c-typeeh"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypetype refexplicitrefwarnjT jX j\ hid_bpf_ctxuh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM6hjubh on success, }(hjhhhNhNubj")}(h``NULL``h]hNULL}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh on error.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj0hM6hjubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjQhhhNhNubj2 )}(hhh]h}(h]h ]h"]h$]h&]entries](j> $hid_bpf_release_context (C function)c.hid_bpf_release_contexthNtauh1j1 hjQhhhNhNubjC )}(hhh](jH )}(hB__bpf_kfunc void hid_bpf_release_context (struct hid_bpf_ctx *ctx)h]jN )}(hA__bpf_kfunc void hid_bpf_release_context(struct hid_bpf_ctx *ctx)h](h __bpf_kfunc}(hjihhhNhNubjf )}(h h]h }(hjqhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjihhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMOubj()}(hvoidh]hvoid}(hjhhhNhNubah}(h]h ]j4ah"]h$]h&]uh1j'hjihhhjhMOubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjihhhjhMOubjw )}(hhid_bpf_release_contexth]j} )}(hhid_bpf_release_contexth]hhid_bpf_release_context}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ](j j eh"]h$]h&]hhuh1jv hjihhhjhMOubj)}(h(struct hid_bpf_ctx *ctx)h]j)}(hstruct hid_bpf_ctx *ctxh](jT )}(hjW h]hstruct}(hjhhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubh)}(hhh]j} )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jo)}jgjsbc.hid_bpf_release_contextasbuh1hhjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj} )}(hctxh]hctx}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubah}(h]h ]h"]h$]h&]hhuh1jhjihhhjhMOubeh}(h]h ]h"]h$]h&]hhj uh1jM j j hjehhhjhMOubah}(h]j`ah ](j j eh"]h$]h&]j j )j huh1jG hjhMOhjbhhubj )}(hhh]h)}(h0Release the previously allocated context **ctx**h](h)Release the previously allocated context }(hj?hhhNhNubj )}(h**ctx**h]hctx}(hjGhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj?ubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMOhj<hhubah}(h]h ]h"]h$]h&]uh1j hjbhhhjhMOubeh}(h]h ](j functioneh"]h$]h&]j j j jej jej j j uh1jB hhhjQhNhNubj )}(hL**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context to releaseh](h)}(h**Parameters**h]j )}(hjoh]h Parameters}(hjqhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjmubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMShjiubj )}(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}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMUhjubjD )}(hhh]h)}(hthe HID-BPF context to releaseh]hthe HID-BPF context to release}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMQhjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhMUhjubah}(h]h ]h"]h$]h&]uh1j hjiubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjQhhhNhNubj2 )}(hhh]h}(h]h ]h"]h$]h&]entries](j> hid_bpf_hw_request (C function)c.hid_bpf_hw_requesthNtauh1j1 hjQhhhNhNubjC )}(hhh](jH )}(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]jN )}(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}(hjhhhNhNubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj()}(hinth]hint}(hjhhhNhNubah}(h]h ]j4ah"]h$]h&]uh1j'hjhhhjhMubjf )}(h h]h }(hj hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjhhhjhMubjw )}(hhid_bpf_hw_requesth]j} )}(hhid_bpf_hw_requesth]hhid_bpf_hw_request}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ](j j eh"]h$]h&]hhuh1jv hjhhhjhMubj)}(hp(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, enum hid_report_type rtype, enum hid_class_request reqtype)h](j)}(hstruct hid_bpf_ctx *ctxh](jT )}(hjW h]hstruct}(hj7hhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hj3ubjf )}(h h]h }(hjDhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj3ubh)}(hhh]j} )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjUhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjRubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjWmodnameN classnameNjT jW )}jZ ]jo)}jgjsbc.hid_bpf_hw_requestasbuh1hhj3ubjf )}(h h]h }(hjuhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj3ubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj3ubj} )}(hctxh]hctx}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj3ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj/ubj)}(h __u8 *bufh](h)}(hhh]j} )}(h__u8h]h__u8}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jqc.hid_bpf_hw_requestasbuh1hhjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj} )}(hbufh]hbuf}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj/ubj)}(hsize_t buf__szh](h)}(hhh]j} )}(hsize_th]hsize_t}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jqc.hid_bpf_hw_requestasbuh1hhjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubj} )}(hbuf__szh]hbuf__sz}(hj-hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj/ubj)}(henum hid_report_type rtypeh](jT )}(henumh]henum}(hjFhhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjBubjf )}(h h]h }(hjThhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjBubh)}(hhh]j} )}(hhid_report_typeh]hhid_report_type}(hjehhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjbubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjgmodnameN classnameNjT jW )}jZ ]jqc.hid_bpf_hw_requestasbuh1hhjBubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjBubj} )}(hrtypeh]hrtype}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjBubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj/ubj)}(henum hid_class_request reqtypeh](jT )}(hjHh]henum}(hjhhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubh)}(hhh]j} )}(hhid_class_requesth]hhid_class_request}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jqc.hid_bpf_hw_requestasbuh1hhjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubj} )}(hreqtypeh]hreqtype}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj/ubeh}(h]h ]h"]h$]h&]hhuh1jhjhhhjhMubeh}(h]h ]h"]h$]h&]hhj uh1jM j j hjhhhjhMubah}(h]jah ](j j eh"]h$]h&]j j )j huh1jG hjhMhjhhubj )}(hhh]h)}(hCommunicate with a HID deviceh]hCommunicate with a HID device}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubah}(h]h ]h"]h$]h&]uh1j hjhhhjhMubeh}(h]h ](j functioneh"]h$]h&]j j j j6j j6j j j uh1jB hhhjQhNhNubj )}(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 )}(hj@h]h Parameters}(hjBhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj>ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj:ubj )}(hhh](j$ )}(hc``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() h](j* )}(h``struct hid_bpf_ctx *ctx``h]j")}(hj_h]hstruct hid_bpf_ctx *ctx}(hjahhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj]ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjYubjD )}(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()}(hjxhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjthMhjuubah}(h]h ]h"]h$]h&]uh1jC hjYubeh}(h]h ]h"]h$]h&]uh1j# hjthMhjVubj$ )}(h&``__u8 *buf`` a ``PTR_TO_MEM`` buffer h](j* )}(h ``__u8 *buf``h]j")}(hjh]h __u8 *buf}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubjD )}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(hjhhhNhNubj")}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh buffer}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhMhjVubj$ )}(h4``size_t buf__sz`` the size of the data to transfer h](j* )}(h``size_t buf__sz``h]j")}(hjh]hsize_t buf__sz}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubjD )}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhMhjVubj$ )}(h|``enum hid_report_type rtype`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) h](j* )}(h``enum hid_report_type rtype``h]j")}(hjh]henum hid_report_type rtype}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubjD )}(hhh]h)}(h\the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](hthe type of the report (}(hj5hhhNhNubj")}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hj=hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj5ubh, }(hj5hhhNhNubj")}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hjOhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj5ubh, }hj5sbj")}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hjahhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj5ubh)}(hj5hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj1hMhj2ubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hj1hMhjVubj$ )}(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}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubjD )}(hhh]h)}(hMthe type of the request (``HID_REQ_GET_REPORT``, ``HID_REQ_SET_REPORT``, ...)h](hthe type of the request (}(hjhhhNhNubj")}(h``HID_REQ_GET_REPORT``h]hHID_REQ_GET_REPORT}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh, }(hjhhhNhNubj")}(h``HID_REQ_SET_REPORT``h]hHID_REQ_SET_REPORT}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh, ...)}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhMhjVubeh}(h]h ]h"]h$]h&]uh1j hj:ubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj:ubh)}(h>**returns** ``0`` on success, a negative error code otherwise.h](j )}(h **returns**h]hreturns}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh }(hjhhhNhNubj")}(h``0``h]h0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubh- on success, a negative error code otherwise.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj:ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjQhhhNhNubj2 )}(hhh]h}(h]h ]h"]h$]h&]entries](j> %hid_bpf_hw_output_report (C function)c.hid_bpf_hw_output_reporthNtauh1j1 hjQhhhNhNubjC )}(hhh](jH )}(h]__bpf_kfunc int hid_bpf_hw_output_report (struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)h]jN )}(h\__bpf_kfunc int hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)h](h __bpf_kfunc}(hjKhhhNhNubjf )}(h h]h }(hjShhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjKhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj()}(hinth]hint}(hjbhhhNhNubah}(h]h ]j4ah"]h$]h&]uh1j'hjKhhhjahMubjf )}(h h]h }(hjphhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjKhhhjahMubjw )}(hhid_bpf_hw_output_reporth]j} )}(hhid_bpf_hw_output_reporth]hhid_bpf_hw_output_report}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj~ubah}(h]h ](j j eh"]h$]h&]hhuh1jv hjKhhhjahMubj)}(h4(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)h](j)}(hstruct hid_bpf_ctx *ctxh](jT )}(hjW h]hstruct}(hjhhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubh)}(hhh]j} )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jo)}jgjsbc.hid_bpf_hw_output_reportasbuh1hhjubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjubj)}(hjh]h*}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj} )}(hctxh]hctx}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(h __u8 *bufh](h)}(hhh]j} )}(h__u8h]h__u8}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjmodnameN classnameNjT jW )}jZ ]jc.hid_bpf_hw_output_reportasbuh1hhj ubjf )}(h h]h }(hj1hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj ubj)}(hjh]h*}(hj?hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj} )}(hbufh]hbuf}(hjLhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubj)}(hsize_t buf__szh](h)}(hhh]j} )}(hsize_th]hsize_t}(hjhhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjeubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjjmodnameN classnameNjT jW )}jZ ]jc.hid_bpf_hw_output_reportasbuh1hhjaubjf )}(h h]h }(hjhhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjaubj} )}(hbuf__szh]hbuf__sz}(hjhhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjaubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjubeh}(h]h ]h"]h$]h&]hhuh1jhjKhhhjahMubeh}(h]h ]h"]h$]h&]hhj uh1jM j j hjGhhhjahMubah}(h]jBah ](j j eh"]h$]h&]j j )j huh1jG hjahMhjDhhubj )}(hhh]h)}(h%Send an output report to a HID deviceh]h%Send an output report to a HID device}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjhhubah}(h]h ]h"]h$]h&]uh1j hjDhhhjahMubeh}(h]h ](j functioneh"]h$]h&]j j j jj jj j j uh1jB hhhjQhNhNubj )}(hX;**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() ``__u8 *buf`` a ``PTR_TO_MEM`` buffer ``size_t buf__sz`` the size of the data to transfer **Description** Returns the number of bytes transferred on success, a negative error code otherwise.h](h)}(h**Parameters**h]j )}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubj )}(hhh](j$ )}(hc``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() h](j* )}(h``struct hid_bpf_ctx *ctx``h]j")}(hjh]hstruct hid_bpf_ctx *ctx}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubjD )}(hhh]h)}(hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()h]hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jC hjubeh}(h]h ]h"]h$]h&]uh1j# hjhMhjubj$ )}(h&``__u8 *buf`` a ``PTR_TO_MEM`` buffer h](j* )}(h ``__u8 *buf``h]j")}(hj8h]h __u8 *buf}(hj:hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj6ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj2ubjD )}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(hjQhhhNhNubj")}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hjYhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjQubh buffer}(hjQhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhjMhMhjNubah}(h]h ]h"]h$]h&]uh1jC hj2ubeh}(h]h ]h"]h$]h&]uh1j# hjMhMhjubj$ )}(h4``size_t buf__sz`` the size of the data to transfer h](j* )}(h``size_t buf__sz``h]j")}(hjh]hsize_t buf__sz}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj}ubjD )}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhMhjubah}(h]h ]h"]h$]h&]uh1jC hj}ubeh}(h]h ]h"]h$]h&]uh1j# hjhMhjubeh}(h]h ]h"]h$]h&]uh1j hjubh)}(h**Description**h]j )}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubh)}(hTReturns the number of bytes transferred on success, a negative error code otherwise.h]hTReturns the number of bytes transferred on success, a negative error code otherwise.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjQhhhNhNubj2 )}(hhh]h}(h]h ]h"]h$]h&]entries](j> %hid_bpf_try_input_report (C function)c.hid_bpf_try_input_reporthNtauh1j1 hjQhhhNhNubjC )}(hhh](jH )}(h|__bpf_kfunc int hid_bpf_try_input_report (struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h]jN )}(h{__bpf_kfunc int hid_bpf_try_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h](h __bpf_kfunc}(hjhhhNhNubjf )}(h h]h }(hj hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjhhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj()}(hinth]hint}(hj hhhNhNubah}(h]h ]j4ah"]h$]h&]uh1j'hjhhhj hMubjf )}(h h]h }(hj$ hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjhhhj hMubjw )}(hhid_bpf_try_input_reporth]j} )}(hhid_bpf_try_input_reporth]hhid_bpf_try_input_report}(hj6 hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj2 ubah}(h]h ](j j eh"]h$]h&]hhuh1jv hjhhhj 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](jT )}(hjW h]hstruct}(hjR hhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjN ubjf )}(h h]h }(hj_ hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjN ubh)}(hhh]j} )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hjp hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjm ubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjr modnameN classnameNjT jW )}jZ ]jo)}jgj8 sbc.hid_bpf_try_input_reportasbuh1hhjN ubjf )}(h h]h }(hj hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjN ubj)}(hjh]h*}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjN ubj} )}(hctxh]hctx}(hj hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjN ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjJ ubj)}(henum hid_report_type typeh](jT )}(hjHh]henum}(hj hhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hj ubjf )}(h h]h }(hj hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj ubh)}(hhh]j} )}(hhid_report_typeh]hhid_report_type}(hj hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj ubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetj modnameN classnameNjT jW )}jZ ]j c.hid_bpf_try_input_reportasbuh1hhj ubjf )}(h h]h }(hj!hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj ubj} )}(htypeh]htype}(hj!hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjJ ubj)}(hu8 *bufh](h)}(hhh]j} )}(hu8h]hu8}(hj*!hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj'!ubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetj,!modnameN classnameNjT jW )}jZ ]j c.hid_bpf_try_input_reportasbuh1hhj#!ubjf )}(h h]h }(hjH!hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj#!ubj)}(hjh]h*}(hjV!hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj#!ubj} )}(hbufh]hbuf}(hjc!hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj#!ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjJ ubj)}(hconst size_t buf__szh](jT )}(hj}h]hconst}(hj|!hhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjx!ubjf )}(h h]h }(hj!hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjx!ubh)}(hhh]j} )}(hsize_th]hsize_t}(hj!hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj!ubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetj!modnameN classnameNjT jW )}jZ ]j c.hid_bpf_try_input_reportasbuh1hhjx!ubjf )}(h h]h }(hj!hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjx!ubj} )}(hbuf__szh]hbuf__sz}(hj!hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjx!ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhjJ ubeh}(h]h ]h"]h$]h&]hhuh1jhjhhhj hMubeh}(h]h ]h"]h$]h&]hhj uh1jM j j hjhhhj hMubah}(h]jah ](j j eh"]h$]h&]j j )j huh1jG hj hMhjhhubj )}(hhh]h)}(h3Inject a HID report in the kernel from a HID deviceh]h3Inject a HID report in the kernel from a HID device}(hj!hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj!hhubah}(h]h ]h"]h$]h&]uh1j hjhhhj hMubeh}(h]h ](j functioneh"]h$]h&]j j j j"j j"j j j uh1jB hhhjQhNhNubj )}(hX**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() ``enum hid_report_type type`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``u8 *buf`` a ``PTR_TO_MEM`` buffer ``const size_t buf__sz`` the size of the data to transfer **Description** Returns ``0`` on success, a negative error code otherwise. This function will immediately fail if the device is not available, thus can be safely used in IRQ context.h](h)}(h**Parameters**h]j )}(hj"h]h Parameters}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj"ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj "ubj )}(hhh](j$ )}(hc``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() h](j* )}(h``struct hid_bpf_ctx *ctx``h]j")}(hj1"h]hstruct hid_bpf_ctx *ctx}(hj3"hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj/"ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj+"ubjD )}(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()}(hjJ"hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjF"hMhjG"ubah}(h]h ]h"]h$]h&]uh1jC hj+"ubeh}(h]h ]h"]h$]h&]uh1j# hjF"hMhj("ubj$ )}(h{``enum hid_report_type type`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) h](j* )}(h``enum hid_report_type type``h]j")}(hjj"h]henum hid_report_type type}(hjl"hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjh"ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhjd"ubjD )}(hhh]h)}(h\the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](hthe type of the report (}(hj"hhhNhNubj")}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj"ubh, }(hj"hhhNhNubj")}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj"ubh, }hj"sbj")}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj"ubh)}(hj"hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj"hMhj"ubah}(h]h ]h"]h$]h&]uh1jC hjd"ubeh}(h]h ]h"]h$]h&]uh1j# hj"hMhj("ubj$ )}(h$``u8 *buf`` a ``PTR_TO_MEM`` buffer h](j* )}(h ``u8 *buf``h]j")}(hj"h]hu8 *buf}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj"ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj"ubjD )}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(hj"hhhNhNubj")}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj"ubh buffer}(hj"hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj"hMhj"ubah}(h]h ]h"]h$]h&]uh1jC hj"ubeh}(h]h ]h"]h$]h&]uh1j# hj"hMhj("ubj$ )}(h:``const size_t buf__sz`` the size of the data to transfer h](j* )}(h``const size_t buf__sz``h]j")}(hj$#h]hconst size_t buf__sz}(hj&#hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj"#ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj#ubjD )}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hj=#hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj9#hMhj:#ubah}(h]h ]h"]h$]h&]uh1jC hj#ubeh}(h]h ]h"]h$]h&]uh1j# hj9#hMhj("ubeh}(h]h ]h"]h$]h&]uh1j hj "ubh)}(h**Description**h]j )}(hj_#h]h Description}(hja#hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj]#ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj "ubh)}(hReturns ``0`` on success, a negative error code otherwise. This function will immediately fail if the device is not available, thus can be safely used in IRQ context.h](hReturns }(hju#hhhNhNubj")}(h``0``h]h0}(hj}#hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hju#ubh on success, a negative error code otherwise. This function will immediately fail if the device is not available, thus can be safely used in IRQ context.}(hju#hhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj "ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjQhhhNhNubj2 )}(hhh]h}(h]h ]h"]h$]h&]entries](j> !hid_bpf_input_report (C function)c.hid_bpf_input_reporthNtauh1j1 hjQhhhNhNubjC )}(hhh](jH )}(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]jN )}(hw__bpf_kfunc int hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h](h __bpf_kfunc}(hj#hhhNhNubjf )}(h h]h }(hj#hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj#hhh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMubj()}(hinth]hint}(hj#hhhNhNubah}(h]h ]j4ah"]h$]h&]uh1j'hj#hhhj#hMubjf )}(h h]h }(hj#hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj#hhhj#hMubjw )}(hhid_bpf_input_reporth]j} )}(hhid_bpf_input_reporth]hhid_bpf_input_report}(hj#hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj#ubah}(h]h ](j j eh"]h$]h&]hhuh1jv hj#hhhj#hMubj)}(hS(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)h](j)}(hstruct hid_bpf_ctx *ctxh](jT )}(hjW h]hstruct}(hj$hhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hj$ubjf )}(h h]h }(hj$hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj$ubh)}(hhh]j} )}(h hid_bpf_ctxh]h hid_bpf_ctx}(hj#$hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj $ubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetj%$modnameN classnameNjT jW )}jZ ]jo)}jgj#sbc.hid_bpf_input_reportasbuh1hhj$ubjf )}(h h]h }(hjC$hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj$ubj)}(hjh]h*}(hjQ$hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj$ubj} )}(hctxh]hctx}(hj^$hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj$ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj#ubj)}(henum hid_report_type typeh](jT )}(hjHh]henum}(hjw$hhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hjs$ubjf )}(h h]h }(hj$hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjs$ubh)}(hhh]j} )}(hhid_report_typeh]hhid_report_type}(hj$hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj$ubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetj$modnameN classnameNjT jW )}jZ ]j?$c.hid_bpf_input_reportasbuh1hhjs$ubjf )}(h h]h }(hj$hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hjs$ubj} )}(htypeh]htype}(hj$hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjs$ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj#ubj)}(hu8 *bufh](h)}(hhh]j} )}(hu8h]hu8}(hj$hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj$ubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetj$modnameN classnameNjT jW )}jZ ]j?$c.hid_bpf_input_reportasbuh1hhj$ubjf )}(h h]h }(hj$hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj$ubj)}(hjh]h*}(hj %hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj$ubj} )}(hbufh]hbuf}(hj%hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj$ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj#ubj)}(hconst size_t buf__szh](jT )}(hj}h]hconst}(hj/%hhhNhNubah}(h]h ]j` ah"]h$]h&]uh1jS hj+%ubjf )}(h h]h }(hj<%hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj+%ubh)}(hhh]j} )}(hsize_th]hsize_t}(hjM%hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hjJ%ubah}(h]h ]h"]h$]h&] refdomainj reftypejg reftargetjO%modnameN classnameNjT jW )}jZ ]j?$c.hid_bpf_input_reportasbuh1hhj+%ubjf )}(h h]h }(hjk%hhhNhNubah}(h]h ]jr ah"]h$]h&]uh1je hj+%ubj} )}(hbuf__szh]hbuf__sz}(hjy%hhhNhNubah}(h]h ]j ah"]h$]h&]uh1j| hj+%ubeh}(h]h ]h"]h$]h&]noemphhhuh1jhj#ubeh}(h]h ]h"]h$]h&]hhuh1jhj#hhhj#hMubeh}(h]h ]h"]h$]h&]hhj uh1jM j j hj#hhhj#hMubah}(h]j#ah ](j j eh"]h$]h&]j j )j huh1jG hj#hMhj#hhubj )}(hhh]h)}(h3Inject a HID report in the kernel from a HID deviceh]h3Inject a HID report in the kernel from a HID device}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%hhubah}(h]h ]h"]h$]h&]uh1j hj#hhhj#hMubeh}(h]h ](j functioneh"]h$]h&]j j j j%j j%j j j uh1jB hhhjQhNhNubj )}(hX$**Parameters** ``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() ``enum hid_report_type type`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) ``u8 *buf`` a ``PTR_TO_MEM`` buffer ``const size_t buf__sz`` the size of the data to transfer **Description** Returns ``0`` on success, a negative error code otherwise. This function will wait for the device to be available before injecting the event, thus needs to be called in sleepable context.h](h)}(h**Parameters**h]j )}(hj%h]h Parameters}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj%ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%ubj )}(hhh](j$ )}(hc``struct hid_bpf_ctx *ctx`` the HID-BPF context previously allocated in hid_bpf_allocate_context() h](j* )}(h``struct hid_bpf_ctx *ctx``h]j")}(hj%h]hstruct hid_bpf_ctx *ctx}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj%ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%ubjD )}(hhh]h)}(hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()h]hFthe HID-BPF context previously allocated in hid_bpf_allocate_context()}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj%hMhj%ubah}(h]h ]h"]h$]h&]uh1jC hj%ubeh}(h]h ]h"]h$]h&]uh1j# hj%hMhj%ubj$ )}(h{``enum hid_report_type type`` the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``) h](j* )}(h``enum hid_report_type type``h]j")}(hj&h]henum hid_report_type type}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj&ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj&ubjD )}(hhh]h)}(h\the type of the report (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, ``HID_OUTPUT_REPORT``)h](hthe type of the report (}(hj6&hhhNhNubj")}(h``HID_INPUT_REPORT``h]hHID_INPUT_REPORT}(hj>&hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj6&ubh, }(hj6&hhhNhNubj")}(h``HID_FEATURE_REPORT``h]hHID_FEATURE_REPORT}(hjP&hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj6&ubh, }hj6&sbj")}(h``HID_OUTPUT_REPORT``h]hHID_OUTPUT_REPORT}(hjb&hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj6&ubh)}(hj6&hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj2&hMhj3&ubah}(h]h ]h"]h$]h&]uh1jC hj&ubeh}(h]h ]h"]h$]h&]uh1j# hj2&hMhj%ubj$ )}(h$``u8 *buf`` a ``PTR_TO_MEM`` buffer h](j* )}(h ``u8 *buf``h]j")}(hj&h]hu8 *buf}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj&ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj&ubjD )}(hhh]h)}(ha ``PTR_TO_MEM`` bufferh](ha }(hj&hhhNhNubj")}(h``PTR_TO_MEM``h]h PTR_TO_MEM}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj&ubh buffer}(hj&hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhj&hMhj&ubah}(h]h ]h"]h$]h&]uh1jC hj&ubeh}(h]h ]h"]h$]h&]uh1j# hj&hMhj%ubj$ )}(h:``const size_t buf__sz`` the size of the data to transfer h](j* )}(h``const size_t buf__sz``h]j")}(hj&h]hconst size_t buf__sz}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj&ubah}(h]h ]h"]h$]h&]uh1j) h_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj&ubjD )}(hhh]h)}(h the size of the data to transferh]h the size of the data to transfer}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj&hMhj&ubah}(h]h ]h"]h$]h&]uh1jC hj&ubeh}(h]h ]h"]h$]h&]uh1j# hj&hMhj%ubeh}(h]h ]h"]h$]h&]uh1j hj%ubh)}(h**Description**h]j )}(hj'h]h Description}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj'ubah}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chM hj%ubh)}(hReturns ``0`` on success, a negative error code otherwise. This function will wait for the device to be available before injecting the event, thus needs to be called in sleepable context.h](hReturns }(hj('hhhNhNubj")}(h``0``h]h0}(hj0'hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj('ubh on success, a negative error code otherwise. This function will wait for the device to be available before injecting the event, thus needs to be called in sleepable context.}(hj('hhhNhNubeh}(h]h ]h"]h$]h&]uh1hh_/var/lib/git/docbuild/linux/Documentation/hid/hid-bpf:204: ./drivers/hid/bpf/hid_bpf_dispatch.chMhj%ubeh}(h]h ] kernelindentah"]h$]h&]uh1j hjQhhhNhNubeh}(h]jah ]h"]gavailable api that can be used in syscall hid-bpf programs or in sleepable hid-bpf struct_ops programs:ah$]h&]uh1hhjhhhhhKubeh}(h]j}ah ]h"]developer api:ah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h%General overview of a HID-BPF programh]h%General overview of a HID-BPF program}(hja'hhhNhNubah}(h]h ]h"]h$]h&]jNj<uh1hhj^'hhhhhKubh)}(hhh](h)}(h*Accessing the data attached to the contexth]h*Accessing the data attached to the context}(hjr'hhhNhNubah}(h]h ]h"]h$]h&]jNj[uh1hhjo'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 }(hj'hhhNhNubj")}(h``struct hid_bpf_ctx``h]hstruct hid_bpf_ctx}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj'ubh doesn’t export the }(hj'hhhNhNubj")}(h``data``h]hdata}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj'ubhE fields directly and to access it, a bpf program needs to first call }(hj'hhhNhNubh)}(h:c:func:`hid_bpf_get_data`h]j")}(hj'h]hhid_bpf_get_data()}(hj'hhhNhNubah}(h]h ](jB j c-funceh"]h$]h&]uh1j!hj'ubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypefunc refexplicitrefwarnjT jX j\ hid_bpf_get_datauh1hhhhKhj'ubh.}(hj'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjo'hhubh)}(hX``offset`` can be any integer, but ``size`` needs to be constant, known at compile time.h](j")}(h ``offset``h]hoffset}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj'ubh can be any integer, but }(hj'hhhNhNubj")}(h``size``h]hsize}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj'ubh- needs to be constant, known at compile time.}(hj'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjo'hhubh)}(hThis allows the following:h]hThis allows the following:}(hj(hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjo'hhubj)}(hhh](h)}(hXRfor a given device, if we know that the report length will always be of a certain value, we can request the ``data`` pointer to point at the full report length. The kernel will ensure we are using a correct size and offset and eBPF will ensure the code will not attempt to read or write outside of the boundaries:: __u8 *data = hid_bpf_get_data(ctx, 0 /* offset */, 256 /* size */); if (!data) return 0; /* ensure data is correct, now the verifier knows we * have 256 bytes available */ bpf_printk("hello world: %02x %02x %02x", data[0], data[128], data[255]); h](h)}(hfor a given device, if we know that the report length will always be of a certain value, we can request the ``data`` pointer to point at the full report length.h](hlfor a given device, if we know that the report length will always be of a certain value, we can request the }(hj(hhhNhNubj")}(h``data``h]hdata}(hj (hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj(ubh, pointer to point at the full report length.}(hj(hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj(ubh)}(hThe kernel will ensure we are using a correct size and offset and eBPF will ensure the code will not attempt to read or write outside of the boundaries::h]hThe kernel will ensure we are using a correct size and offset and eBPF will ensure the code will not attempt to read or write outside of the boundaries:}(hj8(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]);}hjF(sbah}(h]h ]h"]h$]h&]hhuh1j hhhKhj(ubeh}(h]h ]h"]h$]h&]uh1hhj(hhhhhNubh)}(hX%if the report length is variable, but we know the value of ``X`` is always a 16-bit integer, we can then have a pointer to that value only:: __u16 *x = hid_bpf_get_data(ctx, offset, sizeof(*x)); if (!x) return 0; /* something went wrong */ *x += 1; /* increment X by one */ h](h)}(hif the report length is variable, but we know the value of ``X`` is always a 16-bit integer, we can then have a pointer to that value only::h](h;if the report length is variable, but we know the value of }(hj^(hhhNhNubj")}(h``X``h]hX}(hjf(hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj^(ubhK is always a 16-bit integer, we can then have a pointer to that value only:}(hj^(hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjZ(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 */}hj~(sbah}(h]h ]h"]h$]h&]hhuh1j hhhKhjZ(ubeh}(h]h ]h"]h$]h&]uh1hhj(hhhhhNubeh}(h]h ]h"]h$]h&]jjjhjjuh1jhjo'hhhhhKubeh}(h]jaah ]h"]*accessing the data attached to the contextah$]h&]uh1hhj^'hhhhhKubh)}(hhh](h)}(hEffect of a HID-BPF programh]hEffect of a HID-BPF program}(hj(hhhNhNubah}(h]h ]h"]h$]h&]jNj}uh1hhj(hhhhhKubh)}(hX)For all HID-BPF attachment types except for :c:func:`hid_rdesc_fixup`, several eBPF programs can be attached to the same device. If a HID-BPF struct_ops has a :c:func:`hid_rdesc_fixup` while another is already attached to the device, the kernel will return `-EINVAL` when attaching the struct_ops.h](h,For all HID-BPF attachment types except for }(hj(hhhNhNubh)}(h:c:func:`hid_rdesc_fixup`h]j")}(hj(h]hhid_rdesc_fixup()}(hj(hhhNhNubah}(h]h ](jB j c-funceh"]h$]h&]uh1j!hj(ubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypefunc refexplicitrefwarnjT jX j\ hid_rdesc_fixupuh1hhhhKhj(ubhZ, several eBPF programs can be attached to the same device. If a HID-BPF struct_ops has a }(hj(hhhNhNubh)}(h:c:func:`hid_rdesc_fixup`h]j")}(hj(h]hhid_rdesc_fixup()}(hj(hhhNhNubah}(h]h ](jB j c-funceh"]h$]h&]uh1j!hj(ubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypefunc refexplicitrefwarnjT jX j\ hid_rdesc_fixupuh1hhhhKhj(ubhI while another is already attached to the device, the kernel will return }(hj(hhhNhNubhtitle_reference)}(h `-EINVAL`h]h-EINVAL}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j(hj(ubh when attaching the struct_ops.}(hj(hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj(hhubh)}(hX&Unless ``BPF_F_BEFORE`` is added to the flags while attaching the program, the new program is appended at the end of the list. ``BPF_F_BEFORE`` will insert the new program at the beginning of the list which is useful for e.g. tracing where we need to get the unprocessed events from the device.h](hUnless }(hj)hhhNhNubj")}(h``BPF_F_BEFORE``h]h BPF_F_BEFORE}(hj )hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj)ubhh is added to the flags while attaching the program, the new program is appended at the end of the list. }(hj)hhhNhNubj")}(h``BPF_F_BEFORE``h]h BPF_F_BEFORE}(hj2)hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj)ubh will insert the new program at the beginning of the list which is useful for e.g. tracing where we need to get the unprocessed events from the device.}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj(hhubh)}(hNote that if there are multiple programs using the ``BPF_F_BEFORE`` flag, only the most recently loaded one is actually the first in the list.h](h3Note that if there are multiple programs using the }(hjJ)hhhNhNubj")}(h``BPF_F_BEFORE``h]h BPF_F_BEFORE}(hjR)hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjJ)ubhK flag, only the most recently loaded one is actually the first in the list.}(hjJ)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj(hhubh)}(hhh](h)}(h&``SEC("struct_ops/hid_device_event")``h]j")}(hjo)h]h"SEC("struct_ops/hid_device_event")}(hjq)hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjm)ubah}(h]h ]h"]h$]h&]uh1hhjj)hhhhhMubh)}(h~Whenever a matching event is raised, the eBPF programs are called one after the other and are working on the same data buffer.h]h~Whenever a matching event is raised, the eBPF programs are called one after the other and are working on the same data buffer.}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjj)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 }(hj)hhhNhNubjw)}(h*no*h]hno}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1jvhj)ubh$ idea of what the original data was.}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM hjj)hhubh)}(hOnce all the programs are run and return ``0`` or a positive value, the rest of the HID stack will work on the modified data, with the ``size`` field of the last hid_bpf_ctx being the new size of the input stream of data.h](h)Once all the programs are run and return }(hj)hhhNhNubj")}(h``0``h]h0}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj)ubhY or a positive value, the rest of the HID stack will work on the modified data, with the }(hj)hhhNhNubj")}(h``size``h]hsize}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj)ubhN field of the last hid_bpf_ctx being the new size of the input stream of data.}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhjj)hhubh)}(hA BPF program returning a negative error discards the event, i.e. this event will not be processed by the HID stack. Clients (hidraw, input, LEDs) will **not** see this event.h](hA BPF program returning a negative error discards the event, i.e. this event will not be processed by the HID stack. Clients (hidraw, input, LEDs) will }(hj)hhhNhNubj )}(h**not**h]hnot}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj)ubh see this event.}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhjj)hhubeh}(h]sec-struct-ops-hid-device-eventah ]h"]"sec("struct_ops/hid_device_event")ah$]h&]uh1hhj(hhhhhMubh)}(hhh](h)}(h``SEC("syscall")``h]j")}(hj*h]hSEC("syscall")}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj*ubah}(h]h ]h"]h$]h&]uh1hhj *hhhhhMubh)}(h``syscall`` are not attached to a given device. To tell which device we are working with, userspace needs to refer to the device by its unique system id (the last 4 numbers in the sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``).h](j")}(h ``syscall``h]hsyscall}(hj**hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj&*ubh are not attached to a given device. To tell which device we are working with, userspace needs to refer to the device by its unique system id (the last 4 numbers in the sysfs path: }(hj&*hhhNhNubj")}(h,``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``h]h(/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000}(hj<*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj&*ubh).}(hj&*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj *hhubh)}(hXjTo retrieve a context associated with the device, the program must call hid_bpf_allocate_context() and must release it with hid_bpf_release_context() before returning. Once the context is retrieved, one can also request a pointer to kernel memory with hid_bpf_get_data(). This memory is big enough to support all input/output/feature reports of the given device.h]hXjTo retrieve a context associated with the device, the program must call hid_bpf_allocate_context() and must release it with hid_bpf_release_context() before returning. Once the context is retrieved, one can also request a pointer to kernel memory with hid_bpf_get_data(). This memory is big enough to support all input/output/feature reports of the given device.}(hjT*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj *hhubeh}(h] sec-syscallah ]h"]sec("syscall")ah$]h&]uh1hhj(hhhhhMubh)}(hhh](h)}(h%``SEC("struct_ops/hid_rdesc_fixup")``h]j")}(hjo*h]h!SEC("struct_ops/hid_rdesc_fixup")}(hjq*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjm*ubah}(h]h ]h"]h$]h&]uh1hhjj*hhhhhM$ubh)}(hhThe ``hid_rdesc_fixup`` program works in a similar manner to ``.report_fixup`` of ``struct hid_driver``.h](hThe }(hj*hhhNhNubj")}(h``hid_rdesc_fixup``h]hhid_rdesc_fixup}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj*ubh& program works in a similar manner to }(hj*hhhNhNubj")}(h``.report_fixup``h]h .report_fixup}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj*ubh of }(hj*hhhNhNubj")}(h``struct hid_driver``h]hstruct hid_driver}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj*ubh.}(hj*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM&hjj*hhubh)}(hWhen the device is probed, the kernel sets the data buffer of the context with the content of the report descriptor. The memory associated with that buffer is ``HID_MAX_DESCRIPTOR_SIZE`` (currently 4kB).h](hWhen the device is probed, the kernel sets the data buffer of the context with the content of the report descriptor. The memory associated with that buffer is }(hj*hhhNhNubj")}(h``HID_MAX_DESCRIPTOR_SIZE``h]hHID_MAX_DESCRIPTOR_SIZE}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj*ubh (currently 4kB).}(hj*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM)hjj*hhubh)}(hThe eBPF program can modify the data buffer at-will and the kernel uses the modified content and size as the report descriptor.h]hThe eBPF program can modify the data buffer at-will and the kernel uses the modified content and size as the report descriptor.}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM-hjj*hhubh)}(hWhenever a struct_ops containing a ``SEC("struct_ops/hid_rdesc_fixup")`` program is attached (if no program was attached before), the kernel immediately disconnects the HID device and does a reprobe.h](h#Whenever a struct_ops containing a }(hj*hhhNhNubj")}(h%``SEC("struct_ops/hid_rdesc_fixup")``h]h!SEC("struct_ops/hid_rdesc_fixup")}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj*ubh program is attached (if no program was attached before), the kernel immediately disconnects the HID device and does a reprobe.}(hj*hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM0hjj*hhubh)}(h`In the same way, when this struct_ops is detached, the kernel issues a disconnect on the device.h]h`In the same way, when this struct_ops is detached, the kernel issues a disconnect on the device.}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM4hjj*hhubh)}(hXThere is no ``detach`` facility in HID-BPF. Detaching a program happens when all the user space file descriptors pointing at a HID-BPF struct_ops link are closed. Thus, if we need to replace a report descriptor fixup, some cooperation is required from the owner of the original report descriptor fixup. The previous owner will likely pin the struct_ops link in the bpffs, and we can then replace it through normal bpf operations.h](h There is no }(hj$+hhhNhNubj")}(h ``detach``h]hdetach}(hj,+hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj$+ubhX facility in HID-BPF. Detaching a program happens when all the user space file descriptors pointing at a HID-BPF struct_ops link are closed. Thus, if we need to replace a report descriptor fixup, some cooperation is required from the owner of the original report descriptor fixup. The previous owner will likely pin the struct_ops link in the bpffs, and we can then replace it through normal bpf operations.}(hj$+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM7hjj*hhubeh}(h]sec-struct-ops-hid-rdesc-fixupah ]h"]!sec("struct_ops/hid_rdesc_fixup")ah$]h&]uh1hhj(hhhhhM$ubeh}(h]jah ]h"]effect of a hid-bpf programah$]h&]uh1hhj^'hhhhhKubeh}(h]jBah ]h"]%general overview of a hid-bpf programah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h#Attaching a bpf program to a deviceh]h#Attaching a bpf program to a device}(hj]+hhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhjZ+hhhhhM?ubh)}(hWe now use standard struct_ops attachment through ``bpf_map__attach_struct_ops()``. But given that we need to attach a struct_ops to a dedicated HID device, the caller must set ``hid_id`` in the struct_ops map before loading the program in the kernel.h](h2We now use standard struct_ops attachment through }(hjk+hhhNhNubj")}(h ``bpf_map__attach_struct_ops()``h]hbpf_map__attach_struct_ops()}(hjs+hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjk+ubh_. But given that we need to attach a struct_ops to a dedicated HID device, the caller must set }(hjk+hhhNhNubj")}(h ``hid_id``h]hhid_id}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hjk+ubh@ in the struct_ops map before loading the program in the kernel.}(hjk+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMAhjZ+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}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj+ubhR 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}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj+ubh)}(hj+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMEhjZ+hhubh)}(hKOne can also set ``flags``, which is of type ``enum hid_bpf_attach_flags``.h](hOne can also set }(hj+hhhNhNubj")}(h ``flags``h]hflags}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj+ubh, which is of type }(hj+hhhNhNubj")}(h``enum hid_bpf_attach_flags``h]henum hid_bpf_attach_flags}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj+ubh.}(hj+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMHhjZ+hhubh)}(hXWe can not rely on hidraw to bind a BPF program to a HID device. hidraw is an artefact of the processing of the HID device, and is not stable. Some drivers even disable it, so that removes the tracing capabilities on those devices (where it is interesting to get the non-hidraw traces).h]hXWe can not rely on hidraw to bind a BPF program to a HID device. hidraw is an artefact of the processing of the HID device, and is not stable. Some drivers even disable it, so that removes the tracing capabilities on those devices (where it is interesting to get the non-hidraw traces).}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMJhjZ+hhubh)}(h{On the other hand, the ``hid_id`` is stable for the entire life of the HID device, even if we change its report descriptor.h](hOn the other hand, the }(hj ,hhhNhNubj")}(h ``hid_id``h]hhid_id}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj ,ubhZ is stable for the entire life of the HID device, even if we change its report descriptor.}(hj ,hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMOhjZ+hhubh)}(hXGiven that hidraw is not stable when the device disconnects/reconnects, we recommend accessing the current report descriptor of the device through the sysfs. This is available at ``/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor`` as a binary stream.h](hGiven that hidraw is not stable when the device disconnects/reconnects, we recommend accessing the current report descriptor of the device through the sysfs. This is available at }(hj+,hhhNhNubj")}(h;``/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor``h]h7/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor}(hj3,hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj+,ubh as a binary stream.}(hj+,hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMRhjZ+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.}(hjK,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMWhjZ+hhubeh}(h]jah ]h"]#attaching a bpf program to a deviceah$]h&]uh1hhhhhhhhM?ubh)}(hhh](h)}(h9An (almost) complete example of a BPF enhanced HID deviceh]h9An (almost) complete example of a BPF enhanced HID device}(hjc,hhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhj`,hhhhhM[ubh)}(hH*Foreword: for most parts, this could be implemented as a kernel driver*h]jw)}(hjs,h]hFForeword: for most parts, this could be implemented as a kernel driver}(hju,hhhNhNubah}(h]h ]h"]h$]h&]uh1jvhjq,ubah}(h]h ]h"]h$]h&]uh1hhhhM]hj`,hhubh)}(hXyLet's imagine we have a new tablet device that has some haptic capabilities to simulate the surface the user is scratching on. This device would also have a specific 3 positions switch to toggle between *pencil on paper*, *cray on a wall* and *brush on a painting canvas*. To make things even better, we can control the physical position of the switch through a feature report.h](hLet’s imagine we have a new tablet device that has some haptic capabilities to simulate the surface the user is scratching on. This device would also have a specific 3 positions switch to toggle between }(hj,hhhNhNubjw)}(h*pencil on paper*h]hpencil on paper}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1jvhj,ubh, }(hj,hhhNhNubjw)}(h*cray on a wall*h]hcray on a wall}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1jvhj,ubh and }(hj,hhhNhNubjw)}(h*brush on a painting canvas*h]hbrush on a painting canvas}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1jvhj,ubhj. To make things even better, we can control the physical position of the switch through a feature report.}(hj,hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM_hj`,hhubh)}(htAnd of course, the switch is relying on some userspace component to control the haptic feature of the device itself.h]htAnd of course, the switch is relying on some userspace component to control the haptic feature of the device itself.}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMehj`,hhubh)}(hhh](h)}(hFiltering eventsh]hFiltering events}(hj,hhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhj,hhhhhMiubh)}(hThe first step consists in filtering events from the device. Given that the switch position is actually reported in the flow of the pen events, using hidraw to implement that filtering would mean that we wake up userspace for every single event.h]hThe first step consists in filtering events from the device. Given that the switch position is actually reported in the flow of the pen events, using hidraw to implement that filtering would mean that we wake up userspace for every single event.}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMkhj,hhubh)}(h}This is OK for libinput, but having an external library that is just interested in one byte in the report is less than ideal.h]h}This is OK for libinput, but having an external library that is just interested in one byte in the report is less than ideal.}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMohj,hhubh)}(h>For that, we can create a basic skeleton for our BPF program::h]h=For that, we can create a basic skeleton for our BPF program:}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMrhj,hhubj )}(hX#include "vmlinux.h" #include #include /* HID programs need to be GPL */ char _license[] SEC("license") = "GPL"; /* HID-BPF kfunc API definitions */ extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz) __ksym; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 4096 * 64); } ringbuf SEC(".maps"); __u8 current_value = 0; SEC("struct_ops/hid_device_event") int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 192 /* size */); __u8 *buf; if (!data) return 0; /* EPERM check */ if (current_value != data[152]) { buf = bpf_ringbuf_reserve(&ringbuf, 1, 0); if (!buf) return 0; *buf = data[152]; bpf_ringbuf_commit(buf, 0); current_value = data[152]; } return 0; } SEC(".struct_ops.link") struct hid_bpf_ops haptic_tablet = { .hid_device_event = (void *)filter_switch, };h]hX#include "vmlinux.h" #include #include /* HID programs need to be GPL */ char _license[] SEC("license") = "GPL"; /* HID-BPF kfunc API definitions */ extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz) __ksym; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 4096 * 64); } ringbuf SEC(".maps"); __u8 current_value = 0; SEC("struct_ops/hid_device_event") int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 192 /* size */); __u8 *buf; if (!data) return 0; /* EPERM check */ if (current_value != data[152]) { buf = bpf_ringbuf_reserve(&ringbuf, 1, 0); if (!buf) return 0; *buf = data[152]; bpf_ringbuf_commit(buf, 0); current_value = data[152]; } return 0; } SEC(".struct_ops.link") struct hid_bpf_ops haptic_tablet = { .hid_device_event = (void *)filter_switch, };}hj-sbah}(h]h ]h"]h$]h&]hhuh1j hhhMthj,hhubh)}(hFTo attach ``haptic_tablet``, userspace needs to set ``hid_id`` first::h](h To attach }(hj#-hhhNhNubj")}(h``haptic_tablet``h]h haptic_tablet}(hj+-hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj#-ubh, userspace needs to set }(hj#-hhhNhNubj")}(h ``hid_id``h]hhid_id}(hj=-hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj#-ubh first:}(hj#-hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj,hhubj )}(hXstatic int attach_filter(struct hid *hid_skel, int hid_id) { int err, link_fd; hid_skel->struct_ops.haptic_tablet->hid_id = hid_id; err = hid__load(skel); if (err) return err; link_fd = bpf_map__attach_struct_ops(hid_skel->maps.haptic_tablet); if (!link_fd) { fprintf(stderr, "can not attach HID-BPF program: %m\n"); return -1; } return link_fd; /* the fd of the created bpf_link */ }h]hXstatic int attach_filter(struct hid *hid_skel, int hid_id) { int err, link_fd; hid_skel->struct_ops.haptic_tablet->hid_id = hid_id; err = hid__load(skel); if (err) return err; link_fd = bpf_map__attach_struct_ops(hid_skel->maps.haptic_tablet); if (!link_fd) { fprintf(stderr, "can not attach HID-BPF program: %m\n"); return -1; } return link_fd; /* the fd of the created bpf_link */ }}hjU-sbah}(h]h ]h"]h$]h&]hhuh1j hhhMhj,hhubh)}(htOur userspace program can now listen to notifications on the ring buffer, and is awaken only when the value changes.h]htOur userspace program can now listen to notifications on the ring buffer, and is awaken only when the value changes.}(hjc-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj,hhubh)}(hWhen the userspace program doesn't need to listen to events anymore, it can just close the returned bpf link from :c:func:`attach_filter`, which will tell the kernel to detach the program from the HID device.h](htWhen the userspace program doesn’t need to listen to events anymore, it can just close the returned bpf link from }(hjq-hhhNhNubh)}(h:c:func:`attach_filter`h]j")}(hj{-h]hattach_filter()}(hj}-hhhNhNubah}(h]h ](jB j c-funceh"]h$]h&]uh1j!hjy-ubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypefunc refexplicitrefwarnjT jX j\ attach_filteruh1hhhhMhjq-ubhG, which will tell the kernel to detach the program from the HID device.}(hjq-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 }(hj-hhhNhNubh)}(h:c:func:`bpf_obj_pin`h]j")}(hj-h]h bpf_obj_pin()}(hj-hhhNhNubah}(h]h ](jB j c-funceh"]h$]h&]uh1j!hj-ubah}(h]h ]h"]h$]h&]refdocjN refdomainj reftypefunc refexplicitrefwarnjT jX j\ bpf_obj_pinuh1hhhhMhj-ubh, as with any bpf_link.}(hj-hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj,hhubeh}(h]jah ]h"]filtering eventsah$]h&]uh1hhj`,hhhhhMiubh)}(hhh](h)}(hControlling the deviceh]hControlling the device}(hj-hhhNhNubah}(h]h ]h"]h$]h&]jNjuh1hhj-hhhhhMubh)}(hTo be able to change the haptic feedback from the tablet, the userspace program needs to emit a feature report on the device itself.h]hTo be able to change the haptic feedback from the tablet, the userspace program needs to emit a feature report on the device itself.}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj-hhubh)}(hgInstead of using hidraw for that, we can create a ``SEC("syscall")`` program that talks to the device::h](h2Instead of using hidraw for that, we can create a }(hj-hhhNhNubj")}(h``SEC("syscall")``h]hSEC("syscall")}(hj.hhhNhNubah}(h]h ]h"]h$]h&]uh1j!hj-ubh" program that talks to the device:}(hj-hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj-hhubj )}(hXW/* some more HID-BPF kfunc API definitions */ extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym; extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym; extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8* data, size_t len, enum hid_report_type type, enum hid_class_request reqtype) __ksym; struct hid_send_haptics_args { /* data needs to come at offset 0 so we can do a memcpy into it */ __u8 data[10]; unsigned int hid; }; SEC("syscall") int send_haptic(struct hid_send_haptics_args *args) { struct hid_bpf_ctx *ctx; int ret = 0; ctx = hid_bpf_allocate_context(args->hid); if (!ctx) return 0; /* EPERM check */ ret = hid_bpf_hw_request(ctx, args->data, 10, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); hid_bpf_release_context(ctx); return ret; }h]hXW/* some more HID-BPF kfunc API definitions */ extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym; extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym; extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8* data, size_t len, enum hid_report_type type, enum hid_class_request reqtype) __ksym; struct hid_send_haptics_args { /* data needs to come at offset 0 so we can do a memcpy into it */ __u8 data[10]; unsigned int hid; }; SEC("syscall") int send_haptic(struct hid_send_haptics_args *args) { struct hid_bpf_ctx *ctx; int ret = 0; ctx = hid_bpf_allocate_context(args->hid); if (!ctx) return 0; /* EPERM check */ ret = hid_bpf_hw_request(ctx, args->data, 10, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); hid_bpf_release_context(ctx); return ret; }}hj.sbah}(h]h ]h"]h$]h&]hhuh1j hhhMhj-hhubh)}(h8And then userspace needs to call that program directly::h]h7And then userspace needs to call that program directly:}(hj'.hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj-hhubj )}(hXGstatic int set_haptic(struct hid *hid_skel, int hid_id, __u8 haptic_value) { int err, prog_fd; int ret = -1; struct hid_send_haptics_args args = { .hid = hid_id, }; DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, .ctx_in = &args, .ctx_size_in = sizeof(args), ); args.data[0] = 0x02; /* report ID of the feature on our device */ args.data[1] = haptic_value; prog_fd = bpf_program__fd(hid_skel->progs.set_haptic); err = bpf_prog_test_run_opts(prog_fd, &tattrs); return err; }h]hXGstatic int set_haptic(struct hid *hid_skel, int hid_id, __u8 haptic_value) { int err, prog_fd; int ret = -1; struct hid_send_haptics_args args = { .hid = hid_id, }; DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, .ctx_in = &args, .ctx_size_in = sizeof(args), ); args.data[0] = 0x02; /* report ID of the feature on our device */ args.data[1] = haptic_value; prog_fd = bpf_program__fd(hid_skel->progs.set_haptic); err = bpf_prog_test_run_opts(prog_fd, &tattrs); return err; }}hj5.sbah}(h]h ]h"]h$]h&]hhuh1j hhhMhj-hhubh)}(hNow our userspace program is aware of the haptic state and can control it. The program could make this state further available to other userspace programs (e.g. via a DBus API).h]hNow our userspace program is aware of the haptic state and can control it. The program could make this state further available to other userspace programs (e.g. via a DBus API).}(hjC.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.}(hjQ.hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM hj-hhubeh}(h]jah ]h"]controlling the deviceah$]h&]uh1hhj`,hhhhhMubeh}(h]jah ]h"]9an (almost) complete example of a bpf enhanced hid deviceah$]h&]uh1hhhhhhhhM[ubeh}(h]hid-bpfah ]h"]hid-bpfah$]h&]uh1hhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerj.error_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourcehnj _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(jr.jo.j:j5j%jjj/jjQj&jsjhjjjjjjjjhj9jjjj[j['j}jjjjjNjjT'jjW+jBj(jajP+jj *j*jg*jd*jI+jF+j],jjj.jj-jjc.ju nametypes}(jr.j:j%jjj&jhjjjjhjjj['jjjNjT'jW+j(jP+j *jg*jI+j],jj.j-jc.uh}(jo.hj5hjj=j/j]jQjjsjjj)jjkjjjj(j9jjjj[jkj}jjj j@ jI jjjjjjj.j3jjQjnjsj`jejjjBjGjjj#j#jBj^'jajo'jj(j*jj)jd*j *jF+jj*jjZ+jj`,jj,jj-j jj)j jKjBjmjdjjjjjjjjj3jjUjLjwjnjjjjjjjjj<j3j[jRj}jtjjjjjjjju 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.